• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rieske / trans / 28460720020

30 Jun 2026 04:42PM UTC coverage: 90.232% (-0.3%) from 90.53%
28460720020

Pull #44

github

rieske
Support pointer members in structs including self-reference

Apply declarator pointer levels when building field types so `int *p`
is not stored as `int`. Use a shared StructBody for struct tags so
`struct Node *next` can refer to an incomplete Node that is completed
when the definition finishes. Tests for int* members and linked nodes.
Pull Request #44: Implement C structs with member access

245 of 306 new or added lines in 12 files covered. (80.07%)

29 existing lines in 3 files now uncovered.

5358 of 5938 relevant lines covered (90.23%)

236113.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.4
/src/codegen/CodeGeneratingVisitor.cpp
1
#include "CodeGeneratingVisitor.h"
2

3
#include <stdexcept>
4

5
#include "semantic_analyzer/ValueEntry.h"
6
#include "semantic_analyzer/LabelEntry.h"
7

8
#include "quadruples/Assign.h"
9
#include "quadruples/Argument.h"
10
#include "quadruples/Call.h"
11
#include "quadruples/Retrieve.h"
12
#include "quadruples/AssignConstant.h"
13
#include "quadruples/Inc.h"
14
#include "quadruples/Dec.h"
15
#include "quadruples/AddressOf.h"
16
#include "quadruples/Dereference.h"
17
#include "quadruples/UnaryMinus.h"
18
#include "quadruples/ValueCompare.h"
19
#include "quadruples/ZeroCompare.h"
20
#include "quadruples/Jump.h"
21
#include "quadruples/Label.h"
22
#include "quadruples/Add.h"
23
#include "quadruples/Sub.h"
24
#include "quadruples/Mul.h"
25
#include "quadruples/Div.h"
26
#include "quadruples/Mod.h"
27
#include "quadruples/And.h"
28
#include "quadruples/Or.h"
29
#include "quadruples/Xor.h"
30
#include "quadruples/Return.h"
31
#include "quadruples/VoidReturn.h"
32
#include "quadruples/LvalueAssign.h"
33
#include "quadruples/StartProcedure.h"
34
#include "quadruples/EndProcedure.h"
35
#include "quadruples/Shl.h"
36
#include "quadruples/Shr.h"
37
#include "quadruples/FieldAccess.h"
38

