From 077da50787871a38e5f865f142a643355763d693 Mon Sep 17 00:00:00 2001 From: Erin Date: Wed, 26 Jul 2023 00:12:50 +0200 Subject: [PATCH] Reworked macros --- hbasm/src/lib.rs | 23 +++++++++------- hbasm/src/macros/mod.rs | 52 ----------------------------------- hbasm/src/macros/text.rs | 36 +++++++++++++++++------- hbbytecode/src/gen_valider.rs | 4 +-- hbbytecode/src/lib.rs | 21 +++++++++++--- 5 files changed, 57 insertions(+), 79 deletions(-) diff --git a/hbasm/src/lib.rs b/hbasm/src/lib.rs index 11b1937..cf7da9e 100644 --- a/hbasm/src/lib.rs +++ b/hbasm/src/lib.rs @@ -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] extern crate alloc; @@ -17,18 +28,10 @@ pub struct Assembler { pub sub: HashSet, } - -// Implement both assembler and generate module for text-code-based one -hbbytecode::invoke_with_def!(macros::impl_all); +hbbytecode::invoke_with_def!(macros::text::gen_text); impl Assembler { - // Special-cased for text-assembler - // - // `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) - } + hbbytecode::invoke_with_def!(macros::asm::impl_asm); /// Append 12 zeroes (UN) at the end /// diff --git a/hbasm/src/macros/mod.rs b/hbasm/src/macros/mod.rs index db4ca00..509f6be 100644 --- a/hbasm/src/macros/mod.rs +++ b/hbasm/src/macros/mod.rs @@ -4,55 +4,3 @@ pub mod asm; 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; diff --git a/hbasm/src/macros/text.rs b/hbasm/src/macros/text.rs index 22f8206..89b360b 100644 --- a/hbasm/src/macros/text.rs +++ b/hbasm/src/macros/text.rs @@ -10,7 +10,21 @@ macro_rules! gen_text { => [$($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 { use { crate::{ @@ -30,7 +44,6 @@ macro_rules! gen_text { #[logos(skip r"-- .*")] pub enum Token { $($(#[token(~([<$opcode:lower>]), |_| hbbytecode::opcode::[<$opcode:upper>])])*)* - #[token("brc", |_| hbbytecode::opcode::BRC)] // Special-cased Opcode(u8), #[regex("[0-9]+", |l| l.slice().parse().ok())] @@ -105,13 +118,6 @@ macro_rules! gen_text { // Got an opcode Some(Ok(Token::Opcode(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.[](op, $($param_i),*); - }), - )* // Special-cased hbbytecode::opcode::BRC => { param_extract_itm!( @@ -122,7 +128,17 @@ macro_rules! gen_text { ); 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.[](op, $($param_i),*); + }), + )* + // Already matched in Logos, should not be able to obtain // invalid opcode. _ => unreachable!(), diff --git a/hbbytecode/src/gen_valider.rs b/hbbytecode/src/gen_valider.rs index f82a017..a3f0193 100644 --- a/hbbytecode/src/gen_valider.rs +++ b/hbbytecode/src/gen_valider.rs @@ -92,9 +92,7 @@ macro_rules! gen_valider { $crate::gen_valider::inst_chk!( rest, $ityn, $($opcode),* ) - )|*| $crate::gen_valider::inst_chk!( - rest, bbb, BRC - ) => rest, + )|* => rest, // The plebs _ => { diff --git a/hbbytecode/src/lib.rs b/hbbytecode/src/lib.rs index 4919eba..0c89673 100644 --- a/hbbytecode/src/lib.rs +++ b/hbbytecode/src/lib.rs @@ -18,9 +18,22 @@ macro_rules! constmod { } /// Invoke macro with bytecode definition format -/// -/// Keep in mind BRC instruction is special-cased and you have to implement -/// it manually. +/// # Input syntax +/// ```no_run +/// 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_rules! invoke_with_def { ($macro:path) => { @@ -28,7 +41,7 @@ macro_rules! invoke_with_def { bbbb(p0: R, p1: R, p2: R, p3: R) => [DIR, DIRF, FMAF], 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) => [LD, ST], bbd(p0: R, p1: R, p2: I)