Skip to content

Commit 3a6abfa

Browse files
cleanup (#38)
1 parent cd9c800 commit 3a6abfa

File tree

2 files changed

+84
-114
lines changed

2 files changed

+84
-114
lines changed

Doxyfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ EXCLUDE_SYMLINKS = NO
981981
# Note that the wildcards are matched against the file with absolute path, so to
982982
# exclude all test directories for example use the pattern */test/*
983983

984-
EXCLUDE_PATTERNS =
984+
EXCLUDE_PATTERNS = /test/ | /benchmark/
985985

986986
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
987987
# (namespaces, classes, functions, etc.) that should be excluded from the

day_17/lib/transpiler.cpp

+83-113
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
#include <cmath>
44
#include <cstdint>
5+
#include <format>
6+
#include <iostream>
7+
#include <string_view>
58

69
namespace aoc::day_17 {
710

8-
[[nodiscard]] auto transpile(program const & program_to_transpile) -> std::string {
9-
std::string result = R"(#pragma once
11+
namespace {
12+
constexpr std::string_view PROGRAM_HEADER = R"(#pragma once
1013
#include <cmath>
1114
#include <cstdint>
1215
#include <iostream>
@@ -15,131 +18,97 @@ namespace aoc::day_17 {
1518
void run_using_best_lang() {
1619
bool first_out = true;)";
1720

18-
result += " int64_t a = " + std::to_string(program_to_transpile.register_a) + ";\n";
19-
result += " int64_t b = " + std::to_string(program_to_transpile.register_b) + ";\n";
20-
result += " int64_t c = " + std::to_string(program_to_transpile.register_c) + ";\n";
21+
constexpr std::string_view HELPERS_HEADER = R"(#pragma once
22+
#include <cmath>
23+
#include <cstdint>
24+
#include <vector>
25+
26+
auto calculate_byte(int64_t a) -> int64_t {
27+
)";
28+
29+
namespace opcode_translation {
30+
static auto translate_div_operation(std::string const & target, int64_t operand) -> std::string {
31+
if (operand < 4) {
32+
return std::format(" {} = {} / {};\n", target, target, static_cast<uint8_t>(std::pow(2, operand)));
33+
}
34+
return std::format(" {} = {} / std::pow(2, {});\n", target, target, to_combo_operand_literal(operand));
35+
}
36+
37+
static auto translate_output(int64_t operand) -> std::string {
38+
return std::format(R"( if(first_out) {{
39+
std::cout << {} % 8 << std::endl;
40+
first_out = false;
41+
}} else {{
42+
std::cout << "," << {} % 8 << std::endl;
43+
}}
44+
)",
45+
to_combo_operand_literal(operand), to_combo_operand_literal(operand));
46+
}
47+
48+
auto translate_opcode(opcode op, int64_t operand, size_t label_index = 0) -> std::string {
49+
switch (op) {
50+
case opcode::ADV:
51+
return translate_div_operation("a", operand);
52+
case opcode::BXL:
53+
return std::format(" b ^= {};\n", operand);
54+
case opcode::BST:
55+
return std::format(" b = {} % 8;\n", to_combo_operand_literal(operand));
56+
case opcode::JNZ:
57+
return std::format(" if (a != 0) goto _{};\n", operand);
58+
case opcode::BXC:
59+
return " b ^= c;\n";
60+
case opcode::OUT:
61+
return translate_output(operand);
62+
case opcode::BDV:
63+
return translate_div_operation("b", operand);
64+
case opcode::CDV:
65+
return translate_div_operation("c", operand);
66+
default:
67+
return "";
68+
}
69+
}
70+
} // namespace opcode_translation
71+
72+
auto initialize_registers(program const & prog) -> std::string {
73+
return std::format(" int64_t a = {};\n int64_t b = {};\n int64_t c = {};\n", prog.register_a,
74+
prog.register_b, prog.register_c);
75+
}
76+
77+
} // anonymous namespace
78+
79+
auto transpile(program const & program_to_transpile) -> std::string {
80+
std::string result{PROGRAM_HEADER};
81+
result += initialize_registers(program_to_transpile);
2182

2283
for (size_t i = 0; i < program_to_transpile.m_chunk.size(); i += 2) {
84+
auto const [op, operand] =
85+
std::tuple{program_to_transpile.m_chunk[i], i + 1 < program_to_transpile.m_chunk.size()
86+
? static_cast<int64_t>(program_to_transpile.m_chunk[i + 1])
87+
: 0};
88+
2389
result += "_" + std::to_string(i * 5) + ": ";
24-
auto op = program_to_transpile.m_chunk[i];
25-
auto operand =
26-
i + 1 < program_to_transpile.m_chunk.size() ? static_cast<int64_t>(program_to_transpile.m_chunk[i + 1]) : 0;
27-
switch (op) {
28-
case opcode::ADV:
29-
{
30-
if (operand < 4) {
31-
result += " a = a / " + std::to_string((uint8_t)std::pow(2, operand)) + ";\n";
32-
} else {
33-
result += " a = a / std::pow(2, " + to_combo_operand_literal(operand) + ");\n";
34-
}
35-
break;
36-
}
37-
case opcode::BXL:
38-
result += " b ^= " + std::to_string(operand) + ";\n";
39-
break;
40-
case opcode::BST:
41-
result += " b = " + to_combo_operand_literal(operand) + " % 8;\n";
42-
break;
43-
case opcode::JNZ:
44-
result += " if (a != 0) goto _" + std::to_string(operand) + ";\n";
45-
break;
46-
case opcode::BXC:
47-
result += " b ^= c;\n";
48-
break;
49-
case opcode::OUT:
50-
result += R"(if(first_out) {
51-
std::cout << )";
52-
result += to_combo_operand_literal(operand) + R"( % 8 << std::endl;
53-
first_out = false;
54-
} else {
55-
std::cout << "," << )";
56-
result += to_combo_operand_literal(operand) + R"( % 8 << std::endl;
57-
}
58-
)";
59-
break;
60-
case opcode::BDV:
61-
{
62-
if (operand < 4) {
63-
result += " b = a / " + std::to_string((uint8_t)std::pow(2, operand)) + ";\n";
64-
} else {
65-
result += " b = a / std::pow(2, " + to_combo_operand_literal(operand) + ");\n";
66-
}
67-
break;
68-
}
69-
case opcode::CDV:
70-
{
71-
if (operand < 4) {
72-
result += " c = a / " + std::to_string((uint8_t)std::pow(2, operand)) + ";\n";
73-
} else {
74-
result += " c = a / std::pow(2, " + to_combo_operand_literal(operand) + ");\n";
75-
}
76-
break;
77-
}
78-
}
90+
result += opcode_translation::translate_opcode(op, operand);
7991
}
8092

8193
result += R"( if (!first_out) {
8294
std::cout << std::endl;
8395
}
84-
return;\n)";
85-
result += "}\n";
86-
96+
return;
97+
}
98+
)";
8799
return result;
88100
}
89101

90-
[[nodiscard]] auto extract_helpers(chunk const & bytecode) -> std::string {
91-
std::string result = R"(#pragma once
92-
#include <cmath>
93-
#include <cstdint>
94-
#include <vector>
95-
96-
auto calculate_byte(int64_t a) -> int64_t {
97-
)";
102+
auto extract_helpers(chunk const & bytecode) -> std::string {
103+
std::string result{HELPERS_HEADER};
98104
result += " int64_t b = 0, c = 0;\n";
99105

100106
for (size_t i = 0; i < bytecode.size(); i += 2) {
101-
auto op = bytecode[i];
102-
auto operand = i + 1 < bytecode.size() ? static_cast<int64_t>(bytecode[i + 1]) : 0;
103-
104-
switch (op) {
105-
case opcode::ADV:
106-
{
107-
if (operand < 4) {
108-
result += "a = a / " + std::to_string((uint8_t)std::pow(2, operand)) + ";\n";
109-
} else {
110-
result += "a = a / std::pow(2, " + to_combo_operand_literal(operand) + ");\n";
111-
}
112-
break;
113-
}
114-
case opcode::BXL:
115-
result += "b ^= " + std::to_string(operand) + ";\n";
116-
break;
117-
case opcode::BST:
118-
result += "b = " + to_combo_operand_literal(operand) + " % 8;\n";
119-
break;
120-
case opcode::BXC:
121-
result += "b ^= c;\n";
122-
break;
123-
case opcode::BDV:
124-
{
125-
if (operand < 4) {
126-
result += "b = a / " + std::to_string((uint8_t)std::pow(2, operand)) + ";\n";
127-
} else {
128-
result += "b = a / std::pow(2, " + to_combo_operand_literal(operand) + ");\n";
129-
}
130-
break;
131-
}
132-
case opcode::CDV:
133-
{
134-
if (operand < 4) {
135-
result += "c = a / " + std::to_string((uint8_t)std::pow(2, operand)) + ";\n";
136-
} else {
137-
result += "c = a / std::pow(2, " + to_combo_operand_literal(operand) + ");\n";
138-
}
139-
break;
140-
}
141-
default:
142-
break;
107+
auto const [op, operand] =
108+
std::tuple{bytecode[i], i + 1 < bytecode.size() ? static_cast<int64_t>(bytecode[i + 1]) : 0};
109+
110+
if (op != opcode::JNZ && op != opcode::OUT) {
111+
result += opcode_translation::translate_opcode(op, operand);
143112
}
144113
}
145114

@@ -161,4 +130,5 @@ auto calculate_byte(int64_t a) -> int64_t {
161130
})";
162131
return result;
163132
}
133+
164134
} // namespace aoc::day_17

0 commit comments

Comments
 (0)