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