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