Home | History | Annotate | Line # | Download | only in ksh
expr.c revision 1.11
      1  1.11     joerg /*	$NetBSD: expr.c,v 1.11 2017/07/01 23:12:08 joerg Exp $	*/
      2   1.2       tls 
      3   1.1       jtc /*
      4   1.1       jtc  * Korn expression evaluation
      5   1.1       jtc  */
      6   1.1       jtc /*
      7   1.1       jtc  * todo: better error handling: if in builtin, should be builtin error, etc.
      8   1.1       jtc  */
      9   1.5       agc #include <sys/cdefs.h>
     10   1.5       agc 
     11   1.5       agc #ifndef lint
     12  1.11     joerg __RCSID("$NetBSD: expr.c,v 1.11 2017/07/01 23:12:08 joerg Exp $");
     13   1.5       agc #endif
     14   1.5       agc 
     15   1.1       jtc 
     16   1.1       jtc #include "sh.h"
     17   1.1       jtc #include <ctype.h>
     18  1.10     kamil #include <stdbool.h>
     19   1.1       jtc 
     20   1.1       jtc /* The order of these enums is constrained by the order of opinfo[] */
     21   1.1       jtc enum token {
     22   1.1       jtc 	/* some (long) unary operators */
     23   1.1       jtc 	O_PLUSPLUS = 0, O_MINUSMINUS,
     24   1.1       jtc 	/* binary operators */
     25   1.1       jtc 	O_EQ, O_NE,
     26   1.1       jtc 	/* assignments are assumed to be in range O_ASN .. O_BORASN */
     27   1.1       jtc 	O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
     28   1.1       jtc 	       O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
     29   1.1       jtc 	O_LSHIFT, O_RSHIFT,
     30   1.1       jtc 	O_LE, O_GE, O_LT, O_GT,
     31   1.1       jtc 	O_LAND,
     32   1.1       jtc 	O_LOR,
     33   1.1       jtc 	O_TIMES, O_DIV, O_MOD,
     34   1.1       jtc 	O_PLUS, O_MINUS,
     35   1.1       jtc 	O_BAND,
     36   1.1       jtc 	O_BXOR,
     37   1.1       jtc 	O_BOR,
     38   1.1       jtc 	O_TERN,
     39   1.1       jtc 	O_COMMA,
     40   1.1       jtc 	/* things after this aren't used as binary operators */
     41   1.1       jtc 	/* unary that are not also binaries */
     42   1.1       jtc 	O_BNOT, O_LNOT,
     43   1.1       jtc 	/* misc */
     44   1.1       jtc 	OPEN_PAREN, CLOSE_PAREN, CTERN,
     45   1.1       jtc 	/* things that don't appear in the opinfo[] table */
     46   1.1       jtc 	VAR, LIT, END, BAD
     47   1.1       jtc     };
     48   1.3   hubertf #define IS_BINOP(op) (((int)op) >= (int)O_EQ && ((int)op) <= (int)O_COMMA)
     49   1.1       jtc #define IS_ASSIGNOP(op)	((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
     50   1.1       jtc 
     51   1.1       jtc enum prec {
     52   1.1       jtc 	P_PRIMARY = 0,		/* VAR, LIT, (), ~ ! - + */
     53   1.1       jtc 	P_MULT,			/* * / % */
     54   1.1       jtc 	P_ADD,			/* + - */
     55   1.1       jtc 	P_SHIFT,		/* << >> */
     56   1.1       jtc 	P_RELATION,		/* < <= > >= */
     57   1.1       jtc 	P_EQUALITY,		/* == != */
     58   1.1       jtc 	P_BAND,			/* & */
     59   1.1       jtc 	P_BXOR,			/* ^ */
     60   1.1       jtc 	P_BOR,			/* | */
     61   1.1       jtc 	P_LAND,			/* && */
     62   1.1       jtc 	P_LOR,			/* || */
     63   1.1       jtc 	P_TERN,			/* ?: */
     64   1.1       jtc 	P_ASSIGN,		/* = *= /= %= += -= <<= >>= &= ^= |= */
     65   1.1       jtc 	P_COMMA			/* , */
     66   1.1       jtc     };
     67   1.1       jtc #define MAX_PREC	P_COMMA
     68   1.1       jtc 
     69   1.1       jtc struct opinfo {
     70   1.1       jtc 	char		name[4];
     71   1.1       jtc 	int		len;	/* name length */
     72   1.6   mycroft 	enum prec	prec;	/* precedence: lower is higher */
     73   1.1       jtc };
     74   1.1       jtc 
     75   1.1       jtc /* Tokens in this table must be ordered so the longest are first
     76   1.1       jtc  * (eg, += before +).  If you change something, change the order
     77   1.1       jtc  * of enum token too.
     78   1.1       jtc  */
     79   1.1       jtc static const struct opinfo opinfo[] = {
     80   1.1       jtc 		{ "++",	 2, P_PRIMARY },	/* before + */
     81   1.1       jtc 		{ "--",	 2, P_PRIMARY },	/* before - */
     82   1.1       jtc 		{ "==",	 2, P_EQUALITY },	/* before = */
     83   1.1       jtc 		{ "!=",	 2, P_EQUALITY },	/* before ! */
     84   1.1       jtc 		{ "=",	 1, P_ASSIGN },		/* keep assigns in a block */
     85   1.1       jtc 		{ "*=",	 2, P_ASSIGN },
     86   1.1       jtc 		{ "/=",	 2, P_ASSIGN },
     87   1.1       jtc 		{ "%=",	 2, P_ASSIGN },
     88   1.1       jtc 		{ "+=",	 2, P_ASSIGN },
     89   1.1       jtc 		{ "-=",	 2, P_ASSIGN },
     90   1.1       jtc 		{ "<<=", 3, P_ASSIGN },
     91   1.1       jtc 		{ ">>=", 3, P_ASSIGN },
     92   1.1       jtc 		{ "&=",	 2, P_ASSIGN },
     93   1.1       jtc 		{ "^=",	 2, P_ASSIGN },
     94   1.1       jtc 		{ "|=",	 2, P_ASSIGN },
     95   1.1       jtc 		{ "<<",	 2, P_SHIFT },
     96   1.1       jtc 		{ ">>",	 2, P_SHIFT },
     97   1.1       jtc 		{ "<=",	 2, P_RELATION },
     98   1.1       jtc 		{ ">=",	 2, P_RELATION },
     99   1.1       jtc 		{ "<",	 1, P_RELATION },
    100   1.1       jtc 		{ ">",	 1, P_RELATION },
    101   1.1       jtc 		{ "&&",	 2, P_LAND },
    102   1.1       jtc 		{ "||",	 2, P_LOR },
    103   1.1       jtc 		{ "*",	 1, P_MULT },
    104   1.1       jtc 		{ "/",	 1, P_MULT },
    105   1.1       jtc 		{ "%",	 1, P_MULT },
    106   1.1       jtc 		{ "+",	 1, P_ADD },
    107   1.1       jtc 		{ "-",	 1, P_ADD },
    108   1.1       jtc 		{ "&",	 1, P_BAND },
    109   1.1       jtc 		{ "^",	 1, P_BXOR },
    110   1.1       jtc 		{ "|",	 1, P_BOR },
    111   1.1       jtc 		{ "?",	 1, P_TERN },
    112   1.1       jtc 		{ ",",	 1, P_COMMA },
    113   1.1       jtc 		{ "~",	 1, P_PRIMARY },
    114   1.1       jtc 		{ "!",	 1, P_PRIMARY },
    115   1.1       jtc 		{ "(",	 1, P_PRIMARY },
    116   1.1       jtc 		{ ")",	 1, P_PRIMARY },
    117   1.1       jtc 		{ ":",	 1, P_PRIMARY },
    118   1.1       jtc 		{ "",	 0, P_PRIMARY } /* end of table */
    119   1.1       jtc 	    };
    120   1.1       jtc 
    121   1.1       jtc 
    122   1.1       jtc typedef struct expr_state Expr_state;
    123   1.1       jtc struct expr_state {
    124   1.1       jtc 	const char *expression;		/* expression being evaluated */
    125   1.1       jtc 	const char *tokp;		/* lexical position */
    126   1.1       jtc 	enum token  tok;		/* token from token() */
    127   1.1       jtc 	int	    noassign;		/* don't do assigns (for ?:,&&,||) */
    128   1.1       jtc 	struct tbl *val;		/* value from token() */
    129   1.1       jtc 	struct tbl *evaling;		/* variable that is being recursively
    130   1.1       jtc 					 * expanded (EXPRINEVAL flag set)
    131   1.1       jtc 					 */
    132   1.1       jtc };
    133   1.1       jtc 
    134   1.1       jtc enum error_type { ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
    135   1.1       jtc 		  ET_LVALUE, ET_RDONLY, ET_STR };
    136   1.1       jtc 
    137   1.3   hubertf static void        evalerr  ARGS((Expr_state *es, enum error_type type,
    138   1.3   hubertf 				  const char *str)) GCC_FUNC_ATTR(noreturn);
    139   1.3   hubertf static struct tbl *evalexpr ARGS((Expr_state *es, enum prec prec));
    140   1.3   hubertf static void        token    ARGS((Expr_state *es));
    141  1.11     joerg static struct tbl *do_ppmm(Expr_state *, enum token, struct tbl *, bool);
    142   1.3   hubertf static void	   assign_check ARGS((Expr_state *es, enum token op,
    143   1.3   hubertf 				      struct tbl *vasn));
    144   1.1       jtc static struct tbl *tempvar  ARGS((void));
    145   1.3   hubertf static struct tbl *intvar   ARGS((Expr_state *es, struct tbl *vp));
    146   1.1       jtc 
    147   1.1       jtc /*
    148   1.6   mycroft  * parse and evaluate expression
    149   1.1       jtc  */
    150   1.1       jtc int
    151   1.1       jtc evaluate(expr, rval, error_ok)
    152   1.1       jtc 	const char *expr;
    153   1.1       jtc 	long *rval;
    154   1.1       jtc 	int error_ok;
    155   1.1       jtc {
    156   1.1       jtc 	struct tbl v;
    157   1.1       jtc 	int ret;
    158   1.1       jtc 
    159   1.1       jtc 	v.flag = DEFINED|INTEGER;
    160   1.1       jtc 	v.type = 0;
    161   1.1       jtc 	ret = v_evaluate(&v, expr, error_ok);
    162   1.1       jtc 	*rval = v.val.i;
    163   1.1       jtc 	return ret;
    164   1.1       jtc }
    165   1.1       jtc 
    166   1.1       jtc /*
    167   1.6   mycroft  * parse and evaluate expression, storing result in vp.
    168   1.1       jtc  */
    169   1.1       jtc int
    170   1.1       jtc v_evaluate(vp, expr, error_ok)
    171   1.1       jtc 	struct tbl *vp;
    172   1.1       jtc 	const char *expr;
    173   1.1       jtc 	volatile int error_ok;
    174   1.1       jtc {
    175   1.1       jtc 	struct tbl *v;
    176   1.1       jtc 	Expr_state curstate;
    177   1.3   hubertf 	Expr_state * const es = &curstate;
    178   1.1       jtc 	int i;
    179   1.1       jtc 
    180   1.1       jtc 	/* save state to allow recursive calls */
    181   1.1       jtc 	curstate.expression = curstate.tokp = expr;
    182   1.1       jtc 	curstate.noassign = 0;
    183   1.1       jtc 	curstate.evaling = (struct tbl *) 0;
    184   1.1       jtc 
    185   1.1       jtc 	newenv(E_ERRH);
    186   1.1       jtc 	i = ksh_sigsetjmp(e->jbuf, 0);
    187   1.1       jtc 	if (i) {
    188   1.1       jtc 		/* Clear EXPRINEVAL in of any variables we were playing with */
    189   1.1       jtc 		if (curstate.evaling)
    190   1.1       jtc 			curstate.evaling->flag &= ~EXPRINEVAL;
    191   1.1       jtc 		quitenv();
    192   1.1       jtc 		if (i == LAEXPR) {
    193   1.3   hubertf 			if (error_ok == KSH_RETURN_ERROR)
    194   1.1       jtc 				return 0;
    195   1.9     joerg 			errorf("%s", null);
    196   1.1       jtc 		}
    197   1.1       jtc 		unwind(i);
    198   1.1       jtc 		/*NOTREACHED*/
    199   1.1       jtc 	}
    200   1.1       jtc 
    201   1.3   hubertf 	token(es);
    202   1.1       jtc #if 1 /* ifdef-out to disallow empty expressions to be treated as 0 */
    203   1.1       jtc 	if (es->tok == END) {
    204   1.1       jtc 		es->tok = LIT;
    205   1.1       jtc 		es->val = tempvar();
    206   1.1       jtc 	}
    207   1.1       jtc #endif /* 0 */
    208   1.3   hubertf 	v = intvar(es, evalexpr(es, MAX_PREC));
    209   1.1       jtc 
    210   1.1       jtc 	if (es->tok != END)
    211   1.3   hubertf 		evalerr(es, ET_UNEXPECTED, (char *) 0);
    212   1.1       jtc 
    213   1.1       jtc 	if (vp->flag & INTEGER)
    214   1.1       jtc 		setint_v(vp, v);
    215   1.1       jtc 	else
    216   1.6   mycroft 		/* can fail if readonly */
    217   1.3   hubertf 		setstr(vp, str_val(v), error_ok);
    218   1.1       jtc 
    219   1.1       jtc 	quitenv();
    220   1.1       jtc 
    221   1.1       jtc 	return 1;
    222   1.1       jtc }
    223   1.1       jtc 
    224   1.1       jtc static void
    225   1.3   hubertf evalerr(es, type, str)
    226   1.3   hubertf 	Expr_state *es;
    227   1.1       jtc 	enum error_type type;
    228   1.1       jtc 	const char *str;
    229   1.1       jtc {
    230   1.1       jtc 	char tbuf[2];
    231   1.1       jtc 	const char *s;
    232   1.1       jtc 
    233   1.1       jtc 	switch (type) {
    234   1.1       jtc 	case ET_UNEXPECTED:
    235   1.1       jtc 		switch (es->tok) {
    236   1.1       jtc 		case VAR:
    237   1.1       jtc 			s = es->val->name;
    238   1.1       jtc 			break;
    239   1.1       jtc 		case LIT:
    240   1.1       jtc 			s = str_val(es->val);
    241   1.1       jtc 			break;
    242   1.1       jtc 		case END:
    243   1.1       jtc 			s = "end of expression";
    244   1.1       jtc 			break;
    245   1.1       jtc 		case BAD:
    246   1.1       jtc 			tbuf[0] = *es->tokp;
    247   1.1       jtc 			tbuf[1] = '\0';
    248   1.1       jtc 			s = tbuf;
    249   1.1       jtc 			break;
    250   1.1       jtc 		default:
    251   1.1       jtc 			s = opinfo[(int)es->tok].name;
    252   1.1       jtc 		}
    253  1.10     kamil 		warningf(true, "%s: unexpected `%s'", es->expression, s);
    254   1.1       jtc 		break;
    255   1.1       jtc 
    256   1.1       jtc 	case ET_BADLIT:
    257  1.10     kamil 		warningf(true, "%s: bad number `%s'", es->expression, str);
    258   1.1       jtc 		break;
    259   1.1       jtc 
    260   1.1       jtc 	case ET_RECURSIVE:
    261  1.10     kamil 		warningf(true, "%s: expression recurses on parameter `%s'",
    262   1.1       jtc 			es->expression, str);
    263   1.1       jtc 		break;
    264   1.1       jtc 
    265   1.1       jtc 	case ET_LVALUE:
    266  1.10     kamil 		warningf(true, "%s: %s requires lvalue",
    267   1.1       jtc 			es->expression, str);
    268   1.1       jtc 		break;
    269   1.1       jtc 
    270   1.1       jtc 	case ET_RDONLY:
    271  1.10     kamil 		warningf(true, "%s: %s applied to read only variable",
    272   1.1       jtc 			es->expression, str);
    273   1.1       jtc 		break;
    274   1.1       jtc 
    275   1.1       jtc 	default: /* keep gcc happy */
    276   1.1       jtc 	case ET_STR:
    277  1.10     kamil 		warningf(true, "%s: %s", es->expression, str);
    278   1.1       jtc 		break;
    279   1.1       jtc 	}
    280   1.1       jtc 	unwind(LAEXPR);
    281   1.1       jtc }
    282   1.1       jtc 
    283   1.1       jtc static struct tbl *
    284   1.3   hubertf evalexpr(es, prec)
    285   1.3   hubertf 	Expr_state *es;
    286   1.1       jtc 	enum prec prec;
    287   1.1       jtc {
    288   1.3   hubertf 	struct tbl *vl, UNINITIALIZED(*vr), *vasn;
    289   1.3   hubertf 	enum token op;
    290   1.1       jtc 	long UNINITIALIZED(res);
    291   1.1       jtc 
    292   1.1       jtc 	if (prec == P_PRIMARY) {
    293   1.1       jtc 		op = es->tok;
    294   1.1       jtc 		if (op == O_BNOT || op == O_LNOT || op == O_MINUS
    295   1.1       jtc 		    || op == O_PLUS)
    296   1.1       jtc 		{
    297   1.3   hubertf 			token(es);
    298   1.3   hubertf 			vl = intvar(es, evalexpr(es, P_PRIMARY));
    299   1.1       jtc 			if (op == O_BNOT)
    300   1.1       jtc 				vl->val.i = ~vl->val.i;
    301   1.1       jtc 			else if (op == O_LNOT)
    302   1.1       jtc 				vl->val.i = !vl->val.i;
    303   1.1       jtc 			else if (op == O_MINUS)
    304   1.1       jtc 				vl->val.i = -vl->val.i;
    305   1.1       jtc 			/* op == O_PLUS is a no-op */
    306   1.1       jtc 		} else if (op == OPEN_PAREN) {
    307   1.3   hubertf 			token(es);
    308   1.3   hubertf 			vl = evalexpr(es, MAX_PREC);
    309   1.1       jtc 			if (es->tok != CLOSE_PAREN)
    310   1.3   hubertf 				evalerr(es, ET_STR, "missing )");
    311   1.3   hubertf 			token(es);
    312   1.1       jtc 		} else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
    313   1.3   hubertf 			token(es);
    314  1.10     kamil 			vl = do_ppmm(es, op, es->val, true);
    315   1.3   hubertf 			token(es);
    316   1.1       jtc 		} else if (op == VAR || op == LIT) {
    317   1.1       jtc 			vl = es->val;
    318   1.3   hubertf 			token(es);
    319   1.1       jtc 		} else {
    320   1.3   hubertf 			evalerr(es, ET_UNEXPECTED, (char *) 0);
    321   1.1       jtc 			/*NOTREACHED*/
    322   1.1       jtc 		}
    323   1.1       jtc 		if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
    324  1.10     kamil 			vl = do_ppmm(es, es->tok, vl, false);
    325   1.3   hubertf 			token(es);
    326   1.1       jtc 		}
    327   1.1       jtc 		return vl;
    328   1.1       jtc 	}
    329   1.3   hubertf 	vl = evalexpr(es, ((int) prec) - 1);
    330   1.1       jtc 	for (op = es->tok; IS_BINOP(op) && opinfo[(int) op].prec == prec;
    331   1.1       jtc 		op = es->tok)
    332   1.1       jtc 	{
    333   1.3   hubertf 		token(es);
    334   1.1       jtc 		vasn = vl;
    335   1.1       jtc 		if (op != O_ASN) /* vl may not have a value yet */
    336   1.3   hubertf 			vl = intvar(es, vl);
    337   1.1       jtc 		if (IS_ASSIGNOP(op)) {
    338   1.3   hubertf 			assign_check(es, op, vasn);
    339   1.3   hubertf 			vr = intvar(es, evalexpr(es, P_ASSIGN));
    340   1.1       jtc 		} else if (op != O_TERN && op != O_LAND && op != O_LOR)
    341   1.3   hubertf 			vr = intvar(es, evalexpr(es, ((int) prec) - 1));
    342   1.1       jtc 		if ((op == O_DIV || op == O_MOD || op == O_DIVASN
    343   1.1       jtc 		     || op == O_MODASN) && vr->val.i == 0)
    344   1.1       jtc 		{
    345   1.1       jtc 			if (es->noassign)
    346   1.1       jtc 				vr->val.i = 1;
    347   1.1       jtc 			else
    348   1.3   hubertf 				evalerr(es, ET_STR, "zero divisor");
    349   1.1       jtc 		}
    350   1.1       jtc 		switch ((int) op) {
    351   1.1       jtc 		case O_TIMES:
    352   1.1       jtc 		case O_TIMESASN:
    353   1.1       jtc 			res = vl->val.i * vr->val.i;
    354   1.1       jtc 			break;
    355   1.1       jtc 		case O_DIV:
    356   1.1       jtc 		case O_DIVASN:
    357   1.1       jtc 			res = vl->val.i / vr->val.i;
    358   1.1       jtc 			break;
    359   1.1       jtc 		case O_MOD:
    360   1.1       jtc 		case O_MODASN:
    361   1.1       jtc 			res = vl->val.i % vr->val.i;
    362   1.1       jtc 			break;
    363   1.1       jtc 		case O_PLUS:
    364   1.1       jtc 		case O_PLUSASN:
    365   1.1       jtc 			res = vl->val.i + vr->val.i;
    366   1.1       jtc 			break;
    367   1.1       jtc 		case O_MINUS:
    368   1.1       jtc 		case O_MINUSASN:
    369   1.1       jtc 			res = vl->val.i - vr->val.i;
    370   1.1       jtc 			break;
    371   1.1       jtc 		case O_LSHIFT:
    372   1.1       jtc 		case O_LSHIFTASN:
    373   1.1       jtc 			res = vl->val.i << vr->val.i;
    374   1.1       jtc 			break;
    375   1.1       jtc 		case O_RSHIFT:
    376   1.1       jtc 		case O_RSHIFTASN:
    377   1.1       jtc 			res = vl->val.i >> vr->val.i;
    378   1.1       jtc 			break;
    379   1.1       jtc 		case O_LT:
    380   1.1       jtc 			res = vl->val.i < vr->val.i;
    381   1.1       jtc 			break;
    382   1.1       jtc 		case O_LE:
    383   1.1       jtc 			res = vl->val.i <= vr->val.i;
    384   1.1       jtc 			break;
    385   1.1       jtc 		case O_GT:
    386   1.1       jtc 			res = vl->val.i > vr->val.i;
    387   1.1       jtc 			break;
    388   1.1       jtc 		case O_GE:
    389   1.1       jtc 			res = vl->val.i >= vr->val.i;
    390   1.1       jtc 			break;
    391   1.1       jtc 		case O_EQ:
    392   1.1       jtc 			res = vl->val.i == vr->val.i;
    393   1.1       jtc 			break;
    394   1.1       jtc 		case O_NE:
    395   1.1       jtc 			res = vl->val.i != vr->val.i;
    396   1.1       jtc 			break;
    397   1.1       jtc 		case O_BAND:
    398   1.1       jtc 		case O_BANDASN:
    399   1.1       jtc 			res = vl->val.i & vr->val.i;
    400   1.1       jtc 			break;
    401   1.1       jtc 		case O_BXOR:
    402   1.1       jtc 		case O_BXORASN:
    403   1.1       jtc 			res = vl->val.i ^ vr->val.i;
    404   1.1       jtc 			break;
    405   1.1       jtc 		case O_BOR:
    406   1.1       jtc 		case O_BORASN:
    407   1.1       jtc 			res = vl->val.i | vr->val.i;
    408   1.1       jtc 			break;
    409   1.1       jtc 		case O_LAND:
    410   1.1       jtc 			if (!vl->val.i)
    411   1.1       jtc 				es->noassign++;
    412   1.3   hubertf 			vr = intvar(es, evalexpr(es, ((int) prec) - 1));
    413   1.1       jtc 			res = vl->val.i && vr->val.i;
    414   1.1       jtc 			if (!vl->val.i)
    415   1.1       jtc 				es->noassign--;
    416   1.1       jtc 			break;
    417   1.1       jtc 		case O_LOR:
    418   1.1       jtc 			if (vl->val.i)
    419   1.1       jtc 				es->noassign++;
    420   1.3   hubertf 			vr = intvar(es, evalexpr(es, ((int) prec) - 1));
    421   1.1       jtc 			res = vl->val.i || vr->val.i;
    422   1.1       jtc 			if (vl->val.i)
    423   1.1       jtc 				es->noassign--;
    424   1.1       jtc 			break;
    425   1.1       jtc 		case O_TERN:
    426   1.1       jtc 			{
    427   1.8  christos 				int ex = vl->val.i != 0;
    428   1.8  christos 				if (!ex)
    429   1.1       jtc 					es->noassign++;
    430   1.3   hubertf 				vl = evalexpr(es, MAX_PREC);
    431   1.8  christos 				if (!ex)
    432   1.1       jtc 					es->noassign--;
    433   1.1       jtc 				if (es->tok != CTERN)
    434   1.3   hubertf 					evalerr(es, ET_STR, "missing :");
    435   1.3   hubertf 				token(es);
    436   1.8  christos 				if (ex)
    437   1.1       jtc 					es->noassign++;
    438   1.3   hubertf 				vr = evalexpr(es, P_TERN);
    439   1.8  christos 				if (ex)
    440   1.1       jtc 					es->noassign--;
    441   1.8  christos 				vl = ex ? vl : vr;
    442   1.1       jtc 			}
    443   1.1       jtc 			break;
    444   1.1       jtc 		case O_ASN:
    445   1.1       jtc 			res = vr->val.i;
    446   1.1       jtc 			break;
    447   1.1       jtc 		case O_COMMA:
    448   1.1       jtc 			res = vr->val.i;
    449   1.1       jtc 			break;
    450   1.1       jtc 		}
    451   1.1       jtc 		if (IS_ASSIGNOP(op)) {
    452   1.1       jtc 			vr->val.i = res;
    453   1.1       jtc 			if (vasn->flag & INTEGER)
    454   1.1       jtc 				setint_v(vasn, vr);
    455   1.1       jtc 			else
    456   1.1       jtc 				setint(vasn, res);
    457   1.1       jtc 			vl = vr;
    458   1.1       jtc 		} else if (op != O_TERN)
    459   1.1       jtc 			vl->val.i = res;
    460   1.1       jtc 	}
    461   1.1       jtc 	return vl;
    462   1.1       jtc }
    463   1.1       jtc 
    464   1.1       jtc static void
    465   1.3   hubertf token(es)
    466   1.3   hubertf 	Expr_state *es;
    467   1.1       jtc {
    468   1.3   hubertf 	const char *cp;
    469   1.3   hubertf 	int c;
    470   1.1       jtc 	char *tvar;
    471   1.1       jtc 
    472   1.1       jtc 	/* skip white space */
    473   1.7    rillig 	for (cp = es->tokp; (c = *cp), isspace((unsigned char)c); cp++)
    474   1.1       jtc 		;
    475   1.1       jtc 	es->tokp = cp;
    476   1.1       jtc 
    477   1.1       jtc 	if (c == '\0')
    478   1.1       jtc 		es->tok = END;
    479   1.1       jtc 	else if (letter(c)) {
    480   1.1       jtc 		for (; letnum(c); c = *cp)
    481   1.1       jtc 			cp++;
    482   1.1       jtc 		if (c == '[') {
    483   1.1       jtc 			int len;
    484   1.1       jtc 
    485   1.1       jtc 			len = array_ref_len(cp);
    486   1.1       jtc 			if (len == 0)
    487   1.3   hubertf 				evalerr(es, ET_STR, "missing ]");
    488   1.1       jtc 			cp += len;
    489   1.1       jtc 		}
    490   1.3   hubertf #ifdef KSH
    491   1.3   hubertf 		else if (c == '(' /*)*/ ) {
    492   1.3   hubertf 		    /* todo: add math functions (all take single argument):
    493   1.3   hubertf 		     * abs acos asin atan cos cosh exp int log sin sinh sqrt
    494   1.3   hubertf 		     * tan tanh
    495   1.3   hubertf 		     */
    496   1.3   hubertf 		    ;
    497   1.3   hubertf 		}
    498   1.3   hubertf #endif /* KSH */
    499   1.1       jtc 		if (es->noassign) {
    500   1.1       jtc 			es->val = tempvar();
    501   1.1       jtc 			es->val->flag |= EXPRLVALUE;
    502   1.1       jtc 		} else {
    503   1.1       jtc 			tvar = str_nsave(es->tokp, cp - es->tokp, ATEMP);
    504   1.1       jtc 			es->val = global(tvar);
    505   1.1       jtc 			afree(tvar, ATEMP);
    506   1.1       jtc 		}
    507   1.1       jtc 		es->tok = VAR;
    508   1.1       jtc 	} else if (digit(c)) {
    509   1.1       jtc 		for (; c != '_' && (letnum(c) || c == '#'); c = *cp++)
    510   1.1       jtc 			;
    511   1.1       jtc 		tvar = str_nsave(es->tokp, --cp - es->tokp, ATEMP);
    512   1.1       jtc 		es->val = tempvar();
    513   1.1       jtc 		es->val->flag &= ~INTEGER;
    514   1.1       jtc 		es->val->type = 0;
    515   1.1       jtc 		es->val->val.s = tvar;
    516   1.1       jtc 		if (setint_v(es->val, es->val) == NULL)
    517   1.3   hubertf 			evalerr(es, ET_BADLIT, tvar);
    518   1.1       jtc 		afree(tvar, ATEMP);
    519   1.1       jtc 		es->tok = LIT;
    520   1.1       jtc 	} else {
    521   1.1       jtc 		int i, n0;
    522   1.1       jtc 
    523   1.1       jtc 		for (i = 0; (n0 = opinfo[i].name[0]); i++)
    524   1.1       jtc 			if (c == n0
    525   1.1       jtc 			    && strncmp(cp, opinfo[i].name, opinfo[i].len) == 0)
    526   1.1       jtc 			{
    527   1.1       jtc 				es->tok = (enum token) i;
    528   1.1       jtc 				cp += opinfo[i].len;
    529   1.1       jtc 				break;
    530   1.1       jtc 			}
    531   1.1       jtc 		if (!n0)
    532   1.1       jtc 			es->tok = BAD;
    533   1.1       jtc 	}
    534   1.1       jtc 	es->tokp = cp;
    535   1.1       jtc }
    536   1.1       jtc 
    537   1.1       jtc /* Do a ++ or -- operation */
    538   1.1       jtc static struct tbl *
    539  1.11     joerg do_ppmm(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
    540   1.1       jtc {
    541   1.1       jtc 	struct tbl *vl;
    542   1.1       jtc 	int oval;
    543   1.1       jtc 
    544   1.3   hubertf 	assign_check(es, op, vasn);
    545   1.1       jtc 
    546   1.3   hubertf 	vl = intvar(es, vasn);
    547   1.1       jtc 	oval = op == O_PLUSPLUS ? vl->val.i++ : vl->val.i--;
    548   1.1       jtc 	if (vasn->flag & INTEGER)
    549   1.1       jtc 		setint_v(vasn, vl);
    550   1.1       jtc 	else
    551   1.1       jtc 		setint(vasn, vl->val.i);
    552   1.1       jtc 	if (!is_prefix)		/* undo the inc/dec */
    553   1.1       jtc 		vl->val.i = oval;
    554   1.1       jtc 
    555   1.1       jtc 	return vl;
    556   1.1       jtc }
    557   1.1       jtc 
    558   1.1       jtc static void
    559   1.3   hubertf assign_check(es, op, vasn)
    560   1.3   hubertf 	Expr_state *es;
    561   1.1       jtc 	enum token op;
    562   1.1       jtc 	struct tbl *vasn;
    563   1.1       jtc {
    564   1.1       jtc 	if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE))
    565   1.3   hubertf 		evalerr(es, ET_LVALUE, opinfo[(int) op].name);
    566   1.1       jtc 	else if (vasn->flag & RDONLY)
    567   1.3   hubertf 		evalerr(es, ET_RDONLY, opinfo[(int) op].name);
    568   1.1       jtc }
    569   1.1       jtc 
    570   1.1       jtc static struct tbl *
    571   1.1       jtc tempvar()
    572   1.1       jtc {
    573   1.1       jtc 	register struct tbl *vp;
    574   1.1       jtc 
    575   1.1       jtc 	vp = (struct tbl*) alloc(sizeof(struct tbl), ATEMP);
    576   1.1       jtc 	vp->flag = ISSET|INTEGER;
    577   1.1       jtc 	vp->type = 0;
    578   1.1       jtc 	vp->areap = ATEMP;
    579   1.1       jtc 	vp->val.i = 0;
    580   1.1       jtc 	vp->name[0] = '\0';
    581   1.1       jtc 	return vp;
    582   1.1       jtc }
    583   1.1       jtc 
    584   1.1       jtc /* cast (string) variable to temporary integer variable */
    585   1.1       jtc static struct tbl *
    586   1.3   hubertf intvar(es, vp)
    587   1.3   hubertf 	Expr_state *es;
    588   1.3   hubertf 	struct tbl *vp;
    589   1.1       jtc {
    590   1.3   hubertf 	struct tbl *vq;
    591   1.1       jtc 
    592   1.1       jtc 	/* try to avoid replacing a temp var with another temp var */
    593   1.1       jtc 	if (vp->name[0] == '\0'
    594   1.1       jtc 	    && (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER))
    595   1.1       jtc 		return vp;
    596   1.1       jtc 
    597   1.1       jtc 	vq = tempvar();
    598   1.1       jtc 	if (setint_v(vq, vp) == NULL) {
    599   1.1       jtc 		if (vp->flag & EXPRINEVAL)
    600   1.3   hubertf 			evalerr(es, ET_RECURSIVE, vp->name);
    601   1.1       jtc 		es->evaling = vp;
    602   1.1       jtc 		vp->flag |= EXPRINEVAL;
    603   1.3   hubertf 		v_evaluate(vq, str_val(vp), KSH_UNWIND_ERROR);
    604   1.1       jtc 		vp->flag &= ~EXPRINEVAL;
    605   1.1       jtc 		es->evaling = (struct tbl *) 0;
    606   1.1       jtc 	}
    607   1.1       jtc 	return vq;
    608   1.1       jtc }
    609