perl 4.0 patch 22: patch #20, continued
[p5sagit/p5-mst-13.2.git] / consarg.c
index 4252ad5..fe4542b 100644 (file)
--- a/consarg.c
+++ b/consarg.c
@@ -1,25 +1,33 @@
-/* $Header: consarg.c,v 3.0.1.3 90/02/28 16:47:54 lwall Locked $
+/* $RCSfile: consarg.c,v $$Revision: 4.0.1.4 $$Date: 92/06/08 12:26:27 $
  *
- *    Copyright (c) 1989, Larry Wall
+ *    Copyright (c) 1991, 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.
+ *    You may distribute under the terms of either the GNU General Public
+ *    License or the Artistic License, as specified in the README file.
  *
  * $Log:       consarg.c,v $
- * Revision 3.0.1.3  90/02/28  16:47:54  lwall
- * patch9: the x operator is now up to 10 times faster
- * patch9: @_ clobbered by ($foo,$bar) = split
+ * Revision 4.0.1.4  92/06/08  12:26:27  lwall
+ * patch20: new warning for use of x with non-numeric right operand
+ * patch20: modulus with highest bit in left operand set didn't always work
+ * patch20: illegal lvalue message could be followed by core dump
+ * patch20: deleted some minor memory leaks
  * 
- * Revision 3.0.1.2  89/11/17  15:11:34  lwall
- * patch5: defined $foo{'bar'} should not create element
+ * Revision 4.0.1.3  91/11/05  16:21:16  lwall
+ * patch11: random cleanup
+ * patch11: added eval {}
+ * patch11: added sort {} LIST
+ * patch11: "foo" x -1 dumped core
+ * patch11: substr() and vec() weren't allowed in an lvalue list
  * 
- * Revision 3.0.1.1  89/11/11  04:14:30  lwall
- * patch2: '-' x 26 made warnings about undefined value
- * patch2: eval with no args caused strangeness
- * patch2: local(@foo) didn't work, but local(@foo,$bar) did
+ * Revision 4.0.1.2  91/06/07  10:33:12  lwall
+ * patch4: new copyright notice
+ * patch4: length($`), length($&), length($') now optimized to avoid string copy
  * 
- * Revision 3.0  89/10/18  15:10:30  lwall
- * 3.0 baseline
+ * Revision 4.0.1.1  91/04/11  17:38:34  lwall
+ * patch1: fixed "Bad free" error
+ * 
+ * Revision 4.0  91/03/20  01:06:15  lwall
+ * 4.0 baseline.
  * 
  */
 
@@ -54,12 +62,18 @@ ARG *limarg;
            arg_free(limarg);
        }
        else {
+           arg[3].arg_flags = 0;
+           arg[3].arg_len = 0;
            arg[3].arg_type = A_EXPR;
            arg[3].arg_ptr.arg_arg = limarg;
        }
     }
-    else
+    else {
+       arg[3].arg_flags = 0;
+       arg[3].arg_len = 0;
        arg[3].arg_type = A_NULL;
+       arg[3].arg_ptr.arg_arg = Nullarg;
+    }
     arg->arg_type = O_SPLIT;
     spat = arg[2].arg_ptr.arg_spat;
     spat->spat_repl = stab2arg(A_STAB,aadd(stab));
@@ -82,6 +96,9 @@ register ARG *pat;
     register SPAT *spat;
     register ARG *newarg;
 
