-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCodeGen.cpp
More file actions
222 lines (195 loc) · 7.51 KB
/
Copy pathCodeGen.cpp
File metadata and controls
222 lines (195 loc) · 7.51 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
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
// ============================================================
// CodeGen
// ============================================================
//
// Purpose: INTERMEDIATE CODE GENERATION
// Produces Three-Address Code (TAC) from the AST.
// Each complex expression is broken into simple steps
// using temporary variables t0, t1, t2 …
// ============================================================
#include "CodeGen.h"
#include <iostream>
#include <iomanip>
#include <sstream>
// toString() for a single TAC instruction
std::string TACInstruction::toString() const {
if (op == "GOTO") {
return "GOTO " + result; // Unconditional jump
}
if (op == "IF_FALSE") {
return "IF_FALSE " + arg1 + " GOTO " + result;
}
if (op == "LABEL") {
return result + ":"; // Label definition
}
if (op == "PRINT") {
return "PRINT " + arg1; // Print instruction
}
if (op == "RETURN") {
return "RETURN " + arg1;
}
if (op == "HALT") {
return "HALT";
}
if (arg2.empty()) {
return result + " = " + arg1; // Simple assignment/copy
}
return result + " = " + arg1 + " " + op + " " + arg2; // Binary op
}
// CodeGen class implementation
CodeGen::CodeGen() : tempCount_(0), labelCount_(0) {}
std::string CodeGen::newTemp() {
return "t" + std::to_string(tempCount_++); // t0, t1, t2, ...
}
std::string CodeGen::newLabel() {
return "L" + std::to_string(labelCount_++); // L0, L1, L2, ...
}
// EMIT() – helper to add a new instruction to the list
void CodeGen::emit(const std::string& result,
const std::string& op,
const std::string& arg1,
const std::string& arg2) {
instructions_.push_back(TACInstruction{result, op, arg1, arg2});
}
// GENERATE() – entry point for code generation, takes the AST and produces TAC
std::vector<TACInstruction>
CodeGen::generate(const std::vector<ASTNodePtr>& stmts) {
for (const auto& stmt : stmts) {
genStmt(stmt.get()); // Process each statement
}
emit("", "HALT", "", ""); // Program end marker
return instructions_;
}
// GEN_EXPR() – recursively generate code for an expression node
// Returns the name of the temp/variable that holds the result
std::string CodeGen::genExpr(const ASTNode* node) {
// ── Number literal ────────────────────────────────────
if (auto* n = dynamic_cast<const NumberNode*>(node)) {
// Strip trailing zeros from integers for cleaner output
std::string val;
if (n->value == (int)n->value)
val = std::to_string((int)n->value);
else {
std::ostringstream ss;
ss << n->value;
val = ss.str();
}
std::string t = newTemp();
emit(t, "=", val, ""); // t0 = 42
return t;
}
// STRING literal
if (auto* n = dynamic_cast<const StringNode*>(node)) {
std::string t = newTemp();
emit(t, "=", "\"" + n->value + "\"", "");
return t;
}
// Identifier (variable) – just return its name (assumes it’s already declared)
if (auto* n = dynamic_cast<const IdentifierNode*>(node)) {
return n->name; // Already has a name – use it directly
}
// BINARY OPERATOR – generate code for left and right, then combine
if (auto* n = dynamic_cast<const BinaryOpNode*>(node)) {
std::string l = genExpr(n->left.get()); // Generate left
std::string r = genExpr(n->right.get()); // Generate right
std::string t = newTemp();
emit(t, n->op, l, r); // t2 = t0 + t1
return t;
}
return ""; // Should never reach here for valid AST
}
// GEN_STMT() – recursively generate code for a statement node
void CodeGen::genStmt(const ASTNode* node) {
// ── Variable declaration ──────────────────────────────
if (auto* n = dynamic_cast<const VarDeclNode*>(node)) {
if (n->init) {
std::string val = genExpr(n->init.get());
emit(n->name, "=", val, ""); // x = t0
}
return;
}
// ASSIGNMENT – generate code for the right-hand side, then assign to variable
if (auto* n = dynamic_cast<const AssignNode*>(node)) {
std::string val = genExpr(n->expr.get());
emit(n->name, "=", val, ""); // x = t3
return;
}
// IF statement – generate condition, then branch to then/else blocks
// Generated TAC pattern:
// <condition>
// IF_FALSE cond GOTO elseLabel
// <then-body>
// GOTO endLabel
// elseLabel:
// <else-body>
// endLabel:
if (auto* n = dynamic_cast<const IfNode*>(node)) {
std::string elseLabel = newLabel();
std::string endLabel = newLabel();
std::string cond = genExpr(n->condition.get());
emit(elseLabel, "IF_FALSE", cond, ""); // Branch if false
for (const auto& s : n->thenBranch) genStmt(s.get());
emit(endLabel, "GOTO", "", ""); // Skip else
emit(elseLabel, "LABEL", "", ""); // Else entry point
for (const auto& s : n->elseBranch) genStmt(s.get());
emit(endLabel, "LABEL", "", ""); // Merge point
return;
}
// WHILE loop – generate condition and body with appropriate labels
// Generated TAC
// Pattern:
// loopLabel:
// <condition>
// IF_FALSE cond GOTO exitLabel
// <body>
// GOTO loopLabel
// exitLabel:
if (auto* n = dynamic_cast<const WhileNode*>(node)) {
std::string loopLabel = newLabel();
std::string exitLabel = newLabel();
emit(loopLabel, "LABEL", "", "");
std::string cond = genExpr(n->condition.get());
emit(exitLabel, "IF_FALSE", cond, "");
for (const auto& s : n->body) genStmt(s.get());
emit(loopLabel, "GOTO", "", ""); // Back to loop top
emit(exitLabel, "LABEL", "", "");
return;
}
// PRINT statement – generate code for the expression, then emit PRINT instruction
if (auto* n = dynamic_cast<const PrintNode*>(node)) {
std::string val = genExpr(n->expr.get());
emit("", "PRINT", val, "");
return;
}
// RETURN statement – generate code for the return value (if any), then emit RETURN instruction
if (auto* n = dynamic_cast<const ReturnNode*>(node)) {
if (n->expr) {
std::string val = genExpr(n->expr.get());
emit("", "RETURN", val, "");
} else {
emit("", "RETURN", "", "");
}
return;
}
// BLOCK statement – just generate code for each statement in the block
if (auto* n = dynamic_cast<const BlockNode*>(node)) {
for (const auto& s : n->statements) genStmt(s.get());
return;
}
}
// PRINT_INSTRUCTIONS() – utility to display the generated TAC instructions
void CodeGen::printInstructions() const {
std::cout << "\n";
int lineNo = 0;
for (const auto& instr : instructions_) {
if (instr.op != "LABEL") {
// Numbered instruction line
std::cout << " " << std::setw(3) << lineNo++ << " "
<< instr.toString() << "\n";
} else {
// Labels are printed flush-left without a number
std::cout << " " << instr.toString() << "\n";
}
}
std::cout << "\n";
}