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