1 /* expr.c -- arithmetic expression evaluation. */
3 /* Copyright (C) 1990-2020 Free Software Foundation, Inc.
5 This file is part of GNU Bush, the Bourne Again SHell.
7 Bush is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bush is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bush. If not, see <http://www.gnu.org/licenses/>.
22 All arithmetic is done as intmax_t integers with no checking for overflow
23 (though division by 0 is caught and flagged as an error).
25 The following operators are handled, grouped into a set of levels in
26 order of decreasing precedence.
28 "id++", "id--" [post-increment and post-decrement]
29 "-", "+" [(unary operators)]
30 "++id", "--id" [pre-increment and pre-decrement]
32 "**" [(exponentiation)]
44 "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="
47 (Note that most of these operators have special meaning to bush, and an
48 entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure
49 that it is passed intact to the evaluator when using `let'. When using
50 the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))'
51 is treated as if in double quotes.)
53 Sub-expressions within parentheses have a precedence level greater than
54 all of the above levels and are evaluated first. Within a single prece-
55 dence group, evaluation is left-to-right, except for the arithmetic
56 assignment operator (`='), which is evaluated right-to-left (as in C).
58 The expression evaluator returns the value of the expression (assignment
59 statements have as a value what is returned by the RHS). The `let'
60 builtin, on the other hand, returns 0 if the last expression evaluates to
61 a non-zero, and 1 otherwise.
63 Implementation is a recursive-descent parser.
74 #if defined (HAVE_UNISTD_H)
76 # include <sys/types.h>
81 #include "chartypes.h"
85 #include "var/arrayfunc.h"
86 #include "runner/execute_cmd.h"
88 #include "lxrgmr/subst.h"
89 #include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */
91 /* Because of the $((...)) construct, expressions may include newlines.
92 Here is a macro which accepts newlines, tabs and spaces as whitespace. */
93 #define cr_whitespace(c) (whitespace(c) || ((c) == '\n'))
95 /* Size be which the expression stack grows when necessary. */
96 #define EXPR_STACK_GROW_SIZE 10
98 /* Maximum amount of recursion allowed. This prevents a non-integer
99 variable such as "num=num+2" from infinitely adding to itself when
100 "let num=num+2" is given. */
101 #define MAX_EXPR_RECURSION_LEVEL 1024
103 /* The Tokens. Singing "The Lion Sleeps Tonight". */
105 #define EQEQ 1 /* "==" */
106 #define NEQ 2 /* "!=" */
107 #define LEQ 3 /* "<=" */
108 #define GEQ 4 /* ">=" */
109 #define STR 5 /* string */
110 #define NUM 6 /* number */
111 #define LAND 7 /* "&&" Logical AND */
112 #define LOR 8 /* "||" Logical OR */
113 #define LSH 9 /* "<<" Left SHift */
114 #define RSH 10 /* ">>" Right SHift */
115 #define OP_ASSIGN 11 /* op= expassign as in Posix.2 */
116 #define COND 12 /* exp1 ? exp2 : exp3 */
117 #define POWER 13 /* exp1**exp2 */
118 #define PREINC 14 /* ++var */
119 #define PREDEC 15 /* --var */
120 #define POSTINC 16 /* var++ */
121 #define POSTDEC 17 /* var-- */
133 #define BAND '&' /* Bitwise AND */
134 #define BOR '|' /* Bitwise OR. */
135 #define BXOR '^' /* Bitwise eXclusive OR. */
136 #define BNOT '~' /* Bitwise NOT; Two's complement. */
141 /* This should be the function corresponding to the operator with the
142 highest precedence. */
143 #define EXP_HIGHEST expcomma
146 # define MAX_INT_LEN 32
151 char *tokstr
; /* possibly-rewritten lvalue if not NULL */
152 intmax_t tokval
; /* expression evaluated value */
153 SHELL_VAR
*tokvar
; /* variable described by array or var reference */
154 intmax_t ind
; /* array index if not -1 */
157 /* A structure defining a single expression context. */
160 char *expression
, *tp
, *lasttp
;
167 static char *expression
; /* The current expression */
168 static char *tp
; /* token lexical position */
169 static char *lasttp
; /* pointer to last token position */
170 static int curtok
; /* the current token */
171 static int lasttok
; /* the previous token */
172 static int assigntok
; /* the OP in OP= */
173 static char *tokstr
; /* current token string */
174 static intmax_t tokval
; /* current token value */
175 static int noeval
; /* set to 1 if no assignment to be done */
176 static procenv_t evalbuf
;
178 /* set to 1 if the expression has already been run through word expansion */
179 static int already_expanded
;
181 static struct lvalue curlval
= {0, 0, 0, -1};
182 static struct lvalue lastlval
= {0, 0, 0, -1};
184 static int _is_arithop
PARAMS((int));
185 static void readtok
PARAMS((void)); /* lexical analyzer */
187 static void init_lvalue
PARAMS((struct lvalue
*));
188 static struct lvalue
*alloc_lvalue
PARAMS((void));
189 static void free_lvalue
PARAMS((struct lvalue
*));
191 static intmax_t expr_streval
PARAMS((char *, int, struct lvalue
*));
192 static intmax_t strlong
PARAMS((char *));
193 static void evalerror
PARAMS((const char *));
195 static void pushexp
PARAMS((void));
196 static void popexp
PARAMS((void));
197 static void expr_unwind
PARAMS((void));
198 static void expr_bind_variable
PARAMS((char *, char *));
199 #if defined (ARRAY_VARS)
200 static void expr_bind_array_element
PARAMS((char *, arrayind_t
, char *));
203 static intmax_t subexpr
PARAMS((char *));
205 static intmax_t expcomma
PARAMS((void));
206 static intmax_t expassign
PARAMS((void));
207 static intmax_t expcond
PARAMS((void));
208 static intmax_t explor
PARAMS((void));
209 static intmax_t expland
PARAMS((void));
210 static intmax_t expbor
PARAMS((void));
211 static intmax_t expbxor
PARAMS((void));
212 static intmax_t expband
PARAMS((void));
213 static intmax_t exp5
PARAMS((void));
214 static intmax_t exp4
PARAMS((void));
215 static intmax_t expshift
PARAMS((void));
216 static intmax_t exp3
PARAMS((void));
217 static intmax_t expmuldiv
PARAMS((void));
218 static intmax_t exppower
PARAMS((void));
219 static intmax_t exp1
PARAMS((void));
220 static intmax_t exp0
PARAMS((void));
222 /* Global var which contains the stack of expression contexts. */
223 static EXPR_CONTEXT
**expr_stack
;
224 static int expr_depth
; /* Location in the stack. */
225 static int expr_stack_size
; /* Number of slots already allocated. */
227 #if defined (ARRAY_VARS)
228 extern const char * const bush_badsub_errmsg
;
233 (X)->curtok = curtok; \
234 (X)->lasttok = lasttok; \
236 (X)->lasttp = lasttp; \
237 (X)->tokval = tokval; \
238 (X)->tokstr = tokstr; \
239 (X)->noeval = noeval; \
240 (X)->lval = curlval; \
243 #define RESTORETOK(X) \
245 curtok = (X)->curtok; \
246 lasttok = (X)->lasttok; \
248 lasttp = (X)->lasttp; \
249 tokval = (X)->tokval; \
250 tokstr = (X)->tokstr; \
251 noeval = (X)->noeval; \
252 curlval = (X)->lval; \
255 /* Push and save away the contents of the globals describing the
256 current expression context. */
260 EXPR_CONTEXT
*context
;
262 if (expr_depth
>= MAX_EXPR_RECURSION_LEVEL
)
263 evalerror (_("expression recursion level exceeded"));
265 if (expr_depth
>= expr_stack_size
)
267 expr_stack_size
+= EXPR_STACK_GROW_SIZE
;
268 expr_stack
= (EXPR_CONTEXT
**)xrealloc (expr_stack
, expr_stack_size
* sizeof (EXPR_CONTEXT
*));
271 context
= (EXPR_CONTEXT
*)xmalloc (sizeof (EXPR_CONTEXT
));
273 context
->expression
= expression
;
276 expr_stack
[expr_depth
++] = context
;
279 /* Pop the the contents of the expression context stack into the
280 globals describing the current expression context. */
284 EXPR_CONTEXT
*context
;
288 /* See the comment at the top of evalexp() for an explanation of why
290 expression
= lasttp
= 0;
291 evalerror (_("recursion stack underflow"));
294 context
= expr_stack
[--expr_depth
];
296 expression
= context
->expression
;
297 RESTORETOK (context
);
305 while (--expr_depth
> 0)
307 if (expr_stack
[expr_depth
]->tokstr
)
308 free (expr_stack
[expr_depth
]->tokstr
);
310 if (expr_stack
[expr_depth
]->expression
)
311 free (expr_stack
[expr_depth
]->expression
);
313 free (expr_stack
[expr_depth
]);
316 free (expr_stack
[expr_depth
]); /* free the allocated EXPR_CONTEXT */
318 noeval
= 0; /* XXX */
322 expr_bind_variable (lhs
, rhs
)
328 if (lhs
== 0 || *lhs
== 0)
331 #if defined (ARRAY_VARS)
332 aflags
= (assoc_expand_once
&& already_expanded
) ? ASS_NOEXPAND
: 0;
336 v
= bind_int_variable (lhs
, rhs
, aflags
);
337 if (v
&& (readonly_p (v
) || noassign_p (v
)))
338 sh_longjmp (evalbuf
, 1); /* variable assignment error */
339 stupidly_hack_special_variables (lhs
);
342 #if defined (ARRAY_VARS)
343 /* This is similar to the logic in arrayfunc.c:valid_array_subscript when
344 you pass VA_NOEXPAND. */
346 expr_skipsubscript (vp
, cp
)
354 if (assoc_expand_once
& already_expanded
)
357 isassoc
= legal_identifier (vp
) && (entry
= find_variable (vp
)) && assoc_p (entry
);
360 flags
= (isassoc
&& assoc_expand_once
&& already_expanded
) ? VA_NOEXPAND
: 0;
361 return (skipsubscript (cp
, 0, flags
));
364 /* Rewrite tok, which is of the form vname[expression], to vname[ind], where
365 IND is the already-calculated value of expression. */
367 expr_bind_array_element (tok
, ind
, rhs
)
374 char ibuf
[INT_STRLEN_BOUND (arrayind_t
) + 1], *istr
;
376 istr
= fmtumax (ind
, 10, ibuf
, sizeof (ibuf
), 0);
377 vname
= array_variable_name (tok
, 0, (char **)NULL
, (int *)NULL
);
379 llen
= strlen (vname
) + sizeof (ibuf
) + 3;
380 lhs
= xmalloc (llen
);
382 sprintf (lhs
, "%s[%s]", vname
, istr
); /* XXX */
384 /*itrace("expr_bind_array_element: %s=%s", lhs, rhs);*/
385 expr_bind_variable (lhs
, rhs
);
389 #endif /* ARRAY_VARS */
391 /* Evaluate EXPR, and return the arithmetic result. If VALIDP is
392 non-null, a zero is stored into the location to which it points
393 if the expression is invalid, non-zero otherwise. If a non-zero
394 value is returned in *VALIDP, the return value of evalexp() may
397 The `while' loop after the longjmp is caught relies on the above
398 implementation of pushexp and popexp leaving in expr_stack[0] the
399 values that the variables had when the program started. That is,
400 the first things saved are the initial values of the variables that
401 were assigned at program startup or by the compiler. Therefore, it is
402 safe to let the loop terminate when expr_depth == 0, without freeing up
403 any of the expr_depth[0] stuff. */
405 evalexp (expr
, flags
, validp
)
416 already_expanded
= (flags
&EXP_EXPANDED
);
418 FASTCOPY (evalbuf
, oevalbuf
, sizeof (evalbuf
));
420 c
= setjmp_nosigs (evalbuf
);
426 tokstr
= expression
= (char *)NULL
;
429 expr_depth
= 0; /* XXX - make sure */
431 /* We copy in case we've called evalexp recursively */
432 FASTCOPY (oevalbuf
, evalbuf
, sizeof (evalbuf
));
439 val
= subexpr (expr
);
444 FASTCOPY (oevalbuf
, evalbuf
, sizeof (evalbuf
));
456 for (p
= expr
; p
&& *p
&& cr_whitespace (*p
); p
++)
459 if (p
== NULL
|| *p
== '\0')
463 expression
= savestring (expr
);
466 curtok
= lasttok
= 0;
467 tokstr
= (char *)NULL
;
469 init_lvalue (&curlval
);
474 val
= EXP_HIGHEST ();
477 evalerror (_("syntax error in expression"));
490 register intmax_t value
;
492 value
= expassign ();
493 while (curtok
== COMMA
)
496 value
= expassign ();
505 register intmax_t value
;
508 #if defined (HAVE_IMAXDIV)
513 if (curtok
== EQ
|| curtok
== OP_ASSIGN
)
518 special
= curtok
== OP_ASSIGN
;
521 evalerror (_("attempted assignment to non-variable"));
525 op
= assigntok
; /* a OP= b */
530 evalerror (_("syntax error in variable assignment"));
532 /* XXX - watch out for pointer aliasing issues here */
533 lhs
= savestring (tokstr
);
534 /* save ind in case rhs is string var and evaluation overwrites it */
537 value
= expassign ();
541 if ((op
== DIV
|| op
== MOD
) && value
== 0)
544 evalerror (_("division by 0"));
552 /* Handle INTMAX_MIN and INTMAX_MAX * -1 specially here? */
557 if (lvalue
== INTMAX_MIN
&& value
== -1)
558 lvalue
= (op
== DIV
) ? INTMAX_MIN
: 0;
562 idiv
= imaxdiv (lvalue
, value
);
563 lvalue
= (op
== DIV
) ? idiv
.quot
: idiv
.rem
;
566 lvalue
= (op
== DIV
) ? lvalue
/ value
: lvalue
% value
;
592 evalerror (_("bug: bad expassign token"));
601 #if defined (ARRAY_VARS)
603 expr_bind_array_element (lhs
, lind
, rhs
);
606 expr_bind_variable (lhs
, rhs
);
608 if (curlval
.tokstr
&& curlval
.tokstr
== tokstr
)
609 init_lvalue (&curlval
);
614 tokstr
= (char *)NULL
; /* For freeing on errors. */
620 /* Conditional expression (expr?expr:expr) */
624 intmax_t cval
, val1
, val2
, rval
;
628 rval
= cval
= explor ();
629 if (curtok
== QUES
) /* found conditional expr */
638 if (curtok
== 0 || curtok
== COL
)
639 evalerror (_("expression expected"));
641 val1
= EXP_HIGHEST ();
646 evalerror (_("`:' expected for conditional expression"));
657 evalerror (_("expression expected"));
662 rval
= cval
? val1
: val2
;
672 register intmax_t val1
, val2
;
677 while (curtok
== LOR
)
700 register intmax_t val1
, val2
;
705 while (curtok
== LAND
)
728 register intmax_t val1
, val2
;
732 while (curtok
== BOR
)
747 register intmax_t val1
, val2
;
751 while (curtok
== BXOR
)
766 register intmax_t val1
, val2
;
770 while (curtok
== BAND
)
784 register intmax_t val1
, val2
;
788 while ((curtok
== EQEQ
) || (curtok
== NEQ
))
795 val1
= (val1
== val2
);
797 val1
= (val1
!= val2
);
806 register intmax_t val1
, val2
;
809 while ((curtok
== LEQ
) ||
825 else /* (op == GT) */
832 /* Left and right shifts. */
836 register intmax_t val1
, val2
;
840 while ((curtok
== LSH
) || (curtok
== RSH
))
860 register intmax_t val1
, val2
;
864 while ((curtok
== PLUS
) || (curtok
== MINUS
))
873 else if (op
== MINUS
)
883 register intmax_t val1
, val2
;
884 #if defined (HAVE_IMAXDIV)
890 while ((curtok
== MUL
) ||
902 /* Handle division by 0 and twos-complement arithmetic overflow */
903 if (((op
== DIV
) || (op
== MOD
)) && (val2
== 0))
909 while (lasttp
&& *lasttp
&& whitespace (*lasttp
))
911 evalerror (_("division by 0"));
917 else if (op
== MOD
&& val1
== INTMAX_MIN
&& val2
== -1)
922 else if (op
== DIV
&& val1
== INTMAX_MIN
&& val2
== -1)
927 else if (op
== DIV
|| op
== MOD
)
928 #if defined (HAVE_IMAXDIV)
930 idiv
= imaxdiv (val1
, val2
);
931 val1
= (op
== DIV
) ? idiv
.quot
: idiv
.rem
;
934 val1
= (op
== DIV
) ? val1
/ val2
: val1
% val2
;
961 register intmax_t val1
, val2
, c
;
964 while (curtok
== POWER
)
967 val2
= exppower (); /* exponentiation is right-associative */
972 evalerror (_("exponent less than 0"));
973 val1
= ipow (val1
, val2
);
981 register intmax_t val
;
989 else if (curtok
== BNOT
)
995 else if (curtok
== MINUS
)
1001 else if (curtok
== PLUS
)
1016 register intmax_t val
= 0, v2
;
1021 /* XXX - might need additional logic here to decide whether or not
1022 pre-increment or pre-decrement is legal at this point. */
1023 if (curtok
== PREINC
|| curtok
== PREDEC
)
1025 stok
= lasttok
= curtok
;
1028 /* readtok() catches this */
1029 evalerror (_("identifier expected after pre-increment or pre-decrement"));
1031 v2
= tokval
+ ((stok
== PREINC
) ? 1 : -1);
1032 vincdec
= itos (v2
);
1035 #if defined (ARRAY_VARS)
1036 if (curlval
.ind
!= -1)
1037 expr_bind_array_element (curlval
.tokstr
, curlval
.ind
, vincdec
);
1041 expr_bind_variable (tokstr
, vincdec
);
1046 curtok
= NUM
; /* make sure --x=7 is flagged as an error */
1049 else if (curtok
== LPAR
)
1051 /* XXX - save curlval here? Or entire expression context? */
1053 val
= EXP_HIGHEST ();
1055 if (curtok
!= RPAR
) /* ( */
1056 evalerror (_("missing `)'"));
1058 /* Skip over closing paren. */
1061 else if ((curtok
== NUM
) || (curtok
== STR
))
1067 tokstr
= (char *)NULL
; /* keep it from being freed */
1072 /* post-increment or post-decrement */
1073 if (stok
== POSTINC
|| stok
== POSTDEC
)
1075 /* restore certain portions of EC */
1079 lasttok
= STR
; /* ec.curtok */
1081 v2
= val
+ ((stok
== POSTINC
) ? 1 : -1);
1082 vincdec
= itos (v2
);
1085 #if defined (ARRAY_VARS)
1086 if (curlval
.ind
!= -1)
1087 expr_bind_array_element (curlval
.tokstr
, curlval
.ind
, vincdec
);
1090 expr_bind_variable (tokstr
, vincdec
);
1093 curtok
= NUM
; /* make sure x++=7 is flagged as an error */
1097 /* XXX - watch out for pointer aliasing issues here */
1098 if (stok
== STR
) /* free new tokstr before old one is restored */
1107 evalerror (_("syntax error: operand expected"));
1118 lv
->tokval
= lv
->ind
= -1;
1121 static struct lvalue
*
1126 lv
= xmalloc (sizeof (struct lvalue
));
1135 free (lv
); /* should be inlined */
1139 expr_streval (tok
, e
, lvalue
)
1142 struct lvalue
*lvalue
;
1148 #if defined (ARRAY_VARS)
1153 /*itrace("expr_streval: %s: noeval = %d expanded=%d", tok, noeval, already_expanded);*/
1154 /* If we are suppressing evaluation, just short-circuit here instead of
1155 going through the rest of the evaluator. */
1159 initial_depth
= expr_depth
;
1161 #if defined (ARRAY_VARS)
1162 tflag
= assoc_expand_once
&& already_expanded
; /* for a start */
1166 #if defined (ARRAY_VARS)
1167 aflag
= (tflag
) ? AV_NOEXPAND
: 0;
1168 v
= (e
== ']') ? array_variable_part (tok
, tflag
, (char **)0, (int *)0) : find_variable (tok
);
1170 v
= find_variable (tok
);
1172 if (v
== 0 && e
!= ']')
1173 v
= find_variable_last_nameref (tok
, 0);
1175 if ((v
== 0 || invisible_p (v
)) && unbound_vars_is_error
)
1177 #if defined (ARRAY_VARS)
1178 value
= (e
== ']') ? array_variable_name (tok
, tflag
, (char **)0, (int *)0) : tok
;
1183 set_exit_status (EXECUTION_FAILURE
);
1184 err_unboundvar (value
);
1186 #if defined (ARRAY_VARS)
1188 FREE (value
); /* array_variable_name returns new memory */
1191 if (no_longjmp_on_fatal_error
&& interactive_shell
)
1192 sh_longjmp (evalbuf
, 1);
1194 if (interactive_shell
)
1197 top_level_cleanup ();
1198 jump_to_top_level (DISCARD
);
1201 jump_to_top_level (FORCE_EOF
);
1204 #if defined (ARRAY_VARS)
1206 /* If the second argument to get_array_value doesn't include AV_ALLOWALL,
1207 we don't allow references like array[@]. In this case, get_array_value
1208 is just like get_variable_value in that it does not return newly-allocated
1209 memory or quote the results. AFLAG is set above and is either AV_NOEXPAND
1211 value
= (e
== ']') ? get_array_value (tok
, aflag
, (int *)NULL
, &ind
) : get_variable_value (v
);
1213 value
= get_variable_value (v
);
1216 if (expr_depth
< initial_depth
)
1218 if (no_longjmp_on_fatal_error
&& interactive_shell
)
1219 sh_longjmp (evalbuf
, 1);
1223 tval
= (value
&& *value
) ? subexpr (value
) : 0;
1227 lvalue
->tokstr
= tok
; /* XXX */
1228 lvalue
->tokval
= tval
;
1229 lvalue
->tokvar
= v
; /* XXX */
1230 #if defined (ARRAY_VARS)
1288 return 1; /* operator tokens */
1292 return 1; /* questionable */
1294 return 0; /* anything else is invalid */
1298 /* Lexical analyzer/token reader for the expression evaluator. Reads the
1299 next token and puts its value into curtok, while advancing past it.
1300 Updates value of tp. May also set tokval (for number) or tokstr (for
1305 register char *cp
, *xp
;
1306 register unsigned char c
, c1
;
1310 /* Skip leading whitespace. */
1313 while (cp
&& (c
= *cp
) && (cr_whitespace (c
)))
1326 lasttp
= tp
= cp
- 1;
1328 if (legal_variable_starter (c
))
1330 /* variable names not preceded with a dollar sign are shell variables. */
1337 while (legal_variable_char (c
))
1340 if (legal_variable_char2 (cp
) == 0)
1355 #if defined (ARRAY_VARS)
1358 e
= expr_skipsubscript (tp
, cp
); /* XXX - was skipsubscript */
1366 evalerror (bush_badsub_errmsg
);
1368 #endif /* ARRAY_VARS */
1371 /* XXX - watch out for pointer aliasing issues here */
1372 if (curlval
.tokstr
&& curlval
.tokstr
== tokstr
)
1373 init_lvalue (&curlval
);
1376 tokstr
= savestring (tp
);
1379 /* XXX - make peektok part of saved token state? */
1381 tokstr
= (char *)NULL
; /* keep it from being freed */
1387 if (peektok
== STR
) /* free new tokstr before old one is restored */
1392 /* The tests for PREINC and PREDEC aren't strictly correct, but they
1393 preserve old behavior if a construct like --x=9 is given. */
1394 if (lasttok
== PREINC
|| lasttok
== PREDEC
|| peektok
!= EQ
)
1397 tokval
= expr_streval (tokstr
, e
, &curlval
);
1407 while (ISALNUM (c
) || c
== '#' || c
== '@' || c
== '_')
1413 tokval
= strlong (tp
);
1421 if ((c
== EQ
) && (c1
== EQ
))
1423 else if ((c
== NOT
) && (c1
== EQ
))
1425 else if ((c
== GT
) && (c1
== EQ
))
1427 else if ((c
== LT
) && (c1
== EQ
))
1429 else if ((c
== LT
) && (c1
== LT
))
1431 if (*cp
== '=') /* a <<= b */
1440 else if ((c
== GT
) && (c1
== GT
))
1444 assigntok
= RSH
; /* a >>= b */
1451 else if ((c
== BAND
) && (c1
== BAND
))
1453 else if ((c
== BOR
) && (c1
== BOR
))
1455 else if ((c
== '*') && (c1
== '*'))
1457 else if ((c
== '-' || c
== '+') && c1
== c
&& curtok
== STR
)
1458 c
= (c
== '-') ? POSTDEC
: POSTINC
;
1459 else if ((c
== '-' || c
== '+') && c1
== c
&& curtok
== NUM
&& (lasttok
== PREINC
|| lasttok
== PREDEC
))
1461 /* This catches something like --FOO++ */
1463 evalerror ("--: assignment requires lvalue");
1465 evalerror ("++: assignment requires lvalue");
1467 else if ((c
== '-' || c
== '+') && c1
== c
)
1469 /* Quickly scan forward to see if this is followed by optional
1470 whitespace and an identifier. */
1472 while (xp
&& *xp
&& cr_whitespace (*xp
))
1474 if (legal_variable_starter ((unsigned char)*xp
))
1475 c
= (c
== '-') ? PREDEC
: PREINC
;
1477 /* Could force parsing as preinc or predec and throw an error */
1480 /* Posix says unary plus and minus have higher priority than
1481 preinc and predec. */
1482 /* This catches something like --4++ */
1484 evalerror ("--: assignment requires lvalue");
1486 evalerror ("++: assignment requires lvalue");
1489 cp
--; /* not preinc or predec, so unget the character */
1492 else if (c1
== EQ
&& member (c
, "*/%+-&^|"))
1494 assigntok
= c
; /* a OP= b */
1497 else if (_is_arithop (c
) == 0)
1500 /* use curtok, since it hasn't been copied to lasttok yet */
1501 if (curtok
== 0 || _is_arithop (curtok
) || _is_multiop (curtok
))
1502 evalerror (_("syntax error: operand expected"));
1504 evalerror (_("syntax error: invalid arithmetic operator"));
1507 cp
--; /* `unget' the character */
1509 /* Should check here to make sure that the current character is one
1510 of the recognized operators and flag an error if not. Could create
1511 a character map the first time through and check it on subsequent
1525 name
= this_command_name
;
1526 for (t
= expression
; t
&& whitespace (*t
); t
++)
1528 internal_error (_("%s%s%s: %s (error token is \"%s\")"),
1529 name
? name
: "", name
? ": " : "",
1530 t
? t
: "", msg
, (lasttp
&& *lasttp
) ? lasttp
: "");
1531 sh_longjmp (evalbuf
, 1);
1534 /* Convert a string to an intmax_t integer, with an arbitrary base.
1537 Anything else: [base#]number (this is implemented to match ksh93)
1539 Base may be >=2 and <=64. If base is <= 36, the numbers are drawn
1540 from [0-9][a-zA-Z], and lowercase and uppercase letters may be used
1541 interchangeably. If base is > 36 and <= 64, the numbers are drawn
1542 from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 --
1543 you get the picture). */
1545 #define VALID_NUMCHAR(c) (ISALNUM(c) || ((c) == '_') || ((c) == '@'))
1552 register unsigned char c
;
1553 int base
, foundbase
;
1568 if (*s
== 'x' || *s
== 'X')
1579 for (c
= *s
++; c
; c
= *s
++)
1584 evalerror (_("invalid number"));
1586 /* Illegal base specifications raise an evaluation error. */
1587 if (val
< 2 || val
> 64)
1588 evalerror (_("invalid arithmetic base"));
1594 /* Make sure a base# is followed by a character that can compose a
1595 valid integer constant. Jeremy Townshend <jeremy.townshend@gmail.com> */
1596 if (VALID_NUMCHAR (*s
) == 0)
1597 evalerror (_("invalid integer constant"));
1599 else if (VALID_NUMCHAR (c
))
1603 else if (c
>= 'a' && c
<= 'z')
1605 else if (c
>= 'A' && c
<= 'Z')
1606 c
-= 'A' - ((base
<= 36) ? 10 : 36);
1613 evalerror (_("value too great for base"));
1615 val
= (val
* base
) + c
;
1624 #if defined (EXPR_TEST)
1629 return (malloc (n
));
1637 return (realloc (s
, n
));
1640 SHELL_VAR
*find_variable () { return 0;}
1641 SHELL_VAR
*bind_variable () { return 0; }
1643 char *get_string_value () { return 0; }
1645 procenv_t top_level
;
1655 if (setjmp (top_level
))
1658 for (i
= 1; i
< argc
; i
++)
1660 v
= evalexp (argv
[i
], 0, &expok
);
1662 fprintf (stderr
, _("%s: expression error\n"), argv
[i
]);
1664 printf ("'%s' -> %ld\n", argv
[i
], v
);
1670 builtin_error (format
, arg1
, arg2
, arg3
, arg4
, arg5
)
1673 fprintf (stderr
, "expr: ");
1674 fprintf (stderr
, format
, arg1
, arg2
, arg3
, arg4
, arg5
);
1675 fprintf (stderr
, "\n");
1686 #endif /* EXPR_TEST */