Reworked macros
This commit is contained in:
parent
77d807a17d
commit
972df2f6d7
|
@ -1,3 +1,14 @@
|
||||||
|
//! Holey Bytes Assembler
|
||||||
|
//!
|
||||||
|
//! Some people claim:
|
||||||
|
//! > Write programs to handle text streams, because that is a universal interface.
|
||||||
|
//!
|
||||||
|
//! We at AbleCorp believe that nice programatic API is nicer than piping some text
|
||||||
|
//! into a program. It's less error-prone and faster.
|
||||||
|
//!
|
||||||
|
//! So this crate contains both assembleer with API for programs and a text assembler
|
||||||
|
//! for humans to write
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
@ -17,18 +28,10 @@ pub struct Assembler {
|
||||||
pub sub: HashSet<usize>,
|
pub sub: HashSet<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hbbytecode::invoke_with_def!(macros::text::gen_text);
|
||||||
// Implement both assembler and generate module for text-code-based one
|
|
||||||
hbbytecode::invoke_with_def!(macros::impl_all);
|
|
||||||
|
|
||||||
impl Assembler {
|
impl Assembler {
|
||||||
// Special-cased for text-assembler
|
hbbytecode::invoke_with_def!(macros::asm::impl_asm);
|
||||||
//
|
|
||||||
// `p2` is not a register, but the instruction is still BBB
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn i_brc(&mut self, p0: u8, p1: u8, p2: u8) {
|
|
||||||
self.i_param_bbb(hbbytecode::opcode::BRC, p0, p1, p2)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Append 12 zeroes (UN) at the end
|
/// Append 12 zeroes (UN) at the end
|
||||||
///
|
///
|
||||||
|
|
|
@ -4,55 +4,3 @@
|
||||||
|
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
|
|
||||||
#[allow(rustdoc::invalid_rust_codeblocks)]
|
|
||||||
/// Generate code for both programmatic-interface assembler and
|
|
||||||
/// textural interface.
|
|
||||||
///
|
|
||||||
/// Some people claim:
|
|
||||||
/// > Write programs to handle text streams, because that is a universal interface.
|
|
||||||
///
|
|
||||||
/// We at AbleCorp believe that nice programatic API is nicer than piping some text
|
|
||||||
/// into a program. It's less error-prone and faster.
|
|
||||||
///
|
|
||||||
/// # Syntax
|
|
||||||
/// ```no_run
|
|
||||||
/// impl_all!(
|
|
||||||
/// INSTRUCTION_TYPE(p0: TYPE, p1: TYPE, …)
|
|
||||||
/// => [INSTRUCTION_A, INSTRUCTION_B, …],
|
|
||||||
/// …
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
/// - Instruction type determines opcode-generic, instruction-type-specific
|
|
||||||
/// function. Name: `i_param_INSTRUCTION_TYPE`
|
|
||||||
/// - Per-instructions there will be generated opcode-specific functions calling the generic ones
|
|
||||||
/// - Operand types
|
|
||||||
/// - R: Register (u8)
|
|
||||||
/// - I: Immediate (implements [`crate::Imm`] trait)
|
|
||||||
/// - Other types are identity-mapped
|
|
||||||
///
|
|
||||||
/// # Text assembler
|
|
||||||
/// Text assembler generated simply calls methods in the [`crate::Assembler`] type.
|
|
||||||
/// # Syntax
|
|
||||||
/// ```text
|
|
||||||
/// instruction op1, op2, …
|
|
||||||
/// …
|
|
||||||
/// ```
|
|
||||||
/// - Opcode names are lowercase
|
|
||||||
/// - Registers are prefixed with `r` followed by number
|
|
||||||
/// - Operands are separated by `,`
|
|
||||||
/// - Instructions are separated by either line feed or `;` (αυτό δεν είναι ερωτηματικό!)
|
|
||||||
/// - Labels are defined by their names followed by colon `label:`
|
|
||||||
/// - Labels are referenced simply by their names
|
|
||||||
/// - Immediates are numbers, can be negative, floats are not yet supported
|
|
||||||
macro_rules! impl_all {
|
|
||||||
($($tt:tt)*) => {
|
|
||||||
impl Assembler {
|
|
||||||
$crate::macros::asm::impl_asm!($($tt)*);
|
|
||||||
}
|
|
||||||
|
|
||||||
$crate::macros::text::gen_text!($($tt)*);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) use impl_all;
|
|
||||||
|
|
|
@ -10,7 +10,21 @@ macro_rules! gen_text {
|
||||||
=> [$($opcode:ident),* $(,)?],
|
=> [$($opcode:ident),* $(,)?],
|
||||||
)*
|
)*
|
||||||
) => {
|
) => {
|
||||||
/// Text code based assembler
|
/// # Text assembler
|
||||||
|
/// Text assembler generated simply calls methods in the [`crate::Assembler`] type.
|
||||||
|
///
|
||||||
|
/// # Syntax
|
||||||
|
/// ```text
|
||||||
|
/// instruction op1, op2, …
|
||||||
|
/// …
|
||||||
|
/// ```
|
||||||
|
/// - Opcode names are lowercase
|
||||||
|
/// - Registers are prefixed with `r` followed by number
|
||||||
|
/// - Operands are separated by `,`
|
||||||
|
/// - Instructions are separated by either line feed or `;` (αυτό δεν είναι ερωτηματικό!)
|
||||||
|
/// - Labels are defined by their names followed by colon `label:`
|
||||||
|
/// - Labels are referenced simply by their names
|
||||||
|
/// - Immediates are numbers, can be negative, floats are not yet supported
|
||||||
pub mod text {
|
pub mod text {
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
@ -30,7 +44,6 @@ macro_rules! gen_text {
|
||||||
#[logos(skip r"-- .*")]
|
#[logos(skip r"-- .*")]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
$($(#[token(~([<$opcode:lower>]), |_| hbbytecode::opcode::[<$opcode:upper>])])*)*
|
$($(#[token(~([<$opcode:lower>]), |_| hbbytecode::opcode::[<$opcode:upper>])])*)*
|
||||||
#[token("brc", |_| hbbytecode::opcode::BRC)] // Special-cased
|
|
||||||
Opcode(u8),
|
Opcode(u8),
|
||||||
|
|
||||||
#[regex("[0-9]+", |l| l.slice().parse().ok())]
|
#[regex("[0-9]+", |l| l.slice().parse().ok())]
|
||||||
|
@ -105,13 +118,6 @@ macro_rules! gen_text {
|
||||||
// Got an opcode
|
// Got an opcode
|
||||||
Some(Ok(Token::Opcode(op))) => {
|
Some(Ok(Token::Opcode(op))) => {
|
||||||
match op {
|
match op {
|
||||||
// Take all the opcodes and match them to their corresponding functions
|
|
||||||
$(
|
|
||||||
$(hbbytecode::opcode::$opcode)|* => paste::paste!({
|
|
||||||
param_extract_itm!(self, $($param_i: $param_ty),*);
|
|
||||||
self.asm.[<i_param_ $ityn>](op, $($param_i),*);
|
|
||||||
}),
|
|
||||||
)*
|
|
||||||
// Special-cased
|
// Special-cased
|
||||||
hbbytecode::opcode::BRC => {
|
hbbytecode::opcode::BRC => {
|
||||||
param_extract_itm!(
|
param_extract_itm!(
|
||||||
|
@ -122,7 +128,17 @@ macro_rules! gen_text {
|
||||||
);
|
);
|
||||||
|
|
||||||
self.asm.i_param_bbb(op, p0, p1, p2);
|
self.asm.i_param_bbb(op, p0, p1, p2);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
// Take all the opcodes and match them to their corresponding functions
|
||||||
|
$(
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
$(hbbytecode::opcode::$opcode)|* => paste::paste!({
|
||||||
|
param_extract_itm!(self, $($param_i: $param_ty),*);
|
||||||
|
self.asm.[<i_param_ $ityn>](op, $($param_i),*);
|
||||||
|
}),
|
||||||
|
)*
|
||||||
|
|
||||||
// Already matched in Logos, should not be able to obtain
|
// Already matched in Logos, should not be able to obtain
|
||||||
// invalid opcode.
|
// invalid opcode.
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
|
@ -92,9 +92,7 @@ macro_rules! gen_valider {
|
||||||
$crate::gen_valider::inst_chk!(
|
$crate::gen_valider::inst_chk!(
|
||||||
rest, $ityn, $($opcode),*
|
rest, $ityn, $($opcode),*
|
||||||
)
|
)
|
||||||
)|*| $crate::gen_valider::inst_chk!(
|
)|* => rest,
|
||||||
rest, bbb, BRC
|
|
||||||
) => rest,
|
|
||||||
|
|
||||||
// The plebs
|
// The plebs
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -18,9 +18,22 @@ macro_rules! constmod {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoke macro with bytecode definition format
|
/// Invoke macro with bytecode definition format
|
||||||
///
|
/// # Input syntax
|
||||||
/// Keep in mind BRC instruction is special-cased and you have to implement
|
/// ```no_run
|
||||||
/// it manually.
|
/// macro!(
|
||||||
|
/// INSTRUCTION_TYPE(p0: TYPE, p1: TYPE, …)
|
||||||
|
/// => [INSTRUCTION_A, INSTRUCTION_B, …],
|
||||||
|
/// …
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
/// - Instruction type determines opcode-generic, instruction-type-specific
|
||||||
|
/// function. Name: `i_param_INSTRUCTION_TYPE`
|
||||||
|
/// - Per-instructions there will be generated opcode-specific functions calling the generic ones
|
||||||
|
/// - Operand types
|
||||||
|
/// - R: Register (u8)
|
||||||
|
/// - I: Immediate (implements [`crate::Imm`] trait)
|
||||||
|
/// - L: Memory load / store size (u16)
|
||||||
|
/// - Other types are identity-mapped
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! invoke_with_def {
|
macro_rules! invoke_with_def {
|
||||||
($macro:path) => {
|
($macro:path) => {
|
||||||
|
@ -28,7 +41,7 @@ macro_rules! invoke_with_def {
|
||||||
bbbb(p0: R, p1: R, p2: R, p3: R)
|
bbbb(p0: R, p1: R, p2: R, p3: R)
|
||||||
=> [DIR, DIRF, FMAF],
|
=> [DIR, DIRF, FMAF],
|
||||||
bbb(p0: R, p1: R, p2: R)
|
bbb(p0: R, p1: R, p2: R)
|
||||||
=> [ADD, SUB, MUL, AND, OR, XOR, SL, SR, SRS, CMP, CMPU, /*BRC,*/ ADDF, SUBF, MULF],
|
=> [ADD, SUB, MUL, AND, OR, XOR, SL, SR, SRS, CMP, CMPU, BRC, ADDF, SUBF, MULF],
|
||||||
bbdh(p0: R, p1: R, p2: I, p3: L)
|
bbdh(p0: R, p1: R, p2: I, p3: L)
|
||||||
=> [LD, ST],
|
=> [LD, ST],
|
||||||
bbd(p0: R, p1: R, p2: I)
|
bbd(p0: R, p1: R, p2: I)
|
||||||
|
|
Loading…
Reference in a new issue