%{ | |
#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; | |
} |