perl 3.0 patch #14 patch #13, continued
[p5sagit/p5-mst-13.2.git] / perl.y
diff --git a/perl.y b/perl.y
index 45feaaf..96ef414 100644 (file)
--- a/perl.y
+++ b/perl.y
@@ -1,8 +1,33 @@
-/* $Header: perl.y,v 2.0 88/06/05 00:09:36 root Exp $
+/* $Header: perl.y,v 3.0.1.5 90/03/12 16:55:56 lwall Locked $
+ *
+ *    Copyright (c) 1989, Larry Wall
+ *
+ *    You may distribute under the terms of the GNU General Public License
+ *    as specified in the README file that comes with the perl 3.0 kit.
  *
  * $Log:       perl.y,v $
- * Revision 2.0  88/06/05  00:09:36  root
- * Baseline version 2.0.
+ * Revision 3.0.1.5  90/03/12  16:55:56  lwall
+ * patch13: added list slice operator (LIST)[LIST]
+ * patch13: (LIST,) now legal
+ * 
+ * Revision 3.0.1.4  90/02/28  18:03:23  lwall
+ * patch9: line numbers were bogus during certain portions of foreach evaluation
+ * 
+ * Revision 3.0.1.3  89/12/21  20:13:41  lwall
+ * patch7: send() didn't allow a TO argument
+ * 
+ * Revision 3.0.1.2  89/11/11  04:49:04  lwall
+ * patch2: moved yydebug to where its type doesn't matter
+ * patch2: !$foo++ was unreasonably illegal
+ * patch2: local(@foo) didn't work
+ * patch2: default args to unary operators didn't work
+ * 
+ * Revision 3.0.1.1  89/10/26  23:20:41  lwall
+ * patch1: grandfathered "format stdout"
+ * patch1: operator(); is now normally equivalent to operator;
+ * 
+ * Revision 3.0  89/10/18  15:22:04  lwall
+ * 3.0 baseline
  * 
  */
 
 #include "INTERN.h"
 #include "perl.h"
 
-char *tokename[] = {
-"256",
-"word",
-"append","open","write","select","close","loopctl",
-"using","format","do","shift","push","pop","chop/study",
-"while","until","if","unless","else","elsif","continue","split","sprintf",
-"for", "eof", "tell", "seek", "stat",
-"function(no args)","function(1 arg)","function(2 args)","function(3 args)","array function",
-"join", "sub", "file test", "local", "delete",
-"format lines",
-"register","array_length", "array",
-"s","pattern",
-"string","tr",
-"list operator",
-"..",
-"||",
-"&&",
-"==","!=", "EQ", "NE",
-"<=",">=", "LT", "GT", "LE", "GE",
-"unary operation",
-"file test",
-"<<",">>",
-"=~","!~",
-"unary -",
-"++", "--",
-"???"
-};
-
 STAB *scrstab;
+ARG *arg4;     /* rarely used arguments to make_op() */
+ARG *arg5;
 
 %}
 
@@ -55,22 +54,22 @@ STAB *scrstab;
 }
 
 %token <cval> WORD
-%token <ival> APPEND OPEN WRITE SELECT CLOSE LOOPEX
+%token <ival> APPEND OPEN SELECT LOOPEX
 %token <ival> USING FORMAT DO SHIFT PUSH POP LVALFUN
-%token <ival> WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE SPLIT SPRINTF
-%token <ival> FOR FEOF TELL SEEK STAT 
-%token <ival> FUNC0 FUNC1 FUNC2 FUNC3 STABFUN
-%token <ival> JOIN SUB FILETEST LOCAL DELETE
+%token <ival> WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE SPLIT FLIST
+%token <ival> FOR FILOP FILOP2 FILOP3 FILOP4 FILOP22 FILOP25
+%token <ival> FUNC0 FUNC1 FUNC2 FUNC3 HSHFUN HSHFUN3
+%token <ival> FLIST2 SUB FILETEST LOCAL DELETE
+%token <ival> RELOP EQOP MULOP ADDOP PACKAGE AMPER LFUNC4
 %token <formval> FORMLIST
-%token <stabval> REG ARYLEN ARY
+%token <stabval> REG ARYLEN ARY HSH STAR
 %token <arg> SUBST PATTERN
 %token <arg> RSTRING TRANS
 
-%type <ival> prog decl format
+%type <ival> prog decl format remember
 %type <stabval>
 %type <cmdval> block lineseq line loop cond sideff nexpr else
-%type <arg> expr sexpr term
-%type <arg> condmod loopmod
+%type <arg> expr sexpr cexpr csexpr term handle aryword hshword
 %type <arg> texpr listop
 %type <cval> label
 %type <compval> compblock
@@ -84,25 +83,32 @@ STAB *scrstab;
 %left ANDAND
 %left '|' '^'
 %left '&'
-%nonassoc EQ NE SEQ SNE
-%nonassoc '<' '>' LE GE SLT SGT SLE SGE
+%nonassoc EQOP
+%nonassoc RELOP
 %nonassoc <ival> UNIOP
 %nonassoc FILETEST
 %left LS RS
-%left '+' '-' '.'
-%left '*' '/' '%' 'x'
+%left ADDOP
+%left MULOP
 %left MATCH NMATCH 
 %right '!' '~' UMINUS
+%right POW
 %nonassoc INC DEC
 %left '('
 
 %% /* RULES */
 
-prog   :       lineseq
+prog   :       /* NULL */
+               {
+#if defined(YYDEBUG) && defined(DEBUGGING)
+                   yydebug = (debug & 1);
+#endif
+               }
+       /*CONTINUED*/   lineseq
                        { if (in_eval)
-                               eval_root = block_head($1);
+                               eval_root = block_head($2);
                            else
-                               main_root = block_head($1); }
+                               main_root = block_head($2); }
        ;
 
 compblock:     block CONTINUE block
@@ -117,11 +123,17 @@ else      :       /* NULL */
                        { $$ = $2; }
        |       ELSIF '(' expr ')' compblock
                        { cmdline = $1;
-                           $$ = make_ccmd(C_IF,$3,$5); }
+                           $$ = make_ccmd(C_ELSIF,$3,$5); }
+       ;
+
+block  :       '{' remember lineseq '}'
+                       { $$ = block_head($3);
+                         if (savestack->ary_fill > $2)
+                           restorelist($2); }
        ;
 
