8000 Added RECORD initialisation of variables (using curly braces) with ch… · cpp-tutor/pseudocode-compiler@e28f801 · GitHub
[go: up one dir, main page]

Skip to content

Commit e28f801

Browse files
committed
Added RECORD initialisation of variables (using curly braces) with checked member selection for field modification and querying
1 parent ffa5c4e commit e28f801

File tree

4 files changed

+129
-43
lines changed

4 files changed

+129
-43
lines changed

Expression.hpp

100644100755
Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,22 +102,22 @@ class ExpressionOp : public Expression {
102102
output << apply();
103103
}
104104
else {
105-
if (left && right) {
106-
if (op == Operator::DIV) {
107-
output << "Math.floor";
108-
}
109-
output << '(';
110-
left->emit();
111-
output << ' ' << valid_ops.at(op).first << ' ';
112-
right->emit();
113-
output << ')';
114-
}
115-
else if (left) {
116-
output << '(';
117-
output << valid_ops.at(op).first;
118-
left->emit();
119-
output << ')';
120-
}
105+
if (left && right) {
106+
if (op == Operator::DIV) {
107+
output << "Math.floor";
108+
}
109+
output << '(';
110+
left->emit();
111+
output << ' ' << valid_ops.at(op).first << ' ';
112+
right->emit();
113+
output << ')';
114+
}
115+
else if (left) {
116+
output << '(';
117+
output << valid_ops.at(op).first;
118+
left->emit();
119+
output << ')';
120+
}
121121
}
122122
}
123123
virtual ExpT apply() override {
@@ -281,6 +281,28 @@ class ArrayAssign : public Tree {
281281
}
282282
};
283283

