Implemented binop parsing
Uses Operator-precedence parsing algorithm, which I don't fully understand.
This commit is contained in:
parent
8b6d54aec2
commit
2989ac338c
5
Grammar
5
Grammar
@ -12,7 +12,10 @@
|
|||||||
| if <expr> then <statements> else <statements> end
|
| if <expr> then <statements> else <statements> end
|
||||||
| while <expr> SEP <statements> end
|
| while <expr> SEP <statements> end
|
||||||
| ( <expr> )
|
| ( <expr> )
|
||||||
| <simple_expr>
|
| <binop>
|
||||||
|
|
||||||
|
<binop> := <simple_expr>
|
||||||
|
| <simple_expr> <id> <binop>
|
||||||
|
|
||||||
<simple_expr> := <id>
|
<simple_expr> := <id>
|
||||||
| <number>
|
| <number>
|
||||||
|
@ -136,7 +136,7 @@ fn expression(tokens: &mut Tokens) -> ParseResult {
|
|||||||
expect!(RParen, tokens);
|
expect!(RParen, tokens);
|
||||||
expr
|
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 {
|
fn simple_expression(tokens: &mut Tokens) -> ParseResult {
|
||||||
let next = tokens.next();
|
let next = tokens.next();
|
||||||
if let Some(&Identifier(ref value)) = next {
|
if let Some(&Identifier(ref value)) = next {
|
||||||
|
Loading…
Reference in New Issue
Block a user