:(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; call(recipe_number r) :running_recipe(r), pc(0) {} }; typedef stack call_stack; :(code) void run(string form) { recipe_number r = add_recipe(form); call_stack context; context.push(call(r)); run(context); } void run(call_stack context) { // #defines save us the trouble of updating aliases when dependent variables // change. #define TOP_RECIPE Recipe[context.top().running_recipe] #define instructions TOP_RECIPE.steps while (!context.empty()) { while (context.top().pc >= instructions.size()) { context.pop(); if (context.empty()) return; // todo: no results returned warning ++context.top().pc; } size_t& pc = context.top().pc; 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: raise << "undefined operation " << instructions[pc].operation; } ++pc; } #undef TOP_RECIPE #undef instructions } 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 }