/* expr.c -- arithmetic expression evaluation. */
-/* Copyright (C) 1990-2002 Free Software Foundation, Inc.
+/* Copyright (C) 1990-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
"||"
"expr ? expr : expr"
"=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="
+ , [comma]
(Note that most of these operators have special meaning to bash, and an
entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure
#endif
#include "chartypes.h"
+#include "bashintl.h"
#include "shell.h"
static void pushexp __P((void));
static void popexp __P((void));
static void expr_unwind __P((void));
+static void expr_bind_variable __P((char *, char *));
static intmax_t subexpr __P((char *));
extern char *this_command_name;
extern int unbound_vars_is_error;
+#if defined (ARRAY_VARS)
+extern char *bash_badsub_errmsg;
+#endif
+
#define SAVETOK(X) \
do { \
(X)->curtok = curtok; \
EXPR_CONTEXT *context;
if (expr_depth >= MAX_EXPR_RECURSION_LEVEL)
- evalerror ("expression recursion level exceeded");
+ evalerror (_("expression recursion level exceeded"));
if (expr_depth >= expr_stack_size)
{
EXPR_CONTEXT *context;
if (expr_depth == 0)
- evalerror ("recursion stack underflow");
+ evalerror (_("recursion stack underflow"));
context = expr_stack[--expr_depth];
free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */
}
+static void
+expr_bind_variable (lhs, rhs)
+ char *lhs, *rhs;
+{
+ (void)bind_int_variable (lhs, rhs);
+ stupidly_hack_special_variables (lhs);
+}
+
/* Evaluate EXPR, and return the arithmetic result. If VALIDP is
non-null, a zero is stored into the location to which it points
if the expression is invalid, non-zero otherwise. If a non-zero
int *validp;
{
intmax_t val;
+ int c;
+ procenv_t oevalbuf;
val = 0;
- if (setjmp (evalbuf))
+ FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf));
+
+ c = setjmp (evalbuf);
+
+ if (c)
{
FREE (tokstr);
FREE (expression);
if (validp)
*validp = 1;
+ FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf));
+
return (val);
}
val = EXP_HIGHEST ();
if (curtok != 0)
- evalerror ("syntax error in expression");
+ evalerror (_("syntax error in expression"));
FREE (tokstr);
FREE (expression);
special = curtok == OP_ASSIGN;
if (lasttok != STR)
- evalerror ("attempted assignment to non-variable");
+ evalerror (_("attempted assignment to non-variable"));
if (special)
{
break;
case DIV:
if (value == 0)
- evalerror ("division by 0");
+ evalerror (_("division by 0"));
lvalue /= value;
break;
case MOD:
if (value == 0)
- evalerror ("division by 0");
+ evalerror (_("division by 0"));
lvalue %= value;
break;
case PLUS:
break;
default:
free (lhs);
- evalerror ("bug: bad expassign token");
+ evalerror (_("bug: bad expassign token"));
break;
}
value = lvalue;
rhs = itos (value);
if (noeval == 0)
- (void)bind_int_variable (lhs, rhs);
+ expr_bind_variable (lhs, rhs);
free (rhs);
free (lhs);
FREE (tokstr);
{
readtok ();
if (curtok == 0 || curtok == COL)
- evalerror ("expression expected");
+ evalerror (_("expression expected"));
if (cval == 0)
{
set_noeval = 1;
if (set_noeval)
noeval--;
if (curtok != COL)
- evalerror ("`:' expected for conditional expression");
+ evalerror (_("`:' expected for conditional expression"));
readtok ();
if (curtok == 0)
- evalerror ("expression expected");
+ evalerror (_("expression expected"));
set_noeval = 0;
if (cval)
{
val2 = exppower ();
if (((op == DIV) || (op == MOD)) && (val2 == 0))
- evalerror ("division by 0");
+ evalerror (_("division by 0"));
if (op == MUL)
val1 *= val2;
register intmax_t val1, val2, c;
val1 = exp1 ();
- if (curtok == POWER)
+ while (curtok == POWER)
{
readtok ();
- val2 = exp1 ();
+ val2 = exppower (); /* exponentiation is right-associative */
if (val2 == 0)
return (1);
if (val2 < 0)
- evalerror ("exponent less than 0");
+ evalerror (_("exponent less than 0"));
for (c = 1; val2--; c *= val1)
;
val1 = c;
register intmax_t val = 0, v2;
char *vincdec;
int stok;
+ EXPR_CONTEXT ec;
/* XXX - might need additional logic here to decide whether or not
pre-increment or pre-decrement is legal at this point. */
readtok ();
if (curtok != STR)
/* readtok() catches this */
- evalerror ("identifier expected after pre-increment or pre-decrement");
+ evalerror (_("identifier expected after pre-increment or pre-decrement"));
v2 = tokval + ((stok == PREINC) ? 1 : -1);
vincdec = itos (v2);
if (noeval == 0)
- (void)bind_int_variable (tokstr, vincdec);
+ expr_bind_variable (tokstr, vincdec);
free (vincdec);
val = v2;
readtok ();
val = EXP_HIGHEST ();
- if (curtok != RPAR)
- evalerror ("missing `)'");
+ if (curtok != RPAR) /* ( */
+ evalerror (_("missing `)'"));
/* Skip over closing paren. */
readtok ();
else if ((curtok == NUM) || (curtok == STR))
{
val = tokval;
- if (curtok == STR && (*tp == '+' || *tp == '-') && tp[1] == *tp &&
- (tp[2] == '\0' || (ISALNUM ((unsigned char)tp[2]) == 0)))
+ if (curtok == STR)
{
+ SAVETOK (&ec);
+ tokstr = (char *)NULL; /* keep it from being freed */
+ noeval = 1;
+ readtok ();
+ stok = curtok;
+
/* post-increment or post-decrement */
- v2 = val + ((*tp == '+') ? 1 : -1);
- vincdec = itos (v2);
- if (noeval == 0)
- (void)bind_int_variable (tokstr, vincdec);
- free (vincdec);
- tp += 2;
- curtok = NUM; /* make sure x++=7 is flagged as an error */
+ if (stok == POSTINC || stok == POSTDEC)
+ {
+ /* restore certain portions of EC */
+ tokstr = ec.tokstr;
+ noeval = ec.noeval;
+ lasttok = STR; /* ec.curtok */
+
+ v2 = val + ((stok == POSTINC) ? 1 : -1);
+ vincdec = itos (v2);
+ if (noeval == 0)
+ expr_bind_variable (tokstr, vincdec);
+ free (vincdec);
+ curtok = NUM; /* make sure x++=7 is flagged as an error */
+ }
+ else
+ {
+ if (stok == STR) /* free new tokstr before old one is restored */
+ FREE (tokstr);
+ RESTORETOK (&ec);
+ }
+
}
readtok ();
}
else
- evalerror ("syntax error: operand expected");
+ evalerror (_("syntax error: operand expected"));
return (val);
}
static void
readtok ()
{
- register char *cp;
+ register char *cp, *xp;
register unsigned char c, c1;
register int e;
e = ']';
}
else
- evalerror ("bad array subscript");
+ evalerror (bash_badsub_errmsg);
}
#endif /* ARRAY_VARS */
tokstr = (char *)NULL; /* keep it from being freed */
tp = savecp = cp;
noeval = 1;
+ curtok = STR;
readtok ();
peektok = curtok;
if (peektok == STR) /* free new tokstr before old one is restored */
c = LOR;
else if ((c == '*') && (c1 == '*'))
c = POWER;
- else if ((c == '-') && (c1 == '-') && legal_variable_starter ((unsigned char)*cp))
- c = PREDEC;
- else if ((c == '+') && (c1 == '+') && legal_variable_starter ((unsigned char)*cp))
- c = PREINC;
+ else if ((c == '-' || c == '+') && c1 == c && curtok == STR)
+ c = (c == '-') ? POSTDEC : POSTINC;
+ else if ((c == '-' || c == '+') && c1 == c)
+ {
+ /* Quickly scan forward to see if this is followed by optional
+ whitespace and an identifier. */
+ xp = cp;
+ while (xp && *xp && cr_whitespace (*xp))
+ xp++;
+ if (legal_variable_starter ((unsigned char)*xp))
+ c = (c == '-') ? PREDEC : PREINC;
+ else
+ cp--; /* not preinc or predec, so unget the character */
+ }
else if (c1 == EQ && member (c, "*/%+-&^|"))
{
assigntok = c; /* a OP= b */
Base may be >=2 and <=64. If base is <= 36, the numbers are drawn
from [0-9][a-zA-Z], and lowercase and uppercase letters may be used
interchangably. If base is > 36 and <= 64, the numbers are drawn
- from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, _ = 62, @ = 63 --
+ from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 --
you get the picture). */
static intmax_t
if (c == '#')
{
if (foundbase)
- evalerror ("bad number");
+ evalerror (_("invalid number"));
/* Illegal base specifications raise an evaluation error. */
if (val < 2 || val > 64)
- evalerror ("illegal arithmetic base");
+ evalerror (_("invalid arithmetic base"));
base = val;
val = 0;
c = 63;
if (c >= base)
- evalerror ("value too great for base");
+ evalerror (_("value too great for base"));
val = (val * base) + c;
}
else
break;
}
+
return (val);
}