Skip to content

Commit 3c94d35

Browse files
committed
Get this working, mostly
There's still something subtly wrong, but I haven't diagnosed what. The new tests that reference the qdeql interpreter are ccompletely broken as a result, and therefore commented out. Further testing and bugfixing is required.
1 parent 4cae529 commit 3c94d35

File tree

11 files changed

+120
-38
lines changed

11 files changed

+120
-38
lines changed

qdeql/disassembly.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ ct_bgn_not_end:
296296
ct_bgn_not_end_cleanup:
297297
POP ; Remove the uop from the stack
298298
DEC ; Advance the PC
299-
JMP ct_find_end_loop
299+
JMP ct_bgn_find_end_loop
300300
ct_bgn_found_end:
301301
; If PC is pointing at the end uop, the stack layout is this:
302302
; +======+------+----+

src/any_program_holder.hh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
template<typename IP>
77
class any_program_holder {
88
public:
9-
virtual void advance(IP& ip, std::function<bool()> go_left) const = 0;
10-
virtual instruction at(const IP& ip) const = 0;
11-
virtual std::string raw_at(const IP& ip) const = 0;
9+
virtual void advance(IP& ip, std::function<bool()> go_left) = 0;
10+
virtual instruction at(const IP& ip) = 0;
11+
virtual std::string raw_at(const IP& ip) = 0;
1212
virtual std::pair<size_t, size_t> get_coords(const IP& ip) const = 0;
1313
};

src/assembly_scanner.cpp

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
8787
string label = curr_line.substr(0, i);
8888

8989
DISCARD label_names.insert(label);
90-
auto p = label_locations.insert({ label, get_current_location() });
90+
// Add a NOP for the label to point to
91+
add_instruction({ instruction::operation::NOP, instruction::argument() });
92+
auto p = m_label_locations.insert({ label, get_current_location() });
9193

9294
if (!p.second) {
9395
cerr << "Label '" << label << "' appears twice" << endl;
@@ -182,6 +184,10 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
182184
}
183185
}
184186

187+
// for (const auto& el : m_label_locations) {
188+
// std::cout << "{ " << el.second.first << ", " << el.second.second << " }: " << el.first << std::endl;
189+
// }
190+
185191
// Second pass
186192
for (auto* fragment : *m_fragments) {
187193
for (auto& instr : *fragment) {
@@ -196,35 +202,41 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
196202
return m_fragments;
197203
}
198204

199-
void assembly_scanner::advance(IP& ip, std::function<bool()> go_left) const {
200-
assert(m_fragments != nullptr);
205+
void assembly_scanner::advance(IP& ip, std::function<bool()> go_left) {
206+
instruction i = at(ip);
201207

202-
const IP* to_left = at(ip).first_if_branch();
208+
if (i.get_op() == instruction::operation::JMP) {
209+
ip = i.get_arg().next;
210+
return;
211+
}
212+
213+
const IP* to_left = i.second_if_branch();
203214
if (to_left != nullptr && go_left()) {
204215
ip = *to_left;
205-
return;
206216
}
207217

208218
ip.second++;
209-
if (ip.second > m_fragments->at(ip.first)->size()) {
219+
if (ip.second >= m_fragments->at(ip.first)->size()) {
210220
ip.first++;
211221
ip.second = 0;
212222
}
213-
if (ip.first > m_fragments->size()) {
223+
if (ip.first >= m_fragments->size()) {
214224
ip.first = 0;
215225
}
216226
}
217227

218-
string assembly_scanner::raw_at(const IP& ip) const {
228+
string assembly_scanner::raw_at(const IP& ip) {
219229
// TODO: call disassembler::to_str (move it to somewhere common?)
220-
return "";
230+
char buf[12];
231+
snprintf(buf, sizeof buf, "%" PRId32, static_cast<int32_t>(at(ip).get_op()));
232+
return string(buf);
221233
}
222234

223235
assembly_scanner::IP assembly_scanner::get_current_location() const {
224236
size_t first = this->m_fragments->size();
225237
size_t second = 0;
226-
if (first > 0) {
227-
--first;
238+
--first;
239+
if (first != SIZE_MAX) {
228240
const auto* ptr = this->m_fragments->at(first);
229241
second = ptr->size();
230242
if (second > 0) {
@@ -256,7 +268,13 @@ void assembly_scanner::fake_location_to_real(IP& p) const {
256268
#endif
257269
static_cast<uintptr_t>(p.second);
258270
auto ptr = reinterpret_cast<NONNULL_PTR(const string)>(reconstructed);
259-
p = label_locations.find(*ptr)->second;
271+
const string& str = *ptr;
272+
auto loc = m_label_locations.find(str);
273+
if (loc == m_label_locations.end()) {
274+
cerr << "Undeclared label '" << str << "'" << endl;
275+
exit(EXIT_FAILURE);
276+
}
277+
p = loc->second;
260278
}
261279

262280
#define DESTRINGIFY_NAME(op) \

src/assembly_scanner.hh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ public:
2222

2323
NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) get_fragments();
2424

25-
void advance(IP& ip, std::function<bool()> go_left) const;
26-
std::string raw_at(const IP& ip) const;
25+
void advance(IP& ip, std::function<bool()> go_left);
26+
std::string raw_at(const IP& ip);
2727

2828
inline std::pair<size_t, size_t> get_coords(const IP& ip) const { return ip; }
29-
inline instruction at(const IP& ip) const { return m_fragments->at(ip.first)->at(ip.second); }
29+
inline instruction at(const IP& ip) { return get_fragments()->at(ip.first)->at(ip.second); }
3030
protected:
3131
void fake_location_to_real(IP& p) const;
3232
static instruction::operation opcode_for_name(const std::string& name) noexcept;
3333

34-
std::unordered_map<std::string, IP> label_locations;
34+
std::unordered_map<std::string, IP> m_label_locations;
3535
private:
3636
IP get_current_location() const;
3737
void add_instruction(instruction&& i);

src/instruction.hh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ public:
6767
}
6868
}
6969

70+
CONSTEXPR_UNION const pair<size_t>* second_if_branch() const noexcept {
71+
switch (m_op) {
72+
case operation::BNG:
73+
case operation::TSP:
74+
return &this->m_arg.choice.second;
75+
default:
76+
return nullptr;
77+
}
78+
}
79+
7080
constexpr operation get_op() const noexcept { return m_op; }
7181
CONSTEXPR_UNION const argument& get_arg() const noexcept { return m_arg; }
7282
protected:

src/interpreter.hh

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ extern "C" void send_thread_count(size_t tc);
1414
template<class ProgramHolder>
1515
class interpreter {
1616
public:
17-
inline interpreter(const ProgramHolder& p, flags f) noexcept :
18-
m_program_holder(p), m_threads{ thread<ProgramHolder>(p, f) } {}
17+
inline interpreter(ProgramHolder& p, flags f) noexcept :
18+
m_program_holder(p), m_threads{ thread<ProgramHolder>(&p, f) } {}
1919

2020
inline void run() {
2121
using status = typename thread<ProgramHolder>::status;
@@ -152,11 +152,18 @@ private:
152152

153153
inline void split_thread(std::vector<thread<ProgramHolder>>& new_threads, const thread<ProgramHolder>& old_thread)
154154
const {
155-
new_threads.push_back(old_thread);
156-
new_threads.push_back(old_thread);
155+
thread<ProgramHolder> new_thread_1 = old_thread;
156+
new_thread_1.m_status = thread<ProgramHolder>::status::active;
157+
thread<ProgramHolder> new_thread_2 = new_thread_1;
158+
159+
m_program_holder.advance(new_thread_1.m_ip, []() { return true; });
160+
m_program_holder.advance(new_thread_2.m_ip, []() { return false; });
161+
162+
new_threads.push_back(new_thread_1);
163+
new_threads.push_back(new_thread_2);
157164
}
158165

159-
const ProgramHolder& m_program_holder;
166+
ProgramHolder& m_program_holder;
160167
std::vector<thread<ProgramHolder>> m_threads;
161168
};
162169

src/program_walker.hh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public:
5252

5353
constexpr program_walker(NONNULL_PTR(const program) p) noexcept : m_program(p) {}
5454

55-
inline void advance(IP& ip, std::function<bool()> go_left) const {
55+
inline void advance(IP& ip, std::function<bool()> go_left) {
5656
int24_t op = m_program->at(ip.coords.first, ip.coords.second);
5757
switch (op) {
5858
case MIR_EW:
@@ -80,7 +80,7 @@ public:
8080
program_walker::advance(ip, m_program->side_length());
8181
}
8282

83-
inline instruction at(const IP& ip) const noexcept {
83+
inline instruction at(const IP& ip) noexcept {
8484
int24_t op = m_program->at(ip.coords.first, ip.coords.second);
8585
if (is_branch(op, ip.dir)) {
8686
if (op == static_cast<int24_t>(THR_E) || op == static_cast<int24_t>(THR_W)) {
@@ -96,7 +96,7 @@ public:
9696

9797
inline std::pair<size_t, size_t> get_coords(const IP& ip) const { return ip.coords; }
9898

99-
inline std::string raw_at(const IP& ip) const {
99+
inline std::string raw_at(const IP& ip) {
100100
std::ostringstream oss;
101101
print_unichar(m_program->at(ip.coords.first, ip.coords.second), oss);
102102
return oss.str();

src/thread.hh

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,20 @@ public:
8282
static std::uniform_int_distribution<int32_t> distr(INT24_MIN, INT24_MAX);
8383

8484
// The operation currently being executed
85-
instruction instr = m_program_holder.at(m_ip);
85+
instruction instr = m_program_holder->at(m_ip);
8686
operation op = instr.get_op();
8787

8888
// The web interface needs every thread to send debug info. The CLI expects only active threads to do so.
8989
#ifdef __EMSCRIPTEN__
9090
if (m_flags.debug) {
91-
pair<size_t, size_t> coords = m_program_holder.get_coords(m_ip);
91+
pair<size_t, size_t> coords = m_program_holder->get_coords(m_ip);
9292
send_debug_info(
9393
m_number,
9494
m_flags.show_stack ? m_stack.data() : nullptr,
9595
m_stack.size(),
9696
coords.first,
9797
coords.second,
98-
m_program_holder.raw_at(m_ip).c_str()
98+
m_program_holder->raw_at(m_ip).c_str()
9999
);
100100
}
101101
#endif
@@ -117,14 +117,14 @@ public:
117117
#ifndef __EMSCRIPTEN__
118118
// Print the requisite information in debug mode.
119119
if (m_flags.debug) {
120-
pair<size_t, size_t> coords = m_program_holder.get_coords(m_ip);
120+
pair<size_t, size_t> coords = m_program_holder->get_coords(m_ip);
121121
send_debug_info(
122122
m_number,
123123
m_flags.show_stack ? m_stack.data() : nullptr,
124124
m_stack.size(),
125125
coords.first,
126126
coords.second,
127-
m_program_holder.raw_at(m_ip).c_str()
127+
m_program_holder->raw_at(m_ip).c_str()
128128
);
129129
}
130130
#endif
@@ -133,6 +133,7 @@ public:
133133
switch (op) {
134134
case operation::BNG:
135135
case operation::NOP:
136+
case operation::JMP:
136137
break;
137138
case operation::ADD: {
138139
SIZE_CHECK("add from", 2);
@@ -464,7 +465,7 @@ public:
464465
default: {
465466
cerr << "Unrecognized opcode '";
466467
print_unichar(static_cast<int24_t>(op), cerr);
467-
pair<size_t, size_t> coords = m_program_holder.get_coords(m_ip);
468+
pair<size_t, size_t> coords = m_program_holder->get_coords(m_ip);
468469
cerr << "' (at (" << coords.first << ", " << coords.second << "))\n";
469470
thread<ProgramHolder>::flush_and_exit(EXIT_FAILURE);
470471
}
@@ -478,19 +479,18 @@ public:
478479

479480
#undef SIZE_CHECK
480481
protected:
481-
inline thread(const ProgramHolder& ph, flags f) noexcept :
482+
inline thread(ProgramHolder* ph, flags f) noexcept :
482483
m_program_holder(ph), m_stack(), m_ip(), m_status(status::active), m_flags(f), m_number(thread_count++) {}
483484

484485
constexpr void advance() noexcept {
485-
// FIXME: Segfaults when spawning a new thread with an empty stack
486-
m_program_holder.advance(m_ip, [&]() NOEXCEPT_T {
486+
m_program_holder->advance(m_ip, [&]() NOEXCEPT_T {
487487
EMPTY_PROTECT("branch on") {}
488488
return m_stack.back() < INT24_C(0);
489489
});
490490
}
491491
#undef EMPTY_PROTECT
492492

493-
ProgramHolder m_program_holder;
493+
ProgramHolder* m_program_holder;
494494
std::vector<int24_t> m_stack;
495495
NO_UNIQUE_ADDRESS typename ProgramHolder::IP m_ip;
496496
status m_status;

tests/cli/assembly/cat.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
start:
2+
GTC
3+
BNG end
4+
PTC
5+
POP
6+
JMP start
7+
end:
8+
EXT

tests/cli/assembly/index.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
3+
set -eu
4+
5+
# Adapted from https://cedwards.xyz/defer-for-shell/
6+
DEFER=''
7+
defer () {
8+
DEFER="$*; $DEFER"
9+
# shellcheck disable=SC2064
10+
trap "{ $DEFER}" EXIT
11+
}
12+
13+
text='
14+
/\_/\ ___
15+
= ಠ_ಠ =_______ \ \
16+
__^ __( \.__) )
17+
(@)<_____>__(_____)____/'
18+
19+
folder=$(dirname "$0")
20+
21+
errors=$(mktemp)
22+
defer rm "$errors"
23+
24+
output=$($TRILANGLE -fwA "${folder}/cat.txt" <<<"$text" 2>"$errors")
25+
test ! -s "$errors"
26+
test "$text" = "${output//$'\r'/}"

0 commit comments

Comments
 (0)