ast: improve error messages

This commit is contained in:
Zack Buhman 2023-08-23 20:23:09 +00:00
parent d4e6c1c717
commit 7f69f6b2e1
4 changed files with 70 additions and 22 deletions

View File

@ -1,11 +1,33 @@
#include <unordered_map>
#include "ast_emitter.hpp"
#include "error.hpp"
namespace dsp {
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
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)) {
return variables.at(identifier->name.lexeme);
} 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))
return mov_imm_d1->code() | mov_imm_d1->bits() | value;
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
@ -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
{
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
{
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
@ -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))
return src_d0_imm->code() | src_d0_imm->bits() | value;
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
@ -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))
return d0_dst_imm->code() | d0_dst_imm->bits() | value;
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
@ -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
{
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
{
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
@ -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
{
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 {
num_t value = assign->value->accept(this);
variables.insert({assign->name.lexeme, value});

View File

@ -13,6 +13,13 @@ namespace dsp {
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>
{
emitter_t(variables_t& variables, const addresses_t& addresses)

View File

@ -280,7 +280,8 @@ std::optional<op::op_t *> parser_t::xyd1_bus()
else
throw error(peek(), "expected x-bus, y-bus, or d-bus destination operand");
} 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())
return {new op::mov_imm_d1_t(imm, *dest_o)};
else
@ -365,15 +366,16 @@ load::cond_t parser_t::load_cond()
std::optional<stmt_t *> parser_t::load()
{
if (match(_mvi)) {
const token_t& expr_token = peek();
expr_t * expr = expression();
consume(comma, "expected `,`");
load::dest_t dest = parser_t::load_dest();
if (match(comma)) {
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)};
} 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)};
}
} else
@ -510,7 +512,7 @@ std::optional<stmt_t *> parser_t::dma()
if (auto length_ram_o = dma_length_ram()) {
return {new dma::d0_dst_ram_t(hold, add, dst, *length_ram_o)};
} 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)};
}
} else {
@ -521,7 +523,7 @@ std::optional<stmt_t *> parser_t::dma()
if (auto length_ram_o = dma_length_ram()) {
return {new dma::src_d0_ram_t(hold, add, src, *length_ram_o)};
} 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)};
}
}
@ -551,10 +553,10 @@ std::optional<stmt_t *> parser_t::jump()
if (match(_jmp)) {
if (auto cond_o = jump_cond()) {
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)};
} else {
uimm_t<8> imm = uimm_t<8>(expression());
uimm_t<8> imm = uimm_t<8>(peek(), expression());
return {new jump::jmp_t(imm)};
}
} else

View File

@ -29,18 +29,19 @@ struct stmt_accept_t : stmt_t {
template <bool S, int N>
struct imm_t {
imm_t(expr_t * expr)
: expr(expr) {}
imm_t(const token_t& token, const expr_t * expr)
: token(token), expr(expr) {}
const token_t& token;
const expr_t * expr;
static constexpr bool sign = S;
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
{
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;
}
};
@ -227,10 +228,10 @@ static uint32_t d1_src_bits(d1_src_t src)
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) {}
const simm_t<8> imm;
const uimm_t<8> imm;
const d1_dest_t dest;
uint32_t mask() const { return op_mask(0b11'1111'1111'1111 << 0 ); }