erikb@botter.UUCP (04/03/87)
Here's the source for expr(1). Like test(1), this program was not part of the Minix distribution. Unfortunately, I didn't have time to implement the ':' operator. Maybe there's someone else out there who will do the job... Erik Baalbergen -- cut here -- /* expr(1) -- author Erik Baalbergen */ /* expr accepts the following grammar: expr ::= expr operator expr | "(" expr ")" ; where the priority of the operators is taken care of. The resulting value is printed on stdout. Note that the ":"-operator is not implemented. */ #define EOI 0 #define OR 1 #define AND 2 #define LT 3 #define LE 4 #define EQ 5 #define NE 6 #define GE 7 #define GT 8 #define PLUS 9 #define MINUS 10 #define TIMES 11 #define DIV 12 #define MOD 13 #define COLON 14 #define LPAREN 15 #define RPAREN 16 #define OPERAND 20 #define MAXPRIO 6 struct op { char *op_text; short op_num, op_prio; } ops[] = { {"|", OR, 6}, {"&", AND, 5}, {"<", LT, 4}, {"<=", LE, 4}, {"=", EQ, 4}, {"!=", NE, 4}, {">=", GE, 4}, {">", GT, 4}, {"+", PLUS, 3}, {"-", MINUS, 3}, {"*", TIMES, 2}, {"/", DIV, 2}, {"%", MOD, 2}, /* {":", COLON, 1}, */ {"(", LPAREN, 0}, {")", RPAREN, 0}, {0, 0, 0} }; long eval(), expr(); char *prog; char **ip; struct op *ip_op; main(argc, argv) char *argv[]; { long res; prog = argv[0]; ip = &argv[1]; res = expr(lex(*ip), MAXPRIO); if (*++ip != 0) syntax(); printf("%ld\n", res); exit(0); } lex(s) register char *s; { register struct op *op = ops; if (s == 0) { ip_op = 0; return EOI; } while (op->op_text) { if (strcmp(s, op->op_text) == 0) { ip_op = op; return op->op_num; } op++; } ip_op = 0; return OPERAND; } long num(s) register char *s; { long l = 0; long sign = 1; if (*s == '\0') syntax(); if (*s == '-') { sign = -1; s++; } while (*s >= '0' && *s <= '9') l = l * 10 + *s++ - '0'; if (*s != '\0') syntax(); return sign * l; } syntax() { write(2, prog, strlen(prog)); write(2, ": syntax error\n", 15); exit(1); } long expr(n, prio) { long res; if (n == EOI) syntax(); if (n == LPAREN) { res = expr(lex(*++ip), MAXPRIO); if (lex(*++ip) != RPAREN) syntax(); return res; } if (n != OPERAND) syntax(); if (prio == 0) return num(*ip); res = expr(n, prio - 1); while ((n = lex(*++ip)) && ip_op && ip_op->op_prio == prio) res = eval(res, n, expr(lex(*++ip), prio - 1)); ip--; return res; } long eval(l1, op, l2) long l1, l2; { switch (op) { case OR: return l1 ? l1 : l2; case AND: return (l1 && l2) ? l1 : 0; case LT: return l1 < l2; case LE: return l1 <= l2; case EQ: return l1 == l2; case NE: return l1 != l2; case GE: return l1 >= l2; case GT: return l1 > l2; case PLUS: return l1 + l2; case MINUS: return l1 - l2; case TIMES: return l1 * l2; case DIV: return l1 / l2; case MOD: return l1 % l2; } fatal(); } fatal() { write(2, "fatal\n", 6); exit(1); }
brachman@ubc-cs.UUCP (04/11/87)
The version of expr.c posted by erikb@cs.vu.nl (Erik Baalbergen) has a bug. Try: expr '(' 1 ')' + 1 You'll get "syntax error". I'm about to post a version of expr(1) to net.sources that is almost compatible with the 4.[23] BSD version. The posting will include Henry Spencer's regular expression routines which are very useful even if you don't want my version of expr. By the way, the 4.[23] BSD expr has a bug. Try: expr 5 - 6 - 1 See my recent posting to comp.bugs.4bsd for the fix. ----- Barry Brachman | {ihnp4!alberta,uw-beaver,seismo}! Dept. of Computer Science| ubc-vision!ubc-cs!brachman Univ. of British Columbia| brachman@cs.ubc.cdn Vancouver, B.C. V6T 1W5 | brachman%ubc.csnet@csnet-relay.arpa (604) 228-4327 | brachman@ubc.csnet
erikb@botter.UUCP (04/13/87)
The following is a fix in reply to the bug (expr '(' 1 ')' + 1) as reported by Barry Brachman. The '<' lines refer to the bug version, the '>' to the fixed version. Erik Baalbergen -- cut here -- 4c4,5 < expr ::= expr operator expr | "(" expr ")" ; --- > expr ::= primary | primary operator expr ; > primary ::= '(' expr ')' | signed-integer ; 49,50c50,51 < {"(", LPAREN, 0}, < {")", RPAREN, 0}, --- > {"(", LPAREN, -1}, > {")", RPAREN, -1}, 128,131c129,135 < res = expr(lex(*++ip), MAXPRIO); < if (lex(*++ip) != RPAREN) < syntax(); < return res; --- > if (prio == 0) { > res = expr(lex(*++ip), MAXPRIO); > if (lex(*++ip) != RPAREN) > syntax(); > } > else > res = expr(n, prio - 1); 133c137,143 < if (n != OPERAND) --- > else > if (n == OPERAND) { > if (prio == 0) > return num(*ip); > res = expr(n, prio - 1); > } > else 135,137d144 < if (prio == 0) < return num(*ip); < res = expr(n, prio - 1);