-block  :       '{' lineseq '}'
-                       { $$ = block_head($2); }
+remember:      /* NULL */      /* in case they push a package name */
+                       { $$ = savestack->ary_fill; }
        ;
 
 lineseq        :       /* NULL */
@@ -145,22 +157,30 @@ line      :       decl
                        { $$ = add_label($1,$2); }
        ;
 
-sideff :       expr
+sideff :       error
+                       { $$ = Nullcmd; }
+       |       expr
                        { $$ = make_acmd(C_EXPR, Nullstab, $1, Nullarg); }
-       |       expr condmod
+       |       expr IF expr
                        { $$ = addcond(
-                              make_acmd(C_EXPR, Nullstab, Nullarg, $1), $2); }
-       |       expr loopmod
+                              make_acmd(C_EXPR, Nullstab, Nullarg, $1), $3); }
+       |       expr UNLESS expr
+                       { $$ = addcond(invert(
+                              make_acmd(C_EXPR, Nullstab, Nullarg, $1)), $3); }
+       |       expr WHILE expr
                        { $$ = addloop(
-                              make_acmd(C_EXPR, Nullstab, Nullarg, $1), $2); }
+                              make_acmd(C_EXPR, Nullstab, Nullarg, $1), $3); }
+       |       expr UNTIL expr
+                       { $$ = addloop(invert(
+                              make_acmd(C_EXPR, Nullstab, Nullarg, $1)), $3); }
        ;
 
 cond   :       IF '(' expr ')' compblock
                        { cmdline = $1;
-                           $$ = make_ccmd(C_IF,$3,$5); }
+                           $$ = make_icmd(C_IF,$3,$5); }
        |       UNLESS '(' expr ')' compblock
                        { cmdline = $1;
-                           $$ = invert(make_ccmd(C_IF,$3,$5)); }
+                           $$ = invert(make_icmd(C_IF,$3,$5)); }
        |       IF block compblock
                        { cmdline = $1;
                            $$ = make_ccmd(C_IF,cmd_to_arg($2),$3); }
@@ -195,6 +215,9 @@ loop        :       label WHILE '(' texpr ')' compblock
                             *          @ary = EXPR;
                             *          foreach VAR (@ary) {
                             * where @ary is a hidden array made by genstab().
+                            * (Note that @ary may become a local array if
+                            * it is determined that it might be called
+                            * recursively.  See cmd_tosave().)
                             */
                            if ($5->arg_type != O_ARRAY) {
                                scrstab = aadd(genstab());
@@ -204,15 +227,17 @@ loop      :       label WHILE '(' texpr ')' compblock
                                        listish(make_op(O_ARRAY, 1,
                                          stab2arg(A_STAB,scrstab),
                                          Nullarg,Nullarg, 1)),
-                                       listish($5),
-                                       Nullarg,1)),
+                                       listish(make_list($5)),
+                                       Nullarg)),
                                      Nullarg),
                                    wopt(over($3,add_label($1,
                                      make_ccmd(C_WHILE,
                                        make_op(O_ARRAY, 1,
                                          stab2arg(A_STAB,scrstab),
-                                         Nullarg,Nullarg, 1 ),
+                                         Nullarg,Nullarg ),
                                        $7)))));
+                               $$->c_line = $2;
+                               $$->c_head->c_line = $2;
                            }
                            else {
                                $$ = wopt(over($3,add_label($1,
@@ -229,15 +254,17 @@ loop      :       label WHILE '(' texpr ')' compblock
                                        listish(make_op(O_ARRAY, 1,
                                          stab2arg(A_STAB,scrstab),
                                          Nullarg,Nullarg, 1 )),
-                                       listish($4),
-                                       Nullarg,1)),
+                                       listish(make_list($4)),
+                                       Nullarg)),
                                      Nullarg),
                                    wopt(over(defstab,add_label($1,
                                      make_ccmd(C_WHILE,
                                        make_op(O_ARRAY, 1,
                                          stab2arg(A_STAB,scrstab),
-                                         Nullarg,Nullarg, 1 ),
+                                         Nullarg,Nullarg ),
                                        $6)))));
+                               $$->c_line = $2;
+                               $$->c_head->c_line = $2;
                            }
                            else {      /* lisp, anyone? */
                                $$ = wopt(over(defstab,add_label($1,
@@ -261,7 +288,7 @@ nexpr       :       /* NULL */
        ;
 
 texpr  :       /* NULL means true */
-                       {   scanstr("1"); $$ = yylval.arg; }
+                       { (void)scanstr("1"); $$ = yylval.arg; }
        |       expr
        ;
 
@@ -270,196 +297,209 @@ label   :       /* empty */
        |       WORD ':'
        ;
 
-loopmod :      WHILE expr
-                       { $$ = $2; }
-       |       UNTIL expr
-                       { $$ = make_op(O_NOT,1,$2,Nullarg,Nullarg,0); }
-       ;
-
-condmod :      IF expr
-                       { $$ = $2; }
-       |       UNLESS expr
-                       { $$ = make_op(O_NOT,1,$2,Nullarg,Nullarg,0); }
-       ;
-
 decl   :       format
                        { $$ = 0; }
        |       subrout
                        { $$ = 0; }
+       |       package
+                       { $$ = 0; }
        ;
 
-format :       FORMAT WORD '=' FORMLIST '.' 
-                       { stabent($2,TRUE)->stab_form = $4; safefree($2); }
-       |       FORMAT '=' FORMLIST '.'
-                       { stabent("stdout",TRUE)->stab_form = $3; }
+format :       FORMAT WORD '=' FORMLIST
+                       { if (strEQ($2,"stdout"))
+                           stab_form(stabent("STDOUT",TRUE)) = $4;
+                         else if (strEQ($2,"stderr"))
+                           stab_form(stabent("STDERR",TRUE)) = $4;
+                         else
+                           stab_form(stabent($2,TRUE)) = $4;
+                         Safefree($2);}
+       |       FORMAT '=' FORMLIST
+                       { stab_form(stabent("STDOUT",TRUE)) = $3; }
        ;
 
 subrout        :       SUB WORD block
                        { make_sub($2,$3); }
        ;
 
-expr   :       sexpr ',' expr
-                       { $$ = make_op(O_COMMA, 2, $1, $3, Nullarg,0); }
+package :      PACKAGE WORD ';'
+                       { char tmpbuf[256];
+
+                         savehptr(&curstash);
+                         saveitem(curstname);
+                         str_set(curstname,$2);
+                         sprintf(tmpbuf,"'_%s",$2);
+                         curstash = stab_xhash(hadd(stabent(tmpbuf,TRUE)));
+                         curstash->tbl_coeffsize = 0;
+                         Safefree($2);
+                       }
+       ;
+
+cexpr  :       ',' expr
+                       { $$ = $2; }
+       ;
+
+expr   :       expr ',' sexpr
+                       { $$ = make_op(O_COMMA, 2, $1, $3, Nullarg); }
        |       sexpr
        ;
 
+csexpr :       ',' sexpr
+                       { $$ = $2; }
+       ;
+
 sexpr  :       sexpr '=' sexpr
                        {   $1 = listish($1);
+                           if ($1->arg_type == O_ASSIGN && $1->arg_len == 1)
+                               $1->arg_type = O_ITEM;  /* a local() */
                            if ($1->arg_type == O_LIST)
                                $3 = listish($3);
-                           $$ = l(make_op(O_ASSIGN, 2, $1, $3, Nullarg,1)); }
-       |       sexpr '*' '=' sexpr
-                       { $$ = l(make_op(O_MULTIPLY, 2, $1, $4, Nullarg,0)); }
-       |       sexpr '/' '=' sexpr
-                       { $$ = l(make_op(O_DIVIDE, 2, $1, $4, Nullarg,0)); }
-       |       sexpr '%' '=' sexpr
-                       { $$ = l(make_op(O_MODULO, 2, $1, $4, Nullarg,0)); }
-       |       sexpr 'x' '=' sexpr
-                       { $$ = l(make_op(O_REPEAT, 2, $1, $4, Nullarg,0)); }
-       |       sexpr '+' '=' sexpr
-                       { $$ = l(make_op(O_ADD, 2, $1, $4, Nullarg,0)); }
-       |       sexpr '-' '=' sexpr
-                       { $$ = l(make_op(O_SUBTRACT, 2, $1, $4, Nullarg,0)); }
+                           $$ = l(make_op(O_ASSIGN, 2, $1, $3, Nullarg)); }
+       |       sexpr POW '=' sexpr
+                       { $$ = l(make_op(O_POW, 2, $1, $4, Nullarg)); }
+       |       sexpr MULOP '=' sexpr
+                       { $$ = l(make_op($2, 2, $1, $4, Nullarg)); }
+       |       sexpr ADDOP '=' sexpr
+                       { $$ = rcatmaybe(l(make_op($2, 2, $1, $4, Nullarg)));}
        |       sexpr LS '=' sexpr
-                       { $$ = l(make_op(O_LEFT_SHIFT, 2, $1, $4, Nullarg,0)); }
+                       { $$ = l(make_op(O_LEFT_SHIFT, 2, $1, $4, Nullarg)); }
        |       sexpr RS '=' sexpr
-                       { $$ = l(make_op(O_RIGHT_SHIFT, 2, $1, $4, Nullarg,0)); }
+                       { $$ = l(make_op(O_RIGHT_SHIFT, 2, $1, $4, Nullarg)); }
        |       sexpr '&' '=' sexpr
-                       { $$ = l(make_op(O_BIT_AND, 2, $1, $4, Nullarg,0)); }
+                       { $$ = l(make_op(O_BIT_AND, 2, $1, $4, Nullarg)); }
        |       sexpr '^' '=' sexpr
-                       { $$ = l(make_op(O_XOR, 2, $1, $4, Nullarg,0)); }
+                       { $$ = l(make_op(O_XOR, 2, $1, $4, Nullarg)); }
        |       sexpr '|' '=' sexpr
-                       { $$ = l(make_op(O_BIT_OR, 2, $1, $4, Nullarg,0)); }
-       |       sexpr '.' '=' sexpr
-                       { $$ = l(make_op(O_CONCAT, 2, $1, $4, Nullarg,0)); }
-
-
-       |       sexpr '*' sexpr
-                       { $$ = make_op(O_MULTIPLY, 2, $1, $3, Nullarg,0); }
-       |       sexpr '/' sexpr
-                       { $$ = make_op(O_DIVIDE, 2, $1, $3, Nullarg,0); }
-       |       sexpr '%' sexpr
-                       { $$ = make_op(O_MODULO, 2, $1, $3, Nullarg,0); }
-       |       sexpr 'x' sexpr
-                       { $$ = make_op(O_REPEAT, 2, $1, $3, Nullarg,0); }
-       |       sexpr '+' sexpr
-                       { $$ = make_op(O_ADD, 2, $1, $3, Nullarg,0); }
-       |       sexpr '-' sexpr
-                       { $$ = make_op(O_SUBTRACT, 2, $1, $3, Nullarg,0); }
+                       { $$ = l(make_op(O_BIT_OR, 2, $1, $4, Nullarg)); }
+
+
+       |       sexpr POW sexpr
+                       { $$ = make_op(O_POW, 2, $1, $3, Nullarg); }
+       |       sexpr MULOP sexpr
+                       { $$ = make_op($2, 2, $1, $3, Nullarg); }
+       |       sexpr ADDOP sexpr
+                       { $$ = make_op($2, 2, $1, $3, Nullarg); }
        |       sexpr LS sexpr
-                       { $$ = make_op(O_LEFT_SHIFT, 2, $1, $3, Nullarg,0); }
+                       { $$ = make_op(O_LEFT_SHIFT, 2, $1, $3, Nullarg); }
        |       sexpr RS sexpr
-                       { $$ = make_op(O_RIGHT_SHIFT, 2, $1, $3, Nullarg,0); }
-       |       sexpr '<' sexpr
-                       { $$ = make_op(O_LT, 2, $1, $3, Nullarg,0); }
-       |       sexpr '>' sexpr
-                       { $$ = make_op(O_GT, 2, $1, $3, Nullarg,0); }
-       |       sexpr LE sexpr
-                       { $$ = make_op(O_LE, 2, $1, $3, Nullarg,0); }
-       |       sexpr GE sexpr
-                       { $$ = make_op(O_GE, 2, $1, $3, Nullarg,0); }
-       |       sexpr EQ sexpr
-                       { $$ = make_op(O_EQ, 2, $1, $3, Nullarg,0); }
-       |       sexpr NE sexpr
-                       { $$ = make_op(O_NE, 2, $1, $3, Nullarg,0); }
-       |       sexpr SLT sexpr
-                       { $$ = make_op(O_SLT, 2, $1, $3, Nullarg,0); }
-       |       sexpr SGT sexpr
-                       { $$ = make_op(O_SGT, 2, $1, $3, Nullarg,0); }
-       |       sexpr SLE sexpr
-                       { $$ = make_op(O_SLE, 2, $1, $3, Nullarg,0); }
-       |       sexpr SGE sexpr
-                       { $$ = make_op(O_SGE, 2, $1, $3, Nullarg,0); }
-       |       sexpr SEQ sexpr
-                       { $$ = make_op(O_SEQ, 2, $1, $3, Nullarg,0); }
-       |       sexpr SNE sexpr
-                       { $$ = make_op(O_SNE, 2, $1, $3, Nullarg,0); }
+                       { $$ = make_op(O_RIGHT_SHIFT, 2, $1, $3, Nullarg); }
+       |       sexpr RELOP sexpr
+                       { $$ = make_op($2, 2, $1, $3, Nullarg); }
+       |       sexpr EQOP sexpr
+                       { $$ = make_op($2, 2, $1, $3, Nullarg); }
        |       sexpr '&' sexpr
-                       { $$ = make_op(O_BIT_AND, 2, $1, $3, Nullarg,0); }
+                       { $$ = make_op(O_BIT_AND, 2, $1, $3, Nullarg); }
        |       sexpr '^' sexpr
-                       { $$ = make_op(O_XOR, 2, $1, $3, Nullarg,0); }
+                       { $$ = make_op(O_XOR, 2, $1, $3, Nullarg); }
        |       sexpr '|' sexpr
-                       { $$ = make_op(O_BIT_OR, 2, $1, $3, Nullarg,0); }
+                       { $$ = make_op(O_BIT_OR, 2, $1, $3, Nullarg); }
        |       sexpr DOTDOT sexpr
-                       { $$ = make_op(O_FLIP, 4,
-                           flipflip($1),
-                           flipflip($3),
-                           Nullarg,0);}
+                       { arg4 = Nullarg;
+                         $$ = make_op(O_F_OR_R, 4, $1, $3, Nullarg); }
        |       sexpr ANDAND sexpr
-                       { $$ = make_op(O_AND, 2, $1, $3, Nullarg,0); }
+                       { $$ = make_op(O_AND, 2, $1, $3, Nullarg); }
        |       sexpr OROR sexpr
-                       { $$ = make_op(O_OR, 2, $1, $3, Nullarg,0); }
+                       { $$ = make_op(O_OR, 2, $1, $3, Nullarg); }
        |       sexpr '?' sexpr ':' sexpr
-                       { $$ = make_op(O_COND_EXPR, 3, $1, $3, $5,0); }
-       |       sexpr '.' sexpr
-                       { $$ = make_op(O_CONCAT, 2, $1, $3, Nullarg,0); }
+                       { $$ = make_op(O_COND_EXPR, 3, $1, $3, $5); }
        |       sexpr MATCH sexpr
                        { $$ = mod_match(O_MATCH, $1, $3); }
        |       sexpr NMATCH sexpr
                        { $$ = mod_match(O_NMATCH, $1, $3); }
+       |       term
+                       { $$ = $1; }
+       ;
+
+term   :       '-' term %prec UMINUS
+                       { $$ = make_op(O_NEGATE, 1, $2, Nullarg, Nullarg); }
+       |       '+' term %prec UMINUS
+                       { $$ = $2; }
+       |       '!' term
+                       { $$ = make_op(O_NOT, 1, $2, Nullarg, Nullarg); }
+       |       '~' term
+                       { $$ = make_op(O_COMPLEMENT, 1, $2, Nullarg, Nullarg);}
        |       term INC
                        { $$ = addflags(1, AF_POST|AF_UP,
-                           l(make_op(O_ITEM,1,$1,Nullarg,Nullarg,0))); }
+                           l(make_op(O_ITEM,1,$1,Nullarg,Nullarg))); }
        |       term DEC
                        { $$ = addflags(1, AF_POST,
-                           l(make_op(O_ITEM,1,$1,Nullarg,Nullarg,0))); }
+                           l(make_op(O_ITEM,1,$1,Nullarg,Nullarg))); }
        |       INC term
                        { $$ = addflags(1, AF_PRE|AF_UP,
-                           l(make_op(O_ITEM,1,$2,Nullarg,Nullarg,0))); }
+                           l(make_op(O_ITEM,1,$2,Nullarg,Nullarg))); }
        |       DEC term
                        { $$ = addflags(1, AF_PRE,
-                           l(make_op(O_ITEM,1,$2,Nullarg,Nullarg,0))); }
-       |       term
-                       { $$ = $1; }
-       ;
-
-term   :       '-' term %prec UMINUS
-                       { $$ = make_op(O_NEGATE, 1, $2, Nullarg, Nullarg,0); }
-       |       '!' term
-                       { $$ = make_op(O_NOT, 1, $2, Nullarg, Nullarg,0); }
-       |       '~' term
-                       { $$ = make_op(O_COMPLEMENT, 1, $2, Nullarg, Nullarg,0);}
+                           l(make_op(O_ITEM,1,$2,Nullarg,Nullarg))); }
        |       FILETEST WORD
                        { opargs[$1] = 0;       /* force it special */
                            $$ = make_op($1, 1,
                                stab2arg(A_STAB,stabent($2,TRUE)),
-                               Nullarg, Nullarg,0);
+                               Nullarg, Nullarg);
                        }
        |       FILETEST sexpr
                        { opargs[$1] = 1;
-                           $$ = make_op($1, 1, $2, Nullarg, Nullarg,0); }
+                           $$ = make_op($1, 1, $2, Nullarg, Nullarg); }
        |       FILETEST
                        { opargs[$1] = ($1 != O_FTTTY);
                            $$ = make_op($1, 1,
                                stab2arg(A_STAB,
-                                 $1 == O_FTTTY?stabent("stdin",TRUE):defstab),
-                               Nullarg, Nullarg,0); }
+                                 $1 == O_FTTTY?stabent("STDIN",TRUE):defstab),
+                               Nullarg, Nullarg); }
        |       LOCAL '(' expr ')'
