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