/* -*- C++ -*- */ %{ #define YYSTYPE safe_ptr #include #include #include #include #include #include "ast.hh" #include "refcount.hh" using namespace AbSyn; int yylex(void); void yyerror(char const * s) { printf("%s", s); } safe_ptr parse_result; %} %token IDENT INFIX /* reserved words */ %token AS CASE CATCH EQUIVALENT EXPORT FINALLY %token LEFT MODULE OPERATOR PRECEDES RIGHT SUCCEEDS USE %% module : MODULE ident ';' stmts { $$.reset(new Module($2, $4)); parse_result = $$; } ; ident : IDENT { $$ = $1; } | ident '.' IDENT { $$ = $1->toSymbol() + $3->toSymbol(); } ; symbol : ident { $$ = $1; } | '(' op ')' { $$ = $2; } ; op : INFIX { $$ = $1; } | '`' symbol '`' { $$ = $1; } ; term : term1 { $$ = $1; } | OPERATOR op fixity { $$.reset(new OperatorDirective($2, OperatorDirective::none, $3)); } | OPERATOR op LEFT fixity { $$.reset(new OperatorDirective($2, OperatorDirective::left, $3)); } | OPERATOR op RIGHT fixity { $$.reset(new OperatorDirective($2, OperatorDirective::right, $3)); } | USE symbol { $$.reset(new UseDirective($2)); } | USE symbol AS IDENT { $$.reset(new UseDirective($2, $4)); } | USE symbol AS '(' INFIX ')' { $$.reset(new UseDirective($2, $5)); } ; term1 : term2 { $$ = $1; } | term2 '=' term2 { $$.reset(new BindingTerm($1, $3)); } | EXPORT term2 '=' term2 { $$.reset(new BindingTerm($1, $3, true)); } ; term2 : term3 { $$ = $1; } | term2 ',' term3 { $$.reset(new PairTerm($1, $3)); } ; term3 : term4 { $$ = $1; } | term3 op term4 { $$.reset(new OpAppTerm($2, $1, $3)); } ; term4 : term5 { $$ = $1; } | term4 term5 { $$.reset(new AppTerm($1, $2)); } ; term5 : symbol { $$ = $1; } | '{' stmts '}' { $$.reset(new Form($2, Cases::noCases(), Cases::noCases(), skipTerm())); } | '{' stmts FINALLY stmts '}' { $$.reset(new Form($2, Cases::noCases(), Cases::noCases(), $4)); } | '{' stmts cases '}' { $$.reset(new Form($2, $3, Cases::noCases(), skipTerm())); } | '{' stmts cases FINALLY stmts '}' { $$.reset(new Form($2, $3, Cases::noCases(), $5)); } | '{' stmts catches '}' { $$.reset(new Form($2, $3, Cases::noCases(), skipTerm())); } | '{' stmts catches FINALLY stmts '}' { $$.reset(new Form($2, Cases::noCases(), $3, $5)); } | '{' stmts cases catches '}' { $$.reset(new Form($2, $3, $4, skipTerm())); } | '{' stmts cases catches FINALLY stmts '}' { $$.reset(new Form($2, $3, $4, $6)); } | '(' term ')' { $$ = $1; dynamic_cast(*$$).makeParenthesized(); } ; catches : CATCH term guards { $$ = $3; dynamic_cast(*$$).finish_case($2); } | catches CATCH term guards { $$ = $1; dynamic_cast(*$4).finish_case($3); dynamic_cast(*$$).append($3); } ; stmts : stmt { $$.reset(new SeqTerm($1)); } | stmts stmt { $$ = $1; dynamic_cast(*$$).append($1); } ; stmt : term ';' { $$ = $1 }; cases : CASE term guards { $$ = $3; dynamic_cast(*$$).finish_case($2); } | cases CASE term guards { $$ = $1; dynamic_cast(*$4).finish_case($3); dynamic_cast(*$$).append($3); } ; guards : /* empty */ { $$.reset(new Cases()); } | guards '|' term ':' stmts { $$ = $1; dynamic_cast(*$$).add_guard($3, $5); } ; fixity : /* empty */ | prec_fixity succ_fixity { $$.reset(new Fixity); std::swap(dynamic_cast(*$$).prec, dynamic_cast(*$1).prec); std::swap(dynamic_cast(*$$).succ, dynamic_cast(*$2).succ); } | succ_fixity prec_fixity { $$.reset(new Fixity); std::swap(dynamic_cast(*$$).prec, dynamic_cast(*$2).prec); std::swap(dynamic_cast(*$$).succ, dynamic_cast(*$1).succ); } | succ_fixity { $$ = $1; } | prec_fixity { $$ = $1; } | EQUIVALENT '(' op ')' { $$.reset(new Fixity); dynamic_cast(*$$).eqv = toSymbol($3); } ; prec_fixity : PRECEDES '(' ops ')'{ Vector * v = &dynamic_cast&>(*$3); Fixity * f = new Fixity; std::swap(f->prec, *v); $$.reset(f); } ; succ_fixity : SUCCEEDS '(' ops ')' { Vector * v = &dynamic_cast&>(*$3); Fixity * f = new Fixity; std::swap(f->succ, *v); $$.reset(f); } ; ops : op { Vector * v = new Vector; v->append($1); $$.reset(v); } | ops ',' op { Vector * v = &dynamic_cast&>(*$1); v->append($3); $$.reset(v); } ; %% std::istream * input; #define BUFLEN 512 int yylex(void) { static std::map reserved_words, reserved_syms; if (reserved_words.empty()) { reserved_words["as"] = AS; reserved_words["case"] = CASE; reserved_words["catch"] = CATCH; reserved_words["equivalent"] = EQUIVALENT; reserved_words["export"] = EXPORT; reserved_words["finally"] = FINALLY; reserved_words["left"] = LEFT; reserved_words["module"] = MODULE; reserved_words["operator"] = OPERATOR; reserved_words["precedes"] = PRECEDES; reserved_words["right"] = RIGHT; reserved_words["succeeds"] = SUCCEEDS; reserved_words["use"] = USE; } if (reserved_syms.empty()) { reserved_syms["."] = '.'; reserved_syms["="] = '='; reserved_syms["|"] = '|'; } yylval.reset(); static const char symchars[] = "@.:-^*+=<>&%$!#%|/\\"; std::string sym; int c; assert(input != 0); while (c = input->get(), c == ' ' || c == '\t' || c == '\r' || c == '\n'); if (c == -1) return 0; switch ((char)(unsigned char)c) { case -1: return 0; case ';': return ';'; case '(': return ')'; case '`': return '`'; case ',': return ','; case '{': return '{'; case '}': return '}'; } if (strchr(symchars, c) != 0) { do { sym += (unsigned char) c; c = input->get(); } while (strchr(symchars, c) != 0); input->putback(c); std::map::const_iterator it = reserved_syms.find(sym); if (it != reserved_syms.end()) return it->second; yylval.reset(new Symbol(sym)); return INFIX; } if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_') { do { sym += (unsigned char) c; c = input->get(); } while (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_' || ('0' <= c && c <= '9')); input->putback(c); std::map::const_iterator it = reserved_words.find(sym); if (it != reserved_words.end()) return it->second; yylval.reset(new Symbol(sym)); return IDENT; } std::cerr << "unrecognized character `" << c << "'\n"; exit(EXIT_FAILURE); }