Implemented binop parsing

Uses Operator-precedence parsing algorithm, which I don't fully
understand.
This commit is contained in:
greg 2015-07-26 14:59:01 -07:00
parent 8b6d54aec2
commit 2989ac338c
2 changed files with 73 additions and 2 deletions

View File

@ -12,7 +12,10 @@
| if <expr> then <statements> else <statements> end
| while <expr> SEP <statements> end
| ( <expr> )
| <simple_expr>
| <binop>
<binop> := <simple_expr>
| <simple_expr> <id> <binop>
<simple_expr> := <id>
| <number>

View File

@ -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<i32> {
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 {