Add binop expression parsing
This commit is contained in:
parent
40f3738719
commit
ee14e18787
@ -3,8 +3,9 @@
|
||||
import std::print;
|
||||
|
||||
let test = 5;
|
||||
let simpleAdd = 2 + 2;
|
||||
let arithmetic = 3 + 2 * 5 + 1 * 2;
|
||||
let multiplier = 5 * 2;
|
||||
|
||||
let result = arithmetic * multiplier + arithmetic;
|
||||
let result = arithmetic + multiplier * arithmetic;
|
||||
print(result);
|
42
src/lexer.rs
42
src/lexer.rs
@ -93,22 +93,6 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Strin
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
pub struct FullToken {
|
||||
pub token: Token,
|
||||
position: Position,
|
||||
}
|
||||
|
||||
impl Debug for FullToken {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!(
|
||||
"{:?} (Ln {}, Col {})",
|
||||
self.token, self.position.1, self.position.0
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub type Position = (u32, u32);
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub enum Token {
|
||||
// Values
|
||||
@ -132,6 +116,32 @@ pub enum Token {
|
||||
Eof,
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub fn get_token_prec(&self) -> i8 {
|
||||
match &self {
|
||||
Token::Plus => 10,
|
||||
Token::Times => 20,
|
||||
_ => -1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FullToken {
|
||||
pub token: Token,
|
||||
position: Position,
|
||||
}
|
||||
|
||||
impl Debug for FullToken {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!(
|
||||
"{:?} (Ln {}, Col {})",
|
||||
self.token, self.position.1, self.position.0
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub type Position = (u32, u32);
|
||||
|
||||
pub struct Cursor<'a> {
|
||||
pub position: Position,
|
||||
char_stream: Peekable<Chars<'a>>,
|
||||
|
@ -7,14 +7,22 @@ where
|
||||
fn parse(stream: TokenStream) -> Result<Self, ()>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Expression {
|
||||
VariableName(String),
|
||||
ContantI32(i32),
|
||||
BinopAdd(Box<Expression>, Box<Expression>),
|
||||
BinopMult(Box<Expression>, Box<Expression>),
|
||||
}
|
||||
|
||||
impl Parseable for Expression {
|
||||
fn parse(mut stream: TokenStream) -> Result<Expression, ()> {
|
||||
let lhs = parse_primary_expression(&mut stream)?;
|
||||
parse_binop_rhs(&mut stream, lhs, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_primary_expression(stream: &mut TokenStream) -> Result<Expression, ()> {
|
||||
if let Some(token) = stream.next() {
|
||||
Ok(match &token {
|
||||
Token::Identifier(v) => Expression::VariableName(v.clone()),
|
||||
@ -25,6 +33,45 @@ impl Parseable for Expression {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// This algorithm seems somewhat like magic to me. I understand it if I read
|
||||
/// carefully, but it is difficult to read every single time.
|
||||
///
|
||||
/// Reference for how the algorithm is formed:
|
||||
/// https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.html#binary-expression-parsing
|
||||
fn parse_binop_rhs(
|
||||
stream: &mut TokenStream,
|
||||
mut lhs: Expression,
|
||||
expr_prec: i8,
|
||||
) -> Result<Expression, ()> {
|
||||
while let Some(token) = stream.peek() {
|
||||
let curr_token_prec = token.get_token_prec();
|
||||
|
||||
if curr_token_prec < expr_prec {
|
||||
break; // Just return lhs
|
||||
} else {
|
||||
// token has to be an operator
|
||||
stream.next(); // Eat token
|
||||
|
||||
let mut rhs = parse_primary_expression(stream)?;
|
||||
if let Some(next_op) = stream.peek() {
|
||||
let next_prec = next_op.get_token_prec();
|
||||
if curr_token_prec < next_prec {
|
||||
// Operator on the right of rhs has more precedence, turn
|
||||
// rhs into lhs for new binop
|
||||
rhs = parse_binop_rhs(stream, rhs, curr_token_prec + 1)?;
|
||||
}
|
||||
}
|
||||
|
||||
lhs = match &token {
|
||||
Token::Plus => Expression::BinopAdd(Box::new(lhs), Box::new(rhs)),
|
||||
Token::Times => Expression::BinopMult(Box::new(lhs), Box::new(rhs)),
|
||||
_ => Err(())?,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(lhs)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -20,7 +20,7 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
||||
|
||||
pub fn expect(&mut self, token: Token) -> Result<(), ()> {
|
||||
if let Some(peeked) = self.peek() {
|
||||
if token == *peeked {
|
||||
if token == peeked {
|
||||
self.position += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
@ -41,11 +41,11 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
||||
value
|
||||
}
|
||||
|
||||
pub fn peek(&mut self) -> Option<&Token> {
|
||||
pub fn peek(&mut self) -> Option<Token> {
|
||||
if self.tokens.len() < self.position {
|
||||
None
|
||||
} else {
|
||||
Some(&self.tokens[self.position].token)
|
||||
Some(self.tokens[self.position].token.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user