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