add pratt parser
This commit is contained in:
parent
a4eed5214e
commit
c70c5fab4d
3 changed files with 155 additions and 4 deletions
18
src/main.rs
18
src/main.rs
|
|
@ -3,6 +3,8 @@ use std::{fs::File, io::Read};
|
|||
mod token;
|
||||
mod lexer;
|
||||
use lexer::Lexer;
|
||||
mod parser;
|
||||
use parser::Parser;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let args = std::env::args().collect::<Vec<String>>();
|
||||
|
|
@ -14,10 +16,20 @@ fn main() -> std::io::Result<()> {
|
|||
|
||||
let mut lexer = Lexer::new(&source);
|
||||
|
||||
let mut tokens = Vec::new();
|
||||
while let Some(tok) = lexer.next() {
|
||||
print!("{tok:?}, ");
|
||||
tokens.push(tok);
|
||||
}
|
||||
|
||||
println!("\n");
|
||||
|
||||
let mut parser = Parser::new(tokens);
|
||||
loop {
|
||||
match lexer.next() {
|
||||
Some(tok) => print!("{tok:?}, "),
|
||||
None => break
|
||||
let parsed = parser.parse();
|
||||
match parsed {
|
||||
parser::Expr::EOL => break,
|
||||
_ => println!("{:?}", parsed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
139
src/parser.rs
Normal file
139
src/parser.rs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
use crate::token::Token;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BinaryOp {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UnaryOp {
|
||||
Neg
|
||||
}
|
||||
|
||||
fn prefix_bp(op: &UnaryOp) -> u8 {
|
||||
match op {
|
||||
UnaryOp::Neg => 5
|
||||
}
|
||||
}
|
||||
|
||||
fn infix_bp(op: &BinaryOp) -> (u8, u8) {
|
||||
match op {
|
||||
BinaryOp::Add | BinaryOp::Sub => (1, 2),
|
||||
BinaryOp::Mul | BinaryOp::Div | BinaryOp::Mod => (3, 4)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Expr {
|
||||
Number(i64),
|
||||
Ident(String),
|
||||
EOL,
|
||||
|
||||
Binary {
|
||||
op: BinaryOp,
|
||||
left: Box<Expr>,
|
||||
right: Box<Expr>
|
||||
},
|
||||
|
||||
Unary {
|
||||
op: UnaryOp,
|
||||
right: Box<Expr>
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Parser {
|
||||
tokens: Vec<Token>,
|
||||
pos: usize
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new(tokens: Vec<Token>) -> Self {
|
||||
Self {
|
||||
tokens,
|
||||
pos: 0
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(&mut self) {
|
||||
self.pos += 1;
|
||||
}
|
||||
|
||||
fn peek(&self) -> Option<&Token> {
|
||||
self.tokens.get(self.pos)
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Option<Token> {
|
||||
let tok = self.peek().cloned();
|
||||
self.advance();
|
||||
tok
|
||||
}
|
||||
|
||||
fn parse_atom(&mut self) -> Expr {
|
||||
match self.next() {
|
||||
Some(Token::Number(n)) => Expr::Number(n),
|
||||
Some(Token::Ident(id)) => Expr::Ident(id),
|
||||
Some(Token::LParen) => {
|
||||
let expr = self.parse_expr(0);
|
||||
|
||||
match self.next() {
|
||||
Some(Token::RParen) => expr,
|
||||
_ => panic!("expected ')'")
|
||||
}
|
||||
},
|
||||
tok => panic!("unknown token: {tok:?}")
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_prefix(&mut self) -> Expr {
|
||||
match self.peek() {
|
||||
Some(Token::Sub) => {
|
||||
self.advance();
|
||||
let op = UnaryOp::Neg;
|
||||
|
||||
let bp = prefix_bp(&op);
|
||||
let rhs = self.parse_expr(bp);
|
||||
|
||||
Expr::Unary { op, right: Box::new(rhs) }
|
||||
},
|
||||
_ => self.parse_atom()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_expr(&mut self, min_bp: u8) -> Expr {
|
||||
let mut lhs = self.parse_prefix();
|
||||
|
||||
loop {
|
||||
let op = match self.peek() {
|
||||
Some(Token::Add) => BinaryOp::Add,
|
||||
Some(Token::Sub) => BinaryOp::Sub,
|
||||
Some(Token::Mul) => BinaryOp::Mul,
|
||||
Some(Token::Div) => BinaryOp::Div,
|
||||
Some(Token::Mod) => BinaryOp::Mod,
|
||||
_ => break
|
||||
};
|
||||
|
||||
let (left_bp, right_bp) = infix_bp(&op);
|
||||
|
||||
if left_bp < min_bp {
|
||||
break;
|
||||
}
|
||||
|
||||
self.advance();
|
||||
|
||||
let rhs = self.parse_expr(right_bp);
|
||||
|
||||
lhs = Expr::Binary { left: Box::new(lhs), op, right: Box::new(rhs) }
|
||||
}
|
||||
|
||||
lhs
|
||||
}
|
||||
|
||||
pub fn parse(&mut self) -> Expr {
|
||||
if self.peek() == None {return Expr::EOL}
|
||||
self.parse_expr(0)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Token {
|
||||
Number(i64),
|
||||
Ident(String),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue