:(scenarios run) :(scenario copy_literal) recipe main [ 1:integer <- copy 23:literal ] +run: instruction main/0 +run: ingredient 0 is 23 +mem: storing in location 1 :(scenario copy) recipe main [ 1:integer <- copy 23:literal 2:integer <- copy 1:integer ] +run: instruction main/1 +run: ingredient 0 is 1 +mem: location 1 is 23 +mem: storing in location 2 :(before "End Types") // Each recipe can be 'called' many many times in a program. Each call needs a // little extra information. struct call { recipe_number running_recipe; size_t pc; vector > incoming_atoms; size_t next_ingredient_to_process; vector > outgoing_atoms; call(recipe_number r) :running_recipe(r), pc(0), next_ingredient_to_process(0) {} }; typedef stack call_stack; struct routine { size_t alloc; size_t alloc_max; call_stack calls; size_t limit; size_t running_since; // todo: sleep conditions }; :(code) void run(string form) { run(add_recipes(form)); } void run(recipe_number r) { routine rr; rr.calls.push(call(r)); run(rr); } void run(routine rr) { // #defines save us the trouble of updating aliases when dependent variables // change. #define TOP_RECIPE Recipe[rr.calls.top().running_recipe] #define instructions TOP_RECIPE.steps while (!rr.calls.empty()) { while (rr.calls.top().pc >= instructions.size()) { rr.calls.pop(); if (rr.calls.empty()) return; // todo: no results returned warning ++rr.calls.top().pc; } size_t& pc = rr.calls.top().pc; //? cout << "instruction " << TOP_RECIPE.name << '/' << pc << '\n'; //? 2 trace("run") << "instruction " << TOP_RECIPE.name << '/' << pc; switch (instructions[pc].operation) { // Primitive Recipe Implementations. case COPY: { trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; vector data = read_memory(instructions[pc].ingredients[0]); write_memory(instructions[pc].products[0], data); break; } // End Primitive Recipe Implementations. default: { cout << "non primitive op: " << instructions[pc].operation << '\n'; } } ++pc; } #undef TOP_RECIPE #undef instructions } :(before "End Main") if (argc > 1) { setup(); for (int i = 1; i < argc; ++i) { ifstream fin(argv[i]); while (!fin.eof()) add_recipe(fin); fin.close(); } recipe_number r = Recipe_number[string("main")]; if (r) run(r); dump_memory(); } :(code) vector read_memory(reagent x) { //? cout << "read_memory: " << x.to_string() << '\n'; //? 1 vector result; if (x.types[0] == 0) { // literal result.push_back(to_int(x.name)); return result; } int base = to_int(x.name); for (size_t offset = 0; offset < Type[x.types[0]].size; ++offset) { int val = Memory[base+offset]; trace("mem") << "location " << base+offset << " is " << val; result.push_back(val); } return result; } void write_memory(reagent x, vector data) { int base = to_int(x.name); size_t size = size_of(x); if (size != data.size()) raise << "size mismatch in storing to " << x.to_string(); for (size_t offset = 0; offset < size; ++offset) { trace("mem") << "storing in location " << base+offset; Memory[base+offset] = data[offset]; } } :(code) int to_int(string n) { char* end = NULL; int result = strtol(n.c_str(), &end, /*any base*/0); assert(*end == '\0'); return result; } size_t size_of(reagent r) { type_info t = Type[r.types[0]]; if (!t.is_record && !t.is_array) return t.size; return t.size; // TODO }