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: }

Defined functions

addflags defined in line 2147; used 4 times
arg_free defined in line 2563; used 7 times
cmd_free defined in line 2524; used 4 times
cmd_to_arg defined in line 2299; used 5 times
cval_to_arg defined in line 2239; used 1 times
evalstatic defined in line 1859; used 2 times
expand_charset defined in line 1031; used 2 times
free_arg defined in line 2266; used 16 times
hide_ary defined in line 2155; used 1 times
l defined in line 2067; used 27 times
listish defined in line 2216; used 2 times
load_format defined in line 2369; used 2 times
magicalize defined in line 227; used 1 times
main defined in line 28; never used
make_list defined in line 2164; used 10 times
make_match defined in line 2274; used 4 times
make_op defined in line 1733; used 116 times
mod_match defined in line 1370; used 5 times
op_new defined in line 2253; used 9 times
opt_arg defined in line 1171; used 6 times
scanconst defined in line 849; used 4 times
scanpat defined in line 904; used 5 times
scanreg defined in line 817; used 6 times
scanstr defined in line 1516; used 7 times
scansubst defined in line 955; used 2 times
scantrans defined in line 1052; used 3 times
spat_free defined in line 2599; used 2 times
stab_to_arg defined in line 2225; used 50 times
stio_new defined in line 807; used 7 times
yyerror defined in line 1485; used 9 times
yylex defined in line 253; used 1 times

Defined variables

e_tmpname defined in line 24; used 6 times
filename defined in line 23; used 11 times
rcsid defined in line 1; never used

Defined macros

FUN0 defined in line 247; used 3 times
FUN1 defined in line 248; used 11 times
FUN2 defined in line 249; used 4 times
FUN3 defined in line 250; used 1 times
LOOPX defined in line 245; used 4 times
OPERATOR defined in line 243; used 86 times
RETURN defined in line 242; used 5 times
SFUN defined in line 251; used 3 times
SNARFWORD defined in line 432; used 27 times
TERM defined in line 244; used 18 times
UNI defined in line 246; used 6 times

Usage of this include

Last modified: 2002-12-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 12049
Valid CSS Valid XHTML 1.0 Strict