Reworked macros

This commit is contained in:
Erin 2023-07-26 00:12:50 +02:00 committed by ondra05
parent 77d807a17d
commit 972df2f6d7
5 changed files with 57 additions and 79 deletions

View file

@ -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
/// ///

View file

@ -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;

View file

@ -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!(),

View file

@ -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
_ => { _ => {

View file

@ -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)