========== find program from chapter 5 ========== define(MAXARG,128) define(MAXPAT,128) define(COUNT,1) define(PREVCL,2) define(START,3) define(CLOSIZE,4) define(NOT,BANG) define(BOL,PERCENT) define(ANY,QMARK) define(EOL,DOLLAR) define(CLOSURE,STAR) define(CCL,LBRACK) define(CCLEND,RBRACK) define(NCCL,LETN) define(CHAR,LETA) define(ESCAPE,ATSIGN) # amatch (non-recursive) - look for match starting at lin(from) integer function amatch(lin, from, pat) character lin(MAXLINE), pat(MAXPAT) integer omatch, patsiz integer from, i, j, offset, stack stack = 0 offset = from # next unexamined input character for (j = 1; pat(j) ~= EOS; j = j + patsiz(pat, j)) if (pat(j) == CLOSURE) { # a closure entry stack = j j = j + CLOSIZE # step over CLOSURE for (i = offset; lin(i) ~= EOS; ) # match as many as if (omatch(lin, i, pat, j) == NO) # possible break pat(stack+COUNT) = i - offset pat(stack+START) = offset offset = i # character that made us fail $@$ else if (omatch(lin, offset, pat, j) == NO) { # non-closure for ( ; stack > 0; stack = pat(stack+PREVCL)) if (pat(stack+COUNT) > 0) break if (stack <= 0) { # stack is empty amatch = 0 # return failure return $@$ pat(stack+COUNT) = pat(stack+COUNT) - 1 j = stack + CLOSIZE offset = pat(stack+START) + pat(stack+COUNT) $@$ # else omatch succeeded amatch = offset return # success end # amatch with no metacharacters integer function amatch(lin, from, pat) character lin(MAXLINE), pat(MAXPAT) integer from, i, j i = from for (j = 1; pat(j) ~= EOS; j = j + 1) { if (lin(i) ~= pat(j)) { amatch = 0 return # with no match $@$ i = i + 1 $@$ amatch = i return # successfully end # amatch with some metacharacters integer function amatch(lin, from, pat) character lin(MAXLINE), pat(MAXPAT) integer omatch, patsiz integer from, i, j i = from for (j = 1; pat(j) ~= EOS; j = j + patsiz(pat, j)) if (omatch(lin, i, pat, j) == NO) { amatch = 0 return # with no match $@$ amatch = i return # successfully end # find - find patterns in text character arg(MAXARG), lin(MAXLINE), pat(MAXPAT) integer getarg, getlin, getpat, match if (getarg(1, arg, MAXARG) == EOF) call error("usage: find pattern.") if (getpat(arg, pat) == ERR) call error("illegal pattern.") while (getlin(lin, STDIN) ~= EOF) if (match(lin, pat) == YES) call putlin(lin, STDOUT) stop end # getccl - expand char class at arg(i) into pat(j) integer function getccl(arg, i, pat, j) character arg(MAXARG), pat(MAXPAT) integer addset integer i, j, jstart, junk i = i + 1 # skip over [ if (arg(i) == NOT) { junk = addset(NCCL, pat, j, MAXPAT) i = i + 1 $@$ else junk = addset(CCL, pat, j, MAXPAT) jstart = j junk = addset(0, pat, j, MAXPAT) # leave room for count call filset(CCLEND, arg, i, pat, j, MAXPAT) pat(jstart) = j - jstart - 1 if (arg(i) == CCLEND) getccl = OK else getccl = ERR return end # getpat - convert argument into pattern integer function getpat(arg, pat) integer arg(MAXARG), pat(MAXPAT) integer makpat getpat = makpat(arg, 1, EOS, pat) return end # locate - look for c in char class at pat(offset) integer function locate(c, pat, offset) character c, pat(MAXPAT) integer i, offset # size of class is at pat(offset), characters follow for (i = offset + pat(offset); i > offset; i = i - 1) if (c == pat(i)) { locate = YES return $@$ locate = NO return end # makpat - make pattern from arg(from), terminate at delim integer function makpat(arg, from, delim, pat) character esc character arg(MAXARG), delim, pat(MAXPAT) integer addset, getccl, stclos integer from, i, j, junk, lastcl, lastj, lj j = 1 # pat index lastj = 1 lastcl = 0 for (i = from; arg(i) ~= delim & arg(i) ~= EOS; i = i + 1) { lj = j if (arg(i) == ANY) junk = addset(ANY, pat, j, MAXPAT) else if (arg(i) == BOL & i == from) junk = addset(BOL, pat, j, MAXPAT) else if (arg(i) == EOL & arg(i + 1) == delim) junk = addset(EOL, pat, j, MAXPAT) else if (arg(i) == CCL) { if (getccl(arg, i, pat, j) == ERR) break $@$ else if (arg(i) == CLOSURE & i > from) { lj = lastj if (pat(lj)==BOL | pat(lj)==EOL | pat(lj)==CLOSURE) break lastcl = stclos(pat, j, lastj, lastcl) $@$ else { junk = addset(CHAR, pat, j, MAXPAT) junk = addset(esc(arg, i), pat, j, MAXPAT) $@$ lastj = lj $@$ if (arg(i) ~= delim) # terminated early makpat = ERR else if (addset(EOS, pat, j, MAXPAT) == NO) # no room makpat = ERR else makpat = i return end # match - find match anywhere on line integer function match(lin, pat) character lin(MAXLINE), pat(MAXPAT) integer amatch integer i for (i = 1; lin(i) ~= EOS; i = i + 1) if (amatch(lin, i, pat) > 0) { match = YES return $@$ match = NO return end # omatch - try to match a single pattern at pat(j) integer function omatch(lin, i, pat, j) character lin(MAXLINE), pat(MAXPAT) integer locate integer bump, i, j omatch = NO if (lin(i) == EOS) return bump = -1 if (pat(j) == CHAR) { if (lin(i) == pat(j + 1)) bump = 1 $@$ else if (pat(j) == BOL) { if (i == 1) bump = 0 $@$ else if (pat(j) == ANY) { if (lin(i) ~= NEWLINE) bump = 1 $@$ else if (pat(j) == EOL) { if (lin(i) == NEWLINE) bump = 0 $@$ else if (pat(j) == CCL) { if (locate(lin(i), pat, j + 1) == YES) bump = 1 $@$ else if (pat(j) == NCCL) { if (lin(i) ~= NEWLINE & locate(lin(i), pat, j + 1) == NO) bump = 1 $@$ else call error("in omatch: can't happen.") if (bump >= 0) { i = i + bump omatch = YES $@$ return end # patsiz - returns size of pattern entry at pat(n) integer function patsiz(pat, n) character pat(MAXPAT) integer n if (pat(n) == CHAR) patsiz = 2 else if (pat(n) == BOL | pat(n) == EOL | pat(n) == ANY) patsiz = 1 else if (pat(n) == CCL | pat(n) == NCCL) patsiz = pat(n + 1) + 2 else if (pat(n) == CLOSURE) # optional patsiz = CLOSIZE else call error("in patsiz: can't happen.") return end # stclos - insert closure entry at pat(j) integer function stclos(pat, j, lastj, lastcl) character pat(MAXPAT) integer addset integer j, jp, jt, junk, lastcl, lastj for (jp = j - 1; jp >= lastj; jp = jp - 1) { # make a hole jt = jp + CLOSIZE junk = addset(pat(jp), pat, jt, MAXPAT) $@$ j = j + CLOSIZE stclos = lastj junk = addset(CLOSURE, pat, lastj, MAXPAT) # put closure in it junk = addset(0, pat, lastj, MAXPAT) # COUNT junk = addset(lastcl, pat, lastj, MAXPAT) # PREVCL junk = addset(0, pat, lastj, MAXPAT) # START return end