Skip to content

Instantly share code, notes, and snippets.

@VenturaDelMonte
Last active November 30, 2015 19:23
Show Gist options
  • Save VenturaDelMonte/b9bd693eb43856e1d728 to your computer and use it in GitHub Desktop.
Save VenturaDelMonte/b9bd693eb43856e1d728 to your computer and use it in GitHub Desktop.
/*
* file name: cool.cup
* authors: Bonaventura Del Monte, Antonio Cesarano
* last edit: 04/05/2014
* Parser definition for the COOL language.
*
*/
import java_cup.runtime.*;
/* Stuff enclosed in {: :} is copied verbatim to the class containing
all parser actions. All the extra variables/functions you want to use
in the semantic actions should go here. Don't remove or modify anything
that was there initially. */
action code {:
int curr_lineno() {
return ((CoolTokenLexer)parser.getScanner()).curr_lineno();
}
AbstractSymbol curr_filename() {
return ((CoolTokenLexer)parser.getScanner()).curr_filename();
}
int line = 0;
int tmp_line = 0;
void update_line()
{
line = curr_lineno();
}
:}
/************************************************************************/
/* DONT CHANGE ANYTHING IN THIS SECTION */
parser code {:
int omerrs = 0;
public void syntax_error(Symbol cur_token) {
int lineno = action_obj.curr_lineno();
String filename = action_obj.curr_filename().getString();
System.err.print("\"" + filename + "\", line " + lineno +
": syntax error at or near ");
Utilities.printToken(cur_token);
omerrs++;
if (omerrs>50) {
System.err.println("More than 50 errors");
System.exit(1);
}
}
public void unrecovered_syntax_error(Symbol cur_token) {
}
:}
/* Declare the terminals; a few have types for associated lexemes. The
token ERROR is never used in the parser; thus, it is a parse error when
the lexer returns it. */
terminal CLASS, ELSE, FI, IF, IN, INHERITS, LET, LET_STMT, LOOP, POOL, THEN, WHILE;
terminal CASE, ESAC, OF, DARROW, NEW, ISVOID;
terminal ASSIGN, NOT, LE, ERROR;
terminal PLUS, DIV, MINUS, MULT, EQ, LT, DOT, NEG, COMMA, SEMI, COLON;
terminal LPAREN, RPAREN, AT, LBRACE, RBRACE;
terminal AbstractSymbol STR_CONST, INT_CONST;
terminal Boolean BOOL_CONST;
terminal AbstractSymbol TYPEID, OBJECTID;
/* DON'T CHANGE ANYTHING ABOVE THIS LINE, OR YOUR PARSER WONT WORK */
/**************************************************************************/
/* Complete the nonterminal list below, giving a type for the semantic
value of each non terminal. (See the CUP documentation for details. */
nonterminal Integer dummy;
nonterminal Program program;
nonterminal Classes class_list;
nonterminal Class_ class;
nonterminal Expression expression;
nonterminal Expressions expression_list_semi;
nonterminal Expressions expression_list_comma;
nonterminal Formal formal;
nonterminal Formals formal_list;
nonterminal Feature feature;
nonterminal Features feature_list;
nonterminal Cases case_list;
nonterminal Case single_case;
nonterminal let nested_let;
nonterminal block _block;
/* Non terminal wrappers for terminals */
nonterminal Integer _class, _else, _fi, _if, _in, _inherits, _let, _loop, _pool, _then, _while;
nonterminal Integer _case, _esac, _of, _darrow, _new, _isvoid;
nonterminal Integer _assign, _not, _le;
nonterminal Integer _plus, _div, _minus, _mult, _eq, _lt, _dot, _neg, _comma, _semi, _colon;
nonterminal Integer _lparen, _rparen, _at, _lbrace, _rbrace;
/* Precedence declarations */
precedence right ASSIGN;
precedence left NOT;
precedence nonassoc LT, LE, EQ;
precedence left PLUS, MINUS;
precedence left MULT, DIV;
precedence left ISVOID;
precedence left NEG;
precedence left AT;
precedence left DOT;
program
::= dummy:l class_list:cl
{: RESULT = new programc(l, cl); update_line(); :}
;
dummy // token for getting the program correct line
::=
{: RESULT = curr_lineno(); update_line(); :}
;
class_list
::=
/* single class */
class:c _semi:_line
{: RESULT = (new Classes(_line)).appendElement(c); update_line(); :}
/* several classes */
| class_list:cl class:c _semi {: RESULT = cl.appendElement(c); :}
| error RBRACE SEMI
;
/* NON TERMINAL WRAPPERS FOR TERMINALS: needed for tracking correct line numbers */
_class ::= CLASS {: RESULT = line; update_line(); :};
_else ::= ELSE {: RESULT = line; update_line(); :};
_fi ::= FI {: RESULT = line; update_line(); :};
_if ::= IF {: RESULT = line; update_line(); :};
_in ::= IN {: RESULT = line; update_line(); :};
_inherits ::= INHERITS {: RESULT = line; update_line(); :};
_let ::= LET {: RESULT = line; update_line(); :};
_loop ::= LOOP {: RESULT = line; update_line(); :};
_pool ::= POOL {: RESULT = line; update_line(); :};
_then ::= THEN {: RESULT = line; update_line(); :};
_while ::= WHILE {: RESULT = line; update_line(); :};
_case ::= CASE {: RESULT = line; update_line(); :};
_esac ::= ESAC {: RESULT = line; update_line(); :};
_of ::= OF {: RESULT = line; update_line(); :};
_darrow ::= DARROW {: RESULT = line; update_line(); :};
_new ::= NEW {: RESULT = line; update_line(); :};
_isvoid ::= ISVOID {: RESULT = line; update_line(); :};
_assign ::= ASSIGN {: RESULT = line; update_line(); :};
_not ::= NOT {: RESULT = line; update_line(); :};
_le ::= LE {: RESULT = line; update_line(); :};
_plus ::= PLUS {: RESULT = line; update_line(); :};
_div ::= DIV {: RESULT = line; update_line(); :};
_minus ::= MINUS {: RESULT = line; update_line(); :};
_mult ::= MULT {: RESULT = line; update_line(); :};
_eq ::= EQ {: RESULT = line; update_line(); :};
_lt ::= LT {: RESULT = line; update_line(); :};
_dot ::= DOT {: RESULT = line; update_line(); :};
_neg ::= NEG {: RESULT = line; update_line(); :};
_comma ::= COMMA {: RESULT = line; update_line(); :};
_semi ::= SEMI {: RESULT = line; update_line(); :};
_colon ::= COLON {: RESULT = line; update_line(); :};
_lparen ::= LPAREN {: RESULT = line; update_line(); :};
_rparen ::= RPAREN {: RESULT = line; update_line(); :};
_at ::= AT {: RESULT = line; update_line(); :};
_lbrace ::= LBRACE {: RESULT = line; update_line(); :};
_rbrace ::= RBRACE {: RESULT = line; update_line(); :};
class
::=
/* class TYPE { } */
_class:_line TYPEID:n _lbrace _rbrace
{: RESULT = new class_c(_line, n, AbstractTable.idtable.addString("Object"), new Features (_line), curr_filename()); update_line(); :}
/* class TYPE [inherits TYPE] { [[feature; ]] ∗ } */
| _class:_line TYPEID:n _inherits TYPEID:p _lbrace _rbrace
{: RESULT = new class_c(_line, n, p, new Features (_line), curr_filename()); update_line(); :}
/* class TYPE { [[feature; ]] ∗ } */
| _class:_line TYPEID:n _lbrace feature_list:fl _rbrace
{: RESULT = new class_c(_line, n, AbstractTable.idtable.addString("Object"), fl, curr_filename()); update_line(); :}
/* class TYPE [inherits TYPE] { [[feature; ]] ∗ } */
| _class:_line TYPEID:n _inherits TYPEID:p _lbrace feature_list:fl _rbrace
{: RESULT = new class_c(_line, n, p, fl, curr_filename()); update_line(); :}
;
feature
/* ID( ) : TYPE { expr } */
::= OBJECTID:id _lparen:_line _rparen _colon TYPEID:type _lbrace expression:e _rbrace
{: RESULT = new method(_line, id, new Formals(_line),type,e); update_line(); :}
/* ID( [ formal [[, formal]] ∗ ] ) : TYPE { expr } */
| OBJECTID:id _lparen:_line formal_list:fl _rparen _colon TYPEID:type _lbrace expression:e _rbrace
{: RESULT = new method(_line, id, fl, type, e); update_line(); :}
/* ID : TYPE */
| OBJECTID:id _colon:_line TYPEID:type
{: RESULT = new attr(_line, id, type, new no_expr (0) ); update_line(); :}
/* ID : TYPE [ <- expr ] */
| OBJECTID:id _colon:_line TYPEID:type _assign expression:e
{: RESULT = new attr(_line, id, type, e ); update_line(); :}
;
feature_list
::=
feature:f _semi:_line
{: RESULT = (new Features(_line)).appendElement(f); update_line(); :}
| feature_list:fl feature:f _semi
{: RESULT = fl.appendElement(f); :}
| error _semi
{: RESULT = new Features(0); update_line(); :}
;
formal
::=
/* ID : TYPE */
OBJECTID:id _colon:_line TYPEID:type
{: RESULT = new formalc (_line, id, type) ; update_line(); :}
;
formal_list
::= formal:f
{: RESULT = (new Formals(line)).appendElement(f); update_line(); :}
| formal_list:fl _comma formal:f
{: RESULT = fl.appendElement(f); :}
| error _semi
{: RESULT = new Formals(0); update_line(); :}
| error
{: RESULT = new Formals(0); update_line(); :}
;
expression_list_semi
/* single expression */
::= expression:e _semi:_line
{: RESULT = (new Expressions(e.getLineNumber())).appendElement(e); update_line(); :}
/* multiple expressions */
| expression_list_semi:el expression:e _semi:_line
{: RESULT = el.appendElement(e); :}
;
expression_list_comma
::= expression:e
{: RESULT = (new Expressions(e.getLineNumber())).appendElement(e); update_line(); :}
| expression_list_comma:el _comma:_line expression:e
{: RESULT = el.appendElement(e); :}
;
nested_let
::=
/* , ID : TYPE <- expr in expr */
_comma OBJECTID:id _colon:_line TYPEID:type _assign expression:e1 _in expression:e2
{: RESULT = new let(_line, id, type, e1, e2); update_line(); :}
/* , ID : TYPE in expr */
| _comma OBJECTID:id _colon:_line TYPEID:type _in expression:e
{: RESULT = new let(_line, id, type, new no_expr(0), e); update_line(); :}
/* , ID : TYPE <- expr , ... */
| _comma OBJECTID:id _colon:_line TYPEID:type _assign expression:e1 nested_let:e2
{: RESULT = new let(_line, id, type, e1, e2); update_line(); :}
/* , ID : TYPE , ... */
| _comma OBJECTID:id _colon:_line TYPEID:type nested_let:e
{: RESULT = new let(_line, id, type, new no_expr(0), e); update_line(); :}
/* error handling */
| error nested_let:e2
{: update_line(); :}
| error _in
{: update_line(); :}
| error _assign expression nested_let:e
{: update_line(); :}
| error _assign expression _in expression:e
{: update_line(); :}
| error _colon _assign expression nested_let:e
{: update_line(); :}
| error _colon _assign expression _in expression:e
{: update_line(); :}
| _comma error nested_let:e2
{: update_line(); :}
| _comma error _in
{: update_line(); :}
| _comma error _assign expression nested_let:e
{: update_line(); :}
| _comma error _assign expression _in expression:e
{: update_line(); :}
| _comma error _colon _assign expression nested_let:e
{: update_line(); :}
| _comma error _colon _assign expression _in expression:e
{: update_line(); :}
| _comma OBJECTID:id error nested_let:e
{: update_line(); :}
| _comma OBJECTID:id error _in
{: update_line(); :}
;
single_case
::=
/* ID : TYPE => expr; */
OBJECTID:id _colon:_line TYPEID:type _darrow expression:e _semi
{: RESULT = new branch(_line, id, type, e); update_line(); :}
;
case_list
/* Single case */
::= single_case:sc
{: RESULT = (new Cases(sc.getLineNumber())).appendElement(sc); update_line(); :}
/* multiple cases */
| case_list:cl single_case:sc
{: RESULT = cl.appendElement(sc); :}
;
_block
::=
/* { [[expr; ]] + } */
_lbrace:_line expression_list_semi:els _rbrace
{: RESULT = new block(_line, els); update_line(); :}
/* error handling */
| error
{: RESULT = new block(0, new Expressions(0)); update_line(); :}
;
expression
::=
/* ID <- expr */
OBJECTID:id _assign:_line expression:e
{: RESULT = new assign(_line, id, e) ; update_line(); :}
/* expr.ID() */
| expression:e1 _dot:_line OBJECTID:id _lparen:_line1 _rparen
{: RESULT = new dispatch(_line, e1, id, new Expressions(_line1) ) ; update_line(); :}
/* expr@TYPE.ID() */
| expression:e1 _at TYPEID:type _dot:_line OBJECTID:id _lparen:_line1 _rparen
{: RESULT = new static_dispatch(_line, e1, type, id, new Expressions(_line1)); update_line(); :}
/* expr.ID([[ expr ]]+ ) */
| expression:e1 _dot:_line OBJECTID:id _lparen expression_list_comma:el _rparen
{: RESULT = new dispatch(_line, e1, id, el); update_line(); :}
/* expr@TYPE.ID([[ expr ]]+ ) */
| expression:e1 _at TYPEID:type _dot:_line OBJECTID:id _lparen expression_list_comma:el _rparen
{: RESULT = new static_dispatch(_line, e1, type, id, el); update_line(); :}
/* ID() */
| OBJECTID:id _lparen:_line _rparen
{: RESULT = new dispatch(_line, new object(_line, AbstractTable.idtable.addString("self")), id, new Expressions(_line)); update_line(); :}
/* ID([[ expr ]]+ ) */
| OBJECTID:id _lparen:_line expression_list_comma:el _rparen
{: RESULT = new dispatch(_line, new object(_line, AbstractTable.idtable.addString("self")), id, el); update_line(); :}
/* IF expr THEN expr ELSE expr FI */
| _if:_line expression:e1 _then expression:e2 _else expression:e3 _fi
{: RESULT = new cond(_line, e1,e2,e3); update_line(); :}
/* WHILE expr LOOP expr POOL */
| _while:_line expression:e1 _loop expression:e2 _pool
{: RESULT = new loop(_line, e1, e2); update_line(); :}
/* { [[expr; ]] + } */
| _block:b
{: RESULT = b; update_line(); :}
/* LET ID : TYPE <- expr in expr */
| _let OBJECTID:id _colon:_line TYPEID:type _assign expression:e1 _in expression:e2
{: RESULT = new let(_line, id, type, e1, e2); update_line(); :}
/* LET ID : TYPE in expr */
| _let OBJECTID:id _colon:_line TYPEID:type _in expression:e
{: RESULT = new let(_line, id, type, new no_expr(0), e); update_line(); :}
/* LET ID : TYPE <- expr [[ NESTED_LET ]]+ */
| _let OBJECTID:id _colon:_line TYPEID:type _assign expression:e1 nested_let:e2
{: RESULT = new let(_line, id, type, e1, e2); update_line(); :}
/* LET ID : TYPE [[ NESTED_LET ]]+ */
| _let OBJECTID:id _colon:_line TYPEID:type nested_let:e
{: RESULT = new let(_line, id, type, new no_expr(0), e); update_line(); :}
/* error handling */
| _let error _in
{: update_line(); :}
| _let error nested_let:e
{: update_line(); :}
| error _assign expression nested_let:e
{: update_line(); :}
/* CASE expr OF [[ID : TYPE => expr; ]]+ ESAC */
| _case:_line expression:e _of case_list:cl _esac
{: RESULT = new typcase (_line, e, cl); update_line(); :}
/*
we need %prec OPER because we need to define precedence among symbols w/ equal precedence
for example:
let consider: a - d * (a / d) = 0
this expr should produce the following sub-tree:
EQ
|____SUB
| |_____ a
| |_____ MUL
| |_____ d
| |_____ DIV
| |______ a
| |______ d
|
|____ 0
but w/o %prec it would produce this wrong sub-tree:
SUB
|____MUL
| |_____ d
| |_____ EQ
| |_____ 0
| |_____ DIV
| |______ a
| |______ d
|
|____ a
But why?
* To each production that contains at least one terminal
defined as operator, Cup associates the precedence and
associativity of the rightmost operator.
* If the rule is followed by the keyword %prec, the
precedence and associativity are those of the specified
operator.
* In the case of a shift-reduce conflict, the action
corresponding to the highest precedence production is
executed.
* In the case of a shift-reduce conflict, the action
corresponding to the highest precedence production is
executed.
*/
/* expr + expr */
| expression:e1 _plus:_line expression:e2
{: RESULT = new plus (_line, e1, e2); update_line(); :}
%prec PLUS
/* expr - expr */
| expression:e1 _minus:_line expression:e2
{: RESULT = new sub (_line, e1, e2) ; update_line(); :}
%prec MINUS
/* expr * expr */
| expression:e1 _mult:_line expression:e2
{: RESULT = new mul (_line, e1, e2) ; update_line(); :}
%prec MULT
/* expr / expr */
| expression:e1 _div:_line expression:e2
{: RESULT = new divide (_line, e1, e2); update_line(); :}
%prec DIV
/* expr < expr */
| expression:e1 _lt:_line expression:e2
{: RESULT = new lt (_line, e1, e2); update_line(); :}
/* expr <= expr */
| expression:e1 _le:_line expression:e2
{: RESULT = new leq (_line, e1, e2); update_line(); :}
/* expr = expr */
| expression:e1 _eq:_line expression:e2
{: RESULT = new eq (_line, e1, e2); update_line(); :}
/* ~ expr */
| _neg:_line expression:e
{: RESULT = new neg (_line, e); update_line(); :}
%prec NEG
/* NOT expr */
| _not:_line expression:e
{: RESULT = new comp(_line, e); update_line(); :}
%prec NOT
/* (expr) */
| _lparen:_line expression:e _rparen
{: RESULT = e; update_line(); :}
/* ID */
| OBJECTID:id
{: RESULT = new object(line, id); update_line(); :}
| error OBJECTID:id
{: RESULT = new object(line, id); update_line(); :}
/* integer const */
| INT_CONST:i
{: RESULT = new int_const(line, i); update_line(); :}
/* string const */
| STR_CONST:string
{: RESULT = new string_const(line, string); update_line(); :}
/* true|false */
| BOOL_CONST:b
{: RESULT = new bool_const(line, b); update_line(); :}
/* ISVOID expr */
| _isvoid:_line expression:e
{: RESULT = new isvoid (_line, e); update_line(); :}
/* NEW TYPE */
| _new:_line TYPEID:type
{: RESULT = new new_(_line, type); update_line(); :}
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment