ref: 5465d14bd9d6ff4712f6f298f6cbe5c1f714d4da
parent: ff817d5b1056871ec93b5c0c7d222175c1aace3f
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Apr 19 07:15:13 EDT 2020
fix cpp operator associativity We used to treat all operators as right associative, which means that we would evaluate them incorrecty. For example, '2 - 1 + 1' would evaluate as '2 - (1 + 2)', instead of '(2 - 1) + 1'. This adds an assoc parameter to struct pri, and then uses it to decide how to evaluate operators.
--- a/sys/src/cmd/cpp/eval.c
+++ b/sys/src/cmd/cpp/eval.c
@@ -15,80 +15,52 @@
};
/* conversion types */
-#define RELAT 1
-#define ARITH 2
-#define LOGIC 3
-#define SPCL 4
-#define SHIFT 5
-#define UNARY 6
+enum {+ NONE,
+ RELAT,
+ ARITH,
+ LOGIC,
+ SPCL,
+ SHIFT,
+ UNARY
+};
/* operator priority, arity, and conversion type, indexed by tokentype */
const struct pri {char pri;
+ char assoc;
char arity;
char ctype;
} priority[] = {- [END] { 0, 0, 0 },- [UNCLASS] { 0, 0, 0 },- [NAME] { 0, 0, 0 },- [NUMBER] { 0, 0, 0 },- [STRING] { 0, 0, 0 },- [CCON] { 0, 0, 0 },- [NL] { 0, 0, 0 },- [WS] { 0, 0, 0 },- [DSHARP] { 0, 0, 0 },- [EQ] { 11, 2, RELAT },- [NEQ] { 11, 2, RELAT },- [LEQ] { 12, 2, RELAT },- [GEQ] { 12, 2, RELAT },- [LSH] { 13, 2, SHIFT },- [RSH] { 13, 2, SHIFT },- [LAND] { 7, 2, LOGIC },- [LOR] { 6, 2, LOGIC },- [PPLUS] { 0, 0, 0 },- [MMINUS] { 0, 0, 0 },- [ARROW] { 0, 0, 0 },- [SBRA] { 0, 0, 0 },- [SKET] { 0, 0, 0 },- [LP] { 3, 0, 0 },- [RP] { 3, 0, 0 },- [DOT] { 0, 0, 0 },- [AND] { 10, 2, ARITH },- [STAR] { 15, 2, ARITH },- [PLUS] { 14, 2, ARITH },- [MINUS] { 14, 2, ARITH },- [TILDE] { 16, 1, UNARY },- [NOT] { 16, 1, UNARY },- [SLASH] { 15, 2, ARITH },- [PCT] { 15, 2, ARITH },- [LT] { 12, 2, RELAT },- [GT] { 12, 2, RELAT },- [CIRC] { 9, 2, ARITH },- [OR] { 8, 2, ARITH },- [QUEST] { 5, 2, SPCL },- [COLON] { 5, 2, SPCL },- [ASGN] { 0, 0, 0 },- [COMMA] { 4, 2, 0 },- [XCOMMA] { 4, 2, 0 },- [SHARP] { 0, 0, 0 },- [SEMIC] { 0, 0, 0 },- [CBRA] { 0, 0, 0 },- [CKET] { 0, 0, 0 },- [ASPLUS] { 0, 0, 0 },- [ASMINUS] { 0, 0, 0 },- [ASSTAR] { 0, 0, 0 },- [ASSLASH] { 0, 0, 0 },- [ASPCT] { 0, 0, 0 },- [ASCIRC] { 0, 0, 0 },- [ASLSH] { 0, 0, 0 },- [ASRSH] { 0, 0, 0 },- [ASOR] { 0, 0, 0 },- [ASAND] { 0, 0, 0 },- [ELLIPS] { 0, 0, 0 },- [DSHARP1] { 0, 0, 0 },- [NAME1] { 0, 0, 0 },- [DEFINED] { 16, 1, UNARY },- [UMINUS] { 16, 0, UNARY },+ [END] { 0, 0, 0, 0 },+ [EQ] { 11, 0, 2, RELAT },+ [NEQ] { 11, 0, 2, RELAT },+ [LEQ] { 12, 0, 2, RELAT },+ [GEQ] { 12, 0, 2, RELAT },+ [LSH] { 13, 0, 2, SHIFT },+ [RSH] { 13, 0, 2, SHIFT },+ [LAND] { 7, 0, 2, LOGIC },+ [LOR] { 6, 0, 2, LOGIC },+ [LP] { 3, 1, 0, 0 },+ [RP] { 3, 1, 0, 0 },+ [AND] { 10, 0, 2, ARITH },+ [STAR] { 15, 0, 2, ARITH },+ [PLUS] { 14, 0, 2, ARITH },+ [MINUS] { 14, 0, 2, ARITH },+ [TILDE] { 16, 0, 1, UNARY },+ [NOT] { 16, 0, 1, UNARY },+ [SLASH] { 15, 0, 2, ARITH },+ [PCT] { 15, 0, 2, ARITH },+ [LT] { 12, 0, 2, RELAT },+ [GT] { 12, 0, 2, RELAT },+ [CIRC] { 9, 0, 2, ARITH },+ [OR] { 8, 0, 2, ARITH },+ [QUEST] { 5, 1, 2, SPCL },+ [COLON] { 5, 1, 2, SPCL },+ [COMMA] { 4, 0, 2, 0 },+ [XCOMMA] { 4, 0, 2, 0 },+ [DEFINED] { 16, 0, 1, UNARY },+ [UMINUS] { 16, 0, 0, UNARY },};
int evalop(struct pri);
@@ -98,6 +70,7 @@
/*
* Evaluate an #if #elif #ifdef #ifndef line. trp->tp points to the keyword.
+ * Using shunting yard algorithm.
*/
vlong
eval(Tokenrow *trp, int kw)
@@ -121,7 +94,6 @@
kwdefined->val = NAME;
vp = vals;
op = ops;
- *op++ = END;
for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) { switch(tp->type) {case WS:
@@ -211,7 +183,7 @@
goto syntax;
if (evalop(priority[END])!=0)
return 0;
- if (op!=&ops[1] || vp!=&vals[1]) {+ if (op!=ops || vp!=&vals[1]) {error(ERROR, "Botch in #if/#elif");
return 0;
}
@@ -219,7 +191,7 @@
error(ERROR, "Undefined expression value");
return vals[0].val;
syntax:
- error(ERROR, "Syntax error in #if/#elif");
+ error(ERROR, "Syntax xx error in #if/#elif");
return 0;
fullstakdeveloper:
error(ERROR, "Out of stack space evaluating #if");
@@ -235,7 +207,7 @@
rv2=0;
rtype=0;
- while (pri.pri < priority[op[-1]].pri) {+ while (op != ops && pri.pri + pri.assoc <= priority[op[-1]].pri) {oper = *--op;
if (priority[oper].arity==2) {v2 = *--vp;
--
⑨