// gcom.gr // parser for guarded command example language verbatim { #include "str.h" // stringf #include "ast.h" // AST declarations #include // getenv, atoi, putenv #include // printf } // the parser context class is useful in large examples; // an empty one will suffice here context_class GComContext : public UserActions { public: // given a lexer-allocated string, make a 'string', and // deallocate the lexer-created copy static inline string copyAndFree(char *x) { string ret(x); delete x; return ret; } // for run-time precedence/associativity static int precedence(AExp *a) { if (!a->isA_bin()) { return 20; } // unary A_bin *ab = a->asA_bin(); if (ab->op == AO_TIMES) { return 10; } // * else { return 0; } // +,- } }; // pull in the tokens generated from lexer.h terminals { include("tokens.tok") // declare token sval types token(int) TOK_LITERAL { fun dup(n) { return n; } // nothing special to do for ints fun del(n) {} } token(char*) TOK_IDENTIFIER { fun dup(x) { return strdup(x); } // make a copy fun del(x) { free(x); } // delete a copy } precedence { // high precedence //left 60 "*"; //left 50 "+" "-"; left 40 "!"; // ! has higher precedence than /\ and \/ left 30 TOK_AND; // /\ has higher precedence than \/ left 20 TOK_OR; left 10 ";" "#"; // precedence is irrelvant // low precedence } } // now the grammar; the first symbol is the start symbol nonterm(Stmt*) Start { -> s:Stmt { return s; } } nonterm(AExp*) AExp { fun dup(a) { return a->clone(); } // deep copy fun del(a) { delete a; } // deep delete // implemented precedence/associativity at run time fun merge(a1,a2) { if (precedence(a1) < precedence(a2)) { delete a2; return a1; } // lowest precedence goes on top if (precedence(a1) > precedence(a2)) { delete a1; return a2; } // equal precedence, must be binary operators A_bin *ab1 = a1->asA_bin(); // cast to A_bin* A_bin *ab2 = a2->asA_bin(); // same precedence; associates to the left; that means // that the RHS must use a higher-precedence operator if (precedence(ab1) < precedence(ab1->a2)) { delete ab2; return ab1; } // high-prec exp on right if (precedence(ab2) < precedence(ab2->a2)) { delete ab1; return ab2; } // high-prec exp on right printf("failed to disambiguate!\n"); delete ab2; return ab1; // pick arbitrarily } -> n:TOK_LITERAL { return new A_lit(n); } -> x:TOK_IDENTIFIER { return new A_var(copyAndFree(x)); } -> a1:AExp "+" a2:AExp { return new A_bin(a1, AO_PLUS, a2); } -> a1:AExp "-" a2:AExp { return new A_bin(a1, AO_MINUS, a2); } -> a1:AExp "*" a2:AExp { return new A_bin(a1, AO_TIMES, a2); } -> "(" a:AExp ")" { return new A_group(a); } } nonterm(BExp*) BExp { -> "true" { return new B_lit(true); } -> "false" { return new B_lit(false); } -> a1:AExp "=" a2:AExp { return new B_pred(a1, BP_EQUAL, a2); } -> a1:AExp "<" a2:AExp { return new B_pred(a1, BP_LESS, a2); } -> "!" b:BExp { return new B_not(b); } -> b1:BExp TOK_AND b2:BExp { return new B_bin(b1, BO_AND, b2); } -> b1:BExp TOK_OR b2:BExp { return new B_bin(b1, BO_OR, b2); } -> "(" b:BExp ")" { return b; } } nonterm(Stmt*) Stmt { -> "skip" { return new S_skip; } -> "abort" { return new S_abort; } -> "print" x:TOK_IDENTIFIER { return new S_print(copyAndFree(x)); } -> x:TOK_IDENTIFIER ":=" a:AExp { return new S_assign(copyAndFree(x), a); } -> s1:Stmt ";" s2:Stmt { return new S_seq(s1, s2); } -> "if" g:GCom "fi" { return new S_if(g); } -> "do" g:GCom "od" { return new S_do(g); } } nonterm(GCom*) GCom { -> b:BExp "->" s:Stmt { return new G_stmt(b, s); } -> g1:GCom "#" g2:GCom { return new G_seq(g1, g2); } }