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};