diff options
| author | Gustav Sörnäs <gustav@sornas.net> | 2021-01-09 19:57:39 +0100 |
|---|---|---|
| committer | Gustav Sörnäs <gustav@sornas.net> | 2021-01-09 19:57:39 +0100 |
| commit | 4e589cac364edffb08caf7e09a12cc05894271ac (patch) | |
| tree | 7325c7717ae1b1ead6ad09e6113933cddfe4e3e4 /src | |
| parent | 011e7b31e63864a83627c79c1b2d10d7dc0662b0 (diff) | |
| download | sylt-4e589cac364edffb08caf7e09a12cc05894271ac.tar.gz | |
boolean {comparisons,algebra}
Diffstat (limited to 'src')
| -rw-r--r-- | src/compiler.rs | 76 | ||||
| -rw-r--r-- | src/tokenizer.rs | 9 | ||||
| -rw-r--r-- | src/vm.rs | 90 |
3 files changed, 129 insertions, 46 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index d3d4c2c..4b9e74c 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -8,9 +8,10 @@ struct Compiler { //TODO rustify const PREC_NO: u64 = 0; -const PREC_COMP: u64 = 1; -const PREC_TERM: u64 = 2; -const PREC_FACTOR: u64 = 3; +const PREC_BOOL: u64 = 1; +const PREC_COMP: u64 = 2; +const PREC_TERM: u64 = 3; +const PREC_FACTOR: u64 = 4; impl Compiler { pub fn new(tokens: TokenStream) -> Self { @@ -41,13 +42,19 @@ impl Compiler { fn precedence(&self, token: Token) -> u64 { match token { - Token::Minus => PREC_TERM, - Token::Plus => PREC_TERM, + Token::Star | Token::Slash => PREC_FACTOR, - Token::Star => PREC_FACTOR, - Token::Slash => PREC_FACTOR, + Token::Minus | Token::Plus => PREC_TERM, - Token::EqualEqual => PREC_COMP, + Token::EqualEqual + | Token::Greater + | Token::GreaterEqual + | Token::Less + | Token::LessEqual + | Token::NotEqual + => PREC_COMP, + + Token::And | Token::Or => PREC_BOOL, _ => PREC_NO, } @@ -60,6 +67,9 @@ impl Compiler { Token::Float(_) => self.value(block), Token::Int(_) => self.value(block), + Token::Bool(_) => self.value(block), + + Token::Not => self.unary(block), _ => { return false; }, } @@ -69,13 +79,19 @@ impl Compiler { fn infix(&mut self, token: Token, block: &mut Block) -> bool { match token { - Token::Minus => self.binary(block), - Token::Plus => self.binary(block), - - Token::Slash => self.binary(block), - Token::Star => self.binary(block), - - Token::EqualEqual => self.binary(block), + Token::Minus + | Token::Plus + | Token::Slash + | Token::Star + => self.binary(block), + + Token::EqualEqual + | Token::Greater + | Token::GreaterEqual + | Token::Less + | Token::LessEqual + | Token::NotEqual + => self.comparison(block), _ => { return false; }, } @@ -85,7 +101,8 @@ impl Compiler { fn value(&mut self, block: &mut Block) { let value = match self.eat() { Token::Float(f) => { Value::Float(f) }, - Token::Int(f) => { Value::Int(f) } + Token::Int(i) => { Value::Int(i) } + Token::Bool(b) => { Value::Bool(b) } _ => { self.error("Invalid value.") } }; block.add(Op::Constant(value)); @@ -104,11 +121,13 @@ impl Compiler { } fn unary(&mut self, block: &mut Block) { - if Token::Minus != self.eat() { - self.error("Expected minus at start of negation."); - } + let op = match self.eat() { + Token::Minus => Op::Neg, + Token::Not => Op::Not, + _ => self.error("Invalid unary operator"), + }; self.value(block); - block.add(Op::Neg); + block.add(op); } fn binary(&mut self, block: &mut Block) { @@ -121,12 +140,27 @@ impl Compiler { Token::Minus => Op::Sub, Token::Star => Op::Mul, Token::Slash => Op::Div, - Token::EqualEqual => Op::CompEq, _ => { self.error("Illegal operator"); } }; block.add(op); } + fn comparison(&mut self, block: &mut Block) { + let op = self.eat(); + self.parse_precedence(block, self.precedence(op.clone()) + 1); + + let op: &[Op] = match op { + Token::EqualEqual => &[Op::Equal], + Token::Less => &[Op::Less], + Token::Greater => &[Op::Greater], + Token::NotEqual => &[Op::Equal, Op::Not], + Token::LessEqual => &[Op::Greater, Op::Not], + Token::GreaterEqual => &[Op::Less, Op::Not], + _ => { self.error("Illegal comparison operator"); } + }; + block.add_from(op); + } + fn expression(&mut self, block: &mut Block) { self.parse_precedence(block, PREC_NO); } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index a12285b..1882b48 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -59,6 +59,8 @@ pub enum Token { Equal, #[token("==")] EqualEqual, + #[token("!=")] + NotEqual, #[token("(")] LeftParen, @@ -84,6 +86,13 @@ pub enum Token { #[token("<=")] LessEqual, + #[token("&&")] + And, + #[token("||")] + Or, + #[token("!")] + Not, + #[token(".")] Dot, #[token("->")] @@ -1,12 +1,12 @@ -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] pub enum Value { Float(f64), Int(i64), Bool(bool), } -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub enum Op { Pop, Constant(Value), @@ -17,7 +17,13 @@ pub enum Op { Div, Neg, - CompEq, + And, + Or, + Not, + + Equal, // == + Less, // < + Greater, // > Print, Return, @@ -38,8 +44,17 @@ impl Block { } pub fn add(&mut self, op: Op) -> usize { + let len = self.ops.len(); self.ops.push(op); - self.ops.len() + len + } + + pub fn add_from(&mut self, ops: &[Op]) -> usize { + let len = self.ops.len(); + for op in ops { + self.add(*op); + } + len } } @@ -63,6 +78,11 @@ pub fn run_block(block: Block) { } impl VM { + fn pop_twice(&mut self) -> (Value, Value) { + let (a, b) = (self.stack.pop().unwrap(), self.stack.pop().unwrap()); + (b, a) + } + pub fn run(&mut self) { const PRINT_WHILE_RUNNING: bool = true; const PRINT_BLOCK: bool = true; @@ -76,7 +96,6 @@ impl VM { } loop { - if PRINT_WHILE_RUNNING { print!(" ["); for s in self.stack.iter() { @@ -106,51 +125,73 @@ impl VM { } Op::Add => { - let b = self.stack.pop().unwrap(); - let a = self.stack.pop().unwrap(); - match (a, b) { + match self.pop_twice() { (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b + a)), (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b + a)), - _ => unimplemented!("Cannot add '{:?}' and '{:?}'.", a, b), + (a, b) => unimplemented!("Cannot add '{:?}' and '{:?}'.", a, b), } } Op::Sub => { - let b = self.stack.pop().unwrap(); - let a = self.stack.pop().unwrap(); - match (a, b) { + match self.pop_twice() { (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b - a)), (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b - a)), - _ => unimplemented!("Cannot sub '{:?}' and '{:?}'.", a, b), + (a, b) => unimplemented!("Cannot sub '{:?}' and '{:?}'.", a, b), } } Op::Mul => { - let b = self.stack.pop().unwrap(); - let a = self.stack.pop().unwrap(); - match (a, b) { + match self.pop_twice() { (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b * a)), (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b * a)), - _ => unimplemented!("Cannot mul '{:?}' and '{:?}'.", a, b), + (a, b) => unimplemented!("Cannot mul '{:?}' and '{:?}'.", a, b), } } Op::Div => { - let b = self.stack.pop().unwrap(); - let a = self.stack.pop().unwrap(); - match (a, b) { + match self.pop_twice() { (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b / a)), (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b / a)), - _ => unimplemented!("Cannot mul '{:?}' and '{:?}'.", a, b), + (a, b) => unimplemented!("Cannot mul '{:?}' and '{:?}'.", a, b), } } - Op::CompEq => { - let b = self.stack.pop().unwrap(); - let a = self.stack.pop().unwrap(); + Op::Equal => { + let (a, b) = self.pop_twice(); self.stack.push(Value::Bool(a == b)); } + Op::Less => { + let (a, b) = self.pop_twice(); + self.stack.push(Value::Bool(a < b)); + } + + Op::Greater => { + let (a, b) = self.pop_twice(); + self.stack.push(Value::Bool(a > b)); + } + + Op::And => { + match self.pop_twice() { + (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a && b)), + (a, b) => unimplemented!("Cannot 'and' {:?} and {:?}", a, b), + } + } + + Op::Or => { + match self.pop_twice() { + (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a || b)), + (a, b) => unimplemented!("Cannot 'or' {:?} and {:?}", a, b), + } + } + + Op::Not => { + match self.stack.pop().unwrap() { + Value::Bool(a) => self.stack.push(Value::Bool(!a)), + a => unimplemented!("Cannot 'not' {:?}", a), + } + } + Op::Print => { println!("PRINT: {:?}", self.stack.pop()); } @@ -159,7 +200,6 @@ impl VM { return; } } - self.ip += 1; } } |
