#include #include #include #include #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( "" ); } 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)); } }