%{ /* $Id: parser.y,v 1.9 2004/05/13 14:26:01 nuffer Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "globals.h" #include "parser.h" extern "C" { int yyparse(); int yylex(); void yyerror(char*); } static uint accept; static RegExp *spec; static Scanner *in; /* Bison version 1.875 emits a definition that is not working * with several g++ version. Hence we disable it here. */ #if defined(__GNUC__) #define __attribute__(x) #endif /* strdup() isn't standard C, so if we don't have it, we'll create our * own version */ #if !defined(HAVE_STRDUP) static char* strdup(const char* s) { char* rv = (char*)malloc(strlen(s) + 1); if (rv == NULL) return NULL; strcpy(rv, s); return rv; } #endif %} %start spec %union { Symbol *symbol; RegExp *regexp; Token *token; char op; ExtOp extop; }; %token CLOSESIZE CLOSE ID CODE RANGE STRING %type CLOSE %type close %type CLOSESIZE %type ID %type CODE %type RANGE STRING %type rule look expr diff term factor primary %% spec : { accept = 0; spec = NULL; } | spec rule { spec = spec? mkAlt(spec, $2) : $2; } | spec decl ; decl : ID '=' expr ';' { if($1->re) in->fatal("sym already defined"); $1->re = $3; } ; rule : expr look CODE { $$ = new RuleOp($1, $2, $3, accept++); } ; look : { $$ = new NullOp; } | '/' expr { $$ = $2; } ; expr : diff { $$ = $1; } | expr '|' diff { $$ = mkAlt($1, $3); } ; diff : term { $$ = $1; } | diff '\\' term { $$ = mkDiff($1, $3); if(!$$) in->fatal("can only difference char sets"); } ; term : factor { $$ = $1; } | term factor { $$ = new CatOp($1, $2); } ; factor : primary { $$ = $1; } | primary close { switch($2){ case '*': $$ = mkAlt(new CloseOp($1), new NullOp()); break; case '+': $$ = new CloseOp($1); break; case '?': $$ = mkAlt($1, new NullOp()); break; } } | primary CLOSESIZE { $$ = new CloseVOp($1, $2.minsize, $2.maxsize); } ; close : CLOSE { $$ = $1; } | close CLOSE { $$ = ($1 == $2) ? $1 : '*'; } ; primary : ID { if(!$1->re) in->fatal("can't find symbol"); $$ = $1->re; } | RANGE { $$ = $1; } | STRING { $$ = $1; } | '(' expr ')' { $$ = $2; } ; %% extern "C" { void yyerror(char* s){ in->fatal(s); } int yylex(){ return in->scan(); } } // end extern "C" void line_source(unsigned int line, std::ostream& o) { char * fnamebuf; char * token; o << "#line " << line << " \""; if( fileName != NULL ) { fnamebuf = strdup( fileName ); } else { fnamebuf = strdup( "" ); } token = strtok( fnamebuf, "\\" ); for(;;) { o << token; token = strtok( NULL, "\\" ); if( token == NULL ) break; o << "\\\\"; } o << "\"\n"; ++oline; free( fnamebuf ); } void parse(std::istream& i, std::ostream &o){ o << "/* Generated by re2c " PACKAGE_VERSION " on "; time_t now = time(&now); o.write(ctime(&now), 24); o << " */\n"; oline += 2; in = new Scanner(i); line_source(in->line(), o); while(in->echo(o)){ yyparse(); if(spec) genCode(o, spec); line_source(in->line(), o); } }