home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1991, John F. Haugh II
- * All rights reserved.
- *
- * Permission is granted to copy and create derivative works for any
- * non-commercial purpose, provided this copyright notice is preserved
- * in all copies of source code, or included in human readable form
- * and conspicuously displayed on all copies of object code or
- * distribution media.
- */
-
- #ifndef lint
- static char sccsid[] = "@(#)expr.c 2.2 09:26:00 2/27/91";
- #endif
-
- #include <ctype.h>
-
- /*
- * number - parse numbers
- */
-
- static int
- number (cpp, result)
- char **cpp;
- long *result;
- {
- char *cp = *cpp;
- char *ep;
- char buf[101];
- int i;
- int base;
- long value;
-
- if (! isdigit (*cp))
- return -1;
-
- if (*cp == '0' && *(cp + 1) == 'x') {
- base = 16;
- cp += 2;
- for (i = 0;*cp && isxdigit (*cp);)
- buf[i++] = *cp++;
- } else if (*cp == '0') {
- base = 8;
- cp += 1;
- for (i = 0;*cp && *cp >= '0' && *cp <= '7';)
- buf[i++] = *cp++;
- } else {
- base = 10;
- for (i = 0;*cp && isdigit (*cp);)
- buf[i++] = *cp++;
- }
- buf[i] = '\0';
- *result = strtol (buf, &ep, base);
- if (*ep) {
- *cpp = *cpp + (ep - buf);
- return -1;
- }
- *cpp = cp;
- return 0;
- }
-
- /*
- * symbol - lookup symbol names
- */
-
- static int
- symbol (cpp, result)
- char **cpp;
- long *result;
- {
- char *cp = *cpp;
- char buf[101]; /* yes, the longest symbol is 100 characters */
- int i;
-
- buf[0] = '_'; i = 1;
-
- if (*cp != '_' && ! isalpha (*cp))
- return -1;
-
- while (i < 100 && (*cp == '_' || isalpha (*cp) || isdigit (*cp)))
- buf[i++] = *cp++;
-
- if (i == 100) {
- *cpp = cp;
- return -1;
- }
- buf[i++] = '\0';
-
- if ((*result = sym2addr (buf + 1, 0)) == -1 &&
- (*result = sym2addr (buf, 0)) == -1)
- return -1;
-
- *cpp = cp;
- return 0;
- }
-
- /*
- * term - parse terms
- *
- * <term> ::= '(' <expr> ')' | <number> | <symbol> | '-' <number
- */
-
- static int
- term (cpp, result)
- char **cpp;
- long *result;
- {
- char *cp = *cpp;
-
- while (*cp && isspace (*cp))
- cp++;
-
- if (isdigit (*cp)) {
- if (number (&cp, result)) {
- *cpp = cp;
- return -1;
- }
- } else if (*cp == '_' || isalpha (*cp)) {
- if (symbol (&cp, result)) {
- *cpp = cp;
- return -1;
- }
- } else if (*cp == '(') {
- cp++;
- if (expr (&cp, result)) {
- *cpp = cp;
- return -1;
- }
- while (*cp && isspace (*cp))
- cp++;
-
- if (*cp != ')') {
- *cpp = cp;
- return -1;
- }
- cp++;
- } else if (*cp == '-') {
- cp++;
- if (number (&cp, result)) {
- *cpp = cp;
- return -1;
- }
- *result = - *result;
- } else
- return -1;
-
- *cpp = cp;
- return 0;
- }
-
- /*
- * prod - parse expressions
- *
- * <prod> ::= <prod> ('*' | '/' | '%' | '&') <term> | <term>
- */
-
- static int
- prod (cpp, result)
- char **cpp;
- long *result;
- {
- long left, right;
- enum { star, slash, percent, ampersand } op;
- char *cp = *cpp;
-
- while (*cp && isspace (*cp))
- cp++;
-
- if (term (&cp, &left)) {
- *cpp = cp;
- return -1;
- }
- while (*cp) {
- while (*cp && isspace (*cp))
- cp++;
-
- if (! *cp)
- break;
-
- switch (*cp) {
- case '+':
- case '-':
- case '|':
- case '^':
- case ')': *cpp = cp;
- *result = left;
- return 0;
- case '*': op = star; break;
- case '/': op = slash; break;
- case '%': op = percent; break;
- case '&': op = ampersand; break;
- default: *cpp = cp;
- return -1;
- }
- cp++;
- if (term (&cp, &right)) {
- *cpp = cp;
- return -1;
- }
- switch (op) {
- case star: left *= right; break;
- case slash: if (right == 0)
- return -1;
- left /= right; break;
- case percent: if (right == 0)
- return -1;
- left %= right; break;
- case ampersand: left &= right; break;
- }
- }
- *result = left;
- *cpp = cp;
- return 0;
- }
-
- /*
- * expr - parse expressions
- *
- * <expr> ::= <expr> ('+' | '-' | '|' | '^') <prod> | <prod>
- */
-
- int
- expr (cpp, result)
- char **cpp;
- long *result;
- {
- long left, right;
- enum { plus, minus, pipe, caret } op;
- char *cp = *cpp;
-
- while (*cp && isspace (*cp))
- cp++;
-
- if (prod (&cp, &left)) {
- *cpp = cp;
- return -1;
- }
- while (*cp) {
- while (*cp && isspace (*cp))
- cp++;
-
- if (! *cp)
- break;
-
- switch (*cp) {
- case '+': op = plus; break;
- case '-': op = minus; break;
- case '|': op = pipe; break;
- case '^': op = caret; break;
- default: *cpp = cp;
- return -1;
- }
- cp++;
- if (prod (&cp, &right)) {
- *cpp = cp;
- return -1;
- }
- switch (op) {
- case plus: left += right; break;
- case minus: left -= right; break;
- case pipe: left |= right; break;
- case caret: left ^= right; break;
- }
- }
- *result = left;
- *cpp = cp;
- return 0;
- }
-