v13i001: Perl, a "replacement" for awk and sed, Part01/10

Showing 1-1 of 1 messages
v13i001: Perl, a "replacement" for awk and sed, Part01/10 Rich Salz 2/1/88 5:46 AM
Submitted-by: Larry Wall <lw...@jpl-devvax.jpl.nasa.gov>
Posting-number: Volume 13, Issue 1
Archive-name: perl/part01

[  Perl is kind of designed to make awk and sed semi-obsolete.  This posting
   will include the first 10 patches after the main source.  The following
   description is lifted from Larry's manpage. --r$  ]

   Perl is a interpreted language optimized for scanning arbitrary text
   files, extracting information from those text files, and printing
   reports based on that information.  It's also a good language for many
   system management tasks.  The language is intended to be practical
   (easy to use, efficient, complete) rather than beautiful (tiny,
   elegant, minimal).  It combines (in the author's opinion, anyway) some
   of the best features of C, sed, awk, and sh, so people familiar with
   those languages should have little difficulty with it.  (Language
   historians will also note some vestiges of csh, Pascal, and even
   BASIC-PLUS.) Expression syntax corresponds quite closely to C
   expression syntax.  If you have a problem that would ordinarily use sed
   or awk or sh, but it exceeds their capabilities or must run a little
   faster, and you don't want to write the silly thing in C, then perl may
   be for you.  There are also translators to turn your sed and awk
   scripts into perl scripts.

#! /bin/sh

# Make a new directory for the perl sources, cd to it, and run kits 1
# thru 10 through sh.  When all 10 kits have been run, read README.

echo "This is perl 1.0 kit 1 (of 10).  If kit 1 is complete, the line"
echo '"'"End of kit 1 (of 10)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir x2p 2>/dev/null
echo Extracting README
sed >README <<'!STUFFY!FUNK!' -e 's/X//'
X
X                        Perl Kit, Version 1.0
X
X                    Copyright (c) 1987, Larry Wall
X
XYou may copy the perl kit in whole or in part as long as you don't try to
Xmake money off it, or pretend that you wrote it.
X--------------------------------------------------------------------------
X
XPerl is a language that combines some of the features of C, sed, awk and shell.
XSee the manual page for more hype.
X
XPerl will probably not run on machines with a small address space.
X
XPlease read all the directions below before you proceed any further, and
Xthen follow them carefully.  Failure to do so may void your warranty. :-)
X
XAfter you have unpacked your kit, you should have all the files listed
Xin MANIFEST.
X
XInstallation
X
X1)  Run Configure.  This will figure out various things about your system.
X    Some things Configure will figure out for itself, other things it will
X    ask you about.  It will then proceed to make config.h, config.sh, and
X    Makefile.
X
X    You might possibly have to trim # comments from the front of Configure
X    if your sh doesn't handle them, but all other # comments will be taken
X    care of.
X
X    (If you don't have sh, you'll have to copy the sample file config.H to
X    config.h and edit the config.h to reflect your system's peculiarities.)
X
X2)  Glance through config.h to make sure system dependencies are correct.
X    Most of them should have been taken care of by running the Configure script.
X
X    If you have any additional changes to make to the C definitions, they
X    can be done in the Makefile, or in config.h.  Bear in mind that they will
X    get undone next time you run Configure.
X
X3)  make depend
X
X    This will look for all the includes and modify Makefile accordingly.
X    Configure will offer to do this for you.
X
X4)  make
X
X    This will attempt to make perl in the current directory.
X
X5)  make test
X
X    This will run the regression tests on the perl you just made.
X    If it doesn't say "All tests successful" then something went wrong.
X    See the README in the t subdirectory.
X
X6)  make install
X
X    This will put perl into a public directory (normally /usr/local/bin).
X    It will also try to put the man pages in a reasonable place.  It will not
X    nroff the man page, however.  You may need to be root to do this.  If
X    you are not root, you must own the directories in question and you should
X    ignore any messages about chown not working.
X
X7)  Read the manual entry before running perl.
X
X8)  Go down to the x2p directory and do a "make depend, a "make" and a
X    "make install" to create the awk to perl and sed to perl translators.
X
X9)  IMPORTANT!  Help save the world!  Communicate any problems and suggested
X    patches to me, lw...@jpl-devvax.jpl.nasa.gov (Larry Wall), so we can
X    keep the world in sync.  If you have a problem, there's someone else
X    out there who either has had or will have the same problem.
X
X    If possible, send in patches such that the patch program will apply them.
X    Context diffs are the best, then normal diffs.  Don't send ed scripts--
X    I've probably changed my copy since the version you have.
X
X    Watch for perl patches in comp.sources.bugs.  Patches will generally be
X    in a form usable by the patch program.  If you are just now bringing up
X    perl and aren't sure how many patches there are, write to me and I'll
X    send any you don't have.  Your current patch level is shown in patchlevel.h.
X
!STUFFY!FUNK!
echo Extracting x2p/walk.c
sed >x2p/walk.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: walk.c,v 1.0 87/12/18 13:07:40 root Exp $
X *
X * $Log:        walk.c,v $
X * Revision 1.0  87/12/18  13:07:40  root
X * Initial revision
X *
X */
X
X#include "handy.h"
X#include "EXTERN.h"
X#include "util.h"
X#include "a2p.h"
X
Xbool exitval = FALSE;
Xbool realexit = FALSE;
Xint maxtmp = 0;
X
XSTR *
Xwalk(useval,level,node,numericptr)
Xint useval;
Xint level;
Xregister int node;
Xint *numericptr;
X{
X    register int len;
X    register STR *str;
X    register int type;
X    register int i;
X    register STR *tmpstr;
X    STR *tmp2str;
X    char *t;
X    char *d, *s;
X    int numarg;
X    int numeric = FALSE;
X    STR *fstr;
X    char *index();
X
X    if (!node) {
X        *numericptr = 0;
X        return str_make("");
X    }
X    type = ops[node].ival;
X    len = type >> 8;
X    type &= 255;
X    switch (type) {
X    case OPROG:
X        str = walk(0,level,ops[node+1].ival,&numarg);
X        opens = str_new(0);
X        if (do_split && need_entire && !absmaxfld)
X            split_to_array = TRUE;
X        if (do_split && split_to_array)
X            set_array_base = TRUE;
X        if (set_array_base) {
X            str_cat(str,"$[ = 1;\t\t\t# set array base to 1\n");
X        }
X        if (fswitch && !const_FS)
X            const_FS = fswitch;
X        if (saw_FS > 1 || saw_RS)
X            const_FS = 0;
X        if (saw_ORS && need_entire)
X            do_chop = TRUE;
X        if (fswitch) {
X            str_cat(str,"$FS = '");
X            if (index("*+?.[]()|^$\\",fswitch))
X                str_cat(str,"\\");
X            sprintf(tokenbuf,"%c",fswitch);
X            str_cat(str,tokenbuf);
X            str_cat(str,"';\t\t# field separator from -F switch\n");
X        }
X        else if (saw_FS && !const_FS) {
X            str_cat(str,"$FS = '[ \\t\\n]+';\t\t# default field separator\n");
X        }
X        if (saw_OFS) {
X            str_cat(str,"$, = ' ';\t\t# default output field separator\n");
X        }
X        if (saw_ORS) {
X            str_cat(str,"$\\ = \"\\n\";\t\t# default output record separator\n");
X        }
X        if (str->str_cur > 20)
X            str_cat(str,"\n");
X        if (ops[node+2].ival) {
X            str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
X            str_free(fstr);
X            str_cat(str,"\n\n");
X        }
X        if (saw_line_op)
X            str_cat(str,"line: ");
X        str_cat(str,"while (<>) {\n");
X        tab(str,++level);
X        if (saw_FS && !const_FS)
X            do_chop = TRUE;
X        if (do_chop) {
X            str_cat(str,"chop;\t# strip record separator\n");
X            tab(str,level);
X        }
X        arymax = 0;
X        if (namelist) {
X            while (isalpha(*namelist)) {
X                for (d = tokenbuf,s=namelist;
X                  isalpha(*s) || isdigit(*s) || *s == '_';
X                  *d++ = *s++) ;
X                *d = '\0';
X                while (*s && !isalpha(*s)) s++;
X                namelist = s;
X                nameary[++arymax] = savestr(tokenbuf);
X            }
X        }
X        if (maxfld < arymax)
X            maxfld = arymax;
X        if (do_split)
X            emit_split(str,level);
X        str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
X        str_free(fstr);
X        fixtab(str,--level);
X        str_cat(str,"}\n");
X        if (ops[node+4].ival) {
X            realexit = TRUE;
X            str_cat(str,"\n");
X            tab(str,level);
X            str_scat(str,fstr=walk(0,level,ops[node+4].ival,&numarg));
X            str_free(fstr);
X            str_cat(str,"\n");
X        }
X        if (exitval)
X            str_cat(str,"exit ExitValue;\n");
X        if (do_fancy_opens) {
X            str_cat(str,"\n\
Xsub Pick {\n\
X    ($name) = @_;\n\
X    $fh = $opened{$name};\n\
X    if (!$fh) {\n\
X        $nextfh == 0 && open(fh_0,$name);\n\
X        $nextfh == 1 && open(fh_1,$name);\n\
X        $nextfh == 2 && open(fh_2,$name);\n\
X        $nextfh == 3 && open(fh_3,$name);\n\
X        $nextfh == 4 && open(fh_4,$name);\n\
X        $nextfh == 5 && open(fh_5,$name);\n\
X        $nextfh == 6 && open(fh_6,$name);\n\
X        $nextfh == 7 && open(fh_7,$name);\n\
X        $nextfh == 8 && open(fh_8,$name);\n\
X        $nextfh == 9 && open(fh_9,$name);\n\
X        $fh = $opened{$name} = 'fh_' . $nextfh++;\n\
X    }\n\
X    select($fh);\n\
X}\n\
X");
X        }
X        break;
X    case OHUNKS:
X        str = walk(0,level,ops[node+1].ival,&numarg);
X        str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        if (len == 3) {
X            str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
X            str_free(fstr);
X        }
X        else {
X        }
X        break;
X    case ORANGE:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str," .. ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OPAT:
X        goto def;
X    case OREGEX:
X        str = str_new(0);
X        str_set(str,"/");
X        tmpstr=walk(0,level,ops[node+1].ival,&numarg);
X        /* translate \nnn to [\nnn] */
X        for (s = tmpstr->str_ptr, d = tokenbuf; *s; s++, d++) {
X            if (*s == '\\' && isdigit(s[1]) && isdigit(s[2]) && isdigit(s[3])) {
X                *d++ = '[';
X                *d++ = *s++;
X                *d++ = *s++;
X                *d++ = *s++;
X                *d++ = *s;
X                *d = ']';
X            }
X            else
X                *d = *s;
X        }
X        *d = '\0';
X        str_cat(str,tokenbuf);
X        str_free(tmpstr);
X        str_cat(str,"/");
X        break;
X    case OHUNK:
X        if (len == 1) {
X            str = str_new(0);
X            str = walk(0,level,oper1(OPRINT,0),&numarg);
X            str_cat(str," if ");
X            str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg));
X            str_free(fstr);
X            str_cat(str,";");
X        }
X        else {
X            tmpstr = walk(0,level,ops[node+1].ival,&numarg);
X            if (*tmpstr->str_ptr) {
X                str = str_new(0);
X                str_set(str,"if (");
X                str_scat(str,tmpstr);
X                str_cat(str,") {\n");
X                tab(str,++level);
X                str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
X                str_free(fstr);
X                fixtab(str,--level);
X                str_cat(str,"}\n");
X                tab(str,level);
X            }
X            else {
X                str = walk(0,level,ops[node+2].ival,&numarg);
X            }
X        }
X        break;
X    case OPPAREN:
X        str = str_new(0);
X        str_set(str,"(");
X        str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,")");
X        break;
X    case OPANDAND:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str," && ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OPOROR:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str," || ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OPNOT:
X        str = str_new(0);
X        str_set(str,"!");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OCPAREN:
X        str = str_new(0);
X        str_set(str,"(");
X        str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        numeric |= numarg;
X        str_cat(str,")");
X        break;
X    case OCANDAND:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        str_cat(str," && ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OCOROR:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        str_cat(str," || ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OCNOT:
X        str = str_new(0);
X        str_set(str,"!");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case ORELOP:
X        str = walk(1,level,ops[node+2].ival,&numarg);
X        numeric |= numarg;
X        tmpstr = walk(0,level,ops[node+1].ival,&numarg);
X        tmp2str = walk(1,level,ops[node+3].ival,&numarg);
X        numeric |= numarg;
X        if (!numeric) {
X            t = tmpstr->str_ptr;
X            if (strEQ(t,"=="))
X                str_set(tmpstr,"eq");
X            else if (strEQ(t,"!="))
X                str_set(tmpstr,"ne");
X            else if (strEQ(t,"<"))
X                str_set(tmpstr,"lt");
X            else if (strEQ(t,"<="))
X                str_set(tmpstr,"le");
X            else if (strEQ(t,">"))
X                str_set(tmpstr,"gt");
X            else if (strEQ(t,">="))
X                str_set(tmpstr,"ge");
X            if (!index(tmpstr->str_ptr,'\'') && !index(tmpstr->str_ptr,'"') &&
X              !index(tmp2str->str_ptr,'\'') && !index(tmp2str->str_ptr,'"') )
X                numeric |= 2;
X        }
X        if (numeric & 2) {
X            if (numeric & 1)                /* numeric is very good guess */
X                str_cat(str," ");
X            else
X                str_cat(str,"\377");
X            numeric = 1;
X        }
X        else
X            str_cat(str," ");
X        str_scat(str,tmpstr);
X        str_free(tmpstr);
X        str_cat(str," ");
X        str_scat(str,tmp2str);
X        str_free(tmp2str);
X        numeric = 1;
X        break;
X    case ORPAREN:
X        str = str_new(0);
X        str_set(str,"(");
X        str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        numeric |= numarg;
X        str_cat(str,")");
X        break;
X    case OMATCHOP:
X        str = walk(1,level,ops[node+2].ival,&numarg);
X        str_cat(str," ");
X        tmpstr = walk(0,level,ops[node+1].ival,&numarg);
X        if (strEQ(tmpstr->str_ptr,"~"))
X            str_cat(str,"=~");
X        else {
X            str_scat(str,tmpstr);
X            str_free(tmpstr);
X        }
X        str_cat(str," ");
X        str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case OMPAREN:
X        str = str_new(0);
X        str_set(str,"(");
X        str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        numeric |= numarg;
X        str_cat(str,")");
X        break;
X    case OCONCAT:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str," . ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OASSIGN:
X        str = walk(0,level,ops[node+2].ival,&numarg);
X        str_cat(str," ");
X        tmpstr = walk(0,level,ops[node+1].ival,&numarg);
X        str_scat(str,tmpstr);
X        if (str_len(tmpstr) > 1)
X            numeric = 1;
X        str_free(tmpstr);
X        str_cat(str," ");
X        str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg));
X        str_free(fstr);
X        numeric |= numarg;
X        if (strEQ(str->str_ptr,"$FS = '\240'"))
X            str_set(str,"$FS = '[\240\\n\\t]+'");
X        break;
X    case OADD:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str," + ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case OSUB:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str," - ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case OMULT:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str," * ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case ODIV:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str," / ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case OMOD:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str," % ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case OPOSTINCR:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str,"++");
X        numeric = 1;
X        break;
X    case OPOSTDECR:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str,"--");
X        numeric = 1;
X        break;
X    case OPREINCR:
X        str = str_new(0);
X        str_set(str,"++");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case OPREDECR:
X        str = str_new(0);
X        str_set(str,"--");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case OUMINUS:
X        str = str_new(0);
X        str_set(str,"-");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        numeric = 1;
X        break;
X    case OUPLUS:
X        numeric = 1;
X        goto def;
X    case OPAREN:
X        str = str_new(0);
X        str_set(str,"(");
X        str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,")");
X        numeric |= numarg;
X        break;
X    case OGETLINE:
X        str = str_new(0);
X        str_set(str,"$_ = <>;\n");
X        tab(str,level);
X        if (do_chop) {
X            str_cat(str,"chop;\t# strip record separator\n");
X            tab(str,level);
X        }
X        if (do_split)
X            emit_split(str,level);
X        break;
X    case OSPRINTF:
X        str = str_new(0);
X        str_set(str,"sprintf(");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,")");
X        break;
X    case OSUBSTR:
X        str = str_new(0);
X        str_set(str,"substr(");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,", ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,", ");
X        if (len == 3) {
X            str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg));
X            str_free(fstr);
X        }
X        else
X            str_cat(str,"999999");
X        str_cat(str,")");
X        break;
X    case OSTRING:
X        str = str_new(0);
X        str_set(str,ops[node+1].cval);
X        break;
X    case OSPLIT:
X        str = str_new(0);
X        numeric = 1;
X        tmpstr = walk(1,level,ops[node+2].ival,&numarg);
X        if (useval)
X            str_set(str,"(@");
X        else
X            str_set(str,"@");
X        str_scat(str,tmpstr);
X        str_cat(str," = split(");
X        if (len == 3) {
X            fstr = walk(1,level,ops[node+3].ival,&numarg);
X            if (str_len(fstr) == 3 && *fstr->str_ptr == '\'') {
X                i = fstr->str_ptr[1] & 127;
X                if (index("*+?.[]()|^$\\",i))
X                    sprintf(tokenbuf,"/\\%c/",i);
X                else
X                    sprintf(tokenbuf,"/%c/",i);
X                str_cat(str,tokenbuf);
X            }
X            else
X                str_scat(str,fstr);
X            str_free(fstr);
X        }
X        else if (const_FS) {
X            sprintf(tokenbuf,"/[%c\\n]/",const_FS);
X            str_cat(str,tokenbuf);
X        }
X        else if (saw_FS)
X            str_cat(str,"$FS");
X        else
X            str_cat(str,"/[ \\t\\n]+/");
X        str_cat(str,", ");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,")");
X        if (useval) {
X            str_cat(str,")");
X        }
X        str_free(tmpstr);
X        break;
X    case OINDEX:
X        str = str_new(0);
X        str_set(str,"index(");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,", ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,")");
X        numeric = 1;
X        break;
X    case ONUM:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        break;
X    case OSTR:
X        tmpstr = walk(1,level,ops[node+1].ival,&numarg);
X        s = "'";
X        for (t = tmpstr->str_ptr; *t; t++) {
X            if (*t == '\\' || *t == '\'')
X                s = "\"";
X            *t += 128;
X        }
X        str = str_new(0);
X        str_set(str,s);
X        str_scat(str,tmpstr);
X        str_free(tmpstr);
X        str_cat(str,s);
X        break;
X    case OVAR:
X        str = str_new(0);
X        str_set(str,"$");
X        str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg));
X        if (len == 1) {
X            tmp2str = hfetch(symtab,tmpstr->str_ptr);
X            if (tmp2str && atoi(tmp2str->str_ptr))
X                numeric = 2;
X            if (strEQ(str->str_ptr,"$NR")) {
X                numeric = 1;
X                str_set(str,"$.");
X            }
X            else if (strEQ(str->str_ptr,"$NF")) {
X                numeric = 1;
X                str_set(str,"$#Fld");
X            }
X            else if (strEQ(str->str_ptr,"$0"))
X                str_set(str,"$_");
X        }
X        else {
X            str_cat(tmpstr,"[]");
X            tmp2str = hfetch(symtab,tmpstr->str_ptr);
X            if (tmp2str && atoi(tmp2str->str_ptr))
X                str_cat(str,"[");
X            else
X                str_cat(str,"{");
X            str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X            str_free(fstr);
X            if (tmp2str && atoi(tmp2str->str_ptr))
X                strcpy(tokenbuf,"]");
X            else
X                strcpy(tokenbuf,"}");
X            *tokenbuf += 128;
X            str_cat(str,tokenbuf);
X        }
X        str_free(tmpstr);
X        break;
X    case OFLD:
X        str = str_new(0);
X        if (split_to_array) {
X            str_set(str,"$Fld");
X            str_cat(str,"[");
X            str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X            str_free(fstr);
X            str_cat(str,"]");
X        }
X        else {
X            i = atoi(walk(1,level,ops[node+1].ival,&numarg)->str_ptr);
X            if (i <= arymax)
X                sprintf(tokenbuf,"$%s",nameary[i]);
X            else
X                sprintf(tokenbuf,"$Fld%d",i);
X            str_set(str,tokenbuf);
X        }
X        break;
X    case OVFLD:
X        str = str_new(0);
X        str_set(str,"$Fld[");
X        i = ops[node+1].ival;
X        if ((ops[i].ival & 255) == OPAREN)
X            i = ops[i+1].ival;
X        tmpstr=walk(1,level,i,&numarg);
X        str_scat(str,tmpstr);
X        str_free(tmpstr);
X        str_cat(str,"]");
X        break;
X    case OJUNK:
X        goto def;
X    case OSNEWLINE:
X        str = str_new(2);
X        str_set(str,";\n");
X        tab(str,level);
X        break;
X    case ONEWLINE:
X        str = str_new(1);
X        str_set(str,"\n");
X        tab(str,level);
X        break;
X    case OSCOMMENT:
X        str = str_new(0);
X        str_set(str,";");
X        tmpstr = walk(0,level,ops[node+1].ival,&numarg);
X        for (s = tmpstr->str_ptr; *s && *s != '\n'; s++)
X            *s += 128;
X        str_scat(str,tmpstr);
X        str_free(tmpstr);
X        tab(str,level);
X        break;
X    case OCOMMENT:
X        str = str_new(0);
X        tmpstr = walk(0,level,ops[node+1].ival,&numarg);
X        for (s = tmpstr->str_ptr; *s && *s != '\n'; s++)
X            *s += 128;
X        str_scat(str,tmpstr);
X        str_free(tmpstr);
X        tab(str,level);
X        break;
X    case OCOMMA:
X        str = walk(1,level,ops[node+1].ival,&numarg);
X        str_cat(str,", ");
X        str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OSEMICOLON:
X        str = str_new(1);
X        str_set(str,"; ");
X        break;
X    case OSTATES:
X        str = walk(0,level,ops[node+1].ival,&numarg);
X        str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OSTATE:
X        str = str_new(0);
X        if (len >= 1) {
X            str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg));
X            str_free(fstr);
X            if (len >= 2) {
X                tmpstr = walk(0,level,ops[node+2].ival,&numarg);
X                if (*tmpstr->str_ptr == ';') {
X                    addsemi(str);
X                    str_cat(str,tmpstr->str_ptr+1);
X                }
X                str_free(tmpstr);
X            }
X        }
X        break;
X    case OPRINTF:
X    case OPRINT:
X        str = str_new(0);
X        if (len == 3) {                /* output redirection */
X            tmpstr = walk(1,level,ops[node+3].ival,&numarg);
X            tmp2str = walk(1,level,ops[node+2].ival,&numarg);
X            if (!do_fancy_opens) {
X                t = tmpstr->str_ptr;
X                if (*t == '"' || *t == '\'')
X                    t = cpytill(tokenbuf,t+1,*t);
X                else
X                    fatal("Internal error: OPRINT");
X                d = savestr(t);
X                s = savestr(tokenbuf);
X                for (t = tokenbuf; *t; t++) {
X                    *t &= 127;
X                    if (!isalpha(*t) && !isdigit(*t))
X                        *t = '_';
X                }
X                if (!index(tokenbuf,'_'))
X                    strcpy(t,"_fh");
X                str_cat(opens,"open(");
X                str_cat(opens,tokenbuf);
X                str_cat(opens,", ");
X                d[1] = '\0';
X                str_cat(opens,d);
X                str_scat(opens,tmp2str);
X                str_cat(opens,tmpstr->str_ptr+1);
X                if (*tmp2str->str_ptr == '|')
X                    str_cat(opens,") || die 'Cannot pipe to \"");
X                else
X                    str_cat(opens,") || die 'Cannot create file \"");
X                if (*d == '"')
X                    str_cat(opens,"'.\"");
X                str_cat(opens,s);
X                if (*d == '"')
X                    str_cat(opens,"\".'");
X                str_cat(opens,"\".';\n");
X                str_free(tmpstr);
X                str_free(tmp2str);
X                safefree(s);
X                safefree(d);
X            }
X            else {
X                sprintf(tokenbuf,"do Pick('%s' . (%s)) &&\n",
X                   tmp2str->str_ptr, tmpstr->str_ptr);
X                str_cat(str,tokenbuf);
X                tab(str,level+1);
X                *tokenbuf = '\0';
X                str_free(tmpstr);
X                str_free(tmp2str);
X            }
X        }
X        else
X            strcpy(tokenbuf,"stdout");
X        if (type == OPRINTF)
X            str_cat(str,"printf");
X        else
X            str_cat(str,"print");
X        if (len == 3 || do_fancy_opens) {
X            if (*tokenbuf)
X                str_cat(str," ");
X            str_cat(str,tokenbuf);
X        }
X        tmpstr = walk(1+(type==OPRINT),level,ops[node+1].ival,&numarg);
X        if (!*tmpstr->str_ptr && lval_field) {
X            t = saw_OFS ? "$," : "' '";
X            if (split_to_array) {
X                sprintf(tokenbuf,"join(%s,@Fld)",t);
X                str_cat(tmpstr,tokenbuf);
X            }
X            else {
X                for (i = 1; i < maxfld; i++) {
X                    if (i <= arymax)
X                        sprintf(tokenbuf,"$%s, ",nameary[i]);
X                    else
X                        sprintf(tokenbuf,"$Fld%d, ",i);
X                    str_cat(tmpstr,tokenbuf);
X                }
X                if (maxfld <= arymax)
X                    sprintf(tokenbuf,"$%s",nameary[maxfld]);
X                else
X                    sprintf(tokenbuf,"$Fld%d",maxfld);
X                str_cat(tmpstr,tokenbuf);
X            }
X        }
X        if (*tmpstr->str_ptr) {
X            str_cat(str," ");
X            str_scat(str,tmpstr);
X        }
X        else {
X            str_cat(str," $_");
X        }
X        str_free(tmpstr);
X        break;
X    case OLENGTH:
X        str = str_make("length(");
X        goto maybe0;
X    case OLOG:
X        str = str_make("log(");
X        goto maybe0;
X    case OEXP:
X        str = str_make("exp(");
X        goto maybe0;
X    case OSQRT:
X        str = str_make("sqrt(");
X        goto maybe0;
X    case OINT:
X        str = str_make("int(");
X      maybe0:
X        numeric = 1;
X        if (len > 0)
X            tmpstr = walk(1,level,ops[node+1].ival,&numarg);
X        else
X            tmpstr = str_new(0);;
X        if (!*tmpstr->str_ptr) {
X            if (lval_field) {
X                t = saw_OFS ? "$," : "' '";
X                if (split_to_array) {
X                    sprintf(tokenbuf,"join(%s,@Fld)",t);
X                    str_cat(tmpstr,tokenbuf);
X                }
X                else {
X                    sprintf(tokenbuf,"join(%s, ",t);
X                    str_cat(tmpstr,tokenbuf);
X                    for (i = 1; i < maxfld; i++) {
X                        if (i <= arymax)
X                            sprintf(tokenbuf,"$%s,",nameary[i]);
X                        else
X                            sprintf(tokenbuf,"$Fld%d,",i);
X                        str_cat(tmpstr,tokenbuf);
X                    }
X                    if (maxfld <= arymax)
X                        sprintf(tokenbuf,"$%s)",nameary[maxfld]);
X                    else
X                        sprintf(tokenbuf,"$Fld%d)",maxfld);
X                    str_cat(tmpstr,tokenbuf);
X                }
X            }
X            else
X                str_cat(tmpstr,"$_");
X        }
X        if (strEQ(tmpstr->str_ptr,"$_")) {
X            if (type == OLENGTH && !do_chop) {
X                str = str_make("(length(");
X                str_cat(tmpstr,") - 1");
X            }
X        }
X        str_scat(str,tmpstr);
X        str_free(tmpstr);
X        str_cat(str,")");
X        break;
X    case OBREAK:
X        str = str_new(0);
X        str_set(str,"last");
X        break;
X    case ONEXT:
X        str = str_new(0);
X        str_set(str,"next line");
X        break;
X    case OEXIT:
X        str = str_new(0);
X        if (realexit) {
X            str_set(str,"exit");
X            if (len == 1) {
X                str_cat(str," ");
X                exitval = TRUE;
X                str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X                str_free(fstr);
X            }
X        }
X        else {
X            if (len == 1) {
X                str_set(str,"ExitValue = ");
X                exitval = TRUE;
X                str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X                str_free(fstr);
X                str_cat(str,"; ");
X            }
X            str_cat(str,"last line");
X        }
X        break;
X    case OCONTINUE:
X        str = str_new(0);
X        str_set(str,"next");
X        break;
X    case OREDIR:
X        goto def;
X    case OIF:
X        str = str_new(0);
X        str_set(str,"if (");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,") ");
X        str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        if (len == 3) {
X            i = ops[node+3].ival;
X            if (i) {
X                if ((ops[i].ival & 255) == OBLOCK) {
X                    i = ops[i+1].ival;
X                    if (i) {
X                        if ((ops[i].ival & 255) != OIF)
X                            i = 0;
X                    }
X                }
X                else
X                    i = 0;
X            }
X            if (i) {
X                str_cat(str,"els");
X                str_scat(str,fstr=walk(0,level,i,&numarg));
X                str_free(fstr);
X            }
X            else {
X                str_cat(str,"else ");
X                str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
X                str_free(fstr);
X            }
X        }
X        break;
X    case OWHILE:
X        str = str_new(0);
X        str_set(str,"while (");
X        str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,") ");
X        str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OFOR:
X        str = str_new(0);
X        str_set(str,"for (");
X        str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg));
X        i = numarg;
X        if (i) {
X            t = s = tmpstr->str_ptr;
X            while (isalpha(*t) || isdigit(*t) || *t == '$' || *t == '_')
X                t++;
X            i = t - s;
X            if (i < 2)
X                i = 0;
X        }
X        str_cat(str,"; ");
X        fstr=walk(1,level,ops[node+2].ival,&numarg);
X        if (i && (t = index(fstr->str_ptr,0377))) {
X            if (strnEQ(fstr->str_ptr,s,i))
X                *t = ' ';
X        }
X        str_scat(str,fstr);
X        str_free(fstr);
X        str_free(tmpstr);
X        str_cat(str,"; ");
X        str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg));
X        str_free(fstr);
X        str_cat(str,") ");
X        str_scat(str,fstr=walk(0,level,ops[node+4].ival,&numarg));
X        str_free(fstr);
X        break;
X    case OFORIN:
X        tmpstr=walk(0,level,ops[node+2].ival,&numarg);
X        str = str_new(0);
X        str_sset(str,tmpstr);
X        str_cat(str,"[]");
X        tmp2str = hfetch(symtab,str->str_ptr);
X        if (tmp2str && atoi(tmp2str->str_ptr)) {
X            maxtmp++;
X            fstr=walk(1,level,ops[node+1].ival,&numarg);
X            sprintf(tokenbuf,
X              "for ($T_%d = 1; ($%s = $%s[$T_%d]) || $T_%d <= $#%s; $T_%d++)%c",
X              maxtmp,
X              fstr->str_ptr,
X              tmpstr->str_ptr,
X              maxtmp,
X              maxtmp,
X              tmpstr->str_ptr,
X              maxtmp,
X              0377);
X            str_set(str,tokenbuf);
X            str_free(fstr);
X            str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
X            str_free(fstr);
X        }
X        else {
X            str_set(str,"while (($junkkey,$");
X            str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X            str_free(fstr);
X            str_cat(str,") = each(");
X            str_scat(str,tmpstr);
X            str_cat(str,")) ");
X            str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
X            str_free(fstr);
X        }
X        str_free(tmpstr);
X        break;
X    case OBLOCK:
X        str = str_new(0);
X        str_set(str,"{");
X        if (len == 2) {
X            str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
X            str_free(fstr);
X        }
X        fixtab(str,++level);
X        str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg));
X        str_free(fstr);
X        addsemi(str);
X        fixtab(str,--level);
X        str_cat(str,"}\n");
X        tab(str,level);
X        break;
X    default:
X      def:
X        if (len) {
X            if (len > 5)
X                fatal("Garbage length in walk");
X            str = walk(0,level,ops[node+1].ival,&numarg);
X            for (i = 2; i<= len; i++) {
X                str_scat(str,fstr=walk(0,level,ops[node+i].ival,&numarg));
X                str_free(fstr);
X            }
X        }
X        else {
X            str = Nullstr;
X        }
X        break;
X    }
X    if (!str)
X        str = str_new(0);
X    *numericptr = numeric;
X#ifdef DEBUGGING
X    if (debug & 4) {
X        printf("%3d %5d %15s %d %4d ",level,node,opname[type],len,str->str_cur);
X        for (t = str->str_ptr; *t && t - str->str_ptr < 40; t++)
X            if (*t == '\n')
X                printf("\\n");
X            else if (*t == '\t')
X                printf("\\t");
X            else
X                putchar(*t);
X        putchar('\n');
X    }
X#endif
X    return str;
X}
X
Xtab(str,lvl)
Xregister STR *str;
Xregister int lvl;
X{
X    while (lvl > 1) {
X        str_cat(str,"\t");
X        lvl -= 2;
X    }
X    if (lvl)
X        str_cat(str,"    ");
X}
X
Xfixtab(str,lvl)
Xregister STR *str;
Xregister int lvl;
X{
X    register char *s;
X
X    /* strip trailing white space */
X
X    s = str->str_ptr+str->str_cur - 1;
X    while (s >= str->str_ptr && (*s == ' ' || *s == '\t'))
X        s--;
X    s[1] = '\0';
X    str->str_cur = s + 1 - str->str_ptr;
X    if (s >= str->str_ptr && *s != '\n')
X        str_cat(str,"\n");
X
X    tab(str,lvl);
X}
X
Xaddsemi(str)
Xregister STR *str;
X{
X    register char *s;
X
X    s = str->str_ptr+str->str_cur - 1;
X    while (s >= str->str_ptr && (*s == ' ' || *s == '\t' || *s == '\n'))
X        s--;
X    if (s >= str->str_ptr && *s != ';' && *s != '}')
X        str_cat(str,";");
X}
X
Xemit_split(str,level)
Xregister STR *str;
Xint level;
X{
X    register int i;
X
X    if (split_to_array)
X        str_cat(str,"@Fld");
X    else {
X        str_cat(str,"(");
X        for (i = 1; i < maxfld; i++) {
X            if (i <= arymax)
X                sprintf(tokenbuf,"$%s,",nameary[i]);
X            else
X                sprintf(tokenbuf,"$Fld%d,",i);
X            str_cat(str,tokenbuf);
X        }
X        if (maxfld <= arymax)
X            sprintf(tokenbuf,"$%s)",nameary[maxfld]);
X        else
X            sprintf(tokenbuf,"$Fld%d)",maxfld);
X        str_cat(str,tokenbuf);
X    }
X    if (const_FS) {
X        sprintf(tokenbuf," = split(/[%c\\n]/);\n",const_FS);
X        str_cat(str,tokenbuf);
X    }
X    else if (saw_FS)
X        str_cat(str," = split($FS);\n");
X    else
X        str_cat(str," = split;\n");
X    tab(str,level);
X}
X
Xprewalk(numit,level,node,numericptr)
Xint numit;
Xint level;
Xregister int node;
Xint *numericptr;
X{
X    register int len;
X    register int type;
X    register int i;
X    char *t;
X    char *d, *s;
X    int numarg;
X    int numeric = FALSE;
X
X    if (!node) {
X        *numericptr = 0;
X        return 0;
X    }
X    type = ops[node].ival;
X    len = type >> 8;
X    type &= 255;
X    switch (type) {
X    case OPROG:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        if (ops[node+2].ival) {
X            prewalk(0,level,ops[node+2].ival,&numarg);
X        }
X        ++level;
X        prewalk(0,level,ops[node+3].ival,&numarg);
X        --level;
X        if (ops[node+3].ival) {
X            prewalk(0,level,ops[node+4].ival,&numarg);
X        }
X        break;
X    case OHUNKS:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        if (len == 3) {
X            prewalk(0,level,ops[node+3].ival,&numarg);
X        }
X        break;
X    case ORANGE:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        prewalk(1,level,ops[node+2].ival,&numarg);
X        break;
X    case OPAT:
X        goto def;
X    case OREGEX:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        break;
X    case OHUNK:
X        if (len == 1) {
X            prewalk(0,level,ops[node+1].ival,&numarg);
X        }
X        else {
X            i = prewalk(0,level,ops[node+1].ival,&numarg);
X            if (i) {
X                ++level;
X                prewalk(0,level,ops[node+2].ival,&numarg);
X                --level;
X            }
X            else {
X                prewalk(0,level,ops[node+2].ival,&numarg);
X            }
X        }
X        break;
X    case OPPAREN:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        break;
X    case OPANDAND:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        break;
X    case OPOROR:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        break;
X    case OPNOT:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        break;
X    case OCPAREN:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        numeric |= numarg;
X        break;
X    case OCANDAND:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        break;
X    case OCOROR:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        break;
X    case OCNOT:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        break;
X    case ORELOP:
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        numeric |= numarg;
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+3].ival,&numarg);
X        numeric |= numarg;
X        numeric = 1;
X        break;
X    case ORPAREN:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        numeric |= numarg;
X        break;
X    case OMATCHOP:
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+3].ival,&numarg);
X        numeric = 1;
X        break;
X    case OMPAREN:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        numeric |= numarg;
X        break;
X    case OCONCAT:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        break;
X    case OASSIGN:
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+3].ival,&numarg);
X        if (numarg || strlen(ops[ops[node+1].ival+1].cval) > 1) {
X            numericize(ops[node+2].ival);
X            if (!numarg)
X                numericize(ops[node+3].ival);
X        }
X        numeric |= numarg;
X        break;
X    case OADD:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        prewalk(1,level,ops[node+2].ival,&numarg);
X        numeric = 1;
X        break;
X    case OSUB:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        prewalk(1,level,ops[node+2].ival,&numarg);
X        numeric = 1;
X        break;
X    case OMULT:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        prewalk(1,level,ops[node+2].ival,&numarg);
X        numeric = 1;
X        break;
X    case ODIV:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        prewalk(1,level,ops[node+2].ival,&numarg);
X        numeric = 1;
X        break;
X    case OMOD:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        prewalk(1,level,ops[node+2].ival,&numarg);
X        numeric = 1;
X        break;
X    case OPOSTINCR:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        break;
X    case OPOSTDECR:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        break;
X    case OPREINCR:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        break;
X    case OPREDECR:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        break;
X    case OUMINUS:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        break;
X    case OUPLUS:
X        prewalk(1,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        break;
X    case OPAREN:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        numeric |= numarg;
X        break;
X    case OGETLINE:
X        break;
X    case OSPRINTF:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        break;
X    case OSUBSTR:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(1,level,ops[node+2].ival,&numarg);
X        if (len == 3) {
X            prewalk(1,level,ops[node+3].ival,&numarg);
X        }
X        break;
X    case OSTRING:
X        break;
X    case OSPLIT:
X        numeric = 1;
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        if (len == 3)
X            prewalk(0,level,ops[node+3].ival,&numarg);
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        break;
X    case OINDEX:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        numeric = 1;
X        break;
X    case ONUM:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        numeric = 1;
X        break;
X    case OSTR:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        break;
X    case OVAR:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        if (len == 1) {
X            if (numit)
X                numericize(node);
X        }
X        else {
X            prewalk(0,level,ops[node+2].ival,&numarg);
X        }
X        break;
X    case OFLD:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        break;
X    case OVFLD:
X        i = ops[node+1].ival;
X        prewalk(0,level,i,&numarg);
X        break;
X    case OJUNK:
X        goto def;
X    case OSNEWLINE:
X        break;
X    case ONEWLINE:
X        break;
X    case OSCOMMENT:
X        break;
X    case OCOMMENT:
X        break;
X    case OCOMMA:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        break;
X    case OSEMICOLON:
X        break;
X    case OSTATES:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        break;
X    case OSTATE:
X        if (len >= 1) {
X            prewalk(0,level,ops[node+1].ival,&numarg);
X            if (len >= 2) {
X                prewalk(0,level,ops[node+2].ival,&numarg);
X            }
X        }
X        break;
X    case OPRINTF:
X    case OPRINT:
X        if (len == 3) {                /* output redirection */
X            prewalk(0,level,ops[node+3].ival,&numarg);
X            prewalk(0,level,ops[node+2].ival,&numarg);
X        }
X        prewalk(0+(type==OPRINT),level,ops[node+1].ival,&numarg);
X        break;
X    case OLENGTH:
X        goto maybe0;
X    case OLOG:
X        goto maybe0;
X    case OEXP:
X        goto maybe0;
X    case OSQRT:
X        goto maybe0;
X    case OINT:
X      maybe0:
X        numeric = 1;
X        if (len > 0)
X            prewalk(type != OLENGTH,level,ops[node+1].ival,&numarg);
X        break;
X    case OBREAK:
X        break;
X    case ONEXT:
X        break;
X    case OEXIT:
X        if (len == 1) {
X            prewalk(1,level,ops[node+1].ival,&numarg);
X        }
X        break;
X    case OCONTINUE:
X        break;
X    case OREDIR:
X        goto def;
X    case OIF:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        if (len == 3) {
X            prewalk(0,level,ops[node+3].ival,&numarg);
X        }
X        break;
X    case OWHILE:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        break;
X    case OFOR:
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        prewalk(0,level,ops[node+3].ival,&numarg);
X        prewalk(0,level,ops[node+4].ival,&numarg);
X        break;
X    case OFORIN:
X        prewalk(0,level,ops[node+2].ival,&numarg);
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        prewalk(0,level,ops[node+3].ival,&numarg);
X        break;
X    case OBLOCK:
X        if (len == 2) {
X            prewalk(0,level,ops[node+2].ival,&numarg);
X        }
X        ++level;
X        prewalk(0,level,ops[node+1].ival,&numarg);
X        --level;
X        break;
X    default:
X      def:
X        if (len) {
X            if (len > 5)
X                fatal("Garbage length in prewalk");
X            prewalk(0,level,ops[node+1].ival,&numarg);
X            for (i = 2; i<= len; i++) {
X                prewalk(0,level,ops[node+i].ival,&numarg);
X            }
X        }
X        break;...