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