-
Notifications
You must be signed in to change notification settings - Fork 0
/
interpreter.cpp
229 lines (191 loc) · 6.65 KB
/
interpreter.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "interpreter.h"
#include "symbols.h"
#include <forward_list>
#include <iostream>
#include <memory>
#include "log/minlog.h"
using namespace Interpreter;
using namespace Symbols;
using namespace std;
Id::Id(const char *name) : name(name) {
}
int Id::Evaluate() // TODO: Allow more than just int
{
const char* name = this->name;
try
{
Object* object = current_symbol_table->Get(name);
if(object->GetKind() != SymbolInt)
{
minlog::fatal("error: variable '%s' was not an int\n", name);
exit(1);
}
int val = object->GetInt();
return val;
}
catch(std::out_of_range e)
{
minlog::fatal("error: use of undeclared variable '%s'\n", name);
exit(1);
}
}
void Id::Assign(int val) { // TODO: Allow more than just int
Object* object = new Object(val);
if(current_symbol_table->Contains(this->name)) {
current_symbol_table->Get(this->name)->SetInt(val);
} else {
current_symbol_table->Set(this->name, object);
}
}
Val::Val(int val) : val(val) {
}
int Val::Evaluate()
{
return this->val;
}
Op::Op(const char *glyph) : glyph(glyph) {
}
Statements::Statements(Statement *statement, Statements *childStatements)
: statement(statement), childStatements(childStatements)
{
}
void Statements::Execute()
{
Statements *nexts = this;
while(nexts != nullptr)
{
nexts->statement->Execute();
nexts = nexts->childStatements;
}
}
Assignment::Assignment(Id *id, Expression* right) : id(id), right(right) {
}
void Assignment::Execute() {
int val = this->right->Evaluate();
this->id->Assign(val);
minlog::debug("Assigning %s=%d\n", this->id->name, val);
}
Conditional::Conditional(Expression* condition, Statement* statement)
: condition(condition), statement(statement) { }
void Conditional::Execute()
{
int result = this->condition->Evaluate();
if(result) {
this->statement->Execute();
}
}
Print::Print(Expression *expr) : expr(expr) { }
void Print::Execute()
{
int result = this->expr->Evaluate();
printf("%d\n", result);
}
ExpressionNode::ExpressionNode(Expression *left, Expression *right, Op* op)
: left(left), right(right), op(op) { }
int ExpressionNode::Evaluate()
{
const char* op = this->op->glyph;
int left = this->left->Evaluate();
int right = this->right->Evaluate();
if(strcmp(op,"+")==0) {
return left+right;
} else if(strcmp(op,"-")==0) {
return left-right;
} else if(strcmp(op,"*")==0) {
return left*right;
} else if(strcmp(op,"/")==0) {
return left/right;
} else if(strcmp(op,"<")==0) {
return left<right;
} else if(strcmp(op,"<=")==0) {
return left<=right;
} else if(strcmp(op,">")==0) {
return left>right;
} else if(strcmp(op,">=")==0) {
return left>=right;
} else if(strcmp(op,"==")==0) {
return left==right;
} else if(strcmp(op,"!=")==0) {
return left!=right;
} else {
minlog::fatal("fatal error: invalid op '%s'\n", op);
exit(1);
}
}
ProcedureDeclaration::ProcedureDeclaration(Id *id, forward_list<Id*>* arguments, Statements *statements)
: id(id), arguments(arguments), statements(statements) { }
void ProcedureDeclaration::Execute()
{
// Clone the current symbol table into a closure
SymbolTable* closure = new SymbolTable(*current_symbol_table);
// Output some debugging information
int argumentsSize = 0;
for(auto iter : *this->arguments) ++argumentsSize;
minlog::debug("Declaring procedure '%s'(%d args) (in closure %d with closure %d)...\n", this->id->name, argumentsSize, current_symbol_table->sequence, closure->sequence);
// Create object for procedure, with newly created closure as its closure
Object* procedure = new Object(this, closure);
// Place the procedure in its own closure
closure->Set(this->id->name, procedure);
// Place this object in the current symbol table
current_symbol_table->Set(this->id->name, procedure);
}
ProcedureCall::ProcedureCall(Id *id, forward_list<ProcedureCallArgument*>* arguments) : id(id), arguments(arguments)
{
}
typedef forward_list<Id*> argDefList_t;
typedef forward_list<Id*>::iterator argDefListIter_t;
typedef forward_list<ProcedureCallArgument*> argCallList_t;
typedef forward_list<ProcedureCallArgument*>::iterator argCallListIter_t;
void ProcedureCall::Execute()
{
try
{
// Get procedure object out of current symbol table
minlog::debug("Fetching procedure '%s' (from closure %d)...\n", this->id->name, current_symbol_table->sequence);
Object* procedure = current_symbol_table->Get(this->id->name);
minlog::debug("Calling procedure '%s' (using closure %d)...\n", this->id->name, procedure->closure->sequence);
// Assert it's really a procedure
if(procedure->GetKind() != SymbolProcedure)
{
minlog::debug("error: '%s' was not a procedure (closure %d)\n", this->id->name, current_symbol_table->sequence);
exit(1);
}
// Clone the procedure's closure, to which we will add arguments
SymbolTable* closureWithArgs = new SymbolTable(*procedure->closure);
// Populate the closureWithArgs with arguments
argCallList_t* a = this->arguments;
argDefList_t* b = procedure->fVal->arguments;
for(pair<argCallListIter_t,argDefListIter_t> i(a->begin(),b->begin());
i.first != a->end() && i.second != b->end();
++i.first, ++i.second)
{
ProcedureCallArgument* callArgument = (*i.first);
Id* declaredArgument = (*i.second);
minlog::debug(" arg='%s'\n", declaredArgument->name);
const char *argName = declaredArgument->name;
Object* argValue = new Object(callArgument->expression->Evaluate());
closureWithArgs->Set(argName, argValue);
}
// Backup the current symbol table
SymbolTableStateGuard guard;
// Use our new closureWithArgs during our function call
minlog::debug("Switching to closure %d\n", closureWithArgs->sequence);
current_symbol_table = closureWithArgs;
// Execute the procedure
minlog::debug(" executing %s\n", this->id->name);
ProcedureDeclaration* assignment = procedure->GetProcedure();
assignment->statements->Execute();
}
catch(std::out_of_range e)
{
(stderr, "error: use of undeclared function '%s'\n", this->id->name);
exit(1);
}
}
ProcedureCallArgument::ProcedureCallArgument(Expression* expression) : expression(expression)
{
}