Fixed world's worst recursive descent parser (issue #5)
This commit is contained in:
68
src/obj.cpp
68
src/obj.cpp
@@ -41,15 +41,13 @@ static int skip_parens(const string &s, int i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Probably the worst recursive descent parser ever written, but it's an easy
|
// Probably the worst recursive descent parser ever written, but it's an easy
|
||||||
// way to make our assembly language pretty.
|
// way to make our assembly language prettier.
|
||||||
static uint64_t readParenExpression(const string &s, const map<string, Word> &d,
|
static uint64_t rPE(bool &v, const string &s, const map<string, Word> &d,
|
||||||
int start=0, int end=-1)
|
int start, int end)
|
||||||
{
|
{
|
||||||
uint64_t (* const rPE)(const string&, const map<string, Word>&, int, int)
|
D(2, "rPE(" << v << ", " << s << ", d, " << start << ", " << end << ");");
|
||||||
= readParenExpression;
|
|
||||||
if (end == start) return 0;
|
|
||||||
|
|
||||||
if (end==-1) end = s.length();
|
if (end == start) { v = false; return 0; }
|
||||||
|
|
||||||
while (isspace(s[start])) start++;
|
while (isspace(s[start])) start++;
|
||||||
while (isspace(s[end-1])) end--;
|
while (isspace(s[end-1])) end--;
|
||||||
@@ -57,29 +55,37 @@ static uint64_t readParenExpression(const string &s, const map<string, Word> &d,
|
|||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
if (s[i] == '(') { i = skip_parens(s, i); continue; }
|
if (s[i] == '(') { i = skip_parens(s, i); continue; }
|
||||||
|
|
||||||
if (s[i] == '<') return rPE(s, d, start, i) << rPE(s, d, i+2, end);
|
if (s[i] == '<') return rPE(v, s, d, start, i) << rPE(v, s, d, i+2, end);
|
||||||
if (s[i] == '>') return rPE(s, d, start, i) >> rPE(s, d, i+2, end);
|
if (s[i] == '>') return rPE(v, s, d, start, i) >> rPE(v, s, d, i+2, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
if (s[i] == '(') { i = skip_parens(s, i); continue; }
|
if (s[i] == '(') { i = skip_parens(s, i); continue; }
|
||||||
if (s[i] == '+') return rPE(s, d, start, i) + rPE(s, d, i+1, end);
|
if (s[i] == '+') return rPE(v, s, d, start, i) + rPE(v, s, d, i+1, end);
|
||||||
if (s[i] == '-') return rPE(s, d, start, i) - rPE(s, d, i+1, end);
|
if (s[i] == '-') {
|
||||||
if (s[i] == '|') return rPE(s, d, start, i) | rPE(s, d, i+1, end);
|
// If we've already failed, don't try this.
|
||||||
if (s[i] == '^') return rPE(s, d, start, i) ^ rPE(s, d, i+1, end);
|
if (v == false) return 0;
|
||||||
|
|
||||||
|
// If it works as a binary -, return that. Otherwise, it's a unary -
|
||||||
|
uint64_t x(rPE(v, s, d, start, i) - rPE(v, s, d, i+1, end));
|
||||||
|
if (v) return x;
|
||||||
|
else v = true;
|
||||||
|
}
|
||||||
|
if (s[i] == '|') return rPE(v, s, d, start, i) | rPE(v, s, d, i+1, end);
|
||||||
|
if (s[i] == '^') return rPE(v, s, d, start, i) ^ rPE(v, s, d, i+1, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
if (s[i] == '(') { i = skip_parens(s, i); continue; }
|
if (s[i] == '(') { i = skip_parens(s, i); continue; }
|
||||||
if (s[i] == '*') return rPE(s, d, start, i) * rPE(s, d, i+1, end);
|
if (s[i] == '*') return rPE(v, s, d, start, i) * rPE(v, s, d, i+1, end);
|
||||||
if (s[i] == '/') return rPE(s, d, start, i) / rPE(s, d, i+1, end);
|
if (s[i] == '/') return rPE(v, s, d, start, i) / rPE(v, s, d, i+1, end);
|
||||||
if (s[i] == '%') return rPE(s, d, start, i) % rPE(s, d, i+1, end);
|
if (s[i] == '%') return rPE(v, s, d, start, i) % rPE(v, s, d, i+1, end);
|
||||||
if (s[i] == '&') return rPE(s, d, start, i) & rPE(s, d, i+1, end);
|
if (s[i] == '&') return rPE(v, s, d, start, i) & rPE(v, s, d, i+1, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unary operators
|
// Unary operators
|
||||||
if (s[start] == '-') return -rPE(s, d, start+1, end);
|
if (s[start] == '-') return -rPE(v, s, d, start+1, end);
|
||||||
if (s[start] == '`') return log2(rPE(s, d, start+1, end));
|
if (s[start] == '`') return log2(rPE(v, s, d, start+1, end));
|
||||||
|
|
||||||
if (isdigit(s[start])) {
|
if (isdigit(s[start])) {
|
||||||
unsigned long long u;
|
unsigned long long u;
|
||||||
@@ -87,13 +93,22 @@ static uint64_t readParenExpression(const string &s, const map<string, Word> &d,
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s[start] == '(') return rPE(s, d, start+1, end-1);
|
if (s[start] == '(') return rPE(v, s, d, start+1, end-1);
|
||||||
|
|
||||||
map<string, Word>::const_iterator it = d.find(s.substr(start, end-start));
|
string label(s.substr(start, end-start));
|
||||||
|
map<string, Word>::const_iterator it(d.find(label));
|
||||||
if (it != d.end()) return it->second;
|
if (it != d.end()) return it->second;
|
||||||
|
|
||||||
cout << "Error on " << yyline << ": ";
|
// If nothing else works, set valid to false.
|
||||||
exit(1);
|
v = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t readParenExpression(bool &valid, const string &s,
|
||||||
|
const map<string, Word> &d)
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
return rPE(valid, s, d, 0, s.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
int lexerFloatBytes;
|
int lexerFloatBytes;
|
||||||
@@ -355,9 +370,12 @@ Obj *AsmReader::read(std::istream &input) {
|
|||||||
default: asmReaderError(yyline, "Unexpected register");
|
default: asmReaderError(yyline, "Unexpected register");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ASM_T_PEXP:
|
case ASM_T_PEXP: {
|
||||||
// Decode the paren expression.
|
// Decode the paren expression.
|
||||||
yylval.u = readParenExpression(yylval.s, defs);
|
bool valid;
|
||||||
|
yylval.u = readParenExpression(valid, yylval.s, defs);
|
||||||
|
if (!valid) asmReaderError(yyline, "Invalid paren expression");
|
||||||
|
}
|
||||||
case ASM_T_LIT:
|
case ASM_T_LIT:
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case ST_INST1: asmReaderError(yyline, "Unexpected literal");
|
case ST_INST1: asmReaderError(yyline, "Unexpected literal");
|
||||||
|
|||||||
Reference in New Issue
Block a user