-
Notifications
You must be signed in to change notification settings - Fork 0
/
ast_helper.hpp
370 lines (274 loc) · 11.3 KB
/
ast_helper.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
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
//This class is used to create all helper functions needed to be used during genereating RISC-V code
#ifndef ast_helper_hpp
#define ast_helper_hpp
#include <string>
#include <iostream>
#include <map>
//#include <unordered_map> Good idea to probably convert all map to unordered maps
#include <vector>
#include <memory>
#include "../ast.hpp"
//NEED TO FIX FUNCTION CALLS. ALL REGISTERS NEED TO BACKUP TO MEMORY.
class Helper {
protected:
int Regs[32] = {
1, //x0 zero Zero
1, //x1 ra Return address
1, //x2 sp Stack pointer
1, //x3 gp Global pointer
1, //x4 tp Thread pointer
0,0,0, //x5 - x7 t0 - t2 Temporary registers
1,1, //x8 - x9 s0 - s1 Callee-saved registers
1,1,1,1,1,1,1,1, //x10 - x17 a0 - a7 Argument registers
1,1,1,1,1,1,1,1,1,1, //x18 - x27 s2 - s11 Callee-saved registers
0,0,0,0 //x28 - x31 t3 - t6 Temporary registers
};
int Regs_floats[32] = {
1, //f0 zero Zero
0, //f1 ra Return address
0, //f2 sp Stack pointer
0, //f3 gp Global pointer
0, //f4 tp Thread pointer
0,0,0, //f5 - f7 t0 - t2 Temporary registers
1,1, //f8 - f9 s0 - s1 Callee-saved registers
1,1,1,1,1,1,1,1, //f10 - f17 a0 - a7 Argument registers
0,0,0,0,0,0,0,0,0,0, //f18 - f27 s2 - s11 Callee-saved registers
0,0,0,0 //f28 - f31 t3 - t6 Temporary registers
};
std::string function_end;
public:
virtual ~Helper(){
}
//Constructs
Helper(){}
// loop end and start
std::vector<std::string> loop_end;
std::vector<std::string> loop_update;
std::vector<std::string> loop_start;
void new_loop(std::string new_loop_start, std::string new_loop_end, std::string new_loop_update = "None"){
loop_start.push_back(new_loop_start);
loop_update.push_back(new_loop_update);
loop_end.push_back(new_loop_end);
}
void exit_loop(){
if (!loop_start.empty()){
loop_start.pop_back();
loop_update.pop_back();
loop_end.pop_back();
}
else{
std::cerr << "Tried to break or continue in a scope of no loops" << std::endl;
exit(1);
}
}
std::string get_loop_labels(std::string where){
if (where == "Start"){
return loop_start.back();
}
else if (where == "End"){
return loop_end.back();
}
else if (where == "Update"){
return loop_update.back();
}
else{
return "invalid location to jump";
}
}
//Creates Labels for function jumps
std::string createLabel(std::string name){
static int label_count = 0;
label_count+=1;
return "_"+name+"_"+std::to_string(label_count);
}
std::string getfunctionEnd(){
return function_end;
}
//Switch Handling
std::vector<std::string> switch_reg;
std::vector<std::string> switch_label;
std::vector<std::string> switch_status;
//Enum Handling
int last_enum = -1;
std::map<std::string, int> global_enums;
/*
-----------------------------MEMORY MANAGEMENT-------------------------------
*/
//Scopes
int current_scope = 0;
std::vector<std::map<std::string, std::vector<std::string>>> Scopes;
std::vector<int> mem_scope;
//Properties
std::map<std::string, std::vector<std::string>> bindings;
//Memory allocation for scalability
int default_mem_allocation = 128;
int last_mem_allocated = 128;
int min_mem = 4;
//occupy using register
void useReg(int i){
Regs[i] = 1;
}
void useReg_float(int i){
Regs_floats[i] = 1;
}
//deallocate register
void deallocateReg(std::string ®){
if (reg[0] == 'f'){
Regs_floats[std::stoi(reg.erase(0,1))] = 0;
}
else{
Regs[std::stoi(reg.erase(0,1))] = 0;
}
}
//need to implement memory clean when out of scope
//find register to use
std::string allocateReg(std::string datatype){
if (datatype == "float" || datatype == "double" || datatype == "long double"){
for(int i=0; i<32; i++){
if (Regs_floats[i] == 0){
useReg_float(i);
return "f" + std::to_string(i);
}
}
}
else{
for(int i=0; i<32; i++){
if (Regs[i] == 0){
useReg(i);
return "x" + std::to_string(i);
}
}
}
std::cerr << "Register Block!" << std::endl; //need to implement better memory management
exit(1);
}
//find memory offset to use
std::string allocateMemory(){
if (last_mem_allocated == 0){
std::cerr << "StackOverFlow!" << std::endl; //need to implement better memory management
exit(1);
}
last_mem_allocated = last_mem_allocated - min_mem;
return std::to_string(last_mem_allocated);
}
// To save all temporary register in current scope
//(use this function carefully. Very stupid way to solve a problem. Huge memory wasteage)
void save_regs(std::ostream &dst){
for(int i=0; i<7; i++){
dst<<"sw t"<<i<<", "<<allocateMemory()<<"(sp)"<<std::endl;
}
}
// To load all registers from current scope
//(use this function carefully. Very stupid way to solve a problem. Huge memory wasteage)
void load_regs(std::ostream &dst){
for(int i=6; i>-1; i--){
dst<<"lw t"<<i<<", "<<last_mem_allocated<<"(sp)"<<std::endl;
last_mem_allocated = last_mem_allocated + min_mem;
}
}
//New Memory Scope and New Bindings
void newScope(std::ostream &dst, bool override_return = true){
std::map<std::string, std::vector<std::string>> bindings_new;
Scopes.push_back(bindings);
mem_scope.push_back(last_mem_allocated);
current_scope += 1;
bindings = bindings_new;
last_mem_allocated = default_mem_allocation;
if (override_return){
function_end = createLabel("function_end");
}
//sp allocate
dst<<"addi sp, sp, "<<"-"<<default_mem_allocation<<std::endl; //we assume that the tree has stored the value of ra
}
//Exit current scope and Delete Bindings
void exitScope(std::ostream &dst, bool override_return = true){
if (current_scope > 0){
current_scope = current_scope - 1;
bindings = Scopes[current_scope];
last_mem_allocated = mem_scope[current_scope];
Scopes.pop_back();
mem_scope.pop_back();
//sp reset
if (override_return){
dst<<function_end<<":"<<std::endl;
function_end = "Wrong Function End"; //for debugging
}
dst<<"addi sp, sp, "<<default_mem_allocation<<std::endl;
}
else if (current_scope == 0){
//this is probably called when main ends
}
else{
std::cerr << "Exiting beyond base scope!" << std::endl; //need to implement better memory management
exit(1);
}
}
/*
-----------------------------STRING MANAGEMENT-------------------------------
*/
std::vector<std::vector<std::string>> all_headers;
void add_header(std::vector<std::string> new_header) {
all_headers.push_back(new_header);
// n Rows X 2 Coloumns
}
void print_header(std::ostream &dst){
if(all_headers.size() != 0){
dst<<std::endl;
dst<<".data"<<std::endl;
for(int rows = 0; rows < all_headers.size(); rows++){
dst<<all_headers[rows][0]<<":"<<std::endl;
dst<<all_headers[rows][1]<<std::endl;
}
}
}
/*
-----------------------------STRUCT MANAGEMENT-------------------------------
*/
// struct_name -> properties { ( id -> type ) , ( id -> type) , }
std::map<std::string, std::map<std::string, std::string>> structs_created;
// void init_struct(std::ostream &dst, std::string name_of_struct, std::string variable){
// //iterate through each property
// for (auto const &x : structs_created[name_of_struct]) {
// std::string mem = allocateMemory();
// std::vector<std::string> properties;
// properties.push_back(mem);
// properties.push_back(x.second);
// bindings[variable + "." + x.first] = properties;
// }
// }
int type_to_size(std::string returned_type) {
if (returned_type == "int" || returned_type == "unsigned int"){
return 4;
}
else if(returned_type == "long" || returned_type == "unsigned long"){
return 8;
}
else if(returned_type == "char" || returned_type == "unsigned char" || returned_type == "signed char"){
return 1;
}
else if(returned_type == "short" || returned_type == "unsigned short"){
return 2;
}
else if(returned_type == "signed" || returned_type == "unsigned"){
return 4;
}
else if(returned_type == "float"){
return 4;
}
else if(returned_type == "double"){
return 8;
}
else if(returned_type == "long double"){
return 10;
}
else if(returned_type == "void"){
return 1;
}
else {
std::cerr<<returned_type<<": Invalid Data Type Size Read Attempt!"<<std::endl;
exit(1);
return 0;
}
}
};
#endif