39
namespace codegen {
40

41
CodeGeneratingVisitor::CodeGeneratingVisitor() {
374 ✔
42
}
374 ✔
43

44
CodeGeneratingVisitor::~CodeGeneratingVisitor() {
374 ✔
45
}
374 ✔
46

47
void CodeGeneratingVisitor::visit(ast::DeclarationSpecifiers&) {
508 ✔
48
}
508 ✔
49

50
void CodeGeneratingVisitor::visit(ast::Declaration& declaration) {
508 ✔
51
    declaration.visitChildren(*this);
508 ✔
52
}
508 ✔
53

54
void CodeGeneratingVisitor::visit(ast::Declarator& declarator) {
1,220 ✔
55
    declarator.visitChildren(*this);
1,220 ✔
56
}
1,220 ✔
57

58
void CodeGeneratingVisitor::visit(ast::InitializedDeclarator& declarator) {
620 ✔
59
    // File-scope variables are initialized in .data; skip children (would emit assigns with no procedure).
60
    if (declarator.hasInitializer() && declarator.getHolder()->isGlobal()) {
620 ✔
61
        return;
28 ✔
62
    }
63
    declarator.visitChildren(*this);
592 ✔
64
    if (declarator.hasInitializer()) {
592 ✔
65
        instructions.push_back(std::make_unique<Assign>(
38 ✔
66
                declarator.getInitializerHolder()->getName(), declarator.getHolder()->getName()));
76 ✔
67
    }
68
}
69

70
void CodeGeneratingVisitor::visit(ast::ArrayAccess& arrayAccess) {
×
71
    arrayAccess.visitLeftOperand(*this);
×
72
    arrayAccess.visitRightOperand(*this);
×
73

74
    // TODO: not implemented yet
75
    //auto offset = arrayAccess.rightOperandSymbol();
76
    //quadruples.push_back( { code_generator::INDEX, arrayAccess.leftOperandSymbol(), offset, arrayAccess.getResultSymbol() });
77
    //quadruples.push_back( { code_generator::INDEX_ADDR, arrayAccess.leftOperandSymbol(), offset, arrayAccess.getLvalue() });
78
}
×
79

80
void CodeGeneratingVisitor::visit(ast::FunctionCall& functionCall) {
910 ✔
81
    functionCall.visitOperand(*this);
910 ✔
82
    functionCall.visitArguments(*this);
910 ✔
83

84
    for (auto& expression : functionCall.getArgumentList()) {
2,894 ✔
85
        instructions.push_back(std::make_unique<Argument>(expression->getResultSymbol()->getName()));
1,984 ✔
86
    }
87

88
    instructions.push_back(std::make_unique<Call>(functionCall.getSymbol()->getName()));
910 ✔
89
    if (!functionCall.getType().isVoid()) {
910 ✔
90
        instructions.push_back(std::make_unique<Retrieve>(functionCall.getResultSymbol()->getName()));
910 ✔
91
    }
92
}
910 ✔
93

94
void CodeGeneratingVisitor::visit(ast::IdentifierExpression&) {
2,722 ✔
95
}
2,722 ✔
96

97
void CodeGeneratingVisitor::visit(ast::ConstantExpression& constant) {
1,192 ✔
98
    instructions.push_back(std::make_unique<AssignConstant>(constant.getValue(), constant.getResultSymbol()->getName()));
1,192 ✔
99
}
1,192 ✔
100

101
void CodeGeneratingVisitor::visit(ast::StringLiteralExpression& stringLiteral) {
802 ✔
102
    instructions.push_back(
802 ✔
103
        std::make_unique<AssignConstant>(stringLiteral.getConstantSymbol(), stringLiteral.getResultSymbol()->getName())
1,604 ✔
104
    );
105
}
802 ✔
106

107
void CodeGeneratingVisitor::visit(ast::PostfixExpression& expression) {
24 ✔
108
    expression.visitOperand(*this);
24 ✔
109

110
    auto resultSymbolName = expression.getResultSymbol()->getName();
24 ✔
111
    auto preOperationSymbol = expression.getPreOperationSymbol()->getName();
24 ✔
112
    instructions.push_back(std::make_unique<Assign>(resultSymbolName, preOperationSymbol));
24 ✔
113

114
    if (expression.getOperator()->getLexeme() == "++") {
24 ✔
115
        instructions.push_back(std::make_unique<Inc>(resultSymbolName));
18 ✔
116
    } else if (expression.getOperator()->getLexeme() == "--") {
6 ✔
117
        instructions.push_back(std::make_unique<Dec>(resultSymbolName));
6 ✔
118
    }
119

120
    // Dereference (and similar) lvalues: value lives in a temp; store new value through the pointer.
121
    if (auto* lvalue = expression.operandLvalueSymbol()) {
24 ✔
122
        instructions.push_back(std::make_unique<LvalueAssign>(resultSymbolName, lvalue->getName()));
8 ✔
123
    }
124

125
    expression.setResultSymbol(*expression.getPreOperationSymbol());
24 ✔
126
}
24 ✔
127

128
void CodeGeneratingVisitor::visit(ast::PrefixExpression& expression) {
28 ✔
129
    expression.visitOperand(*this);
28 ✔
130

131
    auto resultSymbolName = expression.getResultSymbol()->getName();
28 ✔
132
    if (expression.getOperator()->getLexeme() == "++") {
28 ✔
133
        instructions.push_back(std::make_unique<Inc>(resultSymbolName));
22 ✔
134
    } else if (expression.getOperator()->getLexeme() == "--") {
6 ✔
135
        instructions.push_back(std::make_unique<Dec>(resultSymbolName));
6 ✔
136
    }
137

138
    if (auto* lvalue = expression.operandLvalueSymbol()) {
28 ✔
139
        instructions.push_back(std::make_unique<LvalueAssign>(resultSymbolName, lvalue->getName()));
20 ✔
140
    }
141
}
28 ✔
142

143
void CodeGeneratingVisitor::visit(ast::UnaryExpression& expression) {
544 ✔
144
    expression.visitOperand(*this);
544 ✔
145

146
    switch (expression.getOperator()->getLexeme().front()) {
544 ✔
147
    case '&':
334 ✔
148
        instructions.push_back(std::make_unique<AddressOf>(expression.operandSymbol()->getName(), expression.getResultSymbol()->getName()));
334 ✔
149
        break;
334 ✔
150
    case '*':
90 ✔
151
        instructions.push_back(std::make_unique<Dereference>(expression.operandSymbol()->getName(), expression.getLvalueSymbol()->getName(),
90 ✔
152
                                                             expression.getResultSymbol()->getName()));
180 ✔
153
        break;
90 ✔
154
    case '+':
2 ✔
155
        break;
2 ✔
156
    case '-':
88 ✔
157
        instructions.push_back(std::make_unique<UnaryMinus>(expression.operandSymbol()->getName(), expression.getResultSymbol()->getName()));
88 ✔
158
        break;
88 ✔
159
    case '!':
30 ✔
160
        instructions.push_back(std::make_unique<ZeroCompare>(expression.operandSymbol()->getName()));
30 ✔
161
        instructions.push_back(std::make_unique<Jump>(expression.getTruthyLabel()->getName(), JumpCondition::IF_EQUAL));
30 ✔
162
        instructions.push_back(std::make_unique<AssignConstant>("0", expression.getResultSymbol()->getName()));
30 ✔
163
        instructions.push_back(std::make_unique<Jump>(expression.getFalsyLabel()->getName()));
30 ✔
164
        instructions.push_back(std::make_unique<Label>(expression.getTruthyLabel()->getName()));
30 ✔
165
        instructions.push_back(std::make_unique<AssignConstant>("1", expression.getResultSymbol()->getName()));
30 ✔
166
        instructions.push_back(std::make_unique<Label>(expression.getFalsyLabel()->getName()));
30 ✔
167
        break;
30 ✔
UNCOV
168
    default:
×
169
        throw std::runtime_error { "Unidentified unary operator: " + expression.getOperator()->getLexeme() };
×
170
    }
171
}
544 ✔
172

UNCOV
173
void CodeGeneratingVisitor::visit(ast::TypeCast& expression) {
×
174
    expression.visitOperand(*this);
×
175
    instructions.push_back(std::make_unique<Assign>(expression.operandSymbol()->getName(), expression.getResultSymbol()->getName()));
×
176
}
×
177

178
void CodeGeneratingVisitor::visit(ast::ArithmeticExpression& expression) {
106 ✔
179
    expression.visitLeftOperand(*this);
106 ✔
180
    expression.visitRightOperand(*this);
106 ✔
181

182
    switch (expression.getOperator()->getLexeme().front()) {
106 ✔
183
    case '+':
74 ✔
184
        instructions.push_back(std::make_unique<Add>(expression.leftOperandSymbol()->getName(), expression.rightOperandSymbol()->getName(),
74 ✔
185
                                                     expression.getResultSymbol()->getName()));
148 ✔
186
        break;
74 ✔
187
    case '-':
16 ✔
188
        instructions.push_back(std::make_unique<Sub>(expression.leftOperandSymbol()->getName(), expression.rightOperandSymbol()->getName(),
16 ✔
189
                                                     expression.getResultSymbol()->getName()));
32 ✔
190
        break;
16 ✔
191
    case '*':
8 ✔
192
        instructions.push_back(std::make_unique<Mul>(expression.leftOperandSymbol()->getName(), expression.rightOperandSymbol()->getName(),
8 ✔
193
                                                     expression.getResultSymbol()->getName()));
16 ✔
194
        break;
8 ✔
195
    case '/':
4 ✔
196
        instructions.push_back(std::make_unique<Div>(expression.leftOperandSymbol()->getName(), expression.rightOperandSymbol()->getName(),
4 ✔
197
                                                     expression.getResultSymbol()->getName()));
8 ✔
198
        break;
4 ✔
199
    case '%':
4 ✔
200
        instructions.push_back(std::make_unique<Mod>(expression.leftOperandSymbol()->getName(), expression.rightOperandSymbol()->getName(),
4 ✔
201
                                                     expression.getResultSymbol()->getName()));
8 ✔
202
        break;
4 ✔
UNCOV
203
    default:
×
204
        throw std::runtime_error { "unidentified arithmetic operator: " + expression.getOperator()->getLexeme() };
×
205
    }
206
}
106 ✔
207

208
void CodeGeneratingVisitor::visit(ast::ShiftExpression& expression) {
18 ✔
209
    expression.visitLeftOperand(*this);
18 ✔
210
    expression.visitRightOperand(*this);
18 ✔
211

212
    switch (expression.getOperator()->getLexeme().front()) {
18 ✔
213
    case '<':   // <<
10 ✔
214
        instructions.push_back(std::make_unique<Shl>(
10 ✔
215
                    expression.leftOperandSymbol()->getName(),
20 ✔
216
                    expression.rightOperandSymbol()->getName(),
20 ✔
217
                    expression.getResultSymbol()->getName()));
20 ✔
218
        break;
10 ✔
219
    case '>':   // >>
8 ✔
220
        instructions.push_back(std::make_unique<Shr>(
8 ✔
221
                    expression.leftOperandSymbol()->getName(),
16 ✔
222
                    expression.rightOperandSymbol()->getName(),
16 ✔
223
                    expression.getResultSymbol()->getName()));
16 ✔
224
        break;
8 ✔
UNCOV
225
    default:
×
226
        throw std::runtime_error { "unidentified shift operator!" };
×
227
    }
228
}
18 ✔
229

230
void CodeGeneratingVisitor::visit(ast::ComparisonExpression& expression) {
178 ✔
231
    expression.visitLeftOperand(*this);
178 ✔
232
    expression.visitRightOperand(*this);
178 ✔
233

234
    instructions.push_back(std::make_unique<ValueCompare>(expression.leftOperandSymbol()->getName(), expression.rightOperandSymbol()->getName()));
178 ✔
235

236
    auto truthyLabel = expression.getTruthyLabel()->getName();
178 ✔
237
    if (expression.getOperator()->getLexeme() == ">") {
178 ✔
238
        instructions.push_back(std::make_unique<Jump>(truthyLabel, JumpCondition::IF_ABOVE));
36 ✔
239
    } else if (expression.getOperator()->getLexeme() == "<") {
142 ✔
240
        instructions.push_back(std::make_unique<Jump>(truthyLabel, JumpCondition::IF_BELOW));
56 ✔
241
    } else if (expression.getOperator()->getLexeme() == "<=") {
86 ✔
242
        instructions.push_back(std::make_unique<Jump>(truthyLabel, JumpCondition::IF_BELOW_OR_EQUAL));
28 ✔
243
    } else if (expression.getOperator()->getLexeme() == ">=") {
58 ✔
244
        instructions.push_back(std::make_unique<Jump>(truthyLabel, JumpCondition::IF_ABOVE_OR_EQUAL));
24 ✔
245
    } else if (expression.getOperator()->getLexeme() == "==") {
34 ✔
246
        instructions.push_back(std::make_unique<Jump>(truthyLabel, JumpCondition::IF_EQUAL));
28 ✔
247
    } else if (expression.getOperator()->getLexeme() == "!=") {
6 ✔
248
        instructions.push_back(std::make_unique<Jump>(truthyLabel, JumpCondition::IF_NOT_EQUAL));
6 ✔
249
    } else {
UNCOV
250
        throw std::runtime_error { "unidentified ml_op operator!\n" };
×
251
    }
252

253
    instructions.push_back(std::make_unique<AssignConstant>("0", expression.getResultSymbol()->getName()));
178 ✔
254
    instructions.push_back(std::make_unique<Jump>(expression.getFalsyLabel()->getName()));
178 ✔
255
    instructions.push_back(std::make_unique<Label>(truthyLabel));
178 ✔
256
    instructions.push_back(std::make_unique<AssignConstant>("1", expression.getResultSymbol()->getName()));
178 ✔
257
    instructions.push_back(std::make_unique<Label>(expression.getFalsyLabel()->getName()));
178 ✔
258
}
178 ✔
259

260
void CodeGeneratingVisitor::visit(ast::BitwiseExpression& expression) {
12 ✔
261
    expression.visitLeftOperand(*this);
12 ✔
262
    expression.visitRightOperand(*this);
12 ✔
263

264
    switch (expression.getOperator()->getLexeme().front()) {
12 ✔
265
    case '&':
4 ✔
266
        instructions.push_back(std::make_unique<And>(expression.leftOperandSymbol()->getName(), expression.rightOperandSymbol()->getName(),
4 ✔
267
                                                     expression.getResultSymbol()->getName()));
8 ✔
268
        break;
4 ✔
269
    case '|':
4 ✔
270
        instructions.push_back(std::make_unique<Or>(expression.leftOperandSymbol()->getName(), expression.rightOperandSymbol()->getName(),
4 ✔
271
                                                    expression.getResultSymbol()->getName()));
8 ✔
272
        break;
4 ✔
273
    case '^':
4 ✔
274
        instructions.push_back(std::make_unique<Xor>(expression.leftOperandSymbol()->getName(), expression.rightOperandSymbol()->getName(),
4 ✔
275
                                                     expression.getResultSymbol()->getName()));
8 ✔
276
        break;
4 ✔
UNCOV
277
    default:
×
278
        throw std::runtime_error { "no semantic actions defined for bitwise operator: " + expression.getOperator()->getLexeme() };
×
279
    }
280
}
12 ✔
281

282
void CodeGeneratingVisitor::visit(ast::LogicalAndExpression& expression) {
8 ✔
283
    expression.visitLeftOperand(*this);
8 ✔
284

285
    instructions.push_back(std::make_unique<AssignConstant>("0", expression.getResultSymbol()->getName()));
8 ✔
286
    instructions.push_back(std::make_unique<ZeroCompare>(expression.leftOperandSymbol()->getName()));
8 ✔
287
    instructions.push_back(std::make_unique<Jump>(expression.getExitLabel()->getName(), JumpCondition::IF_EQUAL));
8 ✔
288

289
    expression.visitRightOperand(*this);
8 ✔
290

291
    instructions.push_back(std::make_unique<ZeroCompare>(expression.rightOperandSymbol()->getName()));
8 ✔
292
    instructions.push_back(std::make_unique<Jump>(expression.getExitLabel()->getName(), JumpCondition::IF_EQUAL));
8 ✔
293
    instructions.push_back(std::make_unique<AssignConstant>("1", expression.getResultSymbol()->getName()));
8 ✔
294

295
    instructions.push_back(std::make_unique<Label>(expression.getExitLabel()->getName()));
8 ✔
296
}
8 ✔
297

298
void CodeGeneratingVisitor::visit(ast::LogicalOrExpression& expression) {
8 ✔
299
    expression.visitLeftOperand(*this);
8 ✔
300

301
    instructions.push_back(std::make_unique<AssignConstant>("1", expression.getResultSymbol()->getName()));
8 ✔
302
    instructions.push_back(std::make_unique<ZeroCompare>(expression.leftOperandSymbol()->getName()));
8 ✔
303
    instructions.push_back(std::make_unique<Jump>(expression.getExitLabel()->getName(), JumpCondition::IF_NOT_EQUAL));
8 ✔
304

305
    expression.visitRightOperand(*this);
8 ✔
306

307
    instructions.push_back(std::make_unique<ZeroCompare>(expression.rightOperandSymbol()->getName()));
8 ✔
308
    instructions.push_back(std::make_unique<Jump>(expression.getExitLabel()->getName(), JumpCondition::IF_NOT_EQUAL));
8 ✔
309
    instructions.push_back(std::make_unique<AssignConstant>("0", expression.getResultSymbol()->getName()));
8 ✔
310

311
    instructions.push_back(std::make_unique<Label>(expression.getExitLabel()->getName()));
8 ✔
312
}
8 ✔
313

314
void CodeGeneratingVisitor::visit(ast::AssignmentExpression& expression) {
478 ✔
315
    expression.visitLeftOperand(*this);
478 ✔
316
    expression.visitRightOperand(*this);
478 ✔
317

318
    auto assignmentOperator = expression.getOperator();
478 ✔
319
    auto resultName = expression.getResultSymbol()->getName();
478 ✔
320
    if (assignmentOperator->getLexeme() == "+=")
478 ✔
321
        instructions.push_back(std::make_unique<Add>(
10 ✔
322
                    resultName,
323
                    expression.rightOperandSymbol()->getName(),
20 ✔
324
                    resultName
325
        ));
326
    else if (assignmentOperator->getLexeme() == "-=")
468 ✔
327
        instructions.push_back(std::make_unique<Sub>(
6 ✔
328
                    resultName,
329
                    expression.rightOperandSymbol()->getName(),
12 ✔
330
                    resultName
331
        ));
332
    else if (assignmentOperator->getLexeme() == "*=")
462 ✔
333
        instructions.push_back(std::make_unique<Mul>(
8 ✔
334
                    resultName,
335
                    expression.rightOperandSymbol()->getName(),
16 ✔
336
                    resultName
337
        ));
338
    else if (assignmentOperator->getLexeme() == "/=")
454 ✔
339
        instructions.push_back(std::make_unique<Div>(
6 ✔
340
                    resultName,
341
                    expression.rightOperandSymbol()->getName(),
12 ✔
342
                    resultName
343
        ));
344
    else if (assignmentOperator->getLexeme() == "%=")
448 ✔
345
        instructions.push_back(std::make_unique<Mod>(
6 ✔
346
                    resultName,
347
                    expression.rightOperandSymbol()->getName(),
12 ✔
348
                    resultName
349
        ));
350
    else if (assignmentOperator->getLexeme() == "&=")
442 ✔
351
        instructions.push_back(std::make_unique<And>(
6 ✔
352
                    resultName,
353
                    expression.rightOperandSymbol()->getName(),
12 ✔
354
                    resultName
355
        ));
356
    else if (assignmentOperator->getLexeme() == "^=")
436 ✔
357
        instructions.push_back(std::make_unique<Xor>(
6 ✔
358
                    resultName,
359
                    expression.rightOperandSymbol()->getName(),
12 ✔
360
                    resultName
361
        ));
362
    else if (assignmentOperator->getLexeme() == "|=")
430 ✔
363
        instructions.push_back(std::make_unique<Or>(
6 ✔
364
                    resultName,
365
                    expression.rightOperandSymbol()->getName(),
12 ✔
366
                    resultName
367
        ));
368
    else if (assignmentOperator->getLexeme() == "<<=") {
424 ✔
369
        instructions.push_back(std::make_unique<Shl>(
10 ✔
370
                    resultName,
371
                    expression.rightOperandSymbol()->getName(),
20 ✔
372
                    resultName
373
        ));
374
    } else if (assignmentOperator->getLexeme() == ">>=") {
414 ✔
375
        instructions.push_back(std::make_unique<Shr>(
10 ✔
376
                    resultName,
377
                    expression.rightOperandSymbol()->getName(),
20 ✔
378
                    resultName
379
        ));
380
    } else if (assignmentOperator->getLexeme() == "=") {
404 ✔
381
        if (expression.leftOperandLvalueSymbol()) {
404 ✔
382
            instructions.push_back(std::make_unique<LvalueAssign>(
38 ✔
383
                        expression.rightOperandSymbol()->getName(),
76 ✔
384
                        expression.leftOperandLvalueSymbol()->getName()
76 ✔
385
            ));
386
        } else {
387
            instructions.push_back(std::make_unique<Assign>(
366 ✔
388
                        expression.rightOperandSymbol()->getName(),
732 ✔
389
                        resultName
390
            ));
391
        }
392
        return;
404 ✔
393
    } else {
UNCOV
394
        throw std::runtime_error { "unidentified assignment operator: " + assignmentOperator->getLexeme() };
×
395
    }
396

397
    // Compound assign updated the value temp; write back through pointer lvalues (e.g. *p += 1).
398
    if (auto* lvalue = expression.leftOperandLvalueSymbol()) {
74 ✔
399
        instructions.push_back(std::make_unique<LvalueAssign>(resultName, lvalue->getName()));
20 ✔
400
    }
401
}
478 ✔
402

403
void CodeGeneratingVisitor::visit(ast::ExpressionList& expression) {
2 ✔
404
    expression.visitLeftOperand(*this);
2 ✔
405
    expression.visitRightOperand(*this);
2 ✔
406
}
2 ✔
407

UNCOV
408
void CodeGeneratingVisitor::visit(ast::Operator&) {
×
409
}
×
410

UNCOV
411
void CodeGeneratingVisitor::visit(ast::JumpStatement& statement) {
×
412
    throw std::runtime_error { "not implemented" };
×
413
}
414

415
void CodeGeneratingVisitor::visit(ast::ReturnStatement& statement) {
444 ✔
416
    statement.returnExpression->accept(*this);
444 ✔
417
    instructions.push_back(std::make_unique<Return>(statement.returnExpression->getResultSymbol()->getName()));
444 ✔
418
}
444 ✔
419

420
void CodeGeneratingVisitor::visit(ast::VoidReturnStatement &statement) { instructions.push_back(std::make_unique<VoidReturn>()); }
22 ✔
421

422
void CodeGeneratingVisitor::visit(ast::IfStatement& statement) {
20 ✔
423
    statement.testExpression->accept(*this);
20 ✔
424

425
    instructions.push_back(std::make_unique<ZeroCompare>(statement.testExpression->getResultSymbol()->getName()));
20 ✔
426
    instructions.push_back(std::make_unique<Jump>(statement.getFalsyLabel()->getName(), JumpCondition::IF_EQUAL));
20 ✔
427

428
    statement.body->accept(*this);
20 ✔
429

430
    instructions.push_back(std::make_unique<Label>(statement.getFalsyLabel()->getName()));
20 ✔
431
}
20 ✔
432

433
void CodeGeneratingVisitor::visit(ast::IfElseStatement& statement) {
16 ✔
434
    statement.testExpression->accept(*this);
16 ✔
435

436
    instructions.push_back(std::make_unique<ZeroCompare>(statement.testExpression->getResultSymbol()->getName()));
16 ✔
437
    instructions.push_back(std::make_unique<Jump>(statement.getFalsyLabel()->getName(), JumpCondition::IF_EQUAL));
16 ✔
438

439
    statement.truthyBody->accept(*this);
16 ✔
440
    instructions.push_back(std::make_unique<Jump>(statement.getExitLabel()->getName()));
16 ✔
441
    instructions.push_back(std::make_unique<Label>(statement.getFalsyLabel()->getName()));
16 ✔
442

443
    statement.falsyBody->accept(*this);
16 ✔
444
    instructions.push_back(std::make_unique<Label>(statement.getExitLabel()->getName()));
16 ✔
445
}
16 ✔
446

447
void CodeGeneratingVisitor::visit(ast::LoopStatement& loop) {
50 ✔
448
    loop.header->accept(*this);
50 ✔
449
    loop.body->accept(*this);
50 ✔
450
    // FIXME:
451
    if (loop.header->increment) {
50 ✔
452
        loop.header->increment->accept(*this);
22 ✔
453
    }
454

455
    instructions.push_back(std::make_unique<Jump>(loop.header->getLoopEntry()->getName()));
50 ✔
456
    instructions.push_back(std::make_unique<Label>(loop.header->getLoopExit()->getName()));
50 ✔
457
}
50 ✔
458

459
void CodeGeneratingVisitor::visit(ast::ForLoopHeader& loopHeader) {
30 ✔
460
    if (loopHeader.initialization) {
30 ✔
461
        loopHeader.initialization->accept(*this);
20 ✔
462
    }
463

464
    instructions.push_back(std::make_unique<Label>(loopHeader.getLoopEntry()->getName()));
30 ✔
465
    if (loopHeader.clause) {
30 ✔
466
        loopHeader.clause->accept(*this);
22 ✔
467
        instructions.push_back(std::make_unique<ZeroCompare>(loopHeader.clause->getResultSymbol()->getName()));
22 ✔
468
        instructions.push_back(std::make_unique<Jump>(loopHeader.getLoopExit()->getName(), JumpCondition::IF_EQUAL));
22 ✔
469
    }
470
}
30 ✔
471

472
void CodeGeneratingVisitor::visit(ast::WhileLoopHeader& loopHeader) {
20 ✔
473
    instructions.push_back(std::make_unique<Label>(loopHeader.getLoopEntry()->getName()));
20 ✔
474
    loopHeader.clause->accept(*this);
20 ✔
475
    instructions.push_back(std::make_unique<ZeroCompare>(loopHeader.clause->getResultSymbol()->getName()));
20 ✔
476
    instructions.push_back(std::make_unique<Jump>(loopHeader.getLoopExit()->getName(), JumpCondition::IF_EQUAL));
20 ✔
477
}
20 ✔
478

479
void CodeGeneratingVisitor::visit(ast::Pointer&) {
68 ✔
480
}
68 ✔
481

482
void CodeGeneratingVisitor::visit(ast::Identifier&) {
758 ✔
483
}
758 ✔
484

485
void CodeGeneratingVisitor::visit(ast::FunctionDeclarator& declarator) {
462 ✔
486
    declarator.visitFormalArguments(*this);
462 ✔
487
}
462 ✔
488

UNCOV
489
void CodeGeneratingVisitor::visit(ast::ArrayDeclarator& declaration) {
×
490
    declaration.subscriptExpression->accept(*this);
×
491
    throw std::runtime_error { "not implemented" };
×
492
}
493

494
void CodeGeneratingVisitor::visit(ast::FormalArgument& parameter) {
166 ✔
495
    parameter.visitDeclarator(*this);
166 ✔
496
}
166 ✔
497

498
void CodeGeneratingVisitor::visit(ast::FunctionDefinition& function) {
462 ✔
499
    function.visitDeclarator(*this);
462 ✔
500

501
    std::vector<Value> values;
462 ✔
502
    int nextSlot = 0;
462 ✔
503
    for (auto& valueSymbol : function.getLocalVariables()) {
4,954 ✔
504
        int sizeBytes = valueSymbol.second.getType().getSize();
4,492 ✔
505
        if (sizeBytes < 8) {
4,492 ✔
506
            sizeBytes = 8;
3,148 ✔
507
        }
508
        int words = (sizeBytes + 7) / 8;
4,492 ✔
509
        values.push_back( {
4,492 ✔
510
                valueSymbol.second.getName(),
8,984 ✔
511
                nextSlot,
512
                Type::INTEGRAL,
513
                sizeBytes
514
        });
515
        nextSlot += words;
4,492 ✔
516
    }
462 ✔
517
    std::vector<Value> arguments;
462 ✔
518
    for (auto& argumentSymbol : function.getArguments()) {
628 ✔
519
        int sizeBytes = argumentSymbol.getType().getSize();
166 ✔
520
        if (sizeBytes < 8) {
166 ✔
521
            sizeBytes = 8;
154 ✔
522
        }
523
        arguments.push_back( {
166 ✔
524
                argumentSymbol.getName(),
332 ✔
525
                argumentSymbol.getIndex(),
526
                Type::INTEGRAL,
527
                sizeBytes
528
        });
529
    }
462 ✔
530
    instructions.push_back(std::make_unique<StartProcedure>(function.getSymbol()->getName(), std::move(values), std::move(arguments)));
462 ✔
531

532
    auto instructionsBak = std::move(instructions);
462 ✔
533
    function.visitBody(*this);
462 ✔
534
    auto functionBody = toBasicBlocks(std::move(instructions));
462 ✔
535
    for (auto& bb : functionBody) {
1,830 ✔
536
        if (!bb->terminates()) {
1,368 ✔
537
            bb->appendInstruction(std::make_unique<VoidReturn>());
18 ✔
538
        }
539
        instructionsBak.push_back(std::move(bb));
1,368 ✔
540
    }
541
    instructions = std::move(instructionsBak);
462 ✔
542

543
    instructions.push_back(std::make_unique<EndProcedure>(function.getSymbol()->getName()));
462 ✔
544
}
462 ✔
545

546
void CodeGeneratingVisitor::visit(ast::Block& block) {
574 ✔
547
    block.visitChildren(*this);
574 ✔
548
}
574 ✔
549

550
std::vector<std::unique_ptr<Quadruple>> CodeGeneratingVisitor::getQuadruples() {
374 ✔
551
    return std::move(instructions);
374 ✔
552
}
553

554
std::vector<std::unique_ptr<BasicBlock>> toBasicBlocks(std::vector<std::unique_ptr<Quadruple>> instructions) {
468 ✔
555
    std::vector<std::unique_ptr<BasicBlock>> basicBlocks {};
468 ✔
556

557
    std::unique_ptr<BasicBlock> bb = std::make_unique<BasicBlock>();
468 ✔
558

559
    std::vector<std::unique_ptr<Quadruple>> bbInstructions;
468 ✔
560
    for (auto& instruction : instructions) {
10,088 ✔
561
        if (bb->terminates() || instruction->isLabel()) {
9,620 ✔
562
            basicBlocks.push_back(std::move(bb));
914 ✔
563
            bb = std::make_unique<BasicBlock>();
914 ✔
564
            basicBlocks.back()->setSuccessor(bb.get());
914 ✔
565
        }
566
        bb->appendInstruction(std::move(instruction));
9,620 ✔
567
    }
568
    basicBlocks.push_back(std::move(bb));
468 ✔
569

570
    return basicBlocks;
936 ✔
571
}
468 ✔
572

573
void CodeGeneratingVisitor::visit(ast::MemberAccess& expression) {
48 ✔
574
    expression.getBase()->accept(*this);
48 ✔
575
    const bool arrow = expression.isArrow();
48 ✔
576
    const int offset = expression.getMemberOffset();
48 ✔
577
    const std::string baseName = expression.getBaseResultSymbol()->getName();
48 ✔
578
    const std::string addrName = expression.getFieldAddressSymbol()->getName();
48 ✔
579
    const std::string resultName = expression.getResultSymbol()->getName();
48 ✔
580
    // Materialize field address (dot: &object+off; arrow: pointer+off). Read via existing dereference.
581
    instructions.push_back(std::make_unique<FieldAddress>(baseName, offset, addrName, arrow));
48 ✔
582
    instructions.push_back(std::make_unique<Dereference>(addrName, addrName, resultName));
48 ✔
583
}
48 ✔
584

585
} // namespace codegen
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc