--- src/bin/sh/arith.y 2005/10/08 11:23:28 1.4 +++ src/bin/sh/arith.y 2007/01/04 14:06:21 1.5 @@ -1,58 +1,4 @@ -%token ARITH_NUM ARITH_LPAREN ARITH_RPAREN - -%left ARITH_OR -%left ARITH_AND -%left ARITH_BOR -%left ARITH_BXOR -%left ARITH_BAND -%left ARITH_EQ ARITH_NE -%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE -%left ARITH_LSHIFT ARITH_RSHIFT -%left ARITH_ADD ARITH_SUB -%left ARITH_MUL ARITH_DIV ARITH_REM -%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT -%% - -exp: expr { - return ($1); - } - ; - - -expr: ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; } - | expr ARITH_OR expr { $$ = $1 ? $1 : $3 ? $3 : 0; } - | expr ARITH_AND expr { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } - | expr ARITH_BOR expr { $$ = $1 | $3; } - | expr ARITH_BXOR expr { $$ = $1 ^ $3; } - | expr ARITH_BAND expr { $$ = $1 & $3; } - | expr ARITH_EQ expr { $$ = $1 == $3; } - | expr ARITH_GT expr { $$ = $1 > $3; } - | expr ARITH_GE expr { $$ = $1 >= $3; } - | expr ARITH_LT expr { $$ = $1 < $3; } - | expr ARITH_LE expr { $$ = $1 <= $3; } - | expr ARITH_NE expr { $$ = $1 != $3; } - | expr ARITH_LSHIFT expr { $$ = $1 << $3; } - | expr ARITH_RSHIFT expr { $$ = $1 >> $3; } - | expr ARITH_ADD expr { $$ = $1 + $3; } - | expr ARITH_SUB expr { $$ = $1 - $3; } - | expr ARITH_MUL expr { $$ = $1 * $3; } - | expr ARITH_DIV expr { - if ($3 == 0) - yyerror("division by zero"); - $$ = $1 / $3; - } - | expr ARITH_REM expr { - if ($3 == 0) - yyerror("division by zero"); - $$ = $1 % $3; - } - | ARITH_NOT expr { $$ = !($2); } - | ARITH_BNOT expr { $$ = ~($2); } - | ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); } - | ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; } - | ARITH_NUM - ; -%% +%{ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. @@ -89,23 +35,249 @@ expr: ARITH_LPAREN expr ARITH_RPAREN { $ * SUCH DAMAGE. * * @(#)arith.y 8.3 (Berkeley) 5/4/95 - * $FreeBSD: src/bin/sh/arith.y,v 1.10.2.2 2002/07/19 04:38:51 tjr Exp $ + * $FreeBSD: src/bin/sh/arith.y,v 1.21 2005/08/13 07:59:46 stefanf Exp $ * $DragonFly$ */ +#include +#include + +#include "arith.h" #include "shell.h" +#include "var.h" +%} +%union { + arith_t l_value; + char* s_value; +} +%token ARITH_NUM ARITH_LPAREN ARITH_RPAREN +%token ARITH_VAR + +%type expr +%right ARITH_ASSIGN +%right ARITH_ADDASSIGN ARITH_SUBASSIGN +%right ARITH_MULASSIGN ARITH_DIVASSIGN ARITH_REMASSIGN +%right ARITH_RSHASSIGN ARITH_LSHASSIGN +%right ARITH_BANDASSIGN ARITH_BXORASSIGN ARITH_BORASSIGN +%left ARITH_OR +%left ARITH_AND +%left ARITH_BOR +%left ARITH_BXOR +%left ARITH_BAND +%left ARITH_EQ ARITH_NE +%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE +%left ARITH_LSHIFT ARITH_RSHIFT +%left ARITH_ADD ARITH_SUB +%left ARITH_MUL ARITH_DIV ARITH_REM +%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT +%% + +exp: + expr + { return ($1); } + ; + +expr: + ARITH_LPAREN expr ARITH_RPAREN + { $$ = $2; } | + expr ARITH_OR expr + { $$ = $1 ? $1 : $3 ? $3 : 0; } | + expr ARITH_AND expr + { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } | + expr ARITH_BOR expr + { $$ = $1 | $3; } | + expr ARITH_BXOR expr + { $$ = $1 ^ $3; } | + expr ARITH_BAND expr + { $$ = $1 & $3; } | + expr ARITH_EQ expr + { $$ = $1 == $3; } | + expr ARITH_GT expr + { $$ = $1 > $3; } | + expr ARITH_GE expr + { $$ = $1 >= $3; } | + expr ARITH_LT expr + { $$ = $1 < $3; } | + expr ARITH_LE expr + { $$ = $1 <= $3; } | + expr ARITH_NE expr + { $$ = $1 != $3; } | + expr ARITH_LSHIFT expr + { $$ = $1 << $3; } | + expr ARITH_RSHIFT expr + { $$ = $1 >> $3; } | + expr ARITH_ADD expr + { $$ = $1 + $3; } | + expr ARITH_SUB expr + { $$ = $1 - $3; } | + expr ARITH_MUL expr + { $$ = $1 * $3; } | + expr ARITH_DIV expr + { + if ($3 == 0) + yyerror("division by zero"); + $$ = $1 / $3; + } | + expr ARITH_REM expr + { + if ($3 == 0) + yyerror("division by zero"); + $$ = $1 % $3; + } | + ARITH_NOT expr + { $$ = !($2); } | + ARITH_BNOT expr + { $$ = ~($2); } | + ARITH_SUB expr %prec ARITH_UNARYMINUS + { $$ = -($2); } | + ARITH_ADD expr %prec ARITH_UNARYPLUS + { $$ = $2; } | + ARITH_NUM | + ARITH_VAR + { + char *p; + arith_t arith_val; + char *str_val; + + if (lookupvar($1) == NULL) + setvarsafe($1, "0", 0); + str_val = lookupvar($1); + arith_val = strtoarith_t(str_val, &p, 0); + /* + * Conversion is successful only in case + * we've converted _all_ characters. + */ + if (*p != '\0') + yyerror("variable conversion error"); + $$ = arith_val; + } | + ARITH_VAR ARITH_ASSIGN expr + { + if (arith_assign($1, $3) != 0) + yyerror("variable assignment error"); + $$ = $3; + } | + ARITH_VAR ARITH_ADDASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) + $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_SUBASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) - $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_MULASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) * $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_DIVASSIGN expr + { + arith_t value; + + if ($3 == 0) + yyerror("division by zero"); + + value = atoarith_t(lookupvar($1)) / $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_REMASSIGN expr + { + arith_t value; + + if ($3 == 0) + yyerror("division by zero"); + + value = atoarith_t(lookupvar($1)) % $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_RSHASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) >> $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_LSHASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) << $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_BANDASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) & $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_BXORASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) ^ $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_BORASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) | $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } ; +%% #include "error.h" #include "output.h" #include "memalloc.h" -#include "arith.h" +#define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3) const char *arith_buf, *arith_startbuf; -extern void arith_lex_reset(void); int yylex(void); int yyparse(void); -void yyerror(const char *s); +static void yyerror(const char *s); + +static int +arith_assign(char *name, arith_t value) +{ + char *str; + int ret; + + str = (char *)ckmalloc(lstrlen(value)); + sprintf(str, ARITH_FORMAT_STR, value); + ret = setvarsafe(name, str, 0); + free(str); + return (ret); +} int arith(const char *s) @@ -116,19 +288,19 @@ arith(const char *s) INTOFF; result = yyparse(); - arith_lex_reset(); /* reprime lex */ + arith_lex_reset(); /* Reprime lex. */ INTON; return (result); } -void +static void yyerror(const char *s) { yyerrok; yyclearin; - arith_lex_reset(); /* reprime lex */ + arith_lex_reset(); /* Reprime lex. */ error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); } @@ -147,7 +319,7 @@ expcmd(int argc, char **argv) p = argv[1]; if (argc > 2) { /* - * concatenate arguments + * Concatenate arguments. */ STARTSTACKSTR(concat); ap = argv + 2;