Skip to content

Commit

Permalink
updates for C++17
Browse files Browse the repository at this point in the history
  • Loading branch information
bbrk24 committed Oct 4, 2024
1 parent 9be41fb commit 1391816
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 72 deletions.
63 changes: 32 additions & 31 deletions src/assembly_scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using std::cerr;
using std::endl;
using std::string;
using std::string_view;
using std::string_view_literals::operator""sv;

#define WHITESPACE " \n\r\t"

Expand All @@ -16,14 +18,12 @@ using std::string;
exit(EXIT_FAILURE);
}

NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_scanner::get_fragments() {
if (m_fragments != nullptr) {
return m_fragments;
const std::vector<std::optional<std::vector<instruction>>>& assembly_scanner::get_fragments() {
if (m_fragments.has_value()) {
return *m_fragments;
}
assert(m_slices == nullptr);

m_fragments = new std::vector<NONNULL_PTR(std::vector<instruction>)>();
m_slices = new std::vector<std::vector<program_slice>>();
m_fragments.emplace(std::vector<std::optional<std::vector<instruction>>>());

// We need to do two passes: one to resolve labels, and one to assign targets to jumps. During the first pass, the
// fragments are actually constructed. However, jumps may not have valid targets yet, so we need some way to store
Expand Down Expand Up @@ -61,7 +61,7 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
}
line_end = m_program.find_first_of('\n', line_start);
string curr_line = m_program.substr(line_start, line_end - line_start);
program_slice curr_slice{ line_start, line_end };
string_view curr_slice = curr_line;

// Unquoted semicolons are comments. Remove them.
size_t i;
Expand All @@ -75,7 +75,7 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
}
if (i < curr_line.size()) {
curr_line.erase(i);
curr_slice.end = curr_slice.start + i;
curr_slice = curr_line;
}
// If the line is only a comment, move on
if (curr_line.empty()) {
Expand All @@ -87,7 +87,7 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
continue;
} else {
curr_line.erase(i + 1);
curr_slice.end = curr_slice.start + i + 1;
curr_slice = curr_line;
}

// Look for labels (non-whitespace in the first column)
Expand All @@ -101,13 +101,14 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
}
string label = curr_line.substr(0, i);

DISCARD label_names.insert(label);
[[maybe_unused]] auto _0 = label_names.insert(label);
// Add a NOP for the label to point to
// FIXME: This is a hack
add_instruction({ instruction::operation::NOP, instruction::argument() }, { curr_slice.start, i + 1 });
auto p = m_label_locations.insert({ label, get_current_location() });
string_view slice = curr_slice.substr(0, i + 1);
add_instruction({ instruction::operation::NOP, instruction::argument() }, slice);
auto [_, inserted] = m_label_locations.insert({ label, get_current_location() });