+    if (!pat)
+       return Nullarg;
+
     if ((pat->arg_type == O_MATCH ||
         pat->arg_type == O_SUBST ||
         pat->arg_type == O_TRANS ||
@@ -113,14 +130,16 @@ register ARG *pat;
        if (pat->arg_len >= 2) {
            newarg[2].arg_type = pat[2].arg_type;
            newarg[2].arg_ptr = pat[2].arg_ptr;
+           newarg[2].arg_len = pat[2].arg_len;
            newarg[2].arg_flags = pat[2].arg_flags;
            if (pat->arg_len >= 3) {
                newarg[3].arg_type = pat[3].arg_type;
                newarg[3].arg_ptr = pat[3].arg_ptr;
+               newarg[3].arg_len = pat[3].arg_len;
                newarg[3].arg_flags = pat[3].arg_flags;
            }
        }
-       Safefree(pat);
+       free_arg(pat);
     }
     else {
        Newz(202,spat,1,SPAT);
@@ -146,17 +165,18 @@ ARG *arg3;
 {
     register ARG *arg;
     register ARG *chld;
-    register int doarg;
+    register unsigned doarg;
+    register int i;
     extern ARG *arg4;  /* should be normal arguments, really */
     extern ARG *arg5;
 
     arg = op_new(newlen);
     arg->arg_type = type;
-    doarg = opargs[type];
+    /*SUPPRESS 560*/
     if (chld = arg1) {
        if (chld->arg_type == O_ITEM &&
-           (hoistable[chld[1].arg_type] || chld[1].arg_type == A_LVAL ||
-            (chld[1].arg_type == A_LEXPR &&
+           (hoistable[ i = (chld[1].arg_type&A_MASK)] || i == A_LVAL ||
+            (i == A_LEXPR &&
              (chld[1].arg_ptr.arg_arg->arg_type == O_LIST ||
               chld[1].arg_ptr.arg_arg->arg_type == O_ARRAY ||
               chld[1].arg_ptr.arg_arg->arg_type == O_HASH ))))
@@ -171,15 +191,11 @@ ARG *arg3;
            arg[1].arg_type = A_EXPR;
            arg[1].arg_ptr.arg_arg = chld;
        }
-       if (!(doarg & 1))
-           arg[1].arg_type |= A_DONT;
-       if (doarg & 2)
-           arg[1].arg_flags |= AF_ARYOK;
     }
-    doarg >>= 2;
+    /*SUPPRESS 560*/
     if (chld = arg2) {
        if (chld->arg_type == O_ITEM && 
-           (hoistable[chld[1].arg_type] || 
+           (hoistable[chld[1].arg_type&A_MASK] || 
             (type == O_ASSIGN && 
              ((chld[1].arg_type == A_READ && !(arg[1].arg_type & A_DONT))
                ||
@@ -196,14 +212,10 @@ ARG *arg3;
            arg[2].arg_type = A_EXPR;
            arg[2].arg_ptr.arg_arg = chld;
        }
-       if (!(doarg & 1))
-           arg[2].arg_type |= A_DONT;
-       if (doarg & 2)
-           arg[2].arg_flags |= AF_ARYOK;
     }
-    doarg >>= 2;
+    /*SUPPRESS 560*/
     if (chld = arg3) {
-       if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type]) {
+       if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type&A_MASK]) {
            arg[3].arg_type = chld[1].arg_type;
            arg[3].arg_ptr = chld[1].arg_ptr;
            arg[3].arg_len = chld[1].arg_len;
@@ -213,13 +225,9 @@ ARG *arg3;
            arg[3].arg_type = A_EXPR;
            arg[3].arg_ptr.arg_arg = chld;
        }
-       if (!(doarg & 1))
-           arg[3].arg_type |= A_DONT;
-       if (doarg & 2)
-           arg[3].arg_flags |= AF_ARYOK;
     }
     if (newlen >= 4 && (chld = arg4)) {
-       if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type]) {
+       if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type&A_MASK]) {
            arg[4].arg_type = chld[1].arg_type;
            arg[4].arg_ptr = chld[1].arg_ptr;
            arg[4].arg_len = chld[1].arg_len;
@@ -231,7 +239,7 @@ ARG *arg3;
        }
     }
     if (newlen >= 5 && (chld = arg5)) {
-       if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type]) {
+       if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type&A_MASK]) {
            arg[5].arg_type = chld[1].arg_type;
            arg[5].arg_ptr = chld[1].arg_ptr;
            arg[5].arg_len = chld[1].arg_len;
@@ -242,6 +250,14 @@ ARG *arg3;
            arg[5].arg_ptr.arg_arg = chld;
        }
     }
+    doarg = opargs[type];
+    for (i = 1; i <= newlen; ++i) {
+       if (!(doarg & 1))
+           arg[i].arg_type |= A_DONT;
+       if (doarg & 2)
+           arg[i].arg_flags |= AF_ARYOK;
+       doarg >>= 2;
+    }
 #ifdef DEBUGGING
     if (debug & 16) {
        fprintf(stderr,"%lx <= make_op(%s",arg,opname[arg->arg_type]);
@@ -263,15 +279,15 @@ ARG *arg3;
        fprintf(stderr,")\n");
     }
 #endif
-    evalstatic(arg);           /* see if we can consolidate anything */
+    arg = evalstatic(arg);     /* see if we can consolidate anything */
     return arg;
 }
 
