initial import

This commit is contained in:
garbeam@wmii.de
2005-11-20 18:27:27 +02:00
commit e5f0f74b8a
323 changed files with 41871 additions and 0 deletions

46
grep/Makefile Normal file
View File

@@ -0,0 +1,46 @@
# grep - grep unix port from plan9
# Depends on ../lib9
include ../config.mk
TARG = grep
OFILES = y.tab.o main.o comp.o sub.o
YFILES = grep.y
MANFILES = grep.1
all:
@if [ ! -f y.tab.c ]; then \
${MAKE} -f Makefile depend;\
fi
@${MAKE} -f Makefile ${TARG}
@echo built ${TARG}
depend:
@echo YACC ${YFILES}
@${YACC} -d ${YFILES}
install: ${TARG}
@mkdir -p ${DESTDIR}${PREFIX}/bin
@cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
@chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
@cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
@chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
.c.o:
@echo CC $*.c
@${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
clean:
rm -f ${OFILES} ${TARG} y.tab.c y.tab.h
${TARG}: ${OFILES}
@echo LD ${TARG}
@${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9

277
grep/comp.c Normal file
View File

@@ -0,0 +1,277 @@
#include "grep.h"
/*
* incremental compiler.
* add the branch c to the
* state s.
*/
void
increment(State *s, int c)
{
int i;
State *t, **tt;
Re *re1, *re2;
nfollow = 0;
gen++;
matched = 0;
for(i=0; i<s->count; i++)
fol1(s->re[i], c);
qsort(follow, nfollow, sizeof(*follow), fcmp);
for(tt=&state0; t = *tt;) {
if(t->count > nfollow) {
tt = &t->linkleft;
goto cont;
}
if(t->count < nfollow) {
tt = &t->linkright;
goto cont;
}
for(i=0; i<nfollow; i++) {
re1 = t->re[i];
re2 = follow[i];
if(re1 > re2) {
tt = &t->linkleft;
goto cont;
}
if(re1 < re2) {
tt = &t->linkright;
goto cont;
}
}
if(!!matched && !t->match) {
tt = &t->linkleft;
goto cont;
}
if(!matched && !!t->match) {
tt = &t->linkright;
goto cont;
}
s->next[c] = t;
return;
cont:;
}
t = sal(nfollow);
*tt = t;
for(i=0; i<nfollow; i++) {
re1 = follow[i];
t->re[i] = re1;
}
s->next[c] = t;
t->match = matched;
}
int
fcmp(const void *va, const void *vb)
{
Re **aa, **bb;
Re *a, *b;
aa = (Re**)va;
bb = (Re**)vb;
a = *aa;
b = *bb;
if(a > b)
return 1;
if(a < b)
return -1;
return 0;
}
void
fol1(Re *r, int c)
{
Re *r1;
loop:
if(r->gen == gen)
return;
if(nfollow >= maxfollow)
error("nfollow");
r->gen = gen;
switch(r->type) {
default:
error("fol1");
case Tcase:
if(c >= 0 && c < 256)
if(r1 = r->u.cases[c])
follow[nfollow++] = r1;
if(r = r->next)
goto loop;
break;
case Talt:
case Tor:
fol1(r->u.alt, c);
r = r->next;
goto loop;
case Tbegin:
if(c == '\n' || c == Cbegin)
follow[nfollow++] = r->next;
break;
case Tend:
if(c == '\n')
matched = 1;
break;
case Tclass:
if(c >= r->u.x.lo && c <= r->u.x.hi)
follow[nfollow++] = r->next;
break;
}
}
Rune tab1[] =
{
0x007f,
0x07ff,
};
Rune tab2[] =
{
0x003f,
0x0fff,
};
Re2
rclass(Rune p0, Rune p1)
{
char xc0[6], xc1[6];
int i, n, m;
Re2 x;
if(p0 > p1)
return re2char(0xff, 0xff); // no match
/*
* bust range into same length
* character sequences
*/
for(i=0; i<nelem(tab1); i++) {
m = tab1[i];
if(p0 <= m && p1 > m)
return re2or(rclass(p0, m), rclass(m+1, p1));
}
/*
* bust range into part of a single page
* or into full pages
*/
for(i=0; i<nelem(tab2); i++) {
m = tab2[i];
if((p0 & ~m) != (p1 & ~m)) {
if((p0 & m) != 0)
return re2or(rclass(p0, p0|m), rclass((p0|m)+1, p1));
if((p1 & m) != m)
return re2or(rclass(p0, (p1&~m)-1), rclass(p1&~m, p1));
}
}
n = runetochar(xc0, &p0);
i = runetochar(xc1, &p1);
if(i != n)
error("length");
x = re2char(xc0[0], xc1[0]);
for(i=1; i<n; i++)
x = re2cat(x, re2char(xc0[i], xc1[i]));
return x;
}
int
pcmp(const void *va, const void *vb)
{
int n;
Rune *a, *b;
a = (Rune*)va;
b = (Rune*)vb;
n = a[0] - b[0];
if(n)
return n;
return a[1] - b[1];
}
/*
* convert character chass into
* run-pair ranges of matches.
* this is 10646/utf specific and
* needs to be changed for some
* other input character set.
* this is the key to a fast
* regular search of characters
* by looking at sequential bytes.
*/
Re2
re2class(char *s)
{
Rune pairs[200], *p, *q, ov;
int nc;
Re2 x;
nc = 0;
if(*s == '^') {
nc = 1;
s++;
}
p = pairs;
s += chartorune(p, s);
for(;;) {
if(*p == '\\')
s += chartorune(p, s);
if(*p == 0)
break;
p[1] = *p;
p += 2;
s += chartorune(p, s);
if(*p != '-')
continue;
s += chartorune(p, s);
if(*p == '\\')
s += chartorune(p, s);
if(*p == 0)
break;
p[-1] = *p;
s += chartorune(p, s);
}
*p = 0;
qsort(pairs, (p-pairs)/2, 2*sizeof(*pairs), pcmp);
q = pairs;
for(p=pairs+2; *p; p+=2) {
if(p[0] > p[1])
continue;
if(p[0] > q[1] || p[1] < q[0]) {
q[2] = p[0];
q[3] = p[1];
q += 2;
continue;
}
if(p[0] < q[0])
q[0] = p[0];
if(p[1] > q[1])
q[1] = p[1];
}
q[2] = 0;
p = pairs;
if(nc) {
x = rclass(0, p[0]-1);
ov = p[1]+1;
for(p+=2; *p; p+=2) {
x = re2or(x, rclass(ov, p[0]-1));
ov = p[1]+1;
}
x = re2or(x, rclass(ov, 0xffff));
} else {
x = rclass(p[0], p[1]);
for(p+=2; *p; p+=2)
x = re2or(x, rclass(p[0], p[1]));
}
return x;
}

124
grep/grep.1 Normal file
View File

@@ -0,0 +1,124 @@
.TH GREP 1
.SH NAME
grep, g \- search a file for a pattern
.SH SYNOPSIS
.B grep
[
.I option ...
]
.I pattern
[
.I file ...
]
.PP
.B g
[
.I option ...
]
.I pattern
[
.I file ...
]
.SH DESCRIPTION
.I Grep\^
searches the input
.I files\^
(standard input default)
for lines that match the
.IR pattern ,
a regular expression as defined in
.IR regexp (7)
with the addition of a newline character as an alternative
(substitute for
.BR | )
with lowest precedence.
Normally, each line matching the pattern is `selected',
and each selected line is copied to the standard output.
The options are
.TP
.B -c
Print only a count of matching lines.
.PD 0
.TP
.B -h
Do not print file name tags (headers) with output lines.
.TP
.B -e
The following argument is taken as a
.IR pattern .
This option makes it easy to specify patterns that
might confuse argument parsing, such as
.BR -n .
.TP
.B -i
Ignore alphabetic case distinctions. The implementation
folds into lower case all letters in the pattern and input before
interpretation. Matched lines are printed in their original form.
.TP
.B -l
(ell) Print the names of files with selected lines; don't print the lines.
.TP
.B -L
Print the names of files with no selected lines;
the converse of
.BR -l .
.TP
.B -n
Mark each printed line with its line number counted in its file.
.TP
.B -s
Produce no output, but return status.
.TP
.B -v
Reverse: print lines that do not match the pattern.
.TP
.B -f
The pattern argument is the name of a file containing regular
expressions one per line.
.TP
.B -b
Don't buffer the output: write each output line as soon as it is discovered.
.PD
.PP
Output lines are tagged by file name when there is more than one
input file.
(To force this tagging, include
.B /dev/null
as a file name argument.)
.PP
Care should be taken when
using the shell metacharacters
.B $*[^|()=\e
and newline
in
.IR pattern ;
it is safest to enclose the
entire expression
in single quotes
.BR \&\|' \|.\|.\|.\| ' .
An expression starting with '*'
will treat the rest of the expression
as literal characters.
.PP
.I G
invokes grep with
.B -n
and forces tagging of output lines by file name.
If no files are listed, it searches all files matching
.IP
.EX
*.C *.b *.c *.h *.m *.cc *.java *.cgi *.pl *.py *.tex *.ms
.EE
.SH SOURCE
.B \*9/src/cmd/grep
.br
.B \*9/bin/g
.SH SEE ALSO
.IR ed (1),
.IR awk (1),
.IR sed (1),
.IR sam (1),
.IR regexp (7)
.SH DIAGNOSTICS
Exit status is null if any lines are selected,
or non-null when no lines are selected or an error occurs.

125
grep/grep.h Normal file
View File

@@ -0,0 +1,125 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#ifndef EXTERN
#define EXTERN extern
#endif
typedef struct Re Re;
typedef struct Re2 Re2;
typedef struct State State;
struct State
{
int count;
int match;
Re** re;
State* linkleft;
State* linkright;
State* next[256];
};
struct Re2
{
Re* beg;
Re* end;
};
struct Re
{
uchar type;
ushort gen;
union
{
Re* alt; /* Talt */
Re** cases; /* case */
struct /* class */
{
Rune lo;
Rune hi;
} x;
Rune val; /* char */
} u;
Re* next;
};
enum
{
Talt = 1,
Tbegin,
Tcase,
Tclass,
Tend,
Tor,
Caselim = 7,
Nhunk = 1<<16,
Cbegin = 0x10000,
Flshcnt = (1<<9)-1,
Cflag = 1<<0,
Hflag = 1<<1,
Iflag = 1<<2,
Llflag = 1<<3,
LLflag = 1<<4,
Nflag = 1<<5,
Sflag = 1<<6,
Vflag = 1<<7,
Bflag = 1<<8
};
EXTERN union
{
char string[16*1024];
struct
{
/*
* if a line requires multiple reads, we keep shifting
* buf down into pre and then do another read into
* buf. so you'll get the last 16-32k of the matching line.
* if h were smaller than buf you'd get a suffix of the
* line with a hole cut out.
*/
uchar pre[16*1024]; /* to save to previous '\n' */
uchar buf[16*1024]; /* input buffer */
} u;
} u;
EXTERN char *filename;
EXTERN Biobuf bout;
EXTERN char flags[256];
EXTERN Re** follow;
EXTERN ushort gen;
EXTERN char* input;
EXTERN long lineno;
EXTERN int literal;
EXTERN int matched;
EXTERN long maxfollow;
EXTERN long nfollow;
EXTERN int peekc;
EXTERN Biobuf* rein;
EXTERN State* state0;
EXTERN Re2 topre;
extern Re* addcase(Re*);
extern void appendnext(Re*, Re*);
extern void error(char*);
extern int fcmp(const void*, const void*); /* (Re**, Re**) */
extern void fol1(Re*, int);
extern int getrec(void);
extern void increment(State*, int);
#define initstate grepinitstate
extern State* initstate(Re*);
extern void* mal(int);
extern void patchnext(Re*, Re*);
extern Re* ral(int);
extern Re2 re2cat(Re2, Re2);
extern Re2 re2class(char*);
extern Re2 re2or(Re2, Re2);
extern Re2 re2char(int, int);
extern Re2 re2star(Re2);
extern State* sal(int);
extern int search(char*, int);
extern void str2top(char*);
extern int yyparse(void);
extern void reprint(char*, Re*);
extern void yyerror(char*, ...);

226
grep/grep.y Normal file
View File

@@ -0,0 +1,226 @@
%{
#include "grep.h"
%}
%union
{
int val;
char* str;
Re2 re;
}
%type <re> expr prog
%type <re> expr0 expr1 expr2 expr3 expr4
%token <str> LCLASS
%token <val> LCHAR
%token LLPAREN LRPAREN LALT LSTAR LPLUS LQUES
%token LBEGIN LEND LDOT LBAD LNEWLINE
%%
prog:
expr newlines
{
$$.beg = ral(Tend);
$$.end = $$.beg;
$$ = re2cat(re2star(re2or(re2char(0x00, '\n'-1), re2char('\n'+1, 0xff))), $$);
$$ = re2cat($1, $$);
$$ = re2cat(re2star(re2char(0x00, 0xff)), $$);
topre = $$;
}
expr:
expr0
| expr newlines expr0
{
$$ = re2or($1, $3);
}
expr0:
expr1
| LSTAR { literal = 1; } expr1
{
$$ = $3;
}
expr1:
expr2
| expr1 LALT expr2
{
$$ = re2or($1, $3);
}
expr2:
expr3
| expr2 expr3
{
$$ = re2cat($1, $2);
}
expr3:
expr4
| expr3 LSTAR
{
$$ = re2star($1);
}
| expr3 LPLUS
{
$$.beg = ral(Talt);
patchnext($1.end, $$.beg);
$$.beg->u.alt = $1.beg;
$$.end = $$.beg;
$$.beg = $1.beg;
}
| expr3 LQUES
{
$$.beg = ral(Talt);
$$.beg->u.alt = $1.beg;
$$.end = $1.end;
appendnext($$.end, $$.beg);
}
expr4:
LCHAR
{
$$.beg = ral(Tclass);
$$.beg->u.x.lo = $1;
$$.beg->u.x.hi = $1;
$$.end = $$.beg;
}
| LBEGIN
{
$$.beg = ral(Tbegin);
$$.end = $$.beg;
}
| LEND
{
$$.beg = ral(Tend);
$$.end = $$.beg;
}
| LDOT
{
$$ = re2class("^\n");
}
| LCLASS
{
$$ = re2class($1);
}
| LLPAREN expr1 LRPAREN
{
$$ = $2;
}
newlines:
LNEWLINE
| newlines LNEWLINE
%%
void
yyerror(char *e, ...)
{
if(filename)
fprint(2, "grep: %s:%ld: %s\n", filename, lineno, e);
else
fprint(2, "grep: %s\n", e);
exits("syntax");
}
int
yylex(void)
{
char *q, *eq;
int c, s;
if(peekc) {
s = peekc;
peekc = 0;
return s;
}
c = getrec();
if(literal) {
if(c != 0 && c != '\n') {
yylval.val = c;
return LCHAR;
}
literal = 0;
}
switch(c) {
default:
yylval.val = c;
s = LCHAR;
break;
case '\\':
c = getrec();
yylval.val = c;
s = LCHAR;
if(c == '\n')
s = LNEWLINE;
break;
case '[':
goto getclass;
case '(':
s = LLPAREN;
break;
case ')':
s = LRPAREN;
break;
case '|':
s = LALT;
break;
case '*':
s = LSTAR;
break;
case '+':
s = LPLUS;
break;
case '?':
s = LQUES;
break;
case '^':
s = LBEGIN;
break;
case '$':
s = LEND;
break;
case '.':
s = LDOT;
break;
case 0:
peekc = -1;
case '\n':
s = LNEWLINE;
break;
}
return s;
getclass:
q = u.string;
eq = q + nelem(u.string) - 5;
c = getrec();
if(c == '^') {
q[0] = '^';
q[1] = '\n';
q[2] = '-';
q[3] = '\n';
q += 4;
c = getrec();
}
for(;;) {
if(q >= eq)
error("class too long");
if(c == ']' || c == 0)
break;
if(c == '\\') {
*q++ = c;
c = getrec();
if(c == 0)
break;
}
*q++ = c;
c = getrec();
}
*q = 0;
if(c == 0)
return LBAD;
yylval.str = u.string;
return LCLASS;
}

263
grep/main.c Normal file
View File

@@ -0,0 +1,263 @@
#define EXTERN
#include "grep.h"
char *validflags = "bchiLlnsv";
void
usage(void)
{
fprint(2, "usage: grep [-%s] [-f file] [-e expr] [file ...]\n", validflags);
exits("usage");
}
void
main(int argc, char *argv[])
{
int i, status;
ARGBEGIN {
default:
if(utfrune(validflags, ARGC()) == nil)
usage();
flags[ARGC()]++;
break;
case 'E': /* ignore, turns gnu grep into egrep */
break;
case 'e':
flags['e']++;
lineno = 0;
str2top(ARGF());
break;
case 'f':
flags['f']++;
filename = ARGF();
rein = Bopen(filename, OREAD);
if(rein == 0) {
fprint(2, "grep: can't open %s: %r\n", filename);
exits("open");
}
lineno = 1;
str2top(filename);
break;
} ARGEND
if(flags['f'] == 0 && flags['e'] == 0) {
if(argc <= 0)
usage();
str2top(argv[0]);
argc--;
argv++;
}
follow = mal(maxfollow*sizeof(*follow));
state0 = initstate(topre.beg);
Binit(&bout, 1, OWRITE);
switch(argc) {
case 0:
status = search(0, 0);
break;
case 1:
status = search(argv[0], 0);
break;
default:
status = 0;
for(i=0; i<argc; i++)
status |= search(argv[i], Hflag);
break;
}
if(status)
exits(0);
exits("no matches");
}
int
search(char *file, int flag)
{
State *s, *ns;
int c, fid, eof, nl, empty;
long count, lineno, n;
uchar *elp, *lp, *bol;
if(file == 0) {
file = "stdin";
fid = 0;
flag |= Bflag;
} else
fid = open(file, OREAD);
if(fid < 0) {
fprint(2, "grep: can't open %s: %r\n", file);
return 0;
}
if(flags['b'])
flag ^= Bflag; /* dont buffer output */
if(flags['c'])
flag |= Cflag; /* count */
if(flags['h'])
flag &= ~Hflag; /* do not print file name in output */
if(flags['i'])
flag |= Iflag; /* fold upper-lower */
if(flags['l'])
flag |= Llflag; /* print only name of file if any match */
if(flags['L'])
flag |= LLflag; /* print only name of file if any non match */
if(flags['n'])
flag |= Nflag; /* count only */
if(flags['s'])
flag |= Sflag; /* status only */
if(flags['v'])
flag |= Vflag; /* inverse match */
s = state0;
lineno = 0;
count = 0;
eof = 0;
empty = 1;
nl = 0;
lp = u.u.buf;
bol = lp;
loop0:
n = lp-bol;
if(n > sizeof(u.u.pre))
n = sizeof(u.u.pre);
memmove(u.u.buf-n, bol, n);
bol = u.u.buf-n;
n = read(fid, u.u.buf, sizeof(u.u.buf));
/* if file has no final newline, simulate one to emit matches to last line */
if(n > 0) {
empty = 0;
nl = u.u.buf[n-1]=='\n';
} else {
if(n < 0){
fprint(2, "grep: read error on %s: %r\n", file);
return count != 0;
}
if(!eof && !nl && !empty) {
u.u.buf[0] = '\n';
n = 1;
eof = 1;
}
}
if(n <= 0) {
close(fid);
if(flag & Cflag) {
if(flag & Hflag)
Bprint(&bout, "%s:", file);
Bprint(&bout, "%ld\n", count);
}
if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
Bprint(&bout, "%s\n", file);
Bflush(&bout);
return count != 0;
}
lp = u.u.buf;
elp = lp+n;
if(flag & Iflag)
goto loopi;
/*
* normal character loop
*/
loop:
c = *lp;
ns = s->next[c];
if(ns == 0) {
increment(s, c);
goto loop;
}
// if(flags['2'])
// if(s->match)
// print("%d: %.2x**\n", s, c);
// else
// print("%d: %.2x\n", s, c);
lp++;
s = ns;
if(c == '\n') {
lineno++;
if(!!s->match == !(flag&Vflag)) {
count++;
if(flag & (Cflag|Sflag|Llflag|LLflag))
goto cont;
if(flag & Hflag)
Bprint(&bout, "%s:", file);
if(flag & Nflag)
Bprint(&bout, "%ld: ", lineno);
/* suppress extra newline at EOF unless we are labeling matches with file name */
Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
if(flag & Bflag)
Bflush(&bout);
}
if((lineno & Flshcnt) == 0)
Bflush(&bout);
cont:
bol = lp;
}
if(lp != elp)
goto loop;
goto loop0;
/*
* character loop for -i flag
* for speed
*/
loopi:
c = *lp;
if(c >= 'A' && c <= 'Z')
c += 'a'-'A';
ns = s->next[c];
if(ns == 0) {
increment(s, c);
goto loopi;
}
lp++;
s = ns;
if(c == '\n') {
lineno++;
if(!!s->match == !(flag&Vflag)) {
count++;
if(flag & (Cflag|Sflag|Llflag|LLflag))
goto conti;
if(flag & Hflag)
Bprint(&bout, "%s:", file);
if(flag & Nflag)
Bprint(&bout, "%ld: ", lineno);
/* suppress extra newline at EOF unless we are labeling matches with file name */
Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
if(flag & Bflag)
Bflush(&bout);
}
if((lineno & Flshcnt) == 0)
Bflush(&bout);
conti:
bol = lp;
}
if(lp != elp)
goto loopi;
goto loop0;
}
State*
initstate(Re *r)
{
State *s;
int i;
addcase(r);
if(flags['1'])
reprint("r", r);
nfollow = 0;
gen++;
fol1(r, Cbegin);
follow[nfollow++] = r;
qsort(follow, nfollow, sizeof(*follow), fcmp);
s = sal(nfollow);
for(i=0; i<nfollow; i++)
s->re[i] = follow[i];
return s;
}

317
grep/sub.c Normal file
View File

@@ -0,0 +1,317 @@
#include "grep.h"
void*
mal(int n)
{
static char *s;
static int m = 0;
void *v;
n = (n+3) & ~3;
if(m < n) {
if(n > Nhunk) {
v = sbrk(n);
memset(v, 0, n);
return v;
}
s = sbrk(Nhunk);
m = Nhunk;
}
v = s;
s += n;
m -= n;
memset(v, 0, n);
return v;
}
State*
sal(int n)
{
State *s;
s = mal(sizeof(*s));
// s->next = mal(256*sizeof(*s->next));
s->count = n;
s->re = mal(n*sizeof(*state0->re));
return s;
}
Re*
ral(int type)
{
Re *r;
r = mal(sizeof(*r));
r->type = type;
maxfollow++;
return r;
}
void
error(char *s)
{
fprint(2, "grep: internal error: %s\n", s);
exits(s);
}
int
countor(Re *r)
{
int n;
n = 0;
loop:
switch(r->type) {
case Tor:
n += countor(r->u.alt);
r = r->next;
goto loop;
case Tclass:
return n + r->u.x.hi - r->u.x.lo + 1;
}
return n;
}
Re*
oralloc(int t, Re *r, Re *b)
{
Re *a;
if(b == 0)
return r;
a = ral(t);
a->u.alt = r;
a->next = b;
return a;
}
void
case1(Re *c, Re *r)
{
int n;
loop:
switch(r->type) {
case Tor:
case1(c, r->u.alt);
r = r->next;
goto loop;
case Tclass: /* add to character */
for(n=r->u.x.lo; n<=r->u.x.hi; n++)
c->u.cases[n] = oralloc(Tor, r->next, c->u.cases[n]);
break;
default: /* add everything unknown to next */
c->next = oralloc(Talt, r, c->next);
break;
}
}
Re*
addcase(Re *r)
{
int i, n;
Re *a;
if(r->gen == gen)
return r;
r->gen = gen;
switch(r->type) {
default:
error("addcase");
case Tor:
n = countor(r);
if(n >= Caselim) {
a = ral(Tcase);
a->u.cases = mal(256*sizeof(*a->u.cases));
case1(a, r);
for(i=0; i<256; i++)
if(a->u.cases[i]) {
r = a->u.cases[i];
if(countor(r) < n)
a->u.cases[i] = addcase(r);
}
return a;
}
return r;
case Talt:
r->next = addcase(r->next);
r->u.alt = addcase(r->u.alt);
return r;
case Tbegin:
case Tend:
case Tclass:
return r;
}
}
void
str2top(char *p)
{
Re2 oldtop;
oldtop = topre;
input = p;
topre.beg = 0;
topre.end = 0;
yyparse();
gen++;
if(topre.beg == 0)
yyerror("syntax");
if(oldtop.beg)
topre = re2or(oldtop, topre);
}
void
appendnext(Re *a, Re *b)
{
Re *n;
while(n = a->next)
a = n;
a->next = b;
}
void
patchnext(Re *a, Re *b)
{
Re *n;
while(a) {
n = a->next;
a->next = b;
a = n;
}
}
int
getrec(void)
{
int c;
if(flags['f']) {
c = Bgetc(rein);
if(c <= 0)
return 0;
} else
c = *input++ & 0xff;
if(flags['i'] && c >= 'A' && c <= 'Z')
c += 'a'-'A';
if(c == '\n')
lineno++;
return c;
}
Re2
re2cat(Re2 a, Re2 b)
{
Re2 c;
c.beg = a.beg;
c.end = b.end;
patchnext(a.end, b.beg);
return c;
}
Re2
re2star(Re2 a)
{
Re2 c;
c.beg = ral(Talt);
c.beg->u.alt = a.beg;
patchnext(a.end, c.beg);
c.end = c.beg;
return c;
}
Re2
re2or(Re2 a, Re2 b)
{
Re2 c;
c.beg = ral(Tor);
c.beg->u.alt = b.beg;
c.beg->next = a.beg;
c.end = b.end;
appendnext(c.end, a.end);
return c;
}
Re2
re2char(int c0, int c1)
{
Re2 c;
c.beg = ral(Tclass);
c.beg->u.x.lo = c0 & 0xff;
c.beg->u.x.hi = c1 & 0xff;
c.end = c.beg;
return c;
}
void
reprint1(Re *a)
{
int i, j;
loop:
if(a == 0)
return;
if(a->gen == gen)
return;
a->gen = gen;
print("%p: ", a);
switch(a->type) {
default:
print("type %d\n", a->type);
error("print1 type");
case Tcase:
print("case ->%p\n", a->next);
for(i=0; i<256; i++)
if(a->u.cases[i]) {
for(j=i+1; j<256; j++)
if(a->u.cases[i] != a->u.cases[j])
break;
print(" [%.2x-%.2x] ->%p\n", i, j-1, a->u.cases[i]);
i = j-1;
}
for(i=0; i<256; i++)
reprint1(a->u.cases[i]);
break;
case Tbegin:
print("^ ->%p\n", a->next);
break;
case Tend:
print("$ ->%p\n", a->next);
break;
case Tclass:
print("[%.2x-%.2x] ->%p\n", a->u.x.lo, a->u.x.hi, a->next);
break;
case Tor:
case Talt:
print("| %p ->%p\n", a->u.alt, a->next);
reprint1(a->u.alt);
break;
}
a = a->next;
goto loop;
}
void
reprint(char *s, Re *r)
{
print("%s:\n", s);
gen++;
reprint1(r);
print("\n\n");
}