]> git.ipfire.org Git - thirdparty/bash.git/blame - expr.c
bash-4.3-beta overlay
[thirdparty/bash.git] / expr.c
CommitLineData
726f6388
JA
1/* expr.c -- arithmetic expression evaluation. */
2
ad4aef08 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
2e4498b3
CR
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
2e4498b3
CR
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
2e4498b3
CR
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 "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="
5565fb1a 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
c84e5202 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"
5e13499c 82#include "bashintl.h"
bb70624e 83
ccc6cda3 84#include "shell.h"
c677e9e0 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
726f6388
JA
91/* Size be which the expression stack grows when neccessary. */
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
68dfe178
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
68dfe178
CR
174static struct lvalue curlval = {0, 0, 0, -1};
175static struct lvalue lastlval = {0, 0, 0, -1};
176
dc8fbaf9 177static int _is_arithop __P((int));
f73dda09 178static void readtok __P((void)); /* lexical analyzer */
7117c2d2 179
68dfe178
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 *));
d3ad40de 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));
d3a24ed2 191static void expr_bind_variable __P((char *, char *));
c31d56a7 192#if defined (ARRAY_VARS)
68dfe178 193static void expr_bind_array_element __P((char *, arrayind_t, char *));
c31d56a7 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;
0d8616ff 221extern int unbound_vars_is_error, last_command_exit_value;
726f6388 222
5e13499c 223#if defined (ARRAY_VARS)
d3ad40de 224extern const char * const bash_badsub_errmsg;
5e13499c
CR
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; \
68dfe178 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; \
68dfe178 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)
5e13499c 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)
5e13499c 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 */
53ac45a3
CR
307
308 noeval = 0; /* XXX */
7117c2d2
JA
309}
310
d3a24ed2
CR
311static void
312expr_bind_variable (lhs, rhs)
313 char *lhs, *rhs;
314{
22818c14
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 */
d3a24ed2
CR
320 stupidly_hack_special_variables (lhs);
321}
322
c31d56a7 323#if defined (ARRAY_VARS)
68dfe178
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
68dfe178 344/*itrace("expr_bind_array_element: %s=%s", lhs, rhs);*/
c84e5202 345 expr_bind_variable (lhs, rhs);
68dfe178
CR
346 free (vname);
347 free (lhs);
348}
c31d56a7 349#endif /* ARRAY_VARS */
68dfe178 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;
d3a24ed2
CR
370 int c;
371 procenv_t oevalbuf;
726f6388 372
f73dda09 373 val = 0;
53ac45a3 374 noeval = 0;
726f6388 375
d3a24ed2
CR
376 FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf));
377
36eb585c 378 c = setjmp_nosigs (evalbuf);
d3a24ed2
CR
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
d3a24ed2
CR
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
68dfe178 420 curtok = lasttok = 0;
726f6388 421 tokstr = (char *)NULL;
f73dda09 422 tokval = 0;
68dfe178
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)
5e13499c 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;
68dfe178 461 arrayind_t lind;
e3db237e
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)
5e13499c 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
c84e5202 483 /* XXX - watch out for pointer aliasing issues here */
726f6388 484 lhs = savestring (tokstr);
68dfe178
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 {
19baff85
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:
77638cbf 507 if (lvalue == INTMAX_MIN && value == -1)
ba4ab055 508 lvalue = (op == DIV) ? INTMAX_MIN : 0;
77638cbf 509 else
e3db237e 510#if HAVE_IMAXDIV
ba4ab055
CR
511 {
512 idiv = imaxdiv (lvalue, value);
513 lvalue = (op == DIV) ? idiv.quot : idiv.rem;
514 }
e3db237e 515#else
ba4ab055 516 lvalue = (op == DIV) ? lvalue / value : lvalue % value;
e3db237e 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);
5e13499c 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)
68dfe178 550 {
c31d56a7 551#if defined (ARRAY_VARS)
68dfe178
CR
552 if (lind != -1)
553 expr_bind_array_element (lhs, lind, rhs);
554 else
c31d56a7 555#endif
68dfe178
CR
556 expr_bind_variable (lhs, rhs);
557 }
ad4aef08
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 }
c84e5202 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)
5e13499c 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)
5e13499c 595 evalerror (_("`:' expected for conditional expression"));
ccc6cda3
JA
596 readtok ();
597 if (curtok == 0)
5e13499c 598 evalerror (_("expression expected"));
d166f048 599 set_noeval = 0;
ccc6cda3 600 if (cval)
d166f048
JA
601 {
602 set_noeval = 1;
603 noeval++;
604 }
adfe6c99
CR
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;
1442f67c 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;
1442f67c 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;
1442f67c 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);
1442f67c 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;
1442f67c 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;
1442f67c 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;
1442f67c 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;
e3db237e
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;
842
843 readtok ();
844
cce855bc 845 val2 = exppower ();
726f6388 846
77638cbf 847 /* Handle division by 0 and twos-complement arithmetic overflow */
726f6388 848 if (((op == DIV) || (op == MOD)) && (val2 == 0))
19baff85
CR
849 {
850 if (noeval == 0)
851 evalerror (_("division by 0"));
852 else
853 val2 = 1;
854 }
77638cbf
CR
855 else if (op == MOD && val1 == INTMAX_MIN && val2 == -1)
856 {
857 val1 = 0;
858 continue;
859 }
860 else if (op == DIV && val1 == INTMAX_MIN && val2 == -1)
861 val2 = 1;
726f6388
JA
862
863 if (op == MUL)
28ef6c31 864 val1 *= val2;
e3db237e
CR
865 else if (op == DIV || op == MOD)
866#if defined (HAVE_IMAXDIV)
ba4ab055
CR
867 {
868 idiv = imaxdiv (val1, val2);
869 val1 = (op == DIV) ? idiv.quot : idiv.rem;
870 }
e3db237e
CR
871#else
872 val1 = (op == DIV) ? val1 / val2 : val1 % val2;
873#endif
1442f67c 874 lasttok = NUM;
726f6388
JA
875 }
876 return (val1);
877}
878
b28ff8c9
CR
879static intmax_t
880ipow (base, exp)
881 intmax_t base, exp;
882{
883 intmax_t result;
884
885 result = 1;
886 while (exp)
887 {
888 if (exp & 1)
889 result *= base;
890 exp >>= 1;
891 base *= base;
892 }
893 return result;
894}
895
7117c2d2 896static intmax_t
cce855bc
JA
897exppower ()
898{
7117c2d2 899 register intmax_t val1, val2, c;
cce855bc
JA
900
901 val1 = exp1 ();
5565fb1a 902 while (curtok == POWER)
cce855bc
JA
903 {
904 readtok ();
b66cc816 905 val2 = exppower (); /* exponentiation is right-associative */
1442f67c 906 lasttok = NUM;
cce855bc 907 if (val2 == 0)
f73dda09 908 return (1);
bb70624e 909 if (val2 < 0)
5e13499c 910 evalerror (_("exponent less than 0"));
b28ff8c9 911 val1 = ipow (val1, val2);
cce855bc
JA
912 }
913 return (val1);
914}
915
7117c2d2 916static intmax_t
726f6388
JA
917exp1 ()
918{
7117c2d2 919 register intmax_t val;
726f6388
JA
920
921 if (curtok == NOT)
922 {
923 readtok ();
924 val = !exp1 ();
1442f67c 925 lasttok = NUM;
726f6388
JA
926 }
927 else if (curtok == BNOT)
928 {
929 readtok ();
930 val = ~exp1 ();
1442f67c 931 lasttok = NUM;
726f6388 932 }
e88665cc
CR
933 else if (curtok == MINUS)
934 {
935 readtok ();
936 val = - exp1 ();
1442f67c 937 lasttok = NUM;
e88665cc
CR
938 }
939 else if (curtok == PLUS)
940 {
941 readtok ();
942 val = exp1 ();
1442f67c 943 lasttok = NUM;
e88665cc 944 }
726f6388
JA
945 else
946 val = exp0 ();
947
948 return (val);
949}
950
7117c2d2 951static intmax_t
726f6388
JA
952exp0 ()
953{
7117c2d2 954 register intmax_t val = 0, v2;
bb70624e
JA
955 char *vincdec;
956 int stok;
762a763b 957 EXPR_CONTEXT ec;
bb70624e
JA
958
959 /* XXX - might need additional logic here to decide whether or not
960 pre-increment or pre-decrement is legal at this point. */
961 if (curtok == PREINC || curtok == PREDEC)
962 {
963 stok = lasttok = curtok;
964 readtok ();
965 if (curtok != STR)
28ef6c31 966 /* readtok() catches this */
5e13499c 967 evalerror (_("identifier expected after pre-increment or pre-decrement"));
726f6388 968
bb70624e
JA
969 v2 = tokval + ((stok == PREINC) ? 1 : -1);
970 vincdec = itos (v2);
971 if (noeval == 0)
68dfe178 972 {
c31d56a7 973#if defined (ARRAY_VARS)
68dfe178
CR
974 if (curlval.ind != -1)
975 expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
976 else
c31d56a7 977#endif
68dfe178
CR
978 expr_bind_variable (tokstr, vincdec);
979 }
bb70624e
JA
980 free (vincdec);
981 val = v2;
982
983 curtok = NUM; /* make sure --x=7 is flagged as an error */
984 readtok ();
985 }
726f6388
JA
986 else if (curtok == LPAR)
987 {
c84e5202 988 /* XXX - save curlval here? Or entire expression context? */
726f6388 989 readtok ();
bb70624e 990 val = EXP_HIGHEST ();
726f6388 991
5e13499c
CR
992 if (curtok != RPAR) /* ( */
993 evalerror (_("missing `)'"));
726f6388
JA
994
995 /* Skip over closing paren. */
996 readtok ();
997 }
998 else if ((curtok == NUM) || (curtok == STR))
999 {
1000 val = tokval;
762a763b 1001 if (curtok == STR)
bb70624e 1002 {
762a763b
CR
1003 SAVETOK (&ec);
1004 tokstr = (char *)NULL; /* keep it from being freed */
1005 noeval = 1;
1006 readtok ();
1007 stok = curtok;
1008
bb70624e 1009 /* post-increment or post-decrement */
762a763b
CR
1010 if (stok == POSTINC || stok == POSTDEC)
1011 {
1012 /* restore certain portions of EC */
1013 tokstr = ec.tokstr;
1014 noeval = ec.noeval;
68dfe178 1015 curlval = ec.lval;
762a763b
CR
1016 lasttok = STR; /* ec.curtok */
1017
1018 v2 = val + ((stok == POSTINC) ? 1 : -1);
1019 vincdec = itos (v2);
1020 if (noeval == 0)
68dfe178 1021 {
c31d56a7 1022#if defined (ARRAY_VARS)
68dfe178
CR
1023 if (curlval.ind != -1)
1024 expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
1025 else
c31d56a7 1026#endif
68dfe178
CR
1027 expr_bind_variable (tokstr, vincdec);
1028 }
762a763b
CR
1029 free (vincdec);
1030 curtok = NUM; /* make sure x++=7 is flagged as an error */
1031 }
1032 else
1033 {
c84e5202 1034 /* XXX - watch out for pointer aliasing issues here */
762a763b
CR
1035 if (stok == STR) /* free new tokstr before old one is restored */
1036 FREE (tokstr);
1037 RESTORETOK (&ec);
1038 }
bb70624e
JA
1039 }
1040
726f6388
JA
1041 readtok ();
1042 }
1043 else
5e13499c 1044 evalerror (_("syntax error: operand expected"));
726f6388
JA
1045
1046 return (val);
1047}
1048
68dfe178
CR
1049static void
1050init_lvalue (lv)
1051 struct lvalue *lv;
1052{
1053 lv->tokstr = 0;
1054 lv->tokvar = 0;
1055 lv->tokval = lv->ind = -1;
1056}
1057
1058static struct lvalue *
1059alloc_lvalue ()
1060{
1061 struct lvalue *lv;
1062
1063 lv = xmalloc (sizeof (struct lvalue));
1064 init_lvalue (lv);
1065 return (lv);
1066}
1067
1068static void
1069free_lvalue (lv)
1070 struct lvalue *lv;
1071{
1072 free (lv); /* should be inlined */
1073}
1074
7117c2d2 1075static intmax_t
68dfe178 1076expr_streval (tok, e, lvalue)
7117c2d2
JA
1077 char *tok;
1078 int e;
68dfe178 1079 struct lvalue *lvalue;
7117c2d2
JA
1080{
1081 SHELL_VAR *v;
1082 char *value;
1083 intmax_t tval;
68dfe178
CR
1084#if defined (ARRAY_VARS)
1085 arrayind_t ind;
1086#endif
7117c2d2 1087
c84e5202
CR
1088/*itrace("expr_streval: %s: noeval = %d", tok, noeval);*/
1089 /* If we are suppressing evaluation, just short-circuit here instead of
1090 going through the rest of the evaluator. */
1091 if (noeval)
1092 return (0);
1093
7117c2d2
JA
1094 /* [[[[[ */
1095#if defined (ARRAY_VARS)
1096 v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok);
1097#else
1098 v = find_variable (tok);
1099#endif
1100
1101 if ((v == 0 || invisible_p (v)) && unbound_vars_is_error)
1102 {
1103#if defined (ARRAY_VARS)
1104 value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok;
1105#else
1106 value = tok;
1107#endif
1108
0d8616ff 1109 last_command_exit_value = EXECUTION_FAILURE;
7117c2d2
JA
1110 err_unboundvar (value);
1111
1112#if defined (ARRAY_VARS)
1113 if (e == ']')
1114 FREE (value); /* array_variable_name returns new memory */
1115#endif
1116
1117 if (interactive_shell)
1118 {
1119 expr_unwind ();
c184f645 1120 top_level_cleanup ();
7117c2d2
JA
1121 jump_to_top_level (DISCARD);
1122 }
1123 else
1124 jump_to_top_level (FORCE_EOF);
1125 }
1126
1127#if defined (ARRAY_VARS)
c31d56a7 1128 ind = -1;
7117c2d2
JA
1129 /* Second argument of 0 to get_array_value means that we don't allow
1130 references like array[@]. In this case, get_array_value is just
1131 like get_variable_value in that it does not return newly-allocated
1132 memory or quote the results. */
68dfe178 1133 value = (e == ']') ? get_array_value (tok, 0, (int *)NULL, &ind) : get_variable_value (v);
7117c2d2
JA
1134#else
1135 value = get_variable_value (v);
1136#endif
1137
1138 tval = (value && *value) ? subexpr (value) : 0;
1139
68dfe178
CR
1140 if (lvalue)
1141 {
1142 lvalue->tokstr = tok; /* XXX */
1143 lvalue->tokval = tval;
1144 lvalue->tokvar = v; /* XXX */
c31d56a7 1145#if defined (ARRAY_VARS)
68dfe178 1146 lvalue->ind = ind;
c31d56a7
CR
1147#else
1148 lvalue->ind = -1;
1149#endif
68dfe178
CR
1150 }
1151
7117c2d2
JA
1152 return (tval);
1153}
1154
dc8fbaf9
CR
1155static int
1156_is_multiop (c)
1157 int c;
1158{
1159 switch (c)
1160 {
1161 case EQEQ:
1162 case NEQ:
1163 case LEQ:
1164 case GEQ:
1165 case LAND:
1166 case LOR:
1167 case LSH:
1168 case RSH:
1169 case OP_ASSIGN:
1170 case COND:
1171 case POWER:
1172 case PREINC:
1173 case PREDEC:
1174 case POSTINC:
1175 case POSTDEC:
1176 return 1;
1177 default:
1178 return 0;
1179 }
1180}
1181
1182static int
1183_is_arithop (c)
1184 int c;
1185{
1186 switch (c)
1187 {
1188 case EQ:
1189 case GT:
1190 case LT:
1191 case PLUS:
1192 case MINUS:
1193 case MUL:
1194 case DIV:
1195 case MOD:
1196 case NOT:
1197 case LPAR:
1198 case RPAR:
1199 case BAND:
1200 case BOR:
1201 case BXOR:
1202 case BNOT:
1203 return 1; /* operator tokens */
1204 case QUES:
1205 case COL:
1206 case COMMA:
1207 return 1; /* questionable */
1208 default:
1209 return 0; /* anything else is invalid */
1210 }
1211}
1212
726f6388
JA
1213/* Lexical analyzer/token reader for the expression evaluator. Reads the
1214 next token and puts its value into curtok, while advancing past it.
1215 Updates value of tp. May also set tokval (for number) or tokstr (for
1216 string). */
1217static void
1218readtok ()
1219{
762a763b 1220 register char *cp, *xp;
f73dda09
JA
1221 register unsigned char c, c1;
1222 register int e;
68dfe178 1223 struct lvalue lval;
726f6388
JA
1224
1225 /* Skip leading whitespace. */
ccc6cda3
JA
1226 cp = tp;
1227 c = e = 0;
726f6388
JA
1228 while (cp && (c = *cp) && (cr_whitespace (c)))
1229 cp++;
1230
1231 if (c)
1232 cp++;
ccc6cda3 1233
726f6388
JA
1234 if (c == '\0')
1235 {
1236 lasttok = curtok;
1237 curtok = 0;
1238 tp = cp;
1239 return;
1240 }
cc12da02 1241 lasttp = tp = cp - 1;
726f6388 1242
ccc6cda3 1243 if (legal_variable_starter (c))
726f6388 1244 {
bb70624e 1245 /* variable names not preceded with a dollar sign are shell variables. */
7117c2d2 1246 char *savecp;
bb70624e
JA
1247 EXPR_CONTEXT ec;
1248 int peektok;
726f6388 1249
ccc6cda3 1250 while (legal_variable_char (c))
726f6388
JA
1251 c = *cp++;
1252
1253 c = *--cp;
ccc6cda3
JA
1254
1255#if defined (ARRAY_VARS)
1256 if (c == '[')
1257 {
3eb2d94a 1258 e = skipsubscript (cp, 0, 0);
ccc6cda3
JA
1259 if (cp[e] == ']')
1260 {
1261 cp += e + 1;
1262 c = *cp;
1263 e = ']';
1264 }
1265 else
5e13499c 1266 evalerror (bash_badsub_errmsg);
ccc6cda3
JA
1267 }
1268#endif /* ARRAY_VARS */
1269
726f6388 1270 *cp = '\0';
c84e5202
CR
1271 /* XXX - watch out for pointer aliasing issues here */
1272 if (curlval.tokstr && curlval.tokstr == tokstr)
1273 init_lvalue (&curlval);
1274
ccc6cda3 1275 FREE (tokstr);
726f6388 1276 tokstr = savestring (tp);
bb70624e 1277 *cp = c;
ccc6cda3 1278
68dfe178 1279 /* XXX - make peektok part of saved token state? */
bb70624e
JA
1280 SAVETOK (&ec);
1281 tokstr = (char *)NULL; /* keep it from being freed */
1282 tp = savecp = cp;
1283 noeval = 1;
762a763b 1284 curtok = STR;
bb70624e
JA
1285 readtok ();
1286 peektok = curtok;
1287 if (peektok == STR) /* free new tokstr before old one is restored */
1288 FREE (tokstr);
1289 RESTORETOK (&ec);
1290 cp = savecp;
1291
1292 /* The tests for PREINC and PREDEC aren't strictly correct, but they
1293 preserve old behavior if a construct like --x=9 is given. */
1294 if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ)
68dfe178
CR
1295 {
1296 lastlval = curlval;
1297 tokval = expr_streval (tokstr, e, &curlval);
1298 }
bb70624e 1299 else
28ef6c31 1300 tokval = 0;
726f6388 1301
726f6388
JA
1302 lasttok = curtok;
1303 curtok = STR;
1304 }
f73dda09 1305 else if (DIGIT(c))
726f6388 1306 {
f73dda09 1307 while (ISALNUM (c) || c == '#' || c == '@' || c == '_')
726f6388
JA
1308 c = *cp++;
1309
1310 c = *--cp;
1311 *cp = '\0';
1312
1313 tokval = strlong (tp);
1314 *cp = c;
1315 lasttok = curtok;
1316 curtok = NUM;
1317 }
1318 else
1319 {
1320 c1 = *cp++;
ccc6cda3 1321 if ((c == EQ) && (c1 == EQ))
726f6388
JA
1322 c = EQEQ;
1323 else if ((c == NOT) && (c1 == EQ))
1324 c = NEQ;
1325 else if ((c == GT) && (c1 == EQ))
1326 c = GEQ;
1327 else if ((c == LT) && (c1 == EQ))
1328 c = LEQ;
1329 else if ((c == LT) && (c1 == LT))
1330 {
1331 if (*cp == '=') /* a <<= b */
1332 {
1333 assigntok = LSH;
1334 c = OP_ASSIGN;
1335 cp++;
1336 }
1337 else
1338 c = LSH;
1339 }
1340 else if ((c == GT) && (c1 == GT))
1341 {
1342 if (*cp == '=')
1343 {
1344 assigntok = RSH; /* a >>= b */
1345 c = OP_ASSIGN;
1346 cp++;
1347 }
1348 else
1349 c = RSH;
1350 }
1351 else if ((c == BAND) && (c1 == BAND))
1352 c = LAND;
1353 else if ((c == BOR) && (c1 == BOR))
1354 c = LOR;
cce855bc 1355 else if ((c == '*') && (c1 == '*'))
28ef6c31 1356 c = POWER;
762a763b
CR
1357 else if ((c == '-' || c == '+') && c1 == c && curtok == STR)
1358 c = (c == '-') ? POSTDEC : POSTINC;
1359 else if ((c == '-' || c == '+') && c1 == c)
1360 {
1361 /* Quickly scan forward to see if this is followed by optional
1362 whitespace and an identifier. */
1363 xp = cp;
1364 while (xp && *xp && cr_whitespace (*xp))
1365 xp++;
1366 if (legal_variable_starter ((unsigned char)*xp))
1367 c = (c == '-') ? PREDEC : PREINC;
1368 else
1369 cp--; /* not preinc or predec, so unget the character */
1370 }
28ef6c31 1371 else if (c1 == EQ && member (c, "*/%+-&^|"))
726f6388
JA
1372 {
1373 assigntok = c; /* a OP= b */
1374 c = OP_ASSIGN;
1375 }
dc8fbaf9
CR
1376 else if (_is_arithop (c) == 0)
1377 {
1378 cp--;
1379 /* use curtok, since it hasn't been copied to lasttok yet */
1380 if (curtok == 0 || _is_arithop (curtok) || _is_multiop (curtok))
1381 evalerror (_("syntax error: operand expected"));
1382 else
1383 evalerror (_("syntax error: invalid arithmetic operator"));
1384 }
726f6388
JA
1385 else
1386 cp--; /* `unget' the character */
dc8fbaf9
CR
1387
1388 /* Should check here to make sure that the current character is one
1389 of the recognized operators and flag an error if not. Could create
1390 a character map the first time through and check it on subsequent
1391 calls. */
726f6388
JA
1392 lasttok = curtok;
1393 curtok = c;
1394 }
1395 tp = cp;
1396}
1397
1398static void
1399evalerror (msg)
d3ad40de 1400 const char *msg;
726f6388
JA
1401{
1402 char *name, *t;
1403
1404 name = this_command_name;
726f6388
JA
1405 for (t = expression; whitespace (*t); t++)
1406 ;
d3ad40de 1407 internal_error (_("%s%s%s: %s (error token is \"%s\")"),
ccc6cda3
JA
1408 name ? name : "", name ? ": " : "", t,
1409 msg, (lasttp && *lasttp) ? lasttp : "");
726f6388
JA
1410 longjmp (evalbuf, 1);
1411}
1412
7117c2d2 1413/* Convert a string to an intmax_t integer, with an arbitrary base.
726f6388 1414 0nnn -> base 8
cce855bc 1415 0[Xx]nn -> base 16
ccc6cda3
JA
1416 Anything else: [base#]number (this is implemented to match ksh93)
1417
1418 Base may be >=2 and <=64. If base is <= 36, the numbers are drawn
1419 from [0-9][a-zA-Z], and lowercase and uppercase letters may be used
1420 interchangably. If base is > 36 and <= 64, the numbers are drawn
2206f89a 1421 from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 --
ccc6cda3
JA
1422 you get the picture). */
1423
7117c2d2 1424static intmax_t
726f6388
JA
1425strlong (num)
1426 char *num;
1427{
ccc6cda3 1428 register char *s;
f73dda09 1429 register unsigned char c;
ccc6cda3 1430 int base, foundbase;
7117c2d2 1431 intmax_t val;
726f6388 1432
ccc6cda3 1433 s = num;
726f6388 1434
ccc6cda3
JA
1435 base = 10;
1436 foundbase = 0;
726f6388
JA
1437 if (*s == '0')
1438 {
1439 s++;
1440
f73dda09
JA
1441 if (*s == '\0')
1442 return 0;
ccc6cda3 1443
726f6388
JA
1444 /* Base 16? */
1445 if (*s == 'x' || *s == 'X')
1446 {
1447 base = 16;
1448 s++;
1449 }
1450 else
1451 base = 8;
ccc6cda3 1452 foundbase++;
726f6388
JA
1453 }
1454
f73dda09 1455 val = 0;
726f6388
JA
1456 for (c = *s++; c; c = *s++)
1457 {
1458 if (c == '#')
1459 {
ccc6cda3 1460 if (foundbase)
5e13499c 1461 evalerror (_("invalid number"));
ccc6cda3 1462
ccc6cda3 1463 /* Illegal base specifications raise an evaluation error. */
f73dda09 1464 if (val < 2 || val > 64)
5e13499c 1465 evalerror (_("invalid arithmetic base"));
726f6388 1466
f73dda09
JA
1467 base = val;
1468 val = 0;
ccc6cda3
JA
1469 foundbase++;
1470 }
f73dda09 1471 else if (ISALNUM(c) || (c == '_') || (c == '@'))
ccc6cda3 1472 {
f73dda09
JA
1473 if (DIGIT(c))
1474 c = TODIGIT(c);
ccc6cda3
JA
1475 else if (c >= 'a' && c <= 'z')
1476 c -= 'a' - 10;
1477 else if (c >= 'A' && c <= 'Z')
1478 c -= 'A' - ((base <= 36) ? 10 : 36);
ccc6cda3 1479 else if (c == '@')
f73dda09
JA
1480 c = 62;
1481 else if (c == '_')
ccc6cda3
JA
1482 c = 63;
1483
1484 if (c >= base)
5e13499c 1485 evalerror (_("value too great for base"));
ccc6cda3
JA
1486
1487 val = (val * base) + c;
726f6388
JA
1488 }
1489 else
ccc6cda3 1490 break;
726f6388 1491 }
2206f89a 1492
726f6388
JA
1493 return (val);
1494}
1495
1496#if defined (EXPR_TEST)
f73dda09 1497void *
726f6388
JA
1498xmalloc (n)
1499 int n;
1500{
1501 return (malloc (n));
1502}
1503
f73dda09 1504void *
726f6388
JA
1505xrealloc (s, n)
1506 char *s;
1507 int n;
1508{
1509 return (realloc (s, n));
1510}
1511
1512SHELL_VAR *find_variable () { return 0;}
1513SHELL_VAR *bind_variable () { return 0; }
1514
1515char *get_string_value () { return 0; }
1516
ccc6cda3 1517procenv_t top_level;
726f6388
JA
1518
1519main (argc, argv)
1520 int argc;
1521 char **argv;
1522{
1523 register int i;
7117c2d2 1524 intmax_t v;
d166f048 1525 int expok;
726f6388
JA
1526
1527 if (setjmp (top_level))
1528 exit (0);
1529
1530 for (i = 1; i < argc; i++)
1531 {
d166f048
JA
1532 v = evalexp (argv[i], &expok);
1533 if (expok == 0)
d3ad40de 1534 fprintf (stderr, _("%s: expression error\n"), argv[i]);
d166f048 1535 else
28ef6c31 1536 printf ("'%s' -> %ld\n", argv[i], v);
726f6388
JA
1537 }
1538 exit (0);
1539}
1540
1541int
1542builtin_error (format, arg1, arg2, arg3, arg4, arg5)
1543 char *format;
1544{
1545 fprintf (stderr, "expr: ");
1546 fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
1547 fprintf (stderr, "\n");
1548 return 0;
1549}
1550
1551char *
1552itos (n)
7117c2d2 1553 intmax_t n;
726f6388
JA
1554{
1555 return ("42");
1556}
1557
1558#endif /* EXPR_TEST */