-void
+ARG *
 evalstatic(arg)
 register ARG *arg;
 {
-    register STR *str;
+    static STR *str = Nullstr;
     register STR *s1;
     register STR *s2;
     double value;              /* must not be register */
@@ -284,262 +300,371 @@ register ARG *arg;
     double sin(), cos(), atan2(), pow();
 
     if (!arg || !arg->arg_len)
-       return;
+       return arg;
 
-    if ((arg[1].arg_type == A_SINGLE || arg->arg_type == O_AELEM) &&
-        (arg->arg_len == 1 || arg[2].arg_type == A_SINGLE) ) {
+    if (!str)
        str = Str_new(20,0);
+
+    if (arg[1].arg_type == A_SINGLE)
        s1 = arg[1].arg_ptr.arg_str;
-       if (arg->arg_len > 1)
-           s2 = arg[2].arg_ptr.arg_str;
-       else
-           s2 = Nullstr;
-       switch (arg->arg_type) {
-       case O_AELEM:
-           i = (int)str_gnum(s2);
-           if (i < 32767 && i >= 0) {
-               arg->arg_type = O_ITEM;
-               arg->arg_len = 1;
-               arg[1].arg_type = A_ARYSTAB;    /* $abc[123] is hoistable now */
-               arg[1].arg_len = i;
-               arg[1].arg_ptr = arg[1].arg_ptr;        /* get stab pointer */
-               str_free(s2);
-           }
-           /* FALL THROUGH */
-       default:
-           str_free(str);
-           str = Nullstr;              /* can't be evaluated yet */
-           break;
-       case O_CONCAT:
-           str_sset(str,s1);
-           str_scat(str,s2);
-           break;
-       case O_REPEAT:
-           i = (int)str_gnum(s2);
-           tmps = str_get(s1);
-           str_nset(str,"",0);
+    else
+       s1 = Nullstr;
+    if (arg->arg_len >= 2 && arg[2].arg_type == A_SINGLE)
+       s2 = arg[2].arg_ptr.arg_str;
+    else
+       s2 = Nullstr;
+
+#define CHECK1 if (!s1) return arg
+#define CHECK2 if (!s2) return arg
+#define CHECK12 if (!s1 || !s2) return arg
+
+    switch (arg->arg_type) {
+    default:
+       return arg;
+    case O_SORT:
+       if (arg[1].arg_type == A_CMD)
+           arg[1].arg_type |= A_DONT;
+       return arg;
+    case O_EVAL:
+       if (arg[1].arg_type == A_CMD) {
+           arg->arg_type = O_TRY;
+           arg[1].arg_type |= A_DONT;
+           return arg;
+       }
+       CHECK1;
+       arg->arg_type = O_EVALONCE;
+       return arg;
+    case O_AELEM:
+       CHECK2;
+       i = (int)str_gnum(s2);
+       if (i < 32767 && i >= 0) {
+           arg->arg_type = O_ITEM;
+           arg->arg_len = 1;
+           arg[1].arg_type = A_ARYSTAB;        /* $abc[123] is hoistable now */
+           arg[1].arg_len = i;
+           str_free(s2);
+           Renew(arg, 2, ARG);
+       }
+       return arg;
+    case O_CONCAT:
+       CHECK12;
+       str_sset(str,s1);
+       str_scat(str,s2);
+       break;
+    case O_REPEAT:
+       CHECK2;
+       if (dowarn && !s2->str_nok && !looks_like_number(s2))
+           warn("Right operand of x is not numeric");
+       CHECK1;
+       i = (int)str_gnum(s2);
+       tmps = str_get(s1);
+       str_nset(str,"",0);
+       if (i > 0) {
            STR_GROW(str, i * s1->str_cur + 1);
            repeatcpy(str->str_ptr, tmps, s1->str_cur, i);
            str->str_cur = i * s1->str_cur;
            str->str_ptr[str->str_cur] = '\0';
-           break;
-       case O_MULTIPLY:
-           value = str_gnum(s1);
-           str_numset(str,value * str_gnum(s2));
-           break;
-       case O_DIVIDE:
-           value = str_gnum(s2);
-           if (value == 0.0)
-               yyerror("Illegal division by constant zero");
-           else
-               str_numset(str,str_gnum(s1) / value);
-           break;
-       case O_MODULO:
-           tmplong = (long)str_gnum(s2);
-           if (tmplong == 0L) {
-               yyerror("Illegal modulus of constant zero");
-               break;
+       }
+       break;
+    case O_MULTIPLY:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,value * str_gnum(s2));
+       break;
+    case O_DIVIDE:
+       CHECK12;
+       value = str_gnum(s2);
+       if (value == 0.0)
+           yyerror("Illegal division by constant zero");
+       else
+#ifdef SLOPPYDIVIDE
+       /* insure that 20./5. == 4. */
+       {
+           double x;
+           int    k;
+           x =  str_gnum(s1);
+           if ((double)(int)x     == x &&
+               (double)(int)value == value &&
+               (k = (int)x/(int)value)*(int)value == (int)x) {
+               value = k;
+           } else {
+               value = x/value;
            }
-           tmp2 = (long)str_gnum(s1);
+           str_numset(str,value);
+       }
+#else
+       str_numset(str,str_gnum(s1) / value);
+#endif
+       break;
+    case O_MODULO:
+       CHECK12;
+       tmplong = (unsigned long)str_gnum(s2);
+       if (tmplong == 0L) {
+           yyerror("Illegal modulus of constant zero");
+           return arg;
+       }
+       value = str_gnum(s1);
 #ifndef lint
-           if (tmp2 >= 0)
-               str_numset(str,(double)(tmp2 % tmplong));
-           else
-               str_numset(str,(double)(tmplong - (-tmp2 % tmplong)));
+       if (value >= 0.0)
+           str_numset(str,(double)(((unsigned long)value) % tmplong));
+       else {
+           tmp2 = (long)value;
+           str_numset(str,(double)((tmplong-((-tmp2 - 1) % tmplong)) - 1));
+       }
 #else
-           tmp2 = tmp2;
+       tmp2 = tmp2;
 #endif
-           break;
-       case O_ADD:
-           value = str_gnum(s1);
-           str_numset(str,value + str_gnum(s2));
-           break;
-       case O_SUBTRACT:
-           value = str_gnum(s1);
-           str_numset(str,value - str_gnum(s2));
-           break;
-       case O_LEFT_SHIFT:
-           value = str_gnum(s1);
-           i = (int)str_gnum(s2);
+       break;
+    case O_ADD:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,value + str_gnum(s2));
+       break;
+    case O_SUBTRACT:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,value - str_gnum(s2));
+       break;
+    case O_LEFT_SHIFT:
+       CHECK12;
+       value = str_gnum(s1);
+       i = (int)str_gnum(s2);
 #ifndef lint
-           str_numset(str,(double)(((long)value) << i));
+       str_numset(str,(double)(((long)value) << i));
 #endif
-           break;
-       case O_RIGHT_SHIFT:
-           value = str_gnum(s1);
-           i = (int)str_gnum(s2);
+       break;
+    case O_RIGHT_SHIFT:
+       CHECK12;
+       value = str_gnum(s1);
+       i = (int)str_gnum(s2);
 #ifndef lint
-           str_numset(str,(double)(((long)value) >> i));
+       str_numset(str,(double)(((long)value) >> i));
 #endif
-           break;
-       case O_LT:
-           value = str_gnum(s1);
-           str_numset(str,(value < str_gnum(s2)) ? 1.0 : 0.0);
-           break;
-       case O_GT:
-           value = str_gnum(s1);
-           str_numset(str,(value > str_gnum(s2)) ? 1.0 : 0.0);
-           break;
-       case O_LE:
-           value = str_gnum(s1);
-           str_numset(str,(value <= str_gnum(s2)) ? 1.0 : 0.0);
-           break;
-       case O_GE:
-           value = str_gnum(s1);
-           str_numset(str,(value >= str_gnum(s2)) ? 1.0 : 0.0);
-           break;
-       case O_EQ:
-           if (dowarn) {
-               if ((!s1->str_nok && !looks_like_number(s1)) ||
-                   (!s2->str_nok && !looks_like_number(s2)) )
-                   warn("Possible use of == on string value");
-           }
-           value = str_gnum(s1);
-           str_numset(str,(value == str_gnum(s2)) ? 1.0 : 0.0);
-           break;
-       case O_NE:
-           value = str_gnum(s1);
-           str_numset(str,(value != str_gnum(s2)) ? 1.0 : 0.0);
-           break;
-       case O_BIT_AND:
-           value = str_gnum(s1);
+       break;
+    case O_LT:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,(value < str_gnum(s2)) ? 1.0 : 0.0);
+       break;
+    case O_GT:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,(value > str_gnum(s2)) ? 1.0 : 0.0);
+       break;
+    case O_LE:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,(value <= str_gnum(s2)) ? 1.0 : 0.0);
+       break;
+    case O_GE:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,(value >= str_gnum(s2)) ? 1.0 : 0.0);
+       break;
+    case O_EQ:
+       CHECK12;
+       if (dowarn) {
+           if ((!s1->str_nok && !looks_like_number(s1)) ||
+               (!s2->str_nok && !looks_like_number(s2)) )
+               warn("Possible use of == on string value");
+       }
+       value = str_gnum(s1);
+       str_numset(str,(value == str_gnum(s2)) ? 1.0 : 0.0);
+       break;
+    case O_NE:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,(value != str_gnum(s2)) ? 1.0 : 0.0);
+       break;
+    case O_NCMP:
+       CHECK12;
+       value = str_gnum(s1);
+       value -= str_gnum(s2);
+       if (value > 0.0)
+           value = 1.0;
+       else if (value < 0.0)
+           value = -1.0;
+       str_numset(str,value);
+       break;
+    case O_BIT_AND:
+       CHECK12;
+       value = str_gnum(s1);
 #ifndef lint
-           str_numset(str,(double)(((long)value) & ((long)str_gnum(s2))));
+       str_numset(str,(double)(U_L(value) & U_L(str_gnum(s2))));
 #endif
-           break;
-       case O_XOR:
-           value = str_gnum(s1);
+       break;
+    case O_XOR:
+       CHECK12;
+       value = str_gnum(s1);
 #ifndef lint
-           str_numset(str,(double)(((long)value) ^ ((long)str_gnum(s2))));
+       str_numset(str,(double)(U_L(value) ^ U_L(str_gnum(s2))));
 #endif
-           break;
-       case O_BIT_OR:
-           value = str_gnum(s1);
+       break;
+    case O_BIT_OR:
+       CHECK12;
+       value = str_gnum(s1);
 #ifndef lint
-           str_numset(str,(double)(((long)value) | ((long)str_gnum(s2))));
+       str_numset(str,(double)(U_L(value) | U_L(str_gnum(s2))));
 #endif
-           break;
-       case O_AND:
-           if (str_true(s1))
-               str_sset(str,s2);
-           else
-               str_sset(str,s1);
-           break;
-       case O_OR:
-           if (str_true(s1))
-               str_sset(str,s1);
-           else
-               str_sset(str,s2);
-           break;
-       case O_COND_EXPR:
-           if ((arg[3].arg_type & A_MASK) != A_SINGLE) {
-               str_free(str);
-               str = Nullstr;
-           }
-           else {
-               if (str_true(s1))
-                   str_sset(str,s2);
-               else
-                   str_sset(str,arg[3].arg_ptr.arg_str);
-               str_free(arg[3].arg_ptr.arg_str);
-           }
-           break;
-       case O_NEGATE:
-           str_numset(str,(double)(-str_gnum(s1)));
-           break;
-       case O_NOT:
-           str_numset(str,(double)(!str_true(s1)));
-           break;
-       case O_COMPLEMENT:
+       break;
+    case O_AND:
+       CHECK12;
+       if (str_true(s1))
+           str_sset(str,s2);
+       else
+           str_sset(str,s1);
+       break;
+    case O_OR:
+       CHECK12;
+       if (str_true(s1))
+           str_sset(str,s1);
+       else
+           str_sset(str,s2);
+       break;
+    case O_COND_EXPR:
+       CHECK12;
+       if ((arg[3].arg_type & A_MASK) != A_SINGLE)
+           return arg;
+       if (str_true(s1))
+           str_sset(str,s2);
+       else
+           str_sset(str,arg[3].arg_ptr.arg_str);
+       str_free(arg[3].arg_ptr.arg_str);
+       Renew(arg, 3, ARG);
+       break;
+    case O_NEGATE:
+       CHECK1;
+       str_numset(str,(double)(-str_gnum(s1)));
+       break;
+    case O_NOT:
+       CHECK1;
+#ifdef NOTNOT
+       { char xxx = str_true(s1); str_numset(str,(double)!xxx); }
+#else
+       str_numset(str,(double)(!str_true(s1)));
+#endif
+       break;
+    case O_COMPLEMENT:
+       CHECK1;
 #ifndef lint
