forked from koniifer/ableos
Reworked macros
This commit is contained in:
parent
5055626968
commit
077da50787
|
@ -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<usize>,
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.[<i_param_ $ityn>](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.[<i_param_ $ityn>](op, $($param_i),*);
|
||||
}),
|
||||
)*
|
||||
|
||||
// Already matched in Logos, should not be able to obtain
|
||||
// invalid opcode.
|
||||
_ => unreachable!(),
|
||||
|
|
|
@ -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
|
||||
_ => {
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue