• 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 · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc