]> git.ipfire.org Git - thirdparty/bash.git/blob - expr.c
Imported from ../bash-2.05.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 <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 */