-                       { $$ = localize(listish(make_list(hide_ary($3)))); }
+                       { $$ = l(localize(make_op(O_ASSIGN, 1,
+                               localize(listish(make_list($3))),
+                               Nullarg,Nullarg))); }
+       |       '(' expr ',' ')'
+                       { $$ = make_list(hide_ary($2)); }
        |       '(' expr ')'
                        { $$ = make_list(hide_ary($2)); }
        |       '(' ')'
                        { $$ = make_list(Nullarg); }
        |       DO sexpr        %prec FILETEST
-                       { $$ = make_op(O_DOFILE,1,$2,Nullarg,Nullarg,0);
-                           allstabs = TRUE;}
+                       { $$ = fixeval(
+                           make_op(O_DOFILE,2,$2,Nullarg,Nullarg) );
+                         allstabs = TRUE;}
        |       DO block        %prec '('
                        { $$ = cmd_to_arg($2); }
        |       REG     %prec '('
                        { $$ = stab2arg(A_STAB,$1); }
+       |       STAR    %prec '('
+                       { $$ = stab2arg(A_STAR,$1); }
        |       REG '[' expr ']'        %prec '('
-                       { $$ = make_op(O_ARRAY, 2,
-                               $3, stab2arg(A_STAB,aadd($1)), Nullarg,0); }
+                       { $$ = make_op(O_AELEM, 2,
+                               stab2arg(A_STAB,aadd($1)), $3, Nullarg); }
+       |       HSH     %prec '('
+                       { $$ = make_op(O_HASH, 1,
+                               stab2arg(A_STAB,$1),
+                               Nullarg, Nullarg); }
        |       ARY     %prec '('
                        { $$ = make_op(O_ARRAY, 1,
                                stab2arg(A_STAB,$1),
-                               Nullarg, Nullarg, 1); }
+                               Nullarg, Nullarg); }
        |       REG '{' expr '}'        %prec '('
