Skip to content

Commit

Permalink
Get this working, mostly
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bbrk24 committed Sep 23, 2024
1 parent 9049a24 commit 6d4371e
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 38 deletions.
2 changes: 1 addition & 1 deletion qdeql/disassembly.txt
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ ct_bgn_not_end:
ct_bgn_not_end_cleanup:
POP ; Remove the uop from the stack
DEC ; Advance the PC
JMP ct_find_end_loop
JMP ct_bgn_find_end_loop
ct_bgn_found_end:
; If PC is pointing at the end uop, the stack layout is this:
; +======+------+----+
Expand Down
6 changes: 3 additions & 3 deletions src/any_program_holder.hh
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
template<typename IP>
class any_program_holder {
public:
virtual void advance(IP& ip, std::function<bool()> go_left) const = 0;
virtual instruction at(const IP& ip) const = 0;
virtual std::string raw_at(const IP& ip) const = 0;
virtual void advance(IP& ip, std::function<bool()> go_left) = 0;
virtual instruction at(const IP& ip) = 0;
virtual std::string raw_at(const IP& ip) = 0;
virtual std::pair<size_t, size_t> get_coords(const IP& ip) const = 0;
};
42 changes: 30 additions & 12 deletions src/assembly_scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
string label = curr_line.substr(0, i);

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

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

// for (const auto& el : m_label_locations) {
// std::cout << "{ " << el.second.first << ", " << el.second.second << " }: " << el.first << std::endl;
// }

// Second pass
for (auto* fragment : *m_fragments) {
for (auto& instr : *fragment) {
Expand All @@ -196,35 +202,41 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
return m_fragments;
}

void assembly_scanner::advance(IP& ip, std::function<bool()> go_left) const {
assert(m_fragments != nullptr);
void assembly_scanner::advance(IP& ip, std::function<bool()> go_left) {
instruction i = at(ip);

const IP* to_left = at(ip).first_if_branch();
if (i.get_op() == instruction::operation::JMP) {
ip = i.get_arg().next;
return;
}

const IP* to_left = i.second_if_branch();
if (to_left != nullptr && go_left()) {
ip = *to_left;
return;
}

ip.second++;
if (ip.second > m_fragments->at(ip.first)->size()) {
if (ip.second >= m_fragments->at(ip.first)->size()) {
ip.first++;
ip.second = 0;
}
if (ip.first > m_fragments->size()) {
if (ip.first >= m_fragments->size()) {
ip.first = 0;
}
}

string assembly_scanner::raw_at(const IP& ip) const {
string assembly_scanner::raw_at(const IP& ip) {
// TODO: call disassembler::to_str (move it to somewhere common?)
return "";
char buf[12];
snprintf(buf, sizeof buf, "%" PRId32, static_cast<int32_t>(at(ip).get_op()));
return string(buf);
}

assembly_scanner::IP assembly_scanner::get_current_location() const {
size_t first = this->m_fragments->size();
size_t second = 0;
if (first > 0) {
--first;
--first;
if (first != SIZE_MAX) {
const auto* ptr = this->m_fragments->at(first);
second = ptr->size();
if (second > 0) {
Expand Down Expand Up @@ -256,7 +268,13 @@ void assembly_scanner::fake_location_to_real(IP& p) const {
#endif
static_cast<uintptr_t>(p.second);
auto ptr = reinterpret_cast<NONNULL_PTR(const string)>(reconstructed);
p = label_locations.find(*ptr)->second;
const string& str = *ptr;
auto loc = m_label_locations.find(str);
if (loc == m_label_locations.end()) {
cerr << "Undeclared label '" << str << "'" << endl;
exit(EXIT_FAILURE);
}
p = loc->second;
}

#define DESTRINGIFY_NAME(op) \
Expand Down
8 changes: 4 additions & 4 deletions src/assembly_scanner.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ public:

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

void advance(IP& ip, std::function<bool()> go_left) const;
std::string raw_at(const IP& ip) const;
void advance(IP& ip, std::function<bool()> go_left);
std::string raw_at(const IP& ip);

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

std::unordered_map<std::string, IP> label_locations;
std::unordered_map<std::string, IP> m_label_locations;
private:
IP get_current_location() const;
void add_instruction(instruction&& i);
Expand Down
10 changes: 10 additions & 0 deletions src/instruction.hh
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ public:
}
}

CONSTEXPR_UNION const pair<size_t>* second_if_branch() const noexcept {
switch (m_op) {
case operation::BNG:
case operation::TSP:
return &this->m_arg.choice.second;
default:
return nullptr;
}
}

constexpr operation get_op() const noexcept { return m_op; }
CONSTEXPR_UNION const argument& get_arg() const noexcept { return m_arg; }
protected:
Expand Down
17 changes: 12 additions & 5 deletions src/interpreter.hh
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ extern "C" void send_thread_count(size_t tc);
template<class ProgramHolder>
class interpreter {
public:
inline interpreter(const ProgramHolder& p, flags f) noexcept :
m_program_holder(p), m_threads{ thread<ProgramHolder>(p, f) } {}
inline interpreter(ProgramHolder& p, flags f) noexcept :
m_program_holder(p), m_threads{ thread<ProgramHolder>(&p, f) } {}

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

inline void split_thread(std::vector<thread<ProgramHolder>>& new_threads, const thread<ProgramHolder>& old_thread)
const {
new_threads.push_back(old_thread);
new_threads.push_back(old_thread);
thread<ProgramHolder> new_thread_1 = old_thread;
new_thread_1.m_status = thread<ProgramHolder>::status::active;
thread<ProgramHolder> new_thread_2 = new_thread_1;

m_program_holder.advance(new_thread_1.m_ip, []() { return true; });
m_program_holder.advance(new_thread_2.m_ip, []() { return false; });

new_threads.push_back(new_thread_1);
new_threads.push_back(new_thread_2);
}

const ProgramHolder& m_program_holder;
ProgramHolder& m_program_holder;
std::vector<thread<ProgramHolder>> m_threads;
};

Expand Down
6 changes: 3 additions & 3 deletions src/program_walker.hh
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public:

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

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

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

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

inline std::string raw_at(const IP& ip) const {
inline std::string raw_at(const IP& ip) {
std::ostringstream oss;
print_unichar(m_program->at(ip.coords.first, ip.coords.second), oss);
return oss.str();
Expand Down
20 changes: 10 additions & 10 deletions src/thread.hh
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,20 @@ public:
static std::uniform_int_distribution<int32_t> distr(INT24_MIN, INT24_MAX);

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

// The web interface needs every thread to send debug info. The CLI expects only active threads to do so.
#ifdef __EMSCRIPTEN__
if (m_flags.debug) {
pair<size_t, size_t> coords = m_program_holder.get_coords(m_ip);
pair<size_t, size_t> coords = m_program_holder->get_coords(m_ip);
send_debug_info(
m_number,
m_flags.show_stack ? m_stack.data() : nullptr,
m_stack.size(),
coords.first,
coords.second,
m_program_holder.raw_at(m_ip).c_str()
m_program_holder->raw_at(m_ip).c_str()
);
}
#endif
Expand All @@ -117,14 +117,14 @@ public:
#ifndef __EMSCRIPTEN__
// Print the requisite information in debug mode.
if (m_flags.debug) {
pair<size_t, size_t> coords = m_program_holder.get_coords(m_ip);
pair<size_t, size_t> coords = m_program_holder->get_coords(m_ip);
send_debug_info(
m_number,
m_flags.show_stack ? m_stack.data() : nullptr,
m_stack.size(),
coords.first,
coords.second,
m_program_holder.raw_at(m_ip).c_str()
m_program_holder->raw_at(m_ip).c_str()
);
}
#endif
Expand All @@ -133,6 +133,7 @@ public:
switch (op) {
case operation::BNG:
case operation::NOP:
case operation::JMP:
break;
case operation::ADD: {
SIZE_CHECK("add from", 2);
Expand Down Expand Up @@ -464,7 +465,7 @@ public:
default: {
cerr << "Unrecognized opcode '";
print_unichar(static_cast<int24_t>(op), cerr);
pair<size_t, size_t> coords = m_program_holder.get_coords(m_ip);
pair<size_t, size_t> coords = m_program_holder->get_coords(m_ip);
cerr << "' (at (" << coords.first << ", " << coords.second << "))\n";
thread<ProgramHolder>::flush_and_exit(EXIT_FAILURE);
}
Expand All @@ -478,19 +479,18 @@ public:

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

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

ProgramHolder m_program_holder;
ProgramHolder* m_program_holder;
std::vector<int24_t> m_stack;
NO_UNIQUE_ADDRESS typename ProgramHolder::IP m_ip;
status m_status;
Expand Down
8 changes: 8 additions & 0 deletions tests/cli/assembly/cat.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
start:
GTC
BNG end
PTC
POP
JMP start
end:
EXT
26 changes: 26 additions & 0 deletions tests/cli/assembly/index.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

set -eu

# Adapted from https://cedwards.xyz/defer-for-shell/
DEFER=''
defer () {
DEFER="$*; $DEFER"
# shellcheck disable=SC2064
trap "{ $DEFER}" EXIT
}

text='
/\_/\ ___
= ಠ_ಠ =_______ \ \
__^ __( \.__) )
(@)<_____>__(_____)____/'

folder=$(dirname "$0")

errors=$(mktemp)
defer rm "$errors"

output=$($TRILANGLE -fwA "${folder}/cat.txt" <<<"$text" 2>"$errors")
test ! -s "$errors"
test "$text" = "${output//$'\r'/}"
13 changes: 13 additions & 0 deletions tests/cli/qdeql/index.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,18 @@ run_qdeql () {
fi
}

run_qdeql_asm () {
if [ "$#" -gt 1 ]
then
printf '%s\0%s' "$(cat "$1")" "$2" | $TRILANGLE -Aaf "${root}/qdeql/disassembly.txt"
else
$TRILANGLE -A "${root}/qdeql/disassembly.txt" <"$1"
fi
}

# hello world
test 'hello world' = "$(run_qdeql "${folder}/hello.qd")"
# test 'hello world' = "$(run_qdeql_asm "${folder}/hello.qd")"

# cat
# Qdeql is limited to bytes, so this cat can't be the same Unicode cat
Expand All @@ -28,6 +38,9 @@ text='
output=$(run_qdeql "${folder}/cat.qd" "$text")
test "$text" = "${output//$'\r'/}"

# output=$(run_qdeql_asm "${folder}/cat.qd" "$text")
# test "$text" = "${output//$'\r'/}"

# truth machine
test 0 = "$(run_qdeql "${folder}/tm.qd" 0)"
test 1111111111 = "$(run_qdeql "${folder}/tm.qd" 1 | head -c 10)"
Expand Down

0 comments on commit 6d4371e

Please sign in to comment.