diff --git a/assignments/PA3/cool.y b/assignments/PA3/cool.y index 2760cc9..f2a22a5 100644 --- a/assignments/PA3/cool.y +++ b/assignments/PA3/cool.y @@ -159,10 +159,11 @@ %nonassoc '<' LE '=' %left '+' '-' %left '*' '/' - %precedence ISVOID - %precedence '~' - %precedence '@' - %precedence '.' + %nonassoc ISVOID + %nonassoc '~' + %nonassoc '@' + %nonassoc '.' + %left LETEXPR %% @@ -188,15 +189,15 @@ stringtable.add_string(curr_filename)); } | CLASS TYPEID INHERITS TYPEID '{' feature_list '}' ';' { $$ = class_($2,$4,$6,stringtable.add_string(curr_filename)); } + | CLASS TYPEID INHERITS TYPEID '{' '}' ';' + { $$ = class_($2,$4,nil_Features(),stringtable.add_string(curr_filename)); } ; /* Feature list may be empty, but no empty features in list. */ - feature_list: /* empty */ - { $$ = nil_Features(); } - | feature ';' + feature_list : feature ';' { $$ = single_Features($1); } | feature_list feature ';' - { $$ = append_Classes($1, single_Features($2)); } + { $$ = append_Features($1, single_Features($2)); } ; feature : OBJECTID ':' TYPEID @@ -206,11 +207,12 @@ { $$ = attr($1, $3, $5); } | OBJECTID '(' formal_list ')' ':' TYPEID '{' expression '}' { $$ = method($1, $3, $6, $8); } + | OBJECTID '(' ')' ':' TYPEID '{' expression '}' + { $$ = method($1, nil_Formals(), $5, $7); } ; - formal_list : /* empty */ - { $$ = nil_Formals(); } - | formal + formal_list + : formal { $$ = single_Formals($1); } | formal_list ',' formal /* a little different from classlist */ { $$ = append_Formals($1, single_Formals($3)); } @@ -220,17 +222,15 @@ { $$ = formal($1, $3); } ; - expression_list_comma : /* TODO Perhaps empty expr_list should not be valid? */ - { $$ = nil_Expressions(); } - | expression + expression_list_comma + : 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 ';' + expression_list_colon + : expression ';' /* the only usage `{ [[expr; ]]+}` says one or more exprs needed, so no empty option*/ { $$ = single_Expressions($1); } | expression_list_colon expression ';' { $$ = append_Expressions($1, single_Expressions($2)); } @@ -241,23 +241,36 @@ /* expr[@TYPE].ID([expr[[,expr]]*]) */ | expression '.' OBJECTID '(' expression_list_comma ')' { $$ = dispatch($1, $3, $5); } + | expression '.' OBJECTID '(' ')' + { $$ = dispatch($1, $3, nil_Expressions()); } /* Only in the case of @TYPE, we use static dispatch*/ | expression '@' TYPEID '.' OBJECTID '(' expression_list_comma ')' { $$ = static_dispatch($1, $3, $5, $7); } + | expression '@' TYPEID '.' OBJECTID '(' ')' + { $$ = static_dispatch($1, $3, $5, nil_Expressions()); } /* Actually, `ID( [ expr [[, expr]]∗ ])` is self omitted, so add it in parsing */ | OBJECTID '(' expression_list_comma ')' { $$ = dispatch(object(idtable.add_string("self")), $1, $3); } + | OBJECTID '(' ')' + { $$ = dispatch(object(idtable.add_string("self")), $1, nil_Expressions()); } | 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 */ + /* It is not any obvious to me where the shift-reduce conflict lies. + * Try `bison -Wcounterexample {OTHERFLAGS} cool.y > counterexample.txt 2>&1` + * Thanks to the examples, one possible situation could be: let id1:T1 in expression.f() + * there could be 2 interpretations: (let id1:T1 in expression).f() | let id1:T1 in (expression.f()) + * This should be specified to dis-ambiguite + * + * The manual says, the expr extends as far as possible + */ | LET nested_let { $$ = $2; } | CASE expression OF case_list ESAC @@ -265,7 +278,7 @@ | NEW TYPEID { $$ = new_($2); } | ISVOID expression - { $$ = isvoid($1); } + { $$ = isvoid($2); } /* the rules below need precedence specification */ | expression '+' expression { $$ = plus($1, $3); } @@ -276,7 +289,7 @@ | expression '/' expression { $$ = divide($1, $3); } | '~' expression - { $$ = beg($2); } + { $$ = neg($2); } | expression '<' expression { $$ = lt($1, $3); } | expression LE expression @@ -300,21 +313,23 @@ case_list : case ';' { $$ = single_Cases($1); } | case_list case ';' - { $$ = append_Casess($1, single_Cases($2)); } + { $$ = append_Cases($1, single_Cases($2)); } ; case : OBJECTID ':' TYPEID DARROW expression { $$ = branch($1, $3, $5); } ; - nested_let: OBJECTID ':' TYPEID ',' nested_let + 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); } + | OBJECTID ':' TYPEID IN expression %prec LETEXPR + { $$ = let($1, $3, no_expr(), $5); } + | OBJECTID ':' TYPEID ASSIGN expression IN expression %prec LETEXPR + { $$ = let($1, $3, $5, $7); } + ; /* end of grammar */ %%