-                       { $$ = make_op(O_HASH, 2,
-                               $3, stab2arg(A_STAB,hadd($1)), Nullarg,0); }
+                       { $$ = make_op(O_HELEM, 2,
+                               stab2arg(A_STAB,hadd($1)),
+                               jmaybe($3),
+                               Nullarg); }
+       |       '(' expr ')' '[' expr ']'       %prec '('
+                       { $$ = make_op(O_LSLICE, 3,
+                               Nullarg,
+                               listish(make_list($5)),
+                               listish(make_list($2))); }
+       |       ARY '[' expr ']'        %prec '('
+                       { $$ = make_op(O_ASLICE, 2,
+                               stab2arg(A_STAB,aadd($1)),
+                               listish(make_list($3)),
+                               Nullarg); }
+       |       ARY '{' expr '}'        %prec '('
+                       { $$ = make_op(O_HSLICE, 2,
+                               stab2arg(A_STAB,hadd($1)),
+                               listish(make_list($3)),
+                               Nullarg); }
        |       DELETE REG '{' expr '}' %prec '('
                        { $$ = make_op(O_DELETE, 2,
-                               $4, stab2arg(A_STAB,hadd($2)), Nullarg,0); }
+                               stab2arg(A_STAB,hadd($2)),
+                               jmaybe($4),
+                               Nullarg); }
        |       ARYLEN  %prec '('
                        { $$ = stab2arg(A_ARYLEN,$1); }
        |       RSTRING %prec '('
@@ -471,249 +511,247 @@ term    :       '-' term %prec UMINUS
        |       TRANS   %prec '('
                        { $$ = $1; }
        |       DO WORD '(' expr ')'
-                       { $$ = make_op(O_SUBR, 2,
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+                               stab2arg(A_WORD,stabent($2,TRUE)),
                                make_list($4),
+                               Nullarg); Safefree($2); }
+       |       AMPER WORD '(' expr ')'
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
                                stab2arg(A_WORD,stabent($2,TRUE)),
-                               Nullarg,1); }
+                               make_list($4),
+                               Nullarg); Safefree($2); }
        |       DO WORD '(' ')'
-                       { $$ = make_op(O_SUBR, 2,
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+                               stab2arg(A_WORD,stabent($2,TRUE)),
                                make_list(Nullarg),
+                               Nullarg); }
+       |       AMPER WORD '(' ')'
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
                                stab2arg(A_WORD,stabent($2,TRUE)),
-                               Nullarg,1); }
+                               make_list(Nullarg),
+                               Nullarg); }
+       |       AMPER WORD
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+                               stab2arg(A_WORD,stabent($2,TRUE)),
+                               Nullarg,
+                               Nullarg); }
        |       DO REG '(' expr ')'
-                       { $$ = make_op(O_SUBR, 2,
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+                               stab2arg(A_STAB,$2),
                                make_list($4),
+                               Nullarg); }
+       |       AMPER REG '(' expr ')'
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
                                stab2arg(A_STAB,$2),
-                               Nullarg,1); }
+                               make_list($4),
+                               Nullarg); }
        |       DO REG '(' ')'
-                       { $$ = make_op(O_SUBR, 2,
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+                               stab2arg(A_STAB,$2),
                                make_list(Nullarg),
+                               Nullarg); }
+       |       AMPER REG '(' ')'
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
                                stab2arg(A_STAB,$2),
-                               Nullarg,1); }
+                               make_list(Nullarg),
+                               Nullarg); }
+       |       AMPER REG
+                       { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
+                               stab2arg(A_STAB,$2),
+                               Nullarg,
+                               Nullarg); }
        |       LOOPEX
