-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsymbol_table.cpp
More file actions
172 lines (149 loc) · 5.56 KB
/
symbol_table.cpp
File metadata and controls
172 lines (149 loc) · 5.56 KB
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
#include "../include/symbol_table.h"
SymbolTable::SymbolTable() : currentOffset(0) {
// Create global scope
scopes.push_back(std::make_unique<Scope>(0));
registerBuiltinTypes();
}
void SymbolTable::registerBuiltinTypes() {
// Register primitive types
auto voidType = std::make_unique<PrimitiveType>(PrimitiveType::Kind::VOID);
auto boolType = std::make_unique<PrimitiveType>(PrimitiveType::Kind::BOOL);
auto charType = std::make_unique<PrimitiveType>(PrimitiveType::Kind::CHAR);
auto intType = std::make_unique<PrimitiveType>(PrimitiveType::Kind::INT);
auto longType = std::make_unique<PrimitiveType>(PrimitiveType::Kind::LONG);
auto floatType = std::make_unique<PrimitiveType>(PrimitiveType::Kind::FLOAT);
auto doubleType = std::make_unique<PrimitiveType>(PrimitiveType::Kind::DOUBLE);
auto stringType = std::make_unique<PrimitiveType>(PrimitiveType::Kind::STRING);
declareType("void", std::move(voidType));
declareType("bool", std::move(boolType));
declareType("char", std::move(charType));
declareType("int", std::move(intType));
declareType("long", std::move(longType));
declareType("float", std::move(floatType));
declareType("double", std::move(doubleType));
declareType("string", std::move(stringType));
}
void SymbolTable::enterScope() {
scopes.push_back(std::make_unique<Scope>(getCurrentScopeLevel() + 1));
}
void SymbolTable::exitScope() {
if (scopes.size() > 1) { // Don't remove global scope
currentOffset -= scopes.back()->size;
scopes.pop_back();
}
}
size_t SymbolTable::getCurrentScopeLevel() const {
return scopes.size() - 1;
}
bool SymbolTable::declareSymbol(const std::string& name, std::unique_ptr<Type> type,
bool isConstant) {
if (scopes.empty()) {
setError("No active scope");
return false;
}
auto& currentScope = scopes.back()->symbols;
if (currentScope.find(name) != currentScope.end()) {
setError("Symbol '" + name + "' already declared in current scope");
return false;
}
auto symbol = std::make_unique<Symbol>(name, std::move(type), isConstant);
symbol->scopeLevel = getCurrentScopeLevel();
symbol->offset = currentOffset;
currentOffset += symbol->type->getSize();
scopes.back()->size += symbol->type->getSize();
currentScope[name] = std::move(symbol);
return true;
}
Symbol* SymbolTable::findSymbol(const std::string& name) {
// Search from innermost scope to outermost
for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) {
auto found = (*it)->symbols.find(name);
if (found != (*it)->symbols.end()) {
return found->second.get();
}
}
return nullptr;
}
bool SymbolTable::declareType(const std::string& name, std::unique_ptr<Type> type) {
if (types.find(name) != types.end()) {
setError("Type '" + name + "' already declared");
return false;
}
types[name] = std::move(type);
return true;
}
Type* SymbolTable::findType(const std::string& name) {
auto it = types.find(name);
return it != types.end() ? it->second.get() : nullptr;
}
Type* SymbolTable::getType(const std::string& name) const {
auto it = types.find(name);
if (it == types.end()) {
// Try to find in current scope
for (auto scopeIt = scopes.rbegin(); scopeIt != scopes.rend(); ++scopeIt) {
auto found = (*scopeIt)->symbols.find(name);
if (found != (*scopeIt)->symbols.end()) {
return found->second->type.get();
}
}
return nullptr;
}
return it->second.get();
}
bool SymbolTable::isTypeCompatible(const Type* source, const Type* target) {
if (!source || !target) {
return false;
}
return source->isCompatibleWith(target);
}
std::string SymbolTable::getCommonType(const std::string& type1, const std::string& type2) {
Type* t1 = findType(type1);
Type* t2 = findType(type2);
if (!t1 || !t2) {
return "";
}
// Same type
if (t1->isCompatibleWith(t2)) {
return type1;
}
// Handle numeric types
if (t1->getKind() == TypeKind::PRIMITIVE && t2->getKind() == TypeKind::PRIMITIVE) {
auto p1 = static_cast<const PrimitiveType*>(t1);
auto p2 = static_cast<const PrimitiveType*>(t2);
switch (p1->getPrimitiveKind()) {
case PrimitiveType::Kind::DOUBLE:
return "double";
case PrimitiveType::Kind::FLOAT:
if (p2->getPrimitiveKind() == PrimitiveType::Kind::DOUBLE) {
return "double";
}
return "float";
case PrimitiveType::Kind::LONG:
switch (p2->getPrimitiveKind()) {
case PrimitiveType::Kind::DOUBLE:
case PrimitiveType::Kind::FLOAT:
return type2;
default:
return "long";
}
case PrimitiveType::Kind::INT:
switch (p2->getPrimitiveKind()) {
case PrimitiveType::Kind::DOUBLE:
case PrimitiveType::Kind::FLOAT:
case PrimitiveType::Kind::LONG:
return type2;
default:
return "int";
}
default:
break;
}
}
return "";
}
void SymbolTable::setError(const std::string& error) {
lastError = error;
}
const std::string& SymbolTable::getLastError() const {
return lastError;
}