Imported from ../bash-2.05b.tar.gz.
This commit is contained in:
parent
f73dda092b
commit
7117c2d221
362 changed files with 34387 additions and 15063 deletions
253
expr.c
253
expr.c
|
@ -1,6 +1,6 @@
|
|||
/* expr.c -- arithmetic expression evaluation. */
|
||||
|
||||
/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1990-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
/*
|
||||
All arithmetic is done as long integers with no checking for overflow
|
||||
All arithmetic is done as intmax_t integers with no checking for overflow
|
||||
(though division by 0 is caught and flagged as an error).
|
||||
|
||||
The following operators are handled, grouped into a set of levels in
|
||||
|
@ -142,41 +142,44 @@ static int curtok; /* the current token */
|
|||
static int lasttok; /* the previous token */
|
||||
static int assigntok; /* the OP in OP= */
|
||||
static char *tokstr; /* current token string */
|
||||
static long tokval; /* current token value */
|
||||
static intmax_t tokval; /* current token value */
|
||||
static int noeval; /* set to 1 if no assignment to be done */
|
||||
static procenv_t evalbuf;
|
||||
|
||||
static void readtok __P((void)); /* lexical analyzer */
|
||||
static long strlong __P((char *));
|
||||
|
||||
static intmax_t expr_streval __P((char *, int));
|
||||
static intmax_t strlong __P((char *));
|
||||
static void evalerror __P((char *));
|
||||
|
||||
static void pushexp __P((void));
|
||||
static void popexp __P((void));
|
||||
static void expr_unwind __P((void));
|
||||
|
||||
static long subexpr __P((char *));
|
||||
static intmax_t subexpr __P((char *));
|
||||
|
||||
static long expcomma __P((void));
|
||||
static long expassign __P((void));
|
||||
static long expcond __P((void));
|
||||
static long explor __P((void));
|
||||
static long expland __P((void));
|
||||
static long expbor __P((void));
|
||||
static long expbxor __P((void));
|
||||
static long expband __P((void));
|
||||
static long exp5 __P((void));
|
||||
static long exp4 __P((void));
|
||||
static long expshift __P((void));
|
||||
static long exp3 __P((void));
|
||||
static long exp2 __P((void));
|
||||
static long exppower __P((void));
|
||||
static long exp1 __P((void));
|
||||
static long exp0 __P((void));
|
||||
static intmax_t expcomma __P((void));
|
||||
static intmax_t expassign __P((void));
|
||||
static intmax_t expcond __P((void));
|
||||
static intmax_t explor __P((void));
|
||||
static intmax_t expland __P((void));
|
||||
static intmax_t expbor __P((void));
|
||||
static intmax_t expbxor __P((void));
|
||||
static intmax_t expband __P((void));
|
||||
static intmax_t exp5 __P((void));
|
||||
static intmax_t exp4 __P((void));
|
||||
static intmax_t expshift __P((void));
|
||||
static intmax_t exp3 __P((void));
|
||||
static intmax_t exp2 __P((void));
|
||||
static intmax_t exppower __P((void));
|
||||
static intmax_t exp1 __P((void));
|
||||
static intmax_t exp0 __P((void));
|
||||
|
||||
/* A structure defining a single expression context. */
|
||||
typedef struct {
|
||||
int curtok, lasttok;
|
||||
char *expression, *tp, *lasttp;
|
||||
long tokval;
|
||||
intmax_t tokval;
|
||||
char *tokstr;
|
||||
int noeval;
|
||||
} EXPR_CONTEXT;
|
||||
|
@ -185,7 +188,7 @@ typedef struct {
|
|||
/* Not used yet. */
|
||||
typedef struct {
|
||||
char *tokstr;
|
||||
long tokval;
|
||||
intmax_t tokval;
|
||||
} LVALUE;
|
||||
#endif
|
||||
|
||||
|
@ -195,6 +198,7 @@ static int expr_depth; /* Location in the stack. */
|
|||
static int expr_stack_size; /* Number of slots already allocated. */
|
||||
|
||||
extern char *this_command_name;
|
||||
extern int unbound_vars_is_error;
|
||||
|
||||
#define SAVETOK(X) \
|
||||
do { \
|
||||
|
@ -260,6 +264,22 @@ popexp ()
|
|||
free (context);
|
||||
}
|
||||
|
||||
static void
|
||||
expr_unwind ()
|
||||
{
|
||||
while (--expr_depth > 0)
|
||||
{
|
||||
if (expr_stack[expr_depth]->tokstr)
|
||||
free (expr_stack[expr_depth]->tokstr);
|
||||
|
||||
if (expr_stack[expr_depth]->expression)
|
||||
free (expr_stack[expr_depth]->expression);
|
||||
|
||||
free (expr_stack[expr_depth]);
|
||||
}
|
||||
free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -273,41 +293,22 @@ popexp ()
|
|||
were assigned at program startup or by the compiler. Therefore, it is
|
||||
safe to let the loop terminate when expr_depth == 0, without freeing up
|
||||
any of the expr_depth[0] stuff. */
|
||||
long
|
||||
intmax_t
|
||||
evalexp (expr, validp)
|
||||
char *expr;
|
||||
int *validp;
|
||||
{
|
||||
long val;
|
||||
#if 0
|
||||
procenv_t old_evalbuf;
|
||||
#endif
|
||||
intmax_t val;
|
||||
|
||||
val = 0;
|
||||
|
||||
#if 0
|
||||
/* Save the value of evalbuf to protect it around possible recursive
|
||||
calls to evalexp (). */
|
||||
COPY_PROCENV (evalbuf, old_evalbuf);
|
||||
#endif
|
||||
|
||||
if (setjmp (evalbuf))
|
||||
{
|
||||
FREE (tokstr);
|
||||
FREE (expression);
|
||||
tokstr = expression = (char *)NULL;
|
||||
|
||||
while (--expr_depth > 0)
|
||||
{
|
||||
if (expr_stack[expr_depth]->tokstr)
|
||||
free (expr_stack[expr_depth]->tokstr);
|
||||
|
||||
if (expr_stack[expr_depth]->expression)
|
||||
free (expr_stack[expr_depth]->expression);
|
||||
|
||||
free (expr_stack[expr_depth]);
|
||||
}
|
||||
free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */
|
||||
expr_unwind ();
|
||||
|
||||
if (validp)
|
||||
*validp = 0;
|
||||
|
@ -316,23 +317,17 @@ evalexp (expr, validp)
|
|||
|
||||
val = subexpr (expr);
|
||||
|
||||
#if 0
|
||||
/* Restore the value of evalbuf so that any subsequent longjmp calls
|
||||
will have a valid location to jump to. */
|
||||
COPY_PROCENV (old_evalbuf, evalbuf);
|
||||
#endif
|
||||
|
||||
if (validp)
|
||||
*validp = 1;
|
||||
|
||||
return (val);
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
subexpr (expr)
|
||||
char *expr;
|
||||
{
|
||||
long val;
|
||||
intmax_t val;
|
||||
char *p;
|
||||
|
||||
for (p = expr; p && *p && cr_whitespace (*p); p++)
|
||||
|
@ -364,10 +359,10 @@ subexpr (expr)
|
|||
return val;
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
expcomma ()
|
||||
{
|
||||
register long value;
|
||||
register intmax_t value;
|
||||
|
||||
value = expassign ();
|
||||
while (curtok == COMMA)
|
||||
|
@ -379,17 +374,17 @@ expcomma ()
|
|||
return value;
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
expassign ()
|
||||
{
|
||||
register long value;
|
||||
register intmax_t value;
|
||||
char *lhs, *rhs;
|
||||
|
||||
value = expcond ();
|
||||
if (curtok == EQ || curtok == OP_ASSIGN)
|
||||
{
|
||||
int special, op;
|
||||
long lvalue;
|
||||
intmax_t lvalue;
|
||||
|
||||
special = curtok == OP_ASSIGN;
|
||||
|
||||
|
@ -414,9 +409,13 @@ expassign ()
|
|||
lvalue *= value;
|
||||
break;
|
||||
case DIV:
|
||||
if (value == 0)
|
||||
evalerror ("division by 0");
|
||||
lvalue /= value;
|
||||
break;
|
||||
case MOD:
|
||||
if (value == 0)
|
||||
evalerror ("division by 0");
|
||||
lvalue %= value;
|
||||
break;
|
||||
case PLUS:
|
||||
|
@ -460,10 +459,10 @@ expassign ()
|
|||
}
|
||||
|
||||
/* Conditional expression (expr?expr:expr) */
|
||||
static long
|
||||
static intmax_t
|
||||
expcond ()
|
||||
{
|
||||
long cval, val1, val2, rval;
|
||||
intmax_t cval, val1, val2, rval;
|
||||
int set_noeval;
|
||||
|
||||
set_noeval = 0;
|
||||
|
@ -504,10 +503,10 @@ expcond ()
|
|||
}
|
||||
|
||||
/* Logical OR. */
|
||||
static long
|
||||
static intmax_t
|
||||
explor ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
int set_noeval;
|
||||
|
||||
val1 = expland ();
|
||||
|
@ -532,10 +531,10 @@ explor ()
|
|||
}
|
||||
|
||||
/* Logical AND. */
|
||||
static long
|
||||
static intmax_t
|
||||
expland ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
int set_noeval;
|
||||
|
||||
val1 = expbor ();
|
||||
|
@ -560,10 +559,10 @@ expland ()
|
|||
}
|
||||
|
||||
/* Bitwise OR. */
|
||||
static long
|
||||
static intmax_t
|
||||
expbor ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
|
||||
val1 = expbxor ();
|
||||
|
||||
|
@ -578,10 +577,10 @@ expbor ()
|
|||
}
|
||||
|
||||
/* Bitwise XOR. */
|
||||
static long
|
||||
static intmax_t
|
||||
expbxor ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
|
||||
val1 = expband ();
|
||||
|
||||
|
@ -596,10 +595,10 @@ expbxor ()
|
|||
}
|
||||
|
||||
/* Bitwise AND. */
|
||||
static long
|
||||
static intmax_t
|
||||
expband ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
|
||||
val1 = exp5 ();
|
||||
|
||||
|
@ -613,10 +612,10 @@ expband ()
|
|||
return (val1);
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
exp5 ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
|
||||
val1 = exp4 ();
|
||||
|
||||
|
@ -634,10 +633,10 @@ exp5 ()
|
|||
return (val1);
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
exp4 ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
|
||||
val1 = expshift ();
|
||||
while ((curtok == LEQ) ||
|
||||
|
@ -663,10 +662,10 @@ exp4 ()
|
|||
}
|
||||
|
||||
/* Left and right shifts. */
|
||||
static long
|
||||
static intmax_t
|
||||
expshift ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
|
||||
val1 = exp3 ();
|
||||
|
||||
|
@ -686,10 +685,10 @@ expshift ()
|
|||
return (val1);
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
exp3 ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
|
||||
val1 = exp2 ();
|
||||
|
||||
|
@ -708,10 +707,10 @@ exp3 ()
|
|||
return (val1);
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
exp2 ()
|
||||
{
|
||||
register long val1, val2;
|
||||
register intmax_t val1, val2;
|
||||
|
||||
val1 = exppower ();
|
||||
|
||||
|
@ -738,10 +737,10 @@ exp2 ()
|
|||
return (val1);
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
exppower ()
|
||||
{
|
||||
register long val1, val2, c;
|
||||
register intmax_t val1, val2, c;
|
||||
|
||||
val1 = exp1 ();
|
||||
if (curtok == POWER)
|
||||
|
@ -759,10 +758,10 @@ exppower ()
|
|||
return (val1);
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
exp1 ()
|
||||
{
|
||||
register long val;
|
||||
register intmax_t val;
|
||||
|
||||
if (curtok == NOT)
|
||||
{
|
||||
|
@ -780,10 +779,10 @@ exp1 ()
|
|||
return (val);
|
||||
}
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
exp0 ()
|
||||
{
|
||||
register long val = 0, v2;
|
||||
register intmax_t val = 0, v2;
|
||||
char *vincdec;
|
||||
int stok;
|
||||
|
||||
|
@ -852,6 +851,61 @@ exp0 ()
|
|||
return (val);
|
||||
}
|
||||
|
||||
static intmax_t
|
||||
expr_streval (tok, e)
|
||||
char *tok;
|
||||
int e;
|
||||
{
|
||||
SHELL_VAR *v;
|
||||
char *value;
|
||||
intmax_t tval;
|
||||
|
||||
/* [[[[[ */
|
||||
#if defined (ARRAY_VARS)
|
||||
v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok);
|
||||
#else
|
||||
v = find_variable (tok);
|
||||
#endif
|
||||
|
||||
if ((v == 0 || invisible_p (v)) && unbound_vars_is_error)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok;
|
||||
#else
|
||||
value = tok;
|
||||
#endif
|
||||
|
||||
err_unboundvar (value);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (e == ']')
|
||||
FREE (value); /* array_variable_name returns new memory */
|
||||
#endif
|
||||
|
||||
if (interactive_shell)
|
||||
{
|
||||
expr_unwind ();
|
||||
jump_to_top_level (DISCARD);
|
||||
}
|
||||
else
|
||||
jump_to_top_level (FORCE_EOF);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Second argument of 0 to get_array_value means that we don't allow
|
||||
references like array[@]. In this case, get_array_value is just
|
||||
like get_variable_value in that it does not return newly-allocated
|
||||
memory or quote the results. */
|
||||
value = (e == ']') ? get_array_value (tok, 0, (int *)NULL) : get_variable_value (v);
|
||||
#else
|
||||
value = get_variable_value (v);
|
||||
#endif
|
||||
|
||||
tval = (value && *value) ? subexpr (value) : 0;
|
||||
|
||||
return (tval);
|
||||
}
|
||||
|
||||
/* Lexical analyzer/token reader for the expression evaluator. Reads the
|
||||
next token and puts its value into curtok, while advancing past it.
|
||||
Updates value of tp. May also set tokval (for number) or tokstr (for
|
||||
|
@ -885,7 +939,7 @@ readtok ()
|
|||
if (legal_variable_starter (c))
|
||||
{
|
||||
/* variable names not preceded with a dollar sign are shell variables. */
|
||||
char *value, *savecp;
|
||||
char *savecp;
|
||||
EXPR_CONTEXT ec;
|
||||
int peektok;
|
||||
|
||||
|
@ -928,20 +982,7 @@ readtok ()
|
|||
/* The tests for PREINC and PREDEC aren't strictly correct, but they
|
||||
preserve old behavior if a construct like --x=9 is given. */
|
||||
if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
value = (e == ']') ? get_array_value (tokstr, 0) : get_string_value (tokstr);
|
||||
#else
|
||||
value = get_string_value (tokstr);
|
||||
#endif
|
||||
|
||||
tokval = (value && *value) ? subexpr (value) : 0;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (e == ']')
|
||||
FREE (value); /* get_array_value returns newly-allocated memory */
|
||||
#endif
|
||||
}
|
||||
tokval = expr_streval (tokstr, e);
|
||||
else
|
||||
tokval = 0;
|
||||
|
||||
|
@ -1032,7 +1073,7 @@ evalerror (msg)
|
|||
longjmp (evalbuf, 1);
|
||||
}
|
||||
|
||||
/* Convert a string to a long integer, with an arbitrary base.
|
||||
/* Convert a string to an intmax_t integer, with an arbitrary base.
|
||||
0nnn -> base 8
|
||||
0[Xx]nn -> base 16
|
||||
Anything else: [base#]number (this is implemented to match ksh93)
|
||||
|
@ -1043,14 +1084,14 @@ evalerror (msg)
|
|||
from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, _ = 62, @ = 63 --
|
||||
you get the picture). */
|
||||
|
||||
static long
|
||||
static intmax_t
|
||||
strlong (num)
|
||||
char *num;
|
||||
{
|
||||
register char *s;
|
||||
register unsigned char c;
|
||||
int base, foundbase;
|
||||
long val;
|
||||
intmax_t val;
|
||||
|
||||
s = num;
|
||||
|
||||
|
@ -1142,7 +1183,7 @@ main (argc, argv)
|
|||
char **argv;
|
||||
{
|
||||
register int i;
|
||||
long v;
|
||||
intmax_t v;
|
||||
int expok;
|
||||
|
||||
if (setjmp (top_level))
|
||||
|
@ -1171,7 +1212,7 @@ builtin_error (format, arg1, arg2, arg3, arg4, arg5)
|
|||
|
||||
char *
|
||||
itos (n)
|
||||
long n;
|
||||
intmax_t n;
|
||||
{
|
||||
return ("42");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue