This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix to installing non-xs ext's in priv lib
[perl5.git] / x2p / a2py.c
index c995040..84fdc48 100644 (file)
@@ -1,41 +1,86 @@
-/* $Header: a2py.c,v 1.0.1.1 88/01/28 11:07:08 root Exp $
+/*    a2py.c
  *
- * $Log:       a2py.c,v $
- * Revision 1.0.1.1  88/01/28  11:07:08  root
- * patch8: added support for FOO=bar switches using eval.
- * 
- * Revision 1.0  87/12/18  17:50:33  root
- * Initial revision
- * 
+ *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ *    2000, 2001, 2002, by Larry Wall and others
+ *
+ *    You may distribute under the terms of either the GNU General Public
+ *    License or the Artistic License, as specified in the README file.
  */
 
+#if defined(OS2) || defined(WIN32) || defined(NETWARE)
+#if defined(WIN32)
+#include <io.h>
+#endif
+#if defined(NETWARE)
+#include "../netware/clibstuf.h"
+#endif
+#include "../patchlevel.h"
+#endif
 #include "util.h"
-char *index();
 
-char *filename;
+const char *filename;
+const char *myname;
+
+int checkers = 0;
+
+int oper0(int type);
+int oper1(int type, int arg1);
+int oper2(int type, int arg1, int arg2);
+int oper3(int type, int arg1, int arg2, int arg3);
+int oper4(int type, int arg1, int arg2, int arg3, int arg4);
+int oper5(int type, int arg1, int arg2, int arg3, int arg4, int arg5);
+STR *walk(int useval, int level, register int node, int *numericptr, int minprec);
+#ifdef NETWARE
+char *savestr(char *str);
+char *cpy2(register char *to, register char *from, register int delim);
+#endif
+
+#if defined(OS2) || defined(WIN32) || defined(NETWARE)
+static void usage(void);
 
-main(argc,argv,env)
-register int argc;
-register char **argv;
-register char **env;
+static void
+usage()
+{
+    printf("\nThis is the AWK to PERL translator, revision %d.0, version %d\n", PERL_REVISION, PERL_VERSION);
+    printf("\nUsage: %s [-D<number>] [-F<char>] [-n<fieldlist>] [-<number>] filename\n", myname);
+    printf("\n  -D<number>      sets debugging flags."
+           "\n  -F<character>   the awk script to translate is always invoked with"
+           "\n                  this -F switch."
+           "\n  -n<fieldlist>   specifies the names of the input fields if input does"
+           "\n                  not have to be split into an array."
+           "\n  -<number>       causes a2p to assume that input will always have that"
+           "\n                  many fields.\n");
+    exit(1);
+}
+#endif
+
+#ifdef __osf__
+#pragma message disable (mainparm) /* We have the envp in main(). */
+#endif
+
+int
+main(register int argc, register const char **argv, register const char **env)
 {
     register STR *str;
-    register char *s;
     int i;
-    STR *walk();
     STR *tmpstr;
+    /* char *namelist;    */
 
+       #ifdef NETWARE
+               fnInitGpfGlobals();     /* For importing the CLIB calls in place of Watcom calls */
+       #endif  /* NETWARE */
+
+    myname = argv[0];
     linestr = str_new(80);
     str = str_new(0);          /* first used for -I flags */
     for (argc--,argv++; argc; argc--,argv++) {
        if (argv[0][0] != '-' || !argv[0][1])
            break;
-      reswitch:
        switch (argv[0][1]) {
 #ifdef DEBUGGING
        case 'D':
            debug = atoi(argv[0]+2);
-#ifdef YYDEBUG
+#if YYDEBUG
            yydebug = (debug & 1);
 #endif
            break;
@@ -51,35 +96,50 @@ register char **env;
        case 'n':
            namelist = savestr(argv[0]+2);
            break;
+       case 'o':
+           old_awk = TRUE;
+           break;
        case '-':
            argc--,argv++;
            goto switch_end;
        case 0:
            break;
        default:
+#if defined(OS2) || defined(WIN32) || defined(NETWARE)
+           fprintf(stderr, "Unrecognized switch: %s\n",argv[0]);
+            usage();
+#else
            fatal("Unrecognized switch: %s\n",argv[0]);
+#endif
        }
     }
   switch_end:
 
     /* open script */
 
-    if (argv[0] == Nullch)
-       argv[0] = "-";
+    if (argv[0] == NULL) {
+#if defined(OS2) || defined(WIN32) || defined(NETWARE)
+       if ( isatty(fileno(stdin)) )
+           usage();
+#endif
+        argv[0] = "-";
+    }
     filename = savestr(argv[0]);
+
     if (strEQ(filename,"-"))
        argv[0] = "";
     if (!*argv[0])
        rsfp = stdin;
     else
        rsfp = fopen(argv[0],"r");
-    if (rsfp == Nullfp)
+    if (rsfp == NULL)
        fatal("Awk script \"%s\" doesn't seem to exist.\n",filename);
 
     /* init tokener */
 
     bufptr = str_get(linestr);
     symtab = hnew();
+    curarghash = hnew();
 
     /* now parse the report spec */
 
@@ -115,10 +175,16 @@ register char **env;
 
     /* second pass to produce new program */
 
-    tmpstr = walk(0,0,root,&i);
-    str = str_make("#!/bin/perl\n\n");
+    tmpstr = walk(0,0,root,&i,P_MIN);
+    str = str_make(STARTPERL);
+    str_cat(str, "\neval 'exec ");
+    str_cat(str, BIN);
+    str_cat(str, "/perl -S $0 ${1+\"$@\"}'\n\
+    if $running_under_some_shell;\n\
+                       # this emulates #! processing on NIH machines.\n\
+                       # (remove #! line above if indigestible)\n\n");
     str_cat(str,
-      "eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;\n");
+      "eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;\n");
     str_cat(str,
       "                        # process any FOO=bar switches\n\n");
     if (do_opens && opens) {
@@ -133,27 +199,40 @@ register char **env;
 #endif
     fixup(str);
     putlines(str);
+    if (checkers) {
+       fprintf(stderr,
+         "Please check my work on the %d line%s I've marked with \"#???\".\n",
+               checkers, checkers == 1 ? "" : "s" );
+       fprintf(stderr,
+         "The operation I've selected may be wrong for the operand types.\n");
+    }
     exit(0);
+    /* by ANSI specs return is needed. This also shuts up VC++ and his warnings */
+    return(0);
 }
 
 #define RETURN(retval) return (bufptr = s,retval)
 #define XTERM(retval) return (expectterm = TRUE,bufptr = s,retval)
 #define XOP(retval) return (expectterm = FALSE,bufptr = s,retval)
-#define ID(x) return (yylval=string(x,0),expectterm = FALSE,bufptr = s,VAR)
+#define ID(x) return (yylval=string(x,0),expectterm = FALSE,bufptr = s,idtype)
 
-yylex()
+int idtype;
+
+int
+yylex(void)
 {
     register char *s = bufptr;
     register char *d;
     register int tmp;
 
   retry:
-#ifdef YYDEBUG
-    if (yydebug)
-       if (index(s,'\n'))
+#if YYDEBUG
+    if (yydebug) {
+       if (strchr(s,'\n'))
            fprintf(stderr,"Tokener at %s",s);
        else
            fprintf(stderr,"Tokener at %s\n",s);
+    }
 #endif
     switch (*s) {
     default:
@@ -162,16 +241,22 @@ yylex()
             *s++,filename,line);
        goto retry;
     case '\\':
+       s++;
+       if (*s && *s != '\n') {
+           yyerror("Ignoring spurious backslash");
+           goto retry;
+       }
+       /*FALLSTHROUGH*/
     case 0:
        s = str_get(linestr);
        *s = '\0';
        if (!rsfp)
            RETURN(0);
        line++;
-       if ((s = str_gets(linestr, rsfp)) == Nullch) {
+       if ((s = str_gets(linestr, rsfp)) == NULL) {
            if (rsfp != stdin)
                fclose(rsfp);
-           rsfp = Nullfp;
+           rsfp = NULL;
            s = str_get(linestr);
            RETURN(0);
        }
@@ -194,17 +279,25 @@ yylex()
        }
        XTERM(tmp);
     case '(':
+       tmp = *s++;
+       XTERM(tmp);
     case '{':
     case '[':
     case ')':
     case ']':
+    case '?':
+    case ':':
        tmp = *s++;
        XOP(tmp);
+#ifdef EBCDIC
+    case 7:
+#else
     case 127:
+#endif
        s++;
        XTERM('}');
     case '}':
-       for (d = s + 1; isspace(*d); d++) ;
+       for (d = s + 1; isSPACE(*d); d++) ;
        if (!*d)
            s = d - 1;
        *s = 127;
@@ -214,6 +307,7 @@ yylex()
        XTERM(tmp);
     case '~':
        s++;
+       yylval = string("~",1);
        XTERM(MATCHOP);
     case '+':
     case '-':
@@ -227,9 +321,13 @@ yylex()
        /* FALL THROUGH */
     case '*':
     case '%':
+    case '^':
        tmp = *s++;
        if (*s == '=') {
-           yylval = string(s-1,2);
+           if (tmp == '^')
+               yylval = string("**=",3);
+           else
+               yylval = string(s-1,2);
            s++;
            XTERM(ASGNOP);
        }
@@ -247,7 +345,12 @@ yylex()
        if (tmp == '|')
            XTERM(OROR);
        s--;
-       XTERM('|');
+       while (*s == ' ' || *s == '\t')
+           s++;
+       if (strnEQ(s,"getline",7))
+           XTERM('p');
+       else
+           XTERM('|');
     case '=':
        s++;
        tmp = *s++;
@@ -279,25 +382,31 @@ yylex()
            XTERM(RELOP);
        }
        s--;
-       yylval = string("<",1);
-       XTERM(RELOP);
+       XTERM('<');
     case '>':
        s++;
        tmp = *s++;
+       if (tmp == '>') {
+           yylval = string(">>",2);
+           XTERM(GRGR);
+       }
        if (tmp == '=') {
            yylval = string(">=",2);
            XTERM(RELOP);
        }
        s--;
-       yylval = string(">",1);
-       XTERM(RELOP);
+       XTERM('>');
 
 #define SNARFWORD \
        d = tokenbuf; \
-       while (isalpha(*s) || isdigit(*s) || *s == '_') \
+       while (isALPHA(*s) || isDIGIT(*s) || *s == '_') \
            *d++ = *s++; \
        *d = '\0'; \
-       d = tokenbuf;
+       d = tokenbuf; \
+       if (*s == '(') \
+           idtype = USERFUN; \
+       else \
+           idtype = VAR;
 
     case '$':
        s++;
@@ -305,18 +414,26 @@ yylex()
            s++;
            do_chop = TRUE;
            need_entire = TRUE;
+           idtype = VAR;
            ID("0");
        }
        do_split = TRUE;
-       if (isdigit(*s)) {
-           for (d = s; isdigit(*s); s++) ;
+       if (isDIGIT(*s)) {
+           for (d = s; isDIGIT(*s); s++) ;
            yylval = string(d,s-d);
            tmp = atoi(d);
            if (tmp > maxfld)
                maxfld = tmp;
            XOP(FIELD);
        }
+       for (d = s; isALPHA(*s) || isDIGIT(*s) || *s == '_'; )
+           s++;
        split_to_array = set_array_base = TRUE;
+       if (d != s)
+       {
+           yylval = string(d,s-d);
+           XTERM(SVFIELD);
+       }
        XOP(VFIELD);
 
     case '/':                  /* may either be division or pattern */
@@ -333,7 +450,7 @@ yylex()
        XTERM(tmp);
 
     case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
+    case '5': case '6': case '7': case '8': case '9': case '.':
        s = scannum(s);
        XOP(NUMBER);
     case '"':
@@ -347,6 +464,16 @@ yylex()
 
     case 'a': case 'A':
        SNARFWORD;
+       if (strEQ(d,"ARGC"))
+           set_array_base = TRUE;
+       if (strEQ(d,"ARGV")) {
+           yylval=numary(string("ARGV",0));
+           XOP(VAR);
+       }
+       if (strEQ(d,"atan2")) {
+           yylval = OATAN2;
+           XTERM(FUNN);
+       }
        ID(d);
     case 'b': case 'B':
        SNARFWORD;
@@ -359,9 +486,34 @@ yylex()
        SNARFWORD;
        if (strEQ(d,"continue"))
            XTERM(CONTINUE);
+       if (strEQ(d,"cos")) {
+           yylval = OCOS;
+           XTERM(FUN1);
+       }
+       if (strEQ(d,"close")) {
+           do_fancy_opens = 1;
+           yylval = OCLOSE;
+           XTERM(FUN1);
+       }
+       if (strEQ(d,"chdir"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"crypt"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"chop"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"chmod"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"chown"))
+           *d = toUPPER(*d);
        ID(d);
     case 'd': case 'D':
        SNARFWORD;
+       if (strEQ(d,"do"))
+           XTERM(DO);
+       if (strEQ(d,"delete"))
+           XTERM(DELETE);
+       if (strEQ(d,"die"))
+           *d = toUPPER(*d);
        ID(d);
     case 'e': case 'E':
        SNARFWORD;
@@ -377,33 +529,67 @@ yylex()
            yylval = OEXP;
            XTERM(FUN1);
        }
+       if (strEQ(d,"elsif"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"eq"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"eval"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"eof"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"each"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"exec"))
+           *d = toUPPER(*d);
        ID(d);
     case 'f': case 'F':
        SNARFWORD;
        if (strEQ(d,"FS")) {
            saw_FS++;
            if (saw_FS == 1 && in_begin) {
-               for (d = s; *d && isspace(*d); d++) ;
+               for (d = s; *d && isSPACE(*d); d++) ;
                if (*d == '=') {
-                   for (d++; *d && isspace(*d); d++) ;
+                   for (d++; *d && isSPACE(*d); d++) ;
                    if (*d == '"' && d[2] == '"')
                        const_FS = d[1];
                }
            }
            ID(tokenbuf);
        }
-       if (strEQ(d,"FILENAME"))
-           d = "ARGV";
        if (strEQ(d,"for"))
            XTERM(FOR);
+       else if (strEQ(d,"function"))
+           XTERM(FUNCTION);
+       if (strEQ(d,"FILENAME"))
+           ID("ARGV");
+       if (strEQ(d,"foreach"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"format"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"fork"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"fh"))
+           *d = toUPPER(*d);
        ID(d);
     case 'g': case 'G':
        SNARFWORD;
        if (strEQ(d,"getline"))
            XTERM(GETLINE);
+       if (strEQ(d,"gsub"))
+           XTERM(GSUB);
+       if (strEQ(d,"ge"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"gt"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"goto"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"gmtime"))
+           *d = toUPPER(*d);
        ID(d);
     case 'h': case 'H':
        SNARFWORD;
+       if (strEQ(d,"hex"))
+           *d = toUPPER(*d);
        ID(d);
     case 'i': case 'I':
        SNARFWORD;
@@ -422,9 +608,15 @@ yylex()
        ID(d);
     case 'j': case 'J':
        SNARFWORD;
+       if (strEQ(d,"join"))
+           *d = toUPPER(*d);
        ID(d);
     case 'k': case 'K':
        SNARFWORD;
+       if (strEQ(d,"keys"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"kill"))
+           *d = toUPPER(*d);
        ID(d);
     case 'l': case 'L':
        SNARFWORD;
@@ -436,32 +628,58 @@ yylex()
            yylval = OLOG;
            XTERM(FUN1);
        }
+       if (strEQ(d,"last"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"local"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"lt"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"le"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"locatime"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"link"))
+           *d = toUPPER(*d);
        ID(d);
     case 'm': case 'M':
        SNARFWORD;
+       if (strEQ(d,"match")) {
+           set_array_base = TRUE;
+           XTERM(MATCH);
+       }
+       if (strEQ(d,"m"))
+           *d = toUPPER(*d);
        ID(d);
     case 'n': case 'N':
        SNARFWORD;
        if (strEQ(d,"NF"))
-           do_split = split_to_array = set_array_base = TRUE;
+           do_chop = do_split = split_to_array = set_array_base = TRUE;
        if (strEQ(d,"next")) {
            saw_line_op = TRUE;
            XTERM(NEXT);
        }
+       if (strEQ(d,"ne"))
+           *d = toUPPER(*d);
        ID(d);
     case 'o': case 'O':
        SNARFWORD;
        if (strEQ(d,"ORS")) {
            saw_ORS = TRUE;
-           d = "$\\";
+           ID("\\");
        }
        if (strEQ(d,"OFS")) {
            saw_OFS = TRUE;
-           d = "$,";
+           ID(",");
        }
        if (strEQ(d,"OFMT")) {
-           d = "$#";
+           ID("#");
        }
+       if (strEQ(d,"open"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"ord"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"oct"))
+           *d = toUPPER(*d);
        ID(d);
     case 'p': case 'P':
        SNARFWORD;
@@ -471,6 +689,10 @@ yylex()
        if (strEQ(d,"printf")) {
            XTERM(PRINTF);
        }
+       if (strEQ(d,"push"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"pop"))
+           *d = toUPPER(*d);
        ID(d);
     case 'q': case 'Q':
        SNARFWORD;
@@ -478,9 +700,21 @@ yylex()
     case 'r': case 'R':
        SNARFWORD;
        if (strEQ(d,"RS")) {
-           d = "$/";
            saw_RS = TRUE;
+           ID("/");
        }
+       if (strEQ(d,"rand")) {
+           yylval = ORAND;
+           XTERM(FUN1);
+       }
+       if (strEQ(d,"return"))
+           XTERM(RET);
+       if (strEQ(d,"reset"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"redo"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"rename"))
+           *d = toUPPER(*d);
        ID(d);
     case 's': case 'S':
        SNARFWORD;
@@ -492,32 +726,104 @@ yylex()
            set_array_base = TRUE;
            XTERM(SUBSTR);
        }
-       if (strEQ(d,"sprintf"))
-           XTERM(SPRINTF);
+       if (strEQ(d,"sub"))
+           XTERM(SUB);
+       if (strEQ(d,"sprintf")) {
+            /* In old awk, { print sprintf("str%sg"),"in" } prints
+             * "string"; in new awk, "in" is not considered an argument to
+             * sprintf, so the statement breaks.  To support both, the
+             * grammar treats arguments to SPRINTF_OLD like old awk,
+             * SPRINTF_NEW like new.  Here we return the appropriate one.
+             */
+           XTERM(old_awk ? SPRINTF_OLD : SPRINTF_NEW);
+        }
        if (strEQ(d,"sqrt")) {
            yylval = OSQRT;
            XTERM(FUN1);
        }
+       if (strEQ(d,"SUBSEP")) {
+           ID(";");
+       }
+       if (strEQ(d,"sin")) {
+           yylval = OSIN;
+           XTERM(FUN1);
+       }
+       if (strEQ(d,"srand")) {
+           yylval = OSRAND;
+           XTERM(FUN1);
+       }
+       if (strEQ(d,"system")) {
+           yylval = OSYSTEM;
+           XTERM(FUN1);
+       }
+       if (strEQ(d,"s"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"shift"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"select"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"seek"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"stat"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"study"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"sleep"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"symlink"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"sort"))
+           *d = toUPPER(*d);
        ID(d);
     case 't': case 'T':
        SNARFWORD;
+       if (strEQ(d,"tr"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"tell"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"time"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"times"))
+           *d = toUPPER(*d);
        ID(d);
     case 'u': case 'U':
        SNARFWORD;
+       if (strEQ(d,"until"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"unless"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"umask"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"unshift"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"unlink"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"utime"))
+           *d = toUPPER(*d);
        ID(d);
     case 'v': case 'V':
        SNARFWORD;
+       if (strEQ(d,"values"))
+           *d = toUPPER(*d);
        ID(d);
     case 'w': case 'W':
        SNARFWORD;
        if (strEQ(d,"while"))
            XTERM(WHILE);
+       if (strEQ(d,"write"))
+           *d = toUPPER(*d);
+       else if (strEQ(d,"wait"))
+           *d = toUPPER(*d);
        ID(d);
     case 'x': case 'X':
        SNARFWORD;
+       if (strEQ(d,"x"))
+           *d = toUPPER(*d);
        ID(d);
     case 'y': case 'Y':
        SNARFWORD;
+       if (strEQ(d,"y"))
+           *d = toUPPER(*d);
        ID(d);
     case 'z': case 'Z':
        SNARFWORD;
@@ -526,8 +832,7 @@ yylex()
 }
 
 char *
-scanpat(s)
-register char *s;
+scanpat(register char *s)
 {
     register char *d;
 
@@ -537,7 +842,33 @@ register char *s;
     default:
        fatal("Search pattern not found:\n%s",str_get(linestr));
     }
