Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | #include <stdlib.h> #include <ctype.h> /* grammar: Start = Expr ';' Expr = Or | Or '?' Expr ':' Expr Or = And | Or '||' And And = Eq | And '&&' Eq Eq = Rel | Eq '==' Rel | Eq '!=' Rel Rel = Add | Rel '<=' Add | Rel '>=' Add | Rel '<' Add | Rel '>' Add Add = Mul | Add '+' Mul | Add '-' Mul Mul = Prim | Mul '*' Prim | Mul '/' Prim | Mul '%' Prim Prim = '(' Expr ')' | '!' Prim | decimal | 'n' internals: recursive descent expression evaluator with stack depth limit. for binary operators an operator-precedence parser is used. eval* functions store the result of the parsed subexpression and return a pointer to the next non-space character. */ struct st { unsigned long r; unsigned long n; int op; }; static const char *skipspace(const char *s) { while (isspace(*s)) s++; return s; } static const char *evalexpr(struct st *st, const char *s, int d); static const char *evalprim(struct st *st, const char *s, int d) { char *e; if (--d < 0) return ""; s = skipspace(s); if (isdigit(*s)) { st->r = strtoul(s, &e, 10); if (e == s || st->r == -1) return ""; return skipspace(e); } if (*s == 'n') { st->r = st->n; return skipspace(s+1); } if (*s == '(') { s = evalexpr(st, s+1, d); if (*s != ')') return ""; return skipspace(s+1); } if (*s == '!') { s = evalprim(st, s+1, d); st->r = !st->r; return s; } return ""; } static int binop(struct st *st, int op, unsigned long left) { unsigned long a = left, b = st->r; switch (op) { case 0: st->r = a||b; return 0; case 1: st->r = a&&b; return 0; case 2: st->r = a==b; return 0; case 3: st->r = a!=b; return 0; case 4: st->r = a>=b; return 0; case 5: st->r = a<=b; return 0; case 6: st->r = a>b; return 0; case 7: st->r = a<b; return 0; case 8: st->r = a+b; return 0; case 9: st->r = a-b; return 0; case 10: st->r = a*b; return 0; case 11: if (b) {st->r = a%b; return 0;} return 1; case 12: if (b) {st->r = a/b; return 0;} return 1; } return 1; } static const char *parseop(struct st *st, const char *s) { static const char opch[11] = "|&=!><+-*%/"; static const char opch2[6] = "|&===="; int i; for (i=0; i<11; i++) if (*s == opch[i]) { /* note: >,< are accepted with or without = */ if (i<6 && s[1] == opch2[i]) { st->op = i; return s+2; } if (i>=4) { st->op = i+2; return s+1; } break; } st->op = 13; return s; } static const char *evalbinop(struct st *st, const char *s, int minprec, int d) { static const char prec[14] = {1,2,3,3,4,4,4,4,5,5,6,6,6,0}; unsigned long left; int op; d--; s = evalprim(st, s, d); s = parseop(st, s); for (;;) { /* st->r (left hand side value) and st->op are now set, get the right hand side or back out if op has low prec, if op was missing then prec[op]==0 */ op = st->op; if (prec[op] <= minprec) return s; left = st->r; s = evalbinop(st, s, prec[op], d); if (binop(st, op, left)) return ""; } } static const char *evalexpr(struct st *st, const char *s, int d) { unsigned long a, b; if (--d < 0) return ""; s = evalbinop(st, s, 0, d); if (*s != '?') return s; a = st->r; s = evalexpr(st, s+1, d); if (*s != ':') return ""; b = st->r; s = evalexpr(st, s+1, d); st->r = a ? b : st->r; return s; } unsigned long __pleval(const char *s, unsigned long n) { struct st st; st.n = n; s = evalexpr(&st, s, 100); return *s == ';' ? st.r : -1; } |