-           str_numset(str,(double)(~(long)str_gnum(s1)));
+       str_numset(str,(double)(~U_L(str_gnum(s1))));
 #endif
-           break;
-       case O_SIN:
-           str_numset(str,sin(str_gnum(s1)));
-           break;
-       case O_COS:
-           str_numset(str,cos(str_gnum(s1)));
-           break;
-       case O_ATAN2:
-           value = str_gnum(s1);
-           str_numset(str,atan2(value, str_gnum(s2)));
-           break;
-       case O_POW:
-           value = str_gnum(s1);
-           str_numset(str,pow(value, str_gnum(s2)));
-           break;
-       case O_LENGTH:
-           str_numset(str, (double)str_len(s1));
-           break;
-       case O_SLT:
-           str_numset(str,(double)(str_cmp(s1,s2) < 0));
-           break;
-       case O_SGT:
-           str_numset(str,(double)(str_cmp(s1,s2) > 0));
-           break;
-       case O_SLE:
-           str_numset(str,(double)(str_cmp(s1,s2) <= 0));
-           break;
-       case O_SGE:
-           str_numset(str,(double)(str_cmp(s1,s2) >= 0));
-           break;
-       case O_SEQ:
-           str_numset(str,(double)(str_eq(s1,s2)));
-           break;
-       case O_SNE:
-           str_numset(str,(double)(!str_eq(s1,s2)));
-           break;
-       case O_CRYPT:
-#ifdef CRYPT
-           tmps = str_get(s1);
-           str_set(str,crypt(tmps,str_get(s2)));
+       break;
+    case O_SIN:
+       CHECK1;
+       str_numset(str,sin(str_gnum(s1)));
+       break;
+    case O_COS:
+       CHECK1;
+       str_numset(str,cos(str_gnum(s1)));
+       break;
+    case O_ATAN2:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,atan2(value, str_gnum(s2)));
+       break;
+    case O_POW:
+       CHECK12;
+       value = str_gnum(s1);
+       str_numset(str,pow(value, str_gnum(s2)));
+       break;
+    case O_LENGTH:
+       if (arg[1].arg_type == A_STAB) {
+           arg->arg_type = O_ITEM;
+           arg[1].arg_type = A_LENSTAB;
+           return arg;
+       }
+       CHECK1;
+       str_numset(str, (double)str_len(s1));
+       break;
+    case O_SLT:
+       CHECK12;
+       str_numset(str,(double)(str_cmp(s1,s2) < 0));
+       break;
+    case O_SGT:
+       CHECK12;
+       str_numset(str,(double)(str_cmp(s1,s2) > 0));
+       break;
+    case O_SLE:
+       CHECK12;
+       str_numset(str,(double)(str_cmp(s1,s2) <= 0));
+       break;
+    case O_SGE:
+       CHECK12;
+       str_numset(str,(double)(str_cmp(s1,s2) >= 0));
+       break;
+    case O_SEQ:
+       CHECK12;
+       str_numset(str,(double)(str_eq(s1,s2)));
+       break;
+    case O_SNE:
+       CHECK12;
+       str_numset(str,(double)(!str_eq(s1,s2)));
+       break;
+    case O_SCMP:
+       CHECK12;
+       str_numset(str,(double)(str_cmp(s1,s2)));
+       break;
+    case O_CRYPT:
+       CHECK12;
+#ifdef HAS_CRYPT
+       tmps = str_get(s1);
+       str_set(str,crypt(tmps,str_get(s2)));
 #else
