Compare commits

..

3 Commits

Author SHA1 Message Date
0df0b66a6e main: add file output 2023-08-23 22:56:54 +00:00
37fe5d5f81 parser: add error hint for x = 1
I've accidentally attempted this multiple times myself during testing.
2023-08-23 20:41:23 +00:00
7f69f6b2e1 ast: improve error messages 2023-08-23 20:23:09 +00:00
5 changed files with 114 additions and 36 deletions

View File

@ -1,11 +1,33 @@
#include <unordered_map> #include <unordered_map>
#include "ast_emitter.hpp" #include "ast_emitter.hpp"
#include "error.hpp"
namespace dsp { namespace dsp {
namespace ast { namespace ast {
static emitter_error_t error(const token_t& token, const std::string message)
{
dsp::error(token, message);
return emitter_error_t(message);
}
template <bool S, int N>
static emitter_error_t imm_out_of_range(const imm_t<S, N>& imm, num_t value)
{
using imm_type = imm_t<S, N>;
std::string message = "immediate value is out of range";
dsp::error(imm.token, message);
std::cerr << "note:" << std::endl
<< " expect range: ["
<< imm_type::min << ',' << imm_type::max
<< ']' << std::endl
<< " actual value: " << value << std::endl;
return emitter_error_t(message);
}
// expressions // expressions
uint32_t emitter_t::visit(const binary_t * binary) const uint32_t emitter_t::visit(const binary_t * binary) const
@ -41,7 +63,7 @@ uint32_t emitter_t::visit(const identifier_t * identifier) const
if (variables.contains(identifier->name.lexeme)) { if (variables.contains(identifier->name.lexeme)) {
return variables.at(identifier->name.lexeme); return variables.at(identifier->name.lexeme);
} else { } else {
throw std::runtime_error("undefined identifier"); throw ast::error(identifier->name, "undefined identifier");
} }
} }
@ -113,7 +135,7 @@ uint32_t emitter_t::visit(const op::mov_imm_d1_t * mov_imm_d1) const
if (mov_imm_d1->imm.in_range(value)) if (mov_imm_d1->imm.in_range(value))
return mov_imm_d1->code() | mov_imm_d1->bits() | value; return mov_imm_d1->code() | mov_imm_d1->bits() | value;
else else
throw std::runtime_error("out of range"); throw imm_out_of_range(mov_imm_d1->imm, value);
} }
uint32_t emitter_t::visit(const op::mov_ram_d1_t * mov_ram_d1) const uint32_t emitter_t::visit(const op::mov_ram_d1_t * mov_ram_d1) const
@ -130,12 +152,20 @@ uint32_t emitter_t::visit(const op::control_word_t * control_word) const
uint32_t emitter_t::visit(const load::mvi_t * mvi) const uint32_t emitter_t::visit(const load::mvi_t * mvi) const
{ {
return mvi->code() | mvi->bits(); num_t value = mvi->imm.expr->accept(this);
if (mvi->imm.in_range(value))
return mvi->code() | mvi->bits() | value;
else
throw imm_out_of_range(mvi->imm, value);
} }
uint32_t emitter_t::visit(const load::mvi_cond_t * mvi_cond) const uint32_t emitter_t::visit(const load::mvi_cond_t * mvi_cond) const
{ {
return mvi_cond->code() | mvi_cond->bits(); num_t value = mvi_cond->imm.expr->accept(this);
if (mvi_cond->imm.in_range(value))
return mvi_cond->code() | mvi_cond->bits() | value;
else
throw imm_out_of_range(mvi_cond->imm, value);
} }
uint32_t emitter_t::visit(const dma::src_d0_imm_t * src_d0_imm) const uint32_t emitter_t::visit(const dma::src_d0_imm_t * src_d0_imm) const
@ -144,7 +174,7 @@ uint32_t emitter_t::visit(const dma::src_d0_imm_t * src_d0_imm) const
if (src_d0_imm->imm.in_range(value)) if (src_d0_imm->imm.in_range(value))
return src_d0_imm->code() | src_d0_imm->bits() | value; return src_d0_imm->code() | src_d0_imm->bits() | value;
else else
throw std::runtime_error("out of range"); throw imm_out_of_range(src_d0_imm->imm, value);
} }
uint32_t emitter_t::visit(const dma::d0_dst_imm_t * d0_dst_imm) const uint32_t emitter_t::visit(const dma::d0_dst_imm_t * d0_dst_imm) const
@ -153,7 +183,7 @@ uint32_t emitter_t::visit(const dma::d0_dst_imm_t * d0_dst_imm) const
if (d0_dst_imm->imm.in_range(value)) if (d0_dst_imm->imm.in_range(value))
return d0_dst_imm->code() | d0_dst_imm->bits() | value; return d0_dst_imm->code() | d0_dst_imm->bits() | value;
else else
throw std::runtime_error("out of range"); throw imm_out_of_range(d0_dst_imm->imm, value);
} }
uint32_t emitter_t::visit(const dma::src_d0_ram_t * src_d0_ram) const uint32_t emitter_t::visit(const dma::src_d0_ram_t * src_d0_ram) const
@ -168,12 +198,20 @@ uint32_t emitter_t::visit(const dma::d0_dst_ram_t * d0_dst_ram) const
uint32_t emitter_t::visit(const jump::jmp_t * jmp) const uint32_t emitter_t::visit(const jump::jmp_t * jmp) const
{ {
return jmp->code() | jmp->bits(); num_t value = jmp->imm.expr->accept(this);
if (jmp->imm.in_range(value))
return jmp->code() | jmp->bits() | value;
else
throw imm_out_of_range(jmp->imm, value);
} }
uint32_t emitter_t::visit(const jump::jmp_cond_t * jmp_cond) const uint32_t emitter_t::visit(const jump::jmp_cond_t * jmp_cond) const
{ {
return jmp_cond->code() | jmp_cond->bits(); num_t value = jmp_cond->imm.expr->accept(this);
if (jmp_cond->imm.in_range(value))
return jmp_cond->code() | jmp_cond->bits() | value;
else
throw imm_out_of_range(jmp_cond->imm, value);
} }
uint32_t emitter_t::visit(const loop::btm_t * btm) const uint32_t emitter_t::visit(const loop::btm_t * btm) const
@ -204,7 +242,7 @@ uint32_t emitter_t::visit(const nop::nop_t * nop) const
uint32_t emitter_t::visit(const assign_t * assign) const uint32_t emitter_t::visit(const assign_t * assign) const
{ {
if (variables.contains(assign->name.lexeme)) { if (variables.contains(assign->name.lexeme)) {
throw std::runtime_error("assignment redefinition is not allowed"); throw ast::error(assign->name, "assignment redefinition is not allowed");
} else { } else {
num_t value = assign->value->accept(this); num_t value = assign->value->accept(this);
variables.insert({assign->name.lexeme, value}); variables.insert({assign->name.lexeme, value});

View File

@ -13,6 +13,13 @@ namespace dsp {
namespace ast { namespace ast {
struct emitter_error_t : std::runtime_error
{
emitter_error_t(const std::string& msg)
: std::runtime_error(msg)
{ }
};
struct emitter_t : visitor_t<uint32_t> struct emitter_t : visitor_t<uint32_t>
{ {
emitter_t(variables_t& variables, const addresses_t& addresses) emitter_t(variables_t& variables, const addresses_t& addresses)

View File

@ -3,6 +3,7 @@
#include <string> #include <string>
#include <optional> #include <optional>
#include <bitset> #include <bitset>
#include <sstream>
#include "lexer.hpp" #include "lexer.hpp"
#include "token.hpp" #include "token.hpp"
@ -17,7 +18,18 @@ bool had_error = false;
} }
static void run(std::string source) static void write(std::ostream& os, uint32_t v)
{
const char out[4] = {
static_cast<char>((v >> 24) & 0xff),
static_cast<char>((v >> 16) & 0xff),
static_cast<char>((v >> 8 ) & 0xff),
static_cast<char>((v >> 0 ) & 0xff),
};
os.write(out, 4);
}
static void run(std::ostream& os, std::string source)
{ {
using namespace dsp; using namespace dsp;
@ -41,6 +53,7 @@ static void run(std::string source)
uint32_t output = (*stmt_o)->accept(&emitter); uint32_t output = (*stmt_o)->accept(&emitter);
if (output != 0xffff'ffff) { if (output != 0xffff'ffff) {
std::cout << std::bitset<32>(output) << std::endl; std::cout << std::bitset<32>(output) << std::endl;
write(os, output);
} }
} }
} }
@ -51,16 +64,17 @@ static void run_prompt()
std::string line; std::string line;
std::cout << prompt << std::flush; std::cout << prompt << std::flush;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
run(line); std::ostringstream os;
run(os, line);
std::cout << prompt << std::flush; std::cout << prompt << std::flush;
} }
} }
static int run_file(char const * const filename) static int run_file(char const * const input_filename, char const * const output_filename)
{ {
std::ifstream is {filename, std::ios::binary | std::ios::ate}; std::ifstream is {input_filename, std::ios::binary | std::ios::ate};
if (!is.is_open()) { if (!is.is_open()) {
std::cerr << "failed to open " << filename << std::endl; std::cerr << "failed to open " << input_filename << std::endl;
return -1; return -1;
} }
const std::streampos size = is.tellg(); const std::streampos size = is.tellg();
@ -70,7 +84,19 @@ static int run_file(char const * const filename)
std::cerr << "read failed" << std::endl; std::cerr << "read failed" << std::endl;
return -1; return -1;
} }
run(buf);
std::ostringstream os;
run(os, buf);
if (!dsp::had_error) {
std::ofstream ofs {output_filename, std::ios::binary | std::ios::trunc};
if (!ofs.is_open()) {
std::cerr << "failed to open " << output_filename << std::endl;
return -1;
}
ofs << os.str();
}
return dsp::had_error; return dsp::had_error;
} }
@ -78,9 +104,9 @@ int main(const int argc, char const * const argv[])
{ {
switch (argc) { switch (argc) {
case 1: run_prompt(); return dsp::had_error; case 1: run_prompt(); return dsp::had_error;
case 2: return run_file(argv[1]); case 3: return run_file(argv[1], argv[2]);
default: default:
std::cerr << "Usage: " << argv[0] << " [filename]" << std::endl; std::cerr << "Usage: " << argv[0] << " [input-filename output-filename]" << std::endl;
return -1; return -1;
} }
} }

