0930789d6a5631c078bc58e7e1dc76ef00af56d2
[platform/upstream/bash.git] / expr.c
1 /* expr.c -- arithmetic expression evaluation. */
2
3 /* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
4
5    This file is part of GNU Bash, the Bourne Again SHell.
6
7    Bash is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 1, or (at your option)
10    any later version.
11
12    Bash is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15    License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Bash; see the file COPYING.  If not, write to the Free
19    Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 /*
22  All arithmetic is done as long integers with no checking for overflow
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
28         "-", "+"                [(unary operators)]
29         "!", "~"
30         "*", "/", "%"
31         "+", "-"
32         "<<", ">>"
33         "<=", ">=", "<", ">"
34         "==", "!="
35         "&"
36         "^"
37         "|"
38         "&&"
39         "||"
40         "expr ? expr : expr"
41         "=", "*=", "/=", "%=",
42         "+=", "-=", "<<=", ">>=",
43         "&=", "^=", "|="
44
45  (Note that most of these operators have special meaning to bash, and an
46  entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure
47  that it is passed intact to the evaluator when using `let'.  When using
48  the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))'
49  is treated as if in double quotes.)
50
51  Sub-expressions within parentheses have a precedence level greater than
52  all of the above levels and are evaluated first.  Within a single prece-
53  dence group, evaluation is left-to-right, except for the arithmetic
54  assignment operator (`='), which is evaluated right-to-left (as in C).
55
56  The expression evaluator returns the value of the expression (assignment
57  statements have as a value what is returned by the RHS).  The `let'
58  builtin, on the other hand, returns 0 if the last expression evaluates to
59  a non-zero, and 1 otherwise.
60
61  Implementation is a recursive-descent parser.
62
63  Chet Ramey
64  chet@ins.CWRU.Edu
65 */
66
67 #include "config.h"
68
69 #include <stdio.h>
70 #include "bashansi.h"
71 #if defined (HAVE_UNISTD_H)
72 #  include <unistd.h>
73 #endif
74
75 #include "shell.h"
76
77 /* Because of the $((...)) construct, expressions may include newlines.
78    Here is a macro which accepts newlines, tabs and spaces as whitespace. */
79 #define cr_whitespace(c) (whitespace(c) || ((c) == '\n'))
80
81 /* Size be which the expression stack grows when neccessary. */
82 #define EXPR_STACK_GROW_SIZE 10
83
84 /* Maximum amount of recursion allowed.  This prevents a non-integer
85    variable such as "num=num+2" from infinitely adding to itself when
86    "let num=num+2" is given. */
87 #define MAX_EXPR_RECURSION_LEVEL 1024
88
89 /* The Tokens.  Singing "The Lion Sleeps Tonight". */
90
91 #define EQEQ    1       /* "==" */
92 #define NEQ     2       /* "!=" */
93 #define LEQ     3       /* "<=" */
94 #define GEQ     4       /* ">=" */
95 #define STR     5       /* string */
96 #define NUM     6       /* number */
97 #define LAND    7       /* "&&" Logical AND */
98 #define LOR     8       /* "||" Logical OR */
99 #define LSH     9       /* "<<" Left SHift */
100 #define RSH    10       /* ">>" Right SHift */
101 #define OP_ASSIGN 11    /* op= expassign as in Posix.2 */
102 #define COND    12
103 #define EQ      '='
104 #define GT      '>'
105 #define LT      '<'
106 #define PLUS    '+'
107 #define MINUS   '-'
108 #define MUL     '*'
109 #define DIV     '/'
110 #define MOD     '%'
111 #define NOT     '!'
112 #define LPAR    '('
113 #define RPAR    ')'
114 #define BAND    '&'     /* Bitwise AND */
115 #define BOR     '|'     /* Bitwise OR. */
116 #define BXOR    '^'     /* Bitwise eXclusive OR. */
117 #define BNOT    '~'     /* Bitwise NOT; Two's complement. */
118 #define QUES    '?'
119 #define COL     ':'
120
121 static char     *expression;    /* The current expression */
122 static char     *tp;            /* token lexical position */
123 static char     *lasttp;        /* pointer to last token position */
124 static int      curtok;         /* the current token */
125 static int      lasttok;        /* the previous token */
126 static int      assigntok;      /* the OP in OP= */
127 static char     *tokstr;        /* current token string */
128 static int      tokval;         /* current token value */
129 static int      noeval;         /* set to 1 if no assignment to be done */
130 static procenv_t evalbuf;
131
132 static void     readtok ();     /* lexical analyzer */
133 static long     subexpr (), expassign (), exp0 (), exp1 (), exp2 (), exp3 (),
134                 exp4 (), exp5 (), expshift (), expland (), explor (),
135                 expband (), expbor (), expbxor (), expcond ();
136 static long     strlong ();
137 static void     evalerror ();
138
139 /* A structure defining a single expression context. */
140 typedef struct {
141   int curtok, lasttok;
142   char *expression, *tp;
143   int tokval;
144   char *tokstr;
145 } EXPR_CONTEXT;
146
147 /* Global var which contains the stack of expression contexts. */
148 static EXPR_CONTEXT **expr_stack;
149 static int expr_depth;             /* Location in the stack. */
150 static int expr_stack_size;        /* Number of slots already allocated. */
151
152 extern char *this_command_name;
153
154 /* Push and save away the contents of the globals describing the
155    current expression context. */
156 static void
157 pushexp ()
158 {
159   EXPR_CONTEXT *context;
160
161   if (expr_depth >= MAX_EXPR_RECURSION_LEVEL)
162     evalerror ("expression recursion level exceeded");
163
164   if (expr_depth >= expr_stack_size)
165     {
166       expr_stack = (EXPR_CONTEXT **)
167         xrealloc (expr_stack, (expr_stack_size += EXPR_STACK_GROW_SIZE)
168                   * sizeof (EXPR_CONTEXT *));
169     }
170
171   context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT));
172
173   context->curtok = curtok;
174   context->lasttok = lasttok;
175   context->expression = expression;
176   context->tp = tp;
177   context->tokval = tokval;
178   context->tokstr = tokstr;
179   expr_stack[expr_depth++] = context;
180 }
181
182 /* Pop the the contents of the expression context stack into the
183    globals describing the current expression context. */
184 static void
185 popexp ()
186 {
187   EXPR_CONTEXT *context;
188
189   if (expr_depth == 0)
190     evalerror ("recursion stack underflow");
191
192   context = expr_stack[--expr_depth];
193   curtok = context->curtok;
194   lasttok = context->lasttok;
195   expression = context->expression;
196   tp = context->tp;
197   tokval = context->tokval;
198   tokstr = context->tokstr;
199   free (context);
200 }
201
202 /* Evaluate EXPR, and return the arithmetic result.  If VALIDP is
203    non-null, a zero is stored into the location to which it points
204    if the expression is invalid, non-zero otherwise.  If a non-zero
205    value is returned in *VALIDP, the return value of evalexp() may
206    be used.
207
208    The `while' loop after the longjmp is caught relies on the above
209    implementation of pushexp and popexp leaving in expr_stack[0] the
210    values that the variables had when the program started.  That is,
211    the first things saved are the initial values of the variables that
212    were assigned at program startup or by the compiler.  Therefore, it is
213    safe to let the loop terminate when expr_depth == 0, without freeing up
214    any of the expr_depth[0] stuff. */
215 long
216 evalexp (expr, validp)
217      char *expr;
218      int *validp;
219 {
220   long val;
221 #if 0
222   procenv_t old_evalbuf;
223 #endif
224
225   val = 0L;
226
227 #if 0
228   /* Save the value of evalbuf to protect it around possible recursive
229      calls to evalexp (). */
230   COPY_PROCENV (evalbuf, old_evalbuf);
231 #endif
232
233   if (setjmp (evalbuf))
234     {
235       FREE (tokstr);
236       FREE (expression);
237       tokstr = expression = (char *)NULL;
238
239       while (--expr_depth > 0)
240         {
241           if (expr_stack[expr_depth]->tokstr)
242             free (expr_stack[expr_depth]->tokstr);
243
244           if (expr_stack[expr_depth]->expression)
245             free (expr_stack[expr_depth]->expression);
246
247           free (expr_stack[expr_depth]);
248         }
249       free (expr_stack[expr_depth]);    /* free the allocated EXPR_CONTEXT */
250
251       if (validp)
252         *validp = 0;
253       return (0L);
254     }
255
256   val = subexpr (expr);
257
258 #if 0
259   /* Restore the value of evalbuf so that any subsequent longjmp calls
260      will have a valid location to jump to. */
261   COPY_PROCENV (old_evalbuf, evalbuf);
262 #endif
263
264   if (validp)
265     *validp = 1;
266
267   return (val);
268 }
269
270 static long
271 subexpr (expr)
272      char *expr;
273 {
274   long val;
275   char *p;
276
277   for (p = expr; p && *p && cr_whitespace (*p); p++)
278     ;
279
280   if (p == NULL || *p == '\0')
281     return (0L);
282
283   pushexp ();
284   curtok = lasttok = 0;
285   expression = savestring (expr);
286   tp = expression;
287
288   tokstr = (char *)NULL;
289   tokval = 0L;
290
291   readtok ();
292
293   val = expassign ();
294
295   if (curtok != 0)
296     evalerror ("syntax error in expression");
297
298   FREE (tokstr);
299   FREE (expression);
300
301   popexp ();
302
303   return val;
304 }
305
306 /* Bind/create a shell variable with the name LHS to the RHS.
307    This creates or modifies a variable such that it is an integer.
308
309    This should really be in variables.c, but it is here so that all of the
310    expression evaluation stuff is localized.  Since we don't want any
311    recursive evaluation from bind_variable() (possible without this code,
312    since bind_variable() calls the evaluator for variables with the integer
313    attribute set), we temporarily turn off the integer attribute for each
314    variable we set here, then turn it back on after binding as necessary. */
315
316 void
317 bind_int_variable (lhs, rhs)
318      char *lhs, *rhs;
319 {
320   register SHELL_VAR *v;
321   int isint = 0;
322
323   v = find_variable (lhs);
324   if (v)
325     {
326       isint = integer_p (v);
327       v->attributes &= ~att_integer;
328     }
329
330   v = bind_variable (lhs, rhs);
331   if (isint)
332     v->attributes |= att_integer;
333 }
334
335 static long
336 expassign ()
337 {
338   register long value;
339   char *lhs, *rhs;
340
341   value = expcond ();
342   if (curtok == EQ || curtok == OP_ASSIGN)
343     {
344       int special, op;
345       long lvalue;
346
347       special = curtok == OP_ASSIGN;
348
349       if (lasttok != STR)
350         evalerror ("attempted assignment to non-variable");
351
352       if (special)
353         {
354           op = assigntok;               /* a OP= b */
355           lvalue = value;
356         }
357
358       lhs = savestring (tokstr);
359       readtok ();
360       value = expassign ();
361
362       if (special)
363         {
364           switch (op)
365             {
366             case MUL:
367               lvalue *= value;
368               break;
369             case DIV:
370               lvalue /= value;
371               break;
372             case MOD:
373               lvalue %= value;
374               break;
375             case PLUS:
376               lvalue += value;
377               break;
378             case MINUS:
379               lvalue -= value;
380               break;
381             case LSH:
382               lvalue <<= value;
383               break;
384             case RSH:
385               lvalue >>= value;
386               break;
387             case BAND:
388               lvalue &= value;
389               break;
390             case BOR:
391               lvalue |= value;
392               break;
393             default:
394               free (lhs);
395               evalerror ("bug: bad expassign token");
396               break;
397             }
398           value = lvalue;
399         }
400
401       rhs = itos (value);
402       if (noeval == 0)
403         bind_int_variable (lhs, rhs);
404       free (rhs);
405       free (lhs);
406       FREE (tokstr);
407       tokstr = (char *)NULL;            /* For freeing on errors. */
408     }
409   return (value);
410 }
411
412 /* Conditional expression (expr?expr:expr) */
413 static long
414 expcond ()
415 {
416   long cval, val1, val2, rval;
417   int set_noeval;
418
419   set_noeval = 0;
420   rval = cval = explor ();
421   if (curtok == QUES)           /* found conditional expr */
422     {
423       readtok ();
424       if (curtok == 0 || curtok == COL)
425         evalerror ("expression expected");
426       if (cval == 0)
427         {
428           set_noeval = 1;
429           noeval++;
430         }
431 #if 0
432       val1 = explor ();
433 #else
434       val1 = expassign ();
435 #endif
436       if (set_noeval)
437         noeval--;
438       if (curtok != COL)
439         evalerror ("`:' expected for conditional expression");
440       readtok ();
441       if (curtok == 0)
442         evalerror ("expression expected");
443       set_noeval = 0;
444       if (cval)
445         {
446           set_noeval = 1;
447           noeval++;
448         }
449       val2 = explor ();
450       if (set_noeval)
451         noeval--;
452       rval = cval ? val1 : val2;
453       lasttok = COND;
454     }
455   return rval;
456 }
457
458 /* Logical OR. */
459 static long
460 explor ()
461 {
462   register long val1, val2;
463   int set_noeval;
464
465   val1 = expland ();
466
467   while (curtok == LOR)
468     {
469       set_noeval = 0;
470       if (val1 != 0)
471         {
472           noeval++;
473           set_noeval = 1;
474         }
475       readtok ();
476       val2 = expland ();
477       if (set_noeval)
478         noeval--;
479       val1 = val1 || val2;
480       lasttok = LOR;
481     }
482
483   return (val1);
484 }
485
486 /* Logical AND. */
487 static long
488 expland ()
489 {
490   register long val1, val2;
491   int set_noeval;
492
493   val1 = expbor ();
494
495   while (curtok == LAND)
496     {
497       set_noeval = 0;
498       if (val1 == 0)
499         {
500           set_noeval = 1;
501           noeval++;
502         }
503       readtok ();
504       val2 = expbor ();
505       if (set_noeval)
506         noeval--;
507       val1 = val1 && val2;
508       lasttok = LAND;
509     }
510
511   return (val1);
512 }
513
514 /* Bitwise OR. */
515 static long
516 expbor ()
517 {
518   register long val1, val2;
519
520   val1 = expbxor ();
521
522   while (curtok == BOR)
523     {
524       readtok ();
525       val2 = expbxor ();
526       val1 = val1 | val2;
527     }
528
529   return (val1);
530 }
531
532 /* Bitwise XOR. */
533 static long
534 expbxor ()
535 {
536   register long val1, val2;
537
538   val1 = expband ();
539
540   while (curtok == BXOR)
541     {
542       readtok ();
543       val2 = expband ();
544       val1 = val1 ^ val2;
545     }
546
547   return (val1);
548 }
549
550 /* Bitwise AND. */
551 static long
552 expband ()
553 {
554   register long val1, val2;
555
556   val1 = exp5 ();
557
558   while (curtok == BAND)
559     {
560       readtok ();
561       val2 = exp5 ();
562       val1 = val1 & val2;
563     }
564
565   return (val1);
566 }
567
568 static long
569 exp5 ()
570 {
571   register long val1, val2;
572
573   val1 = exp4 ();
574
575   while ((curtok == EQEQ) || (curtok == NEQ))
576     {
577       int op = curtok;
578
579       readtok ();
580       val2 = exp4 ();
581       if (op == EQEQ)
582         val1 = (val1 == val2);
583       else if (op == NEQ)
584         val1 = (val1 != val2);
585     }
586   return (val1);
587 }
588
589 static long
590 exp4 ()
591 {
592   register long val1, val2;
593
594   val1 = expshift ();
595   while ((curtok == LEQ) ||
596          (curtok == GEQ) ||
597          (curtok == LT) ||
598          (curtok == GT))
599     {
600       int op = curtok;
601
602       readtok ();
603       val2 = expshift ();
604
605       if (op == LEQ)
606         val1 = val1 <= val2;
607       else if (op == GEQ)
608         val1 = val1 >= val2;
609       else if (op == LT)
610         val1 = val1 < val2;
611       else                      /* (op == GT) */
612         val1 = val1 > val2;
613     }
614   return (val1);
615 }
616
617 /* Left and right shifts. */
618 static long
619 expshift ()
620 {
621   register long val1, val2;
622
623   val1 = exp3 ();
624
625   while ((curtok == LSH) || (curtok == RSH))
626     {
627       int op = curtok;
628
629       readtok ();
630       val2 = exp3 ();
631
632       if (op == LSH)
633         val1 = val1 << val2;
634       else
635         val1 = val1 >> val2;
636     }
637
638   return (val1);
639 }
640
641 static long
642 exp3 ()
643 {
644   register long val1, val2;
645
646   val1 = exp2 ();
647
648   while ((curtok == PLUS) || (curtok == MINUS))
649     {
650       int op = curtok;
651
652       readtok ();
653       val2 = exp2 ();
654
655       if (op == PLUS)
656         val1 += val2;
657       else if (op == MINUS)
658         val1 -= val2;
659     }
660   return (val1);
661 }
662
663 static long
664 exp2 ()
665 {
666   register long val1, val2;
667
668   val1 = exp1 ();
669
670   while ((curtok == MUL) ||
671          (curtok == DIV) ||
672          (curtok == MOD))
673     {
674       int op = curtok;
675
676       readtok ();
677
678       val2 = exp1 ();
679
680       if (((op == DIV) || (op == MOD)) && (val2 == 0))
681         evalerror ("division by 0");
682
683       if (op == MUL)
684         val1 *= val2;
685       else if (op == DIV)
686         val1 /= val2;
687       else if (op == MOD)
688         val1 %= val2;
689     }
690   return (val1);
691 }
692
693 static long
694 exp1 ()
695 {
696   register long val;
697
698   if (curtok == NOT)
699     {
700       readtok ();
701       val = !exp1 ();
702     }
703   else if (curtok == BNOT)
704     {
705       readtok ();
706       val = ~exp1 ();
707     }
708   else
709     val = exp0 ();
710
711   return (val);
712 }
713
714 static long
715 exp0 ()
716 {
717   register long val = 0L;
718
719   if (curtok == MINUS)
720     {
721       readtok ();
722       val = - exp0 ();
723     }
724   else if (curtok == PLUS)
725     {
726       readtok ();
727       val = exp0 ();
728     }
729   else if (curtok == LPAR)
730     {
731       readtok ();
732       val = expassign ();
733
734       if (curtok != RPAR)
735         evalerror ("missing `)'");
736
737       /* Skip over closing paren. */
738       readtok ();
739     }
740   else if ((curtok == NUM) || (curtok == STR))
741     {
742       val = tokval;
743       readtok ();
744     }
745   else
746     evalerror ("syntax error: operand expected");
747
748   return (val);
749 }
750
751 /* Lexical analyzer/token reader for the expression evaluator.  Reads the
752    next token and puts its value into curtok, while advancing past it.
753    Updates value of tp.  May also set tokval (for number) or tokstr (for
754    string). */
755 static void
756 readtok ()
757 {
758   register char *cp;
759   register int c, c1, e;
760
761   /* Skip leading whitespace. */
762   cp = tp;
763   c = e = 0;
764   while (cp && (c = *cp) && (cr_whitespace (c)))
765     cp++;
766
767   if (c)
768     cp++;
769
770   lasttp = tp = cp - 1;
771
772   if (c == '\0')
773     {
774       lasttok = curtok;
775       curtok = 0;
776       tp = cp;
777       return;
778     }
779
780   if (legal_variable_starter (c))
781     {
782       /* Semi-bogus ksh compatibility feature -- variable names
783          not preceded with a dollar sign are shell variables. */
784       char *value;
785
786       while (legal_variable_char (c))
787         c = *cp++;
788
789       c = *--cp;
790
791 #if defined (ARRAY_VARS)
792       if (c == '[')
793         {
794           e = skipsubscript (cp, 0);
795           if (cp[e] == ']')
796             {
797               cp += e + 1;
798               c = *cp;
799               e = ']';
800             }
801           else
802             evalerror ("bad array subscript");
803         }
804 #endif /* ARRAY_VARS */
805
806       *cp = '\0';
807
808       FREE (tokstr);
809       tokstr = savestring (tp);
810
811 #if defined (ARRAY_VARS)
812       value = (e == ']') ? get_array_value (tokstr, 0) : get_string_value (tokstr);
813 #else
814       value = get_string_value (tokstr);
815 #endif
816
817       tokval = (value && *value) ? subexpr (value) : 0;
818
819 #if defined (ARRAY_VARS)
820       if (e == ']')
821         FREE (value);   /* get_array_value returns newly-allocated memory */
822 #endif
823
824       *cp = c;
825       lasttok = curtok;
826       curtok = STR;
827     }
828   else if (digit(c))
829     {
830       while (digit (c) || isletter (c) || c == '#' || c == '@' || c == '_')
831         c = *cp++;
832
833       c = *--cp;
834       *cp = '\0';
835
836       tokval = strlong (tp);
837       *cp = c;
838       lasttok = curtok;
839       curtok = NUM;
840     }
841   else
842     {
843       c1 = *cp++;
844       if ((c == EQ) && (c1 == EQ))
845         c = EQEQ;
846       else if ((c == NOT) && (c1 == EQ))
847         c = NEQ;
848       else if ((c == GT) && (c1 == EQ))
849         c = GEQ;
850       else if ((c == LT) && (c1 == EQ))
851         c = LEQ;
852       else if ((c == LT) && (c1 == LT))
853         {
854           if (*cp == '=')       /* a <<= b */
855             {
856               assigntok = LSH;
857               c = OP_ASSIGN;
858               cp++;
859             }
860           else
861             c = LSH;
862         }
863       else if ((c == GT) && (c1 == GT))
864         {
865           if (*cp == '=')
866             {
867               assigntok = RSH;  /* a >>= b */
868               c = OP_ASSIGN;
869               cp++;
870             }
871           else
872             c = RSH;
873         }
874       else if ((c == BAND) && (c1 == BAND))
875         c = LAND;
876       else if ((c == BOR) && (c1 == BOR))
877         c = LOR;
878       else if (c1 == EQ && member(c, "*/%+-&^|"))
879         {
880           assigntok = c;        /* a OP= b */
881           c = OP_ASSIGN;
882         }
883       else
884         cp--;                   /* `unget' the character */
885       lasttok = curtok;
886       curtok = c;
887     }
888   tp = cp;
889 }
890
891 static void
892 evalerror (msg)
893      char *msg;
894 {
895   char *name, *t;
896
897   name = this_command_name;
898   for (t = expression; whitespace (*t); t++)
899     ;
900   internal_error ("%s%s%s: %s (error token is \"%s\")",
901                    name ? name : "", name ? ": " : "", t,
902                    msg, (lasttp && *lasttp) ? lasttp : "");
903   longjmp (evalbuf, 1);
904 }
905
906 /* Convert a string to a long integer, with an arbitrary base.
907    0nnn -> base 8
908    0xnn -> base 16
909    Anything else: [base#]number (this is implemented to match ksh93)
910
911    Base may be >=2 and <=64.  If base is <= 36, the numbers are drawn
912    from [0-9][a-zA-Z], and lowercase and uppercase letters may be used
913    interchangably.  If base is > 36 and <= 64, the numbers are drawn
914    from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, _ = 62, @ = 63 --
915    you get the picture). */
916
917 static long
918 strlong (num)
919      char *num;
920 {
921   register char *s;
922   register int c;
923   int base, foundbase;
924   long val = 0L;
925
926   s = num;
927   if (s == NULL || *s == '\0')
928     return 0L;
929
930   base = 10;
931   foundbase = 0;
932   if (*s == '0')
933     {
934       s++;
935
936       if (s == NULL || *s == '\0')
937         return 0L;
938
939        /* Base 16? */
940       if (*s == 'x' || *s == 'X')
941         {
942           base = 16;
943           s++;
944         }
945       else
946         base = 8;
947       foundbase++;
948     }
949
950   val = 0L;
951   for (c = *s++; c; c = *s++)
952     {
953       if (c == '#')
954         {
955           if (foundbase)
956             evalerror ("bad number");
957
958           base = (int)val;
959
960           /* Illegal base specifications raise an evaluation error. */
961           if (base < 2 || base > 64)
962             evalerror ("illegal arithmetic base");
963
964           val = 0L;
965           foundbase++;
966         }
967       else if (isletter(c) || digit(c) || (c == '_') || (c == '@'))
968         {
969           if (digit(c))
970             c = digit_value(c);
971           else if (c >= 'a' && c <= 'z')
972             c -= 'a' - 10;
973           else if (c >= 'A' && c <= 'Z')
974             c -= 'A' - ((base <= 36) ? 10 : 36);
975           else if (c == '_')
976             c = 62;
977           else if (c == '@')
978             c = 63;
979
980           if (c >= base)
981             evalerror ("value too great for base");
982
983           val = (val * base) + c;
984         }
985       else
986         break;
987     }
988   return (val);
989 }
990
991 #if defined (EXPR_TEST)
992 char *
993 xmalloc (n)
994      int n;
995 {
996   return (malloc (n));
997 }
998
999 char *
1000 xrealloc (s, n)
1001      char *s;
1002      int n;
1003 {
1004   return (realloc (s, n));
1005 }
1006
1007 SHELL_VAR *find_variable () { return 0;}
1008 SHELL_VAR *bind_variable () { return 0; }
1009
1010 char *get_string_value () { return 0; }
1011
1012 procenv_t top_level;
1013
1014 main (argc, argv)
1015      int argc;
1016      char **argv;
1017 {
1018   register int i;
1019   long v;
1020   int expok;
1021
1022   if (setjmp (top_level))
1023     exit (0);
1024
1025   for (i = 1; i < argc; i++)
1026     {
1027       v = evalexp (argv[i], &expok);
1028       if (expok == 0)
1029         fprintf (stderr, "%s: expression error\n", argv[i]);
1030       else
1031         printf ("'%s' -> %ld\n", argv[i], v);
1032     }
1033   exit (0);
1034 }
1035
1036 int
1037 builtin_error (format, arg1, arg2, arg3, arg4, arg5)
1038      char *format;
1039 {
1040   fprintf (stderr, "expr: ");
1041   fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
1042   fprintf (stderr, "\n");
1043   return 0;
1044 }
1045
1046 char *
1047 itos (n)
1048      int n;
1049 {
1050   return ("42");
1051 }
1052
1053 #endif /* EXPR_TEST */