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