%{ /* $Id: parser.y 674 2007-04-16 21:39:11Z helly $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <time.h> #include <string.h> #include <stdlib.h> #include <iostream> #include "globals.h" #include "parser.h" #include "basics.h" #define YYMALLOC malloc #define YYFREE free using namespace re2c; extern "C" { int yylex(); void yyerror(const char*); } static re2c::uint accept; static RegExp *spec; static Scanner *in = NULL; /* 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 { re2c::Symbol *symbol; re2c::RegExp *regexp; re2c::Token *token; char op; int number; re2c::ExtOp extop; re2c::Str *str; }; %token CLOSESIZE CLOSE ID CODE RANGE STRING %token CONFIG VALUE NUMBER %type <op> CLOSE %type <op> close %type <extop> CLOSESIZE %type <symbol> ID %type <token> CODE %type <regexp> RANGE STRING %type <regexp> rule look expr diff term factor primary %type <str> CONFIG VALUE %type <number> NUMBER %% 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; } | ID '=' expr '/' { in->fatal("trailing contexts are not allowed in named definitions"); } | CONFIG '=' VALUE ';' { in->config(*$1, *$3); delete $1; delete $3; } | CONFIG '=' NUMBER ';' { in->config(*$1, $3); delete $1; } ; 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(const char* s) { in->fatal(s); } int yylex(){ return in ? in->scan() : 0; } } // end extern "C" namespace re2c { void parse(Scanner& i, std::ostream& o) { in = &i; o << "/* Generated by re2c " PACKAGE_VERSION; if (!bNoGenerationDate) { o << " on "; time_t now = time(&now); o.write(ctime(&now), 24); } o << " */\n"; o << sourceFileInfo; while(i.echo()) { yyparse(); if(spec) { genCode(o, topIndent, spec); } o << sourceFileInfo; } RegExp::vFreeList.clear(); Range::vFreeList.clear(); Symbol::ClearTable(); in = NULL; } } // end namespace re2c