-                       { $$ = make_op($1,0,Nullarg,Nullarg,Nullarg,0); }
+                       { $$ = make_op($1,0,Nullarg,Nullarg,Nullarg); }
        |       LOOPEX WORD
                        { $$ = make_op($1,1,cval_to_arg($2),
-                           Nullarg,Nullarg,0); }
+                           Nullarg,Nullarg); }
        |       UNIOP
-                       { $$ = make_op($1,1,Nullarg,Nullarg,Nullarg,0); }
+                       { $$ = make_op($1,0,Nullarg,Nullarg,Nullarg);
+                         if ($1 == O_EVAL || $1 == O_RESET)
+                           $$ = fixeval($$); }
        |       UNIOP sexpr
-                       { $$ = make_op($1,1,$2,Nullarg,Nullarg,0); }
-       |       WRITE
-                       { $$ = make_op(O_WRITE, 0,
-                           Nullarg, Nullarg, Nullarg,0); }
-       |       WRITE '(' ')'
-                       { $$ = make_op(O_WRITE, 0,
-                           Nullarg, Nullarg, Nullarg,0); }
-       |       WRITE '(' WORD ')'
-                       { $$ = l(make_op(O_WRITE, 1,
-                           stab2arg(A_STAB,stabent($3,TRUE)),
-                           Nullarg, Nullarg,0)); safefree($3); }
-       |       WRITE '(' expr ')'
-                       { $$ = make_op(O_WRITE, 1, $3, Nullarg, Nullarg,0); }
-       |       SELECT '(' WORD ')'
-                       { $$ = l(make_op(O_SELECT, 1,
-                           stab2arg(A_STAB,stabent($3,TRUE)),
-                           Nullarg, Nullarg,0)); safefree($3); }
-       |       SELECT '(' expr ')'
-                       { $$ = make_op(O_SELECT, 1, $3, Nullarg, Nullarg,0); }
+                       { $$ = make_op($1,1,$2,Nullarg,Nullarg);
+                         if ($1 == O_EVAL || $1 == O_RESET)
+                           $$ = fixeval($$); }
+       |       SELECT
+                       { $$ = make_op(O_SELECT, 0, Nullarg, Nullarg, Nullarg);}
+       |       SELECT '(' handle ')'
+                       { $$ = make_op(O_SELECT, 1, $3, Nullarg, Nullarg); }
+       |       SELECT '(' sexpr csexpr csexpr csexpr ')'
+                       { arg4 = $6;
+                         $$ = make_op(O_SSELECT, 4, $3, $4, $5); }
        |       OPEN WORD       %prec '('
                        { $$ = make_op(O_OPEN, 2,
                            stab2arg(A_WORD,stabent($2,TRUE)),
                            stab2arg(A_STAB,stabent($2,TRUE)),
-                           Nullarg,0); }
+                           Nullarg); }
        |       OPEN '(' WORD ')'
                        { $$ = make_op(O_OPEN, 2,
                            stab2arg(A_WORD,stabent($3,TRUE)),
                            stab2arg(A_STAB,stabent($3,TRUE)),
-                           Nullarg,0); }
-       |       OPEN '(' WORD ',' expr ')'
-                       { $$ = make_op(O_OPEN, 2,
-                           stab2arg(A_WORD,stabent($3,TRUE)),
-                           $5, Nullarg,0); }
-       |       OPEN '(' sexpr ',' expr ')'
+                           Nullarg); }
+       |       OPEN '(' handle cexpr ')'
                        { $$ = make_op(O_OPEN, 2,
                            $3,
-                           $5, Nullarg,0); }
-       |       CLOSE '(' WORD ')'
-                       { $$ = make_op(O_CLOSE, 1,
-                           stab2arg(A_WORD,stabent($3,TRUE)),
-                           Nullarg, Nullarg,0); }
-       |       CLOSE '(' expr ')'
-                       { $$ = make_op(O_CLOSE, 1,
+                           $4, Nullarg); }
+       |       FILOP '(' handle ')'
+                       { $$ = make_op($1, 1,
                            $3,
-                           Nullarg, Nullarg,0); }
-       |       CLOSE WORD      %prec '('
-                       { $$ = make_op(O_CLOSE, 1,
+                           Nullarg, Nullarg); }
+       |       FILOP WORD
+                       { $$ = make_op($1, 1,
                            stab2arg(A_WORD,stabent($2,TRUE)),
-                           Nullarg, Nullarg,0); }
-       |       FEOF '(' WORD ')'
-                       { $$ = make_op(O_EOF, 1,
-                           stab2arg(A_WORD,stabent($3,TRUE)),
-                           Nullarg, Nullarg,0); }
-       |       FEOF '(' expr ')'
-                       { $$ = make_op(O_EOF, 1,
-                           $3,
-                           Nullarg, Nullarg,0); }
-       |       FEOF '(' ')'
-                       { $$ = make_op(O_EOF, 1,
+                           Nullarg, Nullarg);
+                         Safefree($2); }
+       |       FILOP REG
+                       { $$ = make_op($1, 1,
+                           stab2arg(A_STAB,$2),
+                           Nullarg, Nullarg); }
+       |       FILOP '(' ')'
+                       { $$ = make_op($1, 1,
                            stab2arg(A_WORD,Nullstab),
-                           Nullarg, Nullarg,0); }
-       |       FEOF
-                       { $$ = make_op(O_EOF, 0,
-                           Nullarg, Nullarg, Nullarg,0); }
-       |       TELL '(' WORD ')'
-                       { $$ = make_op(O_TELL, 1,
-                           stab2arg(A_WORD,stabent($3,TRUE)),
-                           Nullarg, Nullarg,0); }
-       |       TELL '(' expr ')'
-                       { $$ = make_op(O_TELL, 1,
-                           $3,
-                           Nullarg, Nullarg,0); }
-       |       TELL
-                       { $$ = make_op(O_TELL, 0,
-                           Nullarg, Nullarg, Nullarg,0); }
-       |       SEEK '(' WORD ',' sexpr ',' expr ')'
-                       { $$ = make_op(O_SEEK, 3,
-                           stab2arg(A_WORD,stabent($3,TRUE)),
-                           $5, $7,1); }
-       |       SEEK '(' sexpr ',' sexpr ',' expr ')'
-                       { $$ = make_op(O_SEEK, 3,
-                           $3,
-                           $5, $7,1); }
-       |       PUSH '(' WORD ',' expr ')'
-                       { $$ = make_op($1, 2,
-                           make_list($5),
-                           stab2arg(A_STAB,aadd(stabent($3,TRUE))),
-                           Nullarg,1); }
-       |       PUSH '(' ARY ',' expr ')'
+                           Nullarg, Nullarg); }
+       |       FILOP   %prec '('
+                       { $$ = make_op($1, 0,
+                           Nullarg, Nullarg, Nullarg); }
+       |       FILOP2 '(' handle cexpr ')'
+                       { $$ = make_op($1, 2, $3, $4, Nullarg); }
+       |       FILOP3 '(' handle csexpr cexpr ')'
+                       { $$ = make_op($1, 3, $3, $4, make_list($5)); }
+       |       FILOP22 '(' handle ',' handle ')'
+                       { $$ = make_op($1, 2, $3, $5, Nullarg); }
+       |       FILOP4 '(' handle csexpr csexpr cexpr ')'
+                       { arg4 = $6; $$ = make_op($1, 4, $3, $4, $5); }
+       |       FILOP25 '(' handle ',' handle csexpr csexpr cexpr ')'
+                       { arg4 = $7; arg5 = $8;
+                         $$ = make_op($1, 5, $3, $5, $6); }
+       |       PUSH '(' aryword cexpr ')'
                        { $$ = make_op($1, 2,
-                           make_list($5),
-                           stab2arg(A_STAB,$3),
-                           Nullarg,1); }
-       |       POP WORD        %prec '('
-                       { $$ = make_op(O_POP, 1,
-                           stab2arg(A_STAB,aadd(stabent($2,TRUE))),
-                           Nullarg, Nullarg,0); }
-       |       POP '(' WORD ')'
-                       { $$ = make_op(O_POP, 1,
-                           stab2arg(A_STAB,aadd(stabent($3,TRUE))),
-                           Nullarg, Nullarg,0); }
-       |       POP ARY %prec '('
-                       { $$ = make_op(O_POP, 1,
-                           stab2arg(A_STAB,$2),
-                           Nullarg,
-                           Nullarg,
-                           0); }
-       |       POP '(' ARY ')'
-                       { $$ = make_op(O_POP, 1,
-                           stab2arg(A_STAB,$3),
-                           Nullarg,
-                           Nullarg,
-                           0); }
-       |       SHIFT WORD      %prec '('
-                       { $$ = make_op(O_SHIFT, 1,
-                           stab2arg(A_STAB,aadd(stabent($2,TRUE))),
-                           Nullarg, Nullarg,0); }
-       |       SHIFT '(' WORD ')'
-                       { $$ = make_op(O_SHIFT, 1,
-                           stab2arg(A_STAB,aadd(stabent($3,TRUE))),
-                           Nullarg, Nullarg,0); }
-       |       SHIFT ARY       %prec '('
-                       { $$ = make_op(O_SHIFT, 1,
-                           stab2arg(A_STAB,$2), Nullarg, Nullarg,0); }
-       |       SHIFT '(' ARY ')'
-                       { $$ = make_op(O_SHIFT, 1,
-                           stab2arg(A_STAB,$3), Nullarg, Nullarg,0); }
+                           $3,
+                           make_list($4),
+                           Nullarg); }
+       |       POP aryword     %prec '('
+                       { $$ = make_op(O_POP, 1, $2, Nullarg, Nullarg); }
+       |       POP '(' aryword ')'
+                       { $$ = make_op(O_POP, 1, $3, Nullarg, Nullarg); }
+       |       SHIFT aryword   %prec '('
+                       { $$ = make_op(O_SHIFT, 1, $2, Nullarg, Nullarg); }
+       |       SHIFT '(' aryword ')'
+                       { $$ = make_op(O_SHIFT, 1, $3, Nullarg, Nullarg); }
        |       SHIFT   %prec '('
                        { $$ = make_op(O_SHIFT, 1,
-                           stab2arg(A_STAB,aadd(stabent("ARGV",TRUE))),
-                           Nullarg, Nullarg,0); }
+                           stab2arg(A_STAB,
+                             aadd(stabent(subline ? "_" : "ARGV", TRUE))),
+                           Nullarg, Nullarg); }
        |       SPLIT   %prec '('
