From 9261588dcaa10aac0a9b8b7a81ff70a621cf1551 Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Thu, 16 Jan 2025 14:12:11 +0100 Subject: Add boolean operators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow for expressions that evaluate to a boolean expression. This in turn mean that the value is just set to 0 or 1 depending on the given condition. As with other assemblers, only a value of 0 evaluates to 0, and others go to 1. So, something like "1 && 2" evaluates to 1 even if it doesn't make much sense at first glance (as an assembler we just assume that the programmer knows what it's doing). Signed-off-by: Miquel Sabaté Solà --- lib/xixanta/src/assembler.rs | 67 +++++++++++++++++++++++++++++++++++++++----- lib/xixanta/src/node.rs | 18 ++++++++++++ lib/xixanta/src/parser.rs | 26 ++++++++++++++--- 3 files changed, 100 insertions(+), 11 deletions(-) (limited to 'lib/xixanta') diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index 851f3c3..2621982 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -827,6 +827,7 @@ impl<'a> Assembler<'a> { right.negative = true; rval.neg() } + OperationType::LogicalNot => (rval == 0) as isize, OperationType::BitwiseNot => !rval, OperationType::LoByte => { let r = (rval as u16).to_le_bytes(); @@ -866,10 +867,18 @@ impl<'a> Assembler<'a> { let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); lval / rval } + OperationType::LogicalAnd => { + let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); + ((lval != 0) && (rval != 0)) as isize + } OperationType::And => { let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); lval & rval } + OperationType::LogicalOr => { + let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); + ((lval != 0) || (rval != 0)) as isize + } OperationType::Or => { let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); lval | rval @@ -904,6 +913,30 @@ impl<'a> Assembler<'a> { let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); lval >> rval } + OperationType::Equal => { + let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); + (lval == rval) as isize + } + OperationType::NotEqual => { + let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); + (lval != rval) as isize + } + OperationType::Less => { + let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); + (lval < rval) as isize + } + OperationType::LessEqual => { + let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); + (lval <= rval) as isize + } + OperationType::Greater => { + let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); + (lval > rval) as isize + } + OperationType::GreaterEqual => { + let lval = self.evaluate_node(node.left.as_ref().unwrap())?.value(); + (lval >= rval) as isize + } }; // Prevent overflows. @@ -2387,18 +2420,38 @@ mod tests { ldx #(Value / 2) ldx #(Value << 2) ldx #~Value + ldx #(2 && Value) + ldx #(2 || Value) + ldx #(!Value) + ldx #(2 == Value) + ldx #(2 != Value) + ldx #(2 <> Value) + ldx #(2 < Value) + ldx #(2 <= Value) + ldx #(2 > Value) + ldx #(2 >= Value) "#, ); - assert_eq!(res.len(), 6); + assert_eq!(res.len(), 16); let expected = [ - [0x06, 0x00], - [0xFE, 0xFF], - [0xF8, 0xFF], - [0x02, 0x00], - [0x10, 0x00], - [0xFB, 0xFF], + [0x06, 0x00], // Add + [0xFE, 0xFF], // Subtract + [0xF8, 0xFF], // Multiply + [0x02, 0x00], // Divide + [0x10, 0x00], // Left shift + [0xFB, 0xFF], // Bitwise not + [0x01, 0x00], // Logical and + [0x01, 0x00], // Logical or + [0x00, 0x00], // Logical not + [0x00, 0x00], // Equal + [0x01, 0x00], // Not equal + [0x01, 0x00], // Not equal (bis) + [0x01, 0x00], // Less + [0x01, 0x00], // Less or equal + [0x00, 0x00], // Greater + [0x00, 0x00], // Greater or equal ]; for (idx, node) in res.iter().enumerate() { assert_eq!(node.size, 2); diff --git a/lib/xixanta/src/node.rs b/lib/xixanta/src/node.rs index 04655cb..a31c578 100644 --- a/lib/xixanta/src/node.rs +++ b/lib/xixanta/src/node.rs @@ -197,13 +197,22 @@ pub enum OperationType { Lshift, Rshift, And, + LogicalAnd, Or, + LogicalOr, Xor, UnaryPositive, UnaryNegative, BitwiseNot, + LogicalNot, LoByte, HiByte, + Equal, + NotEqual, + LessEqual, + GreaterEqual, + Less, + Greater, } /// The PNode type. @@ -278,13 +287,22 @@ impl fmt::Display for NodeType { OperationType::Lshift => write!(f, "left shift"), OperationType::Rshift => write!(f, "right shift"), OperationType::And => write!(f, "bitwise and"), + OperationType::LogicalAnd => write!(f, "logical and"), OperationType::Or => write!(f, "bitwise or"), + OperationType::LogicalOr => write!(f, "logical or"), OperationType::Xor => write!(f, "bitwise xor"), OperationType::UnaryPositive => write!(f, "unary positive"), OperationType::UnaryNegative => write!(f, "unary negative"), OperationType::BitwiseNot => write!(f, "bitwise not"), + OperationType::LogicalNot => write!(f, "logical not"), OperationType::LoByte => write!(f, "low byte"), OperationType::HiByte => write!(f, "high byte"), + OperationType::Equal => write!(f, "equal"), + OperationType::NotEqual => write!(f, "not equal"), + OperationType::LessEqual => write!(f, "less or equal"), + OperationType::GreaterEqual => write!(f, "greater or equal"), + OperationType::Less => write!(f, "less"), + OperationType::Greater => write!(f, "greater"), }, } } diff --git a/lib/xixanta/src/parser.rs b/lib/xixanta/src/parser.rs index a91ce8f..5bac127 100644 --- a/lib/xixanta/src/parser.rs +++ b/lib/xixanta/src/parser.rs @@ -1032,6 +1032,7 @@ impl Parser { '~' => Some(NodeType::Operation(OperationType::BitwiseNot)), '<' => Some(NodeType::Operation(OperationType::LoByte)), '>' => Some(NodeType::Operation(OperationType::HiByte)), + '!' => Some(NodeType::Operation(OperationType::LogicalNot)), _ => None, } } @@ -1050,15 +1051,32 @@ impl Parser { '*' => Ok((Some(NodeType::Operation(OperationType::Mul)), 1)), '/' => Ok((Some(NodeType::Operation(OperationType::Div)), 1)), '^' => Ok((Some(NodeType::Operation(OperationType::Xor)), 1)), - '|' => Ok((Some(NodeType::Operation(OperationType::Or)), 1)), - '&' => Ok((Some(NodeType::Operation(OperationType::And)), 1)), + '|' => match second { + '|' => Ok((Some(NodeType::Operation(OperationType::LogicalOr)), 2)), + _ => Ok((Some(NodeType::Operation(OperationType::Or)), 1)), + }, + '&' => match second { + '&' => Ok((Some(NodeType::Operation(OperationType::LogicalAnd)), 2)), + _ => Ok((Some(NodeType::Operation(OperationType::And)), 1)), + }, '<' => match second { '<' => Ok((Some(NodeType::Operation(OperationType::Lshift)), 2)), - _ => Err(self.parser_error(format!("unknown operator '<{}'", second).as_str())), + '>' => Ok((Some(NodeType::Operation(OperationType::NotEqual)), 2)), + '=' => Ok((Some(NodeType::Operation(OperationType::LessEqual)), 2)), + _ => Ok((Some(NodeType::Operation(OperationType::Less)), 1)), }, '>' => match second { '>' => Ok((Some(NodeType::Operation(OperationType::Rshift)), 2)), - _ => Err(self.parser_error(format!("unknown operator '>{}'", second).as_str())), + '=' => Ok((Some(NodeType::Operation(OperationType::GreaterEqual)), 2)), + _ => Ok((Some(NodeType::Operation(OperationType::Greater)), 1)), + }, + '=' => match second { + '=' => Ok((Some(NodeType::Operation(OperationType::Equal)), 2)), + _ => Err(self.parser_error(format!("unknown operator '={}'", second).as_str())), + }, + '!' => match second { + '=' => Ok((Some(NodeType::Operation(OperationType::NotEqual)), 2)), + _ => Err(self.parser_error(format!("unknown operator '!{}'", second).as_str())), }, _ => Ok((None, 0)), } -- cgit v1.2.3