From 1ecee352f5844b0809d7ae66df52e34f42b44c8e Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Thu, 6 Mar 2025 20:33:27 +1300 Subject: Rewrite entire assembler The language is now more general, the code is better structured, error reporting is more detailed, and many new language features have been implemented: - conditional blocks - first-class strings - more expression operators - binary literals - negative values - invocations in constant expressions --- src/types/expression_stack.rs | 89 +++++++++++++++++++++++++++++++++++++++++++ src/types/mod.rs | 7 ++++ src/types/operator.rs | 87 ++++++++++++++++++++++++++++++++++++++++++ src/types/word_template.rs | 46 ++++++++++++++++++++++ 4 files changed, 229 insertions(+) create mode 100644 src/types/expression_stack.rs create mode 100644 src/types/mod.rs create mode 100644 src/types/operator.rs create mode 100644 src/types/word_template.rs (limited to 'src/types') diff --git a/src/types/expression_stack.rs b/src/types/expression_stack.rs new file mode 100644 index 0000000..4d26eb2 --- /dev/null +++ b/src/types/expression_stack.rs @@ -0,0 +1,89 @@ +use crate::*; + + +pub struct ExpressionStack { + stack: Vec, +} + +impl ExpressionStack { + pub fn new() -> Self { + Self { + stack: Vec::new(), + } + } + + pub fn pull_result(mut self) -> Result { + match self.stack.len() { + 0 => Err(StackError::NoReturnValue), + 1 => Ok(self.stack.pop().unwrap()), + _ => Err(StackError::MultipleReturnValues), + } + } + + pub fn push(&mut self, value: isize) { + self.stack.push(value); + } + + pub fn apply(&mut self, operator: Operator, source: &SourceSpan) -> Result<(), Tracked> { + macro_rules! push { + ($val:expr) => { self.stack.push($val) } + } + macro_rules! pop { + ($name:ident) => { + let $name = match self.stack.pop() { + Some(value) => value, + None => return Err(Tracked::from(StackError::Underflow, source.clone())), + }; + } + } + macro_rules! truth { + ($bool:expr) => { match $bool { true => 1, false => 0 } }; + } + match operator { + Operator::Equal => { pop!(b); pop!(a); push!(truth!(a==b)) }, + Operator::NotEqual => { pop!(b); pop!(a); push!(truth!(a!=b)) }, + Operator::LessThan => { pop!(b); pop!(a); push!(truth!(a < b)) }, + Operator::GreaterThan => { pop!(b); pop!(a); push!(truth!(a > b)) }, + Operator::LessThanEqual => { pop!(b); pop!(a); push!(truth!(a <= b)) }, + Operator::GreaterThanEqual => { pop!(b); pop!(a); push!(truth!(a >= b)) }, + Operator::Add => { pop!(b); pop!(a); push!(a + b) }, + Operator::Subtract => { pop!(b); pop!(a); push!(a - b) }, + Operator::Multiply => { pop!(b); pop!(a); push!(a * b) }, + Operator::Divide => { pop!(b); pop!(a); push!(a / b) }, + Operator::Modulo => { pop!(b); pop!(a); push!(a % b) }, + Operator::Exponent => { pop!(b); pop!(a); push!( + if let Ok(b) = u32::try_from(b) { a.saturating_pow(b) } else { 0 } ) }, + Operator::LeftShift => { pop!(b); pop!(a); push!( + if b < 0 { a >> -b } else { a << b } ) }, + Operator::RightShift => { pop!(b); pop!(a); push!( + if b < 0 { a << -b } else { a >> b } ) }, + Operator::BitAnd => { pop!(b); pop!(a); push!(a & b) }, + Operator::BitOr => { pop!(b); pop!(a); push!(a | b) }, + Operator::BitXor => { pop!(b); pop!(a); push!(a ^ b) }, + Operator::BitNot => { pop!(a); push!(!a) }, + } + return Ok(()); + } +} + + +pub enum StackError { + Underflow, + MultipleReturnValues, + NoReturnValue, +} + + +pub fn report_stack_error(error: &Tracked, source_code: &str) { + let context = Context { source_code: &source_code, source: &error.source }; + let message = match &error.value { + StackError::Underflow => + "A stack underflow occurred while evaluating this operator", + StackError::MultipleReturnValues => + "More than one value was left on the stack after this expression was evaluated", + StackError::NoReturnValue => + "No value was left on the stack after this expression was evaluated", + }; + + report_source_issue(LogLevel::Error, &context, message); +} diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..623d525 --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,7 @@ +mod expression_stack; +mod operator; +mod word_template; + +pub use expression_stack::*; +pub use operator::*; +pub use word_template::*; diff --git a/src/types/operator.rs b/src/types/operator.rs new file mode 100644 index 0000000..a7e7b9b --- /dev/null +++ b/src/types/operator.rs @@ -0,0 +1,87 @@ +#[derive(Clone, Copy)] +pub enum Operator { + Equal, + NotEqual, + LessThan, + GreaterThan, + LessThanEqual, + GreaterThanEqual, + Add, + Subtract, + Multiply, + Divide, + Modulo, + Exponent, + LeftShift, + RightShift, + BitAnd, + BitOr, + BitXor, + BitNot, +} + +impl Operator { + pub fn from_str(string: &str) -> Option { + match string { + "=" => Some(Operator::Equal), + "==" => Some(Operator::Equal), + "" => Some(Operator::Equal), + "!=" => Some(Operator::NotEqual), + "" => Some(Operator::NotEqual), + "<" => Some(Operator::LessThan), + "" => Some(Operator::LessThan), + ">" => Some(Operator::GreaterThan), + "" => Some(Operator::GreaterThan), + "<=" => Some(Operator::LessThanEqual), + "" => Some(Operator::LessThanEqual), + ">=" => Some(Operator::GreaterThanEqual), + "" => Some(Operator::GreaterThanEqual), + "+" => Some(Operator::Add), + "" => Some(Operator::Add), + "-" => Some(Operator::Subtract), + "" => Some(Operator::Subtract), + "*" => Some(Operator::Multiply), + "" => Some(Operator::Multiply), + "/" => Some(Operator::Divide), + "
" => Some(Operator::Divide), + "" => Some(Operator::Modulo), + "**" => Some(Operator::Exponent), + "" => Some(Operator::Exponent), + "<<" => Some(Operator::LeftShift), + "" => Some(Operator::LeftShift), + ">>" => Some(Operator::RightShift), + "" => Some(Operator::RightShift), + "" => Some(Operator::BitAnd), + "" => Some(Operator::BitOr), + "" => Some(Operator::BitXor), + "" => Some(Operator::BitNot), + _ => None, + } + } +} + +impl std::fmt::Display for Operator { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + let string = match self { + Operator::Equal => "", + Operator::NotEqual => "", + Operator::LessThan => "", + Operator::GreaterThan => "", + Operator::LessThanEqual => "", + Operator::GreaterThanEqual => "", + Operator::Add => "", + Operator::Subtract => "", + Operator::Multiply => "", + Operator::Divide => "
", + Operator::Modulo => "", + Operator::Exponent => "", + Operator::LeftShift => "", + Operator::RightShift => "", + Operator::BitAnd => "", + Operator::BitOr => "", + Operator::BitXor => "", + Operator::BitNot => "", + }; + write!(f, "{string}") + } +} diff --git a/src/types/word_template.rs b/src/types/word_template.rs new file mode 100644 index 0000000..33d5933 --- /dev/null +++ b/src/types/word_template.rs @@ -0,0 +1,46 @@ +use crate::*; + + +pub struct WordTemplate { + pub value: usize, + /// Width of the word in bits. + pub width: u32, + pub fields: Vec>, +} + +pub struct BitField { + pub name: char, + /// Width of the field in bits. + pub width: u32, + /// Number of bits to the right of the field in the word. + pub shift: u32, +} + + +impl std::fmt::Display for WordTemplate { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + if self.value == 0 { + write!(f, "0")?; + } else { + let bitcount = (self.value.ilog2() + 1) as usize; + 'bit: for i in (0..bitcount).rev() { + let is_first_bit = i+1 == bitcount; + if !is_first_bit && (i+1) % 4 == 0 { + write!(f, "_")?; + } + for field in &self.fields { + let i = i as u32; + if i <= field.width + field.shift - 1 && i >= field.shift { + write!(f, "{}", field.name)?; + continue 'bit; + } + } + match (self.value >> i) & 1 { + 0 => write!(f, "0")?, + _ => write!(f, "1")?, + } + } + } + return Ok(()); + } +} -- cgit v1.2.3-70-g09d2