/* walk.c * * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999, * 2000, 2001, 2002, 2005 by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ #include "EXTERN.h" #include "a2p.h" #include "util.h" bool exitval = FALSE; bool realexit = FALSE; bool saw_getline = FALSE; bool subretnum = FALSE; bool saw_FNR = FALSE; bool saw_argv0 = FALSE; bool saw_fh = FALSE; int maxtmp = 0; const char *lparen; const char *rparen; const char *limit; STR *subs; STR *curargs = Nullstr; static void addsemi ( STR *str ); static void emit_split ( STR *str, int level ); static void fixtab ( STR *str, int lvl ); static void numericize ( int node ); static void tab ( STR *str, int lvl ); int prewalk ( int numit, int level, int node, int *numericptr ); STR * walk ( int useval, int level, int node, int *numericptr, int minprec ); #ifdef NETWARE char *savestr(char *str); char *cpytill(register char *to, register char *from, register int delim); char *instr(char *big, const char *little); #endif STR * walk(int useval, int level, register int node, int *numericptr, int minprec) { register int len; register STR *str; register int type; register int i; register STR *tmpstr; STR *tmp2str; STR *tmp3str; char *t; char *d, *s; int numarg; int numeric = FALSE; STR *fstr; int prec = P_MAX; /* assume no parens needed */ if (!node) { *numericptr = 0; return str_make(""); } type = ops[node].ival; len = type >> 8; type &= 255; switch (type) { case OPROG: arymax = 0; if (namelist) { while (isALPHA(*namelist)) { for (d = tokenbuf,s=namelist; isALPHA(*s) || isDIGIT(*s) || *s == '_'; *d++ = *s++) ; *d = '\0'; while (*s && !isALPHA(*s)) s++; namelist = s; nameary[++arymax] = savestr(tokenbuf); } } if (maxfld < arymax) maxfld = arymax; opens = str_new(0); subs = str_new(0); str = walk(0,level,ops[node+1].ival,&numarg,P_MIN); if (do_split && need_entire && !absmaxfld) split_to_array = TRUE; if (do_split && split_to_array) set_array_base = TRUE; if (set_array_base) { str_cat(str,"$[ = 1;\t\t\t# set array base to 1\n"); } if (fswitch && !const_FS) const_FS = fswitch; if (saw_FS > 1 || saw_RS) const_FS = 0; if (saw_ORS && need_entire) do_chop = TRUE; if (fswitch) { str_cat(str,"$FS = '"); if (strchr("*+?.[]()|^$\\",fswitch)) str_cat(str,"\\"); sprintf(tokenbuf,"%c",fswitch); str_cat(str,tokenbuf); str_cat(str,"';\t\t# field separator from -F switch\n"); } else if (saw_FS && !const_FS) { str_cat(str,"$FS = ' ';\t\t# set field separator\n"); } if (saw_OFS) { str_cat(str,"$, = ' ';\t\t# set output field separator\n"); } if (saw_ORS) { str_cat(str,"$\\ = \"\\n\";\t\t# set output record separator\n"); } if (saw_argv0) { str_cat(str,"$ARGV0 = $0;\t\t# remember what we ran as\n"); } if (str->str_cur > 20) str_cat(str,"\n"); if (ops[node+2].ival) { str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,"\n\n"); } fstr = walk(0,level+1,ops[node+3].ival,&numarg,P_MIN); if (*fstr->str_ptr) { if (saw_line_op) str_cat(str,"line: "); str_cat(str,"while (<>) {\n"); tab(str,++level); if (saw_FS && !const_FS) do_chop = TRUE; if (do_chop) { str_cat(str,"chomp;\t# strip record separator\n"); tab(str,level); } if (do_split) emit_split(str,level); str_scat(str,fstr); str_free(fstr); fixtab(str,--level); str_cat(str,"}\n"); if (saw_FNR) str_cat(str,"continue {\n $FNRbase = $. if eof;\n}\n"); } else if (old_awk) str_cat(str,"while (<>) { } # (no line actions)\n"); if (ops[node+4].ival) { realexit = TRUE; str_cat(str,"\n"); tab(str,level); str_scat(str,fstr=walk(0,level,ops[node+4].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,"\n"); } if (exitval) str_cat(str,"exit $ExitValue;\n"); if (subs->str_ptr) { str_cat(str,"\n"); str_scat(str,subs); } if (saw_getline) { for (len = 0; len < 4; len++) { if (saw_getline & (1 << len)) { sprintf(tokenbuf,"\nsub Getline%d {\n",len); str_cat(str, tokenbuf); if (len & 2) { if (do_fancy_opens) str_cat(str," &Pick('',@_);\n"); else str_cat(str," ($fh) = @_;\n"); } else { if (saw_FNR) str_cat(str," $FNRbase = $. if eof;\n"); } if (len & 1) str_cat(str," local($_);\n"); if (len & 2) str_cat(str, " if ($getline_ok = (($_ = <$fh>) ne ''))"); else str_cat(str, " if ($getline_ok = (($_ = <>) ne ''))"); str_cat(str, " {\n"); level += 2; tab(str,level); i = 0; if (do_chop) { i++; str_cat(str,"chomp;\t# strip record separator\n"); tab(str,level); } if (do_split && !(len & 1)) { i++; emit_split(str,level); } if (!i) str_cat(str,";\n"); fixtab(str,--level); str_cat(str,"}\n $_;\n}\n"); --level; } } } if (do_fancy_opens) { str_cat(str,"\n\ sub Pick {\n\ local($mode,$name,$pipe) = @_;\n\ $fh = $name;\n\ open($name,$mode.$name.$pipe) unless $opened{$name}++;\n\ }\n\ "); } break; case OHUNKS: str = walk(0,level,ops[node+1].ival,&numarg,P_MIN); str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); if (len == 3) { str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg,P_MIN)); str_free(fstr); } else { } break; case ORANGE: prec = P_DOTDOT; str = walk(1,level,ops[node+1].ival,&numarg,prec+1); str_cat(str," .. "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); break; case OPAT: goto def; case OREGEX: str = str_new(0); str_set(str,"/"); tmpstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN); /* translate \nnn to [\nnn] */ for (s = tmpstr->str_ptr, d = tokenbuf; *s; s++, d++) { if (*s == '\\' && isDIGIT(s[1]) && isDIGIT(s[2]) && isDIGIT(s[3])){ *d++ = '['; *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s; *d = ']'; } else *d = *s; } *d = '\0'; for (d=tokenbuf; *d; d++) *d += (char)128; str_cat(str,tokenbuf); str_free(tmpstr); str_cat(str,"/"); break; case OHUNK: if (len == 1) { str = str_new(0); str = walk(0,level,oper1(OPRINT,0),&numarg,P_MIN); str_cat(str," if "); str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,";"); } else { tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN); if (*tmpstr->str_ptr) { str = str_new(0); str_set(str,"if ("); str_scat(str,tmpstr); str_cat(str,") {\n"); tab(str,++level); str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); fixtab(str,--level); str_cat(str,"}\n"); tab(str,level); } else { str = walk(0,level,ops[node+2].ival,&numarg,P_MIN); } } break; case OPPAREN: str = str_new(0); str_set(str,"("); str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,")"); break; case OPANDAND: prec = P_ANDAND; str = walk(1,level,ops[node+1].ival,&numarg,prec); str_cat(str," && "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1)); str_free(fstr); break; case OPOROR: prec = P_OROR; str = walk(1,level,ops[node+1].ival,&numarg,prec); str_cat(str," || "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1)); str_free(fstr); break; case OPNOT: prec = P_UNARY; str = str_new(0); str_set(str,"!"); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec)); str_free(fstr); break; case OCOND: prec = P_COND; str = walk(1,level,ops[node+1].ival,&numarg,prec); str_cat(str," ? "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); str_cat(str," : "); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1)); str_free(fstr); break; case OCPAREN: str = str_new(0); str_set(str,"("); str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); numeric |= numarg; str_cat(str,")"); break; case OCANDAND: prec = P_ANDAND; str = walk(1,level,ops[node+1].ival,&numarg,prec); numeric = 1; str_cat(str," && "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1)); str_free(fstr); break; case OCOROR: prec = P_OROR; str = walk(1,level,ops[node+1].ival,&numarg,prec); numeric = 1; str_cat(str," || "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1)); str_free(fstr); break; case OCNOT: prec = P_UNARY; str = str_new(0); str_set(str,"!"); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec)); str_free(fstr); numeric = 1; break; case ORELOP: prec = P_REL; str = walk(1,level,ops[node+2].ival,&numarg,prec+1); numeric |= numarg; tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN); tmp2str = walk(1,level,ops[node+3].ival,&numarg,prec+1); numeric |= numarg; if (!numeric || (!numarg && (*tmp2str->str_ptr == '"' || *tmp2str->str_ptr == '\''))) { t = tmpstr->str_ptr; if (strEQ(t,"==")) str_set(tmpstr,"eq"); else if (strEQ(t,"!=")) str_set(tmpstr,"ne"); else if (strEQ(t,"<")) str_set(tmpstr,"lt"); else if (strEQ(t,"<=")) str_set(tmpstr,"le"); else if (strEQ(t,">")) str_set(tmpstr,"gt"); else if (strEQ(t,">=")) str_set(tmpstr,"ge"); if (!strchr(tmpstr->str_ptr,'\'') && !strchr(tmpstr->str_ptr,'"') && !strchr(tmp2str->str_ptr,'\'') && !strchr(tmp2str->str_ptr,'"') ) numeric |= 2; } if (numeric & 2) { if (numeric & 1) /* numeric is very good guess */ str_cat(str," "); else str_cat(str,"\377"); numeric = 1; } else str_cat(str," "); str_scat(str,tmpstr); str_free(tmpstr); str_cat(str," "); str_scat(str,tmp2str); str_free(tmp2str); numeric = 1; break; case ORPAREN: str = str_new(0); str_set(str,"("); str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); numeric |= numarg; str_cat(str,")"); break; case OMATCHOP: prec = P_MATCH; str = walk(1,level,ops[node+2].ival,&numarg,prec+1); str_cat(str," "); tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN); if (strEQ(tmpstr->str_ptr,"~")) str_cat(str,"=~"); else { str_scat(str,tmpstr); str_free(tmpstr); } str_cat(str," "); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1)); str_free(fstr); numeric = 1; break; case OMPAREN: str = str_new(0); str_set(str,"("); str_scat(str, fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); numeric |= numarg; str_cat(str,")"); break; case OCONCAT: prec = P_ADD; type = ops[ops[node+1].ival].ival & 255; str = walk(1,level,ops[node+1].ival,&numarg,prec+(type != OCONCAT)); str_cat(str," . "); type = ops[ops[node+2].ival].ival & 255; str_scat(str, fstr=walk(1,level,ops[node+2].ival,&numarg,prec+(type != OCONCAT))); str_free(fstr); break; case OASSIGN: prec = P_ASSIGN; str = walk(0,level,ops[node+2].ival,&numarg,prec+1); str_cat(str," "); tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN); str_scat(str,tmpstr); if (str_len(tmpstr) > 1) numeric = 1; str_free(tmpstr); str_cat(str," "); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec)); str_free(fstr); numeric |= numarg; if (strEQ(str->str_ptr,"$/ = ''")) str_set(str, "$/ = \"\\n\\n\""); break; case OADD: prec = P_ADD; str = walk(1,level,ops[node+1].ival,&numarg,prec); str_cat(str," + "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); numeric = 1; break; case OSUBTRACT: prec = P_ADD; str = walk(1,level,ops[node+1].ival,&numarg,prec); str_cat(str," - "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); numeric = 1; break; case OMULT: prec = P_MUL; str = walk(1,level,ops[node+1].ival,&numarg,prec); str_cat(str," * "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); numeric = 1; break; case ODIV: prec = P_MUL; str = walk(1,level,ops[node+1].ival,&numarg,prec); str_cat(str," / "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); numeric = 1; break; case OPOW: prec = P_POW; str = walk(1,level,ops[node+1].ival,&numarg,prec+1); str_cat(str," ** "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec)); str_free(fstr); numeric = 1; break; case OMOD: prec = P_MUL; str = walk(1,level,ops[node+1].ival,&numarg,prec); str_cat(str," % "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1)); str_free(fstr); numeric = 1; break; case OPOSTINCR: prec = P_AUTO; str = walk(1,level,ops[node+1].ival,&numarg,prec+1); str_cat(str,"++"); numeric = 1; break; case OPOSTDECR: prec = P_AUTO; str = walk(1,level,ops[node+1].ival,&numarg,prec+1); str_cat(str,"--"); numeric = 1; break; case OPREINCR: prec = P_AUTO; str = str_new(0); str_set(str,"++"); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec+1)); str_free(fstr); numeric = 1; break; case OPREDECR: prec = P_AUTO; str = str_new(0); str_set(str,"--"); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec+1)); str_free(fstr); numeric = 1; break; case OUMINUS: prec = P_UNARY; str = str_new(0); str_set(str,"-"); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec)); str_free(fstr); numeric = 1; break; case OUPLUS: numeric = 1; goto def; case OPAREN: str = str_new(0); str_set(str,"("); str_scat(str, fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,")"); numeric |= numarg; break; case OGETLINE: str = str_new(0); if (useval) str_cat(str,"("); if (len > 0) { str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); if (!*fstr->str_ptr) { str_cat(str,"$_"); len = 2; /* a legal fiction */ } str_free(fstr); } else str_cat(str,"$_"); if (len > 1) { tmpstr=walk(1,level,ops[node+3].ival,&numarg,P_MIN); fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN); if (!do_fancy_opens) { t = tmpstr->str_ptr; if (*t == '"' || *t == '\'') t = cpytill(tokenbuf,t+1,*t); else fatal("Internal error: OGETLINE %s", t); d = savestr(t); s = savestr(tokenbuf); for (t = tokenbuf; *t; t++) { *t &= 127; if (isLOWER(*t)) *t = toUPPER(*t); if (!isALPHA(*t) && !isDIGIT(*t)) *t = '_'; } if (!strchr(tokenbuf,'_')) strcpy(t,"_FH"); tmp3str = hfetch(symtab,tokenbuf); if (!tmp3str) { do_opens = TRUE; str_cat(opens,"open("); str_cat(opens,tokenbuf); str_cat(opens,", "); d[1] = '\0'; str_cat(opens,d); str_cat(opens,tmpstr->str_ptr+1); opens->str_cur--; if (*fstr->str_ptr == '|') str_cat(opens,"|"); str_cat(opens,d); if (*fstr->str_ptr == '|') str_cat(opens,") || die 'Cannot pipe from \""); else str_cat(opens,") || die 'Cannot open file \""); if (*d == '"') str_cat(opens,"'.\""); str_cat(opens,s); if (*d == '"') str_cat(opens,"\".'"); str_cat(opens,"\".';\n"); hstore(symtab,tokenbuf,str_make("x")); } safefree(s); safefree(d); str_set(tmpstr,"'"); str_cat(tmpstr,tokenbuf); str_cat(tmpstr,"'"); } if (*fstr->str_ptr == '|') str_cat(tmpstr,", '|'"); str_free(fstr); } else tmpstr = str_make(""); sprintf(tokenbuf," = &Getline%d(%s)",len,tmpstr->str_ptr); str_cat(str,tokenbuf); str_free(tmpstr); if (useval) str_cat(str,",$getline_ok)"); saw_getline |= 1 << len; break; case OSPRINTF: str = str_new(0); str_set(str,"sprintf("); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,")"); break; case OSUBSTR: str = str_new(0); str_set(str,"substr("); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_COMMA+1)); str_free(fstr); str_cat(str,", "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_COMMA+1)); str_free(fstr); if (len == 3) { str_cat(str,", "); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,P_COMMA+1)); str_free(fstr); } str_cat(str,")"); break; case OSTRING: str = str_new(0); str_set(str,ops[node+1].cval); break; case OSPLIT: str = str_new(0); limit = ", -1)"; numeric = 1; tmpstr = walk(1,level,ops[node+2].ival,&numarg,P_MIN); if (useval) str_set(str,"(@"); else str_set(str,"@"); str_scat(str,tmpstr); str_cat(str," = split("); if (len == 3) { fstr = walk(1,level,ops[node+3].ival,&numarg,P_COMMA+1); if (str_len(fstr) == 3 && *fstr->str_ptr == '\'') { i = fstr->str_ptr[1] & 127; if (strchr("*+?.[]()|^$\\",i)) sprintf(tokenbuf,"/\\%c/",i); else if (i == ' ') sprintf(tokenbuf,"' '"); else sprintf(tokenbuf,"/%c/",i); str_cat(str,tokenbuf); } else str_scat(str,fstr); str_free(fstr); } else if (const_FS) { sprintf(tokenbuf,"/[%c\\n]/",const_FS); str_cat(str,tokenbuf); } else if (saw_FS) str_cat(str,"$FS"); else { str_cat(str,"' '"); limit = ")"; } str_cat(str,", "); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_COMMA+1)); str_free(fstr); str_cat(str,limit); if (useval) { str_cat(str,")"); } str_free(tmpstr); break; case OINDEX: str = str_new(0); str_set(str,"index("); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_COMMA+1)); str_free(fstr); str_cat(str,", "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_COMMA+1)); str_free(fstr); str_cat(str,")"); numeric = 1; break; case OMATCH: str = str_new(0); prec = P_ANDAND; str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MATCH+1)); str_free(fstr); str_cat(str," =~ "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MATCH+1)); str_free(fstr); str_cat(str," && ($RLENGTH = length($&), $RSTART = length($`)+1)"); numeric = 1; break; case OUSERDEF: str = str_new(0); subretnum = FALSE; fstr=walk(1,level-1,ops[node+2].ival,&numarg,P_MIN); curargs = str_new(0); str_sset(curargs,fstr); str_cat(curargs,","); tmp2str=walk(1,level,ops[node+5].ival,&numarg,P_MIN); str_free(curargs); curargs = Nullstr; level--; subretnum |= numarg; s = Nullch; t = tmp2str->str_ptr; while ((t = instr(t,"return "))) s = t++; if (s) { i = 0; for (t = s+7; *t; t++) { if (*t == ';' || *t == '}') i++; } if (i == 1) { strcpy(s,s+7); tmp2str->str_cur -= 7; } } str_set(str,"\n"); tab(str,level); str_cat(str,"sub "); str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); str_cat(str," {\n"); tab(str,++level); if (fstr->str_cur) { str_cat(str,"local("); str_scat(str,fstr); str_cat(str,") = @_;"); } str_free(fstr); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,P_MIN)); str_free(fstr); fixtab(str,level); str_scat(str,fstr=walk(1,level,ops[node+4].ival,&numarg,P_MIN)); str_free(fstr); fixtab(str,level); str_scat(str,tmp2str); str_free(tmp2str); fixtab(str,--level); str_cat(str,"}\n"); tab(str,level); str_scat(subs,str); str_set(str,""); str_cat(tmpstr,"("); tmp2str = str_new(0); if (subretnum) str_set(tmp2str,"1"); hstore(symtab,tmpstr->str_ptr,tmp2str); str_free(tmpstr); level++; break; case ORETURN: str = str_new(0); if (len > 0) { str_cat(str,"return "); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_UNI+1)); str_free(fstr); if (numarg) subretnum = TRUE; } else str_cat(str,"return"); break; case OUSERFUN: str = str_new(0); str_set(str,"&"); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,"("); tmpstr = hfetch(symtab,str->str_ptr+3); if (tmpstr && tmpstr->str_ptr) numeric |= atoi(tmpstr->str_ptr); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,")"); break; case OGSUB: case OSUB: { int gsub = type == OGSUB ? 1 : 0; str = str_new(0); tmpstr = str_new(0); i = 0; if (len == 3) { tmpstr = walk(1,level,ops[node+3].ival,&numarg,P_MATCH+1); if (strNE(tmpstr->str_ptr,"$_")) { str_cat(tmpstr, " =~ s"); i++; } else str_set(tmpstr, "s"); } else str_set(tmpstr, "s"); type = ops[ops[node+2].ival].ival; len = type >> 8; type &= 255; tmp3str = str_new(0); { const char *s; if (type == OSTR) { tmp2str=walk(1,level,ops[ops[node+2].ival+1].ival,&numarg,P_MIN); for (t = tmp2str->str_ptr, d=tokenbuf; *t; d++,t++) { if (*t == '&') *d++ = '$' + (char)128; else if (*t == '$') *d++ = '\\' + (char)128; *d = *t + 128; } *d = '\0'; str_set(tmp2str,tokenbuf); s = (gsub ? "/g" : "/"); } else { tmp2str=walk(1,level,ops[node+2].ival,&numarg,P_MIN); str_set(tmp3str,"($s_ = '\"'.("); str_scat(tmp3str,tmp2str); str_cat(tmp3str,").'\"') =~ s/&/\\$&/g, "); str_set(tmp2str,"eval $s_"); s = (gsub ? "/ge" : "/e"); i++; } str_cat(tmp2str,s); } type = ops[ops[node+1].ival].ival; len = type >> 8; type &= 255; fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN); if (type == OREGEX) { if (useval && i) str_cat(str,"("); str_scat(str,tmp3str); str_scat(str,tmpstr); str_scat(str,fstr); str_scat(str,tmp2str); } else if ((type == OFLD && !split_to_array) || (type == OVAR && len == 1)) { if (useval && i) str_cat(str,"("); str_scat(str,tmp3str); str_scat(str,tmpstr); str_cat(str,"/"); str_scat(str,fstr); str_cat(str,"/"); str_scat(str,tmp2str); } else { i++; if (useval) str_cat(str,"("); str_cat(str,"$s = "); str_scat(str,fstr); str_cat(str,", "); str_scat(str,tmp3str); str_scat(str,tmpstr); str_cat(str,"/$s/"); str_scat(str,tmp2str); } if (useval && i) str_cat(str,")"); str_free(fstr); str_free(tmpstr); str_free(tmp2str); str_free(tmp3str); numeric = 1; break; } case ONUM: str = walk(1,level,ops[node+1].ival,&numarg,P_MIN); numeric = 1; break; case OSTR: tmpstr = walk(1,level,ops[node+1].ival,&numarg,P_MIN); { const char *s = "'"; for (t = tmpstr->str_ptr, d=tokenbuf; *t; d++,t++) { if (*t == '\'') s = "\""; else if (*t == '\\') { s = "\""; *d++ = *t++ + 128; switch (*t) { case '\\': case '"': case 'n': case 't': case '$': break; default: /* hide this from perl */ *d++ = '\\' + (char)128; } } *d = *t + 128; } *d = '\0'; str = str_new(0); str_set(str,s); str_cat(str,tokenbuf); str_free(tmpstr); str_cat(str,s); } break; case ODEFINED: prec = P_UNI; str = str_new(0); str_set(str,"defined $"); goto addvar; case ODELETE: str = str_new(0); str_set(str,"delete $"); goto addvar; case OSTAR: str = str_new(0); str_set(str,"*"); goto addvar; case OVAR: str = str_new(0); str_set(str,"$"); addvar: str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); if (len == 1) { tmp2str = hfetch(symtab,tmpstr->str_ptr); if (tmp2str && atoi(tmp2str->str_ptr)) numeric = 2; if (strEQ(str->str_ptr,"$FNR")) { numeric = 1; saw_FNR++; str_set(str,"($.-$FNRbase)"); } else if (strEQ(str->str_ptr,"$NR")) { numeric = 1; str_set(str,"$."); } else if (strEQ(str->str_ptr,"$NF")) { numeric = 1; str_set(str,"$#Fld"); } else if (strEQ(str->str_ptr,"$0")) str_set(str,"$_"); else if (strEQ(str->str_ptr,"$ARGC")) str_set(str,"($#ARGV+1)"); } else { #ifdef NOTDEF if (curargs) { sprintf(tokenbuf,"$%s,",tmpstr->str_ptr); ??? if (instr(curargs->str_ptr,tokenbuf)) str_cat(str,"\377"); /* can't translate yet */ } #endif str_cat(tmpstr,"[]"); tmp2str = hfetch(symtab,tmpstr->str_ptr); if (tmp2str && atoi(tmp2str->str_ptr)) str_cat(str,"["); else str_cat(str,"{"); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); if (strEQ(str->str_ptr,"$ARGV[0")) { str_set(str,"$ARGV0"); saw_argv0++; } else { if (tmp2str && atoi(tmp2str->str_ptr)) strcpy(tokenbuf,"]"); else strcpy(tokenbuf,"}"); *tokenbuf += (char)128; str_cat(str,tokenbuf); } } str_free(tmpstr); break; case OFLD: str = str_new(0); if (split_to_array) { str_set(str,"$Fld"); str_cat(str,"["); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,"]"); } else { i = atoi(walk(1,level,ops[node+1].ival,&numarg,P_MIN)->str_ptr); if (i <= arymax) sprintf(tokenbuf,"$%s",nameary[i]); else sprintf(tokenbuf,"$Fld%d",i); str_set(str,tokenbuf); } break; case OVFLD: str = str_new(0); str_set(str,"$Fld["); i = ops[node+1].ival; if ((ops[i].ival & 255) == OPAREN) i = ops[i+1].ival; tmpstr=walk(1,level,i,&numarg,P_MIN); str_scat(str,tmpstr); str_free(tmpstr); str_cat(str,"]"); break; case OJUNK: goto def; case OSNEWLINE: str = str_new(2); str_set(str,";\n"); tab(str,level); break; case ONEWLINE: str = str_new(1); str_set(str,"\n"); tab(str,level); break; case OSCOMMENT: str = str_new(0); str_set(str,";"); tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN); for (s = tmpstr->str_ptr; *s && *s != '\n'; s++) *s += (char)128; str_scat(str,tmpstr); str_free(tmpstr); tab(str,level); break; case OCOMMENT: str = str_new(0); tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN); for (s = tmpstr->str_ptr; *s && *s != '\n'; s++) *s += (char)128; str_scat(str,tmpstr); str_free(tmpstr); tab(str,level); break; case OCOMMA: prec = P_COMMA; str = walk(1,level,ops[node+1].ival,&numarg,prec); str_cat(str,", "); str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1)); str_free(fstr); break; case OSEMICOLON: str = str_new(1); str_set(str,";\n"); tab(str,level); break; case OSTATES: str = walk(0,level,ops[node+1].ival,&numarg,P_MIN); str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); break; case OSTATE: str = str_new(0); if (len >= 1) { str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); if (len >= 2) { tmpstr = walk(0,level,ops[node+2].ival,&numarg,P_MIN); if (*tmpstr->str_ptr == ';') { addsemi(str); str_cat(str,tmpstr->str_ptr+1); } str_free(tmpstr); } } break; case OCLOSE: str = str_make("close("); tmpstr = walk(1,level,ops[node+1].ival,&numarg,P_MIN); if (!do_fancy_opens) { t = tmpstr->str_ptr; if (*t == '"' || *t == '\'') t = cpytill(tokenbuf,t+1,*t); else fatal("Internal error: OCLOSE %s",t); s = savestr(tokenbuf); for (t = tokenbuf; *t; t++) { *t &= 127; if (isLOWER(*t)) *t = toUPPER(*t); if (!isALPHA(*t) && !isDIGIT(*t)) *t = '_'; } if (!strchr(tokenbuf,'_')) strcpy(t,"_FH"); str_free(tmpstr); safefree(s); str_set(str,"close "); str_cat(str,tokenbuf); } else { sprintf(tokenbuf,"delete $opened{%s} && close(%s)", tmpstr->str_ptr, tmpstr->str_ptr); str_free(tmpstr); str_set(str,tokenbuf); } break; case OPRINTF: case OPRINT: lparen = ""; /* set to parens if necessary */ rparen = ""; str = str_new(0); if (len == 3) { /* output redirection */ tmpstr = walk(1,level,ops[node+3].ival,&numarg,P_MIN); tmp2str = walk(1,level,ops[node+2].ival,&numarg,P_MIN); if (!do_fancy_opens) { t = tmpstr->str_ptr; if (*t == '"' || *t == '\'') t = cpytill(tokenbuf,t+1,*t); else fatal("Internal error: OPRINT"); d = savestr(t); s = savestr(tokenbuf); for (t = tokenbuf; *t; t++) { *t &= 127; if (isLOWER(*t)) *t = toUPPER(*t); if (!isALPHA(*t) && !isDIGIT(*t)) *t = '_'; } if (!strchr(tokenbuf,'_')) strcpy(t,"_FH"); tmp3str = hfetch(symtab,tokenbuf); if (!tmp3str) { str_cat(opens,"open("); str_cat(opens,tokenbuf); str_cat(opens,", "); d[1] = '\0'; str_cat(opens,d); str_scat(opens,tmp2str); str_cat(opens,tmpstr->str_ptr+1); if (*tmp2str->str_ptr == '|') str_cat(opens,") || die 'Cannot pipe to \""); else str_cat(opens,") || die 'Cannot create file \""); if (*d == '"') str_cat(opens,"'.\""); str_cat(opens,s); if (*d == '"') str_cat(opens,"\".'"); str_cat(opens,"\".';\n"); hstore(symtab,tokenbuf,str_make("x")); } str_free(tmpstr); str_free(tmp2str); safefree(s); safefree(d); } else { sprintf(tokenbuf,"&Pick('%s', %s) &&\n", tmp2str->str_ptr, tmpstr->str_ptr); str_cat(str,tokenbuf); tab(str,level+1); strcpy(tokenbuf,"$fh"); str_free(tmpstr); str_free(tmp2str); lparen = "("; rparen = ")"; } } else strcpy(tokenbuf,""); str_cat(str,lparen); /* may be null */ if (type == OPRINTF) str_cat(str,"printf"); else str_cat(str,"print"); saw_fh = 0; if (len == 3 || do_fancy_opens) { if (*tokenbuf) { str_cat(str," "); saw_fh = 1; } str_cat(str,tokenbuf); } tmpstr = walk(1+(type==OPRINT),level,ops[node+1].ival,&numarg,P_MIN); if (!*tmpstr->str_ptr && lval_field) { const char *t = (saw_OFS ? "$," : "' '"); if (split_to_array) { sprintf(tokenbuf,"join(%s,@Fld)",t); str_cat(tmpstr,tokenbuf); } else { for (i = 1; i < maxfld; i++) { if (i <= arymax) sprintf(tokenbuf,"$%s, ",nameary[i]); else sprintf(tokenbuf,"$Fld%d, ",i); str_cat(tmpstr,tokenbuf); } if (maxfld <= arymax) sprintf(tokenbuf,"$%s",nameary[maxfld]); else sprintf(tokenbuf,"$Fld%d",maxfld); str_cat(tmpstr,tokenbuf); } } if (*tmpstr->str_ptr) { str_cat(str," "); if (!saw_fh && *tmpstr->str_ptr == '(') { str_cat(str,"("); str_scat(str,tmpstr); str_cat(str,")"); } else str_scat(str,tmpstr); } else { str_cat(str," $_"); } str_cat(str,rparen); /* may be null */ str_free(tmpstr); break; case ORAND: str = str_make("rand(1)"); break; case OSRAND: str = str_make("srand("); goto maybe0; case OATAN2: str = str_make("atan2("); goto maybe0; case OSIN: str = str_make("sin("); goto maybe0; case OCOS: str = str_make("cos("); goto maybe0; case OSYSTEM: str = str_make("system("); goto maybe0; case OLENGTH: str = str_make("length("); goto maybe0; case OLOG: str = str_make("log("); goto maybe0; case OEXP: str = str_make("exp("); goto maybe0; case OSQRT: str = str_make("sqrt("); goto maybe0; case OINT: str = str_make("int("); maybe0: numeric = 1; if (len > 0) tmpstr = walk(1,level,ops[node+1].ival,&numarg,P_MIN); else tmpstr = str_new(0); if (!tmpstr->str_ptr || !*tmpstr->str_ptr) { if (lval_field) { const char *t = (saw_OFS ? "$," : "' '"); if (split_to_array) { sprintf(tokenbuf,"join(%s,@Fld)",t); str_cat(tmpstr,tokenbuf); } else { sprintf(tokenbuf,"join(%s, ",t); str_cat(tmpstr,tokenbuf); for (i = 1; i < maxfld; i++) { if (i <= arymax) sprintf(tokenbuf,"$%s,",nameary[i]); else sprintf(tokenbuf,"$Fld%d,",i); str_cat(tmpstr,tokenbuf); } if (maxfld <= arymax) sprintf(tokenbuf,"$%s)",nameary[maxfld]); else sprintf(tokenbuf,"$Fld%d)",maxfld); str_cat(tmpstr,tokenbuf); } } else str_cat(tmpstr,"$_"); } if (strEQ(tmpstr->str_ptr,"$_")) { if (type == OLENGTH && !do_chop) { str = str_make("(length("); str_cat(tmpstr,") - 1"); } } str_scat(str,tmpstr); str_free(tmpstr); str_cat(str,")"); break; case OBREAK: str = str_new(0); str_set(str,"last"); break; case ONEXT: str = str_new(0); str_set(str,"next line"); break; case OEXIT: str = str_new(0); if (realexit) { prec = P_UNI; str_set(str,"exit"); if (len == 1) { str_cat(str," "); exitval = TRUE; str_scat(str, fstr=walk(1,level,ops[node+1].ival,&numarg,prec+1)); str_free(fstr); } } else { if (len == 1) { str_set(str,"$ExitValue = "); exitval = TRUE; str_scat(str, fstr=walk(1,level,ops[node+1].ival,&numarg,P_ASSIGN)); str_free(fstr); str_cat(str,"; "); } str_cat(str,"last line"); } break; case OCONTINUE: str = str_new(0); str_set(str,"next"); break; case OREDIR: goto def; case OIF: str = str_new(0); str_set(str,"if ("); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,") "); str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); if (len == 3) { i = ops[node+3].ival; if (i) { if ((ops[i].ival & 255) == OBLOCK) { i = ops[i+1].ival; if (i) { if ((ops[i].ival & 255) != OIF) i = 0; } } else i = 0; } if (i) { str_cat(str,"els"); str_scat(str,fstr=walk(0,level,i,&numarg,P_MIN)); str_free(fstr); } else { str_cat(str,"else "); str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg,P_MIN)); str_free(fstr); } } break; case OWHILE: str = str_new(0); str_set(str,"while ("); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,") "); str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); break; case ODO: str = str_new(0); str_set(str,"do "); str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); if (str->str_ptr[str->str_cur - 1] == '\n') --str->str_cur; str_cat(str," while ("); str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,");"); break; case OFOR: str = str_new(0); str_set(str,"for ("); str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); i = numarg; if (i) { t = s = tmpstr->str_ptr; while (isALPHA(*t) || isDIGIT(*t) || *t == '$' || *t == '_') t++; i = t - s; if (i < 2) i = 0; } str_cat(str,"; "); fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN); if (i && (t = strchr(fstr->str_ptr,0377))) { if (strnEQ(fstr->str_ptr,s,i)) *t = ' '; } str_scat(str,fstr); str_free(fstr); str_free(tmpstr); str_cat(str,"; "); str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,P_MIN)); str_free(fstr); str_cat(str,") "); str_scat(str,fstr=walk(0,level,ops[node+4].ival,&numarg,P_MIN)); str_free(fstr); break; case OFORIN: tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN); d = strchr(tmpstr->str_ptr,'$'); if (!d) fatal("Illegal for loop: %s",tmpstr->str_ptr); s = strchr(d,'{'); if (!s) s = strchr(d,'['); if (!s) fatal("Illegal for loop: %s",d); *s++ = '\0'; for (t = s; (i = *t); t++) { i &= 127; if (i == '}' || i == ']') break; } if (*t) *t = '\0'; str = str_new(0); str_set(str,d+1); str_cat(str,"[]"); tmp2str = hfetch(symtab,str->str_ptr); if (tmp2str && atoi(tmp2str->str_ptr)) { sprintf(tokenbuf, "foreach %s ($[ .. $#%s) ", s, d+1); } else { sprintf(tokenbuf, "foreach %s (keys %%%s) ", s, d+1); } str_set(str,tokenbuf); str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); str_free(tmpstr); break; case OBLOCK: str = str_new(0); str_set(str,"{"); if (len >= 2 && ops[node+2].ival) { str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN)); str_free(fstr); } fixtab(str,++level); str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN)); str_free(fstr); addsemi(str); fixtab(str,--level); str_cat(str,"}\n"); tab(str,level); if (len >= 3) { str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg,P_MIN)); str_free(fstr); } break; default: def: if (len) { if (len > 5) fatal("Garbage length in walk"); str = walk(0,level,ops[node+1].ival,&numarg,P_MIN); for (i = 2; i<= len; i++) { str_scat(str,fstr=walk(0,level,ops[node+i].ival,&numarg,P_MIN)); str_free(fstr); } } else { str = Nullstr; } break; } if (!str) str = str_new(0); if (useval && prec < minprec) { /* need parens? */ fstr = str_new(str->str_cur+2); str_nset(fstr,"(",1); str_scat(fstr,str); str_ncat(fstr,")",1); str_free(str); str = fstr; } *numericptr = numeric; #ifdef DEBUGGING if (debug & 4) { printf("%3d %5d %15s %d %4d ",level,node,opname[type],len,str->str_cur); for (t = str->str_ptr; *t && t - str->str_ptr < 40; t++) if (*t == '\n') printf("\\n"); else if (*t == '\t') printf("\\t"); else putchar(*t); putchar('\n'); } #endif return str; } static void tab(register STR *str, register int lvl) { while (lvl > 1) { str_cat(str,"\t"); lvl -= 2; } if (lvl) str_cat(str," "); } static void fixtab(register STR *str, register int lvl) { register char *s; /* strip trailing white space */ s = str->str_ptr+str->str_cur - 1; while (s >= str->str_ptr && (*s == ' ' || *s == '\t' || *s == '\n')) s--; s[1] = '\0'; str->str_cur = s + 1 - str->str_ptr; if (s >= str->str_ptr && *s != '\n') str_cat(str,"\n"); tab(str,lvl); } static void addsemi(register STR *str) { register char *s; s = str->str_ptr+str->str_cur - 1; while (s >= str->str_ptr && (*s == ' ' || *s == '\t' || *s == '\n')) s--; if (s >= str->str_ptr && *s != ';' && *s != '}') str_cat(str,";"); } static void emit_split(register STR *str, int level) { register int i; if (split_to_array) str_cat(str,"@Fld"); else { str_cat(str,"("); for (i = 1; i < maxfld; i++) { if (i <= arymax) sprintf(tokenbuf,"$%s,",nameary[i]); else sprintf(tokenbuf,"$Fld%d,",i); str_cat(str,tokenbuf); } if (maxfld <= arymax) sprintf(tokenbuf,"$%s)",nameary[maxfld]); else sprintf(tokenbuf,"$Fld%d)",maxfld); str_cat(str,tokenbuf); } if (const_FS) { sprintf(tokenbuf," = split(/[%c\\n]/, $_, -1);\n",const_FS); str_cat(str,tokenbuf); } else if (saw_FS) str_cat(str," = split($FS, $_, -1);\n"); else str_cat(str," = split(' ', $_, -1);\n"); tab(str,level); } int prewalk(int numit, int level, register int node, int *numericptr) { register int len; register int type; register int i; int numarg; int numeric = FALSE; STR *tmpstr; STR *tmp2str; if (!node) { *numericptr = 0; return 0; } type = ops[node].ival; len = type >> 8; type &= 255; switch (type) { case OPROG: prewalk(0,level,ops[node+1].ival,&numarg); if (ops[node+2].ival) { prewalk(0,level,ops[node+2].ival,&numarg); } ++level; prewalk(0,level,ops[node+3].ival,&numarg); --level; if (ops[node+3].ival) { prewalk(0,level,ops[node+4].ival,&numarg); } break; case OHUNKS: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); if (len == 3) { prewalk(0,level,ops[node+3].ival,&numarg); } break; case ORANGE: prewalk(1,level,ops[node+1].ival,&numarg); prewalk(1,level,ops[node+2].ival,&numarg); break; case OPAT: goto def; case OREGEX: prewalk(0,level,ops[node+1].ival,&numarg); break; case OHUNK: if (len == 1) { prewalk(0,level,ops[node+1].ival,&numarg); } else { i = prewalk(0,level,ops[node+1].ival,&numarg); if (i) { ++level; prewalk(0,level,ops[node+2].ival,&numarg); --level; } else { prewalk(0,level,ops[node+2].ival,&numarg); } } break; case OPPAREN: prewalk(0,level,ops[node+1].ival,&numarg); break; case OPANDAND: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); break; case OPOROR: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); break; case OPNOT: prewalk(0,level,ops[node+1].ival,&numarg); break; case OCPAREN: prewalk(0,level,ops[node+1].ival,&numarg); numeric |= numarg; break; case OCANDAND: prewalk(0,level,ops[node+1].ival,&numarg); numeric = 1; prewalk(0,level,ops[node+2].ival,&numarg); break; case OCOROR: prewalk(0,level,ops[node+1].ival,&numarg); numeric = 1; prewalk(0,level,ops[node+2].ival,&numarg); break; case OCNOT: prewalk(0,level,ops[node+1].ival,&numarg); numeric = 1; break; case ORELOP: prewalk(0,level,ops[node+2].ival,&numarg); numeric |= numarg; prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+3].ival,&numarg); numeric |= numarg; numeric = 1; break; case ORPAREN: prewalk(0,level,ops[node+1].ival,&numarg); numeric |= numarg; break; case OMATCHOP: prewalk(0,level,ops[node+2].ival,&numarg); prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+3].ival,&numarg); numeric = 1; break; case OMPAREN: prewalk(0,level,ops[node+1].ival,&numarg); numeric |= numarg; break; case OCONCAT: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); break; case OASSIGN: prewalk(0,level,ops[node+2].ival,&numarg); prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+3].ival,&numarg); if (numarg || strlen(ops[ops[node+1].ival+1].cval) > (Size_t)1) { numericize(ops[node+2].ival); if (!numarg) numericize(ops[node+3].ival); } numeric |= numarg; break; case OADD: prewalk(1,level,ops[node+1].ival,&numarg); prewalk(1,level,ops[node+2].ival,&numarg); numeric = 1; break; case OSUBTRACT: prewalk(1,level,ops[node+1].ival,&numarg); prewalk(1,level,ops[node+2].ival,&numarg); numeric = 1; break; case OMULT: prewalk(1,level,ops[node+1].ival,&numarg); prewalk(1,level,ops[node+2].ival,&numarg); numeric = 1; break; case ODIV: prewalk(1,level,ops[node+1].ival,&numarg); prewalk(1,level,ops[node+2].ival,&numarg); numeric = 1; break; case OPOW: prewalk(1,level,ops[node+1].ival,&numarg); prewalk(1,level,ops[node+2].ival,&numarg); numeric = 1; break; case OMOD: prewalk(1,level,ops[node+1].ival,&numarg); prewalk(1,level,ops[node+2].ival,&numarg); numeric = 1; break; case OPOSTINCR: prewalk(1,level,ops[node+1].ival,&numarg); numeric = 1; break; case OPOSTDECR: prewalk(1,level,ops[node+1].ival,&numarg); numeric = 1; break; case OPREINCR: prewalk(1,level,ops[node+1].ival,&numarg); numeric = 1; break; case OPREDECR: prewalk(1,level,ops[node+1].ival,&numarg); numeric = 1; break; case OUMINUS: prewalk(1,level,ops[node+1].ival,&numarg); numeric = 1; break; case OUPLUS: prewalk(1,level,ops[node+1].ival,&numarg); numeric = 1; break; case OPAREN: prewalk(0,level,ops[node+1].ival,&numarg); numeric |= numarg; break; case OGETLINE: break; case OSPRINTF: prewalk(0,level,ops[node+1].ival,&numarg); break; case OSUBSTR: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(1,level,ops[node+2].ival,&numarg); if (len == 3) { prewalk(1,level,ops[node+3].ival,&numarg); } break; case OSTRING: break; case OSPLIT: numeric = 1; prewalk(0,level,ops[node+2].ival,&numarg); if (len == 3) prewalk(0,level,ops[node+3].ival,&numarg); prewalk(0,level,ops[node+1].ival,&numarg); break; case OINDEX: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); numeric = 1; break; case OMATCH: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); numeric = 1; break; case OUSERDEF: subretnum = FALSE; --level; tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN); ++level; prewalk(0,level,ops[node+2].ival,&numarg); prewalk(0,level,ops[node+4].ival,&numarg); prewalk(0,level,ops[node+5].ival,&numarg); --level; str_cat(tmpstr,"("); tmp2str = str_new(0); if (subretnum || numarg) str_set(tmp2str,"1"); hstore(symtab,tmpstr->str_ptr,tmp2str); str_free(tmpstr); level++; break; case ORETURN: if (len > 0) { prewalk(0,level,ops[node+1].ival,&numarg); if (numarg) subretnum = TRUE; } break; case OUSERFUN: tmp2str = str_new(0); str_scat(tmp2str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN)); fixrargs(tmpstr->str_ptr,ops[node+2].ival,0); str_free(tmpstr); str_cat(tmp2str,"("); tmpstr = hfetch(symtab,tmp2str->str_ptr); if (tmpstr && tmpstr->str_ptr) numeric |= atoi(tmpstr->str_ptr); prewalk(0,level,ops[node+2].ival,&numarg); str_free(tmp2str); break; case OGSUB: case OSUB: if (len >= 3) prewalk(0,level,ops[node+3].ival,&numarg); prewalk(0,level,ops[ops[node+2].ival+1].ival,&numarg); prewalk(0,level,ops[node+1].ival,&numarg); numeric = 1; break; case ONUM: prewalk(0,level,ops[node+1].ival,&numarg); numeric = 1; break; case OSTR: prewalk(0,level,ops[node+1].ival,&numarg); break; case ODEFINED: case ODELETE: case OSTAR: case OVAR: prewalk(0,level,ops[node+1].ival,&numarg); if (len == 1) { if (numit) numericize(node); } else { prewalk(0,level,ops[node+2].ival,&numarg); } break; case OFLD: prewalk(0,level,ops[node+1].ival,&numarg); break; case OVFLD: i = ops[node+1].ival; prewalk(0,level,i,&numarg); break; case OJUNK: goto def; case OSNEWLINE: break; case ONEWLINE: break; case OSCOMMENT: break; case OCOMMENT: break; case OCOMMA: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); prewalk(0,level,ops[node+3].ival,&numarg); break; case OSEMICOLON: break; case OSTATES: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); break; case OSTATE: if (len >= 1) { prewalk(0,level,ops[node+1].ival,&numarg); if (len >= 2) { prewalk(0,level,ops[node+2].ival,&numarg); } } break; case OCLOSE: prewalk(0,level,ops[node+1].ival,&numarg); break; case OPRINTF: case OPRINT: if (len == 3) { /* output redirection */ prewalk(0,level,ops[node+3].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); } prewalk(0+(type==OPRINT),level,ops[node+1].ival,&numarg); break; case ORAND: break; case OSRAND: goto maybe0; case OATAN2: goto maybe0; case OSIN: goto maybe0; case OCOS: goto maybe0; case OSYSTEM: goto maybe0; case OLENGTH: goto maybe0; case OLOG: goto maybe0; case OEXP: goto maybe0; case OSQRT: goto maybe0; case OINT: maybe0: numeric = 1; if (len > 0) prewalk(type != OLENGTH && type != OSYSTEM, level,ops[node+1].ival,&numarg); break; case OBREAK: break; case ONEXT: break; case OEXIT: if (len == 1) { prewalk(1,level,ops[node+1].ival,&numarg); } break; case OCONTINUE: break; case OREDIR: goto def; case OIF: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); if (len == 3) { prewalk(0,level,ops[node+3].ival,&numarg); } break; case OWHILE: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); break; case OFOR: prewalk(0,level,ops[node+1].ival,&numarg); prewalk(0,level,ops[node+2].ival,&numarg); prewalk(0,level,ops[node+3].ival,&numarg); prewalk(0,level,ops[node+4].ival,&numarg); break; case OFORIN: prewalk(0,level,ops[node+2].ival,&numarg); prewalk(0,level,ops[node+1].ival,&numarg); break; case OBLOCK: if (len == 2) { prewalk(0,level,ops[node+2].ival,&numarg); } ++level; prewalk(0,level,ops[node+1].ival,&numarg); --level; break; default: def: if (len) { if (len > 5) fatal("Garbage length in prewalk"); prewalk(0,level,ops[node+1].ival,&numarg); for (i = 2; i<= len; i++) { prewalk(0,level,ops[node+i].ival,&numarg); } } break; } *numericptr = numeric; return 1; } static void numericize(register int node) { register int len; register int type; STR *tmpstr; STR *tmp2str; int numarg; type = ops[node].ival; len = type >> 8; type &= 255; if (type == OVAR && len == 1) { tmpstr=walk(0,0,ops[node+1].ival,&numarg,P_MIN); tmp2str = str_make("1"); hstore(symtab,tmpstr->str_ptr,tmp2str); } }