Add binop expression parsing
This commit is contained in:
parent
40f3738719
commit
ee14e18787
@ -3,8 +3,9 @@
|
|||||||
import std::print;
|
import std::print;
|
||||||
|
|
||||||
let test = 5;
|
let test = 5;
|
||||||
|
let simpleAdd = 2 + 2;
|
||||||
let arithmetic = 3 + 2 * 5 + 1 * 2;
|
let arithmetic = 3 + 2 * 5 + 1 * 2;
|
||||||
let multiplier = 5 * 2;
|
let multiplier = 5 * 2;
|
||||||
|
|
||||||
let result = arithmetic * multiplier + arithmetic;
|
let result = arithmetic + multiplier * arithmetic;
|
||||||
print(result);
|
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)
|
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)]
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
// Values
|
// Values
|
||||||
@ -132,6 +116,32 @@ pub enum Token {
|
|||||||
Eof,
|
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 struct Cursor<'a> {
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
char_stream: Peekable<Chars<'a>>,
|
char_stream: Peekable<Chars<'a>>,
|
||||||
|
@ -7,14 +7,22 @@ where
|
|||||||
fn parse(stream: TokenStream) -> Result<Self, ()>;
|
fn parse(stream: TokenStream) -> Result<Self, ()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
VariableName(String),
|
VariableName(String),
|
||||||
ContantI32(i32),
|
ContantI32(i32),
|
||||||
|
BinopAdd(Box<Expression>, Box<Expression>),
|
||||||
|
BinopMult(Box<Expression>, Box<Expression>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parseable for Expression {
|
impl Parseable for Expression {
|
||||||
fn parse(mut stream: TokenStream) -> Result<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() {
|
if let Some(token) = stream.next() {
|
||||||
Ok(match &token {
|
Ok(match &token {
|
||||||
Token::Identifier(v) => Expression::VariableName(v.clone()),
|
Token::Identifier(v) => Expression::VariableName(v.clone()),
|
||||||
@ -24,7 +32,46 @@ impl Parseable for Expression {
|
|||||||
} else {
|
} else {
|
||||||
Err(())
|
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)]
|
#[derive(Debug)]
|
||||||
|
@ -20,7 +20,7 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
|
|
||||||
pub fn expect(&mut self, token: Token) -> Result<(), ()> {
|
pub fn expect(&mut self, token: Token) -> Result<(), ()> {
|
||||||
if let Some(peeked) = self.peek() {
|
if let Some(peeked) = self.peek() {
|
||||||
if token == *peeked {
|
if token == peeked {
|
||||||
self.position += 1;
|
self.position += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -41,11 +41,11 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek(&mut self) -> Option<&Token> {
|
pub fn peek(&mut self) -> Option<Token> {
|
||||||
if self.tokens.len() < self.position {
|
if self.tokens.len() < self.position {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(&self.tokens[self.position].token)
|
Some(self.tokens[self.position].token.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user