aboutsummaryrefslogtreecommitdiffstats
path: root/src/compiler.rs
diff options
context:
space:
mode:
authorEdvard Thörnros <edvard.thornros@gmail.com>2021-01-09 18:37:08 +0100
committerEdvard Thörnros <edvard.thornros@gmail.com>2021-01-09 18:37:08 +0100
commit97e77b94646fe97a2c83ba85ba1813eb9bd0346a (patch)
tree8b8209e34700904c4e02cf623b1cb1930b52982d /src/compiler.rs
parentefaab433309170e8330a7722e90c26a93dbec252 (diff)
downloadsylt-97e77b94646fe97a2c83ba85ba1813eb9bd0346a.tar.gz
Parsing simple mathematical expressions
Diffstat (limited to 'src/compiler.rs')
-rw-r--r--src/compiler.rs128
1 files changed, 107 insertions, 21 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index 59659f4..ca4fcd3 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -6,6 +6,10 @@ struct Compiler {
tokens: TokenStream,
}
+const PREC_NO: u64 = 0;
+const PREC_TERM: u64 = 1;
+const PREC_FACTOR: u64 = 2;
+
impl Compiler {
pub fn new(tokens: TokenStream) -> Self {
Self {
@@ -15,12 +19,12 @@ impl Compiler {
}
fn error(&self, msg: &str) -> ! {
- println!("ERROR: {}", msg);
+ println!("ERROR: {} range {:?}", msg, self.tokens[self.curr].1);
panic!();
}
fn peek(&self) -> Token {
- if self.tokens.len() < self.curr {
+ if self.tokens.len() <= self.curr {
crate::tokenizer::Token::EOF
} else {
self.tokens[self.curr].0.clone()
@@ -33,39 +37,121 @@ impl Compiler {
t
}
- fn value(&mut self) -> Value {
- match self.eat() {
+ fn precedence(&self, token: Token) -> u64 {
+ match token {
+ Token::Minus => PREC_TERM,
+ Token::Plus => PREC_TERM,
+
+ Token::Star => PREC_FACTOR,
+ Token::Slash => PREC_FACTOR,
+
+ _ => PREC_NO,
+ }
+ }
+
+ fn prefix(&mut self, token: Token, block: &mut Block) -> bool {
+ match token {
+ Token::LeftParen => self.grouping(block),
+ Token::Minus => self.unary(block),
+
+ Token::Float(_) => self.value(block),
+ Token::Int(_) => self.value(block),
+
+ _ => { return false; },
+ }
+ return true;
+ }
+
+
+ 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),
+
+ _ => { return false; },
+ }
+ return true;
+ }
+
+ fn value(&mut self, block: &mut Block) {
+ let value = match self.eat() {
Token::Float(f) => { Value::Float(f) },
Token::Int(f) => { Value::Int(f) }
_ => { self.error("Invalid value.") }
+ };
+ block.add(Op::Constant(value));
+ }
+
+ fn grouping(&mut self, block: &mut Block) {
+ if Token::LeftParen != self.eat() {
+ self.error("Expected left parentasis around expression.");
}
+
+ self.expression(block);
+
+ if Token::RightParen != self.eat() {
+ self.error("Expected closing parentasis after expression.");
+ }
+ }
+
+ fn unary(&mut self, block: &mut Block) {
+ if Token::Minus != self.eat() {
+ self.error("Expected minus at start of negation.");
+ }
+ self.value(block);
+ block.add(Op::Neg);
+ }
+
+ fn binary(&mut self, block: &mut Block) {
+ let op = self.eat();
+
+ self.parse_precedence(block, self.precedence(op.clone()) + 1);
+
+ let op = match op {
+ Token::Plus => Op::Add,
+ Token::Minus => Op::Sub,
+ Token::Star => Op::Mul,
+ Token::Slash => Op::Div,
+ _ => { self.error("Illegal operator"); }
+ };
+ block.add(op);
}
fn expression(&mut self, block: &mut Block) {
- let a = self.value();
- block.add(Op::Constant(a));
+ self.parse_precedence(block, PREC_NO);
+ }
- loop {
- println!("{:?}", self.peek());
- let op = match self.eat() {
- Token::Plus => Op::Add,
- Token::Minus => Op::Sub,
- Token::Star => Op::Mul,
- Token::Slash => Op::Div,
- _ => { break; }
- };
-
- let b = self.value();
- block.add(Op::Constant(b));
- block.add(op);
+ fn parse_precedence(&mut self, block: &mut Block, precedence: u64) {
+ println!("-- {:?}", self.peek());
+ if !self.prefix(self.peek(), block) {
+ self.error("Expected expression.");
+ }
+
+ while precedence <= self.precedence(self.peek()) {
+ if !self.infix(self.peek(), block) {
+ break;
+ }
}
}
pub fn compile(&mut self, name: &str) -> Block {
let mut block = Block::new(name);
- self.expression(&mut block);
- block.add(Op::Print);
+ loop {
+ if self.peek() == Token::EOF {
+ break;
+ }
+
+ self.expression(&mut block);
+ block.add(Op::Print);
+
+ if self.eat() != Token::Newline {
+ self.error("Invalid expression");
+ }
+ }
block.add(Op::Return);
block