diff --git a/assignments/PA3/cool.y b/assignments/PA3/cool.y index 16f1dab..2760cc9 100644 --- a/assignments/PA3/cool.y +++ b/assignments/PA3/cool.y @@ -135,9 +135,34 @@ %type class /* You will want to change the following line. */ - %type dummy_feature_list + %type feature_list + %type feature + %type formal_list + %type formal + %type expression_list_comma + %type expression_list_colon + %type expression + %type case_list + %type case + %type nested_let + /* Precedence declarations go here. */ + /* No need to specify then-else precedence, the silly language forbids omitting else */ + /* %precedence THEN + %precedence ELSE */ + /* all other binary operations are left-associative + * assignment is right-associative, + * three comparison operations do not associate.*/ + %right ASSIGN + %left NOT + %nonassoc '<' LE '=' + %left '+' '-' + %left '*' '/' + %precedence ISVOID + %precedence '~' + %precedence '@' + %precedence '.' %% @@ -154,21 +179,142 @@ | class_list class /* several classes */ { $$ = append_Classes($1,single_Classes($2)); parse_results = $$; } + /* TODO: I guess `parse_results` is only needed in the top-most class_list*/ ; /* If no parent is specified, the class inherits from the Object class. */ - class : CLASS TYPEID '{' dummy_feature_list '}' ';' + class : CLASS TYPEID '{' feature_list '}' ';' { $$ = class_($2,idtable.add_string("Object"),$4, stringtable.add_string(curr_filename)); } - | CLASS TYPEID INHERITS TYPEID '{' dummy_feature_list '}' ';' + | CLASS TYPEID INHERITS TYPEID '{' feature_list '}' ';' { $$ = class_($2,$4,$6,stringtable.add_string(curr_filename)); } ; /* Feature list may be empty, but no empty features in list. */ - dummy_feature_list: /* empty */ + feature_list: /* empty */ { $$ = nil_Features(); } + | feature ';' + { $$ = single_Features($1); } + | feature_list feature ';' + { $$ = append_Classes($1, single_Features($2)); } + ; + feature : OBJECTID ':' TYPEID + /* Use no expr where optional expression omitted*/ + { $$ = attr($1, $3, no_expr()); } + | OBJECTID ':' TYPEID ASSIGN expression + { $$ = attr($1, $3, $5); } + | OBJECTID '(' formal_list ')' ':' TYPEID '{' expression '}' + { $$ = method($1, $3, $6, $8); } + ; + formal_list : /* empty */ + { $$ = nil_Formals(); } + | formal + { $$ = single_Formals($1); } + | formal_list ',' formal /* a little different from classlist */ + { $$ = append_Formals($1, single_Formals($3)); } + ; + + formal : OBJECTID ':' TYPEID + { $$ = formal($1, $3); } + ; + + expression_list_comma : /* TODO Perhaps empty expr_list should not be valid? */ + { $$ = nil_Expressions(); } + | expression + { $$ = single_Expressions($1); } + | expression_list_comma ',' expression + { $$ = append_Expressions($1, single_Expressions($3)); } + ; + + expression_list_colon : /* TODO Perhaps empty expr_list should not be valid? */ + { $$ = nil_Expressions(); } + | expression ';' + { $$ = single_Expressions($1); } + | expression_list_colon expression ';' + { $$ = append_Expressions($1, single_Expressions($2)); } + ; + + expression : OBJECTID ASSIGN expression + { $$ = assign($1, $3); } + /* expr[@TYPE].ID([expr[[,expr]]*]) */ + | expression '.' OBJECTID '(' expression_list_comma ')' + { $$ = dispatch($1, $3, $5); } + /* Only in the case of @TYPE, we use static dispatch*/ + | expression '@' TYPEID '.' OBJECTID '(' expression_list_comma ')' + { $$ = static_dispatch($1, $3, $5, $7); } + /* Actually, `ID( [ expr [[, expr]]∗ ])` is self omitted, so add it in parsing */ + | OBJECTID '(' expression_list_comma ')' + { $$ = dispatch(object(idtable.add_string("self")), $1, $3); } + | IF expression THEN expression ELSE expression FI + { $$ = cond($2, $4, $6); } + | WHILE expression LOOP expression POOL + { $$ = loop($2, $4); } + | '{' expression_list_colon '}' + { $$ = block($2); } + /* TODO let expr */ + /* [manual-P21, tour-section6.5] + * The let constructor only allows one identifier. + * When parsing a let with multiple idents, it should be transformed into nested lets + */ + | LET nested_let + { $$ = $2; } + | CASE expression OF case_list ESAC + { $$ = typcase($2, $4); } + | NEW TYPEID + { $$ = new_($2); } + | ISVOID expression + { $$ = isvoid($1); } + /* the rules below need precedence specification */ + | expression '+' expression + { $$ = plus($1, $3); } + | expression '-' expression + { $$ = sub($1, $3); } + | expression '*' expression + { $$ = mul($1, $3); } + | expression '/' expression + { $$ = divide($1, $3); } + | '~' expression + { $$ = beg($2); } + | expression '<' expression + { $$ = lt($1, $3); } + | expression LE expression + { $$ = leq($1, $3); } + | expression '=' expression + { $$ = eq($1, $3); } + | NOT expression + { $$ = comp($2); } + | '(' expression ')' + { $$ = $2; } + | OBJECTID + { $$ = object($1); } + | INT_CONST + { $$ = int_const($1); } + | STR_CONST + { $$ = string_const($1); } + | BOOL_CONST + { $$ = bool_const($1); } + ; + + case_list : case ';' + { $$ = single_Cases($1); } + | case_list case ';' + { $$ = append_Casess($1, single_Cases($2)); } + ; + + case : OBJECTID ':' TYPEID DARROW expression + { $$ = branch($1, $3, $5); } + ; + + nested_let: OBJECTID ':' TYPEID ',' nested_let + { $$ = let($1, $3, no_expr(), $5); } + | OBJECTID ':' TYPEID ASSIGN expression ',' nested_let + { $$ = let($1, $3, $5, $7); } + | nested_let OBJECTID ':' TYPEID IN expression + { $$ = let($2, $4, no_expr(), $6); } + | nested_let OBJECTID ':' TYPEID ASSIGN expression IN expression + { $$ = let($2, $4, $6, $8); } /* end of grammar */ %%