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