File Coverage

x2p/a2py.c
Criterion Covered Total %
statement 0 769 0.0
branch n/a
condition n/a
subroutine n/a
total 0 769 0.0


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