Code ManagerΒΆ
When generating code, our compiler will need to handle pieces of code created by different subtrees and combine them together to create more code (e.g. to create code for a while, the compiler will need to combine the code to compute the expression and the code of the instruction inside the loop with the right labels and jump instructions).
The Code Manager module provides a class code
that can be used to handle this code combinations, and finally write it to the output file when it is complete. Objects of type code
contain subroutine
objects, which contain instructionList
objects, which in turn contain instruction
objects.
All these classes have methods to extend and combine them (e.g. add a subroutine
to a code
, or add an instruction
to an instructionList
, concatenate two instructionList
objects, etc.)
Additionally, this module contains also a static class counters
that manages counters to generate labels for jumps in if and while instructions, and well as for temporal registers.
1/// predeclaration
2class instructionList;
3class LLVMCodeGen;
4
5////////////////////////////////////////////////////////////////////
6/// Class instruction stores a VM instruction code with its operands
7
8class instruction {
9public:
10 /// instruction codes
11 typedef enum {_LABEL, _UJUMP, _FJUMP, _HALT, _PUSH, _POP, _CALL, _RETURN,
12 _ADD, _SUB, _MUL, _DIV, _EQ, _LT, _LE, _NEG, _NOT, _AND, _OR, _FLOAT,
13 _FADD, _FSUB, _FMUL, _FDIV, _FEQ, _FLT, _FLE, _FNEG,
14 _LOAD, _ILOAD, _CHLOAD, _FLOAD, _XLOAD, _LOADX, _ALOAD, _LOADC, _CLOAD,
15 _READI, _READF, _READC, _WRITEI, _WRITEF, _WRITEC, _WRITES, _WRITELN, _NOOP, _INVALID} Operation;
16
17 /// instruction code
18 Operation oper;
19 /// arguments
20 std::string arg1, arg2, arg3;
21
22 /// constructor
23 instruction(Operation op,
24 const std::string &a1="", const std::string &a2="", const std::string &a3="");
25
26 /// destructor
27 ~instruction();
28
29 // concatenation of instruction+list (or instruction+instruction, via automatic coertion)
30 instructionList operator||(const instructionList &lst) const;
31
32 /// ------ specific constructors for each instruction -------
33
34 // create new instruction "a1 :"
35 static instruction LABEL(const std::string &a1);
36 // create new instruction "goto a1"
37 static instruction UJUMP(const std::string &a1);
38 // create new instruction "ifFalse a1 goto a2"
39 static instruction FJUMP(const std::string &a1, const std::string &a2);
40 // create new instruction "halt"
41 static instruction HALT(const std::string &a1="");
42 // create new instruction "pushparam a1"
43 static instruction PUSH(const std::string &a1="");
44 // create new instruction "popparam a1"
45 static instruction POP(const std::string &a1="");
46 // create new instruction "call a1"
47 static instruction CALL(const std::string &a1);
48 // create new instruction "return"
49 static instruction RETURN();
50 // create new instruction "a1 = a2 + a3"
51 static instruction ADD(const std::string &a1, const std::string &a2, const std::string &a3);
52 // create new instruction "a1 = a2 - a3"
53 static instruction SUB(const std::string &a1, const std::string &a2, const std::string &a3);
54 // create new instruction "a1 = a2 * a3"
55 static instruction MUL(const std::string &a1, const std::string &a2, const std::string &a3);
56 // create new instruction "a1 = a2 / a3"
57 static instruction DIV(const std::string &a1, const std::string &a2, const std::string &a3);
58 // create new instruction "a1 = a2 == a3"
59 static instruction EQ(const std::string &a1, const std::string &a2, const std::string &a3);
60 // create new instruction "a1 = a2 < a3"
61 static instruction LT(const std::string &a1, const std::string &a2, const std::string &a3);
62 // create new instruction "a1 = a2 <= a3"
63 static instruction LE(const std::string &a1, const std::string &a2, const std::string &a3);
64 // create new instruction "a1 = a2 and a3"
65 static instruction AND(const std::string &a1, const std::string &a2, const std::string &a3);
66 // create new instruction "a1 = a2 or a3"
67 static instruction OR(const std::string &a1, const std::string &a2, const std::string &a3);
68 // create new instruction "a1 = a2 +. a3"
69 static instruction FADD(const std::string &a1, const std::string &a2, const std::string &a3);
70 // create new instruction "a1 = a2 -. a3"
71 static instruction FSUB(const std::string &a1, const std::string &a2, const std::string &a3);
72 // create new instruction "a1 = a2 *. a3"
73 static instruction FMUL(const std::string &a1, const std::string &a2, const std::string &a3);
74 // create new instruction "a1 = a2 /. a3"
75 static instruction FDIV(const std::string &a1, const std::string &a2, const std::string &a3);
76 // create new instruction "a1 = a2 ==. a3"
77 static instruction FEQ(const std::string &a1, const std::string &a2, const std::string &a3);
78 // create new instruction "a1 = a2 <. a3"
79 static instruction FLT(const std::string &a1, const std::string &a2, const std::string &a3);
80 // create new instruction "a1 = a2 <=. a3"
81 static instruction FLE(const std::string &a1, const std::string &a2, const std::string &a3);
82 // create new instruction "a1 = not a2"
83 static instruction NOT(const std::string &a1, const std::string &a2);
84 // create new instruction "a1 = - a2"
85 static instruction NEG(const std::string &a1, const std::string &a2);
86 // create new instruction "a1 = -. a2"
87 static instruction FNEG(const std::string &a1, const std::string &a2);
88 // create new instruction "a1 = float a2"
89 static instruction FLOAT(const std::string &a1, const std::string &a2);
90 // create new instruction "a1 = a2"
91 static instruction LOAD(const std::string &a1, const std::string &a2);
92 // create new instruction "a1 = a2" (where a2 is an integer constant)
93 static instruction ILOAD(const std::string &a1, const std::string &a2);
94 // create new instruction "a1 = a2" (where a2 is a character constant)
95 static instruction CHLOAD(const std::string &a1, const std::string &a2);
96 // create new instruction "a1 = a2" (where a2 is a float constant)
97 static instruction FLOAD(const std::string &a1, const std::string &a2);
98 // create new instruction "a1[a2] = a3"
99 static instruction XLOAD(const std::string &a1, const std::string &a2, const std::string &a3);
100 // create new instruction "a1 = a2[a3]"
101 static instruction LOADX(const std::string &a1, const std::string &a2, const std::string &a3);
102 // create new instruction "a1 = &a2"
103 static instruction ALOAD(const std::string &a1, const std::string &a2);
104 // create new instruction "a1 = *a2"
105 static instruction LOADC(const std::string &a1, const std::string &a2);
106 // create new instruction "*a1 = a2"
107 static instruction CLOAD(const std::string &a1, const std::string &a2);
108 // create new instruction "readi a1"
109 static instruction READI(const std::string &a1);
110 // create new instruction "readf a1"
111 static instruction READF(const std::string &a1);
112 // create new instruction "readc a1"
113 static instruction READC(const std::string &a1);
114 // create new instruction "writei a1"
115 static instruction WRITEI(const std::string &a1);
116 // create new instruction "writef a1"
117 static instruction WRITEF(const std::string &a1);
118 // create new instruction "writec a1"
119 static instruction WRITEC(const std::string &a1);
120 // create new instruction "writes 'string constant'"
121 static instruction WRITES(const std::string &a1);
122 // create new instruction "writeln"
123 static instruction WRITELN();
124 // create new instruction "noop" (not really needed)
125 static instruction NOOP();
126
127 // print instruction
128 std::string dump() const;
129};
130
131
132////////////////////////////////////////////////////////////////////
133/// Class instructionList stores a list of instructions
134
135class instructionList : public std::vector<instruction> {
136public:
137 // constructor
138 instructionList();
139 // constructor from a single instruction
140 instructionList(const instruction &);
141 // destructor
142 ~instructionList();
143
144 // concatenation of lists (or list+instruction, via automatic coertion)
145 instructionList operator||(const instructionList &lst) const;
146
147 // print instructionList
148 std::string dump() const;
149};
150
151
152////////////////////////////////////////////////////////////////////
153/// Class var stores a variable name and size
154
155class var {
156public:
157 std::string name;
158 std::string type;
159 size_t nelem;
160
161 var(const std::string &name, const std::string &type, size_t nelem=1);
162 ~var();
163
164 // print var
165 std::string dump() const;
166};
167
168
169////////////////////////////////////////////////////////////////////
170/// Class subroutine stores information about a subroutine (local
171/// vars, parametres, instructions, declared/used labels...)
172
173class subroutine {
174public:
175 /// list of local variables
176 std::list<var> vars;
177 /// list of params
178 std::list<var> params;
179
180 /// constructor and destructor
181 subroutine(const std::string &sname);
182 ~subroutine();
183
184 /// get subroutine name
185 std::string get_name() const;
186 /// add a local var to subroutine
187 void add_var(const var &v);
188 /// add a local var to subroutine
189 void add_var(const std::string &name, const std::string &type, size_t numelem=1);
190 /// add a parameter (size is always 1, since arrays are references)
191 void add_param(const std::string &name, const std::string &type, bool isarray=false);
192 /// add an instruction
193 void add_instruction(const instruction &inst);
194 /// add instruction list to current instructions
195 void add_instructions(const instructionList &lins);
196 /// set instruction list (overwritting current instructions)
197 void set_instructions(const instructionList &lins);
198
199 // print subroutine (params, vars, and instructions)
200 std::string dump() const;
201};
202
203
204////////////////////////////////////////////////////////////////////
205/// Class code stores a whole program (main plus subroutines)
206
207class code {
208public:
209 /// constructor and destructor
210 code();
211 ~code();
212
213 /// get most recently added subroutine (i.e. the one currently being processed)
214 subroutine& get_last_subroutine();
215 /// get subroutine by name
216 const subroutine& get_subroutine(const std::string &name) const;
217 /// add new subroutine
218 void add_subroutine(const subroutine &s);
219 /// get the list of subroutines (needed only in LLVMCodeGen)
220 const std::vector<subroutine> & get_subroutine_list() const;
221
222 // print code (all info for all subroutines)
223 std::string dump() const;
224 /// print the code in LLVM IR
225 std::string dumpLLVM(const TypesMgr & Types, const SymTable &Symbols) const;
226};
227
228
229////////////////////////////////////////////////////////////////////
230/// Class counters manages temporal and labels counters
231
232class counters {
233public:
234 // return id for new label or temp (id is a number, but returned as string
235 // to ease concatenation with other literals (e.g. "labelIF" + "4" -> "LabelIF4")
236 static std::string newLabelIF();
237 static std::string newLabelWHILE();
238 static std::string newTEMP();
239
240 // reset individual counters
241 static void resetLabelIF();
242 static void resetLabelWHILE();
243 static void resetTEMP();
244
245 // reset label counters (IF and WHILE)
246 static void resetLabels();
247 // reset all counters (IF, WHILE, and TEMP)
248 static void reset();
249};