//: Instructions can read from addresses pointing at other locations using the //: 'deref' property. :(scenario "copy_indirect") recipe main [ 1:address:integer <- copy 2:literal 2:integer <- copy 34:literal # This loads location 1 as an address and looks up *that* location. 3:integer <- copy 1:address:integer/deref ] +run: instruction main/2 +mem: location 1 is 2 +mem: location 2 is 34 +mem: storing in location 3 :(replace{} "vector read_memory(reagent x)") vector read_memory(reagent x) { vector result; if (x.types[0] == 0) { // literal result.push_back(to_int(x.name)); return result; } x = canonize(x); int base = to_int(x.name); size_t size = size_of(x); for (size_t offset = 0; offset < size; ++offset) { int val = Memory[base+offset]; trace("mem") << "location " << base+offset << " is " << val; result.push_back(val); } return result; } //: similarly, write to addresses pointing at other locations using the //: 'deref' property :(scenario "store_indirect") recipe main [ 1:address:integer <- copy 2:literal 1:address:integer/deref <- copy 34:literal ] +run: instruction main/1 +mem: location 1 is 2 +mem: storing in location 2 :(replace{} "void write_memory(reagent x, vector data)") void write_memory(reagent x, vector data) { x = canonize(x); int base = to_int(x.name); if (!Type[x.types[0]].is_array && size_of(x) != data.size()) raise << "size mismatch in storing to " << x.to_string(); for (size_t offset = 0; offset < data.size(); ++offset) { trace("mem") << "storing in location " << base+offset; Memory[base+offset] = data[offset]; } } :(code) reagent canonize(reagent x) { reagent r = x; while (has_property(r, "deref")) r = deref(r); return r; } bool has_property(reagent x, string name) { for (size_t i = 0; i < x.properties.size(); ++i) { if (x.properties[i].first == name) return true; } return false; } reagent deref(reagent x) { reagent result(""); assert(x.types[0] == 2); // address // compute name ostringstream out; out << Memory[to_int(x.name)]; result.name = out.str(); trace("mem") << "location " << x.name << " is " << result.name; // populate types copy(++x.types.begin(), x.types.end(), inserter(result.types, result.types.begin())); // drop-one 'deref' int i = 0; int len = x.properties.size(); while (true) { assert(i < len); if (x.properties[i].first == "deref") break; result.properties.push_back(x.properties[i]); ++i; } ++i; // skip first deref while (i < len) { result.properties.push_back(x.properties[i]); } return result; } //: 'get' can read from record address :(scenario "get_indirect") recipe main [ 1:integer <- copy 2:literal 2:integer <- copy 34:literal 3:integer <- copy 35:literal 4:integer <- get 1:address:point/deref, 0:offset ] +run: instruction main/3 +run: address to copy is 2 +run: product 0 is 34 +mem: storing in location 4 :(replace{} "case GET:") case GET: { trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; reagent base = canonize(instructions[pc].ingredients[0]); int base_address = to_int(base.name); int base_type = base.types[0]; assert(Type[base_type].is_record); trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; assert(instructions[pc].ingredients[1].types.size() == 1); assert(instructions[pc].ingredients[1].types[0] == 0); // must be literal size_t offset = to_int(instructions[pc].ingredients[1].name); int src = base_address; for (size_t i = 0; i < offset; ++i) { src += size_of(reagent(Type[base_type].elements[i][0])); } trace("run") << "address to copy is " << src; assert(Type[base_type].is_record); assert(Type[base_type].elements.size() > offset); int src_type = Type[base_type].elements[offset][0]; trace("run") << "its type is " << src_type; ostringstream s; s << src; reagent tmp(s.str()); tmp.types.push_back(src_type); vector result(read_memory(tmp)); trace("run") << "product 0 is " << result[0]; write_memory(instructions[pc].products[0], result); break; } :(scenario "get_address_indirect") # 'get' can read from record address recipe main [ 1:integer <- copy 2:literal 2:integer <- copy 34:literal 3:integer <- copy 35:literal 4:integer <- get-address 1:address:point/deref, 0:offset ] +run: instruction main/3 +run: address to copy is 2 +run: product 0 is 2 :(replace{} "case GET_ADDRESS:") case GET_ADDRESS: { trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; reagent base = canonize(instructions[pc].ingredients[0]); int base_address = to_int(base.name); int base_type = base.types[0]; assert(Type[base_type].is_record); trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; assert(instructions[pc].ingredients[1].types.size() == 1); assert(instructions[pc].ingredients[1].types[0] == 0); // must be literal size_t offset = to_int(instructions[pc].ingredients[1].name); int src = base_address; for (size_t i = 0; i < offset; ++i) { src += size_of(reagent(Type[base_type].elements[i][0])); } trace("run") << "address to copy is " << src; vector result; result.push_back(src); trace("run") << "product 0 is " << result[0]; write_memory(instructions[pc].products[0], result); break; }