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

#### Defined functions

add_label defined in line 1435; used 10 times

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 87
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 136-145(3), 169-178(4), 184-187(2)

addcond defined in line 1445; used 2 times

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 93
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 151

addflags defined in line 2146; used 4 times

- in /usr/src/new/PORT/perl.1.0.10/perl.y line 337-346(4)

addloop defined in line 1456; used 2 times

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 94
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 154

append_line defined in line 1102; used 3 times

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 89
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 130, 184

arg_free defined in line 2562; used 6 times

- in line 2537, 2549-2551(2), 2573, 2604-2606(2)

block_head defined in line 1092; used 4 times

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 88
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 104-106(2), 124

cmd_free defined in line 2523; used 4 times

- in line 2517, 2543-2545(2), 2576

cmd_to_arg defined in line 2298; used 5 times

- in /usr/src/new/PORT/perl.1.0.10/perl.y line 163-165(2), 176-179(2), 363

cval_to_arg defined in line 2238; used 1 times

- in /usr/src/new/PORT/perl.1.0.10/perl.y line 399

do_eval defined in line 2496; used 2 times

- in /usr/src/new/PORT/perl.1.0.10/arg.c line 2101
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 113

evalstatic defined in line 1858; used 2 times

- in line 1837
- in /usr/src/new/PORT/perl.1.0.10/cmd.h line 125

expand_charset defined in line 1030; used 2 times

- in line 1069-1074(2)

flipflip defined in line 1843; used 3 times

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

free_arg defined in line 2265; used 16 times

- in line 1070-1075(2), 1192, 1234, 1335-1336(2), 1345, 1758, 1767, 1792, 1811, 2200-2204(2), 2330, 2595
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 179

hide_ary defined in line 2154; used 1 times

- in /usr/src/new/PORT/perl.1.0.10/perl.y line 359

invert defined in line 1476; used 5 times

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 92
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 161-165(2), 173, 179

l defined in line 2066; used 27 times

- in line 26, 1056, 1391-1396(2), 2326
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 246-270(13), 338-347(4), 412, 418, 549, 555-559(2)

listish defined in line 2215; used 2 times

- in /usr/src/new/PORT/perl.1.0.10/perl.y line 243-245(2)

load_format defined in line 2368; used 2 times

- in line 286
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 115

magicalize defined in line 226; used 1 times

- in line 186

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

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 90
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 140, 149-155(3)

make_ccmd defined in line 1150; used 12 times

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 91
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 120, 159-179(8), 185-187(2)

make_list defined in line 2163; used 10 times

- in /usr/src/new/PORT/perl.1.0.10/perl.y line 359-361(2), 388-393(2), 469-474(2), 541-545(2), 581, 590

make_match defined in line 2273; used 4 times

- in line 950, 1004, 1023
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 105

make_op defined in line 1732; used 116 times

- in line 1056, 1386-1401(4), 1426, 2159, 2220, 2281, 2326, 2363
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 103
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 208, 214, 238, 246-331(41), 338-347(4), 353-357(3), 367-374(3), 387-486(28), 492, 498-512(5), 534-569(12), 576-590(4)

make_split defined in line 1008; used 7 times

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 106
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 517-532(6)

mod_match defined in line 1369; used 5 times

- in /usr/src/new/PORT/perl.1.0.10/perl.y line 333-335(2), 524-530(3)

op_new defined in line 2252; used 9 times

- in line 973, 1525, 1745, 2174, 2192, 2231, 2244, 2304
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 102

opt_arg defined in line 1170; used 6 times

- in line 1144, 1164, 1359, 1451, 1462
- in /usr/src/new/PORT/perl.1.0.10/cmd.h line 124

scanconst defined in line 848; used 4 times

- in line 932, 941, 981, 987

scanpat defined in line 903; used 5 times

- in line 457, 624
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 117
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 516-519(2)

scanreg defined in line 816; used 6 times

- in line 441-450(3), 1657
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 121
- in /usr/src/new/PORT/perl.1.0.10/str.c line 416

scanstr defined in line 1515; used 7 times

- in line 410, 476, 994, 1066-1071(2)
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 120
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 196

scansubst defined in line 954; used 2 times

- in line 682
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 118

scantrans defined in line 1051; used 3 times

- in line 714, 768
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 119

spat_free defined in line 2598; used 2 times

- in line 2535, 2589

stab_to_arg defined in line 2224; used 50 times

- in line 950, 1004, 1023-1026(2), 1056, 2327, 2471
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 101
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 365-377(5), 389-394(2), 413, 419, 425-451(9), 458, 465-487(6), 493, 499-513(5), 531-536(2), 550, 556, 570, 577-591(6)

stabent defined in line 780; used 64 times

- in line 64, 143, 165-173(3), 184-196(5), 202, 234, 442-451(3), 1510, 1614, 1658, 1853, 1995, 2504
- in /usr/src/new/PORT/perl.1.0.10/arg.c line 415, 1612, 1625
- in /usr/src/new/PORT/perl.1.0.10/form.c line 251
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 99
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 224-230(3), 389-394(2), 413, 419, 425-451(9), 458, 465-470(2), 479-483(2), 499-503(2), 513, 520-526(3), 536, 550, 570, 587-591(2)
- in /usr/src/new/PORT/perl.1.0.10/stab.c line 175-180(2), 280, 295, 303
- in /usr/src/new/PORT/perl.1.0.10/util.c line 213

stio_new defined in line 806; used 7 times

- in line 193-197(2), 203, 1615
- in /usr/src/new/PORT/perl.1.0.10/arg.c line 306, 1614
- in /usr/src/new/PORT/perl.1.0.10/perl.h line 180

wopt defined in line 2311; used 6 times

- in /usr/src/new/PORT/perl.1.0.10/perl.h line 95
- in /usr/src/new/PORT/perl.1.0.10/perl.y line 169-178(4), 184

yyerror defined in line 1484; used 9 times

- in line 2103, 2121, 2136, 2292, 2453, 2462-2467(2), 2475, 2492

yylex defined in line 252; used 1 times

- in line 2460

#### Defined variables

e_tmpname defined in line 24; used 4 times

- in line 54-55(2), 107, 156

filename defined in line 23; used 11 times

- in line 118-119(2), 140, 188, 205-206(2), 272, 325-328(3), 1508

rcsid defined in line 1; never used

#### Defined macros

FUN0 defined in line 246; used 3 times

- in line 556, 720-722(2)

FUN1 defined in line 247; used 11 times

- in line 538, 568, 574, 584, 608, 614-616(2), 642-644(2), 702, 734

FUN2 defined in line 248; used 4 times

- in line 500, 582, 618, 676

FUN3 defined in line 249; used 1 times

- in line 690

LOOPX defined in line 244; used 4 times

- in line 566, 606, 632, 674

OPERATOR defined in line 242; used 86 times

- in line 364, 373, 380-407(10), 416-429(6), 461, 468-470(2), 482-528(14), 543-564(7), 570, 576-580(2), 586-592(3), 599-602(2), 610-612(2), 620, 628, 634-640(3), 646-668(7), 678, 692-700(5), 707-710(2), 724-744(7), 750, 756-764(4), 772-776(2)

RETURN defined in line 241; used 5 times

- in line 284, 305, 341, 348-350(2)

SFUN defined in line 250; used 3 times

- in line 540, 596, 748

SNARFWORD defined in line 431; used 27 times

- in line 480-492(4), 514, 522, 548, 560, 572, 578, 588, 594, 604, 622, 630, 638, 648, 666-670(2), 680, 712, 726, 746, 752, 760, 766, 774

TERM defined in line 243; used 18 times

- in line 289, 368, 375, 411, 443-452(3), 458, 477, 536, 625, 683-688(3), 715-718(2), 754, 769

UNI defined in line 245; used 6 times

- in line 496, 518, 530-533(2), 672, 704

#### Usage of this include

perly.c used 1 times

- in /usr/src/new/PORT/perl.1.0.10/perl.y line 596

Last modified: 1988-02-03 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 7578 |