-    s = cpytill(tokenbuf,s,s[-1]);
+
+    d = tokenbuf;
+    for (; *s; s++,d++) {
+       if (*s == '\\') {
+           if (s[1] == '/')
+               *d++ = *s++;
+           else if (s[1] == '\\')
+               *d++ = *s++;
+           else if (s[1] == '[')
+               *d++ = *s++;
+       }
+       else if (*s == '[') {
+           *d++ = *s++;
+           do {
+               if (*s == '\\' && s[1])
+                   *d++ = *s++;
+               if (*s == '/' || (*s == '-' && s[1] == ']'))
+                   *d++ = '\\';
+               *d++ = *s++;
+           } while (*s && *s != ']');
+       }
+       else if (*s == '/')
+           break;
+       *d = *s;
+    }
+    *d = '\0';
+
     if (!*s)
        fatal("Search pattern not terminated:\n%s",str_get(linestr));
     s++;
@@ -545,16 +876,15 @@ register char *s;
     return s;
 }
 
-yyerror(s)
-char *s;
+void
+yyerror(const char *s)
 {
     fprintf(stderr,"%s in file %s at line %d\n",
       s,filename,line);
 }
 
 char *
-scannum(s)
-register char *s;
+scannum(register char *s)
 {
     register char *d;
 
@@ -562,18 +892,26 @@ register char *s;
     case '1': case '2': case '3': case '4': case '5':
     case '6': case '7': case '8': case '9': case '0' : case '.':
        d = tokenbuf;
-       while (isdigit(*s) || *s == '_')
-           *d++ = *s++;
-       if (*s == '.' && index("0123456789eE",s[1]))
-           *d++ = *s++;
-       while (isdigit(*s) || *s == '_')
+       while (isDIGIT(*s)) {
            *d++ = *s++;
-       if (index("eE",*s) && index("+-0123456789",s[1]))
-           *d++ = *s++;
-       if (*s == '+' || *s == '-')
-           *d++ = *s++;
-       while (isdigit(*s))
+       }
+       if (*s == '.') {
+           if (isDIGIT(s[1])) {
+               *d++ = *s++;
+               while (isDIGIT(*s)) {
+                   *d++ = *s++;
+               }
+           }
+           else
+               s++;
+       }
+       if (strchr("eE",*s) && strchr("+-0123456789",s[1])) {
            *d++ = *s++;
+           if (*s == '+' || *s == '-')
+               *d++ = *s++;
+           while (isDIGIT(*s))
+               *d++ = *s++;
+       }
        *d = '\0';
        yylval = string(tokenbuf,0);
        break;
@@ -581,34 +919,37 @@ register char *s;
     return s;
 }
 
-string(ptr,len)
-char *ptr;
+int
+string(const char *ptr, int len)
 {
     int retval = mop;
 
     ops[mop++].ival = OSTRING + (1<<8);
     if (!len)
        len = strlen(ptr);
-    ops[mop].cval = safemalloc(len+1);
+    ops[mop].cval = (char *) safemalloc(len+1);
     strncpy(ops[mop].cval,ptr,len);
     ops[mop++].cval[len] = '\0';
+    if (mop >= OPSMAX)
+       fatal("Recompile a2p with larger OPSMAX\n");
     return retval;
 }
 
-oper0(type)
-int type;
+int
+oper0(int type)
 {
     int retval = mop;
 
     if (type > 255)
        fatal("type > 255 (%d)\n",type);
     ops[mop++].ival = type;
+    if (mop >= OPSMAX)
+       fatal("Recompile a2p with larger OPSMAX\n");
     return retval;
 }
 
-oper1(type,arg1)
-int type;
-int arg1;
+int
+oper1(int type, int arg1)
 {
     int retval = mop;
 
@@ -616,13 +957,13 @@ int arg1;
        fatal("type > 255 (%d)\n",type);
     ops[mop++].ival = type + (1<<8);
     ops[mop++].ival = arg1;
+    if (mop >= OPSMAX)
+       fatal("Recompile a2p with larger OPSMAX\n");
     return retval;
 }
 
-oper2(type,arg1,arg2)
-int type;
-int arg1;
-int arg2;
+int
+oper2(int type, int arg1, int arg2)
 {
     int retval = mop;
 
@@ -631,14 +972,13 @@ int arg2;
     ops[mop++].ival = type + (2<<8);
     ops[mop++].ival = arg1;
     ops[mop++].ival = arg2;
+    if (mop >= OPSMAX)
+       fatal("Recompile a2p with larger OPSMAX\n");
     return retval;
 }
 
