From a569781691ad1ce8b1d86a6ad64763fa2706ece6 Mon Sep 17 00:00:00 2001 From: Kai-Philipp Nosper Date: Thu, 27 Jan 2022 23:10:38 +0100 Subject: [PATCH] Implement more operators - Mod - Bitwise Or - Bitwise And - Bitwise Xor - Shift Left - Shift Right --- src/interpreter.rs | 8 +++++++- src/lexer.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++-- src/parser.rs | 32 +++++++++++++++++++++++------ 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index 993a291..a97b21e 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -37,6 +37,12 @@ impl Interpreter { BinOpType::Mul => Value::I64(lhs * rhs), BinOpType::Sub => Value::I64(lhs - rhs), BinOpType::Div => Value::I64(lhs / rhs), + BinOpType::Mod => Value::I64(lhs % rhs), + BinOpType::BOr => Value::I64(lhs | rhs), + BinOpType::BAnd => Value::I64(lhs & rhs), + BinOpType::BXor => Value::I64(lhs ^ rhs), + BinOpType::Shr => Value::I64(lhs >> rhs), + BinOpType::Shl => Value::I64(lhs << rhs), }, // _ => panic!("Value types are not compatible"), } @@ -45,8 +51,8 @@ impl Interpreter { #[cfg(test)] mod test { - use crate::parser::{Ast, BinOpType}; use super::{Interpreter, Value}; + use crate::parser::{Ast, BinOpType}; #[test] fn test_interpreter_expr() { diff --git a/src/lexer.rs b/src/lexer.rs index 45a1d07..62860b6 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -19,6 +19,24 @@ pub enum Token { /// Slash (/) Div, + /// Percent (%) + Mod, + + /// Pipe (|) + BOr, + + /// Ampersand (&) + BAnd, + + /// Circumflex (^) + BXor, + + /// Shift Left (<<) + Shl, + + /// Shift Right (>>) + Shr, + /// End of file EoF, } @@ -57,7 +75,7 @@ impl<'a> Lexer<'a> { sval.push(self.next().unwrap()); } // Next char is not a number, so stop and finish the number token - _ => break + _ => break, } } @@ -65,10 +83,22 @@ impl<'a> Lexer<'a> { tokens.push(Token::I64(sval.parse().unwrap())); } + '>' if matches!(self.peek(), Some('>')) => { + self.next(); + tokens.push(Token::Shr); + } + '<' if matches!(self.peek(), Some('<')) => { + self.next(); + tokens.push(Token::Shl); + } '+' => tokens.push(Token::Add), '-' => tokens.push(Token::Sub), '*' => tokens.push(Token::Mul), '/' => tokens.push(Token::Div), + '%' => tokens.push(Token::Mod), + '|' => tokens.push(Token::BOr), + '&' => tokens.push(Token::BAnd), + '^' => tokens.push(Token::BXor), //TODO: Don't panic, keep calm _ => panic!("Lexer encountered unexpected char: '{}'", ch), @@ -102,8 +132,17 @@ impl Token { Some(match self { Token::Add => BinOpType::Add, Token::Sub => BinOpType::Sub, + Token::Mul => BinOpType::Mul, Token::Div => BinOpType::Div, + Token::Mod => BinOpType::Mod, + + Token::BAnd => BinOpType::BAnd, + Token::BOr => BinOpType::BOr, + Token::BXor => BinOpType::BXor, + + Token::Shl => BinOpType::Shl, + Token::Shr => BinOpType::Shr, _ => return None, }) } @@ -115,7 +154,7 @@ mod tests { #[test] fn test_lexer() { - let code = "33 +5*2 + 4456467*2334+3"; + let code = "33 +5*2 + 4456467*2334+3 % - / << ^ | & >>"; let expected = vec![ Token::I64(33), Token::Add, @@ -128,6 +167,14 @@ mod tests { Token::I64(2334), Token::Add, Token::I64(3), + Token::Mod, + Token::Sub, + Token::Div, + Token::Shl, + Token::BXor, + Token::BOr, + Token::BAnd, + Token::Shr, ]; let actual = lex(code); diff --git a/src/parser.rs b/src/parser.rs index f8af0d8..5bd88ef 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -16,6 +16,24 @@ pub enum BinOpType { /// Divide Div, + + /// Modulo + Mod, + + /// Bitwise OR (inclusive or) + BOr, + + /// Bitwise And + BAnd, + + /// Bitwise Xor (exclusive or) + BXor, + + /// Shift Left + Shl, + + /// Shift Right + Shr, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -55,8 +73,6 @@ impl> Parser { self.parse_expr_precedence(lhs, 0) } - - /// Parse binary expressions with a precedence equal to or higher than min_prec fn parse_expr_precedence(&mut self, mut lhs: Ast, min_prec: u8) -> Ast { while let Some(binop) = &self.peek().try_to_binop() { @@ -115,8 +131,12 @@ impl BinOpType { /// For example Multiplication is stronger than addition, so Mul has higher precedence than Add. fn precedence(&self) -> u8 { match self { - BinOpType::Add | BinOpType::Sub => 0, - BinOpType::Mul | BinOpType::Div => 1, + BinOpType::BOr => 0, + BinOpType::BXor => 1, + BinOpType::BAnd => 2, + BinOpType::Shl | BinOpType::Shr => 3, + BinOpType::Add | BinOpType::Sub => 4, + BinOpType::Mul | BinOpType::Div | BinOpType::Mod => 5, } } } @@ -136,12 +156,12 @@ mod tests { Token::I64(2), Token::Mul, Token::I64(3), - Token::Add, + Token::Sub, Token::I64(4), ]; let expected = Ast::BinOp( - BinOpType::Add, + BinOpType::Sub, Ast::BinOp( BinOpType::Add, Ast::I64(1).into(),