]> git.ipfire.org Git - thirdparty/bash.git/blame - expr.c
Bash-4.3 patch 11
[thirdparty/bash.git] / expr.c
CommitLineData
726f6388
JA
1/* expr.c -- arithmetic expression evaluation. */
2
ac50fbac 3/* Copyright (C) 1990-2013 Free Software Foundation, Inc.
726f6388
JA
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
3185942a
JA
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
726f6388 11
3185942a
JA
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
726f6388
JA
16
17 You should have received a copy of the GNU General Public License
3185942a
JA
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19*/
726f6388
JA
20
21/*
7117c2d2 22 All arithmetic is done as intmax_t integers with no checking for overflow
726f6388
JA
23 (though division by 0 is caught and flagged as an error).
24
25 The following operators are handled, grouped into a set of levels in
26 order of decreasing precedence.
27
bb70624e
JA
28 "id++", "id--" [post-increment and post-decrement]
29 "++id", "--id" [pre-increment and pre-decrement]
726f6388
JA
30 "-", "+" [(unary operators)]
31 "!", "~"
cce855bc 32 "**" [(exponentiation)]
726f6388
JA
33 "*", "/", "%"
34 "+", "-"
35 "<<", ">>"
36 "<=", ">=", "<", ">"
37 "==", "!="
38 "&"
39 "^"
40 "|"
41 "&&"
42 "||"
ccc6cda3 43 "expr ? expr : expr"
cce855bc 44 "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="
b80f6443 45 , [comma]
726f6388
JA
46
47 (Note that most of these operators have special meaning to bash, and an
48 entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure
49 that it is passed intact to the evaluator when using `let'. When using
50 the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))'
51 is treated as if in double quotes.)
52
53 Sub-expressions within parentheses have a precedence level greater than
54 all of the above levels and are evaluated first. Within a single prece-
55 dence group, evaluation is left-to-right, except for the arithmetic
56 assignment operator (`='), which is evaluated right-to-left (as in C).
57
58 The expression evaluator returns the value of the expression (assignment
59 statements have as a value what is returned by the RHS). The `let'
60 builtin, on the other hand, returns 0 if the last expression evaluates to
61 a non-zero, and 1 otherwise.
62
63 Implementation is a recursive-descent parser.
64
65 Chet Ramey
ac50fbac 66 chet@po.cwru.edu
726f6388
JA
67*/
68
ccc6cda3
JA
69#include "config.h"
70
726f6388
JA
71#include <stdio.h>
72#include "bashansi.h"
cce855bc 73
ccc6cda3 74#if defined (HAVE_UNISTD_H)
cce855bc
JA
75# ifdef _MINIX
76# include <sys/types.h>
77# endif
ccc6cda3
JA
78# include <unistd.h>
79#endif
726f6388 80
f73dda09 81#include "chartypes.h"
b80f6443 82#include "bashintl.h"
bb70624e 83
ccc6cda3 84#include "shell.h"
ac50fbac 85#include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */
726f6388
JA
86
87/* Because of the $((...)) construct, expressions may include newlines.
88 Here is a macro which accepts newlines, tabs and spaces as whitespace. */
89#define cr_whitespace(c) (whitespace(c) || ((c) == '\n'))
90
ac50fbac 91/* Size be which the expression stack grows when necessary. */
726f6388
JA
92#define EXPR_STACK_GROW_SIZE 10
93
94/* Maximum amount of recursion allowed. This prevents a non-integer
95 variable such as "num=num+2" from infinitely adding to itself when
ccc6cda3 96 "let num=num+2" is given. */
726f6388
JA
97#define MAX_EXPR_RECURSION_LEVEL 1024
98
99/* The Tokens. Singing "The Lion Sleeps Tonight". */
100
101#define EQEQ 1 /* "==" */
102#define NEQ 2 /* "!=" */
103#define LEQ 3 /* "<=" */
104#define GEQ 4 /* ">=" */
105#define STR 5 /* string */
106#define NUM 6 /* number */
107#define LAND 7 /* "&&" Logical AND */
108#define LOR 8 /* "||" Logical OR */
109#define LSH 9 /* "<<" Left SHift */
110#define RSH 10 /* ">>" Right SHift */
111#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */
cce855bc
JA
112#define COND 12 /* exp1 ? exp2 : exp3 */
113#define POWER 13 /* exp1**exp2 */
bb70624e
JA
114#define PREINC 14 /* ++var */
115#define PREDEC 15 /* --var */
116#define POSTINC 16 /* var++ */
117#define POSTDEC 17 /* var-- */
726f6388
JA
118#define EQ '='
119#define GT '>'
120#define LT '<'
121#define PLUS '+'
122#define MINUS '-'
123#define MUL '*'
124#define DIV '/'
125#define MOD '%'
126#define NOT '!'
127#define LPAR '('
128#define RPAR ')'
129#define BAND '&' /* Bitwise AND */
ccc6cda3 130#define BOR '|' /* Bitwise OR. */
726f6388
JA
131#define BXOR '^' /* Bitwise eXclusive OR. */
132#define BNOT '~' /* Bitwise NOT; Two's complement. */
ccc6cda3
JA
133#define QUES '?'
134#define COL ':'
bb70624e
JA
135#define COMMA ','
136
137/* This should be the function corresponding to the operator with the
138 highest precedence. */
139#define EXP_HIGHEST expcomma
ccc6cda3 140
495aee44
CR
141#ifndef MAX_INT_LEN
142# define MAX_INT_LEN 32
143#endif
144
145struct lvalue
146{
147 char *tokstr; /* possibly-rewritten lvalue if not NULL */
148 intmax_t tokval; /* expression evaluated value */
149 SHELL_VAR *tokvar; /* variable described by array or var reference */
150 intmax_t ind; /* array index if not -1 */
151};
152
153/* A structure defining a single expression context. */
154typedef struct {
155 int curtok, lasttok;
156 char *expression, *tp, *lasttp;
157 intmax_t tokval;
158 char *tokstr;
159 int noeval;
160 struct lvalue lval;
161} EXPR_CONTEXT;
162
ccc6cda3
JA
163static char *expression; /* The current expression */
164static char *tp; /* token lexical position */
165static char *lasttp; /* pointer to last token position */
166static int curtok; /* the current token */
167static int lasttok; /* the previous token */
168static int assigntok; /* the OP in OP= */
169static char *tokstr; /* current token string */
7117c2d2 170static intmax_t tokval; /* current token value */
ccc6cda3
JA
171static int noeval; /* set to 1 if no assignment to be done */
172static procenv_t evalbuf;
173
495aee44
CR
174static struct lvalue curlval = {0, 0, 0, -1};
175static struct lvalue lastlval = {0, 0, 0, -1};
176
0628567a 177static int _is_arithop __P((int));
f73dda09 178static void readtok __P((void)); /* lexical analyzer */
7117c2d2 179
495aee44
CR
180static void init_lvalue __P((struct lvalue *));
181static struct lvalue *alloc_lvalue __P((void));
182static void free_lvalue __P((struct lvalue *));
183
184static intmax_t expr_streval __P((char *, int, struct lvalue *));
7117c2d2 185static intmax_t strlong __P((char *));
3185942a 186static void evalerror __P((const char *));
f73dda09
JA
187
188static void pushexp __P((void));
189static void popexp __P((void));
7117c2d2 190static void expr_unwind __P((void));
b80f6443 191static void expr_bind_variable __P((char *, char *));
ac50fbac 192#if defined (ARRAY_VARS)
495aee44 193static void expr_bind_array_element __P((char *, arrayind_t, char *));
ac50fbac 194#endif
7117c2d2
JA
195
196static intmax_t subexpr __P((char *));
197
198static intmax_t expcomma __P((void));
199static intmax_t expassign __P((void));
200static intmax_t expcond __P((void));
201static intmax_t explor __P((void));
202static intmax_t expland __P((void));
203static intmax_t expbor __P((void));
204static intmax_t expbxor __P((void));
205static intmax_t expband __P((void));
206static intmax_t exp5 __P((void));
207static intmax_t exp4 __P((void));
208static intmax_t expshift __P((void));
209static intmax_t exp3 __P((void));
210static intmax_t exp2 __P((void));
211static intmax_t exppower __P((void));
212static intmax_t exp1 __P((void));
213static intmax_t exp0 __P((void));
ccc6cda3 214
ccc6cda3
JA
215/* Global var which contains the stack of expression contexts. */
216static EXPR_CONTEXT **expr_stack;
217static int expr_depth; /* Location in the stack. */
218static int expr_stack_size; /* Number of slots already allocated. */
219
220extern char *this_command_name;
0001803f 221extern int unbound_vars_is_error, last_command_exit_value;
726f6388 222
b80f6443 223#if defined (ARRAY_VARS)
3185942a 224extern const char * const bash_badsub_errmsg;
b80f6443
JA
225#endif
226
bb70624e
JA
227#define SAVETOK(X) \
228 do { \
229 (X)->curtok = curtok; \
230 (X)->lasttok = lasttok; \
231 (X)->tp = tp; \
232 (X)->lasttp = lasttp; \
233 (X)->tokval = tokval; \
234 (X)->tokstr = tokstr; \
235 (X)->noeval = noeval; \
495aee44 236 (X)->lval = curlval; \
bb70624e
JA
237 } while (0)
238
239#define RESTORETOK(X) \
240 do { \
241 curtok = (X)->curtok; \
242 lasttok = (X)->lasttok; \
243 tp = (X)->tp; \
244 lasttp = (X)->lasttp; \
245 tokval = (X)->tokval; \
246 tokstr = (X)->tokstr; \
247 noeval = (X)->noeval; \
495aee44 248 curlval = (X)->lval; \
bb70624e
JA
249 } while (0)
250
726f6388
JA
251/* Push and save away the contents of the globals describing the
252 current expression context. */
253static void
254pushexp ()
255{
256 EXPR_CONTEXT *context;
257
726f6388 258 if (expr_depth >= MAX_EXPR_RECURSION_LEVEL)
b80f6443 259 evalerror (_("expression recursion level exceeded"));
726f6388
JA
260
261 if (expr_depth >= expr_stack_size)
262 {
f73dda09
JA
263 expr_stack_size += EXPR_STACK_GROW_SIZE;
264 expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *));
726f6388
JA
265 }
266
d166f048
JA
267 context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT));
268
726f6388 269 context->expression = expression;
bb70624e
JA
270 SAVETOK(context);
271
726f6388
JA
272 expr_stack[expr_depth++] = context;
273}
274
275/* Pop the the contents of the expression context stack into the
276 globals describing the current expression context. */
277static void
278popexp ()
279{
280 EXPR_CONTEXT *context;
281
282 if (expr_depth == 0)
b80f6443 283 evalerror (_("recursion stack underflow"));
726f6388
JA
284
285 context = expr_stack[--expr_depth];
bb70624e 286
726f6388 287 expression = context->expression;
bb70624e
JA
288 RESTORETOK (context);
289
726f6388
JA
290 free (context);
291}
292
7117c2d2
JA
293static void
294expr_unwind ()
295{
296 while (--expr_depth > 0)
297 {
298 if (expr_stack[expr_depth]->tokstr)
299 free (expr_stack[expr_depth]->tokstr);
300
301 if (expr_stack[expr_depth]->expression)
302 free (expr_stack[expr_depth]->expression);
303
304 free (expr_stack[expr_depth]);
305 }
306 free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */
f1be666c
JA
307
308 noeval = 0; /* XXX */
7117c2d2
JA
309}
310
b80f6443
JA
311static void
312expr_bind_variable (lhs, rhs)
313 char *lhs, *rhs;
314{
ac50fbac
CR
315 SHELL_VAR *v;
316
317 v = bind_int_variable (lhs, rhs);
318 if (v && (readonly_p (v) || noassign_p (v)))
319 longjmp (evalbuf, 1); /* variable assignment error */
b80f6443
JA
320 stupidly_hack_special_variables (lhs);
321}
322
ac50fbac 323#if defined (ARRAY_VARS)
495aee44
CR
324/* Rewrite tok, which is of the form vname[expression], to vname[ind], where
325 IND is the already-calculated value of expression. */
326static void
327expr_bind_array_element (tok, ind, rhs)
328 char *tok;
329 arrayind_t ind;
330 char *rhs;
331{
332 char *lhs, *vname;
333 size_t llen;
334 char ibuf[INT_STRLEN_BOUND (arrayind_t) + 1], *istr;
335
336 istr = fmtumax (ind, 10, ibuf, sizeof (ibuf), 0);
337 vname = array_variable_name (tok, (char **)NULL, (int *)NULL);
338
339 llen = strlen (vname) + sizeof (ibuf) + 3;
340 lhs = xmalloc (llen);
341
342 sprintf (lhs, "%s[%s]", vname, istr); /* XXX */
343
495aee44 344/*itrace("expr_bind_array_element: %s=%s", lhs, rhs);*/
ac50fbac 345 expr_bind_variable (lhs, rhs);
495aee44
CR
346 free (vname);
347 free (lhs);
348}
ac50fbac 349#endif /* ARRAY_VARS */
495aee44 350
d166f048
JA
351/* Evaluate EXPR, and return the arithmetic result. If VALIDP is
352 non-null, a zero is stored into the location to which it points
353 if the expression is invalid, non-zero otherwise. If a non-zero
354 value is returned in *VALIDP, the return value of evalexp() may
355 be used.
726f6388
JA
356
357 The `while' loop after the longjmp is caught relies on the above
358 implementation of pushexp and popexp leaving in expr_stack[0] the
359 values that the variables had when the program started. That is,
ccc6cda3 360 the first things saved are the initial values of the variables that
726f6388
JA
361 were assigned at program startup or by the compiler. Therefore, it is
362 safe to let the loop terminate when expr_depth == 0, without freeing up
363 any of the expr_depth[0] stuff. */
7117c2d2 364intmax_t
d166f048 365evalexp (expr, validp)
726f6388 366 char *expr;
d166f048 367 int *validp;
726f6388 368{
7117c2d2 369 intmax_t val;
b80f6443
JA
370 int c;
371 procenv_t oevalbuf;
726f6388 372
f73dda09 373 val = 0;
f1be666c 374 noeval = 0;
726f6388 375
b80f6443
JA
376 FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf));
377
ac50fbac 378 c = setjmp_nosigs (evalbuf);
b80f6443
JA
379
380 if (c)
726f6388 381 {
d166f048
JA
382 FREE (tokstr);
383 FREE (expression);
384 tokstr = expression = (char *)NULL;
726f6388 385
7117c2d2 386 expr_unwind ();
d166f048
JA
387
388 if (validp)
389 *validp = 0;
f73dda09 390 return (0);
726f6388
JA
391 }
392
d166f048
JA
393 val = subexpr (expr);
394
d166f048
JA
395 if (validp)
396 *validp = 1;
397
b80f6443
JA
398 FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf));
399
d166f048
JA
400 return (val);
401}
402
7117c2d2 403static intmax_t
d166f048
JA
404subexpr (expr)
405 char *expr;
406{
7117c2d2 407 intmax_t val;
d166f048
JA
408 char *p;
409
410 for (p = expr; p && *p && cr_whitespace (*p); p++)
411 ;
412
413 if (p == NULL || *p == '\0')
f73dda09 414 return (0);
d166f048 415
726f6388 416 pushexp ();
726f6388
JA
417 expression = savestring (expr);
418 tp = expression;
419
495aee44 420 curtok = lasttok = 0;
726f6388 421 tokstr = (char *)NULL;
f73dda09 422 tokval = 0;
495aee44
CR
423 init_lvalue (&curlval);
424 lastlval = curlval;
726f6388
JA
425
426 readtok ();
427
bb70624e 428 val = EXP_HIGHEST ();
726f6388 429
ccc6cda3 430 if (curtok != 0)
b80f6443 431 evalerror (_("syntax error in expression"));
726f6388 432
d166f048
JA
433 FREE (tokstr);
434 FREE (expression);
726f6388
JA
435
436 popexp ();
437
d166f048 438 return val;
726f6388
JA
439}
440
7117c2d2 441static intmax_t
bb70624e 442expcomma ()
726f6388 443{
7117c2d2 444 register intmax_t value;
726f6388 445
bb70624e
JA
446 value = expassign ();
447 while (curtok == COMMA)
726f6388 448 {
bb70624e
JA
449 readtok ();
450 value = expassign ();
726f6388
JA
451 }
452
bb70624e 453 return value;
726f6388 454}
bb70624e 455
7117c2d2 456static intmax_t
726f6388
JA
457expassign ()
458{
7117c2d2 459 register intmax_t value;
726f6388 460 char *lhs, *rhs;
495aee44 461 arrayind_t lind;
ac50fbac
CR
462#if defined (HAVE_IMAXDIV)
463 imaxdiv_t idiv;
464#endif
726f6388 465
ccc6cda3 466 value = expcond ();
726f6388
JA
467 if (curtok == EQ || curtok == OP_ASSIGN)
468 {
ccc6cda3 469 int special, op;
7117c2d2 470 intmax_t lvalue;
726f6388 471
ccc6cda3
JA
472 special = curtok == OP_ASSIGN;
473
726f6388 474 if (lasttok != STR)
b80f6443 475 evalerror (_("attempted assignment to non-variable"));
726f6388
JA
476
477 if (special)
478 {
479 op = assigntok; /* a OP= b */
480 lvalue = value;
481 }
482
ac50fbac 483 /* XXX - watch out for pointer aliasing issues here */
726f6388 484 lhs = savestring (tokstr);
495aee44
CR
485 /* save ind in case rhs is string var and evaluation overwrites it */
486 lind = curlval.ind;
726f6388
JA
487 readtok ();
488 value = expassign ();
489
490 if (special)
491 {
cf391c36
CR
492 if ((op == DIV || op == MOD) && value == 0)
493 {
494 if (noeval == 0)
495 evalerror (_("division by 0"));
496 else
497 value = 1;
498 }
499
726f6388
JA
500 switch (op)
501 {
502 case MUL:
503 lvalue *= value;
504 break;
505 case DIV:
726f6388 506 case MOD:
ac50fbac
CR
507 if (lvalue == INTMAX_MIN && value == -1)
508 lvalue = (op == DIV) ? INTMAX_MIN : 0;
509 else
510#if HAVE_IMAXDIV
511 {
512 idiv = imaxdiv (lvalue, value);
513 lvalue = (op == DIV) ? idiv.quot : idiv.rem;
514 }
515#else
516 lvalue = (op == DIV) ? lvalue / value : lvalue % value;
517#endif
726f6388
JA
518 break;
519 case PLUS:
520 lvalue += value;
521 break;
522 case MINUS:
523 lvalue -= value;
524 break;
525 case LSH:
526 lvalue <<= value;
527 break;
528 case RSH:
529 lvalue >>= value;
530 break;
531 case BAND:
532 lvalue &= value;
533 break;
534 case BOR:
535 lvalue |= value;
536 break;
28ef6c31
JA
537 case BXOR:
538 lvalue ^= value;
539 break;
726f6388 540 default:
d166f048 541 free (lhs);
b80f6443 542 evalerror (_("bug: bad expassign token"));
726f6388
JA
543 break;
544 }
545 value = lvalue;
546 }
547
548 rhs = itos (value);
ccc6cda3 549 if (noeval == 0)
495aee44 550 {
ac50fbac 551#if defined (ARRAY_VARS)
495aee44
CR
552 if (lind != -1)
553 expr_bind_array_element (lhs, lind, rhs);
554 else
ac50fbac 555#endif
495aee44
CR
556 expr_bind_variable (lhs, rhs);
557 }
ac50fbac
CR
558 if (curlval.tokstr && curlval.tokstr == tokstr)
559 init_lvalue (&curlval);
560
726f6388
JA
561 free (rhs);
562 free (lhs);
d166f048 563 FREE (tokstr);
726f6388
JA
564 tokstr = (char *)NULL; /* For freeing on errors. */
565 }
ac50fbac 566
726f6388
JA
567 return (value);
568}
569
ccc6cda3 570/* Conditional expression (expr?expr:expr) */
7117c2d2 571static intmax_t
ccc6cda3
JA
572expcond ()
573{
7117c2d2 574 intmax_t cval, val1, val2, rval;
d166f048
JA
575 int set_noeval;
576
577 set_noeval = 0;
ccc6cda3
JA
578 rval = cval = explor ();
579 if (curtok == QUES) /* found conditional expr */
580 {
581 readtok ();
582 if (curtok == 0 || curtok == COL)
b80f6443 583 evalerror (_("expression expected"));
ccc6cda3 584 if (cval == 0)
d166f048
JA
585 {
586 set_noeval = 1;
587 noeval++;
588 }
f73dda09 589
bb70624e 590 val1 = EXP_HIGHEST ();
f73dda09 591
d166f048 592 if (set_noeval)
28ef6c31 593 noeval--;
ccc6cda3 594 if (curtok != COL)
b80f6443 595 evalerror (_("`:' expected for conditional expression"));
ccc6cda3
JA
596 readtok ();
597 if (curtok == 0)
b80f6443 598 evalerror (_("expression expected"));
d166f048 599 set_noeval = 0;
ccc6cda3 600 if (cval)
d166f048
JA
601 {
602 set_noeval = 1;
603 noeval++;
604 }
f1be666c
JA
605
606 val2 = expcond ();
d166f048 607 if (set_noeval)
28ef6c31 608 noeval--;
ccc6cda3
JA
609 rval = cval ? val1 : val2;
610 lasttok = COND;
611 }
612 return rval;
613}
614
726f6388 615/* Logical OR. */
7117c2d2 616static intmax_t
726f6388
JA
617explor ()
618{
7117c2d2 619 register intmax_t val1, val2;
d166f048 620 int set_noeval;
726f6388
JA
621
622 val1 = expland ();
623
624 while (curtok == LOR)
625 {
d166f048 626 set_noeval = 0;
ccc6cda3 627 if (val1 != 0)
d166f048
JA
628 {
629 noeval++;
630 set_noeval = 1;
631 }
632 readtok ();
726f6388 633 val2 = expland ();
d166f048 634 if (set_noeval)
ccc6cda3 635 noeval--;
726f6388 636 val1 = val1 || val2;
d166f048 637 lasttok = LOR;
726f6388
JA
638 }
639
640 return (val1);
641}
642
643/* Logical AND. */
7117c2d2 644static intmax_t
726f6388
JA
645expland ()
646{
7117c2d2 647 register intmax_t val1, val2;
d166f048 648 int set_noeval;
726f6388
JA
649
650 val1 = expbor ();
651
652 while (curtok == LAND)
653 {
d166f048 654 set_noeval = 0;
ccc6cda3 655 if (val1 == 0)
d166f048
JA
656 {
657 set_noeval = 1;
658 noeval++;
659 }
660 readtok ();
726f6388 661 val2 = expbor ();
d166f048 662 if (set_noeval)
ccc6cda3 663 noeval--;
726f6388 664 val1 = val1 && val2;
d166f048 665 lasttok = LAND;
726f6388
JA
666 }
667
668 return (val1);
669}
670
671/* Bitwise OR. */
7117c2d2 672static intmax_t
726f6388
JA
673expbor ()
674{
7117c2d2 675 register intmax_t val1, val2;
726f6388
JA
676
677 val1 = expbxor ();
678
679 while (curtok == BOR)
680 {
681 readtok ();
682 val2 = expbxor ();
683 val1 = val1 | val2;
ac50fbac 684 lasttok = NUM;
726f6388
JA
685 }
686
687 return (val1);
688}
689
690/* Bitwise XOR. */
7117c2d2 691static intmax_t
726f6388
JA
692expbxor ()
693{
7117c2d2 694 register intmax_t val1, val2;
726f6388
JA
695
696 val1 = expband ();
697
698 while (curtok == BXOR)
699 {
700 readtok ();
701 val2 = expband ();
702 val1 = val1 ^ val2;
ac50fbac 703 lasttok = NUM;
726f6388
JA
704 }
705
706 return (val1);
707}
708
709/* Bitwise AND. */
7117c2d2 710static intmax_t
726f6388
JA
711expband ()
712{
7117c2d2 713 register intmax_t val1, val2;
726f6388
JA
714
715 val1 = exp5 ();
716
717 while (curtok == BAND)
718 {
719 readtok ();
720 val2 = exp5 ();
721 val1 = val1 & val2;
ac50fbac 722 lasttok = NUM;
726f6388
JA
723 }
724
725 return (val1);
726}
727
7117c2d2 728static intmax_t
726f6388
JA
729exp5 ()
730{
7117c2d2 731 register intmax_t val1, val2;
726f6388
JA
732
733 val1 = exp4 ();
734
735 while ((curtok == EQEQ) || (curtok == NEQ))
736 {
737 int op = curtok;
738
739 readtok ();
740 val2 = exp4 ();
741 if (op == EQEQ)
742 val1 = (val1 == val2);
743 else if (op == NEQ)
744 val1 = (val1 != val2);
ac50fbac 745 lasttok = NUM;
726f6388
JA
746 }
747 return (val1);
748}
749
7117c2d2 750static intmax_t
726f6388
JA
751exp4 ()
752{
7117c2d2 753 register intmax_t val1, val2;
726f6388
JA
754
755 val1 = expshift ();
756 while ((curtok == LEQ) ||
757 (curtok == GEQ) ||
758 (curtok == LT) ||
759 (curtok == GT))
760 {
761 int op = curtok;
762
763 readtok ();
764 val2 = expshift ();
765
766 if (op == LEQ)
767 val1 = val1 <= val2;
768 else if (op == GEQ)
769 val1 = val1 >= val2;
770 else if (op == LT)
771 val1 = val1 < val2;
d166f048 772 else /* (op == GT) */
726f6388 773 val1 = val1 > val2;
ac50fbac 774 lasttok = NUM;
726f6388
JA
775 }
776 return (val1);
777}
778
779/* Left and right shifts. */
7117c2d2 780static intmax_t
726f6388
JA
781expshift ()
782{
7117c2d2 783 register intmax_t val1, val2;
726f6388
JA
784
785 val1 = exp3 ();
786
787 while ((curtok == LSH) || (curtok == RSH))
788 {
789 int op = curtok;
790
791 readtok ();
792 val2 = exp3 ();
793
794 if (op == LSH)
795 val1 = val1 << val2;
796 else
797 val1 = val1 >> val2;
ac50fbac 798 lasttok = NUM;
726f6388
JA
799 }
800
801 return (val1);
802}
803
7117c2d2 804static intmax_t
726f6388
JA
805exp3 ()
806{
7117c2d2 807 register intmax_t val1, val2;
726f6388
JA
808
809 val1 = exp2 ();
810
811 while ((curtok == PLUS) || (curtok == MINUS))
812 {
813 int op = curtok;
814
815 readtok ();
816 val2 = exp2 ();
817
818 if (op == PLUS)
819 val1 += val2;
820 else if (op == MINUS)
821 val1 -= val2;
ac50fbac 822 lasttok = NUM;
726f6388
JA
823 }
824 return (val1);
825}
826
7117c2d2 827static intmax_t
726f6388
JA
828exp2 ()
829{
7117c2d2 830 register intmax_t val1, val2;
ac50fbac
CR
831#if defined (HAVE_IMAXDIV)
832 imaxdiv_t idiv;
833#endif
726f6388 834
cce855bc 835 val1 = exppower ();
726f6388
JA
836
837 while ((curtok == MUL) ||
28ef6c31
JA
838 (curtok == DIV) ||
839 (curtok == MOD))
726f6388
JA
840 {
841 int op = curtok;
ac50fbac 842 char *stp, *sltp;
726f6388 843
ac50fbac 844 stp = tp;
726f6388
JA
845 readtok ();
846
cce855bc 847 val2 = exppower ();
726f6388 848
ac50fbac 849 /* Handle division by 0 and twos-complement arithmetic overflow */
726f6388 850 if (((op == DIV) || (op == MOD)) && (val2 == 0))
cf391c36
CR
851 {
852 if (noeval == 0)
ac50fbac
CR
853 {
854 sltp = lasttp;
855 lasttp = stp;
856 while (lasttp && *lasttp && whitespace (*lasttp))
857 lasttp++;
858 evalerror (_("division by 0"));
859 lasttp = sltp;
860 }
cf391c36
CR
861 else
862 val2 = 1;
863 }
ac50fbac
CR
864 else if (op == MOD && val1 == INTMAX_MIN && val2 == -1)
865 {
866 val1 = 0;
867 continue;
868 }
869 else if (op == DIV && val1 == INTMAX_MIN && val2 == -1)
870 val2 = 1;
726f6388
JA
871
872 if (op == MUL)
28ef6c31 873 val1 *= val2;
ac50fbac
CR
874 else if (op == DIV || op == MOD)
875#if defined (HAVE_IMAXDIV)
876 {
877 idiv = imaxdiv (val1, val2);
878 val1 = (op == DIV) ? idiv.quot : idiv.rem;
879 }
880#else
881 val1 = (op == DIV) ? val1 / val2 : val1 % val2;
882#endif
883 lasttok = NUM;
726f6388
JA
884 }
885 return (val1);
886}
887
ac50fbac
CR
888static intmax_t
889ipow (base, exp)
890 intmax_t base, exp;
891{
892 intmax_t result;
893
894 result = 1;
895 while (exp)
896 {
897 if (exp & 1)
898 result *= base;
899 exp >>= 1;
900 base *= base;
901 }
902 return result;
903}
904
7117c2d2 905static intmax_t
cce855bc
JA
906exppower ()
907{
7117c2d2 908 register intmax_t val1, val2, c;
cce855bc
JA
909
910 val1 = exp1 ();
b80f6443 911 while (curtok == POWER)
cce855bc
JA
912 {
913 readtok ();
95732b49 914 val2 = exppower (); /* exponentiation is right-associative */
ac50fbac 915 lasttok = NUM;
cce855bc 916 if (val2 == 0)
f73dda09 917 return (1);
bb70624e 918 if (val2 < 0)
b80f6443 919 evalerror (_("exponent less than 0"));
ac50fbac 920 val1 = ipow (val1, val2);
cce855bc
JA
921 }
922 return (val1);
923}
924
7117c2d2 925static intmax_t
726f6388
JA
926exp1 ()
927{
7117c2d2 928 register intmax_t val;
726f6388
JA
929
930 if (curtok == NOT)
931 {
932 readtok ();
933 val = !exp1 ();
ac50fbac 934 lasttok = NUM;
726f6388
JA
935 }
936 else if (curtok == BNOT)
937 {
938 readtok ();
939 val = ~exp1 ();
ac50fbac 940 lasttok = NUM;
726f6388 941 }
495aee44
CR
942 else if (curtok == MINUS)
943 {
944 readtok ();
945 val = - exp1 ();
ac50fbac 946 lasttok = NUM;
495aee44
CR
947 }
948 else if (curtok == PLUS)
949 {
950 readtok ();
951 val = exp1 ();
ac50fbac 952 lasttok = NUM;
495aee44 953 }
726f6388
JA
954 else
955 val = exp0 ();
956
957 return (val);
958}
959
7117c2d2 960static intmax_t
726f6388
JA
961exp0 ()
962{
7117c2d2 963 register intmax_t val = 0, v2;
bb70624e
JA
964 char *vincdec;
965 int stok;
b80f6443 966 EXPR_CONTEXT ec;
bb70624e
JA
967
968 /* XXX - might need additional logic here to decide whether or not
969 pre-increment or pre-decrement is legal at this point. */
970 if (curtok == PREINC || curtok == PREDEC)
971 {
972 stok = lasttok = curtok;
973 readtok ();
974 if (curtok != STR)
28ef6c31 975 /* readtok() catches this */
b80f6443 976 evalerror (_("identifier expected after pre-increment or pre-decrement"));
726f6388 977
bb70624e
JA
978 v2 = tokval + ((stok == PREINC) ? 1 : -1);
979 vincdec = itos (v2);
980 if (noeval == 0)
495aee44 981 {
ac50fbac 982#if defined (ARRAY_VARS)
495aee44
CR
983 if (curlval.ind != -1)
984 expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
985 else
ac50fbac 986#endif
495aee44
CR
987 expr_bind_variable (tokstr, vincdec);
988 }
bb70624e
JA
989 free (vincdec);
990 val = v2;
991
992 curtok = NUM; /* make sure --x=7 is flagged as an error */
993 readtok ();
994 }
726f6388
JA
995 else if (curtok == LPAR)
996 {
ac50fbac 997 /* XXX - save curlval here? Or entire expression context? */
726f6388 998 readtok ();
bb70624e 999 val = EXP_HIGHEST ();
726f6388 1000
b80f6443
JA
1001 if (curtok != RPAR) /* ( */
1002 evalerror (_("missing `)'"));
726f6388
JA
1003
1004 /* Skip over closing paren. */
1005 readtok ();
1006 }
1007 else if ((curtok == NUM) || (curtok == STR))
1008 {
1009 val = tokval;
b80f6443 1010 if (curtok == STR)
bb70624e 1011 {
b80f6443
JA
1012 SAVETOK (&ec);
1013 tokstr = (char *)NULL; /* keep it from being freed */
1014 noeval = 1;
1015 readtok ();
1016 stok = curtok;
1017
bb70624e 1018 /* post-increment or post-decrement */
b80f6443
JA
1019 if (stok == POSTINC || stok == POSTDEC)
1020 {
1021 /* restore certain portions of EC */
1022 tokstr = ec.tokstr;
1023 noeval = ec.noeval;
495aee44 1024 curlval = ec.lval;
b80f6443
JA
1025 lasttok = STR; /* ec.curtok */
1026
1027 v2 = val + ((stok == POSTINC) ? 1 : -1);
1028 vincdec = itos (v2);
1029 if (noeval == 0)
495aee44 1030 {
ac50fbac 1031#if defined (ARRAY_VARS)
495aee44
CR
1032 if (curlval.ind != -1)
1033 expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
1034 else
ac50fbac 1035#endif
495aee44
CR
1036 expr_bind_variable (tokstr, vincdec);
1037 }
b80f6443
JA
1038 free (vincdec);
1039 curtok = NUM; /* make sure x++=7 is flagged as an error */
1040 }
1041 else
1042 {
ac50fbac 1043 /* XXX - watch out for pointer aliasing issues here */
b80f6443
JA
1044 if (stok == STR) /* free new tokstr before old one is restored */
1045 FREE (tokstr);
1046 RESTORETOK (&ec);
1047 }
bb70624e
JA
1048 }
1049
726f6388
JA
1050 readtok ();
1051 }
1052 else
b80f6443 1053 evalerror (_("syntax error: operand expected"));
726f6388
JA
1054
1055 return (val);
1056}
1057
495aee44
CR
1058static void
1059init_lvalue (lv)
1060 struct lvalue *lv;
1061{
1062 lv->tokstr = 0;
1063 lv->tokvar = 0;
1064 lv->tokval = lv->ind = -1;
1065}
1066
1067static struct lvalue *
1068alloc_lvalue ()
1069{
1070 struct lvalue *lv;
1071
1072 lv = xmalloc (sizeof (struct lvalue));
1073 init_lvalue (lv);
1074 return (lv);
1075}
1076
1077static void
1078free_lvalue (lv)
1079 struct lvalue *lv;
1080{
1081 free (lv); /* should be inlined */
1082}
1083
7117c2d2 1084static intmax_t
495aee44 1085expr_streval (tok, e, lvalue)
7117c2d2
JA
1086 char *tok;
1087 int e;
495aee44 1088 struct lvalue *lvalue;
7117c2d2
JA
1089{
1090 SHELL_VAR *v;
1091 char *value;
1092 intmax_t tval;
495aee44
CR
1093#if defined (ARRAY_VARS)
1094 arrayind_t ind;
1095#endif
7117c2d2 1096
11d0fdf7
CR
1097/*itrace("expr_streval: %s: noeval = %d", tok, noeval);*/
1098 /* If we are suppressing evaluation, just short-circuit here instead of
1099 going through the rest of the evaluator. */
1100 if (noeval)
1101 return (0);
1102
7117c2d2
JA
1103 /* [[[[[ */
1104#if defined (ARRAY_VARS)
1105 v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok);
1106#else
1107 v = find_variable (tok);
1108#endif
1109
1110 if ((v == 0 || invisible_p (v)) && unbound_vars_is_error)
1111 {
1112#if defined (ARRAY_VARS)
1113 value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok;
1114#else
1115 value = tok;
1116#endif
1117
0001803f 1118 last_command_exit_value = EXECUTION_FAILURE;
7117c2d2
JA
1119 err_unboundvar (value);
1120
1121#if defined (ARRAY_VARS)
1122 if (e == ']')
1123 FREE (value); /* array_variable_name returns new memory */
1124#endif
1125
1126 if (interactive_shell)
1127 {
1128 expr_unwind ();
f1be666c 1129 top_level_cleanup ();
7117c2d2
JA
1130 jump_to_top_level (DISCARD);
1131 }
1132 else
1133 jump_to_top_level (FORCE_EOF);
1134 }
1135
1136#if defined (ARRAY_VARS)
ac50fbac 1137 ind = -1;
7117c2d2
JA
1138 /* Second argument of 0 to get_array_value means that we don't allow
1139 references like array[@]. In this case, get_array_value is just
1140 like get_variable_value in that it does not return newly-allocated
1141 memory or quote the results. */
495aee44 1142 value = (e == ']') ? get_array_value (tok, 0, (int *)NULL, &ind) : get_variable_value (v);
7117c2d2
JA
1143#else
1144 value = get_variable_value (v);
1145#endif
1146
1147 tval = (value && *value) ? subexpr (value) : 0;
1148
495aee44
CR
1149 if (lvalue)
1150 {
1151 lvalue->tokstr = tok; /* XXX */
1152 lvalue->tokval = tval;
1153 lvalue->tokvar = v; /* XXX */
ac50fbac 1154#if defined (ARRAY_VARS)
495aee44 1155 lvalue->ind = ind;
ac50fbac
CR
1156#else
1157 lvalue->ind = -1;
1158#endif
495aee44
CR
1159 }
1160
7117c2d2
JA
1161 return (tval);
1162}
1163
0628567a
JA
1164static int
1165_is_multiop (c)
1166 int c;
1167{
1168 switch (c)
1169 {
1170 case EQEQ:
1171 case NEQ:
1172 case LEQ:
1173 case GEQ:
1174 case LAND:
1175 case LOR:
1176 case LSH:
1177 case RSH:
1178 case OP_ASSIGN:
1179 case COND:
1180 case POWER:
1181 case PREINC:
1182 case PREDEC:
1183 case POSTINC:
1184 case POSTDEC:
1185 return 1;
1186 default:
1187 return 0;
1188 }
1189}
1190
1191static int
1192_is_arithop (c)
1193 int c;
1194{
1195 switch (c)
1196 {
1197 case EQ:
1198 case GT:
1199 case LT:
1200 case PLUS:
1201 case MINUS:
1202 case MUL:
1203 case DIV:
1204 case MOD:
1205 case NOT:
1206 case LPAR:
1207 case RPAR:
1208 case BAND:
1209 case BOR:
1210 case BXOR:
1211 case BNOT:
1212 return 1; /* operator tokens */
1213 case QUES:
1214 case COL:
1215 case COMMA:
1216 return 1; /* questionable */
1217 default:
1218 return 0; /* anything else is invalid */
1219 }
1220}
1221
726f6388
JA
1222/* Lexical analyzer/token reader for the expression evaluator. Reads the
1223 next token and puts its value into curtok, while advancing past it.
1224 Updates value of tp. May also set tokval (for number) or tokstr (for
1225 string). */
1226static void
1227readtok ()
1228{
b80f6443 1229 register char *cp, *xp;
f73dda09
JA
1230 register unsigned char c, c1;
1231 register int e;
495aee44 1232 struct lvalue lval;
726f6388
JA
1233
1234 /* Skip leading whitespace. */
ccc6cda3
JA
1235 cp = tp;
1236 c = e = 0;
726f6388
JA
1237 while (cp && (c = *cp) && (cr_whitespace (c)))
1238 cp++;
1239
1240 if (c)
1241 cp++;
ccc6cda3 1242
726f6388
JA
1243 if (c == '\0')
1244 {
1245 lasttok = curtok;
1246 curtok = 0;
1247 tp = cp;
1248 return;
1249 }
3185942a 1250 lasttp = tp = cp - 1;
726f6388 1251
ccc6cda3 1252 if (legal_variable_starter (c))
726f6388 1253 {
bb70624e 1254 /* variable names not preceded with a dollar sign are shell variables. */
7117c2d2 1255 char *savecp;
bb70624e
JA
1256 EXPR_CONTEXT ec;
1257 int peektok;
726f6388 1258
ccc6cda3 1259 while (legal_variable_char (c))
726f6388
JA
1260 c = *cp++;
1261
1262 c = *--cp;
ccc6cda3
JA
1263
1264#if defined (ARRAY_VARS)
1265 if (c == '[')
1266 {
0001803f 1267 e = skipsubscript (cp, 0, 0);
ccc6cda3
JA
1268 if (cp[e] == ']')
1269 {
1270 cp += e + 1;
1271 c = *cp;
1272 e = ']';
1273 }
1274 else
b80f6443 1275 evalerror (bash_badsub_errmsg);
ccc6cda3
JA
1276 }
1277#endif /* ARRAY_VARS */
1278
726f6388 1279 *cp = '\0';
11d0fdf7
CR
1280 /* XXX - watch out for pointer aliasing issues here */
1281 if (curlval.tokstr && curlval.tokstr == tokstr)
1282 init_lvalue (&curlval);
1283
ccc6cda3 1284 FREE (tokstr);
726f6388 1285 tokstr = savestring (tp);
bb70624e 1286 *cp = c;
ccc6cda3 1287
495aee44 1288 /* XXX - make peektok part of saved token state? */
bb70624e
JA
1289 SAVETOK (&ec);
1290 tokstr = (char *)NULL; /* keep it from being freed */
1291 tp = savecp = cp;
1292 noeval = 1;
b80f6443 1293 curtok = STR;
bb70624e
JA
1294 readtok ();
1295 peektok = curtok;
1296 if (peektok == STR) /* free new tokstr before old one is restored */
1297 FREE (tokstr);
1298 RESTORETOK (&ec);
1299 cp = savecp;
1300
1301 /* The tests for PREINC and PREDEC aren't strictly correct, but they
1302 preserve old behavior if a construct like --x=9 is given. */
1303 if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ)
495aee44
CR
1304 {
1305 lastlval = curlval;
1306 tokval = expr_streval (tokstr, e, &curlval);
1307 }
bb70624e 1308 else
28ef6c31 1309 tokval = 0;
726f6388 1310
726f6388
JA
1311 lasttok = curtok;
1312 curtok = STR;
1313 }
f73dda09 1314 else if (DIGIT(c))
726f6388 1315 {
f73dda09 1316 while (ISALNUM (c) || c == '#' || c == '@' || c == '_')
726f6388
JA
1317 c = *cp++;
1318
1319 c = *--cp;
1320 *cp = '\0';
1321
1322 tokval = strlong (tp);
1323 *cp = c;
1324 lasttok = curtok;
1325 curtok = NUM;
1326 }
1327 else
1328 {
1329 c1 = *cp++;
ccc6cda3 1330 if ((c == EQ) && (c1 == EQ))
726f6388
JA
1331 c = EQEQ;
1332 else if ((c == NOT) && (c1 == EQ))
1333 c = NEQ;
1334 else if ((c == GT) && (c1 == EQ))
1335 c = GEQ;
1336 else if ((c == LT) && (c1 == EQ))
1337 c = LEQ;
1338 else if ((c == LT) && (c1 == LT))
1339 {
1340 if (*cp == '=') /* a <<= b */
1341 {
1342 assigntok = LSH;
1343 c = OP_ASSIGN;
1344 cp++;
1345 }
1346 else
1347 c = LSH;
1348 }
1349 else if ((c == GT) && (c1 == GT))
1350 {
1351 if (*cp == '=')
1352 {
1353 assigntok = RSH; /* a >>= b */
1354 c = OP_ASSIGN;
1355 cp++;
1356 }
1357 else
1358 c = RSH;
1359 }
1360 else if ((c == BAND) && (c1 == BAND))
1361 c = LAND;
1362 else if ((c == BOR) && (c1 == BOR))
1363 c = LOR;
cce855bc 1364 else if ((c == '*') && (c1 == '*'))
28ef6c31 1365 c = POWER;
b80f6443
JA
1366 else if ((c == '-' || c == '+') && c1 == c && curtok == STR)
1367 c = (c == '-') ? POSTDEC : POSTINC;
1368 else if ((c == '-' || c == '+') && c1 == c)
1369 {
1370 /* Quickly scan forward to see if this is followed by optional
1371 whitespace and an identifier. */
1372 xp = cp;
1373 while (xp && *xp && cr_whitespace (*xp))
1374 xp++;
1375 if (legal_variable_starter ((unsigned char)*xp))
1376 c = (c == '-') ? PREDEC : PREINC;
1377 else
1378 cp--; /* not preinc or predec, so unget the character */
1379 }
28ef6c31 1380 else if (c1 == EQ && member (c, "*/%+-&^|"))
726f6388
JA
1381 {
1382 assigntok = c; /* a OP= b */
1383 c = OP_ASSIGN;
1384 }
0628567a
JA
1385 else if (_is_arithop (c) == 0)
1386 {
1387 cp--;
1388 /* use curtok, since it hasn't been copied to lasttok yet */
1389 if (curtok == 0 || _is_arithop (curtok) || _is_multiop (curtok))
1390 evalerror (_("syntax error: operand expected"));
1391 else
1392 evalerror (_("syntax error: invalid arithmetic operator"));
1393 }
726f6388
JA
1394 else
1395 cp--; /* `unget' the character */
0628567a
JA
1396
1397 /* Should check here to make sure that the current character is one
1398 of the recognized operators and flag an error if not. Could create
1399 a character map the first time through and check it on subsequent
1400 calls. */
726f6388
JA
1401 lasttok = curtok;
1402 curtok = c;
1403 }
1404 tp = cp;
1405}
1406
1407static void
1408evalerror (msg)
3185942a 1409 const char *msg;
726f6388
JA
1410{
1411 char *name, *t;
1412
1413 name = this_command_name;
726f6388
JA
1414 for (t = expression; whitespace (*t); t++)
1415 ;
3185942a 1416 internal_error (_("%s%s%s: %s (error token is \"%s\")"),
ccc6cda3
JA
1417 name ? name : "", name ? ": " : "", t,
1418 msg, (lasttp && *lasttp) ? lasttp : "");
726f6388
JA
1419 longjmp (evalbuf, 1);
1420}
1421
7117c2d2 1422/* Convert a string to an intmax_t integer, with an arbitrary base.
726f6388 1423 0nnn -> base 8
cce855bc 1424 0[Xx]nn -> base 16
ccc6cda3
JA
1425 Anything else: [base#]number (this is implemented to match ksh93)
1426
1427 Base may be >=2 and <=64. If base is <= 36, the numbers are drawn
1428 from [0-9][a-zA-Z], and lowercase and uppercase letters may be used
1429 interchangably. If base is > 36 and <= 64, the numbers are drawn
95732b49 1430 from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 --
ccc6cda3
JA
1431 you get the picture). */
1432
7117c2d2 1433static intmax_t
726f6388
JA
1434strlong (num)
1435 char *num;
1436{
ccc6cda3 1437 register char *s;
f73dda09 1438 register unsigned char c;
ccc6cda3 1439 int base, foundbase;
7117c2d2 1440 intmax_t val;
726f6388 1441
ccc6cda3 1442 s = num;
726f6388 1443
ccc6cda3
JA
1444 base = 10;
1445 foundbase = 0;
726f6388
JA
1446 if (*s == '0')
1447 {
1448 s++;
1449
f73dda09
JA
1450 if (*s == '\0')
1451 return 0;
ccc6cda3 1452
726f6388
JA
1453 /* Base 16? */
1454 if (*s == 'x' || *s == 'X')
1455 {
1456 base = 16;
1457 s++;
1458 }
1459 else
1460 base = 8;
ccc6cda3 1461 foundbase++;
726f6388
JA
1462 }
1463
f73dda09 1464 val = 0;
726f6388
JA
1465 for (c = *s++; c; c = *s++)
1466 {
1467 if (c == '#')
1468 {
ccc6cda3 1469 if (foundbase)
b80f6443 1470 evalerror (_("invalid number"));
ccc6cda3 1471
ccc6cda3 1472 /* Illegal base specifications raise an evaluation error. */
f73dda09 1473 if (val < 2 || val > 64)
b80f6443 1474 evalerror (_("invalid arithmetic base"));
726f6388 1475
f73dda09
JA
1476 base = val;
1477 val = 0;
ccc6cda3
JA
1478 foundbase++;
1479 }
f73dda09 1480 else if (ISALNUM(c) || (c == '_') || (c == '@'))
ccc6cda3 1481 {
f73dda09
JA
1482 if (DIGIT(c))
1483 c = TODIGIT(c);
ccc6cda3
JA
1484 else if (c >= 'a' && c <= 'z')
1485 c -= 'a' - 10;
1486 else if (c >= 'A' && c <= 'Z')
1487 c -= 'A' - ((base <= 36) ? 10 : 36);
ccc6cda3 1488 else if (c == '@')
f73dda09
JA
1489 c = 62;
1490 else if (c == '_')
ccc6cda3
JA
1491 c = 63;
1492
1493 if (c >= base)
b80f6443 1494 evalerror (_("value too great for base"));
ccc6cda3
JA
1495
1496 val = (val * base) + c;
726f6388
JA
1497 }
1498 else
ccc6cda3 1499 break;
726f6388 1500 }
95732b49 1501
726f6388
JA
1502 return (val);
1503}
1504
1505#if defined (EXPR_TEST)
f73dda09 1506void *
726f6388
JA
1507xmalloc (n)
1508 int n;
1509{
1510 return (malloc (n));
1511}
1512
f73dda09 1513void *
726f6388
JA
1514xrealloc (s, n)
1515 char *s;
1516 int n;
1517{
1518 return (realloc (s, n));
1519}
1520
1521SHELL_VAR *find_variable () { return 0;}
1522SHELL_VAR *bind_variable () { return 0; }
1523
1524char *get_string_value () { return 0; }
1525
ccc6cda3 1526procenv_t top_level;
726f6388
JA
1527
1528main (argc, argv)
1529 int argc;
1530 char **argv;
1531{
1532 register int i;
7117c2d2 1533 intmax_t v;
d166f048 1534 int expok;
726f6388
JA
1535
1536 if (setjmp (top_level))
1537 exit (0);
1538
1539 for (i = 1; i < argc; i++)
1540 {
d166f048
JA
1541 v = evalexp (argv[i], &expok);
1542 if (expok == 0)
3185942a 1543 fprintf (stderr, _("%s: expression error\n"), argv[i]);
d166f048 1544 else
28ef6c31 1545 printf ("'%s' -> %ld\n", argv[i], v);
726f6388
JA
1546 }
1547 exit (0);
1548}
1549
1550int
1551builtin_error (format, arg1, arg2, arg3, arg4, arg5)
1552 char *format;
1553{
1554 fprintf (stderr, "expr: ");
1555 fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
1556 fprintf (stderr, "\n");
1557 return 0;
1558}
1559
1560char *
1561itos (n)
7117c2d2 1562 intmax_t n;
726f6388
JA
1563{
1564 return ("42");
1565}
1566
1567#endif /* EXPR_TEST */