if (!p.second) {
if (!inserted) {
cerr << "Label '" << label << "' appears twice" << endl;
exit(EXIT_FAILURE);
}
Expand All @@ -122,7 +123,7 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s

// Remove leading whitespace, and label if there is one
curr_line.erase(0, i);
curr_slice.start += i;
curr_slice.remove_prefix(i);

// Line should only be the opcode and, if there is one, the argument
if (curr_line.size() < 3) {
Expand All @@ -134,7 +135,7 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
exit(EXIT_FAILURE);
}

string instruction_name = curr_line.substr(0, 3);
string_view instruction_name(curr_line.data(), 3);
instruction::operation opcode = assembly_scanner::opcode_for_name(instruction_name);
switch (opcode) {
case instruction::operation::JMP: {
Expand Down Expand Up @@ -213,7 +214,7 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
}

// Second pass
for (auto* fragment : *m_fragments) {
for (auto& fragment : *m_fragments) {
for (auto& instr : *fragment) {
if (instr.m_op == instruction::operation::JMP) {
fake_location_to_real(instr.m_arg.next);
Expand All @@ -223,7 +224,7 @@ NONNULL_PTR(const std::vector<NONNULL_PTR(std::vector<instruction>)>) assembly_s
}
}

return m_fragments;
return *m_fragments;
}

void assembly_scanner::advance(IP& ip, std::function<bool()> go_left) {
Expand Down Expand Up @@ -251,33 +252,33 @@ assembly_scanner::IP assembly_scanner::get_current_location() const {
size_t second = 0;
--first;
if (first != SIZE_MAX) {
const auto* ptr = this->m_fragments->at(first);
second = ptr->size();
const auto& fragment = this->m_fragments->at(first);
second = fragment->size();
if (second > 0) {
--second;
}
}
return { first, second };
}

void assembly_scanner::add_instruction(instruction&& i, const program_slice& s) {
assert(m_fragments != nullptr && m_slices != nullptr);
void assembly_scanner::add_instruction(instruction&& i, const string_view& s) {
assert(m_fragments.has_value());
if (m_fragments->empty()) {
assert(m_slices->empty());
assert(m_slices.empty());

m_fragments->push_back(new std::vector<instruction>{ std::move(i) });
m_slices->push_back({ s });
m_fragments->push_back(std::vector<instruction>{ std::move(i) });
m_slices.push_back({ s });
} else {
assert(!m_slices->empty());
auto last = m_fragments->back();
assert(!m_slices.empty());
auto& last = m_fragments->back();
assert(!last->empty());
if (last->back().is_exit() || last->back().first_if_branch()
|| last->back().get_op() == instruction::operation::JMP) {
m_fragments->push_back(new std::vector<instruction>{ std::move(i) });
m_slices->push_back({ s });
m_fragments->push_back(std::vector<instruction>{ std::move(i) });
m_slices.push_back({ s });
} else {
last->push_back(std::forward<instruction&&>(i));
m_slices->back().push_back(s);
m_slices.back().push_back(s);
}
}
}
Expand All @@ -299,10 +300,10 @@ void assembly_scanner::fake_location_to_real(IP& p) const {
}

#define DESTRINGIFY_NAME(op) \
if (name == #op) \
if (name == #op##sv) \
return instruction::operation::op

instruction::operation assembly_scanner::opcode_for_name(const std::string& name) noexcept {
instruction::operation assembly_scanner::opcode_for_name(const string_view& name) noexcept {
DESTRINGIFY_NAME(BNG);
DESTRINGIFY_NAME(JMP);
DESTRINGIFY_NAME(TKL);
Expand Down
41 changes: 12 additions & 29 deletions src/assembly_scanner.hh
Original file line number Diff line number Diff line change
@@ -1,54 +1,37 @@
#pragma once

#include <optional>
#include <string_view>
#include <unordered_map>
#include "any_program_holder.hh"

class assembly_scanner : public any_program_holder<std::pair<size_t, size_t>> {
public:
using IP = std::pair<size_t, size_t>;

inline assembly_scanner(const std::string& program) : m_program(program), m_fragments(nullptr), m_slices(nullptr) {}

inline ~assembly_scanner() noexcept {
if (m_fragments == nullptr) {
return;
}
delete m_slices;
for (auto* frag : *m_fragments) {
delete frag;
}
delete m_fragments;
}
CONSTEXPR_ALLOC assembly_scanner(const std::string& program) :
m_program(program), m_fragments(std::nullopt), m_slices{} {}

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

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

inline std::string raw_at(const IP& ip) {
DISCARD get_fragments();
return slice(m_slices->at(ip.first)[ip.second]);
[[maybe_unused]] auto _ = get_fragments();
return std::string(m_slices[ip.first][ip.second]);
}
inline std::pair<size_t, size_t> get_coords(const IP& ip) const { return ip; }
inline instruction at(const IP& ip) { return get_fragments()->at(ip.first)->at(ip.second); }
inline instruction at(const IP& ip) { return get_fragments()[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;
static instruction::operation opcode_for_name(const std::string_view& name) noexcept;

std::unordered_map<std::string, IP> m_label_locations;
private:
struct program_slice {
size_t start;
size_t end;

constexpr size_t length() const noexcept { return end - start; }
};

IP get_current_location() const;
void add_instruction(instruction&& i, const program_slice& s);

inline std::string slice(const program_slice& s) const { return m_program.substr(s.start, s.length()); }
void add_instruction(instruction&& i, const std::string_view& s);

std::string m_program;
std::vector<NONNULL_PTR(std::vector<instruction>)>* m_fragments;
std::vector<std::vector<program_slice>>* m_slices;
std::optional<std::vector<std::optional<std::vector<instruction>>>> m_fragments;
std::vector<std::vector<std::string_view>> m_slices;
};
6 changes: 3 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ inline void execute(const std::string& prg, flags f) {

if (f.assembly) {
assembly_scanner as(prg);
if (as.get_fragments()->size() == 0) {
if (as.get_fragments().size() == 0) {
empty_program();
}
interpreter<assembly_scanner> i(as, f);
interpreter i(as, f);
i.run();
return;
}
Expand All @@ -43,7 +43,7 @@ inline void execute(const std::string& prg, flags f) {
c.write_state(std::cout);
} else {
program_walker pw(&p);
interpreter<program_walker> i(pw, f);
interpreter i(pw, f);
i.run();
}
}
Expand Down
18 changes: 9 additions & 9 deletions src/thread.hh
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ public:
int24_t top = m_stack.back();
m_stack.pop_back();

pair<bool, int24_t> result = m_stack.back().add_with_overflow(top);
auto [overflow, value] = m_stack.back().add_with_overflow(top);

if (m_flags.warnings && result.first) UNLIKELY {
if (m_flags.warnings && overflow) UNLIKELY {
cerr << "Warning: Overflow on addition/subtraction is undefined behavior.\n";
}

m_stack.back() = result.second;
m_stack.back() = value;

break;
}
Expand All @@ -155,13 +155,13 @@ public:
int24_t top = m_stack.back();
m_stack.pop_back();

pair<bool, int24_t> result = m_stack.back().subtract_with_overflow(top);
auto [overflow, value] = m_stack.back().subtract_with_overflow(top);

if (m_flags.warnings && result.first) UNLIKELY {
if (m_flags.warnings && overflow) UNLIKELY {
cerr << "Warning: Overflow on addition/subtraction is undefined behavior.\n";
}

m_stack.back() = result.second;
m_stack.back() = value;

break;
}
Expand All @@ -170,13 +170,13 @@ public:
int24_t top = m_stack.back();
m_stack.pop_back();

pair<bool, int24_t> result = m_stack.back().multiply_with_overflow(top);
auto [overflow, value] = m_stack.back().multiply_with_overflow(top);

if (result.first) UNLIKELY {
if (m_flags.warnings && overflow) UNLIKELY {
cerr << "Warning: Overflow on multiplication is undefined behavior.\n";
}

m_stack.back() = result.second;
m_stack.back() = value;

break;
}
Expand Down

0 comments on commit 1391816

Please sign in to comment.