diff options
author | chin <none@none> | 2007-08-17 12:01:52 -0700 |
---|---|---|
committer | chin <none@none> | 2007-08-17 12:01:52 -0700 |
commit | da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch) | |
tree | 5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libpp/common/ppexpr.c | |
parent | 073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff) | |
download | illumos-joyent-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz |
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93
PSARC/2006/550 Korn Shell 93 Integration
PSARC/2006/587 /etc/ksh.kshrc for ksh93
PSARC/2007/035 ksh93 Amendments
Contributed by Roland Mainz <roland.mainz@nrubsig.org>
--HG--
rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers
rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libpp/common/ppexpr.c')
-rw-r--r-- | usr/src/lib/libpp/common/ppexpr.c | 697 |
1 files changed, 697 insertions, 0 deletions
diff --git a/usr/src/lib/libpp/common/ppexpr.c b/usr/src/lib/libpp/common/ppexpr.c new file mode 100644 index 0000000000..5fd93afde5 --- /dev/null +++ b/usr/src/lib/libpp/common/ppexpr.c @@ -0,0 +1,697 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor expression evaluation support + */ + +#include "pplib.h" + +#include <regex.h> + +#define lex(c) ((((c)=peektoken)>=0?(peektoken=(-1)):((c)=pplex())),(c)) +#define unlex(c) (peektoken=(c)) + +static int peektoken; /* expression lookahead token */ +static char* errmsg; /* subexpr() error message */ + +/* + * exists predicate evaluation + */ + +static int +exists(int op, char* pred, register char* args) +{ + register int c; + register int type; + char* pptoken; + long state; + char file[MAXTOKEN + 1]; + + state = (pp.state & ~DISABLE); + PUSH_STRING(args); + pptoken = pp.token; + pp.token = file; + pp.state |= HEADER|PASSEOF; + type = pplex(); + pp.state &= ~HEADER; + pp.token = pptoken; + switch (type) + { + case T_STRING: + case T_HEADER: + break; + default: + error(1, "%s: \"...\" or <...> argument expected", pred); + c = 0; + goto done; + } + if (op == X_EXISTS) + { + if ((c = pplex()) == ',') + { + while ((c = pplex()) == T_STRING) + { + if (pathaccess(pp.path, pp.token, file, NiL, 0)) + { + pathcanon(pp.path, 0); + message((-2, "%s: %s found", pred, pp.path)); + c = 1; + goto done; + } + if ((c = pplex()) != ',') break; + } + if (c) error(1, "%s: \"...\" arguments expected", pred); + strcpy(pp.path, file); + message((-2, "%s: %s not found", pred, file)); + c = 0; + } + else c = ppsearch(file, type, SEARCH_EXISTS) >= 0; + } + else + { + register struct ppfile* fp; + + fp = ppsetfile(file); + c = fp->flags || fp->guard == INC_IGNORE; + } + done: + while (pplex()); + pp.state = state; + return c; +} + +/* + * strcmp/match predicate evaluation + */ + +static int +compare(char* pred, char* args, int match) +{ + register int c; + char* pptoken; + long state; + regex_t re; + char tmp[MAXTOKEN + 1]; + + state = (pp.state & ~DISABLE); + PUSH_STRING(args); + pp.state |= PASSEOF; + pptoken = pp.token; + pp.token = tmp; + if (!pplex()) + goto bad; + pp.token = pptoken; + if (pplex() != ',' || !pplex()) + goto bad; + if (!match) + c = strcmp(tmp, pp.token); + else if ((c = regcomp(&re, pp.token, REG_AUGMENTED|REG_LENIENT|REG_NULL)) || (c = regexec(&re, tmp, NiL, 0, 0)) && c != REG_NOMATCH) + regfatal(&re, 3, c); + else + { + c = !c; + regfree(&re); + } + if ((pp.state & PASSEOF) && pplex()) + goto bad; + pp.state = state; + return c; + bad: + pp.token = pptoken; + error(2, "%s: 2 arguments expected", pred); + while (pplex()); + pp.state = state; + return 0; +} + +/* + * #if predicate parse and evaluation + */ + +static int +predicate(int warn) +{ + register char* args; + register struct pplist* p; + register struct ppsymbol* sym; + register int type; + int index; + + static char pred[MAXID + 1]; + + /* + * first gather the args + */ + + index = (int)hashref(pp.strtab, pp.token); + if (warn && peekchr() != '(') switch (index) + { + case X_DEFINED: + case X_EXISTS: + case X_INCLUDED: + case X_MATCH: + case X_NOTICED: + case X_OPTION: + case X_SIZEOF: + case X_STRCMP: + break; + default: + if (pp.macref) pprefmac(pp.token, REF_IF); + return 0; + } + strcpy(pred, pp.token); + pp.state |= DISABLE; + type = pppredargs(); + pp.state &= ~DISABLE; + switch (type) + { + case T_ID: + case T_STRING: + break; + default: + unlex(type); + /*FALLTHROUGH*/ + case 0: + if (index && !(pp.state & STRICT)) + error(1, "%s: predicate argument expected", pred); + if (pp.macref) pprefmac(pred, REF_IF); + return 0; + } + args = pp.args; + + /* + * now evaluate + */ + + debug((-6, "pred=%s args=%s", pred, args)); + if ((pp.state & STRICT) && !(pp.mode & HOSTED)) switch (index) + { + case X_DEFINED: + case X_SIZEOF: + break; + default: + error(1, "%s(%s): non-standard predicate test", pred, args); + return 0; + } + switch (index) + { + case X_DEFINED: + if (type != T_ID) error(1, "%s: identifier argument expected", pred); + else if ((sym = pprefmac(args, REF_IF)) && sym->macro) return 1; + else if (args[0] == '_' && args[1] == '_' && !strncmp(args, "__STDPP__", 9)) + { + if (pp.hosted == 1 && pp.in->prev->type == IN_FILE) + { + pp.mode |= HOSTED; + pp.flags |= PP_hosted; + } + return *(args + 9) ? (int)hashref(pp.strtab, args + 9) : 1; + } + break; + case X_EXISTS: + case X_INCLUDED: + return exists(index, pred, args); + case X_MATCH: + case X_STRCMP: + return compare(pred, args, index == X_MATCH); + case X_NOTICED: + if (type != T_ID) error(1, "%s: identifier argument expected", pred); + else if (((sym = pprefmac(args, REF_IF)) || (sym = ppsymref(pp.symtab, args))) && (sym->flags & SYM_NOTICED)) return 1; + break; + case X_OPTION: + return ppoption(args); + case X_SIZEOF: + error(2, "%s invalid in #%s expressions", pred, dirname(IF)); + break; + default: + if (warn && !(pp.mode & HOSTED) && (sym = ppsymref(pp.symtab, pred)) && (sym->flags & SYM_PREDICATE)) + error(1, "use #%s(%s) to disambiguate", pred, args); + if (p = (struct pplist*)hashget(pp.prdtab, pred)) + { + if (!*args) return 1; + while (p) + { + if (streq(p->value, args)) return 1; + p = p->next; + } + } + break; + } + return 0; +} + +/* + * evaluate a long integer subexpression with precedence + * taken from the library routine streval() + * may be called recursively + * + * NOTE: all operands are evaluated as both the parse + * and evaluation are done on the fly + */ + +static long +subexpr(register int precedence, int* pun) +{ + register int c; + register long n; + register long x; + register int operand = 1; + int un = 0; + int xn; + + switch (lex(c)) + { + case 0: + case '\n': + unlex(c); + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "more tokens expected"; + return 0; + case '-': + n = -subexpr(13, &un); + break; + case '+': + n = subexpr(13, &un); + break; + case '!': + n = !subexpr(13, &un); + break; + case '~': + n = ~subexpr(13, &un); + break; + default: + unlex(c); + n = 0; + operand = 0; + break; + } + un <<= 1; + for (;;) + { + switch (lex(c)) + { + case 0: + case '\n': + goto done; + case ')': + if (!precedence) + { + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "too many )'s"; + return 0; + } + goto done; + case '(': + n = subexpr(1, &un); + if (lex(c) != ')') + { + unlex(c); + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "closing ) expected"; + return 0; + } + gotoperand: + if (operand) + { + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operator expected"; + return 0; + } + operand = 1; + un <<= 1; + continue; + case '?': + if (precedence > 1) goto done; + un = 0; + if (lex(c) == ':') + { + if (!n) n = subexpr(2, &un); + else + { + x = pp.mode; + pp.mode |= INACTIVE; + subexpr(2, &xn); + pp.mode = x; + } + } + else + { + unlex(c); + x = subexpr(2, &xn); + if (lex(c) != ':') + { + unlex(c); + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = ": expected for ? operator"; + return 0; + } + if (n) + { + n = x; + un = xn; + subexpr(2, &xn); + } + else n = subexpr(2, &un); + } + break; + case ':': + goto done; + case T_ANDAND: + case T_OROR: + xn = (c == T_ANDAND) ? 4 : 3; + if (precedence >= xn) goto done; + if ((n != 0) == (c == T_ANDAND)) n = subexpr(xn, &un) != 0; + else + { + x = pp.mode; + pp.mode |= INACTIVE; + subexpr(xn, &un); + pp.mode = x; + } + un = 0; + break; + case '|': + if (precedence > 4) goto done; + n |= subexpr(5, &un); + break; + case '^': + if (precedence > 5) goto done; + n ^= subexpr(6, &un); + break; + case '&': + if (precedence > 6) goto done; + n &= subexpr(7, &un); + break; + case T_EQ: + case T_NE: + if (precedence > 7) goto done; + n = (n == subexpr(8, &un)) == (c == T_EQ); + un = 0; + break; + case '<': + case T_LE: + case T_GE: + case '>': + if (precedence > 8) goto done; + x = subexpr(9, &un); + switch (c) + { + case '<': + switch (un) + { + case 01: + n = n < (unsigned long)x; + break; + case 02: + n = (unsigned long)n < x; + break; + case 03: + n = (unsigned long)n < (unsigned long)x; + break; + default: + n = n < x; + break; + } + break; + case T_LE: + switch (un) + { + case 01: + n = n <= (unsigned long)x; + break; + case 02: + n = (unsigned long)n <= x; + break; + case 03: + n = (unsigned long)n <= (unsigned long)x; + break; + default: + n = n <= x; + break; + } + break; + case T_GE: + switch (un) + { + case 01: + n = n >= (unsigned long)x; + break; + case 02: + n = (unsigned long)n >= x; + break; + case 03: + n = (unsigned long)n >= (unsigned long)x; + break; + default: + n = n >= x; + break; + } + break; + case '>': + switch (un) + { + case 01: + n = n > (unsigned long)x; + break; + case 02: + n = (unsigned long)n > x; + break; + case 03: + n = (unsigned long)n > (unsigned long)x; + break; + default: + n = n > x; + break; + } + break; + } + un = 0; + break; + case T_LSHIFT: + case T_RSHIFT: + if (precedence > 9) goto done; + x = subexpr(10, &un); + if (c == T_LSHIFT) n <<= x; + else n >>= x; + un >>= 1; + break; + case '+': + case '-': + if (precedence > 10) goto done; + x = subexpr(11, &un); + if (c == '+') n += x; + else n -= x; + break; + case '*': + case '/': + case '%': + if (precedence > 11) goto done; + x = subexpr(12, &un); + if (c == '*') n *= x; + else if (x == 0) + { + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "divide by zero"; + return 0; + } + else if (c == '/') n /= x; + else n %= x; + break; + case '#': + pp.state |= DISABLE; + c = pplex(); + pp.state &= ~DISABLE; + if (c != T_ID) + { + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "# must precede a predicate identifier"; + return 0; + } + n = predicate(0); + goto gotoperand; + case T_ID: + n = predicate(1); + goto gotoperand; + case T_CHARCONST: + c = *(pp.toknxt - 1); + *(pp.toknxt - 1) = 0; + n = chrtoi(pp.token + 1); + *(pp.toknxt - 1) = c; + if (n & ~((1<<CHAR_BIT)-1)) + { + if (!(pp.mode & HOSTED)) + error(1, "'%s': multi-character character constants are not portable", pp.token); + } +#if CHAR_MIN < 0 + else n = (char)n; +#endif + goto gotoperand; + case T_DECIMAL_U: + case T_DECIMAL_UL: + case T_OCTAL_U: + case T_OCTAL_UL: + case T_HEXADECIMAL_U: + case T_HEXADECIMAL_UL: + un |= 01; + /*FALLTHROUGH*/ + case T_DECIMAL: + case T_DECIMAL_L: + case T_OCTAL: + case T_OCTAL_L: + case T_HEXADECIMAL: + case T_HEXADECIMAL_L: + n = strtoul(pp.token, NiL, 0); + if ((unsigned long)n > LONG_MAX) un |= 01; + goto gotoperand; + case T_WCHARCONST: + n = chrtoi(pp.token); + goto gotoperand; + default: + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid token"; + return 0; + } + if (errmsg) return 0; + if (!operand) goto nooperand; + } + done: + unlex(c); + if (!operand) + { + nooperand: + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operand expected"; + return 0; + } + if (un) *pun |= 01; + return n; +} + +/* + * preprocessor expression evaluator using modified streval(3) + * *pun!=0 if result is unsigned + */ + +long +ppexpr(int* pun) +{ + long n; + int opeektoken; + long ppstate; + + ppstate = (pp.state & (CONDITIONAL|DISABLE|NOSPACE|STRIP)); + pp.state &= ~(DISABLE|STRIP); + pp.state |= CONDITIONAL|NOSPACE; + opeektoken = peektoken; + peektoken = -1; + *pun = 0; + n = subexpr(0, pun); + if (peektoken == ':' && !errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid use of :"; + if (errmsg) + { + error(2, "%s in expression", errmsg); + errmsg = 0; + n = 0; + } + peektoken = opeektoken; + pp.state &= ~(CONDITIONAL|NOSPACE); + pp.state |= ppstate; + if (*pun) debug((-4, "ppexpr() = %luU", n)); + else debug((-4, "ppexpr() = %ld", n)); + return n; +} + +/* + * return non-zero if option s is set + */ + +int +ppoption(char* s) +{ + switch ((int)hashget(pp.strtab, s)) + { + case X_ALLMULTIPLE: + return pp.mode & ALLMULTIPLE; + case X_BUILTIN: + return pp.mode & BUILTIN; + case X_CATLITERAL: + return pp.mode & CATLITERAL; + case X_COMPATIBILITY: + return pp.state & COMPATIBILITY; + case X_DEBUG: + return -error_info.trace; + case X_ELSEIF: + return pp.option & ELSEIF; + case X_FINAL: + return pp.option & FINAL; + case X_HOSTDIR: + return pp.mode & HOSTED; + case X_HOSTED: + return pp.flags & PP_hosted; + case X_INITIAL: + return pp.option & INITIAL; + case X_KEYARGS: + return pp.option & KEYARGS; + case X_LINEBASE: + return pp.flags & PP_linebase; + case X_LINEFILE: + return pp.flags & PP_linefile; + case X_LINETYPE: + return pp.flags & PP_linetype; + case X_PLUSCOMMENT: + return pp.option & PLUSCOMMENT; + case X_PLUSPLUS: + return pp.option & PLUSPLUS; + case X_PLUSSPLICE: + return pp.option & PLUSSPLICE; + case X_PRAGMAEXPAND: + return pp.option & PRAGMAEXPAND; + case X_PREDEFINED: + return pp.option & PREDEFINED; + case X_PREFIX: + return pp.option & PREFIX; + case X_PROTOTYPED: + return pp.option & PROTOTYPED; + case X_READONLY: + return pp.mode & READONLY; + case X_REGUARD: + return pp.option & REGUARD; + case X_SPACEOUT: + return pp.state & SPACEOUT; + case X_SPLICECAT: + return pp.option & SPLICECAT; + case X_SPLICESPACE: + return pp.option & SPLICESPACE; + case X_STRICT: + return pp.state & STRICT; + case X_STRINGSPAN: + return pp.option & STRINGSPAN; + case X_STRINGSPLIT: + return pp.option & STRINGSPLIT; + case X_TEST: + return pp.test; + case X_TEXT: + return !(pp.state & NOTEXT); + case X_TRANSITION: + return pp.state & TRANSITION; + case X_TRUNCATE: + return pp.truncate; + case X_WARN: + return pp.state & WARN; + default: + if (pp.state & WARN) error(1, "%s: unknown option name", s); + return 0; + } +} |