ref: 15a32f06839819cbbf6f40dccc5189c66379bcc0
parent: 2c596d0021299bdeb05bb92866c150b8e43977e9
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;