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