Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e28f801

Browse files
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*>> ArrayArgs
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

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)

AltStyle によって変換されたページ (->オリジナル) /