3 * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
4 * 2000, 2001, 2002, by Larry Wall and others
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.
10 #if defined(OS2) || defined(WIN32) || defined(NETWARE)
15 #include "../netware/clibstuf.h"
17 #include "../patchlevel.h"
27 int oper1(int type, int arg1);
28 int oper2(int type, int arg1, int arg2);
29 int oper3(int type, int arg1, int arg2, int arg3);
30 int oper4(int type, int arg1, int arg2, int arg3, int arg4);
31 int oper5(int type, int arg1, int arg2, int arg3, int arg4, int arg5);
32 STR *walk(int useval, int level, register int node, int *numericptr, int minprec);
34 char *savestr(char *str);
35 char *cpy2(register char *to, register char *from, register int delim);
38 #if defined(OS2) || defined(WIN32) || defined(NETWARE)
39 static void usage(void);
44 printf("\nThis is the AWK to PERL translator, revision %d.0, version %d\n", PERL_REVISION, PERL_VERSION);
45 printf("\nUsage: %s [-D<number>] [-F<char>] [-n<fieldlist>] [-<number>] filename\n", myname);
46 printf("\n -D<number> sets debugging flags."
47 "\n -F<character> the awk script to translate is always invoked with"
49 "\n -n<fieldlist> specifies the names of the input fields if input does"
50 "\n not have to be split into an array."
51 "\n -<number> causes a2p to assume that input will always have that"
58 #pragma message disable (mainparm) /* We have the envp in main(). */
62 main(register int argc, register const char **argv, register const char **env)
70 fnInitGpfGlobals(); /* For importing the CLIB calls in place of Watcom calls */
74 linestr = str_new(80);
75 str = str_new(0); /* first used for -I flags */
76 for (argc--,argv++; argc; argc--,argv++) {
77 if (argv[0][0] != '-' || !argv[0][1])
82 debug = atoi(argv[0]+2);
84 yydebug = (debug & 1);
88 case '0': case '1': case '2': case '3': case '4':
89 case '5': case '6': case '7': case '8': case '9':
90 maxfld = atoi(argv[0]+1);
97 namelist = savestr(argv[0]+2);
108 #if defined(OS2) || defined(WIN32) || defined(NETWARE)
109 fprintf(stderr, "Unrecognized switch: %s\n",argv[0]);
112 fatal("Unrecognized switch: %s\n",argv[0]);
120 if (argv[0] == NULL) {
121 #if defined(OS2) || defined(WIN32) || defined(NETWARE)
122 if ( isatty(fileno(stdin)) )
127 filename = savestr(argv[0]);
129 if (strEQ(filename,"-"))
134 rsfp = fopen(argv[0],"r");
136 fatal("Awk script \"%s\" doesn't seem to exist.\n",filename);
140 bufptr = str_get(linestr);
144 /* now parse the report spec */
147 fatal("Translation aborted due to syntax errors.\n");
157 printf("%d\t%d\t%d\t%-10s",i++,type,len,opname[type]);
159 printf("\t\"%s\"\n",ops[i].cval),i++;
162 printf("\t%d",ops[i].ival),i++;
172 /* first pass to look for numeric variables */
174 prewalk(0,0,root,&i);
176 /* second pass to produce new program */
178 tmpstr = walk(0,0,root,&i,P_MIN);
179 str = str_make(STARTPERL);
180 str_cat(str, "\neval 'exec ");
182 str_cat(str, "/perl -S $0 ${1+\"$@\"}'\n\
183 if $running_under_some_shell;\n\
184 # this emulates #! processing on NIH machines.\n\
185 # (remove #! line above if indigestible)\n\n");
187 "eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;\n");
189 " # process any FOO=bar switches\n\n");
190 if (do_opens && opens) {
195 str_scat(str,tmpstr);
204 "Please check my work on the %d line%s I've marked with \"#???\".\n",
205 checkers, checkers == 1 ? "" : "s" );
207 "The operation I've selected may be wrong for the operand types.\n");
210 /* by ANSI specs return is needed. This also shuts up VC++ and his warnings */
214 #define RETURN(retval) return (bufptr = s,retval)
215 #define XTERM(retval) return (expectterm = TRUE,bufptr = s,retval)
216 #define XOP(retval) return (expectterm = FALSE,bufptr = s,retval)
217 #define ID(x) return (yylval=string(x,0),expectterm = FALSE,bufptr = s,idtype)
224 register char *s = bufptr;
232 fprintf(stderr,"Tokener at %s",s);
234 fprintf(stderr,"Tokener at %s\n",s);
240 "Unrecognized character %c in file %s line %d--ignoring.\n",
245 if (*s && *s != '\n') {
246 yyerror("Ignoring spurious backslash");
251 s = str_get(linestr);
256 if ((s = str_gets(linestr, rsfp)) == NULL) {
260 s = str_get(linestr);
271 yylval = string(s,0);
300 for (d = s + 1; isSPACE(*d); d++) ;
310 yylval = string("~",1);
328 yylval = string("**=",3);
330 yylval = string(s-1,2);
348 while (*s == ' ' || *s == '\t')
350 if (strnEQ(s,"getline",7))
358 yylval = string("==",2);
362 yylval = string("=",1);
368 yylval = string("!=",2);
372 yylval = string("!~",2);
381 yylval = string("<=",2);
390 yylval = string(">>",2);
394 yylval = string(">=",2);
402 while (isALPHA(*s) || isDIGIT(*s) || *s == '_') \
422 for (d = s; isDIGIT(*s); s++) ;
423 yylval = string(d,s-d);
429 for (d = s; isALPHA(*s) || isDIGIT(*s) || *s == '_'; )
431 split_to_array = set_array_base = TRUE;
434 yylval = string(d,s-d);
439 case '/': /* may either be division or pattern */
446 yylval = string("/=",2);
452 case '0': case '1': case '2': case '3': case '4':
453 case '5': case '6': case '7': case '8': case '9': case '.':
458 s = cpy2(tokenbuf,s,s[-1]);
460 fatal("String not terminated:\n%s",str_get(linestr));
462 yylval = string(tokenbuf,0);
468 set_array_base = TRUE;
469 if (strEQ(d,"ARGV")) {
470 yylval=numary(string("ARGV",0));
473 if (strEQ(d,"atan2")) {
480 if (strEQ(d,"break"))
482 if (strEQ(d,"BEGIN"))
487 if (strEQ(d,"continue"))
489 if (strEQ(d,"cos")) {
493 if (strEQ(d,"close")) {
498 if (strEQ(d,"chdir"))
500 else if (strEQ(d,"crypt"))
502 else if (strEQ(d,"chop"))
504 else if (strEQ(d,"chmod"))
506 else if (strEQ(d,"chown"))
513 if (strEQ(d,"delete"))
524 if (strEQ(d,"exit")) {
528 if (strEQ(d,"exp")) {
532 if (strEQ(d,"elsif"))
534 else if (strEQ(d,"eq"))
536 else if (strEQ(d,"eval"))
538 else if (strEQ(d,"eof"))
540 else if (strEQ(d,"each"))
542 else if (strEQ(d,"exec"))
549 if (saw_FS == 1 && in_begin) {
550 for (d = s; *d && isSPACE(*d); d++) ;
552 for (d++; *d && isSPACE(*d); d++) ;
553 if (*d == '"' && d[2] == '"')
561 else if (strEQ(d,"function"))
563 if (strEQ(d,"FILENAME"))
565 if (strEQ(d,"foreach"))
567 else if (strEQ(d,"format"))
569 else if (strEQ(d,"fork"))
571 else if (strEQ(d,"fh"))
576 if (strEQ(d,"getline"))
582 else if (strEQ(d,"gt"))
584 else if (strEQ(d,"goto"))
586 else if (strEQ(d,"gmtime"))
600 if (strEQ(d,"index")) {
601 set_array_base = TRUE;
604 if (strEQ(d,"int")) {
618 else if (strEQ(d,"kill"))
623 if (strEQ(d,"length")) {
627 if (strEQ(d,"log")) {
633 else if (strEQ(d,"local"))
635 else if (strEQ(d,"lt"))
637 else if (strEQ(d,"le"))
639 else if (strEQ(d,"locatime"))
641 else if (strEQ(d,"link"))
646 if (strEQ(d,"match")) {
647 set_array_base = TRUE;
656 do_chop = do_split = split_to_array = set_array_base = TRUE;
657 if (strEQ(d,"next")) {
666 if (strEQ(d,"ORS")) {
670 if (strEQ(d,"OFS")) {
674 if (strEQ(d,"OFMT")) {
679 else if (strEQ(d,"ord"))
681 else if (strEQ(d,"oct"))
686 if (strEQ(d,"print")) {
689 if (strEQ(d,"printf")) {
694 else if (strEQ(d,"pop"))
706 if (strEQ(d,"rand")) {
710 if (strEQ(d,"return"))
712 if (strEQ(d,"reset"))
714 else if (strEQ(d,"redo"))
716 else if (strEQ(d,"rename"))
721 if (strEQ(d,"split")) {
722 set_array_base = TRUE;
725 if (strEQ(d,"substr")) {
726 set_array_base = TRUE;
731 if (strEQ(d,"sprintf")) {
732 /* In old awk, { print sprintf("str%sg"),"in" } prints
733 * "string"; in new awk, "in" is not considered an argument to
734 * sprintf, so the statement breaks. To support both, the
735 * grammar treats arguments to SPRINTF_OLD like old awk,
736 * SPRINTF_NEW like new. Here we return the appropriate one.
738 XTERM(old_awk ? SPRINTF_OLD : SPRINTF_NEW);
740 if (strEQ(d,"sqrt")) {
744 if (strEQ(d,"SUBSEP")) {
747 if (strEQ(d,"sin")) {
751 if (strEQ(d,"srand")) {
755 if (strEQ(d,"system")) {
761 else if (strEQ(d,"shift"))
763 else if (strEQ(d,"select"))
765 else if (strEQ(d,"seek"))
767 else if (strEQ(d,"stat"))
769 else if (strEQ(d,"study"))
771 else if (strEQ(d,"sleep"))
773 else if (strEQ(d,"symlink"))
775 else if (strEQ(d,"sort"))
782 else if (strEQ(d,"tell"))
784 else if (strEQ(d,"time"))
786 else if (strEQ(d,"times"))
791 if (strEQ(d,"until"))
793 else if (strEQ(d,"unless"))
795 else if (strEQ(d,"umask"))
797 else if (strEQ(d,"unshift"))
799 else if (strEQ(d,"unlink"))
801 else if (strEQ(d,"utime"))
806 if (strEQ(d,"values"))
811 if (strEQ(d,"while"))
813 if (strEQ(d,"write"))
815 else if (strEQ(d,"wait"))
835 scanpat(register char *s)
843 fatal("Search pattern not found:\n%s",str_get(linestr));
847 for (; *s; s++,d++) {
851 else if (s[1] == '\\')
853 else if (s[1] == '[')
856 else if (*s == '[') {
859 if (*s == '\\' && s[1])
861 if (*s == '/' || (*s == '-' && s[1] == ']'))
864 } while (*s && *s != ']');
873 fatal("Search pattern not terminated:\n%s",str_get(linestr));
875 yylval = string(tokenbuf,0);
880 yyerror(const char *s)
882 fprintf(stderr,"%s in file %s at line %d\n",
887 scannum(register char *s)
892 case '1': case '2': case '3': case '4': case '5':
893 case '6': case '7': case '8': case '9': case '0' : case '.':
895 while (isDIGIT(*s)) {
901 while (isDIGIT(*s)) {
908 if (strchr("eE",*s) && strchr("+-0123456789",s[1])) {
910 if (*s == '+' || *s == '-')
916 yylval = string(tokenbuf,0);
923 string(const char *ptr, int len)
927 ops[mop++].ival = OSTRING + (1<<8);
930 ops[mop].cval = (char *) safemalloc(len+1);
931 strncpy(ops[mop].cval,ptr,len);
932 ops[mop++].cval[len] = '\0';
934 fatal("Recompile a2p with larger OPSMAX\n");
944 fatal("type > 255 (%d)\n",type);
945 ops[mop++].ival = type;
947 fatal("Recompile a2p with larger OPSMAX\n");
952 oper1(int type, int arg1)
957 fatal("type > 255 (%d)\n",type);
958 ops[mop++].ival = type + (1<<8);
959 ops[mop++].ival = arg1;
961 fatal("Recompile a2p with larger OPSMAX\n");
966 oper2(int type, int arg1, int arg2)
971 fatal("type > 255 (%d)\n",type);
972 ops[mop++].ival = type + (2<<8);
973 ops[mop++].ival = arg1;
974 ops[mop++].ival = arg2;
976 fatal("Recompile a2p with larger OPSMAX\n");
981 oper3(int type, int arg1, int arg2, int arg3)
986 fatal("type > 255 (%d)\n",type);
987 ops[mop++].ival = type + (3<<8);
988 ops[mop++].ival = arg1;
989 ops[mop++].ival = arg2;
990 ops[mop++].ival = arg3;
992 fatal("Recompile a2p with larger OPSMAX\n");
997 oper4(int type, int arg1, int arg2, int arg3, int arg4)
1002 fatal("type > 255 (%d)\n",type);
1003 ops[mop++].ival = type + (4<<8);
1004 ops[mop++].ival = arg1;
1005 ops[mop++].ival = arg2;
1006 ops[mop++].ival = arg3;
1007 ops[mop++].ival = arg4;
1009 fatal("Recompile a2p with larger OPSMAX\n");
1014 oper5(int type, int arg1, int arg2, int arg3, int arg4, int arg5)
1019 fatal("type > 255 (%d)\n",type);
1020 ops[mop++].ival = type + (5<<8);
1021 ops[mop++].ival = arg1;
1022 ops[mop++].ival = arg2;
1023 ops[mop++].ival = arg3;
1024 ops[mop++].ival = arg4;
1025 ops[mop++].ival = arg5;
1027 fatal("Recompile a2p with larger OPSMAX\n");
1040 type = ops[branch].ival;
1043 for (i=depth; i; i--)
1045 if (type == OSTRING) {
1046 printf("%-5d\"%s\"\n",branch,ops[branch+1].cval);
1049 printf("(%-5d%s %d\n",branch,opname[type],len);
1051 for (i=1; i<=len; i++)
1052 dump(ops[branch+i].ival);
1054 for (i=depth; i; i--)
1061 bl(int arg, int maybe)
1065 else if ((ops[arg].ival & 255) != OBLOCK)
1066 return oper2(OBLOCK,arg,maybe);
1067 else if ((ops[arg].ival >> 8) < 2)
1068 return oper2(OBLOCK,ops[arg+1].ival,maybe);
1079 for (s = str->str_ptr; *s; s++) {
1080 if (*s == ';' && s[1] == ' ' && s[2] == '\n') {
1084 else if (*s == '\n') {
1085 for (t = s+1; isSPACE(*t & 127); t++) ;
1087 while (isSPACE(*t & 127) && *t != '\n') t--;
1088 if (*t == '\n' && t-s > 1) {
1101 register char *d, *s, *t, *e;
1102 register int pos, newpos;
1106 for (s = str->str_ptr; *s; s++) {
1115 else if (*s == '\t')
1117 if (pos > 78) { /* split a long line? */
1120 for (t = tokenbuf; isSPACE(*t & 127); t++) {
1127 while (d > tokenbuf && (*d != ' ' || d[-1] != ';'))
1131 while (d > tokenbuf &&
1132 (*d != ' ' || d[-1] != '|' || d[-2] != '|') )
1137 while (d > tokenbuf &&
1138 (*d != ' ' || d[-1] != '&' || d[-2] != '&') )
1143 while (d > tokenbuf && (*d != ' ' || d[-1] != ','))
1148 while (d > tokenbuf && *d != ' ')
1158 if (d[-1] != ';' && !(newpos % 4)) {
1164 newpos += strlen(t);
1179 for (t = tokenbuf; *t; t++) {
1183 strcpy(t+strlen(t)-1, "\t#???\n");
1189 if (strnEQ(t,"#!/bin/awk",10) || strnEQ(t,"#! /bin/awk",11))
1191 if (strnEQ(t,"#!/usr/bin/awk",14) || strnEQ(t,"#! /usr/bin/awk",15))
1194 fputs(tokenbuf,stdout);
1203 key = walk(0,0,arg,&dummy,P_MIN);
1205 hstore(symtab,key->str_ptr,str_make("1"));
1207 set_array_base = TRUE;
1212 rememberargs(int arg)
1219 type = ops[arg].ival & 255;
1220 if (type == OCOMMA) {
1221 rememberargs(ops[arg+1].ival);
1222 rememberargs(ops[arg+3].ival);
1224 else if (type == OVAR) {
1226 hstore(curarghash,ops[ops[arg+1].ival+1].cval,str);
1229 fatal("panic: unknown argument type %d, line %d\n",type,line);
1236 int type = ops[arg].ival & 255;
1239 if (type != OSTRING)
1240 fatal("panic: aryrefarg %d, line %d\n",type,line);
1241 str = hfetch(curarghash,ops[arg+1].cval);
1248 fixfargs(int name, int arg, int prevargs)
1256 type = ops[arg].ival & 255;
1257 if (type == OCOMMA) {
1258 numargs = fixfargs(name,ops[arg+1].ival,prevargs);
1259 numargs = fixfargs(name,ops[arg+3].ival,numargs);
1261 else if (type == OVAR) {
1262 str = hfetch(curarghash,ops[ops[arg+1].ival+1].cval);
1263 if (strEQ(str_get(str),"*")) {
1266 str_set(str,""); /* in case another routine has this */
1267 ops[arg].ival &= ~255;
1268 ops[arg].ival |= OSTAR;
1269 sprintf(tmpbuf,"%s:%d",ops[name+1].cval,prevargs);
1270 fprintf(stderr,"Adding %s\n",tmpbuf);
1273 hstore(curarghash,tmpbuf,str);
1275 numargs = prevargs + 1;
1278 fatal("panic: unknown argument type %d, arg %d, line %d\n",
1279 type,prevargs+1,line);
1284 fixrargs(char *name, int arg, int prevargs)
1292 type = ops[arg].ival & 255;
1293 if (type == OCOMMA) {
1294 numargs = fixrargs(name,ops[arg+1].ival,prevargs);
1295 numargs = fixrargs(name,ops[arg+3].ival,numargs);
1298 char *tmpbuf = (char *) safemalloc(strlen(name) + (sizeof(prevargs) * 3) + 5);
1299 sprintf(tmpbuf,"%s:%d",name,prevargs);
1300 str = hfetch(curarghash,tmpbuf);
1302 if (str && strEQ(str->str_ptr,"*")) {
1303 if (type == OVAR || type == OSTAR) {
1304 ops[arg].ival &= ~255;
1305 ops[arg].ival |= OSTAR;
1308 fatal("Can't pass expression by reference as arg %d of %s\n",
1311 numargs = prevargs + 1;