aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2025-01-16 14:12:11 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2025-01-16 14:12:11 +0100
commit9261588dcaa10aac0a9b8b7a81ff70a621cf1551 (patch)
tree2f58d0889a3bc84c6fd6829ef1fce56f880d8791 /lib/xixanta
parente7d815c73701377ad3f370e5e5e2b3296627a7ae (diff)
downloadtools.nes-9261588dcaa10aac0a9b8b7a81ff70a621cf1551.tar.gz
tools.nes-9261588dcaa10aac0a9b8b7a81ff70a621cf1551.zip
Add boolean operators
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à <mikisabate@gmail.com>
Diffstat (limited to 'lib/xixanta')
-rw-r--r--lib/xixanta/src/assembler.rs67
-rw-r--r--lib/xixanta/src/node.rs18
-rw-r--r--lib/xixanta/src/parser.rs26
3 files changed, 100 insertions, 11 deletions
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)),
}