-           yyerror(
-           "The crypt() function is unimplemented due to excessive paranoia.");
+       yyerror(
+       "The crypt() function is unimplemented due to excessive paranoia.");
 #endif
-           break;
-       case O_EXP:
-           str_numset(str,exp(str_gnum(s1)));
-           break;
-       case O_LOG:
-           str_numset(str,log(str_gnum(s1)));
-           break;
-       case O_SQRT:
-           str_numset(str,sqrt(str_gnum(s1)));
-           break;
-       case O_INT:
-           value = str_gnum(s1);
-           if (value >= 0.0)
-               (void)modf(value,&value);
-           else {
-               (void)modf(-value,&value);
-               value = -value;
-           }
-           str_numset(str,value);
-           break;
-       case O_ORD:
+       break;
+    case O_EXP:
+       CHECK1;
+       str_numset(str,exp(str_gnum(s1)));
+       break;
+    case O_LOG:
+       CHECK1;
+       str_numset(str,log(str_gnum(s1)));
+       break;
+    case O_SQRT:
+       CHECK1;
+       str_numset(str,sqrt(str_gnum(s1)));
+       break;
+    case O_INT:
+       CHECK1;
+       value = str_gnum(s1);
+       if (value >= 0.0)
+           (void)modf(value,&value);
+       else {
+           (void)modf(-value,&value);
+           value = -value;
+       }
+       str_numset(str,value);
+       break;
+    case O_ORD:
+       CHECK1;
 #ifndef I286
-           str_numset(str,(double)(*str_get(s1)));
+       str_numset(str,(double)(*str_get(s1)));
 #else
-           {
-               int  zapc;
-               char *zaps;
+       {
+           int  zapc;
+           char *zaps;
 
-               zaps = str_get(s1);
-               zapc = (int) *zaps;
-               str_numset(str,(double)(zapc));
-           }
-#endif
-           break;
-       }
-       if (str) {
-           arg->arg_type = O_ITEM;     /* note arg1 type is already SINGLE */
-           str_free(s1);
-           str_free(s2);
-           arg[1].arg_ptr.arg_str = str;
+           zaps = str_get(s1);
+           zapc = (int) *zaps;
+           str_numset(str,(double)(zapc));
        }
