diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-02-17 17:14:53 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-02-17 17:14:53 -0800 |
commit | dcf7436e67dd8b84341d1748bae0ac0dd4f8043e (patch) | |
tree | 61c068e7860d8d2d04982b5f57736756b09257e9 | |
parent | 515309164793b2e03c15954bf8a89f0f288a7f2c (diff) | |
download | mu-dcf7436e67dd8b84341d1748bae0ac0dd4f8043e.tar.gz |
776
-rw-r--r-- | cpp/literate/010vm | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/cpp/literate/010vm b/cpp/literate/010vm new file mode 100644 index 00000000..090da3ff --- /dev/null +++ b/cpp/literate/010vm @@ -0,0 +1,114 @@ +// A mu program is a book of recipes (functions) + +:(after "Types") +typedef int recipe_number; +:(before "End Globals") +unordered_map<string, recipe_number> Recipe_number; +unordered_map<recipe_number, recipe> Recipe; +int Next_recipe_number = 1; + +:(before "End Types") +// Recipes are lists of instructions. Recipes are 'run' by running their +// instructions. +struct recipe { + vector<instruction> step; +}; + +const int idle = 0; // always the first entry in the recipe book + +:(before "struct recipe") +// Each instruction is either of the form: +// product1, product2, product3, ... <- operation ingredient1, ingredient2, ingredient3, ... +// or just a single 'label' followed by a colon +// label: +struct instruction { + bool is_label; + string label; // only if is_label + recipe_number operation; // only if !is_label + vector<reagent> ingredients; // only if !is_label + vector<reagent> products; // only if !is_label + instruction(); + void clear(); +}; + +:(before "struct instruction") +// Ingredients and products all the same kind of 'thing' -- a reagent. +// Reagents refer either to numbers or to locations in memory along with +// 'type' tags telling us how to interpret them. They also can contain +// arbitrary other lists of properties besides types, but we're getting ahead +// of ourselves. +struct reagent { + string name; + vector<type_number> types; + vector<pair<string, property> > properties; + reagent(string s); + string to_string(); +}; + +:(before "struct reagent") +struct property { + vector<string> values; +}; + +:(before "End Globals") +// Locations refer to a common 'memory'. Each location can store a number. +unordered_map<int, int> Memory; + +:(after "Types") +// Types encode how the numbers stored in different parts of memory are +// interpreted. A location tagged as a 'character' type will interpret the +// number 97 as the letter 'a', while a different location of type 'integer' +// would not. +// +// Unlike most computers today, mu stores types in a single big table, shared +// by all the mu programs on the computer. This is useful in providing a +// seamless experience to help understand arbitrary mu programs. +typedef int type_number; +:(before "End Globals") +unordered_map<string, type_number> Type_number; +unordered_map<type_number, type_info> Type; +int Next_type_number = 1; + +:(before "End Types") +// You can construct arbitrary new types. Types are either 'records', containing +// 'fields' of other types, 'array's of a single type repeated over and over, +// or 'addresses' pointing at a location elsewhere in memory. +struct type_info { + int size; + bool is_address; + bool is_record; + bool is_array; + vector<type_number> target; // only if is_address + vector<vector<type_number> > elements; // only if is_record or is_array + type_info() :size(0) {} +}; + + + +:(code) +// Helpers + instruction::instruction() :is_label(false), operation(idle) {} + void instruction::clear() { is_label=false; label.clear(); operation=idle; ingredients.clear(); products.clear(); } + + reagent::reagent(string s) { + istringstream in(s); + name = slurp_until(in, ':'); + types.push_back(Type_number[slurp_until(in, '/')]); // todo: multiple types + } + string reagent::to_string() { + ostringstream out; + out << "{name: \"" << name << "\", type: " << types[0] << "}"; // todo: properties + 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(); +} |