1N/A/* $RCSfile: a2py.c,v $$Revision: 4.1 $$Date: 92/08/07 18:29:14 $
1N/A *
1N/A * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
1N/A * 2000, 2001, 2002, by Larry Wall and others
1N/A *
1N/A * You may distribute under the terms of either the GNU General Public
1N/A * License or the Artistic License, as specified in the README file.
1N/A *
1N/A * $Log: a2py.c,v $
1N/A */
1N/A
1N/A#if defined(OS2) || defined(WIN32) || defined(NETWARE)
1N/A#if defined(WIN32)
1N/A#include <io.h>
1N/A#endif
1N/A#if defined(NETWARE)
1N/A#include "../netware/clibstuf.h"
1N/A#endif
1N/A#include "../patchlevel.h"
1N/A#endif
1N/A#include "util.h"
1N/A
1N/Achar *filename;
1N/Achar *myname;
1N/A
1N/Aint checkers = 0;
1N/A
1N/Aint oper0(int type);
1N/Aint oper1(int type, int arg1);
1N/Aint oper2(int type, int arg1, int arg2);
1N/Aint oper3(int type, int arg1, int arg2, int arg3);
1N/Aint oper4(int type, int arg1, int arg2, int arg3, int arg4);
1N/Aint oper5(int type, int arg1, int arg2, int arg3, int arg4, int arg5);
1N/ASTR *walk(int useval, int level, register int node, int *numericptr, int minprec);
1N/A#ifdef NETWARE
1N/Achar *savestr(char *str);
1N/Achar *cpy2(register char *to, register char *from, register int delim);
1N/A#endif
1N/A
1N/A#if defined(OS2) || defined(WIN32) || defined(NETWARE)
1N/Astatic void usage(void);
1N/A
1N/Astatic void
1N/Ausage()
1N/A{
1N/A printf("\nThis is the AWK to PERL translator, revision %d.0, version %d\n", PERL_REVISION, PERL_VERSION);
1N/A printf("\nUsage: %s [-D<number>] [-F<char>] [-n<fieldlist>] [-<number>] filename\n", myname);
1N/A printf("\n -D<number> sets debugging flags."
1N/A "\n -F<character> the awk script to translate is always invoked with"
1N/A "\n this -F switch."
1N/A "\n -n<fieldlist> specifies the names of the input fields if input does"
1N/A "\n not have to be split into an array."
1N/A "\n -<number> causes a2p to assume that input will always have that"
1N/A "\n many fields.\n");
1N/A exit(1);
1N/A}
1N/A#endif
1N/A
1N/Aint
1N/Amain(register int argc, register char **argv, register char **env)
1N/A{
1N/A register STR *str;
1N/A int i;
1N/A STR *tmpstr;
1N/A /* char *namelist; */
1N/A
1N/A #ifdef NETWARE
1N/A fnInitGpfGlobals(); /* For importing the CLIB calls in place of Watcom calls */
1N/A #endif /* NETWARE */
1N/A
1N/A myname = argv[0];
1N/A linestr = str_new(80);
1N/A str = str_new(0); /* first used for -I flags */
1N/A for (argc--,argv++; argc; argc--,argv++) {
1N/A if (argv[0][0] != '-' || !argv[0][1])
1N/A break;
1N/A switch (argv[0][1]) {
1N/A#ifdef DEBUGGING
1N/A case 'D':
1N/A debug = atoi(argv[0]+2);
1N/A#if YYDEBUG
1N/A yydebug = (debug & 1);
1N/A#endif
1N/A break;
1N/A#endif
1N/A case '0': case '1': case '2': case '3': case '4':
1N/A case '5': case '6': case '7': case '8': case '9':
1N/A maxfld = atoi(argv[0]+1);
1N/A absmaxfld = TRUE;
1N/A break;
1N/A case 'F':
1N/A fswitch = argv[0][2];
1N/A break;
1N/A case 'n':
1N/A namelist = savestr(argv[0]+2);
1N/A break;
1N/A case 'o':
1N/A old_awk = TRUE;
1N/A break;
1N/A case '-':
1N/A argc--,argv++;
1N/A goto switch_end;
1N/A case 0:
1N/A break;
1N/A default:
1N/A#if defined(OS2) || defined(WIN32) || defined(NETWARE)
1N/A fprintf(stderr, "Unrecognized switch: %s\n",argv[0]);
1N/A usage();
1N/A#else
1N/A fatal("Unrecognized switch: %s\n",argv[0]);
1N/A#endif
1N/A }
1N/A }
1N/A switch_end:
1N/A
1N/A /* open script */
1N/A
1N/A if (argv[0] == Nullch) {
1N/A#if defined(OS2) || defined(WIN32) || defined(NETWARE)
1N/A if ( isatty(fileno(stdin)) )
1N/A usage();
1N/A#endif
1N/A argv[0] = "-";
1N/A }
1N/A filename = savestr(argv[0]);
1N/A
1N/A filename = savestr(argv[0]);
1N/A if (strEQ(filename,"-"))
1N/A argv[0] = "";
1N/A if (!*argv[0])
1N/A rsfp = stdin;
1N/A else
1N/A rsfp = fopen(argv[0],"r");
1N/A if (rsfp == Nullfp)
1N/A fatal("Awk script \"%s\" doesn't seem to exist.\n",filename);
1N/A
1N/A /* init tokener */
1N/A
1N/A bufptr = str_get(linestr);
1N/A symtab = hnew();
1N/A curarghash = hnew();
1N/A
1N/A /* now parse the report spec */
1N/A
1N/A if (yyparse())
1N/A fatal("Translation aborted due to syntax errors.\n");
1N/A
1N/A#ifdef DEBUGGING
1N/A if (debug & 2) {
1N/A int type, len;
1N/A
1N/A for (i=1; i<mop;) {
1N/A type = ops[i].ival;
1N/A len = type >> 8;
1N/A type &= 255;
1N/A printf("%d\t%d\t%d\t%-10s",i++,type,len,opname[type]);
1N/A if (type == OSTRING)
1N/A printf("\t\"%s\"\n",ops[i].cval),i++;
1N/A else {
1N/A while (len--) {
1N/A printf("\t%d",ops[i].ival),i++;
1N/A }
1N/A putchar('\n');
1N/A }
1N/A }
1N/A }
1N/A if (debug & 8)
1N/A dump(root);
1N/A#endif
1N/A
1N/A /* first pass to look for numeric variables */
1N/A
1N/A prewalk(0,0,root,&i);
1N/A
1N/A /* second pass to produce new program */
1N/A
1N/A tmpstr = walk(0,0,root,&i,P_MIN);
1N/A str = str_make(STARTPERL);
1N/A str_cat(str, "\neval 'exec ");
1N/A str_cat(str, BIN);
1N/A str_cat(str, "/perl -S $0 ${1+\"$@\"}'\n\
1N/A if $running_under_some_shell;\n\
1N/A # this emulates #! processing on NIH machines.\n\
1N/A # (remove #! line above if indigestible)\n\n");
1N/A str_cat(str,
1N/A "eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;\n");
1N/A str_cat(str,
1N/A " # process any FOO=bar switches\n\n");
1N/A if (do_opens && opens) {
1N/A str_scat(str,opens);
1N/A str_free(opens);
1N/A str_cat(str,"\n");
1N/A }
1N/A str_scat(str,tmpstr);
1N/A str_free(tmpstr);
1N/A#ifdef DEBUGGING
1N/A if (!(debug & 16))
1N/A#endif
1N/A fixup(str);
1N/A putlines(str);
1N/A if (checkers) {
1N/A fprintf(stderr,
1N/A "Please check my work on the %d line%s I've marked with \"#???\".\n",
1N/A checkers, checkers == 1 ? "" : "s" );
1N/A fprintf(stderr,
1N/A "The operation I've selected may be wrong for the operand types.\n");
1N/A }
1N/A exit(0);
1N/A /* by ANSI specs return is needed. This also shuts up VC++ and his warnings */
1N/A return(0);
1N/A}
1N/A
1N/A#define RETURN(retval) return (bufptr = s,retval)
1N/A#define XTERM(retval) return (expectterm = TRUE,bufptr = s,retval)
1N/A#define XOP(retval) return (expectterm = FALSE,bufptr = s,retval)
1N/A#define ID(x) return (yylval=string(x,0),expectterm = FALSE,bufptr = s,idtype)
1N/A
1N/Aint idtype;
1N/A
1N/Aint
1N/Ayylex(void)
1N/A{
1N/A register char *s = bufptr;
1N/A register char *d;
1N/A register int tmp;
1N/A
1N/A retry:
1N/A#if YYDEBUG
1N/A if (yydebug) {
1N/A if (strchr(s,'\n'))
1N/A fprintf(stderr,"Tokener at %s",s);
1N/A else
1N/A fprintf(stderr,"Tokener at %s\n",s);
1N/A }
1N/A#endif
1N/A switch (*s) {
1N/A default:
1N/A fprintf(stderr,
1N/A "Unrecognized character %c in file %s line %d--ignoring.\n",
1N/A *s++,filename,line);
1N/A goto retry;
1N/A case '\\':
1N/A s++;
1N/A if (*s && *s != '\n') {
1N/A yyerror("Ignoring spurious backslash");
1N/A goto retry;
1N/A }
1N/A /*FALLSTHROUGH*/
1N/A case 0:
1N/A s = str_get(linestr);
1N/A *s = '\0';
1N/A if (!rsfp)
1N/A RETURN(0);
1N/A line++;
1N/A if ((s = str_gets(linestr, rsfp)) == Nullch) {
1N/A if (rsfp != stdin)
1N/A fclose(rsfp);
1N/A rsfp = Nullfp;
1N/A s = str_get(linestr);
1N/A RETURN(0);
1N/A }
1N/A goto retry;
1N/A case ' ': case '\t':
1N/A s++;
1N/A goto retry;
1N/A case '\n':
1N/A *s = '\0';
1N/A XTERM(NEWLINE);
1N/A case '#':
1N/A yylval = string(s,0);
1N/A *s = '\0';
1N/A XTERM(COMMENT);
1N/A case ';':
1N/A tmp = *s++;
1N/A if (*s == '\n') {
1N/A s++;
1N/A XTERM(SEMINEW);
1N/A }
1N/A XTERM(tmp);
1N/A case '(':
1N/A tmp = *s++;
1N/A XTERM(tmp);
1N/A case '{':
1N/A case '[':
1N/A case ')':
1N/A case ']':
1N/A case '?':
1N/A case ':':
1N/A tmp = *s++;
1N/A XOP(tmp);
1N/A#ifdef EBCDIC
1N/A case 7:
1N/A#else
1N/A case 127:
1N/A#endif
1N/A s++;
1N/A XTERM('}');
1N/A case '}':
1N/A for (d = s + 1; isSPACE(*d); d++) ;
1N/A if (!*d)
1N/A s = d - 1;
1N/A *s = 127;
1N/A XTERM(';');
1N/A case ',':
1N/A tmp = *s++;
1N/A XTERM(tmp);
1N/A case '~':
1N/A s++;
1N/A yylval = string("~",1);
1N/A XTERM(MATCHOP);
1N/A case '+':
1N/A case '-':
1N/A if (s[1] == *s) {
1N/A s++;
1N/A if (*s++ == '+')
1N/A XTERM(INCR);
1N/A else
1N/A XTERM(DECR);
1N/A }
1N/A /* FALL THROUGH */
1N/A case '*':
1N/A case '%':
1N/A case '^':
1N/A tmp = *s++;
1N/A if (*s == '=') {
1N/A if (tmp == '^')
1N/A yylval = string("**=",3);
1N/A else
1N/A yylval = string(s-1,2);
1N/A s++;
1N/A XTERM(ASGNOP);
1N/A }
1N/A XTERM(tmp);
1N/A case '&':
1N/A s++;
1N/A tmp = *s++;
1N/A if (tmp == '&')
1N/A XTERM(ANDAND);
1N/A s--;
1N/A XTERM('&');
1N/A case '|':
1N/A s++;
1N/A tmp = *s++;
1N/A if (tmp == '|')
1N/A XTERM(OROR);
1N/A s--;
1N/A while (*s == ' ' || *s == '\t')
1N/A s++;
1N/A if (strnEQ(s,"getline",7))
1N/A XTERM('p');
1N/A else
1N/A XTERM('|');
1N/A case '=':
1N/A s++;
1N/A tmp = *s++;
1N/A if (tmp == '=') {
1N/A yylval = string("==",2);
1N/A XTERM(RELOP);
1N/A }
1N/A s--;
1N/A yylval = string("=",1);
1N/A XTERM(ASGNOP);
1N/A case '!':
1N/A s++;
1N/A tmp = *s++;
1N/A if (tmp == '=') {
1N/A yylval = string("!=",2);
1N/A XTERM(RELOP);
1N/A }
1N/A if (tmp == '~') {
1N/A yylval = string("!~",2);
1N/A XTERM(MATCHOP);
1N/A }
1N/A s--;
1N/A XTERM(NOT);
1N/A case '<':
1N/A s++;
1N/A tmp = *s++;
1N/A if (tmp == '=') {
1N/A yylval = string("<=",2);
1N/A XTERM(RELOP);
1N/A }
1N/A s--;
1N/A XTERM('<');
1N/A case '>':
1N/A s++;
1N/A tmp = *s++;
1N/A if (tmp == '>') {
1N/A yylval = string(">>",2);
1N/A XTERM(GRGR);
1N/A }
1N/A if (tmp == '=') {
1N/A yylval = string(">=",2);
1N/A XTERM(RELOP);
1N/A }
1N/A s--;
1N/A XTERM('>');
1N/A
1N/A#define SNARFWORD \
1N/A d = tokenbuf; \
1N/A while (isALPHA(*s) || isDIGIT(*s) || *s == '_') \
1N/A *d++ = *s++; \
1N/A *d = '\0'; \
1N/A d = tokenbuf; \
1N/A if (*s == '(') \
1N/A idtype = USERFUN; \
1N/A else \
1N/A idtype = VAR;
1N/A
1N/A case '$':
1N/A s++;
1N/A if (*s == '0') {
1N/A s++;
1N/A do_chop = TRUE;
1N/A need_entire = TRUE;
1N/A idtype = VAR;
1N/A ID("0");
1N/A }
1N/A do_split = TRUE;
1N/A if (isDIGIT(*s)) {
1N/A for (d = s; isDIGIT(*s); s++) ;
1N/A yylval = string(d,s-d);
1N/A tmp = atoi(d);
1N/A if (tmp > maxfld)
1N/A maxfld = tmp;
1N/A XOP(FIELD);
1N/A }
1N/A split_to_array = set_array_base = TRUE;
1N/A XOP(VFIELD);
1N/A
1N/A case '/': /* may either be division or pattern */
1N/A if (expectterm) {
1N/A s = scanpat(s);
1N/A XTERM(REGEX);
1N/A }
1N/A tmp = *s++;
1N/A if (*s == '=') {
1N/A yylval = string("/=",2);
1N/A s++;
1N/A XTERM(ASGNOP);
1N/A }
1N/A XTERM(tmp);
1N/A
1N/A case '0': case '1': case '2': case '3': case '4':
1N/A case '5': case '6': case '7': case '8': case '9': case '.':
1N/A s = scannum(s);
1N/A XOP(NUMBER);
1N/A case '"':
1N/A s++;
1N/A s = cpy2(tokenbuf,s,s[-1]);
1N/A if (!*s)
1N/A fatal("String not terminated:\n%s",str_get(linestr));
1N/A s++;
1N/A yylval = string(tokenbuf,0);
1N/A XOP(STRING);
1N/A
1N/A case 'a': case 'A':
1N/A SNARFWORD;
1N/A if (strEQ(d,"ARGC"))
1N/A set_array_base = TRUE;
1N/A if (strEQ(d,"ARGV")) {
1N/A yylval=numary(string("ARGV",0));
1N/A XOP(VAR);
1N/A }
1N/A if (strEQ(d,"atan2")) {
1N/A yylval = OATAN2;
1N/A XTERM(FUNN);
1N/A }
1N/A ID(d);
1N/A case 'b': case 'B':
1N/A SNARFWORD;
1N/A if (strEQ(d,"break"))
1N/A XTERM(BREAK);
1N/A if (strEQ(d,"BEGIN"))
1N/A XTERM(BEGIN);
1N/A ID(d);
1N/A case 'c': case 'C':
1N/A SNARFWORD;
1N/A if (strEQ(d,"continue"))
1N/A XTERM(CONTINUE);
1N/A if (strEQ(d,"cos")) {
1N/A yylval = OCOS;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"close")) {
1N/A do_fancy_opens = 1;
1N/A yylval = OCLOSE;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"chdir"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"crypt"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"chop"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"chmod"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"chown"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'd': case 'D':
1N/A SNARFWORD;
1N/A if (strEQ(d,"do"))
1N/A XTERM(DO);
1N/A if (strEQ(d,"delete"))
1N/A XTERM(DELETE);
1N/A if (strEQ(d,"die"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'e': case 'E':
1N/A SNARFWORD;
1N/A if (strEQ(d,"END"))
1N/A XTERM(END);
1N/A if (strEQ(d,"else"))
1N/A XTERM(ELSE);
1N/A if (strEQ(d,"exit")) {
1N/A saw_line_op = TRUE;
1N/A XTERM(EXIT);
1N/A }
1N/A if (strEQ(d,"exp")) {
1N/A yylval = OEXP;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"elsif"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"eq"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"eval"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"eof"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"each"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"exec"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'f': case 'F':
1N/A SNARFWORD;
1N/A if (strEQ(d,"FS")) {
1N/A saw_FS++;
1N/A if (saw_FS == 1 && in_begin) {
1N/A for (d = s; *d && isSPACE(*d); d++) ;
1N/A if (*d == '=') {
1N/A for (d++; *d && isSPACE(*d); d++) ;
1N/A if (*d == '"' && d[2] == '"')
1N/A const_FS = d[1];
1N/A }
1N/A }
1N/A ID(tokenbuf);
1N/A }
1N/A if (strEQ(d,"for"))
1N/A XTERM(FOR);
1N/A else if (strEQ(d,"function"))
1N/A XTERM(FUNCTION);
1N/A if (strEQ(d,"FILENAME"))
1N/A d = "ARGV";
1N/A if (strEQ(d,"foreach"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"format"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"fork"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"fh"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'g': case 'G':
1N/A SNARFWORD;
1N/A if (strEQ(d,"getline"))
1N/A XTERM(GETLINE);
1N/A if (strEQ(d,"gsub"))
1N/A XTERM(GSUB);
1N/A if (strEQ(d,"ge"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"gt"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"goto"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"gmtime"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'h': case 'H':
1N/A SNARFWORD;
1N/A if (strEQ(d,"hex"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'i': case 'I':
1N/A SNARFWORD;
1N/A if (strEQ(d,"if"))
1N/A XTERM(IF);
1N/A if (strEQ(d,"in"))
1N/A XTERM(IN);
1N/A if (strEQ(d,"index")) {
1N/A set_array_base = TRUE;
1N/A XTERM(INDEX);
1N/A }
1N/A if (strEQ(d,"int")) {
1N/A yylval = OINT;
1N/A XTERM(FUN1);
1N/A }
1N/A ID(d);
1N/A case 'j': case 'J':
1N/A SNARFWORD;
1N/A if (strEQ(d,"join"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'k': case 'K':
1N/A SNARFWORD;
1N/A if (strEQ(d,"keys"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"kill"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'l': case 'L':
1N/A SNARFWORD;
1N/A if (strEQ(d,"length")) {
1N/A yylval = OLENGTH;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"log")) {
1N/A yylval = OLOG;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"last"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"local"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"lt"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"le"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"locatime"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"link"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'm': case 'M':
1N/A SNARFWORD;
1N/A if (strEQ(d,"match")) {
1N/A set_array_base = TRUE;
1N/A XTERM(MATCH);
1N/A }
1N/A if (strEQ(d,"m"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'n': case 'N':
1N/A SNARFWORD;
1N/A if (strEQ(d,"NF"))
1N/A do_chop = do_split = split_to_array = set_array_base = TRUE;
1N/A if (strEQ(d,"next")) {
1N/A saw_line_op = TRUE;
1N/A XTERM(NEXT);
1N/A }
1N/A if (strEQ(d,"ne"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'o': case 'O':
1N/A SNARFWORD;
1N/A if (strEQ(d,"ORS")) {
1N/A saw_ORS = TRUE;
1N/A d = "\\";
1N/A }
1N/A if (strEQ(d,"OFS")) {
1N/A saw_OFS = TRUE;
1N/A d = ",";
1N/A }
1N/A if (strEQ(d,"OFMT")) {
1N/A d = "#";
1N/A }
1N/A if (strEQ(d,"open"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"ord"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"oct"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'p': case 'P':
1N/A SNARFWORD;
1N/A if (strEQ(d,"print")) {
1N/A XTERM(PRINT);
1N/A }
1N/A if (strEQ(d,"printf")) {
1N/A XTERM(PRINTF);
1N/A }
1N/A if (strEQ(d,"push"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"pop"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'q': case 'Q':
1N/A SNARFWORD;
1N/A ID(d);
1N/A case 'r': case 'R':
1N/A SNARFWORD;
1N/A if (strEQ(d,"RS")) {
1N/A d = "/";
1N/A saw_RS = TRUE;
1N/A }
1N/A if (strEQ(d,"rand")) {
1N/A yylval = ORAND;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"return"))
1N/A XTERM(RET);
1N/A if (strEQ(d,"reset"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"redo"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"rename"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 's': case 'S':
1N/A SNARFWORD;
1N/A if (strEQ(d,"split")) {
1N/A set_array_base = TRUE;
1N/A XOP(SPLIT);
1N/A }
1N/A if (strEQ(d,"substr")) {
1N/A set_array_base = TRUE;
1N/A XTERM(SUBSTR);
1N/A }
1N/A if (strEQ(d,"sub"))
1N/A XTERM(SUB);
1N/A if (strEQ(d,"sprintf")) {
1N/A /* In old awk, { print sprintf("str%sg"),"in" } prints
1N/A * "string"; in new awk, "in" is not considered an argument to
1N/A * sprintf, so the statement breaks. To support both, the
1N/A * grammar treats arguments to SPRINTF_OLD like old awk,
1N/A * SPRINTF_NEW like new. Here we return the appropriate one.
1N/A */
1N/A XTERM(old_awk ? SPRINTF_OLD : SPRINTF_NEW);
1N/A }
1N/A if (strEQ(d,"sqrt")) {
1N/A yylval = OSQRT;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"SUBSEP")) {
1N/A d = ";";
1N/A }
1N/A if (strEQ(d,"sin")) {
1N/A yylval = OSIN;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"srand")) {
1N/A yylval = OSRAND;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"system")) {
1N/A yylval = OSYSTEM;
1N/A XTERM(FUN1);
1N/A }
1N/A if (strEQ(d,"s"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"shift"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"select"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"seek"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"stat"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"study"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"sleep"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"symlink"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"sort"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 't': case 'T':
1N/A SNARFWORD;
1N/A if (strEQ(d,"tr"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"tell"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"time"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"times"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'u': case 'U':
1N/A SNARFWORD;
1N/A if (strEQ(d,"until"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"unless"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"umask"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"unshift"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"unlink"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"utime"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'v': case 'V':
1N/A SNARFWORD;
1N/A if (strEQ(d,"values"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'w': case 'W':
1N/A SNARFWORD;
1N/A if (strEQ(d,"while"))
1N/A XTERM(WHILE);
1N/A if (strEQ(d,"write"))
1N/A *d = toUPPER(*d);
1N/A else if (strEQ(d,"wait"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'x': case 'X':
1N/A SNARFWORD;
1N/A if (strEQ(d,"x"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'y': case 'Y':
1N/A SNARFWORD;
1N/A if (strEQ(d,"y"))
1N/A *d = toUPPER(*d);
1N/A ID(d);
1N/A case 'z': case 'Z':
1N/A SNARFWORD;
1N/A ID(d);
1N/A }
1N/A}
1N/A
1N/Achar *
1N/Ascanpat(register char *s)
1N/A{
1N/A register char *d;
1N/A
1N/A switch (*s++) {
1N/A case '/':
1N/A break;
1N/A default:
1N/A fatal("Search pattern not found:\n%s",str_get(linestr));
1N/A }
1N/A
1N/A d = tokenbuf;
1N/A for (; *s; s++,d++) {
1N/A if (*s == '\\') {
1N/A if (s[1] == '/')
1N/A *d++ = *s++;
1N/A else if (s[1] == '\\')
1N/A *d++ = *s++;
1N/A else if (s[1] == '[')
1N/A *d++ = *s++;
1N/A }
1N/A else if (*s == '[') {
1N/A *d++ = *s++;
1N/A do {
1N/A if (*s == '\\' && s[1])
1N/A *d++ = *s++;
1N/A if (*s == '/' || (*s == '-' && s[1] == ']'))
1N/A *d++ = '\\';
1N/A *d++ = *s++;
1N/A } while (*s && *s != ']');
1N/A }
1N/A else if (*s == '/')
1N/A break;
1N/A *d = *s;
1N/A }
1N/A *d = '\0';
1N/A
1N/A if (!*s)
1N/A fatal("Search pattern not terminated:\n%s",str_get(linestr));
1N/A s++;
1N/A yylval = string(tokenbuf,0);
1N/A return s;
1N/A}
1N/A
1N/Avoid
1N/Ayyerror(char *s)
1N/A{
1N/A fprintf(stderr,"%s in file %s at line %d\n",
1N/A s,filename,line);
1N/A}
1N/A
1N/Achar *
1N/Ascannum(register char *s)
1N/A{
1N/A register char *d;
1N/A
1N/A switch (*s) {
1N/A case '1': case '2': case '3': case '4': case '5':
1N/A case '6': case '7': case '8': case '9': case '0' : case '.':
1N/A d = tokenbuf;
1N/A while (isDIGIT(*s)) {
1N/A *d++ = *s++;
1N/A }
1N/A if (*s == '.') {
1N/A if (isDIGIT(s[1])) {
1N/A *d++ = *s++;
1N/A while (isDIGIT(*s)) {
1N/A *d++ = *s++;
1N/A }
1N/A }
1N/A else
1N/A s++;
1N/A }
1N/A if (strchr("eE",*s) && strchr("+-0123456789",s[1])) {
1N/A *d++ = *s++;
1N/A if (*s == '+' || *s == '-')
1N/A *d++ = *s++;
1N/A while (isDIGIT(*s))
1N/A *d++ = *s++;
1N/A }
1N/A *d = '\0';
1N/A yylval = string(tokenbuf,0);
1N/A break;
1N/A }
1N/A return s;
1N/A}
1N/A
1N/Aint
1N/Astring(char *ptr, int len)
1N/A{
1N/A int retval = mop;
1N/A
1N/A ops[mop++].ival = OSTRING + (1<<8);
1N/A if (!len)
1N/A len = strlen(ptr);
1N/A ops[mop].cval = (char *) safemalloc(len+1);
1N/A strncpy(ops[mop].cval,ptr,len);
1N/A ops[mop++].cval[len] = '\0';
1N/A if (mop >= OPSMAX)
1N/A fatal("Recompile a2p with larger OPSMAX\n");
1N/A return retval;
1N/A}
1N/A
1N/Aint
1N/Aoper0(int type)
1N/A{
1N/A int retval = mop;
1N/A
1N/A if (type > 255)
1N/A fatal("type > 255 (%d)\n",type);
1N/A ops[mop++].ival = type;
1N/A if (mop >= OPSMAX)
1N/A fatal("Recompile a2p with larger OPSMAX\n");
1N/A return retval;
1N/A}
1N/A
1N/Aint
1N/Aoper1(int type, int arg1)
1N/A{
1N/A int retval = mop;
1N/A
1N/A if (type > 255)
1N/A fatal("type > 255 (%d)\n",type);
1N/A ops[mop++].ival = type + (1<<8);
1N/A ops[mop++].ival = arg1;
1N/A if (mop >= OPSMAX)
1N/A fatal("Recompile a2p with larger OPSMAX\n");
1N/A return retval;
1N/A}
1N/A
1N/Aint
1N/Aoper2(int type, int arg1, int arg2)
1N/A{
1N/A int retval = mop;
1N/A
1N/A if (type > 255)
1N/A fatal("type > 255 (%d)\n",type);
1N/A ops[mop++].ival = type + (2<<8);
1N/A ops[mop++].ival = arg1;
1N/A ops[mop++].ival = arg2;
1N/A if (mop >= OPSMAX)
1N/A fatal("Recompile a2p with larger OPSMAX\n");
1N/A return retval;
1N/A}
1N/A
1N/Aint
1N/Aoper3(int type, int arg1, int arg2, int arg3)
1N/A{
1N/A int retval = mop;
1N/A
1N/A if (type > 255)
1N/A fatal("type > 255 (%d)\n",type);
1N/A ops[mop++].ival = type + (3<<8);
1N/A ops[mop++].ival = arg1;
1N/A ops[mop++].ival = arg2;
1N/A ops[mop++].ival = arg3;
1N/A if (mop >= OPSMAX)
1N/A fatal("Recompile a2p with larger OPSMAX\n");
1N/A return retval;
1N/A}
1N/A
1N/Aint
1N/Aoper4(int type, int arg1, int arg2, int arg3, int arg4)
1N/A{
1N/A int retval = mop;
1N/A
1N/A if (type > 255)
1N/A fatal("type > 255 (%d)\n",type);
1N/A ops[mop++].ival = type + (4<<8);
1N/A ops[mop++].ival = arg1;
1N/A ops[mop++].ival = arg2;
1N/A ops[mop++].ival = arg3;
1N/A ops[mop++].ival = arg4;
1N/A if (mop >= OPSMAX)
1N/A fatal("Recompile a2p with larger OPSMAX\n");
1N/A return retval;
1N/A}
1N/A
1N/Aint
1N/Aoper5(int type, int arg1, int arg2, int arg3, int arg4, int arg5)
1N/A{
1N/A int retval = mop;
1N/A
1N/A if (type > 255)
1N/A fatal("type > 255 (%d)\n",type);
1N/A ops[mop++].ival = type + (5<<8);
1N/A ops[mop++].ival = arg1;
1N/A ops[mop++].ival = arg2;
1N/A ops[mop++].ival = arg3;
1N/A ops[mop++].ival = arg4;
1N/A ops[mop++].ival = arg5;
1N/A if (mop >= OPSMAX)
1N/A fatal("Recompile a2p with larger OPSMAX\n");
1N/A return retval;
1N/A}
1N/A
1N/Aint depth = 0;
1N/A
1N/Avoid
1N/Adump(int branch)
1N/A{
1N/A register int type;
1N/A register int len;
1N/A register int i;
1N/A
1N/A type = ops[branch].ival;
1N/A len = type >> 8;
1N/A type &= 255;
1N/A for (i=depth; i; i--)
1N/A printf(" ");
1N/A if (type == OSTRING) {
1N/A printf("%-5d\"%s\"\n",branch,ops[branch+1].cval);
1N/A }
1N/A else {
1N/A printf("(%-5d%s %d\n",branch,opname[type],len);
1N/A depth++;
1N/A for (i=1; i<=len; i++)
1N/A dump(ops[branch+i].ival);
1N/A depth--;
1N/A for (i=depth; i; i--)
1N/A printf(" ");
1N/A printf(")\n");
1N/A }
1N/A}
1N/A
1N/Aint
1N/Abl(int arg, int maybe)
1N/A{
1N/A if (!arg)
1N/A return 0;
1N/A else if ((ops[arg].ival & 255) != OBLOCK)
1N/A return oper2(OBLOCK,arg,maybe);
1N/A else if ((ops[arg].ival >> 8) < 2)
1N/A return oper2(OBLOCK,ops[arg+1].ival,maybe);
1N/A else
1N/A return arg;
1N/A}
1N/A
1N/Avoid
1N/Afixup(STR *str)
1N/A{
1N/A register char *s;
1N/A register char *t;
1N/A
1N/A for (s = str->str_ptr; *s; s++) {
1N/A if (*s == ';' && s[1] == ' ' && s[2] == '\n') {
1N/A strcpy(s+1,s+2);
1N/A s++;
1N/A }
1N/A else if (*s == '\n') {
1N/A for (t = s+1; isSPACE(*t & 127); t++) ;
1N/A t--;
1N/A while (isSPACE(*t & 127) && *t != '\n') t--;
1N/A if (*t == '\n' && t-s > 1) {
1N/A if (s[-1] == '{')
1N/A s--;
1N/A strcpy(s+1,t);
1N/A }
1N/A s++;
1N/A }
1N/A }
1N/A}
1N/A
1N/Avoid
1N/Aputlines(STR *str)
1N/A{
1N/A register char *d, *s, *t, *e;
1N/A register int pos, newpos;
1N/A
1N/A d = tokenbuf;
1N/A pos = 0;
1N/A for (s = str->str_ptr; *s; s++) {
1N/A *d++ = *s;
1N/A pos++;
1N/A if (*s == '\n') {
1N/A *d = '\0';
1N/A d = tokenbuf;
1N/A pos = 0;
1N/A putone();
1N/A }
1N/A else if (*s == '\t')
1N/A pos += 7;
1N/A if (pos > 78) { /* split a long line? */
1N/A *d-- = '\0';
1N/A newpos = 0;
1N/A for (t = tokenbuf; isSPACE(*t & 127); t++) {
1N/A if (*t == '\t')
1N/A newpos += 8;
1N/A else
1N/A newpos += 1;
1N/A }
1N/A e = d;
1N/A while (d > tokenbuf && (*d != ' ' || d[-1] != ';'))
1N/A d--;
1N/A if (d < t+10) {
1N/A d = e;
1N/A while (d > tokenbuf &&
1N/A (*d != ' ' || d[-1] != '|' || d[-2] != '|') )
1N/A d--;
1N/A }
1N/A if (d < t+10) {
1N/A d = e;
1N/A while (d > tokenbuf &&
1N/A (*d != ' ' || d[-1] != '&' || d[-2] != '&') )
1N/A d--;
1N/A }
1N/A if (d < t+10) {
1N/A d = e;
1N/A while (d > tokenbuf && (*d != ' ' || d[-1] != ','))
1N/A d--;
1N/A }
1N/A if (d < t+10) {
1N/A d = e;
1N/A while (d > tokenbuf && *d != ' ')
1N/A d--;
1N/A }
1N/A if (d > t+3) {
1N/A char save[2048];
1N/A strcpy(save, d);
1N/A *d = '\n';
1N/A d[1] = '\0';
1N/A putone();
1N/A putchar('\n');
1N/A if (d[-1] != ';' && !(newpos % 4)) {
1N/A *t++ = ' ';
1N/A *t++ = ' ';
1N/A newpos += 2;
1N/A }
1N/A strcpy(t,save+1);
1N/A newpos += strlen(t);
1N/A d = t + strlen(t);
1N/A pos = newpos;
1N/A }
1N/A else
1N/A d = e + 1;
1N/A }
1N/A }
1N/A}
1N/A
1N/Avoid
1N/Aputone(void)
1N/A{
1N/A register char *t;
1N/A
1N/A for (t = tokenbuf; *t; t++) {
1N/A *t &= 127;
1N/A if (*t == 127) {
1N/A *t = ' ';
1N/A strcpy(t+strlen(t)-1, "\t#???\n");
1N/A checkers++;
1N/A }
1N/A }
1N/A t = tokenbuf;
1N/A if (*t == '#') {
1N/A if (strnEQ(t,"#!/bin/awk",10) || strnEQ(t,"#! /bin/awk",11))
1N/A return;
1N/A if (strnEQ(t,"#!/usr/bin/awk",14) || strnEQ(t,"#! /usr/bin/awk",15))
1N/A return;
1N/A }
1N/A fputs(tokenbuf,stdout);
1N/A}
1N/A
1N/Aint
1N/Anumary(int arg)
1N/A{
1N/A STR *key;
1N/A int dummy;
1N/A
1N/A key = walk(0,0,arg,&dummy,P_MIN);
1N/A str_cat(key,"[]");
1N/A hstore(symtab,key->str_ptr,str_make("1"));
1N/A str_free(key);
1N/A set_array_base = TRUE;
1N/A return arg;
1N/A}
1N/A
1N/Aint
1N/Arememberargs(int arg)
1N/A{
1N/A int type;
1N/A STR *str;
1N/A
1N/A if (!arg)
1N/A return arg;
1N/A type = ops[arg].ival & 255;
1N/A if (type == OCOMMA) {
1N/A rememberargs(ops[arg+1].ival);
1N/A rememberargs(ops[arg+3].ival);
1N/A }
1N/A else if (type == OVAR) {
1N/A str = str_new(0);
1N/A hstore(curarghash,ops[ops[arg+1].ival+1].cval,str);
1N/A }
1N/A else
1N/A fatal("panic: unknown argument type %d, line %d\n",type,line);
1N/A return arg;
1N/A}
1N/A
1N/Aint
1N/Aaryrefarg(int arg)
1N/A{
1N/A int type = ops[arg].ival & 255;
1N/A STR *str;
1N/A
1N/A if (type != OSTRING)
1N/A fatal("panic: aryrefarg %d, line %d\n",type,line);
1N/A str = hfetch(curarghash,ops[arg+1].cval);
1N/A if (str)
1N/A str_set(str,"*");
1N/A return arg;
1N/A}
1N/A
1N/Aint
1N/Afixfargs(int name, int arg, int prevargs)
1N/A{
1N/A int type;
1N/A STR *str;
1N/A int numargs = 0;
1N/A
1N/A if (!arg)
1N/A return prevargs;
1N/A type = ops[arg].ival & 255;
1N/A if (type == OCOMMA) {
1N/A numargs = fixfargs(name,ops[arg+1].ival,prevargs);
1N/A numargs = fixfargs(name,ops[arg+3].ival,numargs);
1N/A }
1N/A else if (type == OVAR) {
1N/A str = hfetch(curarghash,ops[ops[arg+1].ival+1].cval);
1N/A if (strEQ(str_get(str),"*")) {
1N/A char tmpbuf[128];
1N/A
1N/A str_set(str,""); /* in case another routine has this */
1N/A ops[arg].ival &= ~255;
1N/A ops[arg].ival |= OSTAR;
1N/A sprintf(tmpbuf,"%s:%d",ops[name+1].cval,prevargs);
1N/A fprintf(stderr,"Adding %s\n",tmpbuf);
1N/A str = str_new(0);
1N/A str_set(str,"*");
1N/A hstore(curarghash,tmpbuf,str);
1N/A }
1N/A numargs = prevargs + 1;
1N/A }
1N/A else
1N/A fatal("panic: unknown argument type %d, arg %d, line %d\n",
1N/A type,prevargs+1,line);
1N/A return numargs;
1N/A}
1N/A
1N/Aint
1N/Afixrargs(char *name, int arg, int prevargs)
1N/A{
1N/A int type;
1N/A STR *str;
1N/A int numargs;
1N/A
1N/A if (!arg)
1N/A return prevargs;
1N/A type = ops[arg].ival & 255;
1N/A if (type == OCOMMA) {
1N/A numargs = fixrargs(name,ops[arg+1].ival,prevargs);
1N/A numargs = fixrargs(name,ops[arg+3].ival,numargs);
1N/A }
1N/A else {
1N/A char *tmpbuf = (char *) safemalloc(strlen(name) + (sizeof(prevargs) * 3) + 5);
1N/A sprintf(tmpbuf,"%s:%d",name,prevargs);
1N/A str = hfetch(curarghash,tmpbuf);
1N/A safefree(tmpbuf);
1N/A if (str && strEQ(str->str_ptr,"*")) {
1N/A if (type == OVAR || type == OSTAR) {
1N/A ops[arg].ival &= ~255;
1N/A ops[arg].ival |= OSTAR;
1N/A }
1N/A else
1N/A fatal("Can't pass expression by reference as arg %d of %s\n",
1N/A prevargs+1, name);
1N/A }
1N/A numargs = prevargs + 1;
1N/A }
1N/A return numargs;
1N/A}