blob: c698a442bde095ab3f0d21d3e2abb03d560119d5 [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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020026 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Mike Frysinger98c52642009-04-02 10:02:37 +000027 */
Mike Frysinger98c52642009-04-02 10:02:37 +000028/* 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 */
Mike Frysinger98c52642009-04-02 10:02:37 +000094/*
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 */
Mike Frysinger98c52642009-04-02 10:02:37 +0000103/*
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 */
Denys Vlasenko03dad222010-01-12 23:29:57 +0100119#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 )
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +0200125//#define endofname (math_hooks->endofname)
Mike Frysinger98c52642009-04-02 10:02:37 +0000126
Mike Frysinger98c52642009-04-02 10:02:37 +0000127typedef 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 */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200156#define convert_prec_is_assign(prec) do { if (prec == 3) prec = 2; } while (0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000157
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
218static int
219tok_have_assign(operator op)
220{
221 operator prec = PREC(op);
222
Denys Vlasenkob771c652010-09-13 00:34:26 +0200223 convert_prec_is_assign(prec);
Mike Frysinger98c52642009-04-02 10:02:37 +0000224 return (prec == PREC(TOK_ASSIGN) ||
225 prec == PREC_PRE || prec == PREC_POST);
226}
227
228static int
229is_right_associativity(operator prec)
230{
231 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
232 || prec == PREC(TOK_CONDITIONAL));
233}
234
235typedef 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
243typedef 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
248static chk_var_recursive_looped_t *prev_chk_var_recursive;
249
250static int
251arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks)
252{
253 if (t->var) {
Denys Vlasenko76ace252009-10-12 15:25:01 +0200254 const char *p = lookupvar(t->var);
Mike Frysinger98c52642009-04-02 10:02:37 +0000255
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 */
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +0200289static NOINLINE int
Mike Frysinger98c52642009-04-02 10:02:37 +0000290arith_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)) {
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000409 char buf[sizeof(arith_t)*3 + 2];
Mike Frysinger98c52642009-04-02 10:02:37 +0000410
411 if (numptr_m1->var == NULL) {
412 /* Hmm, 1=2 ? */
413 goto err;
414 }
415 /* save to shell variable */
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000416 sprintf(buf, arith_t_fmt, rez);
Denys Vlasenko03dad222010-01-12 23:29:57 +0100417 setvar(numptr_m1->var, buf);
Mike Frysinger98c52642009-04-02 10:02:37 +0000418 /* 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 */
433static 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 ")" */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200477#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
Mike Frysinger98c52642009-04-02 10:02:37 +0000478
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +0200479const char* FAST_FUNC
480endofname(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
Mike Frysinger98c52642009-04-02 10:02:37 +0000491arith_t
492arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
493{
Denys Vlasenkob771c652010-09-13 00:34:26 +0200494 operator lasttok;
Mike Frysinger98c52642009-04-02 10:02:37 +0000495 int errcode;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200496 const char *start_expr = expr = skip_whitespace(expr);
497 unsigned expr_len = strlen(expr) + 2;
Mike Frysinger98c52642009-04-02 10:02:37 +0000498 /* 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. */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200502 v_n_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
503 v_n_t *numstackptr = numstack;
Mike Frysinger98c52642009-04-02 10:02:37 +0000504 /* Stack of operator tokens */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200505 operator *const stack = alloca(expr_len * sizeof(stack[0]));
506 operator *stackptr = stack;
Mike Frysinger98c52642009-04-02 10:02:37 +0000507
508 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200509 errcode = 0;
Mike Frysinger98c52642009-04-02 10:02:37 +0000510
511 while (1) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200512 const char *p;
513 operator op;
514 operator prec;
515 char arithval;
516
517 expr = skip_whitespace(expr);
Mike Frysinger98c52642009-04-02 10:02:37 +0000518 arithval = *expr;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200519 if (arithval == '\0') {
520 if (expr == start_expr) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000521 /* Null expression. */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200522 numstack->val = 0;
523 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000524 }
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
Denys Vlasenkob771c652010-09-13 00:34:26 +0200531 if (expr != ptr_to_rparen + 1) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000532 /* If we haven't done so already, */
533 /* append a closing right paren */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200534 expr = ptr_to_rparen;
Mike Frysinger98c52642009-04-02 10:02:37 +0000535 /* and let the loop process it. */
536 continue;
537 }
538 /* At this point, we're done with the expression. */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200539 if (numstackptr != numstack + 1) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000540 /* ... but if there isn't, it's bad */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200541 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000542 }
543 if (numstack->var) {
544 /* expression is $((var)) only, lookup now */
545 errcode = arith_lookup_val(numstack, math_hooks);
546 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200547 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000548 }
549
Mike Frysinger98c52642009-04-02 10:02:37 +0000550 p = endofname(expr);
551 if (p != expr) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200552 /* Name */
553 size_t var_name_size = (p-expr) + 1; /* +1 for NUL */
Mike Frysinger98c52642009-04-02 10:02:37 +0000554 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 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200563
Mike Frysinger98c52642009-04-02 10:02:37 +0000564 if (isdigit(arithval)) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200565 /* Number */
Mike Frysinger98c52642009-04-02 10:02:37 +0000566 numstackptr->var = NULL;
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200567 errno = 0;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200568 numstackptr->val = strto_arith_t(expr, (char**) &expr, 0);
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200569 if (errno)
570 numstackptr->val = 0; /* bash compat */
Mike Frysinger98c52642009-04-02 10:02:37 +0000571 goto num;
572 }
Mike Frysinger98c52642009-04-02 10:02:37 +0000573
Denys Vlasenkob771c652010-09-13 00:34:26 +0200574 /* 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;
Mike Frysinger98c52642009-04-02 10:02:37 +0000583 break;
584 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200585 /* Go to next element of op_tokens[] */
Mike Frysinger98c52642009-04-02 10:02:37 +0000586 while (*p)
587 p++;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200588 p += 2; /* skip NUL and TOK_foo bytes */
589 if (*p == '\0') /* no next element, operator not found */
590 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000591 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200592 op = p[1]; /* fetch TOK_foo value */
593 /* NB: expr now points past the operator */
Mike Frysinger98c52642009-04-02 10:02:37 +0000594
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
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200600 * token was a number, or a right paren (which pretends to be
Mike Frysinger98c52642009-04-02 10:02:37 +0000601 * 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 }
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200619 /* We don't want an unary operator to cause recursive descent on the
Mike Frysinger98c52642009-04-02 10:02:37 +0000620 * 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) {
Denys Vlasenko51850c82010-09-13 01:09:11 +0200638 operator prev_op = *--stackptr;
Mike Frysinger98c52642009-04-02 10:02:37 +0000639 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 */
Denys Vlasenko51850c82010-09-13 01:09:11 +0200643 if (prev_op == TOK_LPAREN) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000644 /* Any operator directly after a */
645 lasttok = TOK_NUM;
646 /* close paren should consider itself binary */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200647 goto next;
Mike Frysinger98c52642009-04-02 10:02:37 +0000648 }
649 } else {
Denys Vlasenko51850c82010-09-13 01:09:11 +0200650 operator prev_prec = PREC(prev_op);
Denys Vlasenkob771c652010-09-13 00:34:26 +0200651 convert_prec_is_assign(prec);
652 convert_prec_is_assign(prev_prec);
Denys Vlasenko51850c82010-09-13 01:09:11 +0200653 if (prev_prec < prec
654 || (prev_prec == prec && is_right_associativity(prec))
655 ) {
656 stackptr++;
Mike Frysinger98c52642009-04-02 10:02:37 +0000657 break;
Denys Vlasenko51850c82010-09-13 01:09:11 +0200658 }
Mike Frysinger98c52642009-04-02 10:02:37 +0000659 }
Denys Vlasenko51850c82010-09-13 01:09:11 +0200660 errcode = arith_apply(prev_op, numstack, &numstackptr, math_hooks);
Denys Vlasenkob771c652010-09-13 00:34:26 +0200661 if (errcode)
662 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000663 }
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;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200671 next: ;
672 } /* while (1) */
673
674 err:
675 numstack->val = errcode = -1;
676 ret:
677 *perrcode = errcode;
678 return numstack->val;
Mike Frysinger98c52642009-04-02 10:02:37 +0000679}
680
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000681/*
Mike Frysinger98c52642009-04-02 10:02:37 +0000682 * 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 */