-                       { scanpat("/\\s+/");
-                           $$ = make_split(defstab,yylval.arg); }
-       |       SPLIT '(' WORD ')'
-                       { scanpat("/\\s+/");
-                           $$ = make_split(stabent($3,TRUE),yylval.arg); }
-       |       SPLIT '(' WORD ',' PATTERN ')'
-                       { $$ = make_split(stabent($3,TRUE),$5); }
-       |       SPLIT '(' WORD ',' PATTERN ',' sexpr ')'
-                       { $$ = mod_match(O_MATCH,
-                           $7,
-                           make_split(stabent($3,TRUE),$5) ); }
-       |       SPLIT '(' sexpr ',' sexpr ')'
-                       { $$ = mod_match(O_MATCH, $5, make_split(defstab,$3) ); }
+                       { (void)scanpat("/\\s+/");
+                           $$ = make_split(defstab,yylval.arg,Nullarg); }
+       |       SPLIT '(' sexpr csexpr csexpr ')'
+                       { $$ = mod_match(O_MATCH, $4,
+                         make_split(defstab,$3,$5));}
+       |       SPLIT '(' sexpr csexpr ')'
+                       { $$ = mod_match(O_MATCH, $4,
+                         make_split(defstab,$3,Nullarg) ); }
        |       SPLIT '(' sexpr ')'
                        { $$ = mod_match(O_MATCH,
                            stab2arg(A_STAB,defstab),
-                           make_split(defstab,$3) ); }
-       |       JOIN '(' WORD ',' expr ')'
-                       { $$ = make_op(O_JOIN, 2,
-                           $5,
-                           stab2arg(A_STAB,aadd(stabent($3,TRUE))),
-                           Nullarg,0); }
-       |       JOIN '(' sexpr ',' expr ')'
-                       { $$ = make_op(O_JOIN, 2,
+                           make_split(defstab,$3,Nullarg) ); }
+       |       FLIST2 '(' sexpr cexpr ')'
+                       { $$ = make_op($1, 2,
                            $3,
-                           make_list($5),
-                           Nullarg,2); }
-       |       SPRINTF '(' expr ')'
-                       { $$ = make_op(O_SPRINTF, 1,
+                           listish(make_list($4)),
+                           Nullarg); }
+       |       FLIST '(' expr ')'
+                       { $$ = make_op($1, 1,
                            make_list($3),
                            Nullarg,
-                           Nullarg,1); }
-       |       STAT '(' WORD ')'
-                       { $$ = l(make_op(O_STAT, 1,
-                           stab2arg(A_STAB,stabent($3,TRUE)),
-                           Nullarg, Nullarg,0)); }
-       |       STAT '(' expr ')'
-                       { $$ = make_op(O_STAT, 1, $3, Nullarg, Nullarg,0); }
+                           Nullarg); }
+       |       LVALFUN sexpr   %prec '('
+                       { $$ = l(make_op($1, 1, fixl($1,$2),
+                           Nullarg, Nullarg)); }
        |       LVALFUN
                        { $$ = l(make_op($1, 1,
                            stab2arg(A_STAB,defstab),
-                           Nullarg, Nullarg,0)); }
-       |       LVALFUN '(' expr ')'
-                       { $$ = l(make_op($1, 1, $3, Nullarg, Nullarg,0)); }
+                           Nullarg, Nullarg)); }
        |       FUNC0
