From 2989ac338c33c30900bbfb60b17b988efc5cb2a5 Mon Sep 17 00:00:00 2001 From: greg Date: Sun, 26 Jul 2015 14:59:01 -0700 Subject: [PATCH] Implemented binop parsing Uses Operator-precedence parsing algorithm, which I don't fully understand. --- Grammar | 5 +++- src/parser.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/Grammar b/Grammar index 869ae42..f880104 100644 --- a/Grammar +++ b/Grammar @@ -12,7 +12,10 @@ | if then else end | while SEP end | ( ) - | + | + + := + | := | diff --git a/src/parser.rs b/src/parser.rs index 13d29e8..fa27649 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -136,7 +136,7 @@ fn expression(tokens: &mut Tokens) -> ParseResult { expect!(RParen, tokens); expr }, - _ => simple_expression(tokens) + _ => binop_expression(tokens) } } @@ -196,6 +196,74 @@ fn while_expression(tokens: &mut Tokens) -> ParseResult { )) } +fn binop_expression(tokens: &mut Tokens) -> ParseResult { + let lhs = match simple_expression(tokens) { + err@ParseResult::Err(_) => return err, + ParseResult::Ok(ast) => ast + }; + + binop_rhs(0, lhs, tokens) +} + +fn binop_rhs(precedence: i32, lhs: AST, tokens: &mut Tokens) -> ParseResult { + + let lookahead_precedence = tokens.peek().and_then(|tok| get_binop_precedence(tok)); + + let output = match lookahead_precedence { + None => lhs, + Some(next) => { + if next < precedence { + lhs + } else { + let binop = match tokens.next() { + Some(&Identifier(ref s)) => AST::Name(s.clone()), + _ => return ParseResult::Err("Bad binop parse".to_string()) + }; + let preliminary_rhs = match simple_expression(tokens) { + err@ParseResult::Err(_) => return err, + ParseResult::Ok(ast) => ast + }; + + let after_rhs_precedence = tokens.peek().and_then(|tok| get_binop_precedence(tok)); + let true_rhs = match after_rhs_precedence { + Some(arp) if arp >= next => { + match binop_rhs(precedence+1, preliminary_rhs, tokens) { + ParseResult::Ok(ast) => ast, + err@ParseResult::Err(_) => return err + } + }, + + _ => preliminary_rhs + }; + + AST::BinOp( + Box::new(binop), + Box::new(lhs), + Box::new(true_rhs) + ) + } + } + }; + + ParseResult::Ok(output) +} + +fn get_binop_precedence(token: &Token) -> Option { + let identifier_str = match token { + &Identifier(ref s) => s, + _ => return None + }; + let precedence = match &identifier_str[..] { + "+" => 20, + "-" => 20, + "*" => 40, + "/" => 40, + _ => -1 + }; + + Some(precedence) +} + fn simple_expression(tokens: &mut Tokens) -> ParseResult { let next = tokens.next(); if let Some(&Identifier(ref value)) = next {