diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index f6abdda..fb1f495 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -130,6 +130,18 @@ action code {: return new ComplexSymbolFactory.Location(first.getLocation()[0], first.getLocation()[1]); } + + /** Return the rightmost non-whitespace location in NODES, or null if NODES + * is empty. Assumes that the nodes of NODES are ordered in increasing + * order of location, from left to right. */ + ComplexSymbolFactory.Location getRight(List nodes) { + if (nodes.isEmpty()) { + return null; + } + Node last = nodes.get(nodes.size()-1); + return new ComplexSymbolFactory.Location(last.getLocation()[2], + last.getLocation()[3]); + } :} @@ -213,6 +225,7 @@ terminal String RBR; terminal String ARROW; terminal String IS; + /* Returned by the lexer for erroneous tokens. Since it does not appear in * the grammar, it indicates a syntax error. */ terminal UNRECOGNIZED; @@ -223,10 +236,22 @@ terminal UNRECOGNIZED; * defines the listed nonterminal identifier symbols to have semantic values * of type . */ non terminal Program program; -non terminal List program_head; +non terminal List program_head, class_body, class_body_defs, fun_body_decs; non terminal List stmt_list, opt_stmt_list; non terminal Stmt stmt, expr_stmt; non terminal Expr expr, binary_expr; +non terminal VarDef var_def; +non terminal ClassDef class_def; +non terminal FuncDef fun_def; +non terminal Literal literal; +non terminal TypedVar typed_var; +non terminal TypeAnnotation type, ret_type; +non terminal Identifier identifier; +non terminal List typed_vars; +non terminal GlobalDecl global_decl; +non terminal NonLocalDecl nonlocal_decl; + + /* Precedences (lowest to highest) for resolving what would otherwise be * ambiguities in the form of shift/reduce conflicts.. */ @@ -244,16 +269,97 @@ start with program; /***** GRAMMAR RULES *****/ +/* Rules are defined in the order given by the language reference */ + +/* program */ program ::= program_head:d opt_stmt_list:s {: RESULT = new Program(d.isEmpty() ? getLeft(s) : getLeft(d), sxright, d, s, errors); :} ; -/* Initial list of declarations. */ -program_head ::= /* not implemented; currently matches empty string */ - {: RESULT = empty(); :} +program_head ::= program_head:d var_def:vd {: RESULT = combine(d, vd); :} + | program_head:d class_def:cd {: RESULT = combine(d, cd); :} + | program_head:d fun_def:fd {: RESULT = combine(d, fd); :} + | program_head:d error:e {: RESULT = d; :} + | {: RESULT = empty(); :} + ; + + +/* class_def */ +class_def ::= CLASS:c identifier:id LPAR identifier:parentId RPAR COLON NEWLINE INDENT class_body:cb DEDENT {: RESULT = new ClassDef(cxleft, getRight(cb), id, parentId, cb); :}; + + +/* class_body */ +class_body ::= PASS NEWLINE {: RESULT = empty(); :} + | class_body_defs:defs {: RESULT = defs; :} + ; + +class_body_defs ::= class_body_defs:defs var_def:vd {: RESULT = combine(defs, vd); :} + | class_body_defs:defs fun_def:fd {: RESULT = combine(defs, fd); :} + | class_body_defs:defs error {: RESULT = defs; :} + | var_def:vd {: RESULT = single(vd); :} + | fun_def:fd {: RESULT = single(fd); :} + ; + + +/* fun_def */ +fun_def ::= DEF:def identifier:id LPAR typed_vars:params RPAR ret_type:rt COLON NEWLINE INDENT fun_body_decs:fbd stmt_list:sl DEDENT + {: RESULT = new FuncDef(defxleft, getRight(sl), id, params, rt, fbd, sl); :} + ; + +ret_type ::= ARROW type:t {: RESULT= t; :} + | {: RESULT= null; :} + ; + +typed_vars ::= typed_var:tv {: RESULT= single(tv); :} + | typed_vars:tvs COMMA typed_var:tv {: RESULT= combine(tvs, tv); :} + | typed_vars:tvs COMMA error {: RESULT= tvs; :} + | {: RESULT= empty(); :} + ; + + + +/* fun_body */ +fun_body_decs ::= fun_body_decs:fbd global_decl:gd {: RESULT= combine(fbd, gd); :} + | fun_body_decs:fbd nonlocal_decl:nd {: RESULT= combine(fbd, nd); :} + | fun_body_decs:fbd var_def:vd {: RESULT= combine(fbd, vd); :} + | fun_body_decs:fbd fun_def:fd {: RESULT= combine(fbd, fd); :} + | fun_body_decs:fbd error {: RESULT= fbd; :} + | {: RESULT= empty(); :} ; + + +/* typed_var */ +typed_var ::= identifier:id COLON type:t {: RESULT = new TypedVar(idxleft, txright, id, t); :}; + + +/* type */ +type ::= identifier:id {: RESULT = new ClassType(idxleft, idxright, id.name); :} + | STRING:str {: RESULT = new ClassType(strxleft, strxright, str); :} + | LBR:lbr type:t RBR:rbr {: RESULT = new ListType(lbrxleft, rbrxright, t); :} + ; + + +/* global_decl */ +global_decl ::= GLOBAL:g identifier:id NEWLINE {: RESULT = new GlobalDecl(gxleft, idxright, id); :}; + + +/* nonlocal_decl */ +nonlocal_decl ::= NONLOCAL:n identifier:id NEWLINE {: RESULT = new NonLocalDecl(nxleft, idxright, id); :}; + + +/* var_def */ +var_def ::= typed_var:t ASSIGN literal:l NEWLINE {: RESULT = new VarDef(txleft, lxright, t, l); :}; + + +/* literal */ +literal ::= NONE:n {: RESULT = new NoneLiteral(nxleft, nxright); :} + | BOOL:b {: RESULT = new BooleanLiteral(bxleft, bxright, b); :} + | NUMBER:n {: RESULT = new IntegerLiteral(nxleft, nxright, n); :} + | STRING:s {: RESULT = new StringLiteral(sxleft, sxright, s); :} + ; + opt_stmt_list ::= {: RESULT = empty(); :} | stmt_list:s {: RESULT = s; :} @@ -286,3 +392,7 @@ binary_expr ::= expr:e1 PLUS:op expr:e2 {: RESULT = new BinaryExpr(e1xleft, e2xright, e1, op, e2); :} ; + + +/* Extras - rules below have not been given in language reference, we have them to ease implementation */ +identifier ::= ID:idStr {: RESULT = new Identifier(idStrxleft, idStrxright, idStr); :};