1 /* $NetBSD: expr.c,v 1.9 2011/10/16 17:12:11 joerg Exp $ */
4 * Korn expression evaluation
7 * todo: better error handling: if in builtin, should be builtin error, etc.
12 __RCSID("$NetBSD: expr.c,v 1.9 2011/10/16 17:12:11 joerg Exp $");
20 /* The order of these enums is constrained by the order of opinfo[] */
22 /* some (long) unary operators */
23 O_PLUSPLUS
= 0, O_MINUSMINUS
,
24 /* binary operators */
26 /* assignments are assumed to be in range O_ASN .. O_BORASN */
27 O_ASN
, O_TIMESASN
, O_DIVASN
, O_MODASN
, O_PLUSASN
, O_MINUSASN
,
28 O_LSHIFTASN
, O_RSHIFTASN
, O_BANDASN
, O_BXORASN
, O_BORASN
,
30 O_LE
, O_GE
, O_LT
, O_GT
,
33 O_TIMES
, O_DIV
, O_MOD
,
40 /* things after this aren't used as binary operators */
41 /* unary that are not also binaries */
44 OPEN_PAREN
, CLOSE_PAREN
, CTERN
,
45 /* things that don't appear in the opinfo[] table */
48 #define IS_BINOP(op) (((int)op) >= (int)O_EQ && ((int)op) <= (int)O_COMMA)
49 #define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
52 P_PRIMARY
= 0, /* VAR, LIT, (), ~ ! - + */
56 P_RELATION
, /* < <= > >= */
57 P_EQUALITY
, /* == != */
64 P_ASSIGN
, /* = *= /= %= += -= <<= >>= &= ^= |= */
67 #define MAX_PREC P_COMMA
71 int len
; /* name length */
72 enum prec prec
; /* precedence: lower is higher */
75 /* Tokens in this table must be ordered so the longest are first
76 * (eg, += before +). If you change something, change the order
79 static const struct opinfo opinfo
[] = {
80 { "++", 2, P_PRIMARY
}, /* before + */
81 { "--", 2, P_PRIMARY
}, /* before - */
82 { "==", 2, P_EQUALITY
}, /* before = */
83 { "!=", 2, P_EQUALITY
}, /* before ! */
84 { "=", 1, P_ASSIGN
}, /* keep assigns in a block */
85 { "*=", 2, P_ASSIGN
},
86 { "/=", 2, P_ASSIGN
},
87 { "%=", 2, P_ASSIGN
},
88 { "+=", 2, P_ASSIGN
},
89 { "-=", 2, P_ASSIGN
},
90 { "<<=", 3, P_ASSIGN
},
91 { ">>=", 3, P_ASSIGN
},
92 { "&=", 2, P_ASSIGN
},
93 { "^=", 2, P_ASSIGN
},
94 { "|=", 2, P_ASSIGN
},
97 { "<=", 2, P_RELATION
},
98 { ">=", 2, P_RELATION
},
99 { "<", 1, P_RELATION
},
100 { ">", 1, P_RELATION
},
113 { "~", 1, P_PRIMARY
},
114 { "!", 1, P_PRIMARY
},
115 { "(", 1, P_PRIMARY
},
116 { ")", 1, P_PRIMARY
},
117 { ":", 1, P_PRIMARY
},
118 { "", 0, P_PRIMARY
} /* end of table */
122 typedef struct expr_state Expr_state
;
124 const char *expression
; /* expression being evaluated */
125 const char *tokp
; /* lexical position */
126 enum token tok
; /* token from token() */
127 int noassign
; /* don't do assigns (for ?:,&&,||) */
128 struct tbl
*val
; /* value from token() */
129 struct tbl
*evaling
; /* variable that is being recursively
130 * expanded (EXPRINEVAL flag set)
134 enum error_type
{ ET_UNEXPECTED
, ET_BADLIT
, ET_RECURSIVE
,
135 ET_LVALUE
, ET_RDONLY
, ET_STR
};
137 static void evalerr
ARGS((Expr_state
*es
, enum error_type type
,
138 const char *str
)) GCC_FUNC_ATTR(noreturn
);
139 static struct tbl
*evalexpr
ARGS((Expr_state
*es
, enum prec prec
));
140 static void token
ARGS((Expr_state
*es
));
141 static struct tbl
*do_ppmm
ARGS((Expr_state
*es
, enum token op
,
142 struct tbl
*vasn
, bool_t is_prefix
));
143 static void assign_check
ARGS((Expr_state
*es
, enum token op
,
145 static struct tbl
*tempvar
ARGS((void));
146 static struct tbl
*intvar
ARGS((Expr_state
*es
, struct tbl
*vp
));
149 * parse and evaluate expression
152 evaluate(expr
, rval
, error_ok
)
160 v
.flag
= DEFINED
|INTEGER
;
162 ret
= v_evaluate(&v
, expr
, error_ok
);
168 * parse and evaluate expression, storing result in vp.
171 v_evaluate(vp
, expr
, error_ok
)
174 volatile int error_ok
;
178 Expr_state
* const es
= &curstate
;
181 /* save state to allow recursive calls */
182 curstate
.expression
= curstate
.tokp
= expr
;
183 curstate
.noassign
= 0;
184 curstate
.evaling
= (struct tbl
*) 0;
187 i
= ksh_sigsetjmp(e
->jbuf
, 0);
189 /* Clear EXPRINEVAL in of any variables we were playing with */
190 if (curstate
.evaling
)
191 curstate
.evaling
->flag
&= ~EXPRINEVAL
;
194 if (error_ok
== KSH_RETURN_ERROR
)
203 #if 1 /* ifdef-out to disallow empty expressions to be treated as 0 */
204 if (es
->tok
== END
) {
209 v
= intvar(es
, evalexpr(es
, MAX_PREC
));
212 evalerr(es
, ET_UNEXPECTED
, (char *) 0);
214 if (vp
->flag
& INTEGER
)
217 /* can fail if readonly */
218 setstr(vp
, str_val(v
), error_ok
);
226 evalerr(es
, type
, str
)
228 enum error_type type
;
241 s
= str_val(es
->val
);
244 s
= "end of expression";
252 s
= opinfo
[(int)es
->tok
].name
;
254 warningf(TRUE
, "%s: unexpected `%s'", es
->expression
, s
);
258 warningf(TRUE
, "%s: bad number `%s'", es
->expression
, str
);
262 warningf(TRUE
, "%s: expression recurses on parameter `%s'",
263 es
->expression
, str
);
267 warningf(TRUE
, "%s: %s requires lvalue",
268 es
->expression
, str
);
272 warningf(TRUE
, "%s: %s applied to read only variable",
273 es
->expression
, str
);
276 default: /* keep gcc happy */
278 warningf(TRUE
, "%s: %s", es
->expression
, str
);
289 struct tbl
*vl
, UNINITIALIZED(*vr
), *vasn
;
291 long UNINITIALIZED(res
);
293 if (prec
== P_PRIMARY
) {
295 if (op
== O_BNOT
|| op
== O_LNOT
|| op
== O_MINUS
299 vl
= intvar(es
, evalexpr(es
, P_PRIMARY
));
301 vl
->val
.i
= ~vl
->val
.i
;
302 else if (op
== O_LNOT
)
303 vl
->val
.i
= !vl
->val
.i
;
304 else if (op
== O_MINUS
)
305 vl
->val
.i
= -vl
->val
.i
;
306 /* op == O_PLUS is a no-op */
307 } else if (op
== OPEN_PAREN
) {
309 vl
= evalexpr(es
, MAX_PREC
);
310 if (es
->tok
!= CLOSE_PAREN
)
311 evalerr(es
, ET_STR
, "missing )");
313 } else if (op
== O_PLUSPLUS
|| op
== O_MINUSMINUS
) {
315 vl
= do_ppmm(es
, op
, es
->val
, TRUE
);
317 } else if (op
== VAR
|| op
== LIT
) {
321 evalerr(es
, ET_UNEXPECTED
, (char *) 0);
324 if (es
->tok
== O_PLUSPLUS
|| es
->tok
== O_MINUSMINUS
) {
325 vl
= do_ppmm(es
, es
->tok
, vl
, FALSE
);
330 vl
= evalexpr(es
, ((int) prec
) - 1);
331 for (op
= es
->tok
; IS_BINOP(op
) && opinfo
[(int) op
].prec
== prec
;
336 if (op
!= O_ASN
) /* vl may not have a value yet */
338 if (IS_ASSIGNOP(op
)) {
339 assign_check(es
, op
, vasn
);
340 vr
= intvar(es
, evalexpr(es
, P_ASSIGN
));
341 } else if (op
!= O_TERN
&& op
!= O_LAND
&& op
!= O_LOR
)
342 vr
= intvar(es
, evalexpr(es
, ((int) prec
) - 1));
343 if ((op
== O_DIV
|| op
== O_MOD
|| op
== O_DIVASN
344 || op
== O_MODASN
) && vr
->val
.i
== 0)
349 evalerr(es
, ET_STR
, "zero divisor");
354 res
= vl
->val
.i
* vr
->val
.i
;
358 res
= vl
->val
.i
/ vr
->val
.i
;
362 res
= vl
->val
.i
% vr
->val
.i
;
366 res
= vl
->val
.i
+ vr
->val
.i
;
370 res
= vl
->val
.i
- vr
->val
.i
;
374 res
= vl
->val
.i
<< vr
->val
.i
;
378 res
= vl
->val
.i
>> vr
->val
.i
;
381 res
= vl
->val
.i
< vr
->val
.i
;
384 res
= vl
->val
.i
<= vr
->val
.i
;
387 res
= vl
->val
.i
> vr
->val
.i
;
390 res
= vl
->val
.i
>= vr
->val
.i
;
393 res
= vl
->val
.i
== vr
->val
.i
;
396 res
= vl
->val
.i
!= vr
->val
.i
;
400 res
= vl
->val
.i
& vr
->val
.i
;
404 res
= vl
->val
.i
^ vr
->val
.i
;
408 res
= vl
->val
.i
| vr
->val
.i
;
413 vr
= intvar(es
, evalexpr(es
, ((int) prec
) - 1));
414 res
= vl
->val
.i
&& vr
->val
.i
;
421 vr
= intvar(es
, evalexpr(es
, ((int) prec
) - 1));
422 res
= vl
->val
.i
|| vr
->val
.i
;
428 int ex
= vl
->val
.i
!= 0;
431 vl
= evalexpr(es
, MAX_PREC
);
434 if (es
->tok
!= CTERN
)
435 evalerr(es
, ET_STR
, "missing :");
439 vr
= evalexpr(es
, P_TERN
);
452 if (IS_ASSIGNOP(op
)) {
454 if (vasn
->flag
& INTEGER
)
459 } else if (op
!= O_TERN
)
473 /* skip white space */
474 for (cp
= es
->tokp
; (c
= *cp
), isspace((unsigned char)c
); cp
++)
480 else if (letter(c
)) {
481 for (; letnum(c
); c
= *cp
)
486 len
= array_ref_len(cp
);
488 evalerr(es
, ET_STR
, "missing ]");
492 else if (c
== '(' /*)*/ ) {
493 /* todo: add math functions (all take single argument):
494 * abs acos asin atan cos cosh exp int log sin sinh sqrt
502 es
->val
->flag
|= EXPRLVALUE
;
504 tvar
= str_nsave(es
->tokp
, cp
- es
->tokp
, ATEMP
);
505 es
->val
= global(tvar
);
509 } else if (digit(c
)) {
510 for (; c
!= '_' && (letnum(c
) || c
== '#'); c
= *cp
++)
512 tvar
= str_nsave(es
->tokp
, --cp
- es
->tokp
, ATEMP
);
514 es
->val
->flag
&= ~INTEGER
;
516 es
->val
->val
.s
= tvar
;
517 if (setint_v(es
->val
, es
->val
) == NULL
)
518 evalerr(es
, ET_BADLIT
, tvar
);
524 for (i
= 0; (n0
= opinfo
[i
].name
[0]); i
++)
526 && strncmp(cp
, opinfo
[i
].name
, opinfo
[i
].len
) == 0)
528 es
->tok
= (enum token
) i
;
538 /* Do a ++ or -- operation */
540 do_ppmm(es
, op
, vasn
, is_prefix
)
549 assign_check(es
, op
, vasn
);
551 vl
= intvar(es
, vasn
);
552 oval
= op
== O_PLUSPLUS
? vl
->val
.i
++ : vl
->val
.i
--;
553 if (vasn
->flag
& INTEGER
)
556 setint(vasn
, vl
->val
.i
);
557 if (!is_prefix
) /* undo the inc/dec */
564 assign_check(es
, op
, vasn
)
569 if (vasn
->name
[0] == '\0' && !(vasn
->flag
& EXPRLVALUE
))
570 evalerr(es
, ET_LVALUE
, opinfo
[(int) op
].name
);
571 else if (vasn
->flag
& RDONLY
)
572 evalerr(es
, ET_RDONLY
, opinfo
[(int) op
].name
);
578 register struct tbl
*vp
;
580 vp
= (struct tbl
*) alloc(sizeof(struct tbl
), ATEMP
);
581 vp
->flag
= ISSET
|INTEGER
;
589 /* cast (string) variable to temporary integer variable */
597 /* try to avoid replacing a temp var with another temp var */
598 if (vp
->name
[0] == '\0'
599 && (vp
->flag
& (ISSET
|INTEGER
|EXPRLVALUE
)) == (ISSET
|INTEGER
))
603 if (setint_v(vq
, vp
) == NULL
) {
604 if (vp
->flag
& EXPRINEVAL
)
605 evalerr(es
, ET_RECURSIVE
, vp
->name
);
607 vp
->flag
|= EXPRINEVAL
;
608 v_evaluate(vq
, str_val(vp
), KSH_UNWIND_ERROR
);
609 vp
->flag
&= ~EXPRINEVAL
;
610 es
->evaling
= (struct tbl
*) 0;