+#endif
+       break;
+    }
+    arg->arg_type = O_ITEM;    /* note arg1 type is already SINGLE */
+    str_free(s1);
+    arg[1].arg_ptr.arg_str = str;
+    if (s2) {
+       str_free(s2);
+       arg[2].arg_ptr.arg_str = Nullstr;
+       arg[2].arg_type = A_NULL;
     }
+    str = Nullstr;
+
+    return arg;
 }
 
 ARG *
@@ -624,6 +749,12 @@ register ARG *arg;
                    case O_HSLICE: case O_LHSLICE:
                        arg1[i].arg_ptr.arg_arg->arg_type = O_LHSLICE;
                        break;
+                   case O_SUBSTR: case O_VEC:
+                       (void)l(arg1[i].arg_ptr.arg_arg);
+                       Renewc(arg1[i].arg_ptr.arg_arg->arg_ptr.arg_str, 1,
+                         struct lstring, STR);
+                           /* grow string struct to hold an lstring struct */
+                       break;
                    default:
                        goto ill_item;
                    }
@@ -659,8 +790,10 @@ register ARG *arg;
                      nothing_in_common(arg1,spat->spat_repl)) {
                        spat->spat_repl[1].arg_ptr.arg_stab =
                            arg1[1].arg_ptr.arg_stab;
+                       arg1[1].arg_ptr.arg_stab = Nullstab;
                        spat->spat_flags |= SPAT_ONCE;
                        arg_free(arg1); /* recursive */
+                       arg[1].arg_ptr.arg_arg = Nullarg;
                        free_arg(arg);  /* non-recursive */
                        return arg2;    /* split has builtin assign */
                    }
@@ -698,6 +831,7 @@ register ARG *arg;
        else if (arg1->arg_type == O_ASLICE) {
            arg1->arg_type = O_LASLICE;
            if (arg->arg_type == O_ASSIGN) {
+               dehoist(arg,2);
                arg[1].arg_flags |= AF_ARYOK;
                arg[2].arg_flags |= AF_ARYOK;
            }
@@ -705,6 +839,7 @@ register ARG *arg;
        else if (arg1->arg_type == O_HSLICE) {
            arg1->arg_type = O_LHSLICE;
            if (arg->arg_type == O_ASSIGN) {
+               dehoist(arg,2);
                arg[1].arg_flags |= AF_ARYOK;
                arg[2].arg_flags |= AF_ARYOK;
            }
@@ -718,14 +853,14 @@ register ARG *arg;
            Renewc(arg1->arg_ptr.arg_str, 1, struct lstring, STR);
                        /* grow string struct to hold an lstring struct */
        }
-       else if (arg1->arg_type == O_ASSIGN) {
-           if (arg->arg_type == O_CHOP)
-               arg[1].arg_flags &= ~AF_ARYOK;  /* grandfather chop idiom */
-       }
+       else if (arg1->arg_type == O_ASSIGN)
+           /*SUPPRESS 530*/
+           ;
        else {
            (void)sprintf(tokenbuf,
              "Illegal expression (%s) as lvalue",opname[arg1->arg_type]);
            yyerror(tokenbuf);
+           return arg;
        }
        arg[1].arg_type = A_LEXPR | (arg[1].arg_type & A_DONT);
        if (arg->arg_type == O_ASSIGN && (arg1[1].arg_flags & AF_ARYOK)) {
@@ -750,6 +885,7 @@ register ARG *arg;
        (void)sprintf(tokenbuf,
          "Illegal item (%s) as lvalue",argname[arg[1].arg_type&A_MASK]);
        yyerror(tokenbuf);
+       return arg;
     }
     arg[1].arg_type = A_LVAL | (arg[1].arg_type & A_DONT);
 #ifdef DEBUGGING
@@ -776,6 +912,7 @@ ARG *arg;
     return arg;
 }
 
+void
 dehoist(arg,i)
 ARG *arg;
 {
@@ -839,6 +976,7 @@ register ARG *arg;
     if (arg->arg_type != O_COMMA) {
        if (arg->arg_type != O_ARRAY)
            arg->arg_flags |= AF_LISTISH;       /* see listish() below */
+           arg->arg_flags |= AF_LISTISH;       /* see listish() below */
        return arg;
     }
     for (i = 2, node = arg; ; i++) {
@@ -854,26 +992,14 @@ register ARG *arg;
        node = arg;
        arg = op_new(i);
        tmpstr = arg->arg_ptr.arg_str;
-#ifdef STRUCTCOPY
-       *arg = *node;           /* copy everything except the STR */
-#else
-       (void)bcopy((char *)node, (char *)arg, sizeof(ARG));
-#endif
+       StructCopy(node, arg, ARG);     /* copy everything except the STR */
        arg->arg_ptr.arg_str = tmpstr;
        for (j = i; ; ) {
-#ifdef STRUCTCOPY
-           arg[j] = node[2];
-#else
-           (void)bcopy((char *)(node+2), (char *)(arg+j), sizeof(ARG));
-#endif
+           StructCopy(node+2, arg+j, ARG);
            arg[j].arg_flags |= AF_ARYOK;
            --j;                /* Bug in Xenix compiler */
            if (j < 2) {
-#ifdef STRUCTCOPY
-               arg[1] = node[1];
-#else
-               (void)bcopy((char *)(node+1), (char *)(arg+1), sizeof(ARG));
-#endif
+               StructCopy(node+1, arg+1, ARG);
                free_arg(node);
                break;
            }
@@ -886,6 +1012,8 @@ register ARG *arg;
     arg[2].arg_flags |= AF_ARYOK;
     arg->arg_type = O_LIST;
     arg->arg_len = i;
+    str_free(arg->arg_ptr.arg_str);
+    arg->arg_ptr.arg_str = Nullstr;
     return arg;
 }
 
@@ -895,7 +1023,7 @@ ARG *
 listish(arg)
 ARG *arg;
 {
-    if (arg->arg_flags & AF_LISTISH)
+    if (arg && arg->arg_flags & AF_LISTISH)
        arg = make_op(O_LIST,1,arg,Nullarg,Nullarg);
     return arg;
 }
@@ -905,7 +1033,16 @@ maybelistish(optype, arg)
 int optype;
 ARG *arg;
 {
-    if (optype == O_PRTF ||
+    ARG *tmparg = arg;
+
+    if (optype == O_RETURN && arg->arg_type == O_ITEM &&
+      arg[1].arg_type == A_EXPR && (tmparg = arg[1].arg_ptr.arg_arg) &&
+      ((tmparg->arg_flags & AF_LISTISH) || (tmparg->arg_type == O_ARRAY) )) {
+       tmparg = listish(tmparg);
+       free_arg(arg);
+       arg = tmparg;
+    }
+    else if (optype == O_PRTF ||
       (arg->arg_type == O_ASLICE || arg->arg_type == O_HSLICE ||
        arg->arg_type == O_F_OR_R) )
        arg = listish(arg);
@@ -923,27 +1060,19 @@ ARG *arg;
 }
 
 ARG *
-fixeval(arg)
-ARG *arg;
-{
-    Renew(arg, 3, ARG);
-    if (arg->arg_len == 0)
-       arg[1].arg_type = A_NULL;
-    arg->arg_len = 2;
-    arg[2].arg_ptr.arg_hash = curstash;
-    arg[2].arg_type = A_NULL;
-    return arg;
-}
-
-ARG *
 rcatmaybe(arg)
 ARG *arg;
 {
-    if (arg->arg_type == O_CONCAT && arg[2].arg_type == A_READ) {
-       arg->arg_type = O_RCAT; 
-       arg[2].arg_type = arg[2].arg_ptr.arg_arg[1].arg_type;
-       arg[2].arg_ptr = arg[2].arg_ptr.arg_arg[1].arg_ptr;
-       free_arg(arg[2].arg_ptr.arg_arg);
+    ARG *arg2;
+
+    if (arg->arg_type == O_CONCAT && arg[2].arg_type == A_EXPR) {
+       arg2 = arg[2].arg_ptr.arg_arg;
+       if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
+           arg->arg_type = O_RCAT;     
+           arg[2].arg_type = arg2[1].arg_type;
+           arg[2].arg_ptr = arg2[1].arg_ptr;
+           free_arg(arg2);
+       }
     }
     return arg;
 }
@@ -1047,6 +1176,7 @@ ARG *arg2;
     thisexpr++;
     if (arg_common(arg1,thisexpr,1))
        return 0;       /* hit eval or do {} */
+    stab_lastexpr(defstab) = thisexpr;         /* pretend to hit @_ */
     if (arg_common(arg2,thisexpr,0))
        return 0;       /* hit identifier again */
     return 1;
@@ -1097,7 +1227,7 @@ int marking;
 
                while (*s) {
                    if (*s == '$' && s[1]) {
-                       s = scanreg(s,send,tokenbuf);
+                       s = scanident(s,send,tokenbuf);
                        stab = stabent(tokenbuf,TRUE);
                        if (marking)
                            stab_lastexpr(stab) = exprnum;