diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
commit | 3950ffe2a485479f6561c27364d3d7df5a21d124 (patch) | |
tree | 468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libast/string/strexpr.c | |
download | ksh-3950ffe2a485479f6561c27364d3d7df5a21d124.tar.gz |
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/lib/libast/string/strexpr.c')
-rw-r--r-- | src/lib/libast/string/strexpr.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/src/lib/libast/string/strexpr.c b/src/lib/libast/string/strexpr.c new file mode 100644 index 0000000..23be2f5 --- /dev/null +++ b/src/lib/libast/string/strexpr.c @@ -0,0 +1,294 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * G. S. Fowler + * D. G. Korn + * AT&T Bell Laboratories + * + * long integer arithmetic expression evaluator + * long constants may be represented as: + * + * 0ooo octal + * 0[xX]hhh hexadecimal + * ddd decimal + * n#ccc base n, 2 <= b <= 36 + * + * NOTE: all operands are evaluated as both the parse + * and evaluation are done on the fly + */ + +#include <ast.h> +#include <ctype.h> + +#define getchr(ex) (*(ex)->nextchr++) +#define peekchr(ex) (*(ex)->nextchr) +#define ungetchr(ex) ((ex)->nextchr--) + +#define error(ex,msg) return(seterror(ex,msg)) + +typedef struct /* expression handle */ +{ + char* nextchr; /* next expression char */ + char* errchr; /* next char after error */ + char* errmsg; /* error message text */ + long (*convert)(const char*, char**, void*); + void* handle; /* user convert handle */ +} Expr_t; + +/* + * set error message string + */ + +static long +seterror(register Expr_t* ex, char* msg) +{ + if (!ex->errmsg) ex->errmsg = msg; + ex->errchr = ex->nextchr; + ex->nextchr = ""; + return(0); +} + +/* + * evaluate a subexpression with precedence + */ + +static long +expr(register Expr_t* ex, register int precedence) +{ + register int c; + register long n; + register long x; + char* pos; + int operand = 1; + + while (c = getchr(ex), isspace(c)); + switch (c) + { + case 0: + ungetchr(ex); + if (!precedence) return(0); + error(ex, "more tokens expected"); + case '-': + n = -expr(ex, 13); + break; + case '+': + n = expr(ex, 13); + break; + case '!': + n = !expr(ex, 13); + break; + case '~': + n = ~expr(ex, 13); + break; + default: + ungetchr(ex); + n = 0; + operand = 0; + break; + } + for (;;) + { + switch (c = getchr(ex)) + { + case 0: + goto done; + case ')': + if (!precedence) error(ex, "too many )'s"); + goto done; + case '(': + n = expr(ex, 1); + if (getchr(ex) != ')') + { + ungetchr(ex); + error(ex, "closing ) expected"); + } + gotoperand: + if (operand) error(ex, "operator expected"); + operand = 1; + continue; + case '?': + if (precedence > 1) goto done; + if (peekchr(ex) == ':') + { + getchr(ex); + x = expr(ex, 2); + if (!n) n = x; + } + else + { + x = expr(ex, 2); + if (getchr(ex) != ':') + { + ungetchr(ex); + error(ex, ": expected for ? operator"); + } + if (n) + { + n = x; + expr(ex, 2); + } + else n = expr(ex, 2); + } + break; + case ':': + goto done; + case '|': + if (peekchr(ex) == '|') + { + if (precedence > 2) goto done; + getchr(ex); + x = expr(ex, 3); + n = n || x; + } + else + { + if (precedence > 4) goto done; + x = expr(ex, 5); + n |= x; + } + break; + case '^': + if (precedence > 5) goto done; + x = expr(ex, 6); + n ^= x; + break; + case '&': + if (peekchr(ex) == '&') + { + if (precedence > 3) goto done; + getchr(ex); + x = expr(ex, 4); + n = n && x; + } + else + { + if (precedence > 6) goto done; + x = expr(ex, 7); + n &= x; + } + break; + case '=': + case '!': + if (peekchr(ex) != '=') error(ex, "operator syntax error"); + if (precedence > 7) goto done; + getchr(ex); + x = expr(ex, 8); + if (c == '=') n = n == x; + else n = n != x; + break; + case '<': + case '>': + if (peekchr(ex) == c) + { + if (precedence > 9) goto done; + getchr(ex); + x = expr(ex, 10); + if (c == '<') n <<= x; + else n >>= x; + } + else + { + if (precedence > 8) goto done; + if (peekchr(ex) == '=') + { + getchr(ex); + x = expr(ex, 9); + if (c == '<') n = n <= x; + else n = n >= x; + } + else + { + x = expr(ex, 9); + if (c == '<') n = n < x; + else n = n > x; + } + } + break; + case '+': + case '-': + if (precedence > 10) goto done; + x = expr(ex, 11); + if (c == '+') n += x; + else n -= x; + break; + case '*': + case '/': + case '%': + if (precedence > 11) goto done; + x = expr(ex, 12); + if (c == '*') n *= x; + else if (x == 0) error(ex, "divide by zero"); + else if (c == '/') n /= x; + else n %= x; + break; + default: + if (isspace(c)) continue; + pos = --ex->nextchr; + if (isdigit(c)) n = strton(ex->nextchr, &ex->nextchr, NiL, 0); + else if (ex->convert) n = (*ex->convert)(ex->nextchr, &ex->nextchr, ex->handle); + if (ex->nextchr == pos) error(ex, "syntax error"); + goto gotoperand; + } + if (ex->errmsg) return(0); + if (!operand) error(ex, "operand expected"); + } + done: + ungetchr(ex); + if (!operand) error(ex, "operand expected"); + return(n); +} + +/* + * evaluate an integer arithmetic expression in s + * + * (long)(*convert)(const char* string, char** end, void* handle) + * is a user supplied conversion routine that is called when unknown + * chars are encountered; string points to the part to be + * converted and end is adjusted to point to the next non-converted + * character; if string is 0 then end points to an error message string + * + * NOTE: (*convert)() may call strexpr(ex, ) + */ + +long +strexpr(const char* s, char** end, long(*convert)(const char*, char**, void*), void* handle) +{ + long n; + Expr_t ex; + + ex.nextchr = (char*)s; + ex.errmsg = 0; + ex.convert = convert; + ex.handle = handle; + n = expr(&ex, 0); + if (peekchr(&ex) == ':') + seterror(&ex, "invalid use of :"); + if (ex.errmsg) + { + if (convert) (*convert)(NiL, &ex.errmsg, handle); + ex.nextchr = ex.errchr; + n = 0; + } + if (end) *end = ex.nextchr; + return(n); +} |