From 2b4e522b12a7eb87e91cd1cdc56064ee429a5212 Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Tue, 11 Feb 2025 14:00:20 +1300 Subject: Initial commit --- src/tokens/constant_expression.rs | 134 ++++++++++++++++++++++++++++++++++++ src/tokens/mod.rs | 11 +++ src/tokens/packed_binary_literal.rs | 60 ++++++++++++++++ src/tokens/semantic.rs | 71 +++++++++++++++++++ src/tokens/syntactic.rs | 66 ++++++++++++++++++ 5 files changed, 342 insertions(+) create mode 100644 src/tokens/constant_expression.rs create mode 100644 src/tokens/mod.rs create mode 100644 src/tokens/packed_binary_literal.rs create mode 100644 src/tokens/semantic.rs create mode 100644 src/tokens/syntactic.rs (limited to 'src/tokens') diff --git a/src/tokens/constant_expression.rs b/src/tokens/constant_expression.rs new file mode 100644 index 0000000..e4aa099 --- /dev/null +++ b/src/tokens/constant_expression.rs @@ -0,0 +1,134 @@ +use crate::*; + + +pub struct ConstantExpression { + pub tokens: Vec, +} + +impl ConstantExpression { + pub fn from_str(string: &str, tokeniser: &Tokeniser) -> Self { + parse_constant_expression(string, tokeniser) + } +} + +pub struct ConstantExpressionToken { + pub source: SourceSpan, + pub variant: ConstantExpressionTokenVariant, +} + +pub enum ConstantExpressionTokenVariant { + SymbolReference(String), + IntegerLiteral(usize), + Operator(Operator), + Error(ConstantExpressionParseError), +} + +pub enum Operator { + Equal, + NotEqual, + LessThan, + GreaterThan, + Add, + Subtract, + LeftShift, + RightShift, + And, + Or, + Xor, + Not, +} + +pub enum ConstantExpressionParseError { + InvalidHexadecimalLiteral(String), +} + + +impl ConstantExpression { + pub fn evaluate(&self, environment: &Environment) -> Result { + use ConstantExpressionTokenVariant as Token; + use ConstantExpressionEvaluationError as EvalErr; + + let mut stack = Vec::new(); + macro_rules! push { + ($value:expr) => { stack.push($value) }; + } + macro_rules! pop { + ($name:ident) => { let $name = match stack.pop() { + Some(value) => value, + None => return Err(EvalErr::StackUnderflow), + }; }; + } + macro_rules! truth { + ($bool:expr) => { match $bool { true => 1, false => 0 } }; + } + + for token in &self.tokens { + match &token.variant { + Token::IntegerLiteral(value) => push!(*value), + Token::SymbolReference(name) => match environment.get_integer(name) { + Ok(value) => push!(value), + Err(_) => todo!(), + } + Token::Operator(operator) => 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::Add => { pop!(b); pop!(a); push!(a + b) }, + Operator::Subtract => { pop!(b); pop!(a); push!(a - b) }, + Operator::LeftShift => { pop!(b); pop!(a); push!(a << b) }, + Operator::RightShift => { pop!(b); pop!(a); push!(a >> b) }, + Operator::And => { pop!(b); pop!(a); push!(a & b) }, + Operator::Or => { pop!(b); pop!(a); push!(a | b) }, + Operator::Xor => { pop!(b); pop!(a); push!(a ^ b) }, + Operator::Not => { pop!(a); push!(!a) }, + } + Token::Error(_) => (), + } + } + match stack.len() { + 0 => Err(EvalErr::NoReturnValue), + 1 => Ok(stack[0]), + _ => Err(EvalErr::MultipleReturnValues), + } + } +} + +pub enum ConstantExpressionEvaluationError { + StackUnderflow, + MultipleReturnValues, + NoReturnValue, +} + + +impl std::fmt::Debug for ConstantExpression { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + use ConstantExpressionTokenVariant as TokenVar; + for (i, token) in self.tokens.iter().enumerate() { + let string = match &token.variant { + TokenVar::SymbolReference(name) => name, + TokenVar::IntegerLiteral(value) => &value.to_string(), + TokenVar::Operator(operator) => match operator { + Operator::Equal => "=", + Operator::NotEqual => "!", + Operator::LessThan => "<", + Operator::GreaterThan => ">", + Operator::Add => "+", + Operator::Subtract => "-", + Operator::LeftShift => "<<", + Operator::RightShift => ">>", + Operator::And => "&", + Operator::Or => "|", + Operator::Xor => "^", + Operator::Not => "~", + } + TokenVar::Error(_) => "", + }; + match i { + 0 => write!(f, "{string}")?, + _ => write!(f, " {string}")?, + } + } + return Ok(()); + } +} diff --git a/src/tokens/mod.rs b/src/tokens/mod.rs new file mode 100644 index 0000000..65f361c --- /dev/null +++ b/src/tokens/mod.rs @@ -0,0 +1,11 @@ +mod syntactic; +pub use syntactic::*; + +mod semantic; +pub use semantic::*; + +mod constant_expression; +pub use constant_expression::*; + +mod packed_binary_literal; +pub use packed_binary_literal::*; diff --git a/src/tokens/packed_binary_literal.rs b/src/tokens/packed_binary_literal.rs new file mode 100644 index 0000000..1252398 --- /dev/null +++ b/src/tokens/packed_binary_literal.rs @@ -0,0 +1,60 @@ +use crate::*; + + +pub struct PackedBinaryLiteral { + pub value: usize, + pub fields: Vec, + pub errors: Vec, +} + +impl PackedBinaryLiteral { + pub fn from_str(string: &str, parent: &Tokeniser) -> Self { + parse_packed_binary_literal(string, parent) + } +} + +pub struct BitField { + pub name: char, + pub source: SourceSpan, + /// Length of field in bits + pub bits: usize, + /// Distance to left-shift field in value + pub shift: usize, +} + +pub struct PackedBinaryLiteralParseError { + pub source: SourceSpan, + pub variant: PackedBinaryLiteralParseErrorVariant, +} + +pub enum PackedBinaryLiteralParseErrorVariant { + DuplicateFieldName(char), + InvalidCharacter(char), +} + + +impl std::fmt::Display for PackedBinaryLiteral { + 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() { + if (i+1) % 4 == 0 { + write!(f, "_")?; + } + for field in &self.fields { + if i <= field.bits + 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(()); + } +} diff --git a/src/tokens/semantic.rs b/src/tokens/semantic.rs new file mode 100644 index 0000000..ed53685 --- /dev/null +++ b/src/tokens/semantic.rs @@ -0,0 +1,71 @@ +use crate::*; + + +pub enum SemanticToken { + MacroDefinition, + Invocation, +} + +pub struct Invocation { + pub name: String, + pub bytecode: BytecodeSpan, + pub arguments: Vec, +} + +pub struct BlockLiteral { + pub tokens: Vec, +} + +pub struct BlockToken { + pub source: SourceSpan, + pub bytecode: BytecodeSpan, + pub variant: BlockTokenVariant, +} + +pub enum BlockTokenVariant { + Invocation(Invocation), + Word(PackedBinaryLiteral), +} + +pub struct MacroDefinition { + pub name: String, + pub arguments: Vec, + pub body: BlockLiteral, +} + +// -------------------------------------------------------------------------- // + +pub struct SemanticParseError { + pub source: SourceSpan, + pub variant: SemanticParseErrorVariant, +} + +pub enum SemanticParseErrorVariant { + +} + +// -------------------------------------------------------------------------- // + +pub struct DefinitionArgument { + pub name: String, + pub source: SourceSpan, + pub variant: DefinitionArgumentVariant, +} + +pub enum DefinitionArgumentVariant { + Integer, + Block, +} + +pub struct InvocationArgument { + pub source: SourceSpan, + pub variant: InvocationArgumentVariant, +} + +pub enum InvocationArgumentVariant { + BlockLiteral(BlockLiteral), + IntegerLiteral(usize), + ConstantExpression(ConstantExpression), + Invocation(Invocation), +} + diff --git a/src/tokens/syntactic.rs b/src/tokens/syntactic.rs new file mode 100644 index 0000000..000d178 --- /dev/null +++ b/src/tokens/syntactic.rs @@ -0,0 +1,66 @@ +use crate::*; + + +pub struct SyntacticToken { + pub source: SourceSpan, + pub variant: SyntacticTokenVariant, +} + +pub enum SyntacticTokenVariant { + LabelDefinition(String), + MacroDefinition(String), + MacroDefinitionTerminator, + + DecimalLiteral(usize), + HexadecimalLiteral(usize), + PackedBinaryLiteral(PackedBinaryLiteral), + + Comment(String), + ConstantExpression(ConstantExpression), + + BlockOpen, + BlockClose, + Separator, + + Symbol(String), + + Error(SyntacticParseError), +} + +#[derive(Debug)] +pub enum SyntacticParseError { + InvalidHexadecimalLiteral(String), + InvalidSymbolIdentifier(String), + UnterminatedComment, + UnterminatedConstantExpression, +} + + +impl std::fmt::Debug for SyntacticToken { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + use SyntacticTokenVariant::*; + let start = &self.source.in_merged; + let name = match &self.variant { + LabelDefinition(name) => format!("LabelDefinition({name})"), + MacroDefinition(name) => format!("MacroDefinition({name})"), + MacroDefinitionTerminator => format!("MacroDefinitionTerminator"), + + DecimalLiteral(value) => format!("DecimalLiteral({value})"), + HexadecimalLiteral(value) => format!("HexadecimalLiteral(0x{value:x})"), + PackedBinaryLiteral(pbl) => format!("PackedBinaryLiteral({pbl})"), + + Comment(_) => format!("Comment"), + ConstantExpression(expr) => format!("ConstantExpression({expr:?})"), + + BlockOpen => format!("BlockOpen"), + BlockClose => format!("BlockClose"), + Separator => format!("Separator"), + + Symbol(name) => format!("Symbol({name})"), + + Error(error) => format!("Error({error:?})"), + }; + + write!(f, "{start} {name}") + } +} -- cgit v1.2.3-70-g09d2