home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / p / perl4036.zip / x2p / a2py.c < prev    next >
C/C++ Source or Header  |  1993-02-08  |  25KB  |  1,299 lines

  1. /* $RCSfile: a2py.c,v $$Revision: 4.0.1.2 $$Date: 92/06/08 16:15:16 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    a2py.c,v $
  9.  * Revision 4.0.1.2  92/06/08  16:15:16  lwall
  10.  * patch20: in a2p, now warns about spurious backslashes
  11.  * patch20: in a2p, now allows [ to be backslashed in pattern
  12.  * patch20: in a2p, now allows numbers of the form 2.
  13.  * 
  14.  * Revision 4.0.1.1  91/06/07  12:12:59  lwall
  15.  * patch4: new copyright notice
  16.  * 
  17.  * Revision 4.0  91/03/20  01:57:26  lwall
  18.  * 4.0 baseline.
  19.  * 
  20.  */
  21.  
  22. #ifdef OS2
  23. #include "../patchlevel.h"
  24. #endif
  25. #include "util.h"
  26. char *index();
  27.  
  28. char *filename;
  29. char *myname;
  30.  
  31. int checkers = 0;
  32. STR *walk();
  33.  
  34. #ifdef OS2
  35. usage()
  36. {
  37.     printf("\nThis is the AWK to PERL translator, version 4.0, patchlevel %d\n", PATCHLEVEL);
  38.     printf("\nUsage: %s [-D<number>] [-F<char>] [-n<fieldlist>] [-<number>] filename\n", myname);
  39.     printf("\n  -D<number>      sets debugging flags."
  40.            "\n  -F<character>   the awk script to translate is always invoked with"
  41.            "\n                  this -F switch."
  42.            "\n  -n<fieldlist>   specifies the names of the input fields if input does"
  43.            "\n                  not have to be split into an array."
  44.            "\n  -<number>       causes a2p to assume that input will always have that"
  45.            "\n                  many fields.\n");
  46.     exit(1);
  47. }
  48. #endif
  49. main(argc,argv,env)
  50. register int argc;
  51. register char **argv;
  52. register char **env;
  53. {
  54.     register STR *str;
  55.     register char *s;
  56.     int i;
  57.     STR *tmpstr;
  58.  
  59.     myname = argv[0];
  60.     linestr = str_new(80);
  61.     str = str_new(0);        /* first used for -I flags */
  62.     for (argc--,argv++; argc; argc--,argv++) {
  63.     if (argv[0][0] != '-' || !argv[0][1])
  64.         break;
  65.       reswitch:
  66.     switch (argv[0][1]) {
  67. #ifdef DEBUGGING
  68.     case 'D':
  69.         debug = atoi(argv[0]+2);
  70. #ifdef YYDEBUG
  71.         yydebug = (debug & 1);
  72. #endif
  73.         break;
  74. #endif
  75.     case '0': case '1': case '2': case '3': case '4':
  76.     case '5': case '6': case '7': case '8': case '9':
  77.         maxfld = atoi(argv[0]+1);
  78.         absmaxfld = TRUE;
  79.         break;
  80.     case 'F':
  81.         fswitch = argv[0][2];
  82.         break;
  83.     case 'n':
  84.         namelist = savestr(argv[0]+2);
  85.         break;
  86.     case '-':
  87.         argc--,argv++;
  88.         goto switch_end;
  89.     case 0:
  90.         break;
  91.     default:
  92.         fatal("Unrecognized switch: %s\n",argv[0]);
  93. #ifdef OS2
  94.             usage();
  95. #endif
  96.     }
  97.     }
  98.   switch_end:
  99.  
  100.     /* open script */
  101.  
  102.     if (argv[0] == Nullch) {
  103. #ifdef OS2
  104.     if ( isatty(fileno(stdin)) )
  105.         usage();
  106. #endif
  107.         argv[0] = "-";
  108.     }
  109.     filename = savestr(argv[0]);
  110.  
  111.     filename = savestr(argv[0]);
  112.     if (strEQ(filename,"-"))
  113.     argv[0] = "";
  114.     if (!*argv[0])
  115.     rsfp = stdin;
  116.     else
  117.     rsfp = fopen(argv[0],"r");
  118.     if (rsfp == Nullfp)
  119.     fatal("Awk script \"%s\" doesn't seem to exist.\n",filename);
  120.  
  121.     /* init tokener */
  122.  
  123.     bufptr = str_get(linestr);
  124.     symtab = hnew();
  125.     curarghash = hnew();
  126.  
  127.     /* now parse the report spec */
  128.  
  129.     if (yyparse())
  130.     fatal("Translation aborted due to syntax errors.\n");
  131.  
  132. #ifdef DEBUGGING
  133.     if (debug & 2) {
  134.     int type, len;
  135.  
  136.     for (i=1; i<mop;) {
  137.         type = ops[i].ival;
  138.         len = type >> 8;
  139.         type &= 255;
  140.         printf("%d\t%d\t%d\t%-10s",i++,type,len,opname[type]);
  141.         if (type == OSTRING)
  142.         printf("\t\"%s\"\n",ops[i].cval),i++;
  143.         else {
  144.         while (len--) {
  145.             printf("\t%d",ops[i].ival),i++;
  146.         }
  147.         putchar('\n');
  148.         }
  149.     }
  150.     }
  151.     if (debug & 8)
  152.     dump(root);
  153. #endif
  154.  
  155.     /* first pass to look for numeric variables */
  156.  
  157.     prewalk(0,0,root,&i);
  158.  
  159.     /* second pass to produce new program */
  160.  
  161.     tmpstr = walk(0,0,root,&i,P_MIN);
  162.     str = str_make("#!");
  163.     str_cat(str, BIN);
  164.     str_cat(str, "/perl\neval \"exec ");
  165.     str_cat(str, BIN);
  166.     str_cat(str, "/perl -S $0 $*\"\n\
  167.     if $running_under_some_shell;\n\
  168.             # this emulates #! processing on NIH machines.\n\
  169.             # (remove #! line above if indigestible)\n\n");
  170.     str_cat(str,
  171.       "eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;\n");
  172.     str_cat(str,
  173.       "            # process any FOO=bar switches\n\n");
  174.     if (do_opens && opens) {
  175.     str_scat(str,opens);
  176.     str_free(opens);
  177.     str_cat(str,"\n");
  178.     }
  179.     str_scat(str,tmpstr);
  180.     str_free(tmpstr);
  181. #ifdef DEBUGGING
  182.     if (!(debug & 16))
  183. #endif
  184.     fixup(str);
  185.     putlines(str);
  186.     if (checkers) {
  187.     fprintf(stderr,
  188.       "Please check my work on the %d line%s I've marked with \"#???\".\n",
  189.         checkers, checkers == 1 ? "" : "s" );
  190.     fprintf(stderr,
  191.       "The operation I've selected may be wrong for the operand types.\n");
  192.     }
  193.     exit(0);
  194. }
  195.  
  196. #define RETURN(retval) return (bufptr = s,retval)
  197. #define XTERM(retval) return (expectterm = TRUE,bufptr = s,retval)
  198. #define XOP(retval) return (expectterm = FALSE,bufptr = s,retval)
  199. #define ID(x) return (yylval=string(x,0),expectterm = FALSE,bufptr = s,idtype)
  200.  
  201. int idtype;
  202.  
  203. yylex()
  204. {
  205.     register char *s = bufptr;
  206.     register char *d;
  207.     register int tmp;
  208.  
  209.   retry:
  210. #ifdef YYDEBUG
  211.     if (yydebug)
  212.     if (index(s,'\n'))
  213.         fprintf(stderr,"Tokener at %s",s);
  214.     else
  215.         fprintf(stderr,"Tokener at %s\n",s);
  216. #endif
  217.     switch (*s) {
  218.     default:
  219.     fprintf(stderr,
  220.         "Unrecognized character %c in file %s line %d--ignoring.\n",
  221.          *s++,filename,line);
  222.     goto retry;
  223.     case '\\':
  224.     s++;
  225.     if (*s && *s != '\n') {
  226.         yyerror("Ignoring spurious backslash");
  227.         goto retry;
  228.     }
  229.     /*FALLSTHROUGH*/
  230.     case 0:
  231.     s = str_get(linestr);
  232.     *s = '\0';
  233.     if (!rsfp)
  234.         RETURN(0);
  235.     line++;
  236.     if ((s = str_gets(linestr, rsfp)) == Nullch) {
  237.         if (rsfp != stdin)
  238.         fclose(rsfp);
  239.         rsfp = Nullfp;
  240.         s = str_get(linestr);
  241.         RETURN(0);
  242.     }
  243.     goto retry;
  244.     case ' ': case '\t':
  245.     s++;
  246.     goto retry;
  247.     case '\n':
  248.     *s = '\0';
  249.     XTERM(NEWLINE);
  250.     case '#':
  251.     yylval = string(s,0);
  252.     *s = '\0';
  253.     XTERM(COMMENT);
  254.     case ';':
  255.     tmp = *s++;
  256.     if (*s == '\n') {
  257.         s++;
  258.         XTERM(SEMINEW);
  259.     }
  260.     XTERM(tmp);
  261.     case '(':
  262.     tmp = *s++;
  263.     XTERM(tmp);
  264.     case '{':
  265.     case '[':
  266.     case ')':
  267.     case ']':
  268.     case '?':
  269.     case ':':
  270.     tmp = *s++;
  271.     XOP(tmp);
  272.     case 127:
  273.     s++;
  274.     XTERM('}');
  275.     case '}':
  276.     for (d = s + 1; isspace(*d); d++) ;
  277.     if (!*d)
  278.         s = d - 1;
  279.     *s = 127;
  280.     XTERM(';');
  281.     case ',':
  282.     tmp = *s++;
  283.     XTERM(tmp);
  284.     case '~':
  285.     s++;
  286.     yylval = string("~",1);
  287.     XTERM(MATCHOP);
  288.     case '+':
  289.     case '-':
  290.     if (s[1] == *s) {
  291.         s++;
  292.         if (*s++ == '+')
  293.         XTERM(INCR);
  294.         else
  295.         XTERM(DECR);
  296.     }
  297.     /* FALL THROUGH */
  298.     case '*':
  299.     case '%':
  300.     case '^':
  301.     tmp = *s++;
  302.     if (*s == '=') {
  303.         if (tmp == '^')
  304.         yylval = string("**=",3);
  305.         else
  306.         yylval = string(s-1,2);
  307.         s++;
  308.         XTERM(ASGNOP);
  309.     }
  310.     XTERM(tmp);
  311.     case '&':
  312.     s++;
  313.     tmp = *s++;
  314.     if (tmp == '&')
  315.         XTERM(ANDAND);
  316.     s--;
  317.     XTERM('&');
  318.     case '|':
  319.     s++;
  320.     tmp = *s++;
  321.     if (tmp == '|')
  322.         XTERM(OROR);
  323.     s--;
  324.     while (*s == ' ' || *s == '\t')
  325.         s++;
  326.     if (strnEQ(s,"getline",7))
  327.         XTERM('p');
  328.     else
  329.         XTERM('|');
  330.     case '=':
  331.     s++;
  332.     tmp = *s++;
  333.     if (tmp == '=') {
  334.         yylval = string("==",2);
  335.         XTERM(RELOP);
  336.     }
  337.     s--;
  338.     yylval = string("=",1);
  339.     XTERM(ASGNOP);
  340.     case '!':
  341.     s++;
  342.     tmp = *s++;
  343.     if (tmp == '=') {
  344.         yylval = string("!=",2);
  345.         XTERM(RELOP);
  346.     }
  347.     if (tmp == '~') {
  348.         yylval = string("!~",2);
  349.         XTERM(MATCHOP);
  350.     }
  351.     s--;
  352.     XTERM(NOT);
  353.     case '<':
  354.     s++;
  355.     tmp = *s++;
  356.     if (tmp == '=') {
  357.         yylval = string("<=",2);
  358.         XTERM(RELOP);
  359.     }
  360.     s--;
  361.     XTERM('<');
  362.     case '>':
  363.     s++;
  364.     tmp = *s++;
  365.     if (tmp == '>') {
  366.         yylval = string(">>",2);
  367.         XTERM(GRGR);
  368.     }
  369.     if (tmp == '=') {
  370.         yylval = string(">=",2);
  371.         XTERM(RELOP);
  372.     }
  373.     s--;
  374.     XTERM('>');
  375.  
  376. #define SNARFWORD \
  377.     d = tokenbuf; \
  378.     while (isalpha(*s) || isdigit(*s) || *s == '_') \
  379.         *d++ = *s++; \
  380.     *d = '\0'; \
  381.     d = tokenbuf; \
  382.     if (*s == '(') \
  383.         idtype = USERFUN; \
  384.     else \
  385.         idtype = VAR;
  386.  
  387.     case '$':
  388.     s++;
  389.     if (*s == '0') {
  390.         s++;
  391.         do_chop = TRUE;
  392.         need_entire = TRUE;
  393.         idtype = VAR;
  394.         ID("0");
  395.     }
  396.     do_split = TRUE;
  397.     if (isdigit(*s)) {
  398.         for (d = s; isdigit(*s); s++) ;
  399.         yylval = string(d,s-d);
  400.         tmp = atoi(d);
  401.         if (tmp > maxfld)
  402.         maxfld = tmp;
  403.         XOP(FIELD);
  404.     }
  405.     split_to_array = set_array_base = TRUE;
  406.     XOP(VFIELD);
  407.  
  408.     case '/':            /* may either be division or pattern */
  409.     if (expectterm) {
  410.         s = scanpat(s);
  411.         XTERM(REGEX);
  412.     }
  413.     tmp = *s++;
  414.     if (*s == '=') {
  415.         yylval = string("/=",2);
  416.         s++;
  417.         XTERM(ASGNOP);
  418.     }
  419.     XTERM(tmp);
  420.  
  421.     case '0': case '1': case '2': case '3': case '4':
  422.     case '5': case '6': case '7': case '8': case '9': case '.':
  423.     s = scannum(s);
  424.     XOP(NUMBER);
  425.     case '"':
  426.     s++;
  427.     s = cpy2(tokenbuf,s,s[-1]);
  428.     if (!*s)
  429.         fatal("String not terminated:\n%s",str_get(linestr));
  430.     s++;
  431.     yylval = string(tokenbuf,0);
  432.     XOP(STRING);
  433.  
  434.     case 'a': case 'A':
  435.     SNARFWORD;
  436.     if (strEQ(d,"ARGC"))
  437.         set_array_base = TRUE;
  438.     if (strEQ(d,"ARGV")) {
  439.         yylval=numary(string("ARGV",0));
  440.         XOP(VAR);
  441.     }
  442.     if (strEQ(d,"atan2")) {
  443.         yylval = OATAN2;
  444.         XTERM(FUNN);
  445.     }
  446.     ID(d);
  447.     case 'b': case 'B':
  448.     SNARFWORD;
  449.     if (strEQ(d,"break"))
  450.         XTERM(BREAK);
  451.     if (strEQ(d,"BEGIN"))
  452.         XTERM(BEGIN);
  453.     ID(d);
  454.     case 'c': case 'C':
  455.     SNARFWORD;
  456.     if (strEQ(d,"continue"))
  457.         XTERM(CONTINUE);
  458.     if (strEQ(d,"cos")) {
  459.         yylval = OCOS;
  460.         XTERM(FUN1);
  461.     }
  462.     if (strEQ(d,"close")) {
  463.         do_fancy_opens = 1;
  464.         yylval = OCLOSE;
  465.         XTERM(FUN1);
  466.     }
  467.     if (strEQ(d,"chdir"))
  468.         *d = toupper(*d);
  469.     else if (strEQ(d,"crypt"))
  470.         *d = toupper(*d);
  471.     else if (strEQ(d,"chop"))
  472.         *d = toupper(*d);
  473.     else if (strEQ(d,"chmod"))
  474.         *d = toupper(*d);
  475.     else if (strEQ(d,"chown"))
  476.         *d = toupper(*d);
  477.     ID(d);
  478.     case 'd': case 'D':
  479.     SNARFWORD;
  480.     if (strEQ(d,"do"))
  481.         XTERM(DO);
  482.     if (strEQ(d,"delete"))
  483.         XTERM(DELETE);
  484.     if (strEQ(d,"die"))
  485.         *d = toupper(*d);
  486.     ID(d);
  487.     case 'e': case 'E':
  488.     SNARFWORD;
  489.     if (strEQ(d,"END"))
  490.         XTERM(END);
  491.     if (strEQ(d,"else"))
  492.         XTERM(ELSE);
  493.     if (strEQ(d,"exit")) {
  494.         saw_line_op = TRUE;
  495.         XTERM(EXIT);
  496.     }
  497.     if (strEQ(d,"exp")) {
  498.         yylval = OEXP;
  499.         XTERM(FUN1);
  500.     }
  501.     if (strEQ(d,"elsif"))
  502.         *d = toupper(*d);
  503.     else if (strEQ(d,"eq"))
  504.         *d = toupper(*d);
  505.     else if (strEQ(d,"eval"))
  506.         *d = toupper(*d);
  507.     else if (strEQ(d,"eof"))
  508.         *d = toupper(*d);
  509.     else if (strEQ(d,"each"))
  510.         *d = toupper(*d);
  511.     else if (strEQ(d,"exec"))
  512.         *d = toupper(*d);
  513.     ID(d);
  514.     case 'f': case 'F':
  515.     SNARFWORD;
  516.     if (strEQ(d,"FS")) {
  517.         saw_FS++;
  518.         if (saw_FS == 1 && in_begin) {
  519.         for (d = s; *d && isspace(*d); d++) ;
  520.         if (*d == '=') {
  521.             for (d++; *d && isspace(*d); d++) ;
  522.             if (*d == '"' && d[2] == '"')
  523.             const_FS = d[1];
  524.         }
  525.         }
  526.         ID(tokenbuf);
  527.     }
  528.     if (strEQ(d,"for"))
  529.         XTERM(FOR);
  530.     else if (strEQ(d,"function"))
  531.         XTERM(FUNCTION);
  532.     if (strEQ(d,"FILENAME"))
  533.         d = "ARGV";
  534.     if (strEQ(d,"foreach"))
  535.         *d = toupper(*d);
  536.     else if (strEQ(d,"format"))
  537.         *d = toupper(*d);
  538.     else if (strEQ(d,"fork"))
  539.         *d = toupper(*d);
  540.     else if (strEQ(d,"fh"))
  541.         *d = toupper(*d);
  542.     ID(d);
  543.     case 'g': case 'G':
  544.     SNARFWORD;
  545.     if (strEQ(d,"getline"))
  546.         XTERM(GETLINE);
  547.     if (strEQ(d,"gsub"))
  548.         XTERM(GSUB);
  549.     if (strEQ(d,"ge"))
  550.         *d = toupper(*d);
  551.     else if (strEQ(d,"gt"))
  552.         *d = toupper(*d);
  553.     else if (strEQ(d,"goto"))
  554.         *d = toupper(*d);
  555.     else if (strEQ(d,"gmtime"))
  556.         *d = toupper(*d);
  557.     ID(d);
  558.     case 'h': case 'H':
  559.     SNARFWORD;
  560.     if (strEQ(d,"hex"))
  561.         *d = toupper(*d);
  562.     ID(d);
  563.     case 'i': case 'I':
  564.     SNARFWORD;
  565.     if (strEQ(d,"if"))
  566.         XTERM(IF);
  567.     if (strEQ(d,"in"))
  568.         XTERM(IN);
  569.     if (strEQ(d,"index")) {
  570.         set_array_base = TRUE;
  571.         XTERM(INDEX);
  572.     }
  573.     if (strEQ(d,"int")) {
  574.         yylval = OINT;
  575.         XTERM(FUN1);
  576.     }
  577.     ID(d);
  578.     case 'j': case 'J':
  579.     SNARFWORD;
  580.     if (strEQ(d,"join"))
  581.         *d = toupper(*d);
  582.     ID(d);
  583.     case 'k': case 'K':
  584.     SNARFWORD;
  585.     if (strEQ(d,"keys"))
  586.         *d = toupper(*d);
  587.     else if (strEQ(d,"kill"))
  588.         *d = toupper(*d);
  589.     ID(d);
  590.     case 'l': case 'L':
  591.     SNARFWORD;
  592.     if (strEQ(d,"length")) {
  593.         yylval = OLENGTH;
  594.         XTERM(FUN1);
  595.     }
  596.     if (strEQ(d,"log")) {
  597.         yylval = OLOG;
  598.         XTERM(FUN1);
  599.     }
  600.     if (strEQ(d,"last"))
  601.         *d = toupper(*d);
  602.     else if (strEQ(d,"local"))
  603.         *d = toupper(*d);
  604.     else if (strEQ(d,"lt"))
  605.         *d = toupper(*d);
  606.     else if (strEQ(d,"le"))
  607.         *d = toupper(*d);
  608.     else if (strEQ(d,"locatime"))
  609.         *d = toupper(*d);
  610.     else if (strEQ(d,"link"))
  611.         *d = toupper(*d);
  612.     ID(d);
  613.     case 'm': case 'M':
  614.     SNARFWORD;
  615.     if (strEQ(d,"match")) {
  616.         set_array_base = TRUE;
  617.         XTERM(MATCH);
  618.     }
  619.     if (strEQ(d,"m"))
  620.         *d = toupper(*d);
  621.     ID(d);
  622.     case 'n': case 'N':
  623.     SNARFWORD;
  624.     if (strEQ(d,"NF"))
  625.         do_chop = do_split = split_to_array = set_array_base = TRUE;
  626.     if (strEQ(d,"next")) {
  627.         saw_line_op = TRUE;
  628.         XTERM(NEXT);
  629.     }
  630.     if (strEQ(d,"ne"))
  631.         *d = toupper(*d);
  632.     ID(d);
  633.     case 'o': case 'O':
  634.     SNARFWORD;
  635.     if (strEQ(d,"ORS")) {
  636.         saw_ORS = TRUE;
  637.         d = "\\";
  638.     }
  639.     if (strEQ(d,"OFS")) {
  640.         saw_OFS = TRUE;
  641.         d = ",";
  642.     }
  643.     if (strEQ(d,"OFMT")) {
  644.         d = "#";
  645.     }
  646.     if (strEQ(d,"open"))
  647.         *d = toupper(*d);
  648.     else if (strEQ(d,"ord"))
  649.         *d = toupper(*d);
  650.     else if (strEQ(d,"oct"))
  651.         *d = toupper(*d);
  652.     ID(d);
  653.     case 'p': case 'P':
  654.     SNARFWORD;
  655.     if (strEQ(d,"print")) {
  656.         XTERM(PRINT);
  657.     }
  658.     if (strEQ(d,"printf")) {
  659.         XTERM(PRINTF);
  660.     }
  661.     if (strEQ(d,"push"))
  662.         *d = toupper(*d);
  663.     else if (strEQ(d,"pop"))
  664.         *d = toupper(*d);
  665.     ID(d);
  666.     case 'q': case 'Q':
  667.     SNARFWORD;
  668.     ID(d);
  669.     case 'r': case 'R':
  670.     SNARFWORD;
  671.     if (strEQ(d,"RS")) {
  672.         d = "/";
  673.         saw_RS = TRUE;
  674.     }
  675.     if (strEQ(d,"rand")) {
  676.         yylval = ORAND;
  677.         XTERM(FUN1);
  678.     }
  679.     if (strEQ(d,"return"))
  680.         XTERM(RET);
  681.     if (strEQ(d,"reset"))
  682.         *d = toupper(*d);
  683.     else if (strEQ(d,"redo"))
  684.         *d = toupper(*d);
  685.     else if (strEQ(d,"rename"))
  686.         *d = toupper(*d);
  687.     ID(d);
  688.     case 's': case 'S':
  689.     SNARFWORD;
  690.     if (strEQ(d,"split")) {
  691.         set_array_base = TRUE;
  692.         XOP(SPLIT);
  693.     }
  694.     if (strEQ(d,"substr")) {
  695.         set_array_base = TRUE;
  696.         XTERM(SUBSTR);
  697.     }
  698.     if (strEQ(d,"sub"))
  699.         XTERM(SUB);
  700.     if (strEQ(d,"sprintf"))
  701.         XTERM(SPRINTF);
  702.     if (strEQ(d,"sqrt")) {
  703.         yylval = OSQRT;
  704.         XTERM(FUN1);
  705.     }
  706.     if (strEQ(d,"SUBSEP")) {
  707.         d = ";";
  708.     }
  709.     if (strEQ(d,"sin")) {
  710.         yylval = OSIN;
  711.         XTERM(FUN1);
  712.     }
  713.     if (strEQ(d,"srand")) {
  714.         yylval = OSRAND;
  715.         XTERM(FUN1);
  716.     }
  717.     if (strEQ(d,"system")) {
  718.         yylval = OSYSTEM;
  719.         XTERM(FUN1);
  720.     }
  721.     if (strEQ(d,"s"))
  722.         *d = toupper(*d);
  723.     else if (strEQ(d,"shift"))
  724.         *d = toupper(*d);
  725.     else if (strEQ(d,"select"))
  726.         *d = toupper(*d);
  727.     else if (strEQ(d,"seek"))
  728.         *d = toupper(*d);
  729.     else if (strEQ(d,"stat"))
  730.         *d = toupper(*d);
  731.     else if (strEQ(d,"study"))
  732.         *d = toupper(*d);
  733.     else if (strEQ(d,"sleep"))
  734.         *d = toupper(*d);
  735.     else if (strEQ(d,"symlink"))
  736.         *d = toupper(*d);
  737.     else if (strEQ(d,"sort"))
  738.         *d = toupper(*d);
  739.     ID(d);
  740.     case 't': case 'T':
  741.     SNARFWORD;
  742.     if (strEQ(d,"tr"))
  743.         *d = toupper(*d);
  744.     else if (strEQ(d,"tell"))
  745.         *d = toupper(*d);
  746.     else if (strEQ(d,"time"))
  747.         *d = toupper(*d);
  748.     else if (strEQ(d,"times"))
  749.         *d = toupper(*d);
  750.     ID(d);
  751.     case 'u': case 'U':
  752.     SNARFWORD;
  753.     if (strEQ(d,"until"))
  754.         *d = toupper(*d);
  755.     else if (strEQ(d,"unless"))
  756.         *d = toupper(*d);
  757.     else if (strEQ(d,"umask"))
  758.         *d = toupper(*d);
  759.     else if (strEQ(d,"unshift"))
  760.         *d = toupper(*d);
  761.     else if (strEQ(d,"unlink"))
  762.         *d = toupper(*d);
  763.     else if (strEQ(d,"utime"))
  764.         *d = toupper(*d);
  765.     ID(d);
  766.     case 'v': case 'V':
  767.     SNARFWORD;
  768.     if (strEQ(d,"values"))
  769.         *d = toupper(*d);
  770.     ID(d);
  771.     case 'w': case 'W':
  772.     SNARFWORD;
  773.     if (strEQ(d,"while"))
  774.         XTERM(WHILE);
  775.     if (strEQ(d,"write"))
  776.         *d = toupper(*d);
  777.     else if (strEQ(d,"wait"))
  778.         *d = toupper(*d);
  779.     ID(d);
  780.     case 'x': case 'X':
  781.     SNARFWORD;
  782.     if (strEQ(d,"x"))
  783.         *d = toupper(*d);
  784.     ID(d);
  785.     case 'y': case 'Y':
  786.     SNARFWORD;
  787.     if (strEQ(d,"y"))
  788.         *d = toupper(*d);
  789.     ID(d);
  790.     case 'z': case 'Z':
  791.     SNARFWORD;
  792.     ID(d);
  793.     }
  794. }
  795.  
  796. char *
  797. scanpat(s)
  798. register char *s;
  799. {
  800.     register char *d;
  801.  
  802.     switch (*s++) {
  803.     case '/':
  804.     break;
  805.     default:
  806.     fatal("Search pattern not found:\n%s",str_get(linestr));
  807.     }
  808.  
  809.     d = tokenbuf;
  810.     for (; *s; s++,d++) {
  811.     if (*s == '\\') {
  812.         if (s[1] == '/')
  813.         *d++ = *s++;
  814.         else if (s[1] == '\\')
  815.         *d++ = *s++;
  816.         else if (s[1] == '[')
  817.         *d++ = *s++;
  818.     }
  819.     else if (*s == '[') {
  820.         *d++ = *s++;
  821.         do {
  822.         if (*s == '\\' && s[1])
  823.             *d++ = *s++;
  824.         if (*s == '/' || (*s == '-' && s[1] == ']'))
  825.             *d++ = '\\';
  826.         *d++ = *s++;
  827.         } while (*s && *s != ']');
  828.     }
  829.     else if (*s == '/')
  830.         break;
  831.     *d = *s;
  832.     }
  833.     *d = '\0';
  834.  
  835.     if (!*s)
  836.     fatal("Search pattern not terminated:\n%s",str_get(linestr));
  837.     s++;
  838.     yylval = string(tokenbuf,0);
  839.     return s;
  840. }
  841.  
  842. yyerror(s)
  843. char *s;
  844. {
  845.     fprintf(stderr,"%s in file %s at line %d\n",
  846.       s,filename,line);
  847. }
  848.  
  849. char *
  850. scannum(s)
  851. register char *s;
  852. {
  853.     register char *d;
  854.  
  855.     switch (*s) {
  856.     case '1': case '2': case '3': case '4': case '5':
  857.     case '6': case '7': case '8': case '9': case '0' : case '.':
  858.     d = tokenbuf;
  859.     while (isdigit(*s)) {
  860.         *d++ = *s++;
  861.     }
  862.     if (*s == '.') {
  863.         if (isdigit(s[1])) {
  864.         *d++ = *s++;
  865.         while (isdigit(*s)) {
  866.             *d++ = *s++;
  867.         }
  868.         }
  869.         else
  870.         s++;
  871.     }
  872.     if (index("eE",*s) && index("+-0123456789",s[1])) {
  873.         *d++ = *s++;
  874.         if (*s == '+' || *s == '-')
  875.         *d++ = *s++;
  876.         while (isdigit(*s))
  877.         *d++ = *s++;
  878.     }
  879.     *d = '\0';
  880.     yylval = string(tokenbuf,0);
  881.     break;
  882.     }
  883.     return s;
  884. }
  885.  
  886. string(ptr,len)
  887. char *ptr;
  888. {
  889.     int retval = mop;
  890.  
  891.     ops[mop++].ival = OSTRING + (1<<8);
  892.     if (!len)
  893.     len = strlen(ptr);
  894.     ops[mop].cval = safemalloc(len+1);
  895.     strncpy(ops[mop].cval,ptr,len);
  896.     ops[mop++].cval[len] = '\0';
  897.     if (mop >= OPSMAX)
  898.     fatal("Recompile a2p with larger OPSMAX\n");
  899.     return retval;
  900. }
  901.  
  902. oper0(type)
  903. int type;
  904. {
  905.     int retval = mop;
  906.  
  907.     if (type > 255)
  908.     fatal("type > 255 (%d)\n",type);
  909.     ops[mop++].ival = type;
  910.     if (mop >= OPSMAX)
  911.     fatal("Recompile a2p with larger OPSMAX\n");
  912.     return retval;
  913. }
  914.  
  915. oper1(type,arg1)
  916. int type;
  917. int arg1;
  918. {
  919.     int retval = mop;
  920.  
  921.     if (type > 255)
  922.     fatal("type > 255 (%d)\n",type);
  923.     ops[mop++].ival = type + (1<<8);
  924.     ops[mop++].ival = arg1;
  925.     if (mop >= OPSMAX)
  926.     fatal("Recompile a2p with larger OPSMAX\n");
  927.     return retval;
  928. }
  929.  
  930. oper2(type,arg1,arg2)
  931. int type;
  932. int arg1;
  933. int arg2;
  934. {
  935.     int retval = mop;
  936.  
  937.     if (type > 255)
  938.     fatal("type > 255 (%d)\n",type);
  939.     ops[mop++].ival = type + (2<<8);
  940.     ops[mop++].ival = arg1;
  941.     ops[mop++].ival = arg2;
  942.     if (mop >= OPSMAX)
  943.     fatal("Recompile a2p with larger OPSMAX\n");
  944.     return retval;
  945. }
  946.  
  947. oper3(type,arg1,arg2,arg3)
  948. int type;
  949. int arg1;
  950. int arg2;
  951. int arg3;
  952. {
  953.     int retval = mop;
  954.  
  955.     if (type > 255)
  956.     fatal("type > 255 (%d)\n",type);
  957.     ops[mop++].ival = type + (3<<8);
  958.     ops[mop++].ival = arg1;
  959.     ops[mop++].ival = arg2;
  960.     ops[mop++].ival = arg3;
  961.     if (mop >= OPSMAX)
  962.     fatal("Recompile a2p with larger OPSMAX\n");
  963.     return retval;
  964. }
  965.  
  966. oper4(type,arg1,arg2,arg3,arg4)
  967. int type;
  968. int arg1;
  969. int arg2;
  970. int arg3;
  971. int arg4;
  972. {
  973.     int retval = mop;
  974.  
  975.     if (type > 255)
  976.     fatal("type > 255 (%d)\n",type);
  977.     ops[mop++].ival = type + (4<<8);
  978.     ops[mop++].ival = arg1;
  979.     ops[mop++].ival = arg2;
  980.     ops[mop++].ival = arg3;
  981.     ops[mop++].ival = arg4;
  982.     if (mop >= OPSMAX)
  983.     fatal("Recompile a2p with larger OPSMAX\n");
  984.     return retval;
  985. }
  986.  
  987. oper5(type,arg1,arg2,arg3,arg4,arg5)
  988. int type;
  989. int arg1;
  990. int arg2;
  991. int arg3;
  992. int arg4;
  993. int arg5;
  994. {
  995.     int retval = mop;
  996.  
  997.     if (type > 255)
  998.     fatal("type > 255 (%d)\n",type);
  999.     ops[mop++].ival = type + (5<<8);
  1000.     ops[mop++].ival = arg1;
  1001.     ops[mop++].ival = arg2;
  1002.     ops[mop++].ival = arg3;
  1003.     ops[mop++].ival = arg4;
  1004.     ops[mop++].ival = arg5;
  1005.     if (mop >= OPSMAX)
  1006.     fatal("Recompile a2p with larger OPSMAX\n");
  1007.     return retval;
  1008. }
  1009.  
  1010. int depth = 0;
  1011.  
  1012. dump(branch)
  1013. int branch;
  1014. {
  1015.     register int type;
  1016.     register int len;
  1017.     register int i;
  1018.  
  1019.     type = ops[branch].ival;
  1020.     len = type >> 8;
  1021.     type &= 255;
  1022.     for (i=depth; i; i--)
  1023.     printf(" ");
  1024.     if (type == OSTRING) {
  1025.     printf("%-5d\"%s\"\n",branch,ops[branch+1].cval);
  1026.     }
  1027.     else {
  1028.     printf("(%-5d%s %d\n",branch,opname[type],len);
  1029.     depth++;
  1030.     for (i=1; i<=len; i++)
  1031.         dump(ops[branch+i].ival);
  1032.     depth--;
  1033.     for (i=depth; i; i--)
  1034.         printf(" ");
  1035.     printf(")\n");
  1036.     }
  1037. }
  1038.  
  1039. bl(arg,maybe)
  1040. int arg;
  1041. int maybe;
  1042. {
  1043.     if (!arg)
  1044.     return 0;
  1045.     else if ((ops[arg].ival & 255) != OBLOCK)
  1046.     return oper2(OBLOCK,arg,maybe);
  1047.     else if ((ops[arg].ival >> 8) < 2)
  1048.     return oper2(OBLOCK,ops[arg+1].ival,maybe);
  1049.     else
  1050.     return arg;
  1051. }
  1052.  
  1053. fixup(str)
  1054. STR *str;
  1055. {
  1056.     register char *s;
  1057.     register char *t;
  1058.  
  1059.     for (s = str->str_ptr; *s; s++) {
  1060.     if (*s == ';' && s[1] == ' ' && s[2] == '\n') {
  1061.         strcpy(s+1,s+2);
  1062.         s++;
  1063.     }
  1064.     else if (*s == '\n') {
  1065.         for (t = s+1; isspace(*t & 127); t++) ;
  1066.         t--;
  1067.         while (isspace(*t & 127) && *t != '\n') t--;
  1068.         if (*t == '\n' && t-s > 1) {
  1069.         if (s[-1] == '{')
  1070.             s--;
  1071.         strcpy(s+1,t);
  1072.         }
  1073.         s++;
  1074.     }
  1075.     }
  1076. }
  1077.  
  1078. putlines(str)
  1079. STR *str;
  1080. {
  1081.     register char *d, *s, *t, *e;
  1082.     register int pos, newpos;
  1083.  
  1084.     d = tokenbuf;
  1085.     pos = 0;
  1086.     for (s = str->str_ptr; *s; s++) {
  1087.     *d++ = *s;
  1088.     pos++;
  1089.     if (*s == '\n') {
  1090.         *d = '\0';
  1091.         d = tokenbuf;
  1092.         pos = 0;
  1093.         putone();
  1094.     }
  1095.     else if (*s == '\t')
  1096.         pos += 7;
  1097.     if (pos > 78) {        /* split a long line? */
  1098.         *d-- = '\0';
  1099.         newpos = 0;
  1100.         for (t = tokenbuf; isspace(*t & 127); t++) {
  1101.         if (*t == '\t')
  1102.             newpos += 8;
  1103.         else
  1104.             newpos += 1;
  1105.         }
  1106.         e = d;
  1107.         while (d > tokenbuf && (*d != ' ' || d[-1] != ';'))
  1108.         d--;
  1109.         if (d < t+10) {
  1110.         d = e;
  1111.         while (d > tokenbuf &&
  1112.           (*d != ' ' || d[-1] != '|' || d[-2] != '|') )
  1113.             d--;
  1114.         }
  1115.         if (d < t+10) {
  1116.         d = e;
  1117.         while (d > tokenbuf &&
  1118.           (*d != ' ' || d[-1] != '&' || d[-2] != '&') )
  1119.             d--;
  1120.         }
  1121.         if (d < t+10) {
  1122.         d = e;
  1123.         while (d > tokenbuf && (*d != ' ' || d[-1] != ','))
  1124.             d--;
  1125.         }
  1126.         if (d < t+10) {
  1127.         d = e;
  1128.         while (d > tokenbuf && *d != ' ')
  1129.             d--;
  1130.         }
  1131.         if (d > t+3) {
  1132.                 char save[2048];
  1133.                 strcpy(save, d);
  1134.         *d = '\n';
  1135.                 d[1] = '\0';
  1136.         putone();
  1137.         putchar('\n');
  1138.         if (d[-1] != ';' && !(newpos % 4)) {
  1139.             *t++ = ' ';
  1140.             *t++ = ' ';
  1141.             newpos += 2;
  1142.         }
  1143.         strcpy(t,save+1);
  1144.         newpos += strlen(t);
  1145.         d = t + strlen(t);
  1146.         pos = newpos;
  1147.         }
  1148.         else
  1149.         d = e + 1;
  1150.     }
  1151.     }
  1152. }
  1153.  
  1154. putone()
  1155. {
  1156.     register char *t;
  1157.  
  1158.     for (t = tokenbuf; *t; t++) {
  1159.     *t &= 127;
  1160.     if (*t == 127) {
  1161.         *t = ' ';
  1162.         strcpy(t+strlen(t)-1, "\t#???\n");
  1163.         checkers++;
  1164.     }
  1165.     }
  1166.     t = tokenbuf;
  1167.     if (*t == '#') {
  1168.     if (strnEQ(t,"#!/bin/awk",10) || strnEQ(t,"#! /bin/awk",11))
  1169.         return;
  1170.     if (strnEQ(t,"#!/usr/bin/awk",14) || strnEQ(t,"#! /usr/bin/awk",15))
  1171.         return;
  1172.     }
  1173.     fputs(tokenbuf,stdout);
  1174. }
  1175.  
  1176. numary(arg)
  1177. int arg;
  1178. {
  1179.     STR *key;
  1180.     int dummy;
  1181.  
  1182.     key = walk(0,0,arg,&dummy,P_MIN);
  1183.     str_cat(key,"[]");
  1184.     hstore(symtab,key->str_ptr,str_make("1"));
  1185.     str_free(key);
  1186.     set_array_base = TRUE;
  1187.     return arg;
  1188. }
  1189.  
  1190. rememberargs(arg)
  1191. int arg;
  1192. {
  1193.     int type;
  1194.     STR *str;
  1195.  
  1196.     if (!arg)
  1197.     return arg;
  1198.     type = ops[arg].ival & 255;
  1199.     if (type == OCOMMA) {
  1200.     rememberargs(ops[arg+1].ival);
  1201.     rememberargs(ops[arg+3].ival);
  1202.     }
  1203.     else if (type == OVAR) {
  1204.     str = str_new(0);
  1205.     hstore(curarghash,ops[ops[arg+1].ival+1].cval,str);
  1206.     }
  1207.     else
  1208.     fatal("panic: unknown argument type %d, line %d\n",type,line);
  1209.     return arg;
  1210. }
  1211.  
  1212. aryrefarg(arg)
  1213. int arg;
  1214. {
  1215.     int type = ops[arg].ival & 255;
  1216.     STR *str;
  1217.  
  1218.     if (type != OSTRING)
  1219.     fatal("panic: aryrefarg %d, line %d\n",type,line);
  1220.     str = hfetch(curarghash,ops[arg+1].cval);
  1221.     if (str)
  1222.     str_set(str,"*");
  1223.     return arg;
  1224. }
  1225.  
  1226. fixfargs(name,arg,prevargs)
  1227. int name;
  1228. int arg;
  1229. int prevargs;
  1230. {
  1231.     int type;
  1232.     STR *str;
  1233.     int numargs;
  1234.  
  1235.     if (!arg)
  1236.     return prevargs;
  1237.     type = ops[arg].ival & 255;
  1238.     if (type == OCOMMA) {
  1239.     numargs = fixfargs(name,ops[arg+1].ival,prevargs);
  1240.     numargs = fixfargs(name,ops[arg+3].ival,numargs);
  1241.     }
  1242.     else if (type == OVAR) {
  1243.     str = hfetch(curarghash,ops[ops[arg+1].ival+1].cval);
  1244.     if (strEQ(str_get(str),"*")) {
  1245.         char tmpbuf[128];
  1246.  
  1247.         str_set(str,"");        /* in case another routine has this */
  1248.         ops[arg].ival &= ~255;
  1249.         ops[arg].ival |= OSTAR;
  1250.         sprintf(tmpbuf,"%s:%d",ops[name+1].cval,prevargs);
  1251.         fprintf(stderr,"Adding %s\n",tmpbuf);
  1252.         str = str_new(0);
  1253.         str_set(str,"*");
  1254.         hstore(curarghash,tmpbuf,str);
  1255.     }
  1256.     numargs = prevargs + 1;
  1257.     }
  1258.     else
  1259.     fatal("panic: unknown argument type %d, arg %d, line %d\n",
  1260.       type,prevargs+1,line);
  1261.     return numargs;
  1262. }
  1263.  
  1264. fixrargs(name,arg,prevargs)
  1265. char *name;
  1266. int arg;
  1267. int prevargs;
  1268. {
  1269.     int type;
  1270.     STR *str;
  1271.     int numargs;
  1272.  
  1273.     if (!arg)
  1274.     return prevargs;
  1275.     type = ops[arg].ival & 255;
  1276.     if (type == OCOMMA) {
  1277.     numargs = fixrargs(name,ops[arg+1].ival,prevargs);
  1278.     numargs = fixrargs(name,ops[arg+3].ival,numargs);
  1279.     }
  1280.     else {
  1281.     char tmpbuf[128];
  1282.  
  1283.     sprintf(tmpbuf,"%s:%d",name,prevargs);
  1284.     str = hfetch(curarghash,tmpbuf);
  1285.     if (str && strEQ(str->str_ptr,"*")) {
  1286.         if (type == OVAR || type == OSTAR) {
  1287.         ops[arg].ival &= ~255;
  1288.         ops[arg].ival |= OSTAR;
  1289.         }
  1290.         else
  1291.         fatal("Can't pass expression by reference as arg %d of %s\n",
  1292.             prevargs+1, name);
  1293.     }
  1294.     numargs = prevargs + 1;
  1295.     }
  1296.     return numargs;
  1297. }
  1298.  
  1299.