c785828712ae182af9d03644ff3e3f9a1d041c8b
[p5sagit/p5-mst-13.2.git] / x2p / a2py.c
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