View File

@ -280,7 +280,8 @@ std::optional<op::op_t *> parser_t::xyd1_bus()
else else
throw error(peek(), "expected x-bus, y-bus, or d-bus destination operand"); throw error(peek(), "expected x-bus, y-bus, or d-bus destination operand");
} else { } else {
simm_t<8> imm = simm_t<8>(expression()); uimm_t<8> imm = uimm_t<8>(peek(), expression());
consume(comma, "expected `,`");
if (auto dest_o = d1_dest()) if (auto dest_o = d1_dest())
return {new op::mov_imm_d1_t(imm, *dest_o)}; return {new op::mov_imm_d1_t(imm, *dest_o)};
else else
@ -365,15 +366,16 @@ load::cond_t parser_t::load_cond()
std::optional<stmt_t *> parser_t::load() std::optional<stmt_t *> parser_t::load()
{ {
if (match(_mvi)) { if (match(_mvi)) {
const token_t& expr_token = peek();
expr_t * expr = expression(); expr_t * expr = expression();
consume(comma, "expected `,`"); consume(comma, "expected `,`");
load::dest_t dest = parser_t::load_dest(); load::dest_t dest = parser_t::load_dest();
if (match(comma)) { if (match(comma)) {
load::cond_t cond = load_cond(); load::cond_t cond = load_cond();
uimm_t<19> imm = uimm_t<19>(expr); uimm_t<19> imm = uimm_t<19>(expr_token, expr);
return {new load::mvi_cond_t(imm, dest, cond)}; return {new load::mvi_cond_t(imm, dest, cond)};
} else { } else {
uimm_t<25> imm = uimm_t<25>(expr); uimm_t<25> imm = uimm_t<25>(expr_token, expr);
return {new load::mvi_t(imm, dest)}; return {new load::mvi_t(imm, dest)};
} }
} else } else
@ -510,7 +512,7 @@ std::optional<stmt_t *> parser_t::dma()
if (auto length_ram_o = dma_length_ram()) { if (auto length_ram_o = dma_length_ram()) {
return {new dma::d0_dst_ram_t(hold, add, dst, *length_ram_o)}; return {new dma::d0_dst_ram_t(hold, add, dst, *length_ram_o)};
} else { } else {
uimm_t<8> imm = uimm_t<8>(expression()); uimm_t<8> imm = uimm_t<8>(peek(), expression());
return {new dma::d0_dst_imm_t(hold, add, dst, imm)}; return {new dma::d0_dst_imm_t(hold, add, dst, imm)};
} }
} else { } else {
@ -521,7 +523,7 @@ std::optional<stmt_t *> parser_t::dma()
if (auto length_ram_o = dma_length_ram()) { if (auto length_ram_o = dma_length_ram()) {
return {new dma::src_d0_ram_t(hold, add, src, *length_ram_o)}; return {new dma::src_d0_ram_t(hold, add, src, *length_ram_o)};
} else { } else {
uimm_t<8> imm = uimm_t<8>(expression()); uimm_t<8> imm = uimm_t<8>(peek(), expression());
return {new dma::src_d0_imm_t(hold, add, src, imm)}; return {new dma::src_d0_imm_t(hold, add, src, imm)};
} }
} }
@ -551,10 +553,10 @@ std::optional<stmt_t *> parser_t::jump()
if (match(_jmp)) { if (match(_jmp)) {
if (auto cond_o = jump_cond()) { if (auto cond_o = jump_cond()) {
consume(comma, "expected `,` after jump condition"); consume(comma, "expected `,` after jump condition");
uimm_t<8> imm = uimm_t<8>(expression()); uimm_t<8> imm = uimm_t<8>(peek(), expression());
return {new jump::jmp_cond_t(*cond_o, imm)}; return {new jump::jmp_cond_t(*cond_o, imm)};
} else { } else {
uimm_t<8> imm = uimm_t<8>(expression()); uimm_t<8> imm = uimm_t<8>(peek(), expression());
return {new jump::jmp_t(imm)}; return {new jump::jmp_t(imm)};
} }
} else } else
@ -613,7 +615,11 @@ std::optional<stmt_t *> parser_t::statement()
else else
throw error(peek(), "expected eol or eof after instruction"); throw error(peek(), "expected eol or eof after instruction");
} else { } else {
throw error(peek(), "expected statement"); auto exc = error(peek(), "expected statement");
advance();
if (check(equal) || check(_equ))
std::cerr << "hint: it is not legal to assign a value to a keyword" << std::endl;
throw exc;
} }
} }

View File

@ -29,18 +29,19 @@ struct stmt_accept_t : stmt_t {
template <bool S, int N> template <bool S, int N>
struct imm_t { struct imm_t {
imm_t(expr_t * expr) imm_t(const token_t& token, const expr_t * expr)
: expr(expr) {} : token(token), expr(expr) {}
const token_t& token;
const expr_t * expr; const expr_t * expr;
static constexpr bool sign = S; static constexpr bool sign = S;
static constexpr int bits = N; static constexpr int bits = N;
static constexpr num_t max = (1L << (bits - static_cast<num_t>(sign))) - 1;
static constexpr num_t min = sign ? -(max + 1) : 0;
bool in_range(num_t value) const bool in_range(num_t value) const
{ {
constexpr num_t max = (1L << (bits - static_cast<num_t>(sign))) - 1;
constexpr num_t min = sign ? -(max + 1) : 0;
return value <= max && value >= min; return value <= max && value >= min;
} }
}; };
@ -227,14 +228,14 @@ static uint32_t d1_src_bits(d1_src_t src)
struct mov_imm_d1_t : op_t, stmt_accept_t<mov_imm_d1_t> struct mov_imm_d1_t : op_t, stmt_accept_t<mov_imm_d1_t>
{ {
mov_imm_d1_t(simm_t<8> imm, d1_dest_t dest) mov_imm_d1_t(uimm_t<8> imm, d1_dest_t dest)
: imm(imm), dest(dest) {} : imm(imm), dest(dest) {}
const simm_t<8> imm; const uimm_t<8> imm;
const d1_dest_t dest; const d1_dest_t dest;
uint32_t mask() const { return op_mask(0b11'1111'1111'1111 << 0 ); } uint32_t mask() const { return op_mask(0b11'1111'1111'1111 << 0); }
uint32_t code() const { return op_code(0b01'0000'0000'0000 << 14); } uint32_t code() const { return op_code(0b01'0000'0000'0000 << 0); }
uint32_t bits() const { return d1_dest_bits(dest); } uint32_t bits() const { return d1_dest_bits(dest); }
}; };
@ -246,8 +247,8 @@ struct mov_ram_d1_t : op_t, stmt_accept_t<mov_ram_d1_t>
const d1_src_t src; const d1_src_t src;
const d1_dest_t dest; const d1_dest_t dest;
uint32_t mask() const { return op_mask(0b11'1111'0000'1111 << 0 ); } uint32_t mask() const { return op_mask(0b11'1111'0000'1111 << 0); }
uint32_t code() const { return op_code(0b11'0000'0000'0000 << 14); } uint32_t code() const { return op_code(0b11'0000'0000'0000 << 0); }
uint32_t bits() const { return d1_dest_bits(dest) | d1_src_bits(src); } uint32_t bits() const { return d1_dest_bits(dest) | d1_src_bits(src); }
}; };