/* $NetBSD: expr.c,v 1.3 1995/04/28 23:27:15 jtc Exp $ */ /* * Written by J.T. Conklin . * Public domain. * converted to a library function by D'Arcy J.M. Cain * DJMC: I'd like to make this reentrant some day */ #include #include #include #include /* type used by xstrtok function */ typedef struct { char *scanpoint; /* filled in by xstrtok */ char *str2parse; /* string to parse - set for first call */ const char *delim; /* string of delimiters */ int quote; /* respect quoting if set */ } XSTRTOK; extern char *xstrtok(XSTRTOK *xinfo); /* The calling program is expected to have a fatal function */ void fatal(const char *s,...); enum token { OR, AND, EQ, LT, GT, ADD, SUB, MUL, DIV, MOD, MATCH, RP, LP, NE, LE, GE, OPERAND, EOI }; static int eval0(void); static enum token token; static int tokval; static XSTRTOK x; int expr(const char *str); static void nexttoken(void) { static char *p = NULL; static const char *opstr = "|&=<>+-*/%:()"; const char *i; /* just in case */ if (p) while (isspace((int) *p)) p++; if ((!p || !*p) && (p = xstrtok(&x)) == NULL) { token = EOI; return; } if ((*p == '-' && isdigit((int) p[1])) || isdigit((int) *p)) { tokval = strtol(p, &p, 0); token = OPERAND; return; } if ((i = strchr(opstr, *p)) == NULL) fatal("Invalid operator %s", p); if (p[1] == '=') { switch (*i) { case '<': token = LE; p += 2; return; case '>': token = GE; p += 2; return; case '!': token = NE; p += 2; return; } } token = i - opstr; p++; return; } static int eval5(void) { int v; if (token != OPERAND) { if (token == RP) { nexttoken(); v = eval0(); if (token != LP) fatal("Syntax error - token != LP"); nexttoken(); return v; } else fatal("Syntax error - token != RP"); } nexttoken(); return tokval; } /* Parse and evaluate multiplication and division expressions */ static int eval4(void) { enum token op; int l = eval5(), r; while ((op = token) == MUL || op == DIV || op == MOD) { nexttoken(); r = eval5(); if (op == MUL) l *= r; else { if (r == 0) fatal("division by zero"); if (op == DIV) l /= r; else l %= r; } } return l; } /* Parse and evaluate addition and subtraction expressions */ static int eval3(void) { int l = eval4(), r; enum token op; while ((op = token) == ADD || op == SUB) { nexttoken(); r = eval4(); if (op == ADD) l += r; else l -= r; } return l; } /* Parse and evaluate comparison expressions */ static int eval2(void) { int l, r; enum token op; l = eval3(); while ((op = token) == EQ || op == NE || op == LT || op == GT || op == LE || op == GE) { nexttoken(); r = eval3(); switch (op) { case GT: l = (l > r); break; case GE: l = (l >= r); break; case LT: l = (l < r); break; case LE: l = (l <= r); break; case EQ: l = (l == r); break; case NE: l = (l != r); break; default: fatal("Internal error"); } } return l; } /* Parse and evaluate & expressions */ static int eval1(void) { int l = eval2(); while (token == AND) { nexttoken(); l = (eval1() && l); } return l; } /* Parse and evaluate | expressions */ static int eval0(void) { int l = eval1(); while (token == OR) { nexttoken(); l = (eval1() || l); } return l; } int expr(const char *str) { int v; x.str2parse = strdup(str); x.delim = " "; x.quote = 0; nexttoken(); v = eval0(); if (token != EOI) { fatal("Syntax error - token != EOI", token); /* NOTREACHED */ } return v; }