home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / UNIX / ARCHIE / CLIENTS / XARCHIE1.TAR / regex.c < prev    next >
Encoding:
Text File  |  1991-09-12  |  16.9 KB  |  717 lines

  1. /*
  2.  * These routines are from "a pre-release of a bunch of berkelix
  3.  * regex(3)/ed(1) compatible regular-expression routines" written by Ozan
  4.  * S. Yigit, Dept. of Computer Science, York University.  Parts of the
  5.  * code that are not needed by Prospero have been removed, but most of
  6.  * the accompanying information has been left intact.  This file is to be
  7.  * included on those operating systems that do not support re_comp and
  8.  * re_exec.
  9.  *
  10.  * gf: 12 Sep 1991: Modified so routines aren't static, so we can link with
  11.  *                  them instead of including the C code.
  12.  */
  13.  
  14. /*
  15.  
  16. These routines are completely public domain. You can do whatever you
  17. like with them, and hopefully you are professional enough not to strip
  18. out the authorship information, acknowledgements and references.
  19.  
  20. The reason for this being a *pre-release* is that I received a lot
  21. of useful suggestions about packaging, about additional routines etc.
  22. from a few people. I do not have too much time to do those changes
  23. right now, so I am putting this package out for those who needed
  24. it yesterday. Next release will include other routines, and better
  25. packaging.
  26.  
  27. These routines are *not* tested under SysV, but they are tested
  28. under PRO/Venix (2.0) and BSD 4.2.
  29.  
  30. In general, these routines run just as fast, or faster than regex library
  31. routines under BSD 4.2. In some cases, they are slightly slower. I did not
  32. try too hard to optimize the re_exec routine.
  33.  
  34. Coding style is a la K&R, with lotsa short identifiers. I like it
  35. that way. All flames should be fed to yetti!dragon.
  36.  
  37. Acknowledgements: Henry Spencer, Hugh Redelmeier and Drew Sullivan made
  38.           a lot of important suggestions, some of which will be
  39.           incorporated into the next version.
  40.  
  41.  */
  42.  
  43. /*
  44.  * regex - Regular expression pattern matching
  45.  *         and replacement
  46.  *
  47.  *
  48.  * By:  Ozan S. Yigit (oz)
  49.  *      Dept. of Computer Science
  50.  *      York University
  51.  *         [...!utzoo!yetti!oz || oz@yusol.BITNET || oz@yuyetti.BITNET]
  52.  *
  53.  * These routines are the PUBLIC DOMAIN equivalents 
  54.  * of regex routines as found in 4.nBSD UN*X, with minor
  55.  * extensions.
  56.  *
  57.  * These routines are derived from various implementations
  58.  * found in software tools books, and Conroy's grep. They
  59.  * are NOT derived from licensed/restricted software.
  60.  * For more interesting/academic/complicated implementations,
  61.  * see Henry Spencer's regexp routines, or GNU Emacs pattern
  62.  * matching module.
  63.  *
  64.  * Routines:
  65.  *      re_comp:        compile a regular expression into
  66.  *                      a DFA.
  67.  *
  68.  *            char *re_comp(s)
  69.  *            char *s;
  70.  *
  71.  *      re_exec:        execute the DFA to match a pattern.
  72.  *
  73.  *            int re_exec(s)
  74.  *            char *s;
  75.  *
  76.  * Regular Expressions:
  77.  *
  78.  *      [1]     char    matches itself, unless it is a special
  79.  *                      character (metachar): . \ [ ] * + ^ $
  80.  *
  81.  *      [2]     .       matches any character.
  82.  *
  83.  *      [3]     \       matches the character following it, except
  84.  *            when followed by a left or right round bracket,
  85.  *            a digit 1 to 9 or a left or right angle bracket. 
  86.  *            (see [7], [8] and [9])
  87.  *            It is used as an escape character for all 
  88.  *            other meta-characters, and itself. When used
  89.  *            in a set ([4]), it is treated as an ordinary
  90.  *            character.
  91.  *
  92.  *      [4]     [set]   matches one of the characters in the set.
  93.  *                      If the first character in the set is "^",
  94.  *                      it matches a character NOT in the set. A
  95.  *                      shorthand S-E is used to specify a set of
  96.  *                      characters S upto E, inclusive. The special
  97.  *                      characters "]" and "-" have no special
  98.  *                      meaning if they appear as the first chars
  99.  *                      in the set.
  100.  *                      examples:        match:
  101.  *
  102.  *                              [a-z]    any lowercase alpha
  103.  *
  104.  *                              [^]-]    any char except ] and -
  105.  *
  106.  *                              [^A-Z]   any char except uppercase
  107.  *                                       alpha
  108.  *
  109.  *                              [a-zA-Z] any alpha
  110.  *
  111.  *      [5]     *       any regular expression form [1] to [4], followed by
  112.  *                      closure char (*) matches zero or more matches of
  113.  *                      that form.
  114.  *
  115.  *      [6]     +       same as [5], except it matches one or more.
  116.  *
  117.  *      [7]             a regular expression in the form [1] to [10], enclosed
  118.  *                      as \(form\) matches what form matches. The enclosure
  119.  *                      creates a set of tags, used for [8] and for
  120.  *                      pattern substution. The tagged forms are numbered
  121.  *            starting from 1.
  122.  *
  123.  *      [8]             a \ followed by a digit 1 to 9 matches whatever a
  124.  *                      previously tagged regular expression ([7]) matched.
  125.  *
  126.  *    [9]    \<    a regular expression starting with a \< construct
  127.  *        \>    and/or ending with a \> construct, restricts the
  128.  *            pattern matching to the beginning of a word, and/or
  129.  *            the end of a word. A word is defined to be a character
  130.  *            string beginning and/or ending with the characters
  131.  *            A-Z a-z 0-9 and _. It must also be preceded and/or
  132.  *            followed by any character outside those mentioned.
  133.  *
  134.  *      [10]            a composite regular expression xy where x and y
  135.  *                      are in the form [1] to [10] matches the longest
  136.  *                      match of x followed by a match for y.
  137.  *
  138.  *      [11]    ^    a regular expression starting with a ^ character
  139.  *        $    and/or ending with a $ character, restricts the
  140.  *                      pattern matching to the beginning of the line,
  141.  *                      or the end of line. [anchors] Elsewhere in the
  142.  *            pattern, ^ and $ are treated as ordinary characters.
  143.  *
  144.  *
  145.  * Acknowledgements:
  146.  *
  147.  *    HCR's Hugh Redelmeier has been most helpful in various
  148.  *    stages of development. He convinced me to include BOW
  149.  *    and EOW constructs, originally invented by Rob Pike at
  150.  *    the University of Toronto.
  151.  *
  152.  * References:
  153.  *              Software tools            Kernighan & Plauger
  154.  *              Software tools in Pascal        Kernighan & Plauger
  155.  *              Grep [rsx-11 C dist]            David Conroy
  156.  *        ed - text editor        Un*x Programmer's Manual
  157.  *        Advanced editing on Un*x    B. W. Kernighan
  158.  *        RegExp routines            Henry Spencer
  159.  *
  160.  * Notes:
  161.  *
  162.  *    This implementation uses a bit-set representation for character
  163.  *    classes for speed and compactness. Each character is represented 
  164.  *    by one bit in a 128-bit block. Thus, CCL or NCL always takes a 
  165.  *    constant 16 bytes in the internal dfa, and re_exec does a single
  166.  *    bit comparison to locate the character in the set.
  167.  *
  168.  * Examples:
  169.  *
  170.  *    pattern:    foo*.*
  171.  *    compile:    CHR f CHR o CLO CHR o END CLO ANY END END
  172.  *    matches:    fo foo fooo foobar fobar foxx ...
  173.  *
  174.  *    pattern:    fo[ob]a[rz]    
  175.  *    compile:    CHR f CHR o CCL 2 o b CHR a CCL bitset END
  176.  *    matches:    fobar fooar fobaz fooaz
  177.  *
  178.  *    pattern:    foo\\+
  179.  *    compile:    CHR f CHR o CHR o CHR \ CLO CHR \ END END
  180.  *    matches:    foo\ foo\\ foo\\\  ...
  181.  *
  182.  *    pattern:    \(foo\)[1-3]\1    (same as foo[1-3]foo)
  183.  *    compile:    BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END
  184.  *    matches:    foo1foo foo2foo foo3foo
  185.  *
  186.  *    pattern:    \(fo.*\)-\1
  187.  *    compile:    BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END
  188.  *    matches:    foo-foo fo-fo fob-fob foobar-foobar ...
  189.  * 
  190.  */
  191.  
  192. #define MAXDFA  1024
  193. #define MAXTAG  10
  194.  
  195. #define OKP     1
  196. #define NOP     0
  197.  
  198. #define CHR     1
  199. #define ANY     2
  200. #define CCL     3
  201. #define NCL     4
  202. #define BOL     5
  203. #define EOL     6
  204. #define BOT     7
  205. #define EOT     8
  206. #define BOW    9
  207. #define EOW    10
  208. #define REF     11
  209. #define CLO     12
  210.  
  211. #define END     0
  212.  
  213. /*
  214.  * The following defines are not meant
  215.  * to be changeable. They are for readibility
  216.  * only.
  217.  *
  218.  */
  219. #define MAXCHR    128
  220. #define CHRBIT    8
  221. #define BITBLK    MAXCHR/CHRBIT
  222. #define BLKIND    0170
  223. #define BITIND    07
  224.  
  225. #define ASCIIB    0177
  226.  
  227. typedef /*unsigned*/ char CHAR;
  228.  
  229. static int  tagstk[MAXTAG];             /* subpat tag stack..*/
  230. static CHAR dfa[MAXDFA];        /* automaton..       */
  231. static int  sta = NOP;                   /* status of lastpat */
  232.  
  233. static CHAR bittab[BITBLK];        /* bit table for CCL */
  234.  
  235. static int  internal_error;
  236.  
  237. static void
  238. chset(c) register CHAR c; { bittab[((c)&BLKIND)>>3] |= 1<<((c)&BITIND); }
  239.  
  240. #define badpat(x)    return(*dfa = END, x)
  241. #define store(x)    *mp++ = x
  242.  
  243. char *     
  244. re_comp(pat)
  245. char *pat;
  246. {
  247.     register char *p;               /* pattern pointer   */
  248.     register CHAR *mp=dfa;          /* dfa pointer       */
  249.     register CHAR *lp;              /* saved pointer..   */
  250.     register CHAR *sp=dfa;          /* another one..     */
  251.  
  252.     register int tagi = 0;          /* tag stack index   */
  253.     register int tagc = 1;          /* actual tag count  */
  254.  
  255.     register int n;
  256.     int c1, c2;
  257.         
  258.     internal_error = 0;
  259.  
  260.     if (!pat || !*pat)
  261.         if (sta)
  262.             return(0);
  263.         else
  264.             badpat("No previous regular expression");
  265.     sta = NOP;
  266.  
  267.     for (p = pat; *p; p++) {
  268.         lp = mp;
  269.         switch(*p) {
  270.  
  271.         case '.':               /* match any char..  */
  272.             store(ANY);
  273.             break;
  274.  
  275.         case '^':               /* match beginning.. */
  276.             if (p == pat)
  277.                 store(BOL);
  278.             else {
  279.                 store(CHR);
  280.                 store(*p);
  281.             }
  282.             break;
  283.  
  284.         case '$':               /* match endofline.. */
  285.             if (!*(p+1))
  286.                 store(EOL);
  287.             else {
  288.                 store(CHR);
  289.                 store(*p);
  290.             }
  291.             break;
  292.  
  293.         case '[':               /* match char class..*/
  294.  
  295.             if (*++p == '^') {
  296.                 store(NCL);
  297.                 p++;
  298.             }
  299.             else
  300.                 store(CCL);
  301.  
  302.             if (*p == '-')        /* real dash */
  303.                 chset(*p++);
  304.             if (*p == ']')        /* real brac */
  305.                 chset(*p++);
  306.             while (*p && *p != ']') {
  307.                 if (*p == '-' && *(p+1) && *(p+1) != ']') {
  308.                     p++;
  309.                     c1 = *(p-2) + 1;
  310.                     c2 = *p++;
  311.                     while (c1 <= c2)
  312.                         chset(c1++);
  313.                 }
  314. #ifdef EXTEND
  315.                 else if (*p == '\\' && *(p+1)) {
  316.                     p++;
  317.                     chset(*p++);
  318.                 }
  319. #endif
  320.                 else
  321.                     chset(*p++);
  322.             }
  323.             if (!*p)
  324.                 badpat("Missing ]");
  325.  
  326.             for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
  327.                 store(bittab[n]);
  328.     
  329.             break;
  330.  
  331.         case '*':               /* match 0 or more.. */
  332.         case '+':               /* match 1 or more.. */
  333.             if (p == pat)
  334.                 badpat("Empty closure");
  335.             lp = sp;                /* previous opcode */
  336.             if (*lp == CLO)         /* equivalence..   */
  337.                 break;
  338.             switch(*lp) {
  339.  
  340.             case BOL:
  341.             case BOT:
  342.             case EOT:
  343.             case BOW:
  344.             case EOW:
  345.             case REF:
  346.                 badpat("Illegal closure");
  347.             default:
  348.                 break;
  349.             }
  350.  
  351.             if (*p == '+')
  352.                 for (sp = mp; lp < sp; lp++)
  353.                     store(*lp);
  354.  
  355.             store(END);
  356.             store(END);
  357.             sp = mp;
  358.             while (--mp > lp)
  359.                 *mp = mp[-1];
  360.             store(CLO);
  361.             mp = sp;
  362.             break;
  363.  
  364.         case '\\':              /* tags, backrefs .. */
  365.             switch(*++p) {
  366.  
  367.             case '(':
  368.                 if (tagc < MAXTAG) {
  369.                     tagstk[++tagi] = tagc;
  370.                     store(BOT);
  371.                     store(tagc++);
  372.                 }
  373.                 else
  374.                     badpat("Too many \\(\\) pairs");
  375.                 break;
  376.             case ')':
  377.                 if (*sp == BOT)
  378.                     badpat("Null pattern inside \\(\\)");
  379.                 if (tagi > 0) {
  380.                     store(EOT);
  381.                     store(tagstk[tagi--]);
  382.                 }
  383.                 else
  384.                     badpat("Unmatched \\)");
  385.                 break;
  386.             case '<':
  387.                 store(BOW);
  388.                 break;
  389.             case '>':
  390.                 if (*sp == BOW)
  391.                     badpat("Null pattern inside \\<\\>");
  392.                 store(EOW);
  393.                 break;
  394.             case '1':
  395.             case '2':
  396.             case '3':
  397.             case '4':
  398.             case '5':
  399.             case '6':
  400.             case '7':
  401.             case '8':
  402.             case '9':
  403.                 n = *p-'0';
  404.                 if (tagi > 0 && tagstk[tagi] == n)
  405.                     badpat("Cyclical reference");
  406.                 if (tagc > n) {
  407.                     store(REF);
  408.                     store(n);
  409.                 }
  410.                 else
  411.                     badpat("Undetermined reference");
  412.                 break;
  413. #ifdef EXTEND
  414.             case 'b':
  415.                 store(CHR);
  416.                 store('\b');
  417.                 break;
  418.             case 'n':
  419.                 store(CHR);
  420.                 store('\n');
  421.                 break;
  422.             case 'f':
  423.                 store(CHR);
  424.                 store('\f');
  425.                 break;
  426.             case 'r':
  427.                 store(CHR);
  428.                 store('\r');
  429.                 break;
  430.             case 't':
  431.                 store(CHR);
  432.                 store('\t');
  433.                 break;
  434. #endif
  435.             default:
  436.                 store(CHR);
  437.                 store(*p);
  438.             }
  439.             break;
  440.  
  441.         default :               /* an ordinary char  */
  442.             store(CHR);
  443.             store(*p);
  444.             break;
  445.         }
  446.         sp = lp;
  447.     }
  448.     if (tagi > 0)
  449.         badpat("Unmatched \\(");
  450.     store(END);
  451.     sta = OKP;
  452.     return(0);
  453. }
  454.  
  455.  
  456. static char *bol;
  457. static char *bopat[MAXTAG];
  458. static char *eopat[MAXTAG];
  459.  
  460. char *pmatch();
  461.  
  462. /*
  463.  * re_exec:
  464.  *     execute dfa to find a match.
  465.  *
  466.  *    special cases: (dfa[0])    
  467.  *        BOL
  468.  *            Match only once, starting from the
  469.  *            beginning.
  470.  *        CHR
  471.  *            First locate the character without
  472.  *            calling pmatch, and if found, call
  473.  *            pmatch for the remaining string.
  474.  *        END
  475.  *            re_comp failed, poor luser did not
  476.  *            check for it. Fail fast.
  477.  *
  478.  *    If a match is found, bopat[0] and eopat[0] are set
  479.  *    to the beginning and the end of the matched fragment,
  480.  *    respectively.
  481.  *
  482.  */
  483.  
  484. int
  485. re_exec(lp)
  486. register char *lp;
  487. {
  488.     register char c;
  489.     register char *ep = 0;
  490.     register CHAR *ap = dfa;
  491.  
  492.     bol = lp;
  493.  
  494.     bopat[0] = 0;
  495.     bopat[1] = 0;
  496.     bopat[2] = 0;
  497.     bopat[3] = 0;
  498.     bopat[4] = 0;
  499.     bopat[5] = 0;
  500.     bopat[6] = 0;
  501.     bopat[7] = 0;
  502.     bopat[8] = 0;
  503.     bopat[9] = 0;
  504.  
  505.     switch(*ap) {
  506.  
  507.     case BOL:            /* anchored: match from BOL only */
  508.         ep = pmatch(lp,ap);
  509.         break;
  510.     case CHR:            /* ordinary char: locate it fast */
  511.         c = *(ap+1);
  512.         while (*lp && *lp != c)
  513.             lp++;
  514.         if (!*lp)        /* if EOS, fail, else fall thru. */
  515.             return(0);
  516.     default:            /* regular matching all the way. */
  517.         while (*lp) {
  518.             if ((ep = pmatch(lp,ap)))
  519.                 break;
  520.             lp++;
  521.         }
  522.         break;
  523.     case END:            /* munged automaton. fail always */
  524.         return(0);
  525.     }
  526.     if (!ep)
  527.         return(0);
  528.  
  529.     if (internal_error) 
  530.         return(-1);
  531.  
  532.     bopat[0] = lp;
  533.     eopat[0] = ep;
  534.     return(1);
  535. }
  536.  
  537. /* 
  538.  * pmatch: 
  539.  *    internal routine for the hard part
  540.  *
  541.  *     This code is mostly snarfed from an early
  542.  *     grep written by David Conroy. The backref and
  543.  *     tag stuff, and various other mods are by oZ.
  544.  *
  545.  *    special cases: (dfa[n], dfa[n+1])
  546.  *        CLO ANY
  547.  *            We KNOW ".*" will match ANYTHING
  548.  *            upto the end of line. Thus, go to
  549.  *            the end of line straight, without
  550.  *            calling pmatch recursively. As in
  551.  *            the other closure cases, the remaining
  552.  *            pattern must be matched by moving
  553.  *            backwards on the string recursively,
  554.  *            to find a match for xy (x is ".*" and 
  555.  *            y is the remaining pattern) where
  556.  *            the match satisfies the LONGEST match
  557.  *            for x followed by a match for y.
  558.  *        CLO CHR
  559.  *            We can again scan the string forward
  560.  *            for the single char without recursion, 
  561.  *            and at the point of failure, we execute 
  562.  *            the remaining dfa recursively, as
  563.  *            described above.
  564.  *
  565.  *    At the end of a successful match, bopat[n] and eopat[n]
  566.  *    are set to the beginning and end of subpatterns matched
  567.  *    by tagged expressions (n = 1 to 9).    
  568.  *
  569.  */
  570.  
  571.  
  572. /*
  573.  * character classification table for word boundary
  574.  * operators BOW and EOW. the reason for not using 
  575.  * ctype macros is that we can let the user add into 
  576.  * our own table. see re_modw. This table is not in
  577.  * the bitset form, since we may wish to extend it
  578.  * in the future for other character classifications. 
  579.  *
  580.  *    TRUE for 0-9 A-Z a-z _
  581.  */
  582. static char chrtyp[MAXCHR] = {
  583.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  584.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  585.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  586.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  587.     0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
  588.     1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
  589.     0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 
  590.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  591.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  592.     1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 
  593.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  594.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  595.     1, 1, 1, 0, 0, 0, 0, 0
  596.     };
  597.  
  598. #define inascii(x)    (0177&(x))
  599. #define iswordc(x)     chrtyp[inascii(x)]
  600. #define isinset(x,y)     ((x)[((y)&BLKIND)>>3] & (1<<((y)&BITIND)))
  601.  
  602. /*
  603.  * skip values for CLO XXX to skip past the closure
  604.  *
  605.  */
  606.  
  607. #define ANYSKIP    2     /* CLO ANY END ...       */
  608. #define CHRSKIP    3    /* CLO CHR chr END ...       */
  609. #define CCLSKIP 18    /* CLO CCL 16bytes END ... */
  610.  
  611. static char *
  612. pmatch(lp, ap)
  613. register char *lp;
  614. register CHAR *ap;
  615. {
  616.     register char *e;        /* extra pointer for CLO */
  617.     register char *bp;        /* beginning of subpat.. */
  618.     register char *ep;        /* ending of subpat..     */
  619.     register int op, c, n;
  620.     char *are;            /* to save the line ptr. */
  621.  
  622.     while ((op = *ap++) != END)
  623.         switch(op) {
  624.  
  625.         case CHR:
  626.             if (*lp++ != *ap++)
  627.                 return(0);
  628.             break;
  629.         case ANY:
  630.             if (!*lp++)
  631.                 return(0);
  632.             break;
  633.         case CCL:
  634.             c = *lp++;
  635.             if (!isinset(ap,c))
  636.                 return(0);
  637.             ap += BITBLK;
  638.             break;
  639.         case NCL:
  640.             c = *lp++;
  641.             if (isinset(ap,c))
  642.                 return(0);
  643.             ap += BITBLK;
  644.             break;
  645.         case BOL:
  646.             if (lp != bol)
  647.                 return(0);
  648.             break;
  649.         case EOL:
  650.             if (*lp)
  651.                 return(0);
  652.             break;
  653.         case BOT:
  654.             bopat[*ap++] = lp;
  655.             break;
  656.         case EOT:
  657.             eopat[*ap++] = lp;
  658.             break;
  659.          case BOW:
  660.             if (!(lp!=bol && iswordc(lp[-1])) && iswordc(*lp))
  661.                 break;
  662.             return(0);
  663.         case EOW:
  664.             if ((lp!=bol && iswordc(lp[-1])) && !iswordc(*lp))
  665.                 break;
  666.             return(0);
  667.         case REF:
  668.             n = *ap++;
  669.             bp = bopat[n];
  670.             ep = eopat[n];
  671.             while (bp < ep)
  672.                 if (*bp++ != *lp++)
  673.                     return(0);
  674.             break;
  675.         case CLO:
  676.             are = lp;
  677.             switch(*ap) {
  678.  
  679.             case ANY:
  680.                 while (*lp)
  681.                     lp++;
  682.                 n = ANYSKIP;
  683.                 break;
  684.             case CHR:
  685.                 c = *(ap+1);
  686.                 while (*lp && c == *lp)
  687.                     lp++;
  688.                 n = CHRSKIP;
  689.                 break;
  690.             case CCL:
  691.             case NCL:
  692.                 while (*lp && (e = pmatch(lp, ap)))
  693.                     lp = e;
  694.                 n = CCLSKIP;
  695.                 break;
  696.             default:
  697.                 internal_error++;
  698.                 return(0);
  699.             }
  700.  
  701.             ap += n;
  702.  
  703.             while (lp >= are) {
  704.                 if (e = pmatch(lp, ap))
  705.                     return(e);
  706.                 --lp;
  707.             }
  708.             return(0);
  709.         default:
  710.             internal_error++;
  711.             return(0);
  712.         }
  713.     return(lp);
  714. }
  715.  
  716.  
  717.