:(before "End Globals")
map<recipe_ordinal, recipe> Recipe;
map<string, recipe_ordinal> Recipe_ordinal;
recipe_ordinal Next_recipe_ordinal = 1;
:(after "Types")
typedef long long int recipe_ordinal;
:(before "End Types")
struct recipe {
string name;
vector<instruction> steps;
recipe();
string to_string() const;
};
:(before "struct recipe")
struct instruction {
bool is_label;
string label;
string name;
string old_name;
recipe_ordinal operation;
vector<reagent> ingredients;
vector<reagent> products;
instruction();
void clear();
bool is_clear();
string to_string() const;
};
:(before "struct instruction")
struct reagent {
string original_string;
vector<pair<string, string_tree*> > properties;
string name;
double value;
bool initialized;
type_tree* type;
reagent(string s);
reagent();
~reagent();
reagent(const reagent& old);
reagent& operator=(const reagent& old);
void set_value(double v) { value = v; initialized = true; }
string to_string() const;
};
:(before "struct reagent")
struct property {
vector<string> values;
};
struct type_tree {
type_ordinal value;
type_tree* left;
type_tree* right;
~type_tree();
type_tree(const type_tree& old);
explicit type_tree(type_ordinal v) :value(v), left(NULL), right(NULL) {}
type_tree(type_ordinal v, type_tree* r) :value(v), left(NULL), right(r) {}
type_tree(type_tree* l, type_tree* r) :value(0), left(l), right(r) {}
};
struct string_tree {
string value;
string_tree* left;
string_tree* right;
~string_tree();
string_tree(const string_tree& old);
explicit string_tree(string v) :value(v), left(NULL), right(NULL) {}
string_tree(string v, string_tree* r) :value(v), left(NULL), right(r) {}
string_tree(string_tree* l, string_tree* r) :left(l), right(r) {}
string to_string() const;
};
:(before "End Globals")
map<long long int, double> Memory;
:(before "End Setup")
Memory.clear();
:(after "Types")
typedef long long int type_ordinal;
:(before "End Globals")
map<string, type_ordinal> Type_ordinal;
map<type_ordinal, type_info> Type;
type_ordinal Next_type_ordinal = 1;
:(code)
void setup_types() {
Type.clear(); Type_ordinal.clear();
put(Type_ordinal, "literal", 0);
Next_type_ordinal = 1;
type_ordinal number = put(Type_ordinal, "number", Next_type_ordinal++);
put(Type_ordinal, "location", get(Type_ordinal, "number"));
get_or_insert(Type, number).name = "number";
type_ordinal address = put(Type_ordinal, "address", Next_type_ordinal++);
get_or_insert(Type, address).name = "address";
type_ordinal boolean = put(Type_ordinal, "boolean", Next_type_ordinal++);
get_or_insert(Type, boolean).name = "boolean";
type_ordinal character = put(Type_ordinal, "character", Next_type_ordinal++);
get_or_insert(Type, character).name = "character";
type_ordinal array = put(Type_ordinal, "array", Next_type_ordinal++);
get_or_insert(Type, array).name = "array";
}
void teardown_types() {
for (map<type_ordinal, type_info>::iterator p = Type.begin(); p != Type.end(); ++p) {
for (long long int i = 0; i < SIZE(p->second.elements); ++i)
delete p->second.elements.at(i);
}
Type_ordinal.clear();
}
:(before "End One-time Setup")
setup_types();
atexit(teardown_types);
:(before "End Types")
enum kind_of_type {
PRIMITIVE,
CONTAINER,
EXCLUSIVE_CONTAINER
};
struct type_info {
string name;
kind_of_type kind;
long long int size;
vector<type_tree*> elements;
vector<string> element_names;
type_info() :kind(PRIMITIVE), size(0) {}
};
enum primitive_recipes {
IDLE = 0,
COPY,
MAX_PRIMITIVE_RECIPES,
};
:(code)
void setup_recipes() {
Recipe.clear(); Recipe_ordinal.clear();
put(Recipe_ordinal, "idle", IDLE);
put(Recipe_ordinal, "copy", COPY);
}
:(before "End One-time Setup")
setup_recipes();
assert(MAX_PRIMITIVE_RECIPES < 200);
Next_recipe_ordinal = 200;
put(Recipe_ordinal, "main", Next_recipe_ordinal++);
:(before "End Test Run Initialization")
assert(Next_recipe_ordinal < 1000);
:(before "End Setup")
Next_recipe_ordinal = 1000;
^L
:(code)
recipe::recipe() {
}
instruction::instruction() :is_label(false), operation(IDLE) {
}
void instruction::clear() { is_label=false; label.clear(); name.clear(); old_name.clear(); operation=IDLE; ingredients.clear(); products.clear(); }
bool instruction::is_clear() { return !is_label && name.empty(); }
reagent::reagent(string s) :original_string(s), value(0), initialized(false), type(NULL) {
istringstream in(s);
in >> std::noskipws;
while (!in.eof()) {
istringstream row(slurp_until(in, '/'));
row >> std::noskipws;
string key = slurp_until(row, ':');
string_tree* value = parse_property_list(row);
properties.push_back(pair<string, string_tree*>(key, value));
}
name = properties.at(0).first;
type = new_type_tree(properties.at(0).second);
if (is_integer(name) && type == NULL) {
type = new type_tree(0);
assert(!properties.at(0).second);
properties.at(0).second = new string_tree("literal");
}
if (name == "_" && type == NULL) {
type = new type_tree(0);
assert(!properties.at(0).second);
properties.at(0).second = new string_tree("dummy");
}
}
string_tree* parse_property_list(istream& in) {
skip_whitespace(in);
if (in.eof()) return NULL;
string_tree* result = new string_tree(slurp_until(in, ':'));
result->right = parse_property_list(in);
return result;
}
type_tree* new_type_tree(const string_tree* properties) {
if (!properties) return NULL;
type_tree* result = new type_tree(0);
if (!properties->value.empty()) {
const string& type_name = properties->value;
if (contains_key(Type_ordinal, type_name))
result->value = get(Type_ordinal, type_name);
else if (is_integer(type_name))
result->value = 0;
else
result->value = -1;
}
result->left = new_type_tree(properties->left);
result->right = new_type_tree(properties->right);
return result;
}
reagent::reagent(const reagent& old) :original_string(old.original_string), properties(old.properties), name(old.name), value(old.value), initialized(old.initialized) {
properties.clear();
for (long long int i = 0; i < SIZE(old.properties); ++i) {
properties.push_back(pair<string, string_tree*>(old.properties.at(i).first,
old.properties.at(i).second ? new string_tree(*old.properties.at(i).second) : NULL));
}
type = old.type ? new type_tree(*old.type) : NULL;
}
type_tree::type_tree(const type_tree& old) :value(old.value) {
left = old.left ? new type_tree(*old.left) : NULL;
right = old.right ? new type_tree(*old.right) : NULL;
}
string_tree::string_tree(const string_tree& old) {
value = old.value;
left = old.left ? new string_tree(*old.left) : NULL;
right = old.right ? new string_tree(*old.right) : NULL;
}
reagent& reagent::operator=(const reagent& old) {
original_string = old.original_string;
properties.clear();
for (long long int i = 0; i < SIZE(old.properties); ++i)
properties.push_back(pair<string, string_tree*>(old.properties.at(i).first, old.properties.at(i).second ? new string_tree(*old.properties.at(i).second) : NULL));
name = old.name;
value = old.value;
initialized = old.initialized;
type = old.type ? new type_tree(*old.type) : NULL;
return *this;
}
reagent::~reagent() {
for (long long int i = 0; i < SIZE(properties); ++i)
if (properties.at(i).second) delete properties.at(i).second;
delete type;
}
type_tree::~type_tree() {
delete left;
delete right;
}
string_tree::~string_tree() {
delete left;
delete right;
}
reagent::reagent() :value(0), initialized(false), type(NULL) {
properties.push_back(pair<string, string_tree*>("", NULL));
}
string reagent::to_string() const {
ostringstream out;
if (!properties.empty()) {
out << "{";
for (long long int i = 0; i < SIZE(properties); ++i) {
if (i > 0) out << ", ";
out << "\"" << properties.at(i).first << "\": " << debug_string(properties.at(i).second);
}
out << "}";
}
return out.str();
}
string debug_string(const reagent& x) {
ostringstream out;
out << x.name << ": " << debug_string(x.type) << " -- " << x.to_string();
return out.str();
}
string debug_string(const string_tree* property) {
if (!property) return "<>";
ostringstream out;
if (!property->left && !property->right)
out << '"' << property->value << '"';
else
dump_property_tree(property, out);
return out.str();
}
void dump_property_tree(const string_tree* property, ostream& out) {
out << "<";
if (property->left)
dump_property_tree(property->left, out);
else
out << '"' << property->value << '"';
out << " : ";
if (property->right)
dump_property_tree(property->right, out);
else
out << "<>";
out << ">";
}
string debug_string(const type_tree* type) {
if (!type) return "NULLNULLNULL";
ostringstream out;
if (!type->left && !type->right)
dump_type_name(type->value, out);
else
dump_types_tree(type, out);
return out.str();
}
void dump_types_tree(const type_tree* type, ostream& out) {
out << "<";
if (type->left)
dump_types_tree(type->left, out);
else
dump_type_name(type->value, out);
out << " : ";
if (type->right)
dump_types_tree(type->right, out);
else
out << "<>";
out << ">";
}
void dump_type_name(type_ordinal type, ostream& out) {
if (contains_key(Type, type))
out << get(Type, type).name;
else
out << "?" << type;
}
string instruction::to_string() const {
if (is_label) return label;
ostringstream out;
for (long long int i = 0; i < SIZE(products); ++i) {
if (i > 0) out << ", ";
out << products.at(i).original_string;
}
if (!products.empty()) out << " <- ";
out << name << ' ';
for (long long int i = 0; i < SIZE(ingredients); ++i) {
if (i > 0) out << ", ";
out << ingredients.at(i).original_string;
}
return out.str();
}
string debug_string(const recipe& x) {
ostringstream out;
out << "- recipe " << x.name << '\n';
for (long long int index = 0; index < SIZE(x.steps); ++index) {
const instruction& inst = x.steps.at(index);
out << "inst: " << inst.to_string() << '\n';
out << " ingredients\n";
for (long long int i = 0; i < SIZE(inst.ingredients); ++i)
out << " " << debug_string(inst.ingredients.at(i)) << '\n';
out << " products\n";
for (long long int i = 0; i < SIZE(inst.products); ++i)
out << " " << debug_string(inst.products.at(i)) << '\n';
}
return out.str();
}
string slurp_until(istream& in, char delim) {
ostringstream out;
char c;
while (in >> c) {
if (c == delim) {
break;
}
out << c;
}
return out.str();
}
bool has_property(reagent x, string name) {
for (long long int i = 1; i < SIZE(x.properties); ++i) {
if (x.properties.at(i).first == name) return true;
}
return false;
}
string_tree* property(const reagent& r, const string& name) {
for (long long int p = 1; p != SIZE(r.properties); ++p) {
if (r.properties.at(p).first == name)
return r.properties.at(p).second;
}
return NULL;
}
bool deeply_equal(const string_tree* a, const string_tree* b) {
if (!a) return !b;
if (!b) return !a;
return a->value == b->value
&& deeply_equal(a->left, b->left)
&& deeply_equal(a->right, b->right);
}
:(before "End Globals")
set<string> Literal_type_names;
:(before "End One-time Setup")
Literal_type_names.insert("literal");
Literal_type_names.insert("number");
Literal_type_names.insert("character");
:(code)
bool deeply_equal_types(const string_tree* a, const string_tree* b) {
if (!a) return !b;
if (!b) return !a;
if (Literal_type_names.find(a->value) != Literal_type_names.end())
return Literal_type_names.find(b->value) != Literal_type_names.end();
return a->value == b->value
&& deeply_equal_types(a->left, b->left)
&& deeply_equal_types(a->right, b->right);
}
void dump_memory() {
for (map<long long int, double>::iterator p = Memory.begin(); p != Memory.end(); ++p) {
cout << p->first << ": " << no_scientific(p->second) << '\n';
}
}
string recipe::to_string() const {
ostringstream out;
out << "recipe " << name << " [\n";
for (long long int i = 0; i < SIZE(steps); ++i)
out << " " << steps.at(i).to_string() << '\n';
out << "]\n";
return out.str();
}
string string_tree::to_string() const {
ostringstream out;
dump(this, out);
return out.str();
}
void dump(const string_tree* x, ostream& out) {
if (!x->left && !x->right) {
out << x->value;
return;
}
out << '(';
for (const string_tree* curr = x; curr; curr = curr->right) {
if (curr != x) out << ' ';
if (curr->left)
dump(curr->left, out);
else
out << curr->value;
}
out << ')';
}
void skip_whitespace(istream& in) {
while (!in.eof() && isspace(in.peek()) && in.peek() != '\n') {
in.get();
}
}
:(before "End Types")
struct no_scientific {
double x;
explicit no_scientific(double y) :x(y) {}
};
:(code)
ostream& operator<<(ostream& os, no_scientific x) {
if (!isfinite(x.x)) {
os << x.x;
return os;
}
ostringstream tmp;
tmp << std::fixed << x.x;
os << trim_floating_point(tmp.str());
return os;
}
string trim_floating_point(const string& in) {
if (in.empty()) return "";
long long int len = SIZE(in);
while (len > 1) {
if (in.at(len-1) != '0') break;
--len;
}
if (in.at(len-1) == '.') --len;
return in.substr(0, len);
}
void test_trim_floating_point() {
CHECK_EQ("", trim_floating_point(""));
CHECK_EQ("0", trim_floating_point("000000000"));
CHECK_EQ("1.5", trim_floating_point("1.5000"));
CHECK_EQ("1.000001", trim_floating_point("1.000001"));
CHECK_EQ("23", trim_floating_point("23.000000"));
CHECK_EQ("23", trim_floating_point("23.0"));
CHECK_EQ("23", trim_floating_point("23."));
CHECK_EQ("23", trim_floating_point("23"));
CHECK_EQ("3", trim_floating_point("3.000000"));
CHECK_EQ("3", trim_floating_point("3.0"));
CHECK_EQ("3", trim_floating_point("3."));
CHECK_EQ("3", trim_floating_point("3"));
}
:(before "End Includes")
#include<utility>
using std::pair;
#include<math.h>