284+
class ObjectAssign : public Tree {
285+
std::vector<std::string> fields;
286+
std::string label;
287+
std::vector<Expression *> values;
288+
public:
289+
ObjectAssign(std::vector<std::string>&& f, std::string_view l, std::vector<Expression *>&& v)
290+
: Tree(nullptr, nullptr), fields{ f }, label{ l }, values{ v } {}
291+
virtual void emit() override {
292+
size_t v{ 0 };
293+
output << indent << label << " = { ";
294+
for (auto sep = ""; auto& f : fields) {
295+
output << sep << f << ": ";
296+
values.at(v++)->emit();
297+
sep = ", ";
298+
}
299+
output << " };\n";
300+
if (right) {
301+
right->emit();
302+
}
303+
}
304+
};
305+
284306
class ElementAssign : public Tree {
285307
std::string label;
286308
Expression *index;

Symbol.hpp

100644100755
Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class Symbol {
1919
}
2020
else if (iter->second.index() == 2) {
2121
if (std::get<ExpI>(iter->second) != std::get<ExpI>(value)) {
22-
throw std::runtime_error("attempt assign with different type");
22+
throw std::runtime_error("attempt to assign with different type");
2323
}
2424
}
2525
}
@@ -101,6 +101,33 @@ class Symbol {
101101
}
102102
return ExpI::None;
103103
}
104+
ExpI fieldtype(const std::string& label, size_t field) {
105+
if (auto iter = SymTab.find(subroutine + '.' + label); iter != SymTab.end()) {
106+
if ((iter->second.index() == 1) && (static_cast<ExpI>(std::get<ExpT>(iter->second).index()) == ExpI::RecordT)) {
107+
const auto& recfield = std::get<RecordT>(std::get<ExpT>(iter->second));
108+
return recfield.at(field).second;
109+
}
110+
}
111+
return ExpI::None;
112+
}
113+
std::string fieldname(const std::string& label, size_t field) {
114+
if (auto iter = SymTab.find(subroutine + '.' + label); iter != SymTab.end()) {
115+
if ((iter->second.index() == 1) && (static_cast<ExpI>(std::get<ExpT>(iter->second).index()) == ExpI::RecordT)) {
116+
const auto& recfield = std::get<RecordT>(std::get<ExpT>(iter->second));
117+
return recfield.at(field).first;
118+
}
119+
}
120+
return "";
121+
}
122+
std::string record(const std::string& label) {
123+
if (auto iter = SymTab.find(subroutine + '.' + label); iter != SymTab.end()) {
124+
if ((iter->second.index() == 1) && (static_cast<ExpI>(std::get<ExpT>(iter->second).index()) == ExpI::ObjectT)) {
125+
const auto& obj = std::get<ObjectT>(std::get<ExpT>(iter->second));
126+
return static_cast<std::string>(obj);
127+
}
128+
}
129+
return "";
130+
}
104131
ExpI arraytype(const std::string& label) {
105132
if (auto iter = SymTab.find(subroutine + '.' + label); iter != SymTab.end()) {
106133
if ((iter->second.index() == 1) && (static_cast<ExpI>(std::get<ExpT>(iter->second).index()) == ExpI::Array2T)) {
@@ -142,7 +169,7 @@ class Decls : public Tree {
142169
if (s.second.index() == 2) {
143170
vars.push_back(s.first.substr(subroutine.length() + 1));
144171
}
145-
else if ((s.second.index() == 1) && (static_cast<ExpI>(std::get<ExpT>(s.second).index()) == ExpI::RecordT)) {
172+
else if ((s.second.index() == 1) && (static_cast<ExpI>(std::get<ExpT>(s.second).index()) == ExpI::ObjectT)) {
146173
vars.push_back(s.first.substr(subroutine.length() + 1));
147174
}
148175
else if ((s.second.index() == 1) && (static_cast<ExpI>(std::get<ExpT>(s.second).index()) == ExpI::Array2T)) {
@@ -182,6 +209,7 @@ class Decls : public Tree {
182209
output << " = []";
183210
break;
184211
case ExpI::RecordT:
212+
case ExpI::ObjectT:
185213
output << " = {}";
186214
break;
187215
default:
@@ -215,6 +243,7 @@ inline std::ostream& operator<<(std::ostream& os, const ExpT& expr) {
215243
case ExpI::Array2T:
216244
return os << "[]";
217245
case ExpI::RecordT:
246+
case ExpI::ObjectT:
218247
os << "{ ";
219248
for (auto sep = ""; const auto& field : std::get<RecordT>(expr)) {
220249
os << sep << field.first + ": ";

SymbolTypes.hpp

100644100755
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class String : public std::string {
88
: std::string(std::forward<Args>(args)...) {}
99
};
1010

11-
enum class ExpI { None, BoolT, IntT, RealT, StringT, ArrayT, Array2T, RecordT, SubroutineT };
11+
enum class ExpI { None, BoolT, IntT, RealT, StringT, ArrayT, Array2T, RecordT, ObjectT, SubroutineT };
1212

1313
const std::unordered_map<std::string,ExpI> ExpI_types{
1414
{ "Boolean", ExpI::BoolT },
@@ -23,12 +23,13 @@ using IntT = int;
2323
using RealT = double;
2424
using StringT = String;
2525
using RecordT = std::vector<std::pair<std::string,ExpI>>;
26+
using ObjectT = std::string;
2627
using SubroutineT = std::pair<std::vector<std::pair<std::string,ExpI>>,ExpI>;
2728

2829
using ArrayT = std::vector<ExpI>;
2930
using Array2T = std::vector<std::variant<ExpI,ArrayT>>;
3031

31-
using ExpT = std::variant<std::monostate,BoolT,IntT,RealT,StringT,ArrayT,Array2T,RecordT,SubroutineT>;
32+
using ExpT = std::variant<std::monostate,BoolT,IntT,RealT,StringT,ArrayT,Array2T,RecordT,ObjectT,SubroutineT>;
3233
using SymbolT = std::variant<std::monostate,ExpT,ExpI>;
3334

3435
std::ostream& operator<<(std::ostream& os, const ExpT& expr);

grammar.y

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
DOT "."
6262
LBRAK "["
6363
RBRAK "]"
64+
LCURL "{"
65+
RCURL "}"
6466
;
6567

6668
%token <std::string> ID SUBID UNKNOWN;
@@ -76,7 +78,7 @@
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
}
8000
@@ -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

471501
Array2 : %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

478508
BoolExp : 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

637671
void 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

Comments
 (0)
0