home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume20 / perl3.0 / part12 < prev    next >
Encoding:
Internet Message Format  |  1989-11-01  |  49.3 KB

  1. Path: bbn.com!rsalz
  2. From: rsalz@uunet.uu.net (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v20i095:  Perl, a language with features of C/sed/awk/shell/etc, Part12/24
  5. Message-ID: <2115@papaya.bbn.com>
  6. Date: 31 Oct 89 20:13:02 GMT
  7. Lines: 2066
  8. Approved: rsalz@uunet.UU.NET
  9.  
  10. Submitted-by: Larry Wall <lwall@jpl-devvax.jpl.nasa.gov>
  11. Posting-number: Volume 20, Issue 95
  12. Archive-name: perl3.0/part12
  13.  
  14. #! /bin/sh
  15.  
  16. # Make a new directory for the perl sources, cd to it, and run kits 1
  17. # thru 24 through sh.  When all 24 kits have been run, read README.
  18.  
  19. echo "This is perl 3.0 kit 12 (of 24).  If kit 12 is complete, the line"
  20. echo '"'"End of kit 12 (of 24)"'" will echo at the end.'
  21. echo ""
  22. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  23. mkdir t 2>/dev/null
  24. echo Extracting regcomp.c
  25. sed >regcomp.c <<'!STUFFY!FUNK!' -e 's/X//'
  26. X/* NOTE: this is derived from Henry Spencer's regexp code, and should not
  27. X * confused with the original package (see point 3 below).  Thanks, Henry!
  28. X */
  29. X
  30. X/* Additional note: this code is very heavily munged from Henry's version
  31. X * in places.  In some spots I've traded clarity for efficiency, so don't
  32. X * blame Henry for some of the lack of readability.
  33. X */
  34. X
  35. X/* $Header: regcomp.c,v 3.0 89/10/18 15:22:29 lwall Locked $
  36. X *
  37. X * $Log:    regcomp.c,v $
  38. X * Revision 3.0  89/10/18  15:22:29  lwall
  39. X * 3.0 baseline
  40. X * 
  41. X */
  42. X
  43. X/*
  44. X * regcomp and regexec -- regsub and regerror are not used in perl
  45. X *
  46. X *    Copyright (c) 1986 by University of Toronto.
  47. X *    Written by Henry Spencer.  Not derived from licensed software.
  48. X *
  49. X *    Permission is granted to anyone to use this software for any
  50. X *    purpose on any computer system, and to redistribute it freely,
  51. X *    subject to the following restrictions:
  52. X *
  53. X *    1. The author is not responsible for the consequences of use of
  54. X *        this software, no matter how awful, even if they arise
  55. X *        from defects in it.
  56. X *
  57. X *    2. The origin of this software must not be misrepresented, either
  58. X *        by explicit claim or by omission.
  59. X *
  60. X *    3. Altered versions must be plainly marked as such, and must not
  61. X *        be misrepresented as being the original software.
  62. X *
  63. X *
  64. X ****    Alterations to Henry's code are...
  65. X ****
  66. X ****    Copyright (c) 1989, Larry Wall
  67. X ****
  68. X ****    You may distribute under the terms of the GNU General Public License
  69. X ****    as specified in the README file that comes with the perl 3.0 kit.
  70. X *
  71. X * Beware that some of this code is subtly aware of the way operator
  72. X * precedence is structured in regular expressions.  Serious changes in
  73. X * regular-expression syntax might require a total rethink.
  74. X */
  75. X#include "EXTERN.h"
  76. X#include "perl.h"
  77. X#include "INTERN.h"
  78. X#include "regcomp.h"
  79. X
  80. X#ifndef STATIC
  81. X#define    STATIC    static
  82. X#endif
  83. X
  84. X#define    ISMULT1(c)    ((c) == '*' || (c) == '+' || (c) == '?')
  85. X#define    ISMULT2(s)    ((*s) == '*' || (*s) == '+' || (*s) == '?' || \
  86. X    ((*s) == '{' && regcurly(s)))
  87. X#define    META    "^$.[()|?+*\\"
  88. X
  89. X/*
  90. X * Flags to be passed up and down.
  91. X */
  92. X#define    HASWIDTH    01    /* Known never to match null string. */
  93. X#define    SIMPLE        02    /* Simple enough to be STAR/PLUS operand. */
  94. X#define    SPSTART        04    /* Starts with * or +. */
  95. X#define    WORST        0    /* Worst case. */
  96. X
  97. X/*
  98. X * Global work variables for regcomp().
  99. X */
  100. Xstatic char *regprecomp;        /* uncompiled string. */
  101. Xstatic char *regparse;        /* Input-scan pointer. */
  102. Xstatic char *regxend;        /* End of input for compile */
  103. Xstatic int regnpar;        /* () count. */
  104. Xstatic char *regcode;        /* Code-emit pointer; ®dummy = don't. */
  105. Xstatic long regsize;        /* Code size. */
  106. Xstatic int regfold;
  107. Xstatic int regsawbracket;    /* Did we do {d,d} trick? */
  108. X
  109. X/*
  110. X * Forward declarations for regcomp()'s friends.
  111. X */
  112. XSTATIC int regcurly();
  113. XSTATIC char *reg();
  114. XSTATIC char *regbranch();
  115. XSTATIC char *regpiece();
  116. XSTATIC char *regatom();
  117. XSTATIC char *regclass();
  118. XSTATIC char *regnode();
  119. XSTATIC void regc();
  120. XSTATIC void reginsert();
  121. XSTATIC void regtail();
  122. XSTATIC void regoptail();
  123. X
  124. X/*
  125. X - regcomp - compile a regular expression into internal code
  126. X *
  127. X * We can't allocate space until we know how big the compiled form will be,
  128. X * but we can't compile it (and thus know how big it is) until we've got a
  129. X * place to put the code.  So we cheat:  we compile it twice, once with code
  130. X * generation turned off and size counting turned on, and once "for real".
  131. X * This also means that we don't allocate space until we are sure that the
  132. X * thing really will compile successfully, and we never have to move the
  133. X * code and thus invalidate pointers into it.  (Note that it has to be in
  134. X * one piece because free() must be able to free it all.) [NB: not true in perl]
  135. X *
  136. X * Beware that the optimization-preparation code in here knows about some
  137. X * of the structure of the compiled regexp.  [I'll say.]
  138. X */
  139. Xregexp *
  140. Xregcomp(exp,xend,fold,rare)
  141. Xchar *exp;
  142. Xchar *xend;
  143. Xint fold;
  144. Xint rare;
  145. X{
  146. X    register regexp *r;
  147. X    register char *scan;
  148. X    register STR *longest;
  149. X    register int len;
  150. X    register char *first;
  151. X    int flags;
  152. X    int back;
  153. X    int curback;
  154. X    extern char *safemalloc();
  155. X    extern char *savestr();
  156. X
  157. X    if (exp == NULL)
  158. X        fatal("NULL regexp argument");
  159. X
  160. X    /* First pass: determine size, legality. */
  161. X    regfold = fold;
  162. X    regparse = exp;
  163. X    regxend = xend;
  164. X    regprecomp = nsavestr(exp,xend-exp);
  165. X    regsawbracket = 0;
  166. X    regnpar = 1;
  167. X    regsize = 0L;
  168. X    regcode = ®dummy;
  169. X    regc(MAGIC);
  170. X    if (reg(0, &flags) == NULL) {
  171. X        Safefree(regprecomp);
  172. X        return(NULL);
  173. X    }
  174. X
  175. X    /* Small enough for pointer-storage convention? */
  176. X    if (regsize >= 32767L)        /* Probably could be 65535L. */
  177. X        FAIL("regexp too big");
  178. X
  179. X    /* Allocate space. */
  180. X    Newc(1001, r, sizeof(regexp) + (unsigned)regsize, char, regexp);
  181. X    if (r == NULL)
  182. X        FAIL("regexp out of space");
  183. X
  184. X    /* Second pass: emit code. */
  185. X    if (regsawbracket)
  186. X        bcopy(regprecomp,exp,xend-exp);
  187. X    r->precomp = regprecomp;
  188. X    r->subbase = NULL;
  189. X    regparse = exp;
  190. X    regnpar = 1;
  191. X    regcode = r->program;
  192. X    regc(MAGIC);
  193. X    if (reg(0, &flags) == NULL)
  194. X        return(NULL);
  195. X
  196. X    /* Dig out information for optimizations. */
  197. X    r->regstart = Nullstr;    /* Worst-case defaults. */
  198. X    r->reganch = 0;
  199. X    r->regmust = Nullstr;
  200. X    r->regback = -1;
  201. X    r->regstclass = Nullch;
  202. X    scan = r->program+1;            /* First BRANCH. */
  203. X    if (OP(regnext(scan)) == END) {/* Only one top-level choice. */
  204. X        scan = NEXTOPER(scan);
  205. X
  206. X        first = scan;
  207. X        while ((OP(first) > OPEN && OP(first) < CLOSE) ||
  208. X            (OP(first) == BRANCH && OP(regnext(first)) != BRANCH) ||
  209. X            (OP(first) == PLUS) )
  210. X            first = NEXTOPER(first);
  211. X
  212. X        /* Starting-point info. */
  213. X        if (OP(first) == EXACTLY) {
  214. X            r->regstart =
  215. X                str_make(OPERAND(first)+1,*OPERAND(first));
  216. X            if (r->regstart->str_cur > !(sawstudy|fold))
  217. X                fbmcompile(r->regstart,fold);
  218. X        }
  219. X        else if ((exp = index(simple,OP(first))) && exp > simple)
  220. X            r->regstclass = first;
  221. X        else if (OP(first) == BOUND || OP(first) == NBOUND)
  222. X            r->regstclass = first;
  223. X        else if (OP(first) == BOL)
  224. X            r->reganch++;
  225. X
  226. X#ifdef DEBUGGING
  227. X        if (debug & 512)
  228. X            fprintf(stderr,"first %d next %d offset %d\n",
  229. X              OP(first), OP(NEXTOPER(first)), first - scan);
  230. X#endif
  231. X        /*
  232. X         * If there's something expensive in the r.e., find the
  233. X         * longest literal string that must appear and make it the
  234. X         * regmust.  Resolve ties in favor of later strings, since
  235. X         * the regstart check works with the beginning of the r.e.
  236. X         * and avoiding duplication strengthens checking.  Not a
  237. X         * strong reason, but sufficient in the absence of others.
  238. X         * [Now we resolve ties in favor of the earlier string if
  239. X         * it happens that curback has been invalidated, since the
  240. X         * earlier string may buy us something the later one won't.]
  241. X         */
  242. X        longest = str_make("",0);
  243. X        len = 0;
  244. X        curback = 0;
  245. X        back = 0;
  246. X        while (scan != NULL) {
  247. X            if (OP(scan) == BRANCH) {
  248. X                if (OP(regnext(scan)) == BRANCH) {
  249. X                curback = -30000;
  250. X                while (OP(scan) == BRANCH)
  251. X                    scan = regnext(scan);
  252. X                }
  253. X                else    /* single branch is ok */
  254. X                scan = NEXTOPER(scan);
  255. X            }
  256. X            if (OP(scan) == EXACTLY) {
  257. X                first = scan;
  258. X                while (OP(regnext(scan)) >= CLOSE)
  259. X                scan = regnext(scan);
  260. X                if (curback - back == len) {
  261. X                str_ncat(longest, OPERAND(first)+1,
  262. X                    *OPERAND(first));
  263. X                len += *OPERAND(first);
  264. X                curback += *OPERAND(first);
  265. X                first = regnext(scan);
  266. X                }
  267. X                else if (*OPERAND(first) >= len + (curback >= 0)) {
  268. X                len = *OPERAND(first);
  269. X                str_nset(longest, OPERAND(first)+1,len);
  270. X                back = curback;
  271. X                curback += len;
  272. X                first = regnext(scan);
  273. X                }
  274. X                else
  275. X                curback += *OPERAND(first);
  276. X            }
  277. X            else if (index(varies,OP(scan)))
  278. X                curback = -30000;
  279. X            else if (index(simple,OP(scan)))
  280. X                curback++;
  281. X            scan = regnext(scan);
  282. X        }
  283. X        if (len) {
  284. X            r->regmust = longest;
  285. X            if (back < 0)
  286. X                back = -1;
  287. X            r->regback = back;
  288. X            if (len > !(sawstudy||fold||OP(first)==EOL))
  289. X                fbmcompile(r->regmust,fold);
  290. X            r->regmust->str_u.str_useful = 100;
  291. X            if (OP(first) == EOL) /* is match anchored to EOL? */
  292. X                r->regmust->str_pok |= SP_TAIL;
  293. X        }
  294. X        else
  295. X            str_free(longest);
  296. X    }
  297. X
  298. X    r->do_folding = fold;
  299. X    r->nparens = regnpar - 1;
  300. X#ifdef DEBUGGING
  301. X    if (debug & 512)
  302. X        regdump(r);
  303. X#endif
  304. X    return(r);
  305. X}
  306. X
  307. X/*
  308. X - reg - regular expression, i.e. main body or parenthesized thing
  309. X *
  310. X * Caller must absorb opening parenthesis.
  311. X *
  312. X * Combining parenthesis handling with the base level of regular expression
  313. X * is a trifle forced, but the need to tie the tails of the branches to what
  314. X * follows makes it hard to avoid.
  315. X */
  316. Xstatic char *
  317. Xreg(paren, flagp)
  318. Xint paren;            /* Parenthesized? */
  319. Xint *flagp;
  320. X{
  321. X    register char *ret;
  322. X    register char *br;
  323. X    register char *ender;
  324. X    register int parno;
  325. X    int flags;
  326. X
  327. X    *flagp = HASWIDTH;    /* Tentatively. */
  328. X
  329. X    /* Make an OPEN node, if parenthesized. */
  330. X    if (paren) {
  331. X        if (regnpar >= NSUBEXP)
  332. X            FAIL("too many () in regexp");
  333. X        parno = regnpar;
  334. X        regnpar++;
  335. X        ret = regnode(OPEN+parno);
  336. X    } else
  337. X        ret = NULL;
  338. X
  339. X    /* Pick up the branches, linking them together. */
  340. X    br = regbranch(&flags);
  341. X    if (br == NULL)
  342. X        return(NULL);
  343. X    if (ret != NULL)
  344. X        regtail(ret, br);    /* OPEN -> first. */
  345. X    else
  346. X        ret = br;
  347. X    if (!(flags&HASWIDTH))
  348. X        *flagp &= ~HASWIDTH;
  349. X    *flagp |= flags&SPSTART;
  350. X    while (*regparse == '|') {
  351. X        regparse++;
  352. X        br = regbranch(&flags);
  353. X        if (br == NULL)
  354. X            return(NULL);
  355. X        regtail(ret, br);    /* BRANCH -> BRANCH. */
  356. X        if (!(flags&HASWIDTH))
  357. X            *flagp &= ~HASWIDTH;
  358. X        *flagp |= flags&SPSTART;
  359. X    }
  360. X
  361. X    /* Make a closing node, and hook it on the end. */
  362. X    ender = regnode((paren) ? CLOSE+parno : END);    
  363. X    regtail(ret, ender);
  364. X
  365. X    /* Hook the tails of the branches to the closing node. */
  366. X    for (br = ret; br != NULL; br = regnext(br))
  367. X        regoptail(br, ender);
  368. X
  369. X    /* Check for proper termination. */
  370. X    if (paren && *regparse++ != ')') {
  371. X        FAIL("unmatched () in regexp");
  372. X    } else if (!paren && regparse < regxend) {
  373. X        if (*regparse == ')') {
  374. X            FAIL("unmatched () in regexp");
  375. X        } else
  376. X            FAIL("junk on end of regexp");    /* "Can't happen". */
  377. X        /* NOTREACHED */
  378. X    }
  379. X
  380. X    return(ret);
  381. X}
  382. X
  383. X/*
  384. X - regbranch - one alternative of an | operator
  385. X *
  386. X * Implements the concatenation operator.
  387. X */
  388. Xstatic char *
  389. Xregbranch(flagp)
  390. Xint *flagp;
  391. X{
  392. X    register char *ret;
  393. X    register char *chain;
  394. X    register char *latest;
  395. X    int flags;
  396. X
  397. X    *flagp = WORST;        /* Tentatively. */
  398. X
  399. X    ret = regnode(BRANCH);
  400. X    chain = NULL;
  401. X    while (regparse < regxend && *regparse != '|' && *regparse != ')') {
  402. X        latest = regpiece(&flags);
  403. X        if (latest == NULL)
  404. X            return(NULL);
  405. X        *flagp |= flags&HASWIDTH;
  406. X        if (chain == NULL)    /* First piece. */
  407. X            *flagp |= flags&SPSTART;
  408. X        else
  409. X            regtail(chain, latest);
  410. X        chain = latest;
  411. X    }
  412. X    if (chain == NULL)    /* Loop ran zero times. */
  413. X        (void) regnode(NOTHING);
  414. X
  415. X    return(ret);
  416. X}
  417. X
  418. X/*
  419. X - regpiece - something followed by possible [*+?]
  420. X *
  421. X * Note that the branching code sequences used for ? and the general cases
  422. X * of * and + are somewhat optimized:  they use the same NOTHING node as
  423. X * both the endmarker for their branch list and the body of the last branch.
  424. X * It might seem that this node could be dispensed with entirely, but the
  425. X * endmarker role is not redundant.
  426. X */
  427. Xstatic char *
  428. Xregpiece(flagp)
  429. Xint *flagp;
  430. X{
  431. X    register char *ret;
  432. X    register char op;
  433. X    register char *next;
  434. X    int flags;
  435. X    char *origparse = regparse;
  436. X    int orignpar = regnpar;
  437. X    char *max;
  438. X    int iter;
  439. X    char ch;
  440. X
  441. X    ret = regatom(&flags);
  442. X    if (ret == NULL)
  443. X        return(NULL);
  444. X
  445. X    op = *regparse;
  446. X
  447. X    /* Here's a total kludge: if after the atom there's a {\d+,?\d*}
  448. X     * then we decrement the first number by one and reset our
  449. X     * parsing back to the beginning of the same atom.  If the first number
  450. X     * is down to 0, decrement the second number instead and fake up
  451. X     * a ? after it.  Given the way this compiler doesn't keep track
  452. X     * of offsets on the first pass, this is the only way to replicate
  453. X     * a piece of code.  Sigh.
  454. X     */
  455. X    if (op == '{' && regcurly(regparse)) {
  456. X        next = regparse + 1;
  457. X        max = Nullch;
  458. X        while (isdigit(*next) || *next == ',') {
  459. X        if (*next == ',') {
  460. X            if (max)
  461. X            break;
  462. X            else
  463. X            max = next;
  464. X        }
  465. X        next++;
  466. X        }
  467. X        if (*next == '}') {        /* got one */
  468. X        regsawbracket++;    /* remember we clobbered exp */
  469. X        if (!max)
  470. X            max = next;
  471. X        regparse++;
  472. X        iter = atoi(regparse);
  473. X        if (iter > 0) {
  474. X            ch = *max;
  475. X            sprintf(regparse,"%.*d", max-regparse, iter - 1);
  476. X            *max = ch;
  477. X            if (*max == ',' && atoi(max+1) > 0) {
  478. X            ch = *next;
  479. X            sprintf(max+1,"%.*d", next-(max+1), atoi(max+1) - 1);
  480. X            *next = ch;
  481. X            }
  482. X            if (iter != 1 || (*max == ',' || atoi(max+1))) {
  483. X            regparse = origparse;    /* back up input pointer */
  484. X            regnpar = orignpar;    /* don't make more parens */
  485. X            }
  486. X            else {
  487. X            regparse = next;
  488. X            goto nest_check;
  489. X            }
  490. X            *flagp = flags;
  491. X            return ret;
  492. X        }
  493. X        if (*max == ',') {
  494. X            max++;
  495. X            iter = atoi(max);
  496. X            if (max == next) {        /* any number more? */
  497. X            regparse = next;
  498. X            op = '*';        /* fake up one with a star */
  499. X            }
  500. X            else if (iter > 0) {
  501. X            op = '?';        /* fake up optional atom */
  502. X            ch = *next;
  503. X            sprintf(max,"%.*d", next-max, iter - 1);
  504. X            *next = ch;
  505. X            if (iter == 1)
  506. X                regparse = next;
  507. X            else {
  508. X                regparse = origparse - 1; /* offset ++ below */
  509. X                regnpar = orignpar;
  510. X            }
  511. X            }
  512. X            else
  513. X            fatal("Can't do {n,0}");
  514. X        }
  515. X        else
  516. X            fatal("Can't do {0}");
  517. X        }
  518. X    }
  519. X
  520. X    if (!ISMULT1(op)) {
  521. X        *flagp = flags;
  522. X        return(ret);
  523. X    }
  524. X
  525. X    if (!(flags&HASWIDTH) && op != '?')
  526. X        FAIL("regexp *+ operand could be empty");
  527. X    *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
  528. X
  529. X    if (op == '*' && (flags&SIMPLE))
  530. X        reginsert(STAR, ret);
  531. X    else if (op == '*') {
  532. X        /* Emit x* as (x&|), where & means "self". */
  533. X        reginsert(BRANCH, ret);            /* Either x */
  534. X        regoptail(ret, regnode(BACK));        /* and loop */
  535. X        regoptail(ret, ret);            /* back */
  536. X        regtail(ret, regnode(BRANCH));        /* or */
  537. X        regtail(ret, regnode(NOTHING));        /* null. */
  538. X    } else if (op == '+' && (flags&SIMPLE))
  539. X        reginsert(PLUS, ret);
  540. X    else if (op == '+') {
  541. X        /* Emit x+ as x(&|), where & means "self". */
  542. X        next = regnode(BRANCH);            /* Either */
  543. X        regtail(ret, next);
  544. X        regtail(regnode(BACK), ret);        /* loop back */
  545. X        regtail(next, regnode(BRANCH));        /* or */
  546. X        regtail(ret, regnode(NOTHING));        /* null. */
  547. X    } else if (op == '?') {
  548. X        /* Emit x? as (x|) */
  549. X        reginsert(BRANCH, ret);            /* Either x */
  550. X        regtail(ret, regnode(BRANCH));        /* or */
  551. X        next = regnode(NOTHING);        /* null. */
  552. X        regtail(ret, next);
  553. X        regoptail(ret, next);
  554. X    }
  555. X      nest_check:
  556. X    regparse++;
  557. X    if (ISMULT2(regparse))
  558. X        FAIL("nested *?+ in regexp");
  559. X
  560. X    return(ret);
  561. X}
  562. X
  563. X/*
  564. X - regatom - the lowest level
  565. X *
  566. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  567. X * it can turn them into a single node, which is smaller to store and
  568. X * faster to run.  Backslashed characters are exceptions, each becoming a
  569. X * separate node; the code is simpler that way and it's not worth fixing.
  570. X *
  571. X * [Yes, it is worth fixing, some scripts can run twice the speed.]
  572. X */
  573. Xstatic char *
  574. Xregatom(flagp)
  575. Xint *flagp;
  576. X{
  577. X    register char *ret;
  578. X    int flags;
  579. X
  580. X    *flagp = WORST;        /* Tentatively. */
  581. X
  582. X    switch (*regparse++) {
  583. X    case '^':
  584. X        ret = regnode(BOL);
  585. X        break;
  586. X    case '$':
  587. X        ret = regnode(EOL);
  588. X        break;
  589. X    case '.':
  590. X        ret = regnode(ANY);
  591. X        *flagp |= HASWIDTH|SIMPLE;
  592. X        break;
  593. X    case '[':
  594. X        ret = regclass();
  595. X        *flagp |= HASWIDTH|SIMPLE;
  596. X        break;
  597. X    case '(':
  598. X        ret = reg(1, &flags);
  599. X        if (ret == NULL)
  600. X            return(NULL);
  601. X        *flagp |= flags&(HASWIDTH|SPSTART);
  602. X        break;
  603. X    case '|':
  604. X    case ')':
  605. X        FAIL("internal urp in regexp");    /* Supposed to be caught earlier. */
  606. X        break;
  607. X    case '?':
  608. X    case '+':
  609. X    case '*':
  610. X        FAIL("?+* follows nothing in regexp");
  611. X        break;
  612. X    case '\\':
  613. X        switch (*regparse) {
  614. X        case 'w':
  615. X            ret = regnode(ALNUM);
  616. X            *flagp |= HASWIDTH|SIMPLE;
  617. X            regparse++;
  618. X            break;
  619. X        case 'W':
  620. X            ret = regnode(NALNUM);
  621. X            *flagp |= HASWIDTH|SIMPLE;
  622. X            regparse++;
  623. X            break;
  624. X        case 'b':
  625. X            ret = regnode(BOUND);
  626. X            *flagp |= SIMPLE;
  627. X            regparse++;
  628. X            break;
  629. X        case 'B':
  630. X            ret = regnode(NBOUND);
  631. X            *flagp |= SIMPLE;
  632. X            regparse++;
  633. X            break;
  634. X        case 's':
  635. X            ret = regnode(SPACE);
  636. X            *flagp |= HASWIDTH|SIMPLE;
  637. X            regparse++;
  638. X            break;
  639. X        case 'S':
  640. X            ret = regnode(NSPACE);
  641. X            *flagp |= HASWIDTH|SIMPLE;
  642. X            regparse++;
  643. X            break;
  644. X        case 'd':
  645. X            ret = regnode(DIGIT);
  646. X            *flagp |= HASWIDTH|SIMPLE;
  647. X            regparse++;
  648. X            break;
  649. X        case 'D':
  650. X            ret = regnode(NDIGIT);
  651. X            *flagp |= HASWIDTH|SIMPLE;
  652. X            regparse++;
  653. X            break;
  654. X        case 'n':
  655. X        case 'r':
  656. X        case 't':
  657. X        case 'f':
  658. X            goto defchar;
  659. X        case '0': case '1': case '2': case '3': case '4':
  660. X        case '5': case '6': case '7': case '8': case '9':
  661. X            if (isdigit(regparse[1]))
  662. X                goto defchar;
  663. X            else {
  664. X                ret = regnode(REF + *regparse++ - '0');
  665. X                *flagp |= SIMPLE;
  666. X            }
  667. X            break;
  668. X        case '\0':
  669. X            if (regparse >= regxend)
  670. X                FAIL("trailing \\ in regexp");
  671. X            /* FALL THROUGH */
  672. X        default:
  673. X            goto defchar;
  674. X        }
  675. X        break;
  676. X    default: {
  677. X            register int len;
  678. X            register char ender;
  679. X            register char *p;
  680. X            char *oldp;
  681. X            int foo;
  682. X
  683. X            defchar:
  684. X            ret = regnode(EXACTLY);
  685. X            regc(0);        /* save spot for len */
  686. X            for (len=0, p=regparse-1;
  687. X              len < 127 && p < regxend;
  688. X              len++)
  689. X            {
  690. X                oldp = p;
  691. X                switch (*p) {
  692. X                case '^':
  693. X                case '$':
  694. X                case '.':
  695. X                case '[':
  696. X                case '(':
  697. X                case ')':
  698. X                case '|':
  699. X                goto loopdone;
  700. X                case '\\':
  701. X                switch (*++p) {
  702. X                case 'w':
  703. X                case 'W':
  704. X                case 'b':
  705. X                case 'B':
  706. X                case 's':
  707. X                case 'S':
  708. X                case 'd':
  709. X                case 'D':
  710. X                    --p;
  711. X                    goto loopdone;
  712. X                case 'n':
  713. X                    ender = '\n';
  714. X                    p++;
  715. X                    break;
  716. X                case 'r':
  717. X                    ender = '\r';
  718. X                    p++;
  719. X                    break;
  720. X                case 't':
  721. X                    ender = '\t';
  722. X                    p++;
  723. X                    break;
  724. X                case 'f':
  725. X                    ender = '\f';
  726. X                    p++;
  727. X                    break;
  728. X                case '0': case '1': case '2': case '3':case '4':
  729. X                case '5': case '6': case '7': case '8':case '9':
  730. X                    if (isdigit(p[1])) {
  731. X                    foo = *p++ - '0';
  732. X                    foo <<= 3;
  733. X                    foo += *p - '0';
  734. X                    if (isdigit(p[1]))
  735. X                        foo = (foo<<3) + *++p - '0';
  736. X                    ender = foo;
  737. X                    p++;
  738. X                    }
  739. X                    else {
  740. X                    --p;
  741. X                    goto loopdone;
  742. X                    }
  743. X                    break;
  744. X                case '\0':
  745. X                    if (p >= regxend)
  746. X                    FAIL("trailing \\ in regexp");
  747. X                    /* FALL THROUGH */
  748. X                default:
  749. X                    ender = *p++;
  750. X                    break;
  751. X                }
  752. X                break;
  753. X                default:
  754. X                ender = *p++;
  755. X                break;
  756. X                }
  757. X                if (regfold && isupper(ender))
  758. X                    ender = tolower(ender);
  759. X                if (ISMULT2(p)) { /* Back off on ?+*. */
  760. X                if (len)
  761. X                    p = oldp;
  762. X                else {
  763. X                    len++;
  764. X                    regc(ender);
  765. X                }
  766. X                break;
  767. X                }
  768. X                regc(ender);
  769. X            }
  770. X            loopdone:
  771. X            regparse = p;
  772. X            if (len <= 0)
  773. X                FAIL("internal disaster in regexp");
  774. X            *flagp |= HASWIDTH;
  775. X            if (len == 1)
  776. X                *flagp |= SIMPLE;
  777. X            if (regcode != ®dummy)
  778. X                *OPERAND(ret) = len;
  779. X            regc('\0');
  780. X        }
  781. X        break;
  782. X    }
  783. X
  784. X    return(ret);
  785. X}
  786. X
  787. Xstatic void
  788. Xregset(bits,def,c)
  789. Xchar *bits;
  790. Xint def;
  791. Xregister int c;
  792. X{
  793. X    if (regcode == ®dummy)
  794. X        return;
  795. X    if (def)
  796. X        bits[c >> 3] &= ~(1 << (c & 7));
  797. X    else
  798. X        bits[c >> 3] |=  (1 << (c & 7));
  799. X}
  800. X
  801. Xstatic char *
  802. Xregclass()
  803. X{
  804. X    register char *bits;
  805. X    register int class;
  806. X    register int lastclass;
  807. X    register int range = 0;
  808. X    register char *ret;
  809. X    register int def;
  810. X
  811. X    if (*regparse == '^') {    /* Complement of range. */
  812. X        ret = regnode(ANYBUT);
  813. X        regparse++;
  814. X        def = 0;
  815. X    } else {
  816. X        ret = regnode(ANYOF);
  817. X        def = 255;
  818. X    }
  819. X    bits = regcode;
  820. X    for (class = 0; class < 32; class++)
  821. X        regc(def);
  822. X    if (*regparse == ']' || *regparse == '-')
  823. X        regset(bits,def,lastclass = *regparse++);
  824. X    while (regparse < regxend && *regparse != ']') {
  825. X        class = UCHARAT(regparse++);
  826. X        if (class == '\\') {
  827. X            class = UCHARAT(regparse++);
  828. X            switch (class) {
  829. X            case 'w':
  830. X                for (class = 'a'; class <= 'z'; class++)
  831. X                    regset(bits,def,class);
  832. X                for (class = 'A'; class <= 'Z'; class++)
  833. X                    regset(bits,def,class);
  834. X                for (class = '0'; class <= '9'; class++)
  835. X                    regset(bits,def,class);
  836. X                regset(bits,def,'_');
  837. X                lastclass = 1234;
  838. X                continue;
  839. X            case 's':
  840. X                regset(bits,def,' ');
  841. X                regset(bits,def,'\t');
  842. X                regset(bits,def,'\r');
  843. X                regset(bits,def,'\f');
  844. X                regset(bits,def,'\n');
  845. X                lastclass = 1234;
  846. X                continue;
  847. X            case 'd':
  848. X                for (class = '0'; class <= '9'; class++)
  849. X                    regset(bits,def,class);
  850. X                lastclass = 1234;
  851. X                continue;
  852. X            case 'n':
  853. X                class = '\n';
  854. X                break;
  855. X            case 'r':
  856. X                class = '\r';
  857. X                break;
  858. X            case 't':
  859. X                class = '\t';
  860. X                break;
  861. X            case 'f':
  862. X                class = '\f';
  863. X                break;
  864. X            case 'b':
  865. X                class = '\b';
  866. X                break;
  867. X            case '0': case '1': case '2': case '3': case '4':
  868. X            case '5': case '6': case '7': case '8': case '9':
  869. X                class -= '0';
  870. X                if (isdigit(*regparse)) {
  871. X                    class <<= 3;
  872. X                    class += *regparse++ - '0';
  873. X                }
  874. X                if (isdigit(*regparse)) {
  875. X                    class <<= 3;
  876. X                    class += *regparse++ - '0';
  877. X                }
  878. X                break;
  879. X            }
  880. X        }
  881. X        if (!range && class == '-' && regparse < regxend &&
  882. X            *regparse != ']') {
  883. X            range = 1;
  884. X            continue;
  885. X        }
  886. X        if (range) {
  887. X            if (lastclass > class)
  888. X                FAIL("invalid [] range in regexp");
  889. X        }
  890. X        else
  891. X            lastclass = class - 1;
  892. X        range = 0;
  893. X        for (lastclass++; lastclass <= class; lastclass++) {
  894. X            regset(bits,def,lastclass);
  895. X            if (regfold && isupper(lastclass))
  896. X                regset(bits,def,tolower(lastclass));
  897. X        }
  898. X        lastclass = class;
  899. X    }
  900. X    if (*regparse != ']')
  901. X        FAIL("unmatched [] in regexp");
  902. X    regset(bits,0,0);        /* always bomb out on null */
  903. X    regparse++;
  904. X    return ret;
  905. X}
  906. X
  907. X/*
  908. X - regnode - emit a node
  909. X */
  910. Xstatic char *            /* Location. */
  911. Xregnode(op)
  912. Xchar op;
  913. X{
  914. X    register char *ret;
  915. X    register char *ptr;
  916. X
  917. X    ret = regcode;
  918. X    if (ret == ®dummy) {
  919. X#ifdef REGALIGN
  920. X        if (!(regsize & 1))
  921. X            regsize++;
  922. X#endif
  923. X        regsize += 3;
  924. X        return(ret);
  925. X    }
  926. X
  927. X#ifdef REGALIGN
  928. X#ifndef lint
  929. X    if (!((long)ret & 1))
  930. X        *ret++ = 127;
  931. X#endif
  932. X#endif
  933. X    ptr = ret;
  934. X    *ptr++ = op;
  935. X    *ptr++ = '\0';        /* Null "next" pointer. */
  936. X    *ptr++ = '\0';
  937. X    regcode = ptr;
  938. X
  939. X    return(ret);
  940. X}
  941. X
  942. X/*
  943. X - regc - emit (if appropriate) a byte of code
  944. X */
  945. Xstatic void
  946. Xregc(b)
  947. Xchar b;
  948. X{
  949. X    if (regcode != ®dummy)
  950. X        *regcode++ = b;
  951. X    else
  952. X        regsize++;
  953. X}
  954. X
  955. X/*
  956. X - reginsert - insert an operator in front of already-emitted operand
  957. X *
  958. X * Means relocating the operand.
  959. X */
  960. Xstatic void
  961. Xreginsert(op, opnd)
  962. Xchar op;
  963. Xchar *opnd;
  964. X{
  965. X    register char *src;
  966. X    register char *dst;
  967. X    register char *place;
  968. X
  969. X    if (regcode == ®dummy) {
  970. X#ifdef REGALIGN
  971. X        regsize += 4;
  972. X#else
  973. X        regsize += 3;
  974. X#endif
  975. X        return;
  976. X    }
  977. X
  978. X    src = regcode;
  979. X#ifdef REGALIGN
  980. X    regcode += 4;
  981. X#else
  982. X    regcode += 3;
  983. X#endif
  984. X    dst = regcode;
  985. X    while (src > opnd)
  986. X        *--dst = *--src;
  987. X
  988. X    place = opnd;        /* Op node, where operand used to be. */
  989. X    *place++ = op;
  990. X    *place++ = '\0';
  991. X    *place++ = '\0';
  992. X}
  993. X
  994. X/*
  995. X - regtail - set the next-pointer at the end of a node chain
  996. X */
  997. Xstatic void
  998. Xregtail(p, val)
  999. Xchar *p;
  1000. Xchar *val;
  1001. X{
  1002. X    register char *scan;
  1003. X    register char *temp;
  1004. X    register int offset;
  1005. X
  1006. X    if (p == ®dummy)
  1007. X        return;
  1008. X
  1009. X    /* Find last node. */
  1010. X    scan = p;
  1011. X    for (;;) {
  1012. X        temp = regnext(scan);
  1013. X        if (temp == NULL)
  1014. X            break;
  1015. X        scan = temp;
  1016. X    }
  1017. X
  1018. X#ifdef REGALIGN
  1019. X    offset = val - scan;
  1020. X#ifndef lint
  1021. X    *(short*)(scan+1) = offset;
  1022. X#else
  1023. X    offset = offset;
  1024. X#endif
  1025. X#else
  1026. X    if (OP(scan) == BACK)
  1027. X        offset = scan - val;
  1028. X    else
  1029. X        offset = val - scan;
  1030. X    *(scan+1) = (offset>>8)&0377;
  1031. X    *(scan+2) = offset&0377;
  1032. X#endif
  1033. X}
  1034. X
  1035. X/*
  1036. X - regoptail - regtail on operand of first argument; nop if operandless
  1037. X */
  1038. Xstatic void
  1039. Xregoptail(p, val)
  1040. Xchar *p;
  1041. Xchar *val;
  1042. X{
  1043. X    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  1044. X    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  1045. X        return;
  1046. X    regtail(NEXTOPER(p), val);
  1047. X}
  1048. X
  1049. X/*
  1050. X - regcurly - a little FSA that accepts {\d+,?\d*}
  1051. X */
  1052. XSTATIC int
  1053. Xregcurly(s)
  1054. Xregister char *s;
  1055. X{
  1056. X    if (*s++ != '{')
  1057. X    return FALSE;
  1058. X    if (!isdigit(*s))
  1059. X    return FALSE;
  1060. X    while (isdigit(*s))
  1061. X    s++;
  1062. X    if (*s == ',')
  1063. X    s++;
  1064. X    while (isdigit(*s))
  1065. X    s++;
  1066. X    if (*s != '}')
  1067. X    return FALSE;
  1068. X    return TRUE;
  1069. X}
  1070. X
  1071. X#ifdef DEBUGGING
  1072. X
  1073. X/*
  1074. X - regdump - dump a regexp onto stderr in vaguely comprehensible form
  1075. X */
  1076. Xvoid
  1077. Xregdump(r)
  1078. Xregexp *r;
  1079. X{
  1080. X    register char *s;
  1081. X    register char op = EXACTLY;    /* Arbitrary non-END op. */
  1082. X    register char *next;
  1083. X    extern char *index();
  1084. X
  1085. X
  1086. X    s = r->program + 1;
  1087. X    while (op != END) {    /* While that wasn't END last time... */
  1088. X#ifdef REGALIGN
  1089. X        if (!((long)s & 1))
  1090. X            s++;
  1091. X#endif
  1092. X        op = OP(s);
  1093. X        fprintf(stderr,"%2d%s", s-r->program, regprop(s));    /* Where, what. */
  1094. X        next = regnext(s);
  1095. X        if (next == NULL)        /* Next ptr. */
  1096. X            fprintf(stderr,"(0)");
  1097. X        else 
  1098. X            fprintf(stderr,"(%d)", (s-r->program)+(next-s));
  1099. X        s += 3;
  1100. X        if (op == ANYOF || op == ANYBUT) {
  1101. X            s += 32;
  1102. X        }
  1103. X        if (op == EXACTLY) {
  1104. X            /* Literal string, where present. */
  1105. X            s++;
  1106. X            while (*s != '\0') {
  1107. X                (void)putchar(*s);
  1108. X                s++;
  1109. X            }
  1110. X            s++;
  1111. X        }
  1112. X        (void)putchar('\n');
  1113. X    }
  1114. X
  1115. X    /* Header fields of interest. */
  1116. X    if (r->regstart)
  1117. X        fprintf(stderr,"start `%s' ", r->regstart->str_ptr);
  1118. X    if (r->regstclass)
  1119. X        fprintf(stderr,"stclass `%s' ", regprop(r->regstclass));
  1120. X    if (r->reganch)
  1121. X        fprintf(stderr,"anchored ");
  1122. X    if (r->regmust != NULL)
  1123. X        fprintf(stderr,"must have \"%s\" back %d ", r->regmust->str_ptr,
  1124. X          r->regback);
  1125. X    fprintf(stderr,"\n");
  1126. X}
  1127. X
  1128. X/*
  1129. X - regprop - printable representation of opcode
  1130. X */
  1131. Xchar *
  1132. Xregprop(op)
  1133. Xchar *op;
  1134. X{
  1135. X    register char *p;
  1136. X
  1137. X    (void) strcpy(buf, ":");
  1138. X
  1139. X    switch (OP(op)) {
  1140. X    case BOL:
  1141. X        p = "BOL";
  1142. X        break;
  1143. X    case EOL:
  1144. X        p = "EOL";
  1145. X        break;
  1146. X    case ANY:
  1147. X        p = "ANY";
  1148. X        break;
  1149. X    case ANYOF:
  1150. X        p = "ANYOF";
  1151. X        break;
  1152. X    case ANYBUT:
  1153. X        p = "ANYBUT";
  1154. X        break;
  1155. X    case BRANCH:
  1156. X        p = "BRANCH";
  1157. X        break;
  1158. X    case EXACTLY:
  1159. X        p = "EXACTLY";
  1160. X        break;
  1161. X    case NOTHING:
  1162. X        p = "NOTHING";
  1163. X        break;
  1164. X    case BACK:
  1165. X        p = "BACK";
  1166. X        break;
  1167. X    case END:
  1168. X        p = "END";
  1169. X        break;
  1170. X    case ALNUM:
  1171. X        p = "ALNUM";
  1172. X        break;
  1173. X    case NALNUM:
  1174. X        p = "NALNUM";
  1175. X        break;
  1176. X    case BOUND:
  1177. X        p = "BOUND";
  1178. X        break;
  1179. X    case NBOUND:
  1180. X        p = "NBOUND";
  1181. X        break;
  1182. X    case SPACE:
  1183. X        p = "SPACE";
  1184. X        break;
  1185. X    case NSPACE:
  1186. X        p = "NSPACE";
  1187. X        break;
  1188. X    case DIGIT:
  1189. X        p = "DIGIT";
  1190. X        break;
  1191. X    case NDIGIT:
  1192. X        p = "NDIGIT";
  1193. X        break;
  1194. X    case REF:
  1195. X    case REF+1:
  1196. X    case REF+2:
  1197. X    case REF+3:
  1198. X    case REF+4:
  1199. X    case REF+5:
  1200. X    case REF+6:
  1201. X    case REF+7:
  1202. X    case REF+8:
  1203. X    case REF+9:
  1204. X        (void)sprintf(buf+strlen(buf), "REF%d", OP(op)-REF);
  1205. X        p = NULL;
  1206. X        break;
  1207. X    case OPEN+1:
  1208. X    case OPEN+2:
  1209. X    case OPEN+3:
  1210. X    case OPEN+4:
  1211. X    case OPEN+5:
  1212. X    case OPEN+6:
  1213. X    case OPEN+7:
  1214. X    case OPEN+8:
  1215. X    case OPEN+9:
  1216. X        (void)sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
  1217. X        p = NULL;
  1218. X        break;
  1219. X    case CLOSE+1:
  1220. X    case CLOSE+2:
  1221. X    case CLOSE+3:
  1222. X    case CLOSE+4:
  1223. X    case CLOSE+5:
  1224. X    case CLOSE+6:
  1225. X    case CLOSE+7:
  1226. X    case CLOSE+8:
  1227. X    case CLOSE+9:
  1228. X        (void)sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
  1229. X        p = NULL;
  1230. X        break;
  1231. X    case STAR:
  1232. X        p = "STAR";
  1233. X        break;
  1234. X    case PLUS:
  1235. X        p = "PLUS";
  1236. X        break;
  1237. X    default:
  1238. X        FAIL("corrupted regexp opcode");
  1239. X    }
  1240. X    if (p != NULL)
  1241. X        (void) strcat(buf, p);
  1242. X    return(buf);
  1243. X}
  1244. X#endif /* DEBUGGING */
  1245. X
  1246. Xregfree(r)
  1247. Xstruct regexp *r;
  1248. X{
  1249. X    if (r->precomp)
  1250. X        Safefree(r->precomp);
  1251. X    if (r->subbase)
  1252. X        Safefree(r->subbase);
  1253. X    if (r->regmust)
  1254. X        str_free(r->regmust);
  1255. X    if (r->regstart)
  1256. X        str_free(r->regstart);
  1257. X    Safefree(r);
  1258. X}
  1259. !STUFFY!FUNK!
  1260. echo Extracting perl.y
  1261. sed >perl.y <<'!STUFFY!FUNK!' -e 's/X//'
  1262. X/* $Header: perl.y,v 3.0 89/10/18 15:22:04 lwall Locked $
  1263. X *
  1264. X *    Copyright (c) 1989, Larry Wall
  1265. X *
  1266. X *    You may distribute under the terms of the GNU General Public License
  1267. X *    as specified in the README file that comes with the perl 3.0 kit.
  1268. X *
  1269. X * $Log:    perl.y,v $
  1270. X * Revision 3.0  89/10/18  15:22:04  lwall
  1271. X * 3.0 baseline
  1272. X * 
  1273. X */
  1274. X
  1275. X%{
  1276. X#include "INTERN.h"
  1277. X#include "perl.h"
  1278. X
  1279. XSTAB *scrstab;
  1280. XARG *arg4;    /* rarely used arguments to make_op() */
  1281. XARG *arg5;
  1282. X
  1283. X%}
  1284. X
  1285. X%start prog
  1286. X
  1287. X%union {
  1288. X    int    ival;
  1289. X    char *cval;
  1290. X    ARG *arg;
  1291. X    CMD *cmdval;
  1292. X    struct compcmd compval;
  1293. X    STAB *stabval;
  1294. X    FCMD *formval;
  1295. X}
  1296. X
  1297. X%token <cval> WORD
  1298. X%token <ival> APPEND OPEN SELECT LOOPEX
  1299. X%token <ival> USING FORMAT DO SHIFT PUSH POP LVALFUN
  1300. X%token <ival> WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE SPLIT FLIST
  1301. X%token <ival> FOR FILOP FILOP2 FILOP3 FILOP4 FILOP22 FILOP25
  1302. X%token <ival> FUNC0 FUNC1 FUNC2 FUNC3 HSHFUN HSHFUN3
  1303. X%token <ival> FLIST2 SUB FILETEST LOCAL DELETE
  1304. X%token <ival> RELOP EQOP MULOP ADDOP PACKAGE AMPER LFUNC4
  1305. X%token <formval> FORMLIST
  1306. X%token <stabval> REG ARYLEN ARY HSH STAR
  1307. X%token <arg> SUBST PATTERN
  1308. X%token <arg> RSTRING TRANS
  1309. X
  1310. X%type <ival> prog decl format remember
  1311. X%type <stabval>
  1312. X%type <cmdval> block lineseq line loop cond sideff nexpr else
  1313. X%type <arg> expr sexpr cexpr csexpr term handle aryword hshword
  1314. X%type <arg> texpr listop
  1315. X%type <cval> label
  1316. X%type <compval> compblock
  1317. X
  1318. X%nonassoc <ival> LISTOP
  1319. X%left ','
  1320. X%right '='
  1321. X%right '?' ':'
  1322. X%nonassoc DOTDOT
  1323. X%left OROR
  1324. X%left ANDAND
  1325. X%left '|' '^'
  1326. X%left '&'
  1327. X%nonassoc EQOP
  1328. X%nonassoc RELOP
  1329. X%nonassoc <ival> UNIOP
  1330. X%nonassoc FILETEST
  1331. X%left LS RS
  1332. X%left ADDOP
  1333. X%left MULOP
  1334. X%left MATCH NMATCH 
  1335. X%right '!' '~' UMINUS
  1336. X%right POW
  1337. X%nonassoc INC DEC
  1338. X%left '('
  1339. X
  1340. X%% /* RULES */
  1341. X
  1342. Xprog    :    lineseq
  1343. X            { if (in_eval)
  1344. X                eval_root = block_head($1);
  1345. X                else
  1346. X                main_root = block_head($1); }
  1347. X    ;
  1348. X
  1349. Xcompblock:    block CONTINUE block
  1350. X            { $$.comp_true = $1; $$.comp_alt = $3; }
  1351. X    |    block else
  1352. X            { $$.comp_true = $1; $$.comp_alt = $2; }
  1353. X    ;
  1354. X
  1355. Xelse    :    /* NULL */
  1356. X            { $$ = Nullcmd; }
  1357. X    |    ELSE block
  1358. X            { $$ = $2; }
  1359. X    |    ELSIF '(' expr ')' compblock
  1360. X            { cmdline = $1;
  1361. X                $$ = make_ccmd(C_ELSIF,$3,$5); }
  1362. X    ;
  1363. X
  1364. Xblock    :    '{' remember lineseq '}'
  1365. X            { $$ = block_head($3);
  1366. X              if (savestack->ary_fill > $2)
  1367. X                restorelist($2); }
  1368. X    ;
  1369. X
  1370. Xremember:    /* NULL */    /* in case they push a package name */
  1371. X            { $$ = savestack->ary_fill; }
  1372. X    ;
  1373. X
  1374. Xlineseq    :    /* NULL */
  1375. X            { $$ = Nullcmd; }
  1376. X    |    lineseq line
  1377. X            { $$ = append_line($1,$2); }
  1378. X    ;
  1379. X
  1380. Xline    :    decl
  1381. X            { $$ = Nullcmd; }
  1382. X    |    label cond
  1383. X            { $$ = add_label($1,$2); }
  1384. X    |    loop    /* loops add their own labels */
  1385. X    |    label ';'
  1386. X            { if ($1 != Nullch) {
  1387. X                  $$ = add_label($1, make_acmd(C_EXPR, Nullstab,
  1388. X                  Nullarg, Nullarg) );
  1389. X                } else
  1390. X                  $$ = Nullcmd; }
  1391. X    |    label sideff ';'
  1392. X            { $$ = add_label($1,$2); }
  1393. X    ;
  1394. X
  1395. Xsideff    :    error
  1396. X            { $$ = Nullcmd; }
  1397. X    |    expr
  1398. X            { $$ = make_acmd(C_EXPR, Nullstab, $1, Nullarg); }
  1399. X    |    expr IF expr
  1400. X            { $$ = addcond(
  1401. X                   make_acmd(C_EXPR, Nullstab, Nullarg, $1), $3); }
  1402. X    |    expr UNLESS expr
  1403. X            { $$ = addcond(invert(
  1404. X                   make_acmd(C_EXPR, Nullstab, Nullarg, $1)), $3); }
  1405. X    |    expr WHILE expr
  1406. X            { $$ = addloop(
  1407. X                   make_acmd(C_EXPR, Nullstab, Nullarg, $1), $3); }
  1408. X    |    expr UNTIL expr
  1409. X            { $$ = addloop(invert(
  1410. X                   make_acmd(C_EXPR, Nullstab, Nullarg, $1)), $3); }
  1411. X    ;
  1412. X
  1413. Xcond    :    IF '(' expr ')' compblock
  1414. X            { cmdline = $1;
  1415. X                $$ = make_icmd(C_IF,$3,$5); }
  1416. X    |    UNLESS '(' expr ')' compblock
  1417. X            { cmdline = $1;
  1418. X                $$ = invert(make_icmd(C_IF,$3,$5)); }
  1419. X    |    IF block compblock
  1420. X            { cmdline = $1;
  1421. X                $$ = make_ccmd(C_IF,cmd_to_arg($2),$3); }
  1422. X    |    UNLESS block compblock
  1423. X            { cmdline = $1;
  1424. X                $$ = invert(make_ccmd(C_IF,cmd_to_arg($2),$3)); }
  1425. X    ;
  1426. X
  1427. Xloop    :    label WHILE '(' texpr ')' compblock
  1428. X            { cmdline = $2;
  1429. X                $$ = wopt(add_label($1,
  1430. X                make_ccmd(C_WHILE,$4,$6) )); }
  1431. X    |    label UNTIL '(' expr ')' compblock
  1432. X            { cmdline = $2;
  1433. X                $$ = wopt(add_label($1,
  1434. X                invert(make_ccmd(C_WHILE,$4,$6)) )); }
  1435. X    |    label WHILE block compblock
  1436. X            { cmdline = $2;
  1437. X                $$ = wopt(add_label($1,
  1438. X                make_ccmd(C_WHILE, cmd_to_arg($3),$4) )); }
  1439. X    |    label UNTIL block compblock
  1440. X            { cmdline = $2;
  1441. X                $$ = wopt(add_label($1,
  1442. X                invert(make_ccmd(C_WHILE, cmd_to_arg($3),$4)) )); }
  1443. X    |    label FOR REG '(' expr ')' compblock
  1444. X            { cmdline = $2;
  1445. X                /*
  1446. X                 * The following gobbledygook catches EXPRs that
  1447. X                 * aren't explicit array refs and translates
  1448. X                 *        foreach VAR (EXPR) {
  1449. X                 * into
  1450. X                 *        @ary = EXPR;
  1451. X                 *        foreach VAR (@ary) {
  1452. X                 * where @ary is a hidden array made by genstab().
  1453. X                 * (Note that @ary may become a local array if
  1454. X                 * it is determined that it might be called
  1455. X                 * recursively.  See cmd_tosave().)
  1456. X                 */
  1457. X                if ($5->arg_type != O_ARRAY) {
  1458. X                scrstab = aadd(genstab());
  1459. X                $$ = append_line(
  1460. X                    make_acmd(C_EXPR, Nullstab,
  1461. X                      l(make_op(O_ASSIGN,2,
  1462. X                    listish(make_op(O_ARRAY, 1,
  1463. X                      stab2arg(A_STAB,scrstab),
  1464. X                      Nullarg,Nullarg, 1)),
  1465. X                    listish(make_list($5)),
  1466. X                    Nullarg)),
  1467. X                      Nullarg),
  1468. X                    wopt(over($3,add_label($1,
  1469. X                      make_ccmd(C_WHILE,
  1470. X                    make_op(O_ARRAY, 1,
  1471. X                      stab2arg(A_STAB,scrstab),
  1472. X                      Nullarg,Nullarg ),
  1473. X                    $7)))));
  1474. X                }
  1475. X                else {
  1476. X                $$ = wopt(over($3,add_label($1,
  1477. X                make_ccmd(C_WHILE,$5,$7) )));
  1478. X                }
  1479. X            }
  1480. X    |    label FOR '(' expr ')' compblock
  1481. X            { cmdline = $2;
  1482. X                if ($4->arg_type != O_ARRAY) {
  1483. X                scrstab = aadd(genstab());
  1484. X                $$ = append_line(
  1485. X                    make_acmd(C_EXPR, Nullstab,
  1486. X                      l(make_op(O_ASSIGN,2,
  1487. X                    listish(make_op(O_ARRAY, 1,
  1488. X                      stab2arg(A_STAB,scrstab),
  1489. X                      Nullarg,Nullarg, 1 )),
  1490. X                    listish(make_list($4)),
  1491. X                    Nullarg)),
  1492. X                      Nullarg),
  1493. X                    wopt(over(defstab,add_label($1,
  1494. X                      make_ccmd(C_WHILE,
  1495. X                    make_op(O_ARRAY, 1,
  1496. X                      stab2arg(A_STAB,scrstab),
  1497. X                      Nullarg,Nullarg ),
  1498. X                    $6)))));
  1499. X                }
  1500. X                else {    /* lisp, anyone? */
  1501. X                $$ = wopt(over(defstab,add_label($1,
  1502. X                make_ccmd(C_WHILE,$4,$6) )));
  1503. X                }
  1504. X            }
  1505. X    |    label FOR '(' nexpr ';' texpr ';' nexpr ')' block
  1506. X            /* basically fake up an initialize-while lineseq */
  1507. X            {   yyval.compval.comp_true = $10;
  1508. X                yyval.compval.comp_alt = $8;
  1509. X                cmdline = $2;
  1510. X                $$ = append_line($4,wopt(add_label($1,
  1511. X                make_ccmd(C_WHILE,$6,yyval.compval) ))); }
  1512. X    |    label compblock    /* a block is a loop that happens once */
  1513. X            { $$ = add_label($1,make_ccmd(C_BLOCK,Nullarg,$2)); }
  1514. X    ;
  1515. X
  1516. Xnexpr    :    /* NULL */
  1517. X            { $$ = Nullcmd; }
  1518. X    |    sideff
  1519. X    ;
  1520. X
  1521. Xtexpr    :    /* NULL means true */
  1522. X            { (void)scanstr("1"); $$ = yylval.arg; }
  1523. X    |    expr
  1524. X    ;
  1525. X
  1526. Xlabel    :    /* empty */
  1527. X            { $$ = Nullch; }
  1528. X    |    WORD ':'
  1529. X    ;
  1530. X
  1531. Xdecl    :    format
  1532. X            { $$ = 0; }
  1533. X    |    subrout
  1534. X            { $$ = 0; }
  1535. X    |    package
  1536. X            { $$ = 0; }
  1537. X    ;
  1538. X
  1539. Xformat    :    FORMAT WORD '=' FORMLIST
  1540. X            { stab_form(stabent($2,TRUE)) = $4; Safefree($2);}
  1541. X    |    FORMAT '=' FORMLIST
  1542. X            { stab_form(stabent("STDOUT",TRUE)) = $3; }
  1543. X    ;
  1544. X
  1545. Xsubrout    :    SUB WORD block
  1546. X            { make_sub($2,$3); }
  1547. X    ;
  1548. X
  1549. Xpackage :    PACKAGE WORD ';'
  1550. X            { char tmpbuf[256];
  1551. X
  1552. X              savehptr(&curstash);
  1553. X              saveitem(curstname);
  1554. X              str_set(curstname,$2);
  1555. X              sprintf(tmpbuf,"'_%s",$2);
  1556. X              curstash = stab_xhash(hadd(stabent(tmpbuf,TRUE)));
  1557. X              curstash->tbl_coeffsize = 0;
  1558. X              Safefree($2);
  1559. X            }
  1560. X    ;
  1561. X
  1562. Xcexpr    :    ',' expr
  1563. X            { $$ = $2; }
  1564. X    ;
  1565. X
  1566. Xexpr    :    expr ',' sexpr
  1567. X            { $$ = make_op(O_COMMA, 2, $1, $3, Nullarg); }
  1568. X    |    sexpr
  1569. X    ;
  1570. X
  1571. Xcsexpr    :    ',' sexpr
  1572. X            { $$ = $2; }
  1573. X    ;
  1574. X
  1575. Xsexpr    :    sexpr '=' sexpr
  1576. X            {   $1 = listish($1);
  1577. X                if ($1->arg_type == O_ASSIGN && $1->arg_len == 1)
  1578. X                $1->arg_type = O_ITEM;    /* a local() */
  1579. X                if ($1->arg_type == O_LIST)
  1580. X                $3 = listish($3);
  1581. X                $$ = l(make_op(O_ASSIGN, 2, $1, $3, Nullarg)); }
  1582. X    |    sexpr POW '=' sexpr
  1583. X            { $$ = l(make_op(O_POW, 2, $1, $4, Nullarg)); }
  1584. X    |    sexpr MULOP '=' sexpr
  1585. X            { $$ = l(make_op($2, 2, $1, $4, Nullarg)); }
  1586. X    |    sexpr ADDOP '=' sexpr
  1587. X            { $$ = rcatmaybe(l(make_op($2, 2, $1, $4, Nullarg)));}
  1588. X    |    sexpr LS '=' sexpr
  1589. X            { $$ = l(make_op(O_LEFT_SHIFT, 2, $1, $4, Nullarg)); }
  1590. X    |    sexpr RS '=' sexpr
  1591. X            { $$ = l(make_op(O_RIGHT_SHIFT, 2, $1, $4, Nullarg)); }
  1592. X    |    sexpr '&' '=' sexpr
  1593. X            { $$ = l(make_op(O_BIT_AND, 2, $1, $4, Nullarg)); }
  1594. X    |    sexpr '^' '=' sexpr
  1595. X            { $$ = l(make_op(O_XOR, 2, $1, $4, Nullarg)); }
  1596. X    |    sexpr '|' '=' sexpr
  1597. X            { $$ = l(make_op(O_BIT_OR, 2, $1, $4, Nullarg)); }
  1598. X
  1599. X
  1600. X    |    sexpr POW sexpr
  1601. X            { $$ = make_op(O_POW, 2, $1, $3, Nullarg); }
  1602. X    |    sexpr MULOP sexpr
  1603. X            { $$ = make_op($2, 2, $1, $3, Nullarg); }
  1604. X    |    sexpr ADDOP sexpr
  1605. X            { $$ = make_op($2, 2, $1, $3, Nullarg); }
  1606. X    |    sexpr LS sexpr
  1607. X            { $$ = make_op(O_LEFT_SHIFT, 2, $1, $3, Nullarg); }
  1608. X    |    sexpr RS sexpr
  1609. X            { $$ = make_op(O_RIGHT_SHIFT, 2, $1, $3, Nullarg); }
  1610. X    |    sexpr RELOP sexpr
  1611. X            { $$ = make_op($2, 2, $1, $3, Nullarg); }
  1612. X    |    sexpr EQOP sexpr
  1613. X            { $$ = make_op($2, 2, $1, $3, Nullarg); }
  1614. X    |    sexpr '&' sexpr
  1615. X            { $$ = make_op(O_BIT_AND, 2, $1, $3, Nullarg); }
  1616. X    |    sexpr '^' sexpr
  1617. X            { $$ = make_op(O_XOR, 2, $1, $3, Nullarg); }
  1618. X    |    sexpr '|' sexpr
  1619. X            { $$ = make_op(O_BIT_OR, 2, $1, $3, Nullarg); }
  1620. X    |    sexpr DOTDOT sexpr
  1621. X            { arg4 = Nullarg;
  1622. X              $$ = make_op(O_F_OR_R, 4, $1, $3, Nullarg); }
  1623. X    |    sexpr ANDAND sexpr
  1624. X            { $$ = make_op(O_AND, 2, $1, $3, Nullarg); }
  1625. X    |    sexpr OROR sexpr
  1626. X            { $$ = make_op(O_OR, 2, $1, $3, Nullarg); }
  1627. X    |    sexpr '?' sexpr ':' sexpr
  1628. X            { $$ = make_op(O_COND_EXPR, 3, $1, $3, $5); }
  1629. X    |    sexpr MATCH sexpr
  1630. X            { $$ = mod_match(O_MATCH, $1, $3); }
  1631. X    |    sexpr NMATCH sexpr
  1632. X            { $$ = mod_match(O_NMATCH, $1, $3); }
  1633. X    |    term INC
  1634. X            { $$ = addflags(1, AF_POST|AF_UP,
  1635. X                l(make_op(O_ITEM,1,$1,Nullarg,Nullarg))); }
  1636. X    |    term DEC
  1637. X            { $$ = addflags(1, AF_POST,
  1638. X                l(make_op(O_ITEM,1,$1,Nullarg,Nullarg))); }
  1639. X    |    INC term
  1640. X            { $$ = addflags(1, AF_PRE|AF_UP,
  1641. X                l(make_op(O_ITEM,1,$2,Nullarg,Nullarg))); }
  1642. X    |    DEC term
  1643. X            { $$ = addflags(1, AF_PRE,
  1644. X                l(make_op(O_ITEM,1,$2,Nullarg,Nullarg))); }
  1645. X    |    term
  1646. X            { $$ = $1; }
  1647. X    ;
  1648. X
  1649. Xterm    :    '-' term %prec UMINUS
  1650. X            { $$ = make_op(O_NEGATE, 1, $2, Nullarg, Nullarg); }
  1651. X    |    '+' term %prec UMINUS
  1652. X            { $$ = $2; }
  1653. X    |    '!' term
  1654. X            { $$ = make_op(O_NOT, 1, $2, Nullarg, Nullarg); }
  1655. X    |    '~' term
  1656. X            { $$ = make_op(O_COMPLEMENT, 1, $2, Nullarg, Nullarg);}
  1657. X    |    FILETEST WORD
  1658. X            { opargs[$1] = 0;    /* force it special */
  1659. X                $$ = make_op($1, 1,
  1660. X                stab2arg(A_STAB,stabent($2,TRUE)),
  1661. X                Nullarg, Nullarg);
  1662. X            }
  1663. X    |    FILETEST sexpr
  1664. X            { opargs[$1] = 1;
  1665. X                $$ = make_op($1, 1, $2, Nullarg, Nullarg); }
  1666. X    |    FILETEST
  1667. X            { opargs[$1] = ($1 != O_FTTTY);
  1668. X                $$ = make_op($1, 1,
  1669. X                stab2arg(A_STAB,
  1670. X                  $1 == O_FTTTY?stabent("STDIN",TRUE):defstab),
  1671. X                Nullarg, Nullarg); }
  1672. X    |    LOCAL '(' expr ')'
  1673. X            { $$ = l(make_op(O_ITEM, 1,
  1674. X                localize(listish(make_list($3))),
  1675. X                Nullarg,Nullarg)); }
  1676. X    |    '(' expr ')'
  1677. X            { $$ = make_list(hide_ary($2)); }
  1678. X    |    '(' ')'
  1679. X            { $$ = make_list(Nullarg); }
  1680. X    |    DO sexpr    %prec FILETEST
  1681. X            { $$ = fixeval(
  1682. X                make_op(O_DOFILE,2,$2,Nullarg,Nullarg) );
  1683. X              allstabs = TRUE;}
  1684. X    |    DO block    %prec '('
  1685. X            { $$ = cmd_to_arg($2); }
  1686. X    |    REG    %prec '('
  1687. X            { $$ = stab2arg(A_STAB,$1); }
  1688. X    |    STAR    %prec '('
  1689. X            { $$ = stab2arg(A_STAR,$1); }
  1690. X    |    REG '[' expr ']'    %prec '('
  1691. X            { $$ = make_op(O_AELEM, 2,
  1692. X                stab2arg(A_STAB,aadd($1)), $3, Nullarg); }
  1693. X    |    HSH     %prec '('
  1694. X            { $$ = make_op(O_HASH, 1,
  1695. X                stab2arg(A_STAB,$1),
  1696. X                Nullarg, Nullarg); }
  1697. X    |    ARY     %prec '('
  1698. X            { $$ = make_op(O_ARRAY, 1,
  1699. X                stab2arg(A_STAB,$1),
  1700. X                Nullarg, Nullarg); }
  1701. X    |    REG '{' expr '}'    %prec '('
  1702. X            { $$ = make_op(O_HELEM, 2,
  1703. X                stab2arg(A_STAB,hadd($1)),
  1704. X                jmaybe($3),
  1705. X                Nullarg); }
  1706. X    |    ARY '[' expr ']'    %prec '('
  1707. X            { $$ = make_op(O_ASLICE, 2,
  1708. X                stab2arg(A_STAB,aadd($1)),
  1709. X                listish(make_list($3)),
  1710. X                Nullarg); }
  1711. X    |    ARY '{' expr '}'    %prec '('
  1712. X            { $$ = make_op(O_HSLICE, 2,
  1713. X                stab2arg(A_STAB,hadd($1)),
  1714. X                listish(make_list($3)),
  1715. X                Nullarg); }
  1716. X    |    DELETE REG '{' expr '}'    %prec '('
  1717. X            { $$ = make_op(O_DELETE, 2,
  1718. X                stab2arg(A_STAB,hadd($2)),
  1719. X                jmaybe($4),
  1720. X                Nullarg); }
  1721. X    |    ARYLEN    %prec '('
  1722. X            { $$ = stab2arg(A_ARYLEN,$1); }
  1723. X    |    RSTRING    %prec '('
  1724. X            { $$ = $1; }
  1725. X    |    PATTERN    %prec '('
  1726. X            { $$ = $1; }
  1727. X    |    SUBST    %prec '('
  1728. X            { $$ = $1; }
  1729. X    |    TRANS    %prec '('
  1730. X            { $$ = $1; }
  1731. X    |    DO WORD '(' expr ')'
  1732. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1733. X                stab2arg(A_WORD,stabent($2,TRUE)),
  1734. X                make_list($4),
  1735. X                Nullarg); Safefree($2); }
  1736. X    |    AMPER WORD '(' expr ')'
  1737. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1738. X                stab2arg(A_WORD,stabent($2,TRUE)),
  1739. X                make_list($4),
  1740. X                Nullarg); Safefree($2); }
  1741. X    |    DO WORD '(' ')'
  1742. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1743. X                stab2arg(A_WORD,stabent($2,TRUE)),
  1744. X                make_list(Nullarg),
  1745. X                Nullarg); }
  1746. X    |    AMPER WORD '(' ')'
  1747. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1748. X                stab2arg(A_WORD,stabent($2,TRUE)),
  1749. X                make_list(Nullarg),
  1750. X                Nullarg); }
  1751. X    |    AMPER WORD
  1752. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1753. X                stab2arg(A_WORD,stabent($2,TRUE)),
  1754. X                Nullarg,
  1755. X                Nullarg); }
  1756. X    |    DO REG '(' expr ')'
  1757. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1758. X                stab2arg(A_STAB,$2),
  1759. X                make_list($4),
  1760. X                Nullarg); }
  1761. X    |    AMPER REG '(' expr ')'
  1762. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1763. X                stab2arg(A_STAB,$2),
  1764. X                make_list($4),
  1765. X                Nullarg); }
  1766. X    |    DO REG '(' ')'
  1767. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1768. X                stab2arg(A_STAB,$2),
  1769. X                make_list(Nullarg),
  1770. X                Nullarg); }
  1771. X    |    AMPER REG '(' ')'
  1772. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1773. X                stab2arg(A_STAB,$2),
  1774. X                make_list(Nullarg),
  1775. X                Nullarg); }
  1776. X    |    AMPER REG
  1777. X            { $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
  1778. X                stab2arg(A_STAB,$2),
  1779. X                Nullarg,
  1780. X                Nullarg); }
  1781. X    |    LOOPEX
  1782. X            { $$ = make_op($1,0,Nullarg,Nullarg,Nullarg); }
  1783. X    |    LOOPEX WORD
  1784. X            { $$ = make_op($1,1,cval_to_arg($2),
  1785. X                Nullarg,Nullarg); }
  1786. X    |    UNIOP
  1787. X            { $$ = make_op($1,1,Nullarg,Nullarg,Nullarg);
  1788. X              if ($1 == O_EVAL || $1 == O_RESET)
  1789. X                $$ = fixeval($$); }
  1790. X    |    UNIOP sexpr
  1791. X            { $$ = make_op($1,1,$2,Nullarg,Nullarg);
  1792. X              if ($1 == O_EVAL || $1 == O_RESET)
  1793. X                $$ = fixeval($$); }
  1794. X    |    SELECT
  1795. X            { $$ = make_op(O_SELECT, 0, Nullarg, Nullarg, Nullarg);}
  1796. X    |    SELECT '(' handle ')'
  1797. X            { $$ = make_op(O_SELECT, 1, $3, Nullarg, Nullarg); }
  1798. X    |    SELECT '(' sexpr csexpr csexpr csexpr ')'
  1799. X            { arg4 = $6;
  1800. X              $$ = make_op(O_SSELECT, 4, $3, $4, $5); }
  1801. X    |    OPEN WORD    %prec '('
  1802. X            { $$ = make_op(O_OPEN, 2,
  1803. X                stab2arg(A_WORD,stabent($2,TRUE)),
  1804. X                stab2arg(A_STAB,stabent($2,TRUE)),
  1805. X                Nullarg); }
  1806. X    |    OPEN '(' WORD ')'
  1807. X            { $$ = make_op(O_OPEN, 2,
  1808. X                stab2arg(A_WORD,stabent($3,TRUE)),
  1809. X                stab2arg(A_STAB,stabent($3,TRUE)),
  1810. X                Nullarg); }
  1811. X    |    OPEN '(' handle cexpr ')'
  1812. X            { $$ = make_op(O_OPEN, 2,
  1813. X                $3,
  1814. X                $4, Nullarg); }
  1815. X    |    FILOP '(' handle ')'
  1816. X            { $$ = make_op($1, 1,
  1817. X                $3,
  1818. X                Nullarg, Nullarg); }
  1819. X    |    FILOP WORD
  1820. X            { $$ = make_op($1, 1,
  1821. X                stab2arg(A_WORD,stabent($2,TRUE)),
  1822. X                Nullarg, Nullarg);
  1823. X              Safefree($2); }
  1824. X    |    FILOP REG
  1825. X            { $$ = make_op($1, 1,
  1826. X                stab2arg(A_STAB,$2),
  1827. X                Nullarg, Nullarg); }
  1828. X    |    FILOP '(' ')'
  1829. X            { $$ = make_op($1, 1,
  1830. X                stab2arg(A_WORD,Nullstab),
  1831. X                Nullarg, Nullarg); }
  1832. X    |    FILOP    %prec '('
  1833. X            { $$ = make_op($1, 0,
  1834. X                Nullarg, Nullarg, Nullarg); }
  1835. X    |    FILOP2 '(' handle cexpr ')'
  1836. X            { $$ = make_op($1, 2, $3, $4, Nullarg); }
  1837. X    |    FILOP3 '(' handle csexpr cexpr ')'
  1838. X            { $$ = make_op($1, 3, $3, $4, $5); }
  1839. X    |    FILOP22 '(' handle ',' handle ')'
  1840. X            { $$ = make_op($1, 2, $3, $5, Nullarg); }
  1841. X    |    FILOP4 '(' handle csexpr csexpr cexpr ')'
  1842. X            { arg4 = $6; $$ = make_op($1, 4, $3, $4, $5); }
  1843. X    |    FILOP25 '(' handle ',' handle csexpr csexpr cexpr ')'
  1844. X            { arg4 = $7; arg5 = $8;
  1845. X              $$ = make_op($1, 5, $3, $5, $6); }
  1846. X    |    PUSH '(' aryword cexpr ')'
  1847. X            { $$ = make_op($1, 2,
  1848. X                $3,
  1849. X                make_list($4),
  1850. X                Nullarg); }
  1851. X    |    POP aryword    %prec '('
  1852. X            { $$ = make_op(O_POP, 1, $2, Nullarg, Nullarg); }
  1853. X    |    POP '(' aryword ')'
  1854. X            { $$ = make_op(O_POP, 1, $3, Nullarg, Nullarg); }
  1855. X    |    SHIFT aryword    %prec '('
  1856. X            { $$ = make_op(O_SHIFT, 1, $2, Nullarg, Nullarg); }
  1857. X    |    SHIFT '(' aryword ')'
  1858. X            { $$ = make_op(O_SHIFT, 1, $3, Nullarg, Nullarg); }
  1859. X    |    SHIFT    %prec '('
  1860. X            { $$ = make_op(O_SHIFT, 1,
  1861. X                stab2arg(A_STAB,
  1862. X                  aadd(stabent(subline ? "_" : "ARGV", TRUE))),
  1863. X                Nullarg, Nullarg); }
  1864. X    |    SPLIT    %prec '('
  1865. X            { (void)scanpat("/\\s+/");
  1866. X                $$ = make_split(defstab,yylval.arg,Nullarg); }
  1867. X    |    SPLIT '(' sexpr csexpr csexpr ')'
  1868. X            { $$ = mod_match(O_MATCH, $4,
  1869. X              make_split(defstab,$3,$5));}
  1870. X    |    SPLIT '(' sexpr csexpr ')'
  1871. X            { $$ = mod_match(O_MATCH, $4,
  1872. X              make_split(defstab,$3,Nullarg) ); }
  1873. X    |    SPLIT '(' sexpr ')'
  1874. X            { $$ = mod_match(O_MATCH,
  1875. X                stab2arg(A_STAB,defstab),
  1876. X                make_split(defstab,$3,Nullarg) ); }
  1877. X    |    FLIST2 '(' sexpr cexpr ')'
  1878. X            { $$ = make_op($1, 2,
  1879. X                $3,
  1880. X                listish(make_list($4)),
  1881. X                Nullarg); }
  1882. X    |    FLIST '(' expr ')'
  1883. X            { $$ = make_op($1, 1,
  1884. X                make_list($3),
  1885. X                Nullarg,
  1886. X                Nullarg); }
  1887. X    |    LVALFUN sexpr    %prec '('
  1888. X            { $$ = l(make_op($1, 1, fixl($1,$2),
  1889. X                Nullarg, Nullarg)); }
  1890. X    |    LVALFUN
  1891. X            { $$ = l(make_op($1, 1,
  1892. X                stab2arg(A_STAB,defstab),
  1893. X                Nullarg, Nullarg)); }
  1894. X    |    FUNC0
  1895. X            { $$ = make_op($1, 0, Nullarg, Nullarg, Nullarg); }
  1896. X    |    FUNC1 '(' expr ')'
  1897. X            { $$ = make_op($1, 1, $3, Nullarg, Nullarg);
  1898. X              if ($1 == O_EVAL || $1 == O_RESET)
  1899. X                $$ = fixeval($$); }
  1900. X    |    FUNC2 '(' sexpr cexpr ')'
  1901. X            { $$ = make_op($1, 2, $3, $4, Nullarg);
  1902. X                if ($1 == O_INDEX && $$[2].arg_type == A_SINGLE)
  1903. X                fbmcompile($$[2].arg_ptr.arg_str,0); }
  1904. X    |    FUNC3 '(' sexpr csexpr cexpr ')'
  1905. X            { $$ = make_op($1, 3, $3, $4, $5); }
  1906. X    |    LFUNC4 '(' sexpr csexpr csexpr cexpr ')'
  1907. X            { arg4 = $6; $$ = make_op($1, 4, l($3), $4, $5); }
  1908. X    |    HSHFUN '(' hshword ')'
  1909. X            { $$ = make_op($1, 1,
  1910. X                $3,
  1911. X                Nullarg,
  1912. X                Nullarg); }
  1913. X    |    HSHFUN hshword
  1914. X            { $$ = make_op($1, 1,
  1915. X                $2,
  1916. X                Nullarg,
  1917. X                Nullarg); }
  1918. X    |    HSHFUN3 '(' hshword csexpr cexpr ')'
  1919. X            { $$ = make_op($1, 3, $3, $4, $5); }
  1920. X    |    listop
  1921. X    ;
  1922. X
  1923. Xlistop    :    LISTOP
  1924. X            { $$ = make_op($1,2,
  1925. X                stab2arg(A_WORD,Nullstab),
  1926. X                stab2arg(A_STAB,defstab),
  1927. X                Nullarg); }
  1928. X    |    LISTOP expr
  1929. X            { $$ = make_op($1,2,
  1930. X                stab2arg(A_WORD,Nullstab),
  1931. X                maybelistish($1,make_list($2)),
  1932. X                Nullarg); }
  1933. X    |    LISTOP WORD
  1934. X            { $$ = make_op($1,2,
  1935. X                stab2arg(A_WORD,stabent($2,TRUE)),
  1936. X                stab2arg(A_STAB,defstab),
  1937. X                Nullarg); }
  1938. X    |    LISTOP WORD expr
  1939. X            { $$ = make_op($1,2,
  1940. X                stab2arg(A_WORD,stabent($2,TRUE)),
  1941. X                maybelistish($1,make_list($3)),
  1942. X                Nullarg); Safefree($2); }
  1943. X    |    LISTOP REG expr
  1944. X            { $$ = make_op($1,2,
  1945. X                stab2arg(A_STAB,$2),
  1946. X                maybelistish($1,make_list($3)),
  1947. X                Nullarg); }
  1948. X    ;
  1949. X
  1950. Xhandle    :    WORD
  1951. X            { $$ = stab2arg(A_WORD,stabent($1,TRUE)); Safefree($1);}
  1952. X    |    sexpr
  1953. X    ;
  1954. X
  1955. Xaryword    :    WORD
  1956. X            { $$ = stab2arg(A_WORD,aadd(stabent($1,TRUE)));
  1957. X                Safefree($1); }
  1958. X    |    ARY
  1959. X            { $$ = stab2arg(A_STAB,$1); }
  1960. X    ;
  1961. X
  1962. Xhshword    :    WORD
  1963. X            { $$ = stab2arg(A_WORD,hadd(stabent($1,TRUE)));
  1964. X                Safefree($1); }
  1965. X    |    HSH
  1966. X            { $$ = stab2arg(A_STAB,$1); }
  1967. X    ;
  1968. X
  1969. X%% /* PROGRAM */
  1970. !STUFFY!FUNK!
  1971. echo Extracting t/cmd.switch
  1972. sed >t/cmd.switch <<'!STUFFY!FUNK!' -e 's/X//'
  1973. X#!./perl
  1974. X
  1975. X# $Header: cmd.switch,v 3.0 89/10/18 15:25:00 lwall Locked $
  1976. X
  1977. Xprint "1..18\n";
  1978. X
  1979. Xsub foo1 {
  1980. X    $_ = shift(@_);
  1981. X    $a = 0;
  1982. X    until ($a++) {
  1983. X    next if $_ eq 1;
  1984. X    next if $_ eq 2;
  1985. X    next if $_ eq 3;
  1986. X    next if $_ eq 4;
  1987. X    return 20;
  1988. X    }
  1989. X    continue {
  1990. X    return $_;
  1991. X    }
  1992. X}
  1993. X
  1994. Xprint do foo1(0) == 20 ? "ok 1\n" : "not ok 1\n";
  1995. Xprint do foo1(1) == 1 ? "ok 2\n" : "not ok 2\n";
  1996. Xprint do foo1(2) == 2 ? "ok 3\n" : "not ok 3\n";
  1997. Xprint do foo1(3) == 3 ? "ok 4\n" : "not ok 4\n";
  1998. Xprint do foo1(4) == 4 ? "ok 5\n" : "not ok 5\n";
  1999. Xprint do foo1(5) == 20 ? "ok 6\n" : "not ok 6\n";
  2000. X
  2001. Xsub foo2 {
  2002. X    $_ = shift(@_);
  2003. X    {
  2004. X    last if $_ == 1;
  2005. X    last if $_ == 2;
  2006. X    last if $_ == 3;
  2007. X    last if $_ == 4;
  2008. X    }
  2009. X    continue {
  2010. X    return 20;
  2011. X    }
  2012. X    return $_;
  2013. X}
  2014. X
  2015. Xprint do foo2(0) == 20 ? "ok 7\n" : "not ok 1\n";
  2016. Xprint do foo2(1) == 1 ? "ok 8\n" : "not ok 8\n";
  2017. Xprint do foo2(2) == 2 ? "ok 9\n" : "not ok 9\n";
  2018. Xprint do foo2(3) == 3 ? "ok 10\n" : "not ok 10\n";
  2019. Xprint do foo2(4) == 4 ? "ok 11\n" : "not ok 11\n";
  2020. Xprint do foo2(5) == 20 ? "ok 12\n" : "not ok 12\n";
  2021. X
  2022. Xsub foo3 {
  2023. X    $_ = shift(@_);
  2024. X    if (/^1/) {
  2025. X    return 1;
  2026. X    }
  2027. X    elsif (/^2/) {
  2028. X    return 2;
  2029. X    }
  2030. X    elsif (/^3/) {
  2031. X    return 3;
  2032. X    }
  2033. X    elsif (/^4/) {
  2034. X    return 4;
  2035. X    }
  2036. X    else {
  2037. X    return 20;
  2038. X    }
  2039. X    return 40;
  2040. X}
  2041. X
  2042. Xprint do foo3(0) == 20 ? "ok 13\n" : "not ok 13\n";
  2043. Xprint do foo3(1) == 1 ? "ok 14\n" : "not ok 14\n";
  2044. Xprint do foo3(2) == 2 ? "ok 15\n" : "not ok 15\n";
  2045. Xprint do foo3(3) == 3 ? "ok 16\n" : "not ok 16\n";
  2046. Xprint do foo3(4) == 4 ? "ok 17\n" : "not ok 17\n";
  2047. Xprint do foo3(5) == 20 ? "ok 18\n" : "not ok 18\n";
  2048. !STUFFY!FUNK!
  2049. echo ""
  2050. echo "End of kit 12 (of 24)"
  2051. cat /dev/null >kit12isdone
  2052. run=''
  2053. config=''
  2054. for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24; do
  2055.     if test -f kit${iskit}isdone; then
  2056.     run="$run $iskit"
  2057.     else
  2058.     todo="$todo $iskit"
  2059.     fi
  2060. done
  2061. case $todo in
  2062.     '')
  2063.     echo "You have run all your kits.  Please read README and then type Configure."
  2064.     chmod 755 Configure
  2065.     ;;
  2066.     *)  echo "You have run$run."
  2067.     echo "You still need to run$todo."
  2068.     ;;
  2069. esac
  2070. : Someone might mail this, so...
  2071. exit
  2072.  
  2073. -- 
  2074. Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
  2075. Use a domain-based address or give alternate paths, or you may lose out.
  2076.