Compare commits
3 Commits
d4e6c1c717
...
0df0b66a6e
| Author | SHA1 | Date | |
|---|---|---|---|
| 0df0b66a6e | |||
| 37fe5d5f81 | |||
| 7f69f6b2e1 |
@ -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});
|
||||
|
||||
@ -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)
|
||||
|
||||
42
main.cpp
42
main.cpp
@ -3,6 +3,7 @@
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <bitset>
|
||||
#include <sstream>
|
||||
|
||||
#include "lexer.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;
|
||||
|
||||
@ -41,6 +53,7 @@ static void run(std::string source)
|
||||
uint32_t output = (*stmt_o)->accept(&emitter);
|
||||
if (output != 0xffff'ffff) {
|
||||
std::cout << std::bitset<32>(output) << std::endl;
|
||||
write(os, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,16 +64,17 @@ static void run_prompt()
|
||||
std::string line;
|
||||
std::cout << prompt << std::flush;
|
||||
while (std::getline(std::cin, line)) {
|
||||
run(line);
|
||||
std::ostringstream os;
|
||||
run(os, line);
|
||||
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()) {
|
||||
std::cerr << "failed to open " << filename << std::endl;
|
||||
std::cerr << "failed to open " << input_filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
const std::streampos size = is.tellg();
|
||||
@ -70,7 +84,19 @@ static int run_file(char const * const filename)
|
||||
std::cerr << "read failed" << std::endl;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -78,9 +104,9 @@ int main(const int argc, char const * const argv[])
|
||||
{
|
||||
switch (argc) {
|
||||
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:
|
||||
std::cerr << "Usage: " << argv[0] << " [filename]" << std::endl;
|
||||
std::cerr << "Usage: " << argv[0] << " [input-filename output-filename]" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
22
parser.cpp
22
parser.cpp
@ -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
|
||||
@ -613,7 +615,11 @@ std::optional<stmt_t *> parser_t::statement()
|
||||
else
|
||||
throw error(peek(), "expected eol or eof after instruction");
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21
stmt.hpp
21
stmt.hpp
@ -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,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>
|
||||
{
|
||||
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 ); }
|
||||
uint32_t code() const { return op_code(0b01'0000'0000'0000 << 14); }
|
||||
uint32_t mask() const { return op_mask(0b11'1111'1111'1111 << 0); }
|
||||
uint32_t code() const { return op_code(0b01'0000'0000'0000 << 0); }
|
||||
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_dest_t dest;
|
||||
|
||||
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 mask() const { return op_mask(0b11'1111'0000'1111 << 0); }
|
||||
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); }
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user