1: char rcsid[] = "$Header: perly.c,v 1.0.1.3 88/01/28 10:28:31 root Exp $"; 2: /* 3: * $Log: perly.c,v $ 4: * Revision 1.0.1.3 88/01/28 10:28:31 root 5: * patch8: added eval operator. Also fixed expectterm following right curly. 6: * 7: * Revision 1.0.1.2 88/01/24 00:06:03 root 8: * patch 2: s/(abc)/\1/ grandfathering didn't work right. 9: * 10: * Revision 1.0.1.1 88/01/21 21:25:57 root 11: * Now uses CPP and CPPMINUS symbols from config.h. 12: * 13: * Revision 1.0 87/12/18 15:53:31 root 14: * Initial revision 15: * 16: */ 17: 18: bool preprocess = FALSE; 19: bool assume_n = FALSE; 20: bool assume_p = FALSE; 21: bool doswitches = FALSE; 22: bool allstabs = FALSE; /* init all customary symbols in symbol table?*/ 23: char *filename; 24: char *e_tmpname = "/tmp/perl-eXXXXXX"; 25: FILE *e_fp = Nullfp; 26: ARG *l(); 27: 28: main(argc,argv,env) 29: register int argc; 30: register char **argv; 31: register char **env; 32: { 33: register STR *str; 34: register char *s; 35: char *index(); 36: 37: linestr = str_new(80); 38: str = str_make("-I/usr/lib/perl "); /* first used for -I flags */ 39: for (argc--,argv++; argc; argc--,argv++) { 40: if (argv[0][0] != '-' || !argv[0][1]) 41: break; 42: reswitch: 43: switch (argv[0][1]) { 44: #ifdef DEBUGGING 45: case 'D': 46: debug = atoi(argv[0]+2); 47: #ifdef YYDEBUG 48: yydebug = (debug & 1); 49: #endif 50: break; 51: #endif 52: case 'e': 53: if (!e_fp) { 54: e_tmpname = (char*) strdup(e_tmpname); 55: mkstemp(e_tmpname); 56: e_fp = fopen(e_tmpname,"w"); 57: } 58: if (argv[1]) 59: fputs(argv[1],e_fp); 60: putc('\n', e_fp); 61: argc--,argv++; 62: break; 63: case 'i': 64: inplace = savestr(argv[0]+2); 65: argvoutstab = stabent("ARGVOUT",TRUE); 66: break; 67: case 'I': 68: str_cat(str,argv[0]); 69: str_cat(str," "); 70: if (!argv[0][2]) { 71: str_cat(str,argv[1]); 72: argc--,argv++; 73: str_cat(str," "); 74: } 75: break; 76: case 'n': 77: assume_n = TRUE; 78: strcpy(argv[0], argv[0]+1); 79: goto reswitch; 80: case 'p': 81: assume_p = TRUE; 82: strcpy(argv[0], argv[0]+1); 83: goto reswitch; 84: case 'P': 85: preprocess = TRUE; 86: strcpy(argv[0], argv[0]+1); 87: goto reswitch; 88: case 's': 89: doswitches = TRUE; 90: strcpy(argv[0], argv[0]+1); 91: goto reswitch; 92: case 'v': 93: version(); 94: exit(0); 95: case '-': 96: argc--,argv++; 97: goto switch_end; 98: case 0: 99: break; 100: default: 101: fatal("Unrecognized switch: %s\n",argv[0]); 102: } 103: } 104: switch_end: 105: if (e_fp) { 106: fclose(e_fp); 107: argc++,argv--; 108: argv[0] = e_tmpname; 109: } 110: 111: str_set(&str_no,No); 112: str_set(&str_yes,Yes); 113: init_eval(); 114: 115: /* open script */ 116: 117: if (argv[0] == Nullch) 118: argv[0] = "-"; 119: filename = savestr(argv[0]); 120: if (strEQ(filename,"-")) 121: argv[0] = ""; 122: if (preprocess) { 123: sprintf(buf, "\ 124: %s -e '/^[^#]/b' \ 125: -e '/^#[ ]*include[ ]/b' \ 126: -e '/^#[ ]*define[ ]/b' \ 127: -e '/^#[ ]*if[ ]/b' \ 128: -e '/^#[ ]*ifdef[ ]/b' \ 129: -e '/^#[ ]*else/b' \ 130: -e '/^#[ ]*endif/b' \ 131: -e 's/^#.*//' \ 132: %s | %s -C %s%s", 133: SED, argv[0], CPP, str_get(str), CPPMINUS); 134: rsfp = popen(buf,"r"); 135: } 136: else if (!*argv[0]) 137: rsfp = stdin; 138: else 139: rsfp = fopen(argv[0],"r"); 140: if (rsfp == Nullfp) 141: fatal("Perl script \"%s\" doesn't seem to exist.\n",filename); 142: str_free(str); /* free -I directories */ 143: 144: defstab = stabent("_",TRUE); 145: 146: /* init tokener */ 147: 148: bufptr = str_get(linestr); 149: 150: /* now parse the report spec */ 151: 152: if (yyparse()) 153: fatal("Execution aborted due to compilation errors.\n"); 154: 155: if (e_fp) { 156: e_fp = Nullfp; 157: UNLINK(e_tmpname); 158: } 159: argc--,argv++; /* skip name of script */ 160: if (doswitches) { 161: for (; argc > 0 && **argv == '-'; argc--,argv++) { 162: if (argv[0][1] == '-') { 163: argc--,argv++; 164: break; 165: } 166: str_numset(stabent(argv[0]+1,TRUE)->stab_val,(double)1.0); 167: } 168: } 169: if (argvstab = stabent("ARGV",allstabs)) { 170: for (; argc > 0; argc--,argv++) { 171: apush(argvstab->stab_array,str_make(argv[0])); 172: } 173: } 174: if (envstab = stabent("ENV",allstabs)) { 175: for (; *env; env++) { 176: if (!(s = index(*env,'='))) 177: continue; 178: *s++ = '\0'; 179: str = str_make(s); 180: str->str_link.str_magic = envstab; 181: hstore(envstab->stab_hash,*env,str); 182: *--s = '='; 183: } 184: } 185: sigstab = stabent("SIG",allstabs); 186: 187: magicalize("!#?^~=-%0123456789.+&*(),\\/[|"); 188: 189: (tmpstab = stabent("0",allstabs)) && str_set(STAB_STR(tmpstab),filename); 190: (tmpstab = stabent("$",allstabs)) && 191: str_numset(STAB_STR(tmpstab),(double)getpid()); 192: 193: tmpstab = stabent("stdin",TRUE); 194: tmpstab->stab_io = stio_new(); 195: tmpstab->stab_io->fp = stdin; 196: 197: tmpstab = stabent("stdout",TRUE); 198: tmpstab->stab_io = stio_new(); 199: tmpstab->stab_io->fp = stdout; 200: defoutstab = tmpstab; 201: curoutstab = tmpstab; 202: 203: tmpstab = stabent("stderr",TRUE); 204: tmpstab->stab_io = stio_new(); 205: tmpstab->stab_io->fp = stderr; 206: safefree(filename); 207: filename = "(eval)"; 208: 209: setjmp(top_env); /* sets goto_targ on longjump */ 210: 211: #ifdef DEBUGGING 212: if (debug & 1024) 213: dump_cmd(main_root,Nullcmd); 214: if (debug) 215: fprintf(stderr,"\nEXECUTING...\n\n"); 216: #endif 217: 218: /* do it */ 219: 220: (void) cmd_exec(main_root); 221: 222: if (goto_targ) 223: fatal("Can't find label \"%s\"--aborting.\n",goto_targ); 224: exit(0); 225: } 226: 227: magicalize(list) 228: register char *list; 229: { 230: register STAB *stab; 231: char sym[2]; 232: 233: sym[1] = '\0'; 234: while (*sym = *list++) { 235: if (stab = stabent(sym,allstabs)) { 236: stab->stab_flags = SF_VMAGIC; 237: stab->stab_val->str_link.str_magic = stab; 238: } 239: } 240: } 241: 242: #define RETURN(retval) return (bufptr = s,retval) 243: #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,retval) 244: #define TERM(retval) return (expectterm = FALSE,bufptr = s,retval) 245: #define LOOPX(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,LOOPEX) 246: #define UNI(f) return (yylval.ival = f,expectterm = TRUE,bufptr = s,UNIOP) 247: #define FUN0(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,FUNC0) 248: #define FUN1(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,FUNC1) 249: #define FUN2(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,FUNC2) 250: #define FUN3(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,FUNC3) 251: #define SFUN(f) return (yylval.ival = f,expectterm = FALSE,bufptr = s,STABFUN) 252: 253: yylex() 254: { 255: register char *s = bufptr; 256: register char *d; 257: register int tmp; 258: static bool in_format = FALSE; 259: static bool firstline = TRUE; 260: 261: retry: 262: #ifdef YYDEBUG 263: if (yydebug) 264: if (index(s,'\n')) 265: fprintf(stderr,"Tokener at %s",s); 266: else 267: fprintf(stderr,"Tokener at %s\n",s); 268: #endif 269: switch (*s) { 270: default: 271: fprintf(stderr, 272: "Unrecognized character %c in file %s line %d--ignoring.\n", 273: *s++,filename,line); 274: goto retry; 275: case 0: 276: s = str_get(linestr); 277: *s = '\0'; 278: if (firstline && (assume_n || assume_p)) { 279: firstline = FALSE; 280: str_set(linestr,"while (<>) {"); 281: s = str_get(linestr); 282: goto retry; 283: } 284: if (!rsfp) 285: RETURN(0); 286: if (in_format) { 287: yylval.formval = load_format(); /* leaves . in buffer */ 288: in_format = FALSE; 289: s = str_get(linestr); 290: TERM(FORMLIST); 291: } 292: line++; 293: if ((s = str_gets(linestr, rsfp)) == Nullch) { 294: if (preprocess) 295: pclose(rsfp); 296: else if (rsfp != stdin) 297: fclose(rsfp); 298: rsfp = Nullfp; 299: if (assume_n || assume_p) { 300: str_set(linestr,assume_p ? "}continue{print;" : ""); 301: str_cat(linestr,"}"); 302: s = str_get(linestr); 303: goto retry; 304: } 305: s = str_get(linestr); 306: RETURN(0); 307: } 308: #ifdef DEBUG 309: else if (firstline) { 310: char *showinput(); 311: s = showinput(); 312: } 313: #endif 314: firstline = FALSE; 315: goto retry; 316: case ' ': case '\t': 317: s++; 318: goto retry; 319: case '\n': 320: case '#': 321: if (preprocess && s == str_get(linestr) && 322: s[1] == ' ' && isdigit(s[2])) { 323: line = atoi(s+2)-1; 324: for (s += 2; isdigit(*s); s++) ; 325: while (*s && isspace(*s)) s++; 326: if (filename) 327: safefree(filename); 328: s[strlen(s)-1] = '\0'; /* wipe out newline */ 329: filename = savestr(s); 330: s = str_get(linestr); 331: } 332: if (in_eval) { 333: while (*s && *s != '\n') 334: s++; 335: if (*s) 336: s++; 337: line++; 338: } 339: else 340: *s = '\0'; 341: if (lex_newlines) 342: RETURN('\n'); 343: goto retry; 344: case '+': 345: case '-': 346: if (s[1] == *s) { 347: s++; 348: if (*s++ == '+') 349: RETURN(INC); 350: else 351: RETURN(DEC); 352: } 353: /* FALL THROUGH */ 354: case '*': 355: case '%': 356: case '^': 357: case '~': 358: case '(': 359: case ',': 360: case ':': 361: case ';': 362: case '{': 363: case '[': 364: tmp = *s++; 365: OPERATOR(tmp); 366: case ')': 367: case ']': 368: tmp = *s++; 369: TERM(tmp); 370: case '}': 371: tmp = *s++; 372: for (d = s; *d == ' ' || *d == '\t'; d++) ; 373: if (*d == '\n' || *d == '#') 374: OPERATOR(tmp); /* block end */ 375: else 376: TERM(tmp); /* associative array end */ 377: case '&': 378: s++; 379: tmp = *s++; 380: if (tmp == '&') 381: OPERATOR(ANDAND); 382: s--; 383: OPERATOR('&'); 384: case '|': 385: s++; 386: tmp = *s++; 387: if (tmp == '|') 388: OPERATOR(OROR); 389: s--; 390: OPERATOR('|'); 391: case '=': 392: s++; 393: tmp = *s++; 394: if (tmp == '=') 395: OPERATOR(EQ); 396: if (tmp == '~') 397: OPERATOR(MATCH); 398: s--; 399: OPERATOR('='); 400: case '!': 401: s++; 402: tmp = *s++; 403: if (tmp == '=') 404: OPERATOR(NE); 405: if (tmp == '~') 406: OPERATOR(NMATCH); 407: s--; 408: OPERATOR('!'); 409: case '<': 410: if (expectterm) { 411: s = scanstr(s); 412: TERM(RSTRING); 413: } 414: s++; 415: tmp = *s++; 416: if (tmp == '<') 417: OPERATOR(LS); 418: if (tmp == '=') 419: OPERATOR(LE); 420: s--; 421: OPERATOR('<'); 422: case '>': 423: s++; 424: tmp = *s++; 425: if (tmp == '>') 426: OPERATOR(RS); 427: if (tmp == '=') 428: OPERATOR(GE); 429: s--; 430: OPERATOR('>'); 431: 432: #define SNARFWORD \ 433: d = tokenbuf; \ 434: while (isalpha(*s) || isdigit(*s) || *s == '_') \ 435: *d++ = *s++; \ 436: *d = '\0'; \ 437: d = tokenbuf; 438: 439: case '$': 440: if (s[1] == '#' && (isalpha(s[2]) || s[2] == '_')) { 441: s++; 442: s = scanreg(s,tokenbuf); 443: yylval.stabval = aadd(stabent(tokenbuf,TRUE)); 444: TERM(ARYLEN); 445: } 446: s = scanreg(s,tokenbuf); 447: yylval.stabval = stabent(tokenbuf,TRUE); 448: TERM(REG); 449: 450: case '@': 451: s = scanreg(s,tokenbuf); 452: yylval.stabval = aadd(stabent(tokenbuf,TRUE)); 453: TERM(ARY); 454: 455: case '/': /* may either be division or pattern */ 456: case '?': /* may either be conditional or pattern */ 457: if (expectterm) { 458: s = scanpat(s); 459: TERM(PATTERN); 460: } 461: tmp = *s++; 462: OPERATOR(tmp); 463: 464: case '.': 465: if (!expectterm || !isdigit(s[1])) { 466: s++; 467: tmp = *s++; 468: if (tmp == '.') 469: OPERATOR(DOTDOT); 470: s--; 471: OPERATOR('.'); 472: } 473: /* FALL THROUGH */ 474: case '0': case '1': case '2': case '3': case '4': 475: case '5': case '6': case '7': case '8': case '9': 476: case '\'': case '"': case '`': 477: s = scanstr(s); 478: TERM(RSTRING); 479: 480: case '_': 481: SNARFWORD; 482: yylval.cval = savestr(d); 483: OPERATOR(WORD); 484: case 'a': case 'A': 485: SNARFWORD; 486: yylval.cval = savestr(d); 487: OPERATOR(WORD); 488: case 'b': case 'B': 489: SNARFWORD; 490: yylval.cval = savestr(d); 491: OPERATOR(WORD); 492: case 'c': case 'C': 493: SNARFWORD; 494: if (strEQ(d,"continue")) 495: OPERATOR(CONTINUE); 496: if (strEQ(d,"chdir")) 497: UNI(O_CHDIR); 498: if (strEQ(d,"close")) 499: OPERATOR(CLOSE); 500: if (strEQ(d,"crypt")) 501: FUN2(O_CRYPT); 502: if (strEQ(d,"chop")) 503: OPERATOR(CHOP); 504: if (strEQ(d,"chmod")) { 505: yylval.ival = O_CHMOD; 506: OPERATOR(PRINT); 507: } 508: if (strEQ(d,"chown")) { 509: yylval.ival = O_CHOWN; 510: OPERATOR(PRINT); 511: } 512: yylval.cval = savestr(d); 513: OPERATOR(WORD); 514: case 'd': case 'D': 515: SNARFWORD; 516: if (strEQ(d,"do")) 517: OPERATOR(DO); 518: if (strEQ(d,"die")) 519: UNI(O_DIE); 520: yylval.cval = savestr(d); 521: OPERATOR(WORD); 522: case 'e': case 'E': 523: SNARFWORD; 524: if (strEQ(d,"else")) 525: OPERATOR(ELSE); 526: if (strEQ(d,"elsif")) 527: OPERATOR(ELSIF); 528: if (strEQ(d,"eq") || strEQ(d,"EQ")) 529: OPERATOR(SEQ); 530: if (strEQ(d,"exit")) 531: UNI(O_EXIT); 532: if (strEQ(d,"eval")) { 533: allstabs = TRUE; /* must initialize everything since */ 534: UNI(O_EVAL); /* we don't know what will be used */ 535: } 536: if (strEQ(d,"eof")) 537: TERM(FEOF); 538: if (strEQ(d,"exp")) 539: FUN1(O_EXP); 540: if (strEQ(d,"each")) 541: SFUN(O_EACH); 542: if (strEQ(d,"exec")) { 543: yylval.ival = O_EXEC; 544: OPERATOR(PRINT); 545: } 546: yylval.cval = savestr(d); 547: OPERATOR(WORD); 548: case 'f': case 'F': 549: SNARFWORD; 550: if (strEQ(d,"for")) 551: OPERATOR(FOR); 552: if (strEQ(d,"format")) { 553: in_format = TRUE; 554: OPERATOR(FORMAT); 555: } 556: if (strEQ(d,"fork")) 557: FUN0(O_FORK); 558: yylval.cval = savestr(d); 559: OPERATOR(WORD); 560: case 'g': case 'G': 561: SNARFWORD; 562: if (strEQ(d,"gt") || strEQ(d,"GT")) 563: OPERATOR(SGT); 564: if (strEQ(d,"ge") || strEQ(d,"GE")) 565: OPERATOR(SGE); 566: if (strEQ(d,"goto")) 567: LOOPX(O_GOTO); 568: if (strEQ(d,"gmtime")) 569: FUN1(O_GMTIME); 570: yylval.cval = savestr(d); 571: OPERATOR(WORD); 572: case 'h': case 'H': 573: SNARFWORD; 574: if (strEQ(d,"hex")) 575: FUN1(O_HEX); 576: yylval.cval = savestr(d); 577: OPERATOR(WORD); 578: case 'i': case 'I': 579: SNARFWORD; 580: if (strEQ(d,"if")) 581: OPERATOR(IF); 582: if (strEQ(d,"index")) 583: FUN2(O_INDEX); 584: if (strEQ(d,"int")) 585: FUN1(O_INT); 586: yylval.cval = savestr(d); 587: OPERATOR(WORD); 588: case 'j': case 'J': 589: SNARFWORD; 590: if (strEQ(d,"join")) 591: OPERATOR(JOIN); 592: yylval.cval = savestr(d); 593: OPERATOR(WORD); 594: case 'k': case 'K': 595: SNARFWORD; 596: if (strEQ(d,"keys")) 597: SFUN(O_KEYS); 598: if (strEQ(d,"kill")) { 599: yylval.ival = O_KILL; 600: OPERATOR(PRINT); 601: } 602: yylval.cval = savestr(d); 603: OPERATOR(WORD); 604: case 'l': case 'L': 605: SNARFWORD; 606: if (strEQ(d,"last")) 607: LOOPX(O_LAST); 608: if (strEQ(d,"length")) 609: FUN1(O_LENGTH); 610: if (strEQ(d,"lt") || strEQ(d,"LT")) 611: OPERATOR(SLT); 612: if (strEQ(d,"le") || strEQ(d,"LE")) 613: OPERATOR(SLE); 614: if (strEQ(d,"localtime")) 615: FUN1(O_LOCALTIME); 616: if (strEQ(d,"log")) 617: FUN1(O_LOG); 618: if (strEQ(d,"link")) 619: FUN2(O_LINK); 620: yylval.cval = savestr(d); 621: OPERATOR(WORD); 622: case 'm': case 'M': 623: SNARFWORD; 624: if (strEQ(d,"m")) { 625: s = scanpat(s-1); 626: TERM(PATTERN); 627: } 628: yylval.cval = savestr(d); 629: OPERATOR(WORD); 630: case 'n': case 'N': 631: SNARFWORD; 632: if (strEQ(d,"next")) 633: LOOPX(O_NEXT); 634: if (strEQ(d,"ne") || strEQ(d,"NE")) 635: OPERATOR(SNE); 636: yylval.cval = savestr(d); 637: OPERATOR(WORD); 638: case 'o': case 'O': 639: SNARFWORD; 640: if (strEQ(d,"open")) 641: OPERATOR(OPEN); 642: if (strEQ(d,"ord")) 643: FUN1(O_ORD); 644: if (strEQ(d,"oct")) 645: FUN1(O_OCT); 646: yylval.cval = savestr(d); 647: OPERATOR(WORD); 648: case 'p': case 'P': 649: SNARFWORD; 650: if (strEQ(d,"print")) { 651: yylval.ival = O_PRINT; 652: OPERATOR(PRINT); 653: } 654: if (strEQ(d,"printf")) { 655: yylval.ival = O_PRTF; 656: OPERATOR(PRINT); 657: } 658: if (strEQ(d,"push")) { 659: yylval.ival = O_PUSH; 660: OPERATOR(PUSH); 661: } 662: if (strEQ(d,"pop")) 663: OPERATOR(POP); 664: yylval.cval = savestr(d); 665: OPERATOR(WORD); 666: case 'q': case 'Q': 667: SNARFWORD; 668: yylval.cval = savestr(d); 669: OPERATOR(WORD); 670: case 'r': case 'R': 671: SNARFWORD; 672: if (strEQ(d,"reset")) 673: UNI(O_RESET); 674: if (strEQ(d,"redo")) 675: LOOPX(O_REDO); 676: if (strEQ(d,"rename")) 677: FUN2(O_RENAME); 678: yylval.cval = savestr(d); 679: OPERATOR(WORD); 680: case 's': case 'S': 681: SNARFWORD; 682: if (strEQ(d,"s")) { 683: s = scansubst(s); 684: TERM(SUBST); 685: } 686: if (strEQ(d,"shift")) 687: TERM(SHIFT); 688: if (strEQ(d,"split")) 689: TERM(SPLIT); 690: if (strEQ(d,"substr")) 691: FUN3(O_SUBSTR); 692: if (strEQ(d,"sprintf")) 693: OPERATOR(SPRINTF); 694: if (strEQ(d,"sub")) 695: OPERATOR(SUB); 696: if (strEQ(d,"select")) 697: OPERATOR(SELECT); 698: if (strEQ(d,"seek")) 699: OPERATOR(SEEK); 700: if (strEQ(d,"stat")) 701: OPERATOR(STAT); 702: if (strEQ(d,"sqrt")) 703: FUN1(O_SQRT); 704: if (strEQ(d,"sleep")) 705: UNI(O_SLEEP); 706: if (strEQ(d,"system")) { 707: yylval.ival = O_SYSTEM; 708: OPERATOR(PRINT); 709: } 710: yylval.cval = savestr(d); 711: OPERATOR(WORD); 712: case 't': case 'T': 713: SNARFWORD; 714: if (strEQ(d,"tr")) { 715: s = scantrans(s); 716: TERM(TRANS); 717: } 718: if (strEQ(d,"tell")) 719: TERM(TELL); 720: if (strEQ(d,"time")) 721: FUN0(O_TIME); 722: if (strEQ(d,"times")) 723: FUN0(O_TMS); 724: yylval.cval = savestr(d); 725: OPERATOR(WORD); 726: case 'u': case 'U': 727: SNARFWORD; 728: if (strEQ(d,"using")) 729: OPERATOR(USING); 730: if (strEQ(d,"until")) 731: OPERATOR(UNTIL); 732: if (strEQ(d,"unless")) 733: OPERATOR(UNLESS); 734: if (strEQ(d,"umask")) 735: FUN1(O_UMASK); 736: if (strEQ(d,"unshift")) { 737: yylval.ival = O_UNSHIFT; 738: OPERATOR(PUSH); 739: } 740: if (strEQ(d,"unlink")) { 741: yylval.ival = O_UNLINK; 742: OPERATOR(PRINT); 743: } 744: yylval.cval = savestr(d); 745: OPERATOR(WORD); 746: case 'v': case 'V': 747: SNARFWORD; 748: if (strEQ(d,"values")) 749: SFUN(O_VALUES); 750: yylval.cval = savestr(d); 751: OPERATOR(WORD); 752: case 'w': case 'W': 753: SNARFWORD; 754: if (strEQ(d,"write")) 755: TERM(WRITE); 756: if (strEQ(d,"while")) 757: OPERATOR(WHILE); 758: yylval.cval = savestr(d); 759: OPERATOR(WORD); 760: case 'x': case 'X': 761: SNARFWORD; 762: if (!expectterm && strEQ(d,"x")) 763: OPERATOR('x'); 764: yylval.cval = savestr(d); 765: OPERATOR(WORD); 766: case 'y': case 'Y': 767: SNARFWORD; 768: if (strEQ(d,"y")) { 769: s = scantrans(s); 770: TERM(TRANS); 771: } 772: yylval.cval = savestr(d); 773: OPERATOR(WORD); 774: case 'z': case 'Z': 775: SNARFWORD; 776: yylval.cval = savestr(d); 777: OPERATOR(WORD); 778: } 779: } 780: 781: STAB * 782: stabent(name,add) 783: register char *name; 784: int add; 785: { 786: register STAB *stab; 787: 788: for (stab = stab_index[*name]; stab; stab = stab->stab_next) { 789: if (strEQ(name,stab->stab_name)) 790: return stab; 791: } 792: 793: /* no entry--should we add one? */ 794: 795: if (add) { 796: stab = (STAB *) safemalloc(sizeof(STAB)); 797: bzero((char*)stab, sizeof(STAB)); 798: stab->stab_name = savestr(name); 799: stab->stab_val = str_new(0); 800: stab->stab_next = stab_index[*name]; 801: stab_index[*name] = stab; 802: return stab; 803: } 804: return Nullstab; 805: } 806: 807: STIO * 808: stio_new() 809: { 810: STIO *stio = (STIO *) safemalloc(sizeof(STIO)); 811: 812: bzero((char*)stio, sizeof(STIO)); 813: stio->page_len = 60; 814: return stio; 815: } 816: 817: char * 818: scanreg(s,dest) 819: register char *s; 820: char *dest; 821: { 822: register char *d; 823: 824: s++; 825: d = dest; 826: while (isalpha(*s) || isdigit(*s) || *s == '_') 827: *d++ = *s++; 828: *d = '\0'; 829: d = dest; 830: if (!*d) { 831: *d = *s++; 832: if (*d == '{') { 833: d = dest; 834: while (*s && *s != '}') 835: *d++ = *s++; 836: *d = '\0'; 837: d = dest; 838: if (*s) 839: s++; 840: } 841: else 842: d[1] = '\0'; 843: } 844: if (*d == '^' && !isspace(*s)) 845: *d = *s++ & 31; 846: return s; 847: } 848: 849: STR * 850: scanconst(string) 851: char *string; 852: { 853: register STR *retstr; 854: register char *t; 855: register char *d; 856: 857: if (index(string,'|')) { 858: return Nullstr; 859: } 860: retstr = str_make(string); 861: t = str_get(retstr); 862: for (d=t; *d; ) { 863: switch (*d) { 864: case '.': case '[': case '$': case '(': case ')': case '|': 865: *d = '\0'; 866: break; 867: case '\\': 868: if (index("wWbB0123456789",d[1])) { 869: *d = '\0'; 870: break; 871: } 872: strcpy(d,d+1); 873: switch(*d) { 874: case 'n': 875: *d = '\n'; 876: break; 877: case 't': 878: *d = '\t'; 879: break; 880: case 'f': 881: *d = '\f'; 882: break; 883: case 'r': 884: *d = '\r'; 885: break; 886: } 887: /* FALL THROUGH */ 888: default: 889: if (d[1] == '*' || d[1] == '+' || d[1] == '?') { 890: *d = '\0'; 891: break; 892: } 893: d++; 894: } 895: } 896: if (!*t) { 897: str_free(retstr); 898: return Nullstr; 899: } 900: retstr->str_cur = strlen(retstr->str_ptr); /* XXX cheating here */ 901: return retstr; 902: } 903: 904: char * 905: scanpat(s) 906: register char *s; 907: { 908: register SPAT *spat = (SPAT *) safemalloc(sizeof (SPAT)); 909: register char *d; 910: 911: bzero((char *)spat, sizeof(SPAT)); 912: spat->spat_next = spat_root; /* link into spat list */ 913: spat_root = spat; 914: init_compex(&spat->spat_compex); 915: 916: switch (*s++) { 917: case 'm': 918: s++; 919: break; 920: case '/': 921: break; 922: case '?': 923: spat->spat_flags |= SPAT_USE_ONCE; 924: break; 925: default: 926: fatal("Search pattern not found:\n%s",str_get(linestr)); 927: } 928: s = cpytill(tokenbuf,s,s[-1]); 929: if (!*s) 930: fatal("Search pattern not terminated:\n%s",str_get(linestr)); 931: s++; 932: if (*tokenbuf == '^') { 933: spat->spat_first = scanconst(tokenbuf+1); 934: if (spat->spat_first) { 935: spat->spat_flen = strlen(spat->spat_first->str_ptr); 936: if (spat->spat_flen == strlen(tokenbuf+1)) 937: spat->spat_flags |= SPAT_SCANALL; 938: } 939: } 940: else { 941: spat->spat_flags |= SPAT_SCANFIRST; 942: spat->spat_first = scanconst(tokenbuf); 943: if (spat->spat_first) { 944: spat->spat_flen = strlen(spat->spat_first->str_ptr); 945: if (spat->spat_flen == strlen(tokenbuf)) 946: spat->spat_flags |= SPAT_SCANALL; 947: } 948: } 949: if (d = compile(&spat->spat_compex,tokenbuf,TRUE,FALSE)) 950: fatal(d); 951: yylval.arg = make_match(O_MATCH,stab_to_arg(A_STAB,defstab),spat); 952: return s; 953: } 954: 955: char * 956: scansubst(s) 957: register char *s; 958: { 959: register SPAT *spat = (SPAT *) safemalloc(sizeof (SPAT)); 960: register char *d; 961: 962: bzero((char *)spat, sizeof(SPAT)); 963: spat->spat_next = spat_root; /* link into spat list */ 964: spat_root = spat; 965: init_compex(&spat->spat_compex); 966: 967: s = cpytill(tokenbuf,s+1,*s); 968: if (!*s) 969: fatal("Substitution pattern not terminated:\n%s",str_get(linestr)); 970: for (d=tokenbuf; *d; d++) { 971: if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') { 972: register ARG *arg; 973: 974: spat->spat_runtime = arg = op_new(1); 975: arg->arg_type = O_ITEM; 976: arg[1].arg_type = A_DOUBLE; 977: arg[1].arg_ptr.arg_str = str_make(tokenbuf); 978: goto get_repl; /* skip compiling for now */ 979: } 980: } 981: if (*tokenbuf == '^') { 982: spat->spat_first = scanconst(tokenbuf+1); 983: if (spat->spat_first) 984: spat->spat_flen = strlen(spat->spat_first->str_ptr); 985: } 986: else { 987: spat->spat_flags |= SPAT_SCANFIRST; 988: spat->spat_first = scanconst(tokenbuf); 989: if (spat->spat_first) 990: spat->spat_flen = strlen(spat->spat_first->str_ptr); 991: } 992: if (d = compile(&spat->spat_compex,tokenbuf,TRUE,FALSE)) 993: fatal(d); 994: get_repl: 995: s = scanstr(s); 996: if (!*s) 997: fatal("Substitution replacement not terminated:\n%s",str_get(linestr)); 998: spat->spat_repl = yylval.arg; 999: if (*s == 'g') { 1000: s++; 1001: spat->spat_flags &= ~SPAT_USE_ONCE; 1002: } 1003: else 1004: spat->spat_flags |= SPAT_USE_ONCE; 1005: yylval.arg = make_match(O_SUBST,stab_to_arg(A_STAB,defstab),spat); 1006: return s; 1007: } 1008: 1009: ARG * 1010: make_split(stab,arg) 1011: register STAB *stab; 1012: register ARG *arg; 1013: { 1014: if (arg->arg_type != O_MATCH) { 1015: register SPAT *spat = (SPAT *) safemalloc(sizeof (SPAT)); 1016: register char *d; 1017: 1018: bzero((char *)spat, sizeof(SPAT)); 1019: spat->spat_next = spat_root; /* link into spat list */ 1020: spat_root = spat; 1021: init_compex(&spat->spat_compex); 1022: 1023: spat->spat_runtime = arg; 1024: arg = make_match(O_MATCH,stab_to_arg(A_STAB,defstab),spat); 1025: } 1026: arg->arg_type = O_SPLIT; 1027: arg[2].arg_ptr.arg_spat->spat_repl = stab_to_arg(A_STAB,aadd(stab)); 1028: return arg; 1029: } 1030: 1031: char * 1032: expand_charset(s) 1033: register char *s; 1034: { 1035: char t[512]; 1036: register char *d = t; 1037: register int i; 1038: 1039: while (*s) { 1040: if (s[1] == '-' && s[2]) { 1041: for (i = s[0]; i <= s[2]; i++) 1042: *d++ = i; 1043: s += 3; 1044: } 1045: else 1046: *d++ = *s++; 1047: } 1048: *d = '\0'; 1049: return savestr(t); 1050: } 1051: 1052: char * 1053: scantrans(s) 1054: register char *s; 1055: { 1056: ARG *arg = 1057: l(make_op(O_TRANS,2,stab_to_arg(A_STAB,defstab),Nullarg,Nullarg,0)); 1058: register char *t; 1059: register char *r; 1060: register char *tbl = safemalloc(256); 1061: register int i; 1062: 1063: arg[2].arg_type = A_NULL; 1064: arg[2].arg_ptr.arg_cval = tbl; 1065: for (i=0; i<256; i++) 1066: tbl[i] = 0; 1067: s = scanstr(s); 1068: if (!*s) 1069: fatal("Translation pattern not terminated:\n%s",str_get(linestr)); 1070: t = expand_charset(str_get(yylval.arg[1].arg_ptr.arg_str)); 1071: free_arg(yylval.arg); 1072: s = scanstr(s-1); 1073: if (!*s) 1074: fatal("Translation replacement not terminated:\n%s",str_get(linestr)); 1075: r = expand_charset(str_get(yylval.arg[1].arg_ptr.arg_str)); 1076: free_arg(yylval.arg); 1077: yylval.arg = arg; 1078: if (!*r) { 1079: safefree(r); 1080: r = t; 1081: } 1082: for (i = 0; t[i]; i++) { 1083: if (!r[i]) 1084: r[i] = r[i-1]; 1085: tbl[t[i] & 0377] = r[i]; 1086: } 1087: if (r != t) 1088: safefree(r); 1089: safefree(t); 1090: return s; 1091: } 1092: 1093: CMD * 1094: block_head(tail) 1095: register CMD *tail; 1096: { 1097: if (tail == Nullcmd) { 1098: return tail; 1099: } 1100: return tail->c_head; 1101: } 1102: 1103: CMD * 1104: append_line(head,tail) 1105: register CMD *head; 1106: register CMD *tail; 1107: { 1108: if (tail == Nullcmd) 1109: return head; 1110: if (!tail->c_head) /* make sure tail is well formed */ 1111: tail->c_head = tail; 1112: if (head != Nullcmd) { 1113: tail = tail->c_head; /* get to start of tail list */ 1114: if (!head->c_head) 1115: head->c_head = head; /* start a new head list */ 1116: while (head->c_next) { 1117: head->c_next->c_head = head->c_head; 1118: head = head->c_next; /* get to end of head list */ 1119: } 1120: head->c_next = tail; /* link to end of old list */ 1121: tail->c_head = head->c_head; /* propagate head pointer */ 1122: } 1123: while (tail->c_next) { 1124: tail->c_next->c_head = tail->c_head; 1125: tail = tail->c_next; 1126: } 1127: return tail; 1128: } 1129: 1130: CMD * 1131: make_acmd(type,stab,cond,arg) 1132: int type; 1133: STAB *stab; 1134: ARG *cond; 1135: ARG *arg; 1136: { 1137: register CMD *cmd = (CMD *) safemalloc(sizeof (CMD)); 1138: 1139: bzero((char *)cmd, sizeof(CMD)); 1140: cmd->c_type = type; 1141: cmd->ucmd.acmd.ac_stab = stab; 1142: cmd->ucmd.acmd.ac_expr = arg; 1143: cmd->c_expr = cond; 1144: if (cond) { 1145: opt_arg(cmd,1); 1146: cmd->c_flags |= CF_COND; 1147: } 1148: return cmd; 1149: } 1150: 1151: CMD * 1152: make_ccmd(type,arg,cblock) 1153: int type; 1154: register ARG *arg; 1155: struct compcmd cblock; 1156: { 1157: register CMD *cmd = (CMD *) safemalloc(sizeof (CMD)); 1158: 1159: bzero((char *)cmd, sizeof(CMD)); 1160: cmd->c_type = type; 1161: cmd->c_expr = arg; 1162: cmd->ucmd.ccmd.cc_true = cblock.comp_true; 1163: cmd->ucmd.ccmd.cc_alt = cblock.comp_alt; 1164: if (arg) { 1165: opt_arg(cmd,1); 1166: cmd->c_flags |= CF_COND; 1167: } 1168: return cmd; 1169: } 1170: 1171: void 1172: opt_arg(cmd,fliporflop) 1173: register CMD *cmd; 1174: int fliporflop; 1175: { 1176: register ARG *arg; 1177: int opt = CFT_EVAL; 1178: int sure = 0; 1179: ARG *arg2; 1180: char *tmps; /* for True macro */ 1181: int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */ 1182: int flp = fliporflop; 1183: 1184: if (!cmd) 1185: return; 1186: arg = cmd->c_expr; 1187: 1188: /* Turn "if (!expr)" into "unless (expr)" */ 1189: 1190: while (arg->arg_type == O_NOT && arg[1].arg_type == A_EXPR) { 1191: cmd->c_flags ^= CF_INVERT; /* flip sense of cmd */ 1192: cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */ 1193: free_arg(arg); 1194: arg = cmd->c_expr; /* here we go again */ 1195: } 1196: 1197: if (!arg->arg_len) { /* sanity check */ 1198: cmd->c_flags |= opt; 1199: return; 1200: } 1201: 1202: /* for "cond .. cond" we set up for the initial check */ 1203: 1204: if (arg->arg_type == O_FLIP) 1205: context |= 4; 1206: 1207: /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */ 1208: 1209: if (arg->arg_type == O_AND) 1210: context |= 1; 1211: else if (arg->arg_type == O_OR) 1212: context |= 2; 1213: if (context && arg[flp].arg_type == A_EXPR) { 1214: arg = arg[flp].arg_ptr.arg_arg; 1215: flp = 1; 1216: } 1217: 1218: if (arg[flp].arg_flags & (AF_PRE|AF_POST)) { 1219: cmd->c_flags |= opt; 1220: return; /* side effect, can't optimize */ 1221: } 1222: 1223: if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP || 1224: arg->arg_type == O_AND || arg->arg_type == O_OR) { 1225: if (arg[flp].arg_type == A_SINGLE) { 1226: opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE); 1227: cmd->c_first = arg[flp].arg_ptr.arg_str; 1228: goto literal; 1229: } 1230: else if (arg[flp].arg_type == A_STAB || arg[flp].arg_type == A_LVAL) { 1231: cmd->c_stab = arg[flp].arg_ptr.arg_stab; 1232: opt = CFT_REG; 1233: literal: 1234: if (!context) { /* no && or ||? */ 1235: free_arg(arg); 1236: cmd->c_expr = Nullarg; 1237: } 1238: if (!(context & 1)) 1239: cmd->c_flags |= CF_EQSURE; 1240: if (!(context & 2)) 1241: cmd->c_flags |= CF_NESURE; 1242: } 1243: } 1244: else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST || 1245: arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) { 1246: if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) && 1247: arg[2].arg_type == A_SPAT && 1248: arg[2].arg_ptr.arg_spat->spat_first ) { 1249: cmd->c_stab = arg[1].arg_ptr.arg_stab; 1250: cmd->c_first = arg[2].arg_ptr.arg_spat->spat_first; 1251: cmd->c_flen = arg[2].arg_ptr.arg_spat->spat_flen; 1252: if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANALL && 1253: (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) ) 1254: sure |= CF_EQSURE; /* (SUBST must be forced even */ 1255: /* if we know it will work.) */ 1256: arg[2].arg_ptr.arg_spat->spat_first = Nullstr; 1257: arg[2].arg_ptr.arg_spat->spat_flen = 0; /* only one chk */ 1258: sure |= CF_NESURE; /* normally only sure if it fails */ 1259: if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) 1260: cmd->c_flags |= CF_FIRSTNEG; 1261: if (context & 1) { /* only sure if thing is false */ 1262: if (cmd->c_flags & CF_FIRSTNEG) 1263: sure &= ~CF_NESURE; 1264: else 1265: sure &= ~CF_EQSURE; 1266: } 1267: else if (context & 2) { /* only sure if thing is true */ 1268: if (cmd->c_flags & CF_FIRSTNEG) 1269: sure &= ~CF_EQSURE; 1270: else 1271: sure &= ~CF_NESURE; 1272: } 1273: if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/ 1274: if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST) 1275: opt = CFT_SCAN; 1276: else 1277: opt = CFT_ANCHOR; 1278: if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */ 1279: && arg->arg_type == O_MATCH 1280: && context & 4 1281: && fliporflop == 1) { 1282: arg[2].arg_type = A_SINGLE; /* don't do twice */ 1283: arg[2].arg_ptr.arg_str = &str_yes; 1284: } 1285: cmd->c_flags |= sure; 1286: } 1287: } 1288: } 1289: else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE || 1290: arg->arg_type == O_SLT || arg->arg_type == O_SGT) { 1291: if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) { 1292: if (arg[2].arg_type == A_SINGLE) { 1293: cmd->c_stab = arg[1].arg_ptr.arg_stab; 1294: cmd->c_first = arg[2].arg_ptr.arg_str; 1295: cmd->c_flen = 30000; 1296: switch (arg->arg_type) { 1297: case O_SLT: case O_SGT: 1298: sure |= CF_EQSURE; 1299: cmd->c_flags |= CF_FIRSTNEG; 1300: break; 1301: case O_SNE: 1302: cmd->c_flags |= CF_FIRSTNEG; 1303: /* FALL THROUGH */ 1304: case O_SEQ: 1305: sure |= CF_NESURE|CF_EQSURE; 1306: break; 1307: } 1308: if (context & 1) { /* only sure if thing is false */ 1309: if (cmd->c_flags & CF_FIRSTNEG) 1310: sure &= ~CF_NESURE; 1311: else 1312: sure &= ~CF_EQSURE; 1313: } 1314: else if (context & 2) { /* only sure if thing is true */ 1315: if (cmd->c_flags & CF_FIRSTNEG) 1316: sure &= ~CF_EQSURE; 1317: else 1318: sure &= ~CF_NESURE; 1319: } 1320: if (sure & (CF_EQSURE|CF_NESURE)) { 1321: opt = CFT_STROP; 1322: cmd->c_flags |= sure; 1323: } 1324: } 1325: } 1326: } 1327: else if (arg->arg_type == O_ASSIGN && 1328: (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) && 1329: arg[1].arg_ptr.arg_stab == defstab && 1330: arg[2].arg_type == A_EXPR ) { 1331: arg2 = arg[2].arg_ptr.arg_arg; 1332: if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) { 1333: opt = CFT_GETS; 1334: cmd->c_stab = arg2[1].arg_ptr.arg_stab; 1335: if (!(arg2[1].arg_ptr.arg_stab->stab_io->flags & IOF_ARGV)) { 1336: free_arg(arg2); 1337: free_arg(arg); 1338: cmd->c_expr = Nullarg; 1339: } 1340: } 1341: } 1342: else if (arg->arg_type == O_CHOP && 1343: (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) { 1344: opt = CFT_CHOP; 1345: cmd->c_stab = arg[1].arg_ptr.arg_stab; 1346: free_arg(arg); 1347: cmd->c_expr = Nullarg; 1348: } 1349: if (context & 4) 1350: opt |= CF_FLIP; 1351: cmd->c_flags |= opt; 1352: 1353: if (cmd->c_flags & CF_FLIP) { 1354: if (fliporflop == 1) { 1355: arg = cmd->c_expr; /* get back to O_FLIP arg */ 1356: arg[3].arg_ptr.arg_cmd = (CMD*)safemalloc(sizeof(CMD)); 1357: bcopy((char *)cmd, (char *)arg[3].arg_ptr.arg_cmd, sizeof(CMD)); 1358: arg[4].arg_ptr.arg_cmd = (CMD*)safemalloc(sizeof(CMD)); 1359: bcopy((char *)cmd, (char *)arg[4].arg_ptr.arg_cmd, sizeof(CMD)); 1360: opt_arg(arg[4].arg_ptr.arg_cmd,2); 1361: arg->arg_len = 2; /* this is a lie */ 1362: } 1363: else { 1364: if ((opt & CF_OPTIMIZE) == CFT_EVAL) 1365: cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP; 1366: } 1367: } 1368: } 1369: 1370: ARG * 1371: mod_match(type,left,pat) 1372: register ARG *left; 1373: register ARG *pat; 1374: { 1375: 1376: register SPAT *spat; 1377: register ARG *newarg; 1378: 1379: if ((pat->arg_type == O_MATCH || 1380: pat->arg_type == O_SUBST || 1381: pat->arg_type == O_TRANS || 1382: pat->arg_type == O_SPLIT 1383: ) && 1384: pat[1].arg_ptr.arg_stab == defstab ) { 1385: switch (pat->arg_type) { 1386: case O_MATCH: 1387: newarg = make_op(type == O_MATCH ? O_MATCH : O_NMATCH, 1388: pat->arg_len, 1389: left,Nullarg,Nullarg,0); 1390: break; 1391: case O_SUBST: 1392: newarg = l(make_op(type == O_MATCH ? O_SUBST : O_NSUBST, 1393: pat->arg_len, 1394: left,Nullarg,Nullarg,0)); 1395: break; 1396: case O_TRANS: 1397: newarg = l(make_op(type == O_MATCH ? O_TRANS : O_NTRANS, 1398: pat->arg_len, 1399: left,Nullarg,Nullarg,0)); 1400: break; 1401: case O_SPLIT: 1402: newarg = make_op(type == O_MATCH ? O_SPLIT : O_SPLIT, 1403: pat->arg_len, 1404: left,Nullarg,Nullarg,0); 1405: break; 1406: } 1407: if (pat->arg_len >= 2) { 1408: newarg[2].arg_type = pat[2].arg_type; 1409: newarg[2].arg_ptr = pat[2].arg_ptr; 1410: newarg[2].arg_flags = pat[2].arg_flags; 1411: if (pat->arg_len >= 3) { 1412: newarg[3].arg_type = pat[3].arg_type; 1413: newarg[3].arg_ptr = pat[3].arg_ptr; 1414: newarg[3].arg_flags = pat[3].arg_flags; 1415: } 1416: } 1417: safefree((char*)pat); 1418: } 1419: else { 1420: spat = (SPAT *) safemalloc(sizeof (SPAT)); 1421: bzero((char *)spat, sizeof(SPAT)); 1422: spat->spat_next = spat_root; /* link into spat list */ 1423: spat_root = spat; 1424: init_compex(&spat->spat_compex); 1425: 1426: spat->spat_runtime = pat; 1427: newarg = make_op(type,2,left,Nullarg,Nullarg,0); 1428: newarg[2].arg_type = A_SPAT; 1429: newarg[2].arg_ptr.arg_spat = spat; 1430: newarg[2].arg_flags = AF_SPECIAL; 1431: } 1432: 1433: return newarg; 1434: } 1435: 1436: CMD * 1437: add_label(lbl,cmd) 1438: char *lbl; 1439: register CMD *cmd; 1440: { 1441: if (cmd) 1442: cmd->c_label = lbl; 1443: return cmd; 1444: } 1445: 1446: CMD * 1447: addcond(cmd, arg) 1448: register CMD *cmd; 1449: register ARG *arg; 1450: { 1451: cmd->c_expr = arg; 1452: opt_arg(cmd,1); 1453: cmd->c_flags |= CF_COND; 1454: return cmd; 1455: } 1456: 1457: CMD * 1458: addloop(cmd, arg) 1459: register CMD *cmd; 1460: register ARG *arg; 1461: { 1462: cmd->c_expr = arg; 1463: opt_arg(cmd,1); 1464: cmd->c_flags |= CF_COND|CF_LOOP; 1465: if (cmd->c_type == C_BLOCK) 1466: cmd->c_flags &= ~CF_COND; 1467: else { 1468: arg = cmd->ucmd.acmd.ac_expr; 1469: if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD) 1470: cmd->c_flags &= ~CF_COND; /* "do {} while" happens at least once */ 1471: if (arg && arg->arg_type == O_SUBR) 1472: cmd->c_flags &= ~CF_COND; /* likewise for "do subr() while" */ 1473: } 1474: return cmd; 1475: } 1476: 1477: CMD * 1478: invert(cmd) 1479: register CMD *cmd; 1480: { 1481: cmd->c_flags ^= CF_INVERT; 1482: return cmd; 1483: } 1484: 1485: yyerror(s) 1486: char *s; 1487: { 1488: char tmpbuf[128]; 1489: char *tname = tmpbuf; 1490: 1491: if (yychar > 256) { 1492: tname = tokename[yychar-256]; 1493: if (strEQ(tname,"word")) 1494: strcpy(tname,tokenbuf); 1495: else if (strEQ(tname,"register")) 1496: sprintf(tname,"$%s",tokenbuf); 1497: else if (strEQ(tname,"array_length")) 1498: sprintf(tname,"$#%s",tokenbuf); 1499: } 1500: else if (!yychar) 1501: strcpy(tname,"EOF"); 1502: else if (yychar < 32) 1503: sprintf(tname,"^%c",yychar+64); 1504: else if (yychar == 127) 1505: strcpy(tname,"^?"); 1506: else 1507: sprintf(tname,"%c",yychar); 1508: sprintf(tokenbuf, "%s in file %s at line %d, next token \"%s\"\n", 1509: s,filename,line,tname); 1510: if (in_eval) 1511: str_set(stabent("@",TRUE)->stab_val,tokenbuf); 1512: else 1513: fputs(tokenbuf,stderr); 1514: } 1515: 1516: char * 1517: scanstr(s) 1518: register char *s; 1519: { 1520: register char term; 1521: register char *d; 1522: register ARG *arg; 1523: register bool makesingle = FALSE; 1524: char *leave = "\\$nrtfb0123456789"; /* which backslash sequences to keep */ 1525: 1526: arg = op_new(1); 1527: yylval.arg = arg; 1528: arg->arg_type = O_ITEM; 1529: 1530: switch (*s) { 1531: default: /* a substitution replacement */ 1532: arg[1].arg_type = A_DOUBLE; 1533: makesingle = TRUE; /* maybe disable runtime scanning */ 1534: term = *s; 1535: if (term == '\'') 1536: leave = Nullch; 1537: goto snarf_it; 1538: case '0': 1539: { 1540: long i; 1541: int shift; 1542: 1543: arg[1].arg_type = A_SINGLE; 1544: if (s[1] == 'x') { 1545: shift = 4; 1546: s += 2; 1547: } 1548: else if (s[1] == '.') 1549: goto decimal; 1550: else 1551: shift = 3; 1552: i = 0; 1553: for (;;) { 1554: switch (*s) { 1555: default: 1556: goto out; 1557: case '8': case '9': 1558: if (shift != 4) 1559: fatal("Illegal octal digit at line %d",line); 1560: /* FALL THROUGH */ 1561: case '0': case '1': case '2': case '3': case '4': 1562: case '5': case '6': case '7': 1563: i <<= shift; 1564: i += *s++ & 15; 1565: break; 1566: case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 1567: case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 1568: if (shift != 4) 1569: goto out; 1570: i <<= 4; 1571: i += (*s++ & 7) + 9; 1572: break; 1573: } 1574: } 1575: out: 1576: sprintf(tokenbuf,"%d",i); 1577: arg[1].arg_ptr.arg_str = str_make(tokenbuf); 1578: } 1579: break; 1580: case '1': case '2': case '3': case '4': case '5': 1581: case '6': case '7': case '8': case '9': case '.': 1582: decimal: 1583: arg[1].arg_type = A_SINGLE; 1584: d = tokenbuf; 1585: while (isdigit(*s) || *s == '_') 1586: *d++ = *s++; 1587: if (*s == '.' && index("0123456789eE",s[1])) 1588: *d++ = *s++; 1589: while (isdigit(*s) || *s == '_') 1590: *d++ = *s++; 1591: if (index("eE",*s) && index("+-0123456789",s[1])) 1592: *d++ = *s++; 1593: if (*s == '+' || *s == '-') 1594: *d++ = *s++; 1595: while (isdigit(*s)) 1596: *d++ = *s++; 1597: *d = '\0'; 1598: arg[1].arg_ptr.arg_str = str_make(tokenbuf); 1599: break; 1600: case '\'': 1601: arg[1].arg_type = A_SINGLE; 1602: term = *s; 1603: leave = Nullch; 1604: goto snarf_it; 1605: 1606: case '<': 1607: arg[1].arg_type = A_READ; 1608: s = cpytill(tokenbuf,s+1,'>'); 1609: if (!*tokenbuf) 1610: strcpy(tokenbuf,"ARGV"); 1611: if (*s) 1612: s++; 1613: if (rsfp == stdin && strEQ(tokenbuf,"stdin")) 1614: fatal("Can't get both program and data from <stdin>\n"); 1615: arg[1].arg_ptr.arg_stab = stabent(tokenbuf,TRUE); 1616: arg[1].arg_ptr.arg_stab->stab_io = stio_new(); 1617: if (strEQ(tokenbuf,"ARGV")) { 1618: aadd(arg[1].arg_ptr.arg_stab); 1619: arg[1].arg_ptr.arg_stab->stab_io->flags |= IOF_ARGV|IOF_START; 1620: } 1621: break; 1622: case '"': 1623: arg[1].arg_type = A_DOUBLE; 1624: makesingle = TRUE; /* maybe disable runtime scanning */ 1625: term = *s; 1626: goto snarf_it; 1627: case '`': 1628: arg[1].arg_type = A_BACKTICK; 1629: term = *s; 1630: snarf_it: 1631: { 1632: STR *tmpstr; 1633: int sqstart = line; 1634: char *tmps; 1635: 1636: tmpstr = str_new(strlen(s)); 1637: s = str_append_till(tmpstr,s+1,term,leave); 1638: while (!*s) { /* multiple line string? */ 1639: s = str_gets(linestr, rsfp); 1640: if (!*s) 1641: fatal("EOF in string at line %d\n",sqstart); 1642: line++; 1643: s = str_append_till(tmpstr,s,term,leave); 1644: } 1645: s++; 1646: if (term == '\'') { 1647: arg[1].arg_ptr.arg_str = tmpstr; 1648: break; 1649: } 1650: tmps = s; 1651: s = d = tmpstr->str_ptr; /* assuming shrinkage only */ 1652: while (*s) { 1653: if (*s == '$' && s[1]) { 1654: makesingle = FALSE; /* force interpretation */ 1655: if (!isalpha(s[1])) { /* an internal register? */ 1656: int len; 1657: 1658: len = scanreg(s,tokenbuf) - s; 1659: stabent(tokenbuf,TRUE); /* make sure it's created */ 1660: while (len--) 1661: *d++ = *s++; 1662: continue; 1663: } 1664: } 1665: else if (*s == '\\' && s[1]) { 1666: s++; 1667: switch (*s) { 1668: default: 1669: defchar: 1670: if (!leave || index(leave,*s)) 1671: *d++ = '\\'; 1672: *d++ = *s++; 1673: continue; 1674: case '0': case '1': case '2': case '3': 1675: case '4': case '5': case '6': case '7': 1676: *d = *s++ - '0'; 1677: if (index("01234567",*s)) { 1678: *d <<= 3; 1679: *d += *s++ - '0'; 1680: } 1681: else if (!index("`\"",term)) { /* oops, a subpattern */ 1682: s--; 1683: goto defchar; 1684: } 1685: if (index("01234567",*s)) { 1686: *d <<= 3; 1687: *d += *s++ - '0'; 1688: } 1689: d++; 1690: continue; 1691: case 'b': 1692: *d++ = '\b'; 1693: break; 1694: case 'n': 1695: *d++ = '\n'; 1696: break; 1697: case 'r': 1698: *d++ = '\r'; 1699: break; 1700: case 'f': 1701: *d++ = '\f'; 1702: break; 1703: case 't': 1704: *d++ = '\t'; 1705: break; 1706: } 1707: s++; 1708: continue; 1709: } 1710: *d++ = *s++; 1711: } 1712: *d = '\0'; 1713: if (arg[1].arg_type == A_DOUBLE) { 1714: if (makesingle) 1715: arg[1].arg_type = A_SINGLE; /* now we can optimize on it */ 1716: else 1717: leave = "\\"; 1718: for (d = s = tmpstr->str_ptr; *s; *d++ = *s++) { 1719: if (*s == '\\' && (!leave || index(leave,s[1]))) 1720: s++; 1721: } 1722: *d = '\0'; 1723: } 1724: tmpstr->str_cur = d - tmpstr->str_ptr; /* XXX cheat */ 1725: arg[1].arg_ptr.arg_str = tmpstr; 1726: s = tmps; 1727: break; 1728: } 1729: } 1730: return s; 1731: } 1732: 1733: ARG * 1734: make_op(type,newlen,arg1,arg2,arg3,dolist) 1735: int type; 1736: int newlen; 1737: ARG *arg1; 1738: ARG *arg2; 1739: ARG *arg3; 1740: int dolist; 1741: { 1742: register ARG *arg; 1743: register ARG *chld; 1744: register int doarg; 1745: 1746: arg = op_new(newlen); 1747: arg->arg_type = type; 1748: doarg = opargs[type]; 1749: if (chld = arg1) { 1750: if (!(doarg & 1)) 1751: arg[1].arg_flags |= AF_SPECIAL; 1752: if (doarg & 16) 1753: arg[1].arg_flags |= AF_NUMERIC; 1754: if (chld->arg_type == O_ITEM && 1755: (hoistable[chld[1].arg_type] || chld[1].arg_type == A_LVAL) ) { 1756: arg[1].arg_type = chld[1].arg_type; 1757: arg[1].arg_ptr = chld[1].arg_ptr; 1758: arg[1].arg_flags |= chld[1].arg_flags; 1759: free_arg(chld); 1760: } 1761: else { 1762: arg[1].arg_type = A_EXPR; 1763: arg[1].arg_ptr.arg_arg = chld; 1764: if (dolist & 1) { 1765: if (chld->arg_type == O_LIST) { 1766: if (newlen == 1) { /* we can hoist entire list */ 1767: chld->arg_type = type; 1768: free_arg(arg); 1769: arg = chld; 1770: } 1771: else { 1772: arg[1].arg_flags |= AF_SPECIAL; 1773: } 1774: } 1775: else if (chld->arg_type == O_ARRAY && chld->arg_len == 1) 1776: arg[1].arg_flags |= AF_SPECIAL; 1777: } 1778: } 1779: } 1780: if (chld = arg2) { 1781: if (!(doarg & 2)) 1782: arg[2].arg_flags |= AF_SPECIAL; 1783: if (doarg & 32) 1784: arg[2].arg_flags |= AF_NUMERIC; 1785: if (chld->arg_type == O_ITEM && 1786: (hoistable[chld[1].arg_type] || 1787: (type == O_ASSIGN && 1788: (chld[1].arg_type == A_READ || 1789: chld[1].arg_type == A_DOUBLE || 1790: chld[1].arg_type == A_BACKTICK ) ) ) ) { 1791: arg[2].arg_type = chld[1].arg_type; 1792: arg[2].arg_ptr = chld[1].arg_ptr; 1793: free_arg(chld); 1794: } 1795: else { 1796: arg[2].arg_type = A_EXPR; 1797: arg[2].arg_ptr.arg_arg = chld; 1798: if ((dolist & 2) && 1799: (chld->arg_type == O_LIST || 1800: (chld->arg_type == O_ARRAY && chld->arg_len == 1) )) 1801: arg[2].arg_flags |= AF_SPECIAL; 1802: } 1803: } 1804: if (chld = arg3) { 1805: if (!(doarg & 4)) 1806: arg[3].arg_flags |= AF_SPECIAL; 1807: if (doarg & 64) 1808: arg[3].arg_flags |= AF_NUMERIC; 1809: if (chld->arg_type == O_ITEM && hoistable[chld[1].arg_type]) { 1810: arg[3].arg_type = chld[1].arg_type; 1811: arg[3].arg_ptr = chld[1].arg_ptr; 1812: free_arg(chld); 1813: } 1814: else { 1815: arg[3].arg_type = A_EXPR; 1816: arg[3].arg_ptr.arg_arg = chld; 1817: if ((dolist & 4) && 1818: (chld->arg_type == O_LIST || 1819: (chld->arg_type == O_ARRAY && chld->arg_len == 1) )) 1820: arg[3].arg_flags |= AF_SPECIAL; 1821: } 1822: } 1823: #ifdef DEBUGGING 1824: if (debug & 16) { 1825: fprintf(stderr,"%lx <= make_op(%s",arg,opname[arg->arg_type]); 1826: if (arg1) 1827: fprintf(stderr,",%s=%lx", 1828: argname[arg[1].arg_type],arg[1].arg_ptr.arg_arg); 1829: if (arg2) 1830: fprintf(stderr,",%s=%lx", 1831: argname[arg[2].arg_type],arg[2].arg_ptr.arg_arg); 1832: if (arg3) 1833: fprintf(stderr,",%s=%lx", 1834: argname[arg[3].arg_type],arg[3].arg_ptr.arg_arg); 1835: fprintf(stderr,")\n"); 1836: } 1837: #endif 1838: evalstatic(arg); /* see if we can consolidate anything */ 1839: return arg; 1840: } 1841: 1842: /* turn 123 into 123 == $. */ 1843: 1844: ARG * 1845: flipflip(arg) 1846: register ARG *arg; 1847: { 1848: if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_SINGLE) { 1849: arg = (ARG*)saferealloc((char*)arg,3*sizeof(ARG)); 1850: arg->arg_type = O_EQ; 1851: arg->arg_len = 2; 1852: arg[2].arg_type = A_STAB; 1853: arg[2].arg_flags = 0; 1854: arg[2].arg_ptr.arg_stab = stabent(".",TRUE); 1855: } 1856: return arg; 1857: } 1858: 1859: void 1860: evalstatic(arg) 1861: register ARG *arg; 1862: { 1863: register STR *str; 1864: register STR *s1; 1865: register STR *s2; 1866: double value; /* must not be register */ 1867: register char *tmps; 1868: int i; 1869: double exp(), log(), sqrt(), modf(); 1870: char *crypt(); 1871: 1872: if (!arg || !arg->arg_len) 1873: return; 1874: 1875: if (arg[1].arg_type == A_SINGLE && 1876: (arg->arg_len == 1 || arg[2].arg_type == A_SINGLE) ) { 1877: str = str_new(0); 1878: s1 = arg[1].arg_ptr.arg_str; 1879: if (arg->arg_len > 1) 1880: s2 = arg[2].arg_ptr.arg_str; 1881: else 1882: s2 = Nullstr; 1883: switch (arg->arg_type) { 1884: default: 1885: str_free(str); 1886: str = Nullstr; /* can't be evaluated yet */ 1887: break; 1888: case O_CONCAT: 1889: str_sset(str,s1); 1890: str_scat(str,s2); 1891: break; 1892: case O_REPEAT: 1893: i = (int)str_gnum(s2); 1894: while (i--) 1895: str_scat(str,s1); 1896: break; 1897: case O_MULTIPLY: 1898: value = str_gnum(s1); 1899: str_numset(str,value * str_gnum(s2)); 1900: break; 1901: case O_DIVIDE: 1902: value = str_gnum(s1); 1903: str_numset(str,value / str_gnum(s2)); 1904: break; 1905: case O_MODULO: 1906: value = str_gnum(s1); 1907: str_numset(str,(double)(((long)value) % ((long)str_gnum(s2)))); 1908: break; 1909: case O_ADD: 1910: value = str_gnum(s1); 1911: str_numset(str,value + str_gnum(s2)); 1912: break; 1913: case O_SUBTRACT: 1914: value = str_gnum(s1); 1915: str_numset(str,value - str_gnum(s2)); 1916: break; 1917: case O_LEFT_SHIFT: 1918: value = str_gnum(s1); 1919: str_numset(str,(double)(((long)value) << ((long)str_gnum(s2)))); 1920: break; 1921: case O_RIGHT_SHIFT: 1922: value = str_gnum(s1); 1923: str_numset(str,(double)(((long)value) >> ((long)str_gnum(s2)))); 1924: break; 1925: case O_LT: 1926: value = str_gnum(s1); 1927: str_numset(str,(double)(value < str_gnum(s2))); 1928: break; 1929: case O_GT: 1930: value = str_gnum(s1); 1931: str_numset(str,(double)(value > str_gnum(s2))); 1932: break; 1933: case O_LE: 1934: value = str_gnum(s1); 1935: str_numset(str,(double)(value <= str_gnum(s2))); 1936: break; 1937: case O_GE: 1938: value = str_gnum(s1); 1939: str_numset(str,(double)(value >= str_gnum(s2))); 1940: break; 1941: case O_EQ: 1942: value = str_gnum(s1); 1943: str_numset(str,(double)(value == str_gnum(s2))); 1944: break; 1945: case O_NE: 1946: value = str_gnum(s1); 1947: str_numset(str,(double)(value != str_gnum(s2))); 1948: break; 1949: case O_BIT_AND: 1950: value = str_gnum(s1); 1951: str_numset(str,(double)(((long)value) & ((long)str_gnum(s2)))); 1952: break; 1953: case O_XOR: 1954: value = str_gnum(s1); 1955: str_numset(str,(double)(((long)value) ^ ((long)str_gnum(s2)))); 1956: break; 1957: case O_BIT_OR: 1958: value = str_gnum(s1); 1959: str_numset(str,(double)(((long)value) | ((long)str_gnum(s2)))); 1960: break; 1961: case O_AND: 1962: if (str_true(s1)) 1963: str = str_make(str_get(s2)); 1964: else 1965: str = str_make(str_get(s1)); 1966: break; 1967: case O_OR: 1968: if (str_true(s1)) 1969: str = str_make(str_get(s1)); 1970: else 1971: str = str_make(str_get(s2)); 1972: break; 1973: case O_COND_EXPR: 1974: if (arg[3].arg_type != A_SINGLE) { 1975: str_free(str); 1976: str = Nullstr; 1977: } 1978: else { 1979: str = str_make(str_get(str_true(s1) ? s2 : arg[3].arg_ptr.arg_str)); 1980: str_free(arg[3].arg_ptr.arg_str); 1981: } 1982: break; 1983: case O_NEGATE: 1984: str_numset(str,(double)(-str_gnum(s1))); 1985: break; 1986: case O_NOT: 1987: str_numset(str,(double)(!str_true(s1))); 1988: break; 1989: case O_COMPLEMENT: 1990: str_numset(str,(double)(~(long)str_gnum(s1))); 1991: break; 1992: case O_LENGTH: 1993: str_numset(str, (double)str_len(s1)); 1994: break; 1995: case O_SUBSTR: 1996: if (arg[3].arg_type != A_SINGLE || stabent("[",allstabs)) { 1997: str_free(str); /* making the fallacious assumption */ 1998: str = Nullstr; /* that any $[ occurs before substr()*/ 1999: } 2000: else { 2001: char *beg; 2002: int len = (int)str_gnum(s2); 2003: int tmp; 2004: 2005: for (beg = str_get(s1); *beg && len > 0; beg++,len--) ; 2006: len = (int)str_gnum(arg[3].arg_ptr.arg_str); 2007: str_free(arg[3].arg_ptr.arg_str); 2008: if (len > (tmp = strlen(beg))) 2009: len = tmp; 2010: str_nset(str,beg,len); 2011: } 2012: break; 2013: case O_SLT: 2014: tmps = str_get(s1); 2015: str_numset(str,(double)(strLT(tmps,str_get(s2)))); 2016: break; 2017: case O_SGT: 2018: tmps = str_get(s1); 2019: str_numset(str,(double)(strGT(tmps,str_get(s2)))); 2020: break; 2021: case O_SLE: 2022: tmps = str_get(s1); 2023: str_numset(str,(double)(strLE(tmps,str_get(s2)))); 2024: break; 2025: case O_SGE: 2026: tmps = str_get(s1); 2027: str_numset(str,(double)(strGE(tmps,str_get(s2)))); 2028: break; 2029: case O_SEQ: 2030: tmps = str_get(s1); 2031: str_numset(str,(double)(strEQ(tmps,str_get(s2)))); 2032: break; 2033: case O_SNE: 2034: tmps = str_get(s1); 2035: str_numset(str,(double)(strNE(tmps,str_get(s2)))); 2036: break; 2037: case O_CRYPT: 2038: tmps = str_get(s1); 2039: str_set(str,crypt(tmps,str_get(s2))); 2040: break; 2041: case O_EXP: 2042: str_numset(str,exp(str_gnum(s1))); 2043: break; 2044: case O_LOG: 2045: str_numset(str,log(str_gnum(s1))); 2046: break; 2047: case O_SQRT: 2048: str_numset(str,sqrt(str_gnum(s1))); 2049: break; 2050: case O_INT: 2051: modf(str_gnum(s1),&value); 2052: str_numset(str,value); 2053: break; 2054: case O_ORD: 2055: str_numset(str,(double)(*str_get(s1))); 2056: break; 2057: } 2058: if (str) { 2059: arg->arg_type = O_ITEM; /* note arg1 type is already SINGLE */ 2060: str_free(s1); 2061: str_free(s2); 2062: arg[1].arg_ptr.arg_str = str; 2063: } 2064: } 2065: } 2066: 2067: ARG * 2068: l(arg) 2069: register ARG *arg; 2070: { 2071: register int i; 2072: register ARG *arg1; 2073: 2074: arg->arg_flags |= AF_COMMON; /* XXX should cross-match */ 2075: 2076: /* see if it's an array reference */ 2077: 2078: if (arg[1].arg_type == A_EXPR) { 2079: arg1 = arg[1].arg_ptr.arg_arg; 2080: 2081: if (arg1->arg_type == O_LIST && arg->arg_type != O_ITEM) { 2082: /* assign to list */ 2083: arg[1].arg_flags |= AF_SPECIAL; 2084: arg[2].arg_flags |= AF_SPECIAL; 2085: for (i = arg1->arg_len; i >= 1; i--) { 2086: switch (arg1[i].arg_type) { 2087: case A_STAB: case A_LVAL: 2088: arg1[i].arg_type = A_LVAL; 2089: break; 2090: case A_EXPR: case A_LEXPR: 2091: arg1[i].arg_type = A_LEXPR; 2092: if (arg1[i].arg_ptr.arg_arg->arg_type == O_ARRAY) 2093: arg1[i].arg_ptr.arg_arg->arg_type = O_LARRAY; 2094: else if (arg1[i].arg_ptr.arg_arg->arg_type == O_HASH) 2095: arg1[i].arg_ptr.arg_arg->arg_type = O_LHASH; 2096: if (arg1[i].arg_ptr.arg_arg->arg_type == O_LARRAY) 2097: break; 2098: if (arg1[i].arg_ptr.arg_arg->arg_type == O_LHASH) 2099: break; 2100: /* FALL THROUGH */ 2101: default: 2102: sprintf(tokenbuf, 2103: "Illegal item (%s) as lvalue",argname[arg1[i].arg_type]); 2104: yyerror(tokenbuf); 2105: } 2106: } 2107: } 2108: else if (arg1->arg_type == O_ARRAY) { 2109: if (arg1->arg_len == 1 && arg->arg_type != O_ITEM) { 2110: /* assign to array */ 2111: arg[1].arg_flags |= AF_SPECIAL; 2112: arg[2].arg_flags |= AF_SPECIAL; 2113: } 2114: else 2115: arg1->arg_type = O_LARRAY; /* assign to array elem */ 2116: } 2117: else if (arg1->arg_type == O_HASH) 2118: arg1->arg_type = O_LHASH; 2119: else { 2120: sprintf(tokenbuf, 2121: "Illegal expression (%s) as lvalue",opname[arg1->arg_type]); 2122: yyerror(tokenbuf); 2123: } 2124: arg[1].arg_type = A_LEXPR; 2125: #ifdef DEBUGGING 2126: if (debug & 16) 2127: fprintf(stderr,"lval LEXPR\n"); 2128: #endif 2129: return arg; 2130: } 2131: 2132: /* not an array reference, should be a register name */ 2133: 2134: if (arg[1].arg_type != A_STAB && arg[1].arg_type != A_LVAL) { 2135: sprintf(tokenbuf, 2136: "Illegal item (%s) as lvalue",argname[arg[1].arg_type]); 2137: yyerror(tokenbuf); 2138: } 2139: arg[1].arg_type = A_LVAL; 2140: #ifdef DEBUGGING 2141: if (debug & 16) 2142: fprintf(stderr,"lval LVAL\n"); 2143: #endif 2144: return arg; 2145: } 2146: 2147: ARG * 2148: addflags(i,flags,arg) 2149: register ARG *arg; 2150: { 2151: arg[i].arg_flags |= flags; 2152: return arg; 2153: } 2154: 2155: ARG * 2156: hide_ary(arg) 2157: ARG *arg; 2158: { 2159: if (arg->arg_type == O_ARRAY) 2160: return make_op(O_ITEM,1,arg,Nullarg,Nullarg,0); 2161: return arg; 2162: } 2163: 2164: ARG * 2165: make_list(arg) 2166: register ARG *arg; 2167: { 2168: register int i; 2169: register ARG *node; 2170: register ARG *nxtnode; 2171: register int j; 2172: STR *tmpstr; 2173: 2174: if (!arg) { 2175: arg = op_new(0); 2176: arg->arg_type = O_LIST; 2177: } 2178: if (arg->arg_type != O_COMMA) { 2179: arg->arg_flags |= AF_LISTISH; /* see listish() below */ 2180: return arg; 2181: } 2182: for (i = 2, node = arg; ; i++) { 2183: if (node->arg_len < 2) 2184: break; 2185: if (node[2].arg_type != A_EXPR) 2186: break; 2187: node = node[2].arg_ptr.arg_arg; 2188: if (node->arg_type != O_COMMA) 2189: break; 2190: } 2191: if (i > 2) { 2192: node = arg; 2193: arg = op_new(i); 2194: tmpstr = arg->arg_ptr.arg_str; 2195: *arg = *node; /* copy everything except the STR */ 2196: arg->arg_ptr.arg_str = tmpstr; 2197: for (j = 1; ; ) { 2198: arg[j++] = node[1]; 2199: if (j >= i) { 2200: arg[j] = node[2]; 2201: free_arg(node); 2202: break; 2203: } 2204: nxtnode = node[2].arg_ptr.arg_arg; 2205: free_arg(node); 2206: node = nxtnode; 2207: } 2208: } 2209: arg->arg_type = O_LIST; 2210: arg->arg_len = i; 2211: return arg; 2212: } 2213: 2214: /* turn a single item into a list */ 2215: 2216: ARG * 2217: listish(arg) 2218: ARG *arg; 2219: { 2220: if (arg->arg_flags & AF_LISTISH) 2221: arg = make_op(O_LIST,1,arg,Nullarg,Nullarg,0); 2222: return arg; 2223: } 2224: 2225: ARG * 2226: stab_to_arg(atype,stab) 2227: int atype; 2228: register STAB *stab; 2229: { 2230: register ARG *arg; 2231: 2232: arg = op_new(1); 2233: arg->arg_type = O_ITEM; 2234: arg[1].arg_type = atype; 2235: arg[1].arg_ptr.arg_stab = stab; 2236: return arg; 2237: } 2238: 2239: ARG * 2240: cval_to_arg(cval) 2241: register char *cval; 2242: { 2243: register ARG *arg; 2244: 2245: arg = op_new(1); 2246: arg->arg_type = O_ITEM; 2247: arg[1].arg_type = A_SINGLE; 2248: arg[1].arg_ptr.arg_str = str_make(cval); 2249: safefree(cval); 2250: return arg; 2251: } 2252: 2253: ARG * 2254: op_new(numargs) 2255: int numargs; 2256: { 2257: register ARG *arg; 2258: 2259: arg = (ARG*)safemalloc((numargs + 1) * sizeof (ARG)); 2260: bzero((char *)arg, (numargs + 1) * sizeof (ARG)); 2261: arg->arg_ptr.arg_str = str_new(0); 2262: arg->arg_len = numargs; 2263: return arg; 2264: } 2265: 2266: void 2267: free_arg(arg) 2268: ARG *arg; 2269: { 2270: str_free(arg->arg_ptr.arg_str); 2271: safefree((char*)arg); 2272: } 2273: 2274: ARG * 2275: make_match(type,expr,spat) 2276: int type; 2277: ARG *expr; 2278: SPAT *spat; 2279: { 2280: register ARG *arg; 2281: 2282: arg = make_op(type,2,expr,Nullarg,Nullarg,0); 2283: 2284: arg[2].arg_type = A_SPAT; 2285: arg[2].arg_ptr.arg_spat = spat; 2286: #ifdef DEBUGGING 2287: if (debug & 16) 2288: fprintf(stderr,"make_match SPAT=%lx\n",spat); 2289: #endif 2290: 2291: if (type == O_SUBST || type == O_NSUBST) { 2292: if (arg[1].arg_type != A_STAB) 2293: yyerror("Illegal lvalue"); 2294: arg[1].arg_type = A_LVAL; 2295: } 2296: return arg; 2297: } 2298: 2299: ARG * 2300: cmd_to_arg(cmd) 2301: CMD *cmd; 2302: { 2303: register ARG *arg; 2304: 2305: arg = op_new(1); 2306: arg->arg_type = O_ITEM; 2307: arg[1].arg_type = A_CMD; 2308: arg[1].arg_ptr.arg_cmd = cmd; 2309: return arg; 2310: } 2311: 2312: CMD * 2313: wopt(cmd) 2314: register CMD *cmd; 2315: { 2316: register CMD *tail; 2317: register ARG *arg = cmd->c_expr; 2318: char *tmps; /* used by True macro */ 2319: 2320: /* hoist "while (<channel>)" up into command block */ 2321: 2322: if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) { 2323: cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ 2324: cmd->c_flags |= CFT_GETS; /* and set it to do the input */ 2325: cmd->c_stab = arg[1].arg_ptr.arg_stab; 2326: if (arg[1].arg_ptr.arg_stab->stab_io->flags & IOF_ARGV) { 2327: cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$_ =" */ 2328: stab_to_arg(A_LVAL,defstab), arg, Nullarg,1 )); 2329: } 2330: else { 2331: free_arg(arg); 2332: cmd->c_expr = Nullarg; 2333: } 2334: } 2335: 2336: /* First find the end of the true list */ 2337: 2338: if (cmd->ucmd.ccmd.cc_true == Nullcmd) 2339: return cmd; 2340: for (tail = cmd->ucmd.ccmd.cc_true; tail->c_next; tail = tail->c_next) ; 2341: 2342: /* if there's a continue block, link it to true block and find end */ 2343: 2344: if (cmd->ucmd.ccmd.cc_alt != Nullcmd) { 2345: tail->c_next = cmd->ucmd.ccmd.cc_alt; 2346: for ( ; tail->c_next; tail = tail->c_next) ; 2347: } 2348: 2349: /* Here's the real trick: link the end of the list back to the beginning, 2350: * inserting a "last" block to break out of the loop. This saves one or 2351: * two procedure calls every time through the loop, because of how cmd_exec 2352: * does tail recursion. 2353: */ 2354: 2355: tail->c_next = (CMD *) safemalloc(sizeof (CMD)); 2356: tail = tail->c_next; 2357: if (!cmd->ucmd.ccmd.cc_alt) 2358: cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */ 2359: 2360: bcopy((char *)cmd, (char *)tail, sizeof(CMD)); 2361: tail->c_type = C_EXPR; 2362: tail->c_flags ^= CF_INVERT; /* turn into "last unless" */ 2363: tail->c_next = tail->ucmd.ccmd.cc_true; /* loop directly back to top */ 2364: tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg,0); 2365: tail->ucmd.acmd.ac_stab = Nullstab; 2366: return cmd; 2367: } 2368: 2369: FCMD * 2370: load_format() 2371: { 2372: FCMD froot; 2373: FCMD *flinebeg; 2374: register FCMD *fprev = &froot; 2375: register FCMD *fcmd; 2376: register char *s; 2377: register char *t; 2378: register char tmpchar; 2379: bool noblank; 2380: 2381: while ((s = str_gets(linestr,rsfp)) != Nullch) { 2382: line++; 2383: if (strEQ(s,".\n")) { 2384: bufptr = s; 2385: return froot.f_next; 2386: } 2387: if (*s == '#') 2388: continue; 2389: flinebeg = Nullfcmd; 2390: noblank = FALSE; 2391: while (*s) { 2392: fcmd = (FCMD *)safemalloc(sizeof (FCMD)); 2393: bzero((char*)fcmd, sizeof (FCMD)); 2394: fprev->f_next = fcmd; 2395: fprev = fcmd; 2396: for (t=s; *t && *t != '@' && *t != '^'; t++) { 2397: if (*t == '~') { 2398: noblank = TRUE; 2399: *t = ' '; 2400: } 2401: } 2402: tmpchar = *t; 2403: *t = '\0'; 2404: fcmd->f_pre = savestr(s); 2405: fcmd->f_presize = strlen(s); 2406: *t = tmpchar; 2407: s = t; 2408: if (!*s) { 2409: if (noblank) 2410: fcmd->f_flags |= FC_NOBLANK; 2411: break; 2412: } 2413: if (!flinebeg) 2414: flinebeg = fcmd; /* start values here */ 2415: if (*s++ == '^') 2416: fcmd->f_flags |= FC_CHOP; /* for doing text filling */ 2417: switch (*s) { 2418: case '*': 2419: fcmd->f_type = F_LINES; 2420: *s = '\0'; 2421: break; 2422: case '<': 2423: fcmd->f_type = F_LEFT; 2424: while (*s == '<') 2425: s++; 2426: break; 2427: case '>': 2428: fcmd->f_type = F_RIGHT; 2429: while (*s == '>') 2430: s++; 2431: break; 2432: case '|': 2433: fcmd->f_type = F_CENTER; 2434: while (*s == '|') 2435: s++; 2436: break; 2437: default: 2438: fcmd->f_type = F_LEFT; 2439: break; 2440: } 2441: if (fcmd->f_flags & FC_CHOP && *s == '.') { 2442: fcmd->f_flags |= FC_MORE; 2443: while (*s == '.') 2444: s++; 2445: } 2446: fcmd->f_size = s-t; 2447: } 2448: if (flinebeg) { 2449: again: 2450: if ((bufptr = str_gets(linestr ,rsfp)) == Nullch) 2451: goto badform; 2452: line++; 2453: if (strEQ(bufptr,".\n")) { 2454: yyerror("Missing values line"); 2455: return froot.f_next; 2456: } 2457: if (*bufptr == '#') 2458: goto again; 2459: lex_newlines = TRUE; 2460: while (flinebeg || *bufptr) { 2461: switch(yylex()) { 2462: default: 2463: yyerror("Bad value in format"); 2464: *bufptr = '\0'; 2465: break; 2466: case '\n': 2467: if (flinebeg) 2468: yyerror("Missing value in format"); 2469: *bufptr = '\0'; 2470: break; 2471: case REG: 2472: yylval.arg = stab_to_arg(A_LVAL,yylval.stabval); 2473: /* FALL THROUGH */ 2474: case RSTRING: 2475: if (!flinebeg) 2476: yyerror("Extra value in format"); 2477: else { 2478: flinebeg->f_expr = yylval.arg; 2479: do { 2480: flinebeg = flinebeg->f_next; 2481: } while (flinebeg && flinebeg->f_size == 0); 2482: } 2483: break; 2484: case ',': case ';': 2485: continue; 2486: } 2487: } 2488: lex_newlines = FALSE; 2489: } 2490: } 2491: badform: 2492: bufptr = str_get(linestr); 2493: yyerror("Format not terminated"); 2494: return froot.f_next; 2495: } 2496: 2497: STR * 2498: do_eval(str) 2499: STR *str; 2500: { 2501: int retval; 2502: CMD *myroot; 2503: 2504: in_eval++; 2505: str_set(stabent("@",TRUE)->stab_val,""); 2506: line = 1; 2507: str_sset(linestr,str); 2508: bufptr = str_get(linestr); 2509: if (setjmp(eval_env)) 2510: retval = 1; 2511: else 2512: retval = yyparse(); 2513: myroot = eval_root; /* in case cmd_exec does another eval! */ 2514: if (retval) 2515: str = &str_no; 2516: else { 2517: str = cmd_exec(eval_root); 2518: cmd_free(myroot); /* can't free on error, for some reason */ 2519: } 2520: in_eval--; 2521: return str; 2522: } 2523: 2524: cmd_free(cmd) 2525: register CMD *cmd; 2526: { 2527: register CMD *tofree; 2528: register CMD *head = cmd; 2529: 2530: while (cmd) { 2531: if (cmd->c_label) 2532: safefree(cmd->c_label); 2533: if (cmd->c_first) 2534: str_free(cmd->c_first); 2535: if (cmd->c_spat) 2536: spat_free(cmd->c_spat); 2537: if (cmd->c_expr) 2538: arg_free(cmd->c_expr); 2539: switch (cmd->c_type) { 2540: case C_WHILE: 2541: case C_BLOCK: 2542: case C_IF: 2543: if (cmd->ucmd.ccmd.cc_true) 2544: cmd_free(cmd->ucmd.ccmd.cc_true); 2545: if (cmd->c_type == C_IF && cmd->ucmd.ccmd.cc_alt) 2546: cmd_free(cmd->ucmd.ccmd.cc_alt,Nullcmd); 2547: break; 2548: case C_EXPR: 2549: if (cmd->ucmd.acmd.ac_stab) 2550: arg_free(cmd->ucmd.acmd.ac_stab); 2551: if (cmd->ucmd.acmd.ac_expr) 2552: arg_free(cmd->ucmd.acmd.ac_expr); 2553: break; 2554: } 2555: tofree = cmd; 2556: cmd = cmd->c_next; 2557: safefree((char*)tofree); 2558: if (cmd && cmd == head) /* reached end of while loop */ 2559: break; 2560: } 2561: } 2562: 2563: arg_free(arg) 2564: register ARG *arg; 2565: { 2566: register int i; 2567: 2568: for (i = 1; i <= arg->arg_len; i++) { 2569: switch (arg[i].arg_type) { 2570: case A_NULL: 2571: break; 2572: case A_LEXPR: 2573: case A_EXPR: 2574: arg_free(arg[i].arg_ptr.arg_arg); 2575: break; 2576: case A_CMD: 2577: cmd_free(arg[i].arg_ptr.arg_cmd); 2578: break; 2579: case A_STAB: 2580: case A_LVAL: 2581: case A_READ: 2582: case A_ARYLEN: 2583: break; 2584: case A_SINGLE: 2585: case A_DOUBLE: 2586: case A_BACKTICK: 2587: str_free(arg[i].arg_ptr.arg_str); 2588: break; 2589: case A_SPAT: 2590: spat_free(arg[i].arg_ptr.arg_spat); 2591: break; 2592: case A_NUMBER: 2593: break; 2594: } 2595: } 2596: free_arg(arg); 2597: } 2598: 2599: spat_free(spat) 2600: register SPAT *spat; 2601: { 2602: register SPAT *sp; 2603: 2604: if (spat->spat_runtime) 2605: arg_free(spat->spat_runtime); 2606: if (spat->spat_repl) { 2607: arg_free(spat->spat_repl); 2608: } 2609: free_compex(&spat->spat_compex); 2610: 2611: /* now unlink from spat list */ 2612: if (spat_root == spat) 2613: spat_root = spat->spat_next; 2614: else { 2615: for (sp = spat_root; sp->spat_next != spat; sp = sp->spat_next) ; 2616: sp->spat_next = spat->spat_next; 2617: } 2618: 2619: safefree((char*)spat); 2620: }