-                       { $$ = make_op($1, 0, Nullarg, Nullarg, Nullarg,0); }
+                       { $$ = make_op($1, 0, Nullarg, Nullarg, Nullarg); }
+       |       FUNC0 '(' ')'
+                       { $$ = make_op($1, 0, Nullarg, Nullarg, Nullarg); }
+       |       FUNC1 '(' ')'
+                       { $$ = make_op($1, 0, Nullarg, Nullarg, Nullarg);
+                         if ($1 == O_EVAL || $1 == O_RESET)
+                           $$ = fixeval($$); }
        |       FUNC1 '(' expr ')'
-                       { $$ = make_op($1, 1, $3, Nullarg, Nullarg,0); }
-       |       FUNC2 '(' sexpr ',' expr ')'
-                       { $$ = make_op($1, 2, $3, $5, Nullarg, 0);
+                       { $$ = make_op($1, 1, $3, Nullarg, Nullarg);
+                         if ($1 == O_EVAL || $1 == O_RESET)
+                           $$ = fixeval($$); }
+       |       FUNC2 '(' sexpr cexpr ')'
+                       { $$ = make_op($1, 2, $3, $4, Nullarg);
                            if ($1 == O_INDEX && $$[2].arg_type == A_SINGLE)
-                               fbmcompile($$[2].arg_ptr.arg_str); }
-       |       FUNC3 '(' sexpr ',' sexpr ',' expr ')'
-                       { $$ = make_op($1, 3, $3, $5, $7, 0); }
-       |       STABFUN '(' WORD ')'
+                               fbmcompile($$[2].arg_ptr.arg_str,0); }
+       |       FUNC3 '(' sexpr csexpr cexpr ')'
+                       { $$ = make_op($1, 3, $3, $4, $5); }
+       |       LFUNC4 '(' sexpr csexpr csexpr cexpr ')'
+                       { arg4 = $6; $$ = make_op($1, 4, l($3), $4, $5); }
+       |       HSHFUN '(' hshword ')'
+                       { $$ = make_op($1, 1,
+                               $3,
+                               Nullarg,
+                               Nullarg); }
+       |       HSHFUN hshword
                        { $$ = make_op($1, 1,
-                               stab2arg(A_STAB,hadd(stabent($3,TRUE))),
+                               $2,
                                Nullarg,
-                               Nullarg, 0); }
+                               Nullarg); }
+       |       HSHFUN3 '(' hshword csexpr cexpr ')'
+                       { $$ = make_op($1, 3, $3, $4, $5); }
        |       listop
        ;
 
 listop :       LISTOP
                        { $$ = make_op($1,2,
-                               stab2arg(A_STAB,defstab),
                                stab2arg(A_WORD,Nullstab),
-                               Nullarg,0); }
+                               stab2arg(A_STAB,defstab),
+                               Nullarg); }
        |       LISTOP expr
-                       { $$ = make_op($1,2,make_list($2),
+                       { $$ = make_op($1,2,
                                stab2arg(A_WORD,Nullstab),
-                               Nullarg,1); }
+                               maybelistish($1,make_list($2)),
+                               Nullarg); }
        |       LISTOP WORD
                        { $$ = make_op($1,2,
-                               stab2arg(A_STAB,defstab),
                                stab2arg(A_WORD,stabent($2,TRUE)),
-                               Nullarg,1); }
+                               stab2arg(A_STAB,defstab),
+                               Nullarg); }
        |       LISTOP WORD expr
-                       { $$ = make_op($1,2,make_list($3),
+                       { $$ = make_op($1,2,
                                stab2arg(A_WORD,stabent($2,TRUE)),
-                               Nullarg,1); }
+                               maybelistish($1,make_list($3)),
+                               Nullarg); Safefree($2); }
        |       LISTOP REG expr
-                       { $$ = make_op($1,2,make_list($3),
+                       { $$ = make_op($1,2,
                                stab2arg(A_STAB,$2),
-                               Nullarg,1); }
+                               maybelistish($1,make_list($3)),
+                               Nullarg); }
+       ;
+
+handle :       WORD
+                       { $$ = stab2arg(A_WORD,stabent($1,TRUE)); Safefree($1);}
+       |       sexpr
+       ;
+
+aryword        :       WORD
+                       { $$ = stab2arg(A_WORD,aadd(stabent($1,TRUE)));
+                           Safefree($1); }
+       |       ARY
+                       { $$ = stab2arg(A_STAB,$1); }
+       ;
+
+hshword        :       WORD
+                       { $$ = stab2arg(A_WORD,hadd(stabent($1,TRUE)));
+                           Safefree($1); }
+       |       HSH
+                       { $$ = stab2arg(A_STAB,$1); }
        ;
 
 %% /* PROGRAM */