| #include <time.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include "tools/re2c/globals.h" |
| #include "tools/re2c/parse.h" |
| #include "tools/re2c/parser.h" |
| |
| int yylex(void); |
| static RegExp *parse_expr(void); |
| static RegExp *parse_diff(void); |
| static RegExp *parse_term(void); |
| static RegExp *parse_factor(void); |
| static RegExp *parse_primary(void); |
| |
| static unsigned int accept; |
| static RegExp *spec; |
| static Scanner *in; |
| |
| static int curtok, peektok; |
| yystype yylval; |
| static yystype peekval; |
| |
| #define get_next_token() (curtok = yylex()) |
| |
| static void |
| get_peek_token(void) |
| { |
| yystype temp = yylval; /* structure copy */ |
| if (peektok != NONE) |
| Scanner_fatal(in, "more than one token of lookahead?"); |
| peektok = yylex(); |
| peekval = yylval; /* structure copy */ |
| yylval = temp; |
| } |
| |
| static void |
| yyparse(void) |
| { |
| RegExp *re, *look; |
| |
| accept = 0; |
| spec = NULL; |
| get_next_token(); |
| while (curtok != 0) { |
| switch (curtok) { |
| case ID: |
| get_peek_token(); |
| if (peektok == '=') { |
| /* ID = expr; */ |
| Symbol *sym = yylval.symbol; |
| get_next_token(); /* id */ |
| get_next_token(); /* = */ |
| re = parse_expr(); |
| if (curtok != ';') |
| Scanner_fatal(in, "missing `;' after regexp"); |
| get_next_token(); /* ; */ |
| if (sym->re) |
| Scanner_fatal(in, "sym already defined"); |
| sym->re = re; |
| break; |
| } |
| /*@fallthrough@*/ |
| default: |
| /* rule: expr [/ expr] CODE */ |
| re = parse_expr(); |
| if (!re) |
| Scanner_fatal(in, "expression syntax error"); |
| |
| if (curtok == '/') { |
| get_next_token(); /* / */ |
| look = parse_expr(); |
| } else |
| look = RegExp_new_NullOp(); |
| |
| if (curtok != CODE) |
| Scanner_fatal(in, "missing code after regexp"); |
| re = RegExp_new_RuleOp(re, look, yylval.token, accept++); |
| get_next_token(); /* CODE */ |
| spec = spec ? mkAlt(spec, re) : re; |
| } |
| } |
| } |
| |
| static RegExp * |
| parse_expr(void) |
| { |
| RegExp *e, *f; |
| e = parse_diff(); |
| while (curtok == '|') { |
| get_next_token(); /* | */ |
| f = parse_diff(); |
| e = mkAlt(e, f); |
| } |
| return e; |
| } |
| |
| static RegExp * |
| parse_diff(void) |
| { |
| RegExp *e, *f; |
| e = parse_term(); |
| while (curtok == '\\') { |
| get_next_token(); /* \ */ |
| f = parse_term(); |
| e = mkDiff(e, f); |
| if(!e) |
| Scanner_fatal(in, "can only difference char sets"); |
| } |
| return e; |
| } |
| |
| static RegExp * |
| parse_term(void) |
| { |
| RegExp *e, *f; |
| e = parse_factor(); |
| while ((f = parse_factor())) { |
| e = RegExp_new_CatOp(e, f); |
| } |
| return e; |
| } |
| |
| static RegExp * |
| parse_factor(void) |
| { |
| RegExp *e; |
| char ch; |
| e = parse_primary(); |
| while (curtok == CLOSE || curtok == CLOSESIZE) { |
| switch (curtok) { |
| case CLOSE: |
| ch = yylval.op; |
| while (get_next_token() == CLOSE) { |
| if (ch != yylval.op) |
| ch = '*'; |
| } |
| switch (ch) { |
| case '*': |
| e = mkAlt(RegExp_new_CloseOp(e), RegExp_new_NullOp()); |
| break; |
| case '+': |
| e = RegExp_new_CloseOp(e); |
| break; |
| case '?': |
| e = mkAlt(e, RegExp_new_NullOp()); |
| break; |
| } |
| break; |
| case CLOSESIZE: |
| e = RegExp_new_CloseVOp(e, yylval.extop.minsize, |
| yylval.extop.maxsize); |
| get_next_token(); /* CLOSESIZE */ |
| break; |
| default: |
| Scanner_fatal(in, "parse error"); |
| break; |
| } |
| } |
| return e; |
| } |
| |
| static RegExp * |
| parse_primary(void) |
| { |
| RegExp *e; |
| switch (curtok) { |
| case ID: |
| if (!yylval.symbol->re) |
| Scanner_fatal(in, "can't find symbol"); |
| e = yylval.symbol->re; |
| get_next_token(); |
| break; |
| case RANGE: |
| case STRING: |
| e = yylval.regexp; |
| get_next_token(); |
| break; |
| case '(': |
| get_next_token(); |
| e = parse_expr(); |
| if (curtok != ')') |
| Scanner_fatal(in, "missing closing parenthesis"); |
| get_next_token(); |
| break; |
| default: |
| return NULL; |
| } |
| return e; |
| } |
| |
| int |
| yylex(void) |
| { |
| if (peektok != NONE) { |
| int tok = peektok; |
| yylval = peekval; |
| peektok = NONE; |
| return tok; |
| } |
| return Scanner_scan(in); |
| } |
| |
| void line_source(FILE *o, unsigned int line) |
| { |
| char * fnamebuf; |
| char * token; |
| |
| if (iFlag) |
| return; |
| fprintf(o, "#line %u \"", line); |
| if( fileName != NULL ) { |
| fnamebuf = mystrdup( fileName ); |
| } else { |
| fnamebuf = mystrdup( "<stdin>" ); |
| } |
| token = strtok( fnamebuf, "\\" ); |
| for(;;) { |
| fprintf(o, "%s", token); |
| token = strtok( NULL, "\\" ); |
| if( token == NULL ) break; |
| fputs("\\\\", o); |
| } |
| fputs("\"\n", o); oline++; |
| free( fnamebuf ); |
| } |
| |
| void parse(FILE *i, FILE *o){ |
| time_t now; |
| |
| time(&now); |
| |
| peektok = NONE; |
| |
| fputs("/* Generated by re2c 0.9.1-C on ", o); |
| fprintf(o, "%-24s", ctime(&now)); |
| fputs(" */\n", o); oline+=2; |
| |
| in = Scanner_new(i); |
| |
| line_source(o, Scanner_line(in)); |
| |
| while(Scanner_echo(in, o)){ |
| yyparse(); |
| if(spec) |
| genCode(o, spec); |
| line_source(o, Scanner_line(in)); |
| } |
| } |