Sync with FreeBSD:
authorPeter Avalos <pavalos@dragonflybsd.org>
Thu, 4 Jan 2007 14:06:21 +0000 (14:06 +0000)
committerPeter Avalos <pavalos@dragonflybsd.org>
Thu, 4 Jan 2007 14:06:21 +0000 (14:06 +0000)
Implement missing shell arithmetic operators in $(()) expansion
and variable recognition.

Provide missing prototypes and variable declarations in arith.h.

Spelling/style fixes.

bin/sh/arith.h
bin/sh/arith.y
bin/sh/arith_lex.l
bin/sh/shell.h

index 856eaa6..4f21033 100644 (file)
  * SUCH DAMAGE.
  *
  *     @(#)arith.h     1.1 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/arith.h,v 1.5.2.1 2002/07/19 04:38:51 tjr Exp $
- * $DragonFly: src/bin/sh/arith.h,v 1.3 2004/03/19 18:39:40 cpressey Exp $
+ * $FreeBSD: src/bin/sh/arith.h,v 1.11 2005/08/13 07:59:46 stefanf Exp $
+ * $DragonFly: src/bin/sh/arith.h,v 1.4 2007/01/04 14:06:21 pavalos Exp $
  */
 
+extern const char *arith_buf, *arith_startbuf;
+
 int arith(const char *);
+void arith_lex_reset(void);
 int expcmd(int , char **);
index 6c40e13..a245ecc 100644 (file)
@@ -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 { $$ = $2; }
  * 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 $
- * $DragonFly: src/bin/sh/arith.y,v 1.4 2005/10/08 11:23:28 corecode Exp $
+ * $FreeBSD: src/bin/sh/arith.y,v 1.21 2005/08/13 07:59:46 stefanf Exp $
+ * $DragonFly: src/bin/sh/arith.y,v 1.5 2007/01/04 14:06:21 pavalos Exp $
  */
 
+#include <limits.h>
+#include <stdio.h>
+
+#include "arith.h"
 #include "shell.h"
+#include "var.h"
+%}
+%union {
+       arith_t l_value;
+       char* s_value;
+}
+%token <l_value> ARITH_NUM ARITH_LPAREN ARITH_RPAREN
+%token <s_value> ARITH_VAR
+
+%type <l_value>        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;
index 64c9aa0..e57fb7c 100644 (file)
  * SUCH DAMAGE.
  *
  * @(#)arith_lex.l     8.3 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/arith_lex.l,v 1.14.2.2 2002/07/19 04:38:51 tjr Exp $
- * $DragonFly: src/bin/sh/arith_lex.l,v 1.4 2005/04/19 05:18:19 cpressey Exp $
+ * $FreeBSD: src/bin/sh/arith_lex.l,v 1.24 2005/08/13 07:59:46 stefanf Exp $
+ * $DragonFly: src/bin/sh/arith_lex.l,v 1.5 2007/01/04 14:06:21 pavalos Exp $
  */
 
+#include <string.h>
 #include <unistd.h>
 
+#include "arith.h"
+#include "shell.h"
 #include "y.tab.h"
 #include "error.h"
+#include "memalloc.h"
+#include "var.h"
 
-extern int yylex(void);
+int yylex(void);
 
-extern int yylval;
-extern const char *arith_buf, *arith_startbuf;
 #undef YY_INPUT
 #define YY_INPUT(buf,result,max) \
        result = (*buf = *arith_buf++) ? 1 : YY_NULL;
 #define YY_NO_UNPUT
-
-void arith_lex_reset(void);
 %}
 
 %%
 [ \t\n]        { ; }
-[0-9]+ { yylval = atol(yytext); return(ARITH_NUM); }
-"("    { return(ARITH_LPAREN); }
-")"    { return(ARITH_RPAREN); }
-"||"   { return(ARITH_OR); }
-"&&"   { return(ARITH_AND); }
-"|"    { return(ARITH_BOR); }
-"^"    { return(ARITH_BXOR); }
-"&"    { return(ARITH_BAND); }
-"=="   { return(ARITH_EQ); }
-"!="   { return(ARITH_NE); }
-">"    { return(ARITH_GT); }
-">="   { return(ARITH_GE); }
-"<"    { return(ARITH_LT); }
-"<="   { return(ARITH_LE); }
-"<<"   { return(ARITH_LSHIFT); }
-">>"   { return(ARITH_RSHIFT); }
-"*"    { return(ARITH_MUL); }
-"/"    { return(ARITH_DIV); }
-"%"    { return(ARITH_REM); }
-"+"    { return(ARITH_ADD); }
-"-"    { return(ARITH_SUB); }
-"~"    { return(ARITH_BNOT); }
-"!"    { return(ARITH_NOT); }
-.      { error("arith: syntax error: \"%s\"\n", arith_startbuf); }
+
+0x[a-fA-F0-9]+ {
+                       yylval.l_value = strtoarith_t(yytext, NULL, 16);
+                       return ARITH_NUM;
+               }
+
+0[0-7]+                {
+                       yylval.l_value = strtoarith_t(yytext, NULL, 8);
+                       return ARITH_NUM;
+               }
+
+[0-9]+         {
+                       yylval.l_value = strtoarith_t(yytext, NULL, 10);
+                       return ARITH_NUM;
+               }
+
+[A-Za-z][A-Za-z0-9_]*  {
+                       /*
+                        * If variable doesn't exist, we should initialize
+                        * it to zero.
+                        */
+                       char *temp;
+                       if (lookupvar(yytext) == NULL)
+                               setvarsafe(yytext, "0", 0);
+                       temp = (char *)ckmalloc(strlen(yytext) + 1);
+                       yylval.s_value = strcpy(temp, yytext);
+
+                       return ARITH_VAR;
+               }
+
+"("            {       return ARITH_LPAREN;    }
+")"            {       return ARITH_RPAREN;    }
+"||"           {       return ARITH_OR;        }
+"&&"           {       return ARITH_AND;       }
+"|"            {       return ARITH_BOR;       }
+"^"            {       return ARITH_BXOR;      }
+"&"            {       return ARITH_BAND;      }
+"=="           {       return ARITH_EQ;        }
+"!="           {       return ARITH_NE;        }
+">"            {       return ARITH_GT;        }
+">="           {       return ARITH_GE;        }
+"<"            {       return ARITH_LT;        }
+"<="           {       return ARITH_LE;        }
+"<<"           {       return ARITH_LSHIFT;    }
+">>"           {       return ARITH_RSHIFT;    }
+"*"            {       return ARITH_MUL;       }
+"/"            {       return ARITH_DIV;       }
+"%"            {       return ARITH_REM;       }
+"+"            {       return ARITH_ADD;       }
+"-"            {       return ARITH_SUB;       }
+"~"            {       return ARITH_BNOT;      }
+"!"            {       return ARITH_NOT;       }
+"="            {       return ARITH_ASSIGN;    }
+"+="           {       return ARITH_ADDASSIGN; }
+"-="           {       return ARITH_SUBASSIGN; }
+"*="           {       return ARITH_MULASSIGN; }
+"/="           {       return ARITH_DIVASSIGN; }
+"%="           {       return ARITH_REMASSIGN; }
+">>="          {       return ARITH_RSHASSIGN; }
+"<<="          {       return ARITH_LSHASSIGN; }
+"&="           {       return ARITH_BANDASSIGN; }
+"^="           {       return ARITH_BXORASSIGN; }
+"|="           {       return ARITH_BORASSIGN; }
+.              {
+                       error("arith: syntax error: \"%s\"\n", arith_startbuf);
+               }
 %%
 
 void
-arith_lex_reset()
+arith_lex_reset(void)
 {
        YY_NEW_FILE;
 }
index 7cd37ca..9046e45 100644 (file)
@@ -34,8 +34,8 @@
  * SUCH DAMAGE.
  *
  *     @(#)shell.h     8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/shell.h,v 1.11.2.3 2002/08/27 01:36:28 tjr Exp $
- * $DragonFly: src/bin/sh/shell.h,v 1.2 2003/06/17 04:22:50 dillon Exp $
+ * $FreeBSD: src/bin/sh/shell.h,v 1.17 2004/04/06 20:06:51 markm Exp $
+ * $DragonFly: src/bin/sh/shell.h,v 1.3 2007/01/04 14:06:21 pavalos Exp $
  */
 
 /*
  */
 
 
-#define JOBS 1
+#define        JOBS 1
 /* #define DEBUG 1 */
 
+/*
+ * Type of used arithmetics. SUSv3 requires us to have at least signed long.
+ */
+typedef long arith_t;
+#define        ARITH_FORMAT_STR  "%ld"
+#define        atoarith_t(arg)  strtol(arg, NULL, 0)
+#define        strtoarith_t(nptr, endptr, base)  strtol(nptr, endptr, base)
+
 typedef void *pointer;
 #define STATIC  static
-#define MKINIT /* empty */
+#define MKINIT  /* empty */
 
 #include <sys/cdefs.h>
 
 extern char nullstr[1];                /* null string */
 
-
 #ifdef DEBUG
-#define TRACE(param)   sh_trace param
+#define TRACE(param)  sh_trace param
 #else
 #define TRACE(param)
 #endif