-
Notifications
You must be signed in to change notification settings - Fork 0
/
symtable.cc
245 lines (224 loc) · 8.83 KB
/
symtable.cc
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#include "auxlib.h"
#include "symtable.h"
#include "codeutils.h"
#include <iostream>
SymbolTable *global_table = new SymbolTable(NULL);
SymbolTable *current_table = global_table;
// Creates and returns a new symbol table.
//
// Use "new SymbolTable(NULL)" to create the global table
SymbolTable::SymbolTable(SymbolTable* parent) {
// Set the parent (this might be NULL)
this->parent = parent;
// Assign a unique number and increment the global N
this->number = SymbolTable::N++;
}
// Creates a new empty table beneath the current table and returns it.
SymbolTable* SymbolTable::enterBlock() {
// Create a new symbol table beneath the current one
SymbolTable* child = new SymbolTable(this);
// Convert child->number to a string stored in buffer
char buffer[10];
sprintf(&buffer[0], "%d", child->number);
// Use the number as ID for this symbol table
// to identify all child symbol tables
this->subscopes[buffer] = child;
// Return the newly created symbol table
return child;
}
// Returns parent table
SymbolTable* SymbolTable::leaveBlock() {
return this->parent;
}
// Adds the function name as symbol to the current table
// and creates a new empty table beneath the current one.
//
// Example: To enter the function "void add(int a, int b)",
// call "currentSymbolTable->enterFunction("add", "void(int,int)");
SymbolTable* SymbolTable::enterFunction(string name, string signature) {
// Add a new symbol using the signature as type
this->addSymbol(name, signature);
// return NULL;
// Create the child symbol table
SymbolTable* child = new SymbolTable(this);
// Store the symbol table under the name of the function
// This allows us to retrieve the corresponding symbol table of a function
// and the coresponding function of a symbol table.
this->subscopes[name] = child;
return child;
}
// Add a symbol with the provided name and type to the current table.
//
// Example: To add the variable declaration "int i = 23;"
// use "currentSymbolTable->addSymbol("i", "int");
void SymbolTable::addSymbol(string name, string type) {
// Use the variable name as key for the identifier mapping
this->mapping[name] = type;
}
void SymbolTable::addLine(string name, size_t filenr, size_t linenr, size_t index) {
// Use the variable name as key for the identifier mapping
this->filenr[name] = filenr;
this->linenr[name] = linenr;
this->index[name] = index;
}
// Dumps the content of the symbol table and all its inner scopes
// depth denotes the level of indention.
//
// Example: "global_symtable->dump(symfile, 0)"
void SymbolTable::dump(FILE* symfile, int depth) {
// Create a new iterator for <string,string>
std::map<string,string>::iterator it;
// Iterate over all entries in the identifier mapping
for (it = this->mapping.begin(); it != this->mapping.end(); ++it) {
// The key of the mapping entry is the name of the symbol
const char* name = it->first.c_str();
// The value of the mapping entry is the type of the symbol
const char* type = it->second.c_str();
// Print the symbol as "name {blocknumber} type"
// indented by 3 spaces for each level
fprintf(symfile, "%*s%s (%lu.%lu.%lu) {%d} %s\n", 3*depth, "", name,
this->filenr[name], this->linenr[name], this->index[name], this->number, type);
// If the symbol we just printed is actually a function
// then we can find the symbol table of the function by the name
if (this->subscopes.count(name) > 0) {
// And recursively dump the functions symbol table
// before continuing the iteration
this->subscopes[name]->dump(symfile, depth + 1);
}
}
// Create a new iterator for <string,SymbolTable*>
std::map<string,SymbolTable*>::iterator i;
// Iterate over all the child symbol tables
for (i = this->subscopes.begin(); i != this->subscopes.end(); ++i) {
// If we find the key of this symbol table in the symbol mapping
// then it is actually a function scope which we already dumped above
if (this->mapping.count(i->first) < 1) {
// Otherwise, recursively dump the (non-function) symbol table
i->second->dump(symfile, depth + 1);
}
}
}
string SymbolTable::map_function_types(string typeList) {
size_t p = typeList.find("(");
if (p == string::npos)
return map_type(typeList);
string returnList = map_type(typeList.substr(0, p)) + "(";
typeList.erase(0, p+1);
while (typeList.length() > 1) {
p = typeList.find(",");
bool comma = true;
if (p == string::npos) {// There are no more commas
p = typeList.length() - 1; // Set to everthing but the final ')'
comma = false;
}
returnList += map_type(typeList.substr(0, p));
returnList += comma ? "," : "";
typeList.erase(0, p+1);
}
return returnList + ")";
}
void SymbolTable::print_globals(FILE* oilfile) {
// Create a new iterator for <string,string>
std::map<string,string>::iterator it;
// Iterate over all entries in the identifier mapping
for (it = this->mapping.begin(); it != this->mapping.end(); ++it) {
// The key of the mapping entry is the name of the symbol
string name = it->first;
// The value of the mapping entry is the type of the symbol
string type = this->map_function_types(it->second);
// Print the symbol as "name {blocknumber} type"
// indented by 3 spaces for each level
if (type.length() < 2 || type.substr(type.length()-1, 1).compare(")") != 0) {
fprintf(oilfile, "%s __%s;\n", type.c_str(), name.c_str());
}
}
}
// Look up name in this and all surrounding blocks and return its type.
//
// Returns the empty string "" if variable was not found
string SymbolTable::lookup(string name) {
// Look up "name" in the identifier mapping of the current block
if (this->mapping.count(name) > 0) {
// If we found an entry, just return its type
return this->mapping[name];
}
// Otherwise, if there is a surrounding scope
if (this->parent != NULL) {
// look up the symbol in the surrounding scope
// and return its reported type
return this->parent->lookup(name);
} else {
// Return "" if the global symbol table has no entry
errprintf("Unknown identifier: %s\n", name.c_str());
return "";
}
}
int SymbolTable::lookupBlock(string name) {
// Look up "name" in the identifier mapping of the current block
if (this->mapping.count(name) > 0) {
// If we found an entry, just return its type
return this->number;
}
std::map<string,SymbolTable*>::iterator it;
for (it = this->subscopes.begin(); it != this->subscopes.end(); ++it) {
int b = it->second->lookupBlock(name);
if (b > 0)
return b;
}
return -1;
}
// Looks through the symbol table chain to find the function which
// surrounds the scope and returns its signature
// or "" if there is no surrounding function.
//
// Use parentFunction(NULL) to get the parentFunction of the current block.
string SymbolTable::parentFunction(SymbolTable* innerScope) {
// Create a new <string,SymbolTable*> iterator
std::map<string,SymbolTable*>::iterator it;
// Iterate over all the subscopes of the current scopes
for (it = this->subscopes.begin(); it != this->subscopes.end(); ++it) {
// If we find the requested inner scope and if its name is a symbol
// in the identifier mapping
if (it->second == innerScope && this->mapping.count(it->first) > 0) {
// Then it must be the surrounding function, so return its type/signature
return this->mapping[it->first];
}
}
// If we did not find a surrounding function
if (this->parent != NULL) {
// Continue the lookup with the parent scope if there is one
return this->parent->parentFunction(this);
}
// If there is no parent scope, return ""
errprintf("Could not find surrounding function\n");
return "";
}
// initialize running block ID to 0
int SymbolTable::N(0);
// Parses a function signature and returns all types as vector.
// The first element of the vector is always the return type.
//
// Example: "SymbolTable::parseSignature("void(int,int)")
// returns ["void", "int", "int"]
vector<string> SymbolTable::parseSignature(string sig) {
// Initialize result string vector
vector<string> results;
// Find first opening parenthesis
size_t left = sig.find_first_of('(');
if (left == string::npos) {
// Print error and return empty results if not a function signature
errprintf("This %s is not a function\n", sig.c_str());
return results;
}
// Add return type
results.push_back(sig.substr(0, left));
// Starting with the position of the left parenthesis
// Find the next comma or closing parenthesis at each step
// and stop when the end is reached.
for (size_t i = left + 1; i < sig.length()-1; i = sig.find_first_of(",)", i) + 1) {
// At each step, get the substring between the current position
// and the next comma or closing parenthesis
results.push_back(sig.substr(i, sig.find_first_of(",)", i) - i));
}
return results;
}