6161 DOT " ."
6262 LBRAK " ["
6363 RBRAK " ]"
64+ LCURL " {"
65+ RCURL " }"
6466 ;
6567
6668%token <std::string> ID SUBID UNKNOWN ;
7678%nterm <std::pair<Expression*,Tree*> > ElseIf
7779%nterm <std::vector<std::pair<Expression*,Tree*> >> ElseIfs
7880%nterm <std::vector<std::pair<std::string,ExpI> >> Fields Params
79- %nterm <std::vector<Expression*> > Array Args
81+ %nterm <std::vector<Expression*> > Args
8082%nterm <std::vector<std::variant<Expression *,std::vector<Expression*> >>> Array2
8183
8284%left OR
@@ -201,6 +203,24 @@ Stmnt : EOL { $$ = new Empty; prev->link($$); prev = $$; }
201203 YYERROR ;
202204 }
203205 }
206+ | ID ASSIGN ID LCURL Args RCURL EOL {
207+ if ($5 .size() != std::get<RecordT>(table->value ($3 )).size()) {
208+ error (@2 , " wrong number of fields for record type: " + $3 );
209+ YYERROR;
210+ }
211+ std::vector<std::string> fields;
212+ for (int i = 0 ; auto & e : $5 ) {
213+ if (e->type () != table->fieldtype($3 , i)) {
214+ error (@2 , " wrong type(s) of field value(s) for record type: " + $3 );
215+ YYERROR;
216+ }
217+ fields.push_back(table->fieldname ($3 , i++));
218+ }
219+ table->store ($1 , ExpT{ ObjectT{ $3 } });
220+ $$ = new ObjectAssign(std::move(fields), $1 , std::move($5 ));
221+ prev->link ($$);
222+ prev = $$ ;
223+ }
204224 | ID LBRAK Exp RBRAK ASSIGN Exp EOL {
205225 if ($3 ->type () != ExpI::IntT) {
206226 error (@3 , " array index must be IntExp" );
@@ -252,10 +272,12 @@ Stmnt : EOL { $$ = new Empty; prev->link($$); prev = $$; }
252272 $5 ->link ($$);
253273 prev = $$ ;
254274 }
255- | OUTPUT Exp EOL {
256- if ($2 ->type () != ExpI::StringT) {
257- error (@2 , " expression to output must be a StringExp" );
258- YYERROR;
275+ | OUTPUT Args EOL {
276+ for (auto & exp : $2 ) {
277+ if (exp->type () != ExpI::StringT) {
278+ error (@2 , " expression to output must be a StringExp" );
279+ YYERROR;
280+ }
259281 }
260282 $$ = new Output($2 );
261283 prev->link ($$);
@@ -307,16 +329,30 @@ Stmnt : EOL { $$ = new Empty; prev->link($$); prev = $$; }
307329 YYERROR;
308330 }
309331 table->store ($2 , ExpT{ $4 });
310- $$ = new Assign (new Value ($4 ), $2 );
332+ $$ = new Empty;
333+ prev->link ($$);
334+ prev = $$;
335+ }
336+ | ID ASSIGN ID LPAREN Args RPAREN {
337+ if (!table->check ($3 ).first || table->type ($3 ) != ExpI::RecordT) {
338+ error (@3 , " no such record: " + $3 );
339+ YYERROR;
340+ }
341+ $$ = new Empty;
311342 prev->link ($$);
312343 prev = $$;
313344 }
314345 | ID DOT ID ASSIGN Exp {
315- if (!table->check ($1 ).first ) {
346+ if (!table->check ($1 ).first || table-> type ($ 1 ) != ExpI::ObjectT ) {
316347 error (@1 , " no such record: " + $1 );
317348 YYERROR;
318349 }
319- auto type = table->fieldtype ($1 , $3 );
350+ auto record_type = table->record ($1 );
351+ if (record_type.empty ()) {
352+ error (@1 , " no such record type: " + record_type);
353+ YYERROR;
354+ }
355+ auto type = table->fieldtype (record_type, $3 );
320356 if (type == ExpI::None) {
321357 error (@3 , " no such field: " + $3 );
322358 YYERROR;
@@ -347,7 +383,6 @@ Stmnt : EOL { $$ = new Empty; prev->link($$); prev = $$; }
347383 }
348384 | SubCall Args RPAREN EOL {
349385 if ($2 .size () != table->types ($1 ).first .size ()) {
350- std::cerr << $2 .size () << ' ' << table->types ($1 ).first .size () << ' \n ' ;
351386 error (@2 , " wrong number of arguments for call to subroutine: " + $1 );
352387 YYERROR;
353388 }
@@ -458,21 +493,16 @@ SubCall : SUBID {
458493 }
459494 ;
460495
461- Args : Args COMMA Exp { $$ = $ 1 ; $$. push_back ($ 3 ) ; }
496+ Args : %empty { $$ = {} ; }
462497 | Exp { $$.push_back ($1 ); }
463- | %empty { $$ = {}; }
464- ;
465-
466- Array : %empty { $$ = {}; }
467- | Exp { $$.push_back ($1 ); }
468- | Array COMMA Exp { $$ = $1 ; $$.push_back ($3 ); }
498+ | Args COMMA Exp { $$ = $1 ; $$.push_back ($3 ); }
469499 ;
470500
471501Array2 : %empty { $$ = {}; }
472502 | Exp { $$.push_back ($1 ); }
473503 | Array2 COMMA Exp { $$ = $1 ; $$.push_back ($3 ); }
474- | LBRAK Array RBRAK { $$.push_back ($2 ); }
475- | Array2 COMMA LBRAK Array RBRAK { $$ = $1 ; $$.push_back ($4 ); }
504+ | LBRAK Args RBRAK { $$.push_back ($2 ); }
505+ | Array2 COMMA LBRAK Args RBRAK { $$ = $1 ; $$.push_back ($4 ); }
476506 ;
477507
478508BoolExp : Exp {
@@ -503,16 +533,21 @@ Exp : STRING { $$ = new Value($1); }
503533 }
504534 }
505535 | ID DOT ID {
506- if (!table->check ($1 ).first ) {
536+ if (!table->check ($1 ).first || table-> type ($ 1 ) != ExpI::ObjectT ) {
507537 error (@1 , " no such record: " + $1 );
508538 YYERROR;
509539 }
510- auto type = table->fieldtype ($1 , $3 );
540+ auto record_type = table->record ($1 );
541+ if (record_type.empty ()) {
542+ error (@1 , " no such record type: " + record_type);
543+ YYERROR;
544+ }
545+ auto type = table->fieldtype (record_type, $3 );
511546 if (type == ExpI::None) {
512547 error (@3 , " no such field: " + $3 );
513548 YYERROR;
514549 }
515- $$ = new Variable (table->fieldtype ($ 1 , $3 ), $1 + ' .' + $3 );
550+ $$ = new Variable (table->fieldtype (record_type , $3 ), $1 + ' .' + $3 );
516551 }
517552 | ID LBRAK Exp RBRAK { $$ = new Element ($1 , $3 , std::get<ExpI>(std::get<Array2T>(table->value ($1 )).at (0 ))); }
518553 | ID LBRAK Exp RBRAK LBRAK Exp RBRAK { $$ = new Element2 ($1 , $3 , $6 , std::get<ArrayT>(std::get<Array2T>(table->value ($1 )).at (0 )).at (0 )); }
@@ -536,7 +571,6 @@ Exp : STRING { $$ = new Value($1); }
536571 | USERINPUT { $$ = new UserInput (); }
537572 | SubCall Args RPAREN {
538573 if ($2 .size () != table->types ($1 ).first .size ()) {
539- std::cerr << $2 .size () << ' ' << table->types ($1 ).first .size () << ' \n ' ;
540574 error (@2 , " wrong number of arguments for call to subroutine: " + $1 );
541575 YYERROR;
542576 }
@@ -635,7 +669,7 @@ Exp : STRING { $$ = new Value($1); }
635669%%
636670
637671void yy::Parser::error(const location_type& loc, const std::string &e) {
638- *err << "Location " << loc.begin.line << ':' << loc.begin.column;
672+ *err << loc.begin.line << ':' << loc.begin.column;
639673 if (loc.end.line != loc.begin.line) {
640674 *err << '-' << loc.end.line << ':' << loc.end.column - 1;
641675 }
0 commit comments