-oper3(type,arg1,arg2,arg3)
-int type;
-int arg1;
-int arg2;
-int arg3;
+int
+oper3(int type, int arg1, int arg2, int arg3)
 {
     int retval = mop;
 
@@ -648,15 +988,13 @@ int arg3;
     ops[mop++].ival = arg1;
     ops[mop++].ival = arg2;
     ops[mop++].ival = arg3;
+    if (mop >= OPSMAX)
+       fatal("Recompile a2p with larger OPSMAX\n");
     return retval;
 }
 
-oper4(type,arg1,arg2,arg3,arg4)
-int type;
-int arg1;
-int arg2;
-int arg3;
-int arg4;
+int
+oper4(int type, int arg1, int arg2, int arg3, int arg4)
 {
     int retval = mop;
 
@@ -667,16 +1005,13 @@ int arg4;
     ops[mop++].ival = arg2;
     ops[mop++].ival = arg3;
     ops[mop++].ival = arg4;
+    if (mop >= OPSMAX)
+       fatal("Recompile a2p with larger OPSMAX\n");
     return retval;
 }
 
-oper5(type,arg1,arg2,arg3,arg4,arg5)
-int type;
-int arg1;
-int arg2;
-int arg3;
-int arg4;
-int arg5;
+int
+oper5(int type, int arg1, int arg2, int arg3, int arg4, int arg5)
 {
     int retval = mop;
 
@@ -688,13 +1023,15 @@ int arg5;
     ops[mop++].ival = arg3;
     ops[mop++].ival = arg4;
     ops[mop++].ival = arg5;
+    if (mop >= OPSMAX)
+       fatal("Recompile a2p with larger OPSMAX\n");
     return retval;
 }
 
 int depth = 0;
 
-dump(branch)
-int branch;
+void
+dump(int branch)
 {
     register int type;
     register int len;
@@ -720,22 +1057,21 @@ int branch;
     }
 }
 
-bl(arg,maybe)
-int arg;
-int maybe;
+int
+bl(int arg, int maybe)
 {
     if (!arg)
        return 0;
     else if ((ops[arg].ival & 255) != OBLOCK)
        return oper2(OBLOCK,arg,maybe);
-    else if ((ops[arg].ival >> 8) != 2)
+    else if ((ops[arg].ival >> 8) < 2)
        return oper2(OBLOCK,ops[arg+1].ival,maybe);
     else
        return arg;
 }
 
-fixup(str)
-STR *str;
+void
+fixup(STR *str)
 {
     register char *s;
     register char *t;
@@ -746,9 +1082,9 @@ STR *str;
            s++;
        }
        else if (*s == '\n') {
-           for (t = s+1; isspace(*t & 127); t++) ;
+           for (t = s+1; isSPACE(*t & 127); t++) ;
            t--;
-           while (isspace(*t & 127) && *t != '\n') t--;
+           while (isSPACE(*t & 127) && *t != '\n') t--;
            if (*t == '\n' && t-s > 1) {
                if (s[-1] == '{')
                    s--;
@@ -759,8 +1095,8 @@ STR *str;
     }
 }
 
-putlines(str)
-STR *str;
+void
+putlines(STR *str)
 {
     register char *d, *s, *t, *e;
     register int pos, newpos;
@@ -781,7 +1117,7 @@ STR *str;
        if (pos > 78) {         /* split a long line? */
            *d-- = '\0';
            newpos = 0;
-           for (t = tokenbuf; isspace(*t & 127); t++) {
+           for (t = tokenbuf; isSPACE(*t & 127); t++) {
                if (*t == '\t')
                    newpos += 8;
                else
@@ -813,7 +1149,10 @@ STR *str;
                    d--;
            }
            if (d > t+3) {
-               *d = '\0';
+                char save[2048];
+                strcpy(save, d);
+               *d = '\n';
+                d[1] = '\0';
                putone();
                putchar('\n');
                if (d[-1] != ';' && !(newpos % 4)) {
@@ -821,7 +1160,7 @@ STR *str;
                    *t++ = ' ';
                    newpos += 2;
                }
-               strcpy(t,d+1);
+               strcpy(t,save+1);
                newpos += strlen(t);
                d = t + strlen(t);
                pos = newpos;
@@ -832,7 +1171,8 @@ STR *str;
     }
 }
 
-putone()
+void
+putone(void)
 {
     register char *t;
 
@@ -841,26 +1181,134 @@ putone()
        if (*t == 127) {
            *t = ' ';
            strcpy(t+strlen(t)-1, "\t#???\n");
+           checkers++;
        }
     }
     t = tokenbuf;
     if (*t == '#') {
        if (strnEQ(t,"#!/bin/awk",10) || strnEQ(t,"#! /bin/awk",11))
            return;
+       if (strnEQ(t,"#!/usr/bin/awk",14) || strnEQ(t,"#! /usr/bin/awk",15))
+           return;
     }
     fputs(tokenbuf,stdout);
 }
 
-numary(arg)
-int arg;
+int
+numary(int arg)
 {
     STR *key;
     int dummy;
 
-    key = walk(0,0,arg,&dummy);
+    key = walk(0,0,arg,&dummy,P_MIN);
     str_cat(key,"[]");
     hstore(symtab,key->str_ptr,str_make("1"));
     str_free(key);
     set_array_base = TRUE;
     return arg;
 }
+
+int
+rememberargs(int arg)
+{
+    int type;
+    STR *str;
+
+    if (!arg)
+       return arg;
+    type = ops[arg].ival & 255;
+    if (type == OCOMMA) {
+       rememberargs(ops[arg+1].ival);
+       rememberargs(ops[arg+3].ival);
+    }
+    else if (type == OVAR) {
+       str = str_new(0);
+       hstore(curarghash,ops[ops[arg+1].ival+1].cval,str);
+    }
+    else
+       fatal("panic: unknown argument type %d, line %d\n",type,line);
+    return arg;
+}
+
+int
+aryrefarg(int arg)
+{
+    int type = ops[arg].ival & 255;
+    STR *str;
+
+    if (type != OSTRING)
+       fatal("panic: aryrefarg %d, line %d\n",type,line);
+    str = hfetch(curarghash,ops[arg+1].cval);
+    if (str)
+       str_set(str,"*");
+    return arg;
+}
+
+int
+fixfargs(int name, int arg, int prevargs)
+{
+    int type;
+    STR *str;
+    int numargs = 0;
+
+    if (!arg)
+       return prevargs;
+    type = ops[arg].ival & 255;
+    if (type == OCOMMA) {
+       numargs = fixfargs(name,ops[arg+1].ival,prevargs);
+       numargs = fixfargs(name,ops[arg+3].ival,numargs);
+    }
+    else if (type == OVAR) {
+       str = hfetch(curarghash,ops[ops[arg+1].ival+1].cval);
+       if (strEQ(str_get(str),"*")) {
+           char tmpbuf[128];
+
+           str_set(str,"");            /* in case another routine has this */
+           ops[arg].ival &= ~255;
+           ops[arg].ival |= OSTAR;
+           sprintf(tmpbuf,"%s:%d",ops[name+1].cval,prevargs);
+           fprintf(stderr,"Adding %s\n",tmpbuf);
+           str = str_new(0);
+           str_set(str,"*");
+           hstore(curarghash,tmpbuf,str);
+       }
+       numargs = prevargs + 1;
+    }
+    else
+       fatal("panic: unknown argument type %d, arg %d, line %d\n",
+         type,prevargs+1,line);
+    return numargs;
+}
+
+int
+fixrargs(char *name, int arg, int prevargs)
+{
+    int type;
+    STR *str;
+    int numargs;
+
+    if (!arg)
+       return prevargs;
+    type = ops[arg].ival & 255;
+    if (type == OCOMMA) {
+       numargs = fixrargs(name,ops[arg+1].ival,prevargs);
+       numargs = fixrargs(name,ops[arg+3].ival,numargs);
+    }
+    else {
+       char *tmpbuf = (char *) safemalloc(strlen(name) + (sizeof(prevargs) * 3) + 5);
+       sprintf(tmpbuf,"%s:%d",name,prevargs);
+       str = hfetch(curarghash,tmpbuf);
+       safefree(tmpbuf);
+       if (str && strEQ(str->str_ptr,"*")) {
+           if (type == OVAR || type == OSTAR) {
+               ops[arg].ival &= ~255;
+               ops[arg].ival |= OSTAR;
+           }
+           else
+               fatal("Can't pass expression by reference as arg %d of %s\n",
+                   prevargs+1, name);
+       }
+       numargs = prevargs + 1;
+    }
+    return numargs;
+}