diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-05-17 00:52:23 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-05-17 00:52:23 -0700 |
commit | 6f8f9fb53b5a7ef26496d496a4b93266c78d6332 (patch) | |
tree | dd7c6f97ead76e5a2e9026eb49d72f29de417e86 | |
parent | 304963834dbe1e9f019a818e0dbf9c63647fa1c4 (diff) | |
download | mu-6f8f9fb53b5a7ef26496d496a4b93266c78d6332.tar.gz |
1390 - support non-integer literals
Since '3.14159:literal' looks ugly, we'll just say '3.14159'. It's not like non-integers can be confused for anything but literals. Once I tried to turn reagent values into doubles, I uncovered a bug: arithmetic using signed integers is busted; if either operand of subtraction is unsigned the result is unsigned as well. If it needs to be negative: ka-boom. It was only masked because I was eventually storing the result in a long long int, where it was out of range, and so overflowing into the correct signed value. Once I switched to doubles the unsigned value would indeed fit without overflowing. Ka-boom. Yet another reminder that unsigned integers suck. I started using them mostly to avoid warnings in loops when comparing with .size(), which is usually a size_t. Who knows what other crap lurks here. Just use signed integers everywhere. (And avoid bitwise operators.)
-rw-r--r-- | 010vm.cc | 4 | ||||
-rw-r--r-- | 014literal_noninteger.cc | 33 | ||||
-rw-r--r-- | 023jump.cc | 22 | ||||
-rw-r--r-- | 030container.cc | 5 | ||||
-rw-r--r-- | 040brace.cc | 20 |
5 files changed, 60 insertions, 24 deletions
diff --git a/010vm.cc b/010vm.cc index c5e13543..6b94e4a3 100644 --- a/010vm.cc +++ b/010vm.cc @@ -41,12 +41,12 @@ struct instruction { struct reagent { vector<pair<string, vector<string> > > properties; string name; - long long int value; + double value; bool initialized; vector<type_number> types; reagent(string s); reagent(); - void set_value(long long int v) { value = v; initialized = true; } + void set_value(double v) { value = v; initialized = true; } string to_string() const; }; diff --git a/014literal_noninteger.cc b/014literal_noninteger.cc new file mode 100644 index 00000000..94242f41 --- /dev/null +++ b/014literal_noninteger.cc @@ -0,0 +1,33 @@ +//: Support literal non-integers. +//: '3.14159:literal' is ugly, so we'll just say '3.14159' for non-integers. + +:(scenarios load) +:(scenario noninteger_literal) +recipe main [ + 1:number <- copy 3.14159 +] ++parse: ingredient: {name: "3.14159", value: 3.14159, type: 0, properties: ["3.14159": "literal-number"]} + +:(after "reagent::reagent(string s)") + if (is_noninteger(s)) { + name = s; + types.push_back(0); + properties.push_back(pair<string, vector<string> >(name, vector<string>())); + properties.back().second.push_back("literal-number"); + set_value(to_double(s)); + return; + } + +:(code) +bool is_noninteger(const string& s) { + return s.find_first_not_of("0123456789-.") == NOT_FOUND + && s.find('.') != NOT_FOUND; +} + +double to_double(string n) { + char* end = NULL; + // safe because string.c_str() is guaranteed to be null-terminated + double result = strtod(n.c_str(), &end); + assert(*end == '\0'); + return result; +} diff --git a/023jump.cc b/023jump.cc index acf2f95d..b847a66c 100644 --- a/023jump.cc +++ b/023jump.cc @@ -1,5 +1,15 @@ //: Jump primitives +:(scenario jump_can_skip_instructions) +recipe main [ + jump 1:offset + 1:number <- copy 1:literal +] ++run: instruction main/0 ++run: ingredient 0 is 1 +-run: instruction main/1 +-mem: storing 1 in location 1 + :(before "End Primitive Recipe Declarations") JUMP, :(before "End Primitive Recipe Numbers") @@ -14,15 +24,9 @@ case JUMP: { break; } -:(scenario jump_can_skip_instructions) -recipe main [ - jump 1:offset - 1:number <- copy 1:literal -] -+run: instruction main/0 -+run: ingredient 0 is 1 --run: instruction main/1 --mem: storing 1 in location 1 +//: special type to designate jump targets +:(before "End Mu Types Initialization") +Type_number["offset"] = 0; :(scenario jump_backward) recipe main [ diff --git a/030container.cc b/030container.cc index 6df68c0a..71ef229c 100644 --- a/030container.cc +++ b/030container.cc @@ -132,11 +132,6 @@ case GET: { break; } -//: 'get' requires a literal in ingredient 1. We'll use a synonym called -//: 'offset'. -:(before "End Mu Types Initialization") -Type_number["offset"] = 0; - :(scenario get_handles_nested_container_elements) recipe main [ 12:number <- copy 34:literal diff --git a/040brace.cc b/040brace.cc index 6fde1713..ec9c6a4d 100644 --- a/040brace.cc +++ b/040brace.cc @@ -40,21 +40,23 @@ void transform_braces(const recipe_number r) { //? cout << "AAA transform_braces\n"; //? 1 //? exit(0); //? 1 const int OPEN = 0, CLOSE = 1; - list<pair<int/*OPEN/CLOSE*/, /*step*/index_t> > braces; - for (index_t index = 0; index < Recipe[r].steps.size(); ++index) { + // use signed integer for step index because we'll be doing arithmetic on it + list<pair<int/*OPEN/CLOSE*/, /*step*/long long int> > braces; + for (long long int index = 0; index < static_cast<long long int>(Recipe[r].steps.size()); ++index) { const instruction& inst = Recipe[r].steps.at(index); if (inst.label == "{") { trace("brace") << r << ": push (open, " << index << ")"; - braces.push_back(pair<int,index_t>(OPEN, index)); + braces.push_back(pair<int,long long int>(OPEN, index)); } if (inst.label == "}") { trace("brace") << "push (close, " << index << ")"; - braces.push_back(pair<int,index_t>(CLOSE, index)); + braces.push_back(pair<int,long long int>(CLOSE, index)); } } - stack</*step*/index_t> open_braces; + stack</*step*/long long int> open_braces; trace("after-brace") << "recipe " << Recipe[r].name; - for (index_t index = 0; index < Recipe[r].steps.size(); ++index) { + for (long long int index = 0; index < static_cast<long long int>(Recipe[r].steps.size()); ++index) { +//? cerr << index << '\n'; //? 1 instruction& inst = Recipe[r].steps.at(index); //? cout << "AAA " << inst.name << ": " << inst.operation << '\n'; //? 1 if (inst.label == "{") open_braces.push(index); @@ -154,9 +156,11 @@ void transform_braces(const recipe_number r) { } } -int matching_brace(index_t index, const list<pair<int, index_t> >& braces) { +// returns a signed integer not just so that we can return -1 but also to +// enable future signed arithmetic +long long int matching_brace(long long int index, const list<pair<int, long long int> >& braces) { int stacksize = 0; - for (list<pair<int, index_t> >::const_iterator p = braces.begin(); p != braces.end(); ++p) { + for (list<pair<int, long long int> >::const_iterator p = braces.begin(); p != braces.end(); ++p) { if (p->second < index) continue; stacksize += (p->first ? 1 : -1); if (stacksize == 0) return p->second; |