# 2.11BSD#431 - /usr/src/new/PORT/perl.1.0.16/perly.c

##### Functions

    add_label         X
    addcond           X
    addflags          X
    addloop           X
    append_line       X
    arg_free          X
    block_head        X
    cmd_free          X
    cmd_to_arg        X
    cval_to_arg       X
    do_eval           X
    evalstatic        X
    expand_charset    X
    flipflip          X
    free_arg          X
    hide_ary          X
    invert            X
    l                 X
    listish           X
    load_format       X
    magicalize        X
    main              X
    make_acmd         X
    make_ccmd         X
    make_list         X
    make_match        X
    make_op           X
    make_split        X
    mod_match         X
    op_new            X
    opt_arg           X
    scanconst         X
    scanpat           X
    scanreg           X
    scanstr           X
    scansubst         X
    scantrans         X
    spat_free         X
    stab_to_arg       X
    stabent           X
    stio_new          X
    wopt              X
    yyerror           X
    yylex             X

##### Variables

    e_tmpname         X
    filename          X
    rcsid             X

##### Macros

    FUN0              X
    FUN1              X
    FUN2              X
    FUN3              X
    LOOPX             X
    OPERATOR          X
    RETURN            X
    SFUN              X
    SNARFWORD         X
    TERM              X
    UNI               X

       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

add_label defined in line 1436; used 10 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 87
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 135-144(3), 168-177(4), 183-186(2)

addcond defined in line 1446; used 2 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 93
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 150

addflags defined in line 2147; used 4 times

- in /usr/src/new/PORT/perl.1.0.16/perl.y line 336-345(4)

addloop defined in line 1457; used 2 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 94
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 153

append_line defined in line 1103; used 3 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 89
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 129, 183

arg_free defined in line 2563; used 7 times

- in line 2538, 2550-2552(2), 2574, 2605-2607(2)
- in /usr/src/new/PORT/perl.1.0.16/arg.c line 235

block_head defined in line 1093; used 4 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 88
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 103-105(2), 123

cmd_free defined in line 2524; used 4 times

- in line 2518, 2544-2546(2), 2577

cmd_to_arg defined in line 2299; used 5 times

- in /usr/src/new/PORT/perl.1.0.16/perl.y line 162-164(2), 175-178(2), 362

cval_to_arg defined in line 2239; used 1 times

- in /usr/src/new/PORT/perl.1.0.16/perl.y line 398

do_eval defined in line 2497; used 2 times

- in /usr/src/new/PORT/perl.1.0.16/arg.c line 2125
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 113

evalstatic defined in line 1859; used 2 times

- in line 1838
- in /usr/src/new/PORT/perl.1.0.16/cmd.h line 125

expand_charset defined in line 1031; used 2 times

- in line 1070-1075(2)

flipflip defined in line 1844; used 3 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 107
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 320-321(2)

free_arg defined in line 2266; used 16 times

- in line 1071-1076(2), 1193, 1235, 1336-1337(2), 1346, 1759, 1768, 1793, 1812, 2201-2205(2), 2331, 2596
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 179

hide_ary defined in line 2155; used 1 times

- in /usr/src/new/PORT/perl.1.0.16/perl.y line 358

invert defined in line 1477; used 5 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 92
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 160-164(2), 172, 178

l defined in line 2067; used 27 times

- in line 26, 1057, 1392-1397(2), 2327
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 245-269(13), 337-346(4), 411, 417, 548, 554-558(2)

listish defined in line 2216; used 2 times

- in /usr/src/new/PORT/perl.1.0.16/perl.y line 242-244(2)

load_format defined in line 2369; used 2 times

- in line 287
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 115

magicalize defined in line 227; used 1 times

- in line 187

main defined in line 28; never used
make_acmd defined in line 1130; used 5 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 90
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 139, 148-154(3)

make_ccmd defined in line 1151; used 12 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 91
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 119, 158-178(8), 184-186(2)

make_list defined in line 2164; used 10 times

- in /usr/src/new/PORT/perl.1.0.16/perl.y line 358-360(2), 387-392(2), 468-473(2), 540-544(2), 580, 589

make_match defined in line 2274; used 4 times

- in line 951, 1005, 1024
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 105

make_op defined in line 1733; used 116 times

- in line 1057, 1387-1402(4), 1427, 2160, 2221, 2282, 2327, 2364
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 103
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 207, 213, 237, 245-330(41), 337-346(4), 352-356(3), 366-373(3), 386-485(28), 491, 497-511(5), 533-568(12), 575-589(4)

make_split defined in line 1009; used 7 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 106
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 516-531(6)

mod_match defined in line 1370; used 5 times

- in /usr/src/new/PORT/perl.1.0.16/perl.y line 332-334(2), 523-529(3)

op_new defined in line 2253; used 9 times

- in line 974, 1526, 1746, 2175, 2193, 2232, 2245, 2305
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 102

opt_arg defined in line 1171; used 6 times

- in line 1145, 1165, 1360, 1452, 1463
- in /usr/src/new/PORT/perl.1.0.16/cmd.h line 124

scanconst defined in line 849; used 4 times

- in line 933, 942, 982, 988

scanpat defined in line 904; used 5 times

- in line 458, 625
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 117
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 515-518(2)

scanreg defined in line 817; used 6 times

- in line 442-451(3), 1658
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 121
- in /usr/src/new/PORT/perl.1.0.16/str.c line 416

scanstr defined in line 1516; used 7 times

- in line 411, 477, 995, 1067-1072(2)
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 120
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 195

scansubst defined in line 955; used 2 times

- in line 683
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 118

scantrans defined in line 1052; used 3 times

- in line 715, 769
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 119

spat_free defined in line 2599; used 2 times

- in line 2536, 2590

stab_to_arg defined in line 2225; used 50 times

- in line 951, 1005, 1024-1027(2), 1057, 2328, 2472
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 101
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 364-376(5), 388-393(2), 412, 418, 424-450(9), 457, 464-486(6), 492, 498-512(5), 530-535(2), 549, 555, 569, 576-590(6)

stabent defined in line 781; used 64 times

- in line 65, 144, 166-174(3), 185-197(5), 203, 235, 443-452(3), 1511, 1615, 1659, 1854, 1996, 2505
- in /usr/src/new/PORT/perl.1.0.16/arg.c line 434, 1631, 1644
- in /usr/src/new/PORT/perl.1.0.16/form.c line 251
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 99
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 223-229(3), 388-393(2), 412, 418, 424-450(9), 457, 464-469(2), 478-482(2), 498-502(2), 512, 519-525(3), 535, 549, 569, 586-590(2)
- in /usr/src/new/PORT/perl.1.0.16/stab.c line 178, 189, 289, 304, 312
- in /usr/src/new/PORT/perl.1.0.16/util.c line 213

stio_new defined in line 807; used 7 times

- in line 194-198(2), 204, 1616
- in /usr/src/new/PORT/perl.1.0.16/arg.c line 325, 1633
- in /usr/src/new/PORT/perl.1.0.16/perl.h line 180

wopt defined in line 2312; used 6 times

- in /usr/src/new/PORT/perl.1.0.16/perl.h line 95
- in /usr/src/new/PORT/perl.1.0.16/perl.y line 168-177(4), 183

yyerror defined in line 1485; used 9 times

- in line 2104, 2122, 2137, 2293, 2454, 2463-2468(2), 2476, 2493

yylex defined in line 253; used 1 times

- in line 2461

#### Defined variables

e_tmpname defined in line 24; used 6 times

- in line 54-56(4), 108, 157

filename defined in line 23; used 11 times

- in line 119-120(2), 141, 189, 206-207(2), 273, 326-329(3), 1509

rcsid defined in line 1; never used

#### Defined macros

FUN0 defined in line 247; used 3 times

- in line 557, 721-723(2)

FUN1 defined in line 248; used 11 times

- in line 539, 569, 575, 585, 609, 615-617(2), 643-645(2), 703, 735

FUN2 defined in line 249; used 4 times

- in line 501, 583, 619, 677

FUN3 defined in line 250; used 1 times

- in line 691

LOOPX defined in line 245; used 4 times

- in line 567, 607, 633, 675

OPERATOR defined in line 243; used 86 times

- in line 365, 374, 381-408(10), 417-430(6), 462, 469-471(2), 483-529(14), 544-565(7), 571, 577-581(2), 587-593(3), 600-603(2), 611-613(2), 621, 629, 635-641(3), 647-669(7), 679, 693-701(5), 708-711(2), 725-745(7), 751, 757-765(4), 773-777(2)

RETURN defined in line 242; used 5 times

- in line 285, 306, 342, 349-351(2)

SFUN defined in line 251; used 3 times

- in line 541, 597, 749

SNARFWORD defined in line 432; used 27 times

- in line 481-493(4), 515, 523, 549, 561, 573, 579, 589, 595, 605, 623, 631, 639, 649, 667-671(2), 681, 713, 727, 747, 753, 761, 767, 775

TERM defined in line 244; used 18 times

- in line 290, 369, 376, 412, 444-453(3), 459, 478, 537, 626, 684-689(3), 716-719(2), 755, 770

UNI defined in line 246; used 6 times

- in line 497, 519, 531-534(2), 673, 705

#### Usage of this include

perly.c used 1 times

- in /usr/src/new/PORT/perl.1.0.16/perl.y line 595

Last modified: 2002-12-19 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 7547 |