blob: 76159b299f154708b13e25ddbfd22224ed94a58f [file] [log] [blame]
Mike Frysinger98c52642009-04-02 10:02:37 +00001/*
2 * arithmetic code ripped out of ash shell for code sharing
3 *
Denys Vlasenko73067272010-01-12 22:11:24 +01004 * This code is derived from software contributed to Berkeley by
5 * Kenneth Almquist.
6 *
7 * Original BSD copyright notice is retained at the end of this file.
8 *
Mike Frysinger98c52642009-04-02 10:02:37 +00009 * Copyright (c) 1989, 1991, 1993, 1994
10 * The Regents of the University of California. All rights reserved.
11 *
12 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
13 * was re-ported from NetBSD and debianized.
14 *
Mike Frysinger98c52642009-04-02 10:02:37 +000015 * rewrite arith.y to micro stack based cryptic algorithm by
16 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
17 *
18 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
19 * dynamic variables.
20 *
21 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
22 * used in busybox and size optimizations,
23 * rewrote arith (see notes to this), added locale support,
24 * rewrote dynamic variables.
Denys Vlasenko73067272010-01-12 22:11:24 +010025 *
26 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Mike Frysinger98c52642009-04-02 10:02:37 +000027 */
Denis Vlasenko1943aec2009-04-09 14:15:57 +000028#include "libbb.h"
Mike Frysinger98c52642009-04-02 10:02:37 +000029#include "math.h"
30
31#define a_e_h_t arith_eval_hooks_t
32#define lookupvar (math_hooks->lookupvar)
33#define setvar (math_hooks->setvar)
34#define endofname (math_hooks->endofname)
35
36/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
37
38 Permission is hereby granted, free of charge, to any person obtaining
39 a copy of this software and associated documentation files (the
40 "Software"), to deal in the Software without restriction, including
41 without limitation the rights to use, copy, modify, merge, publish,
42 distribute, sublicense, and/or sell copies of the Software, and to
43 permit persons to whom the Software is furnished to do so, subject to
44 the following conditions:
45
46 The above copyright notice and this permission notice shall be
47 included in all copies or substantial portions of the Software.
48
49 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
50 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
51 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
52 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
53 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
54 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
55 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
56*/
57
58/* This is my infix parser/evaluator. It is optimized for size, intended
59 * as a replacement for yacc-based parsers. However, it may well be faster
60 * than a comparable parser written in yacc. The supported operators are
61 * listed in #defines below. Parens, order of operations, and error handling
62 * are supported. This code is thread safe. The exact expression format should
63 * be that which POSIX specifies for shells. */
64
65/* The code uses a simple two-stack algorithm. See
66 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
67 * for a detailed explanation of the infix-to-postfix algorithm on which
68 * this is based (this code differs in that it applies operators immediately
69 * to the stack instead of adding them to a queue to end up with an
70 * expression). */
71
72/* To use the routine, call it with an expression string and error return
73 * pointer */
74
75/*
76 * Aug 24, 2001 Manuel Novoa III
77 *
78 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
79 *
80 * 1) In arith_apply():
81 * a) Cached values of *numptr and &(numptr[-1]).
82 * b) Removed redundant test for zero denominator.
83 *
84 * 2) In arith():
85 * a) Eliminated redundant code for processing operator tokens by moving
86 * to a table-based implementation. Also folded handling of parens
87 * into the table.
88 * b) Combined all 3 loops which called arith_apply to reduce generated
89 * code size at the cost of speed.
90 *
91 * 3) The following expressions were treated as valid by the original code:
92 * 1() , 0! , 1 ( *3 ) .
93 * These bugs have been fixed by internally enclosing the expression in
94 * parens and then checking that all binary ops and right parens are
95 * preceded by a valid expression (NUM_TOKEN).
96 *
97 * Note: It may be desirable to replace Aaron's test for whitespace with
98 * ctype's isspace() if it is used by another busybox applet or if additional
99 * whitespace chars should be considered. Look below the "#include"s for a
100 * precompiler test.
101 */
102
103/*
104 * Aug 26, 2001 Manuel Novoa III
105 *
106 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
107 *
108 * Merge in Aaron's comments previously posted to the busybox list,
109 * modified slightly to take account of my changes to the code.
110 *
111 */
112
113/*
114 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
115 *
116 * - allow access to variable,
117 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
118 * - realize assign syntax (VAR=expr, +=, *= etc)
119 * - realize exponentiation (** operator)
120 * - realize comma separated - expr, expr
121 * - realise ++expr --expr expr++ expr--
122 * - realise expr ? expr : expr (but, second expr calculate always)
123 * - allow hexadecimal and octal numbers
124 * - was restored loses XOR operator
125 * - remove one goto label, added three ;-)
126 * - protect $((num num)) as true zero expr (Manuel`s error)
127 * - always use special isspace(), see comment from bash ;-)
128 */
129
130#define arith_isspace(arithval) \
131 (arithval == ' ' || arithval == '\n' || arithval == '\t')
132
133typedef unsigned char operator;
134
135/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
136 * precedence, and 3 high bits are an ID unique across operators of that
137 * precedence. The ID portion is so that multiple operators can have the
138 * same precedence, ensuring that the leftmost one is evaluated first.
139 * Consider * and /. */
140
141#define tok_decl(prec,id) (((id)<<5)|(prec))
142#define PREC(op) ((op) & 0x1F)
143
144#define TOK_LPAREN tok_decl(0,0)
145
146#define TOK_COMMA tok_decl(1,0)
147
148#define TOK_ASSIGN tok_decl(2,0)
149#define TOK_AND_ASSIGN tok_decl(2,1)
150#define TOK_OR_ASSIGN tok_decl(2,2)
151#define TOK_XOR_ASSIGN tok_decl(2,3)
152#define TOK_PLUS_ASSIGN tok_decl(2,4)
153#define TOK_MINUS_ASSIGN tok_decl(2,5)
154#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
155#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
156
157#define TOK_MUL_ASSIGN tok_decl(3,0)
158#define TOK_DIV_ASSIGN tok_decl(3,1)
159#define TOK_REM_ASSIGN tok_decl(3,2)
160
161/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
162#define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
163
164/* conditional is right associativity too */
165#define TOK_CONDITIONAL tok_decl(4,0)
166#define TOK_CONDITIONAL_SEP tok_decl(4,1)
167
168#define TOK_OR tok_decl(5,0)
169
170#define TOK_AND tok_decl(6,0)
171
172#define TOK_BOR tok_decl(7,0)
173
174#define TOK_BXOR tok_decl(8,0)
175
176#define TOK_BAND tok_decl(9,0)
177
178#define TOK_EQ tok_decl(10,0)
179#define TOK_NE tok_decl(10,1)
180
181#define TOK_LT tok_decl(11,0)
182#define TOK_GT tok_decl(11,1)
183#define TOK_GE tok_decl(11,2)
184#define TOK_LE tok_decl(11,3)
185
186#define TOK_LSHIFT tok_decl(12,0)
187#define TOK_RSHIFT tok_decl(12,1)
188
189#define TOK_ADD tok_decl(13,0)
190#define TOK_SUB tok_decl(13,1)
191
192#define TOK_MUL tok_decl(14,0)
193#define TOK_DIV tok_decl(14,1)
194#define TOK_REM tok_decl(14,2)
195
196/* exponent is right associativity */
197#define TOK_EXPONENT tok_decl(15,1)
198
199/* For now unary operators. */
200#define UNARYPREC 16
201#define TOK_BNOT tok_decl(UNARYPREC,0)
202#define TOK_NOT tok_decl(UNARYPREC,1)
203
204#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
205#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
206
207#define PREC_PRE (UNARYPREC+2)
208
209#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
210#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
211
212#define PREC_POST (UNARYPREC+3)
213
214#define TOK_POST_INC tok_decl(PREC_POST, 0)
215#define TOK_POST_DEC tok_decl(PREC_POST, 1)
216
217#define SPEC_PREC (UNARYPREC+4)
218
219#define TOK_NUM tok_decl(SPEC_PREC, 0)
220#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
221
222#define NUMPTR (*numstackptr)
223
224static int
225tok_have_assign(operator op)
226{
227 operator prec = PREC(op);
228
229 convert_prec_is_assing(prec);
230 return (prec == PREC(TOK_ASSIGN) ||
231 prec == PREC_PRE || prec == PREC_POST);
232}
233
234static int
235is_right_associativity(operator prec)
236{
237 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
238 || prec == PREC(TOK_CONDITIONAL));
239}
240
241typedef struct {
242 arith_t val;
243 arith_t contidional_second_val;
244 char contidional_second_val_initialized;
245 char *var; /* if NULL then is regular number,
246 else is variable name */
247} v_n_t;
248
249typedef struct chk_var_recursive_looped_t {
250 const char *var;
251 struct chk_var_recursive_looped_t *next;
252} chk_var_recursive_looped_t;
253
254static chk_var_recursive_looped_t *prev_chk_var_recursive;
255
256static int
257arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks)
258{
259 if (t->var) {
Denys Vlasenko76ace252009-10-12 15:25:01 +0200260 const char *p = lookupvar(t->var);
Mike Frysinger98c52642009-04-02 10:02:37 +0000261
262 if (p) {
263 int errcode;
264
265 /* recursive try as expression */
266 chk_var_recursive_looped_t *cur;
267 chk_var_recursive_looped_t cur_save;
268
269 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
270 if (strcmp(cur->var, t->var) == 0) {
271 /* expression recursion loop detected */
272 return -5;
273 }
274 }
275 /* save current lookuped var name */
276 cur = prev_chk_var_recursive;
277 cur_save.var = t->var;
278 cur_save.next = cur;
279 prev_chk_var_recursive = &cur_save;
280
281 t->val = arith (p, &errcode, math_hooks);
282 /* restore previous ptr after recursiving */
283 prev_chk_var_recursive = cur;
284 return errcode;
285 }
286 /* allow undefined var as 0 */
287 t->val = 0;
288 }
289 return 0;
290}
291
292/* "applying" a token means performing it on the top elements on the integer
293 * stack. For a unary operator it will only change the top element, but a
294 * binary operator will pop two arguments and push a result */
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +0200295static NOINLINE int
Mike Frysinger98c52642009-04-02 10:02:37 +0000296arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hooks)
297{
298 v_n_t *numptr_m1;
299 arith_t numptr_val, rez;
300 int ret_arith_lookup_val;
301
302 /* There is no operator that can work without arguments */
303 if (NUMPTR == numstack) goto err;
304 numptr_m1 = NUMPTR - 1;
305
306 /* check operand is var with noninteger value */
307 ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks);
308 if (ret_arith_lookup_val)
309 return ret_arith_lookup_val;
310
311 rez = numptr_m1->val;
312 if (op == TOK_UMINUS)
313 rez *= -1;
314 else if (op == TOK_NOT)
315 rez = !rez;
316 else if (op == TOK_BNOT)
317 rez = ~rez;
318 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
319 rez++;
320 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
321 rez--;
322 else if (op != TOK_UPLUS) {
323 /* Binary operators */
324
325 /* check and binary operators need two arguments */
326 if (numptr_m1 == numstack) goto err;
327
328 /* ... and they pop one */
329 --NUMPTR;
330 numptr_val = rez;
331 if (op == TOK_CONDITIONAL) {
332 if (!numptr_m1->contidional_second_val_initialized) {
333 /* protect $((expr1 ? expr2)) without ": expr" */
334 goto err;
335 }
336 rez = numptr_m1->contidional_second_val;
337 } else if (numptr_m1->contidional_second_val_initialized) {
338 /* protect $((expr1 : expr2)) without "expr ? " */
339 goto err;
340 }
341 numptr_m1 = NUMPTR - 1;
342 if (op != TOK_ASSIGN) {
343 /* check operand is var with noninteger value for not '=' */
344 ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks);
345 if (ret_arith_lookup_val)
346 return ret_arith_lookup_val;
347 }
348 if (op == TOK_CONDITIONAL) {
349 numptr_m1->contidional_second_val = rez;
350 }
351 rez = numptr_m1->val;
352 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
353 rez |= numptr_val;
354 else if (op == TOK_OR)
355 rez = numptr_val || rez;
356 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
357 rez &= numptr_val;
358 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
359 rez ^= numptr_val;
360 else if (op == TOK_AND)
361 rez = rez && numptr_val;
362 else if (op == TOK_EQ)
363 rez = (rez == numptr_val);
364 else if (op == TOK_NE)
365 rez = (rez != numptr_val);
366 else if (op == TOK_GE)
367 rez = (rez >= numptr_val);
368 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
369 rez >>= numptr_val;
370 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
371 rez <<= numptr_val;
372 else if (op == TOK_GT)
373 rez = (rez > numptr_val);
374 else if (op == TOK_LT)
375 rez = (rez < numptr_val);
376 else if (op == TOK_LE)
377 rez = (rez <= numptr_val);
378 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
379 rez *= numptr_val;
380 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
381 rez += numptr_val;
382 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
383 rez -= numptr_val;
384 else if (op == TOK_ASSIGN || op == TOK_COMMA)
385 rez = numptr_val;
386 else if (op == TOK_CONDITIONAL_SEP) {
387 if (numptr_m1 == numstack) {
388 /* protect $((expr : expr)) without "expr ? " */
389 goto err;
390 }
391 numptr_m1->contidional_second_val_initialized = op;
392 numptr_m1->contidional_second_val = numptr_val;
393 } else if (op == TOK_CONDITIONAL) {
394 rez = rez ?
395 numptr_val : numptr_m1->contidional_second_val;
396 } else if (op == TOK_EXPONENT) {
397 if (numptr_val < 0)
398 return -3; /* exponent less than 0 */
399 else {
400 arith_t c = 1;
401
402 if (numptr_val)
403 while (numptr_val--)
404 c *= rez;
405 rez = c;
406 }
407 } else if (numptr_val==0) /* zero divisor check */
408 return -2;
409 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
410 rez /= numptr_val;
411 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
412 rez %= numptr_val;
413 }
414 if (tok_have_assign(op)) {
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000415 char buf[sizeof(arith_t)*3 + 2];
Mike Frysinger98c52642009-04-02 10:02:37 +0000416
417 if (numptr_m1->var == NULL) {
418 /* Hmm, 1=2 ? */
419 goto err;
420 }
421 /* save to shell variable */
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000422 sprintf(buf, arith_t_fmt, rez);
Mike Frysinger98c52642009-04-02 10:02:37 +0000423 setvar(numptr_m1->var, buf, 0);
424 /* after saving, make previous value for v++ or v-- */
425 if (op == TOK_POST_INC)
426 rez--;
427 else if (op == TOK_POST_DEC)
428 rez++;
429 }
430 numptr_m1->val = rez;
431 /* protect geting var value, is number now */
432 numptr_m1->var = NULL;
433 return 0;
434 err:
435 return -1;
436}
437
438/* longest must be first */
439static const char op_tokens[] ALIGN1 = {
440 '<','<','=',0, TOK_LSHIFT_ASSIGN,
441 '>','>','=',0, TOK_RSHIFT_ASSIGN,
442 '<','<', 0, TOK_LSHIFT,
443 '>','>', 0, TOK_RSHIFT,
444 '|','|', 0, TOK_OR,
445 '&','&', 0, TOK_AND,
446 '!','=', 0, TOK_NE,
447 '<','=', 0, TOK_LE,
448 '>','=', 0, TOK_GE,
449 '=','=', 0, TOK_EQ,
450 '|','=', 0, TOK_OR_ASSIGN,
451 '&','=', 0, TOK_AND_ASSIGN,
452 '*','=', 0, TOK_MUL_ASSIGN,
453 '/','=', 0, TOK_DIV_ASSIGN,
454 '%','=', 0, TOK_REM_ASSIGN,
455 '+','=', 0, TOK_PLUS_ASSIGN,
456 '-','=', 0, TOK_MINUS_ASSIGN,
457 '-','-', 0, TOK_POST_DEC,
458 '^','=', 0, TOK_XOR_ASSIGN,
459 '+','+', 0, TOK_POST_INC,
460 '*','*', 0, TOK_EXPONENT,
461 '!', 0, TOK_NOT,
462 '<', 0, TOK_LT,
463 '>', 0, TOK_GT,
464 '=', 0, TOK_ASSIGN,
465 '|', 0, TOK_BOR,
466 '&', 0, TOK_BAND,
467 '*', 0, TOK_MUL,
468 '/', 0, TOK_DIV,
469 '%', 0, TOK_REM,
470 '+', 0, TOK_ADD,
471 '-', 0, TOK_SUB,
472 '^', 0, TOK_BXOR,
473 /* uniq */
474 '~', 0, TOK_BNOT,
475 ',', 0, TOK_COMMA,
476 '?', 0, TOK_CONDITIONAL,
477 ':', 0, TOK_CONDITIONAL_SEP,
478 ')', 0, TOK_RPAREN,
479 '(', 0, TOK_LPAREN,
480 0
481};
482/* ptr to ")" */
483#define endexpression (&op_tokens[sizeof(op_tokens)-7])
484
485arith_t
486arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
487{
488 char arithval; /* Current character under analysis */
489 operator lasttok, op;
490 operator prec;
491 operator *stack, *stackptr;
492 const char *p = endexpression;
493 int errcode;
494 v_n_t *numstack, *numstackptr;
495 unsigned datasizes = strlen(expr) + 2;
496
497 /* Stack of integers */
498 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
499 * in any given correct or incorrect expression is left as an exercise to
500 * the reader. */
501 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
502 /* Stack of operator tokens */
503 stackptr = stack = alloca(datasizes * sizeof(stack[0]));
504
505 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
506 *perrcode = errcode = 0;
507
508 while (1) {
509 arithval = *expr;
510 if (arithval == 0) {
511 if (p == endexpression) {
512 /* Null expression. */
513 return 0;
514 }
515
516 /* This is only reached after all tokens have been extracted from the
517 * input stream. If there are still tokens on the operator stack, they
518 * are to be applied in order. At the end, there should be a final
519 * result on the integer stack */
520
521 if (expr != endexpression + 1) {
522 /* If we haven't done so already, */
523 /* append a closing right paren */
524 expr = endexpression;
525 /* and let the loop process it. */
526 continue;
527 }
528 /* At this point, we're done with the expression. */
529 if (numstackptr != numstack+1) {
530 /* ... but if there isn't, it's bad */
531 err:
532 *perrcode = -1;
533 return *perrcode;
534 }
535 if (numstack->var) {
536 /* expression is $((var)) only, lookup now */
537 errcode = arith_lookup_val(numstack, math_hooks);
538 }
539 ret:
540 *perrcode = errcode;
541 return numstack->val;
542 }
543
544 /* Continue processing the expression. */
545 if (arith_isspace(arithval)) {
546 /* Skip whitespace */
547 goto prologue;
548 }
549 p = endofname(expr);
550 if (p != expr) {
551 size_t var_name_size = (p-expr) + 1; /* trailing zero */
552
553 numstackptr->var = alloca(var_name_size);
554 safe_strncpy(numstackptr->var, expr, var_name_size);
555 expr = p;
556 num:
557 numstackptr->contidional_second_val_initialized = 0;
558 numstackptr++;
559 lasttok = TOK_NUM;
560 continue;
561 }
562 if (isdigit(arithval)) {
563 numstackptr->var = NULL;
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200564 errno = 0;
565 /* call strtoul[l]: */
Mike Frysinger98c52642009-04-02 10:02:37 +0000566 numstackptr->val = strto_arith_t(expr, (char **) &expr, 0);
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200567 if (errno)
568 numstackptr->val = 0; /* bash compat */
Mike Frysinger98c52642009-04-02 10:02:37 +0000569 goto num;
570 }
571 for (p = op_tokens; ; p++) {
572 const char *o;
573
574 if (*p == 0) {
575 /* strange operator not found */
576 goto err;
577 }
578 for (o = expr; *p && *o == *p; p++)
579 o++;
580 if (!*p) {
581 /* found */
582 expr = o - 1;
583 break;
584 }
585 /* skip tail uncompared token */
586 while (*p)
587 p++;
588 /* skip zero delim */
589 p++;
590 }
591 op = p[1];
592
593 /* post grammar: a++ reduce to num */
594 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
595 lasttok = TOK_NUM;
596
597 /* Plus and minus are binary (not unary) _only_ if the last
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200598 * token was a number, or a right paren (which pretends to be
Mike Frysinger98c52642009-04-02 10:02:37 +0000599 * a number, since it evaluates to one). Think about it.
600 * It makes sense. */
601 if (lasttok != TOK_NUM) {
602 switch (op) {
603 case TOK_ADD:
604 op = TOK_UPLUS;
605 break;
606 case TOK_SUB:
607 op = TOK_UMINUS;
608 break;
609 case TOK_POST_INC:
610 op = TOK_PRE_INC;
611 break;
612 case TOK_POST_DEC:
613 op = TOK_PRE_DEC;
614 break;
615 }
616 }
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200617 /* We don't want an unary operator to cause recursive descent on the
Mike Frysinger98c52642009-04-02 10:02:37 +0000618 * stack, because there can be many in a row and it could cause an
619 * operator to be evaluated before its argument is pushed onto the
620 * integer stack. */
621 /* But for binary operators, "apply" everything on the operator
622 * stack until we find an operator with a lesser priority than the
623 * one we have just extracted. */
624 /* Left paren is given the lowest priority so it will never be
625 * "applied" in this way.
626 * if associativity is right and priority eq, applied also skip
627 */
628 prec = PREC(op);
629 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
630 /* not left paren or unary */
631 if (lasttok != TOK_NUM) {
632 /* binary op must be preceded by a num */
633 goto err;
634 }
635 while (stackptr != stack) {
636 if (op == TOK_RPAREN) {
637 /* The algorithm employed here is simple: while we don't
638 * hit an open paren nor the bottom of the stack, pop
639 * tokens and apply them */
640 if (stackptr[-1] == TOK_LPAREN) {
641 --stackptr;
642 /* Any operator directly after a */
643 lasttok = TOK_NUM;
644 /* close paren should consider itself binary */
645 goto prologue;
646 }
647 } else {
648 operator prev_prec = PREC(stackptr[-1]);
649
650 convert_prec_is_assing(prec);
651 convert_prec_is_assing(prev_prec);
652 if (prev_prec < prec)
653 break;
654 /* check right assoc */
655 if (prev_prec == prec && is_right_associativity(prec))
656 break;
657 }
658 errcode = arith_apply(*--stackptr, numstack, &numstackptr, math_hooks);
659 if (errcode) goto ret;
660 }
661 if (op == TOK_RPAREN) {
662 goto err;
663 }
664 }
665
666 /* Push this operator to the stack and remember it. */
667 *stackptr++ = lasttok = op;
668 prologue:
669 ++expr;
670 } /* while */
671}
672
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000673/*
Mike Frysinger98c52642009-04-02 10:02:37 +0000674 * Copyright (c) 1989, 1991, 1993, 1994
675 * The Regents of the University of California. All rights reserved.
676 *
677 * This code is derived from software contributed to Berkeley by
678 * Kenneth Almquist.
679 *
680 * Redistribution and use in source and binary forms, with or without
681 * modification, are permitted provided that the following conditions
682 * are met:
683 * 1. Redistributions of source code must retain the above copyright
684 * notice, this list of conditions and the following disclaimer.
685 * 2. Redistributions in binary form must reproduce the above copyright
686 * notice, this list of conditions and the following disclaimer in the
687 * documentation and/or other materials provided with the distribution.
688 * 3. Neither the name of the University nor the names of its contributors
689 * may be used to endorse or promote products derived from this software
690 * without specific prior written permission.
691 *
692 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
693 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
694 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
695 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
696 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
697 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
698 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
699 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
700 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
701 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
702 * SUCH DAMAGE.
703 */