-
Notifications
You must be signed in to change notification settings - Fork 0
/
symbol_table.hpp
129 lines (104 loc) · 3.99 KB
/
symbol_table.hpp
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
#ifndef SYMBOL_TABLE_HPP
#define SYMBOL_TABLE_HPP
#include <llvm/IR/Function.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Instructions.h>
#include <string>
#include <unordered_map>
#include <vector>
/*
* Similar to value, stores llvm::Type along with any other data the frontend
* needs
*/
struct type_i { // TODO: Fix name; type_info collides with some header
llvm::Type *llvm_type;
bool is_signed;
type_i(llvm::Type *t = nullptr, bool s = true) : llvm_type(t), is_signed(s) {}
};
/*
* The frontend needs to maintain more data for a value than a llvm::Value holds
* such as the signedness, since it determines which instructions to emit.
* This struct is a wrapper of llvm::Value and any other extra data that is to
* be maintained
*/
struct value {
llvm::Value *llvm_val = nullptr;
bool is_signed = false;
static value null;
value() = default;
value(llvm::Value *val, bool s) : llvm_val(val), is_signed(s) {}
type_i get_type();
};
class scope {
std::unordered_map<std::string, value> variables;
llvm::IRBuilder<> *builder;
public:
scope(llvm::IRBuilder<> *builder) : builder(builder){};
scope(scope &&other) = default;
llvm::AllocaInst *get_alloca(llvm::Type *llvm_type, std::string name);
llvm::AllocaInst *add_var(type_i type, std::string name);
llvm::Function *add_func(llvm::Function *func, std::string name);
value add_val(value val, std::string name);
bool check_var(std::string name);
value get_var(std::string name);
llvm::IRBuilder<> *get_builder();
};
class func_scope {
std::vector<scope> scopes;
llvm::IRBuilder<> *builder;
bool own_builder;
llvm::Function *func;
// alloca's are added before this no-op instruction. Remove after done.
llvm::Instruction *alloca_end;
std::unordered_multimap<std::string, llvm::BranchInst *> pending_gotos;
std::unordered_map<std::string, llvm::BasicBlock *> label_blocks;
void push_scope();
void pop_scope();
public:
func_scope(llvm::Function *func);
func_scope(llvm::IRBuilder<> *builder);
func_scope(func_scope &&other) = default;
~func_scope();
llvm::Function *get_scope_func();
// Doesn't add allocation to the symbol table
llvm::AllocaInst *get_alloca(llvm::Type *llvm_type, std::string name);
llvm::AllocaInst *add_var(type_i type, std::string name);
llvm::Function *add_func(llvm::Function *func, std::string name);
value add_val(value val, std::string name);
bool check_top_scope(std::string name);
void add_block_terminator(llvm::Instruction *ins);
// This class' constructor pushes new scope and its destructor pops the scope
class auto_scope {
func_scope *s;
public:
auto_scope(func_scope *s) : s(s) { s->push_scope(); }
~auto_scope() { s->pop_scope(); }
};
auto_scope new_scope() { return auto_scope(this); }
// Add a label with the given name to the function. Raises an error if the
// label already exists
void add_label(std::string name, llvm::BasicBlock *block);
// Adds a goto instruction through the given builder. If the label is not
// found yet, the instruction is added to a list of pending instructions and
// are updated when the label is added
void add_goto_inst(std::string name, llvm::IRBuilder<> *builder,
llvm::BasicBlock *next_block);
// Searches all scopes from top to bottom for variable defined by name.
value get_var(std::string name);
};
class symbol_table {
std::vector<func_scope> func_scopes;
llvm::IRBuilder<> &global_builder;
llvm::Function *curr_func;
public:
symbol_table(llvm::IRBuilder<> &global_builder);
void push_func_scope(llvm::Function *func); // Adds scope to top of the stack
void pop_func_scope(); // Pops scope off the stack
func_scope *top_func_scope();
llvm::Function *get_curr_func();
value add_var(type_i type, std::string name);
llvm::Function *add_func(llvm::Function *func, std::string name);
// Searches top function scope and global scope for variable defined by name.
value get_var(std::string name);
};
#endif /* SYMBOL_TABLE_HPP */