Compare commits
No commits in common. "99be8a16c753575148bd0b93a6fb19748825a6c4" and "ad7a8ad8793019ad93cee971187cc7d0f0cca462" have entirely different histories.
99be8a16c7
...
ad7a8ad879
5 changed files with 25 additions and 222 deletions
38
src/eval.rs
38
src/eval.rs
|
|
@ -1,38 +0,0 @@
|
||||||
use crate::parser::{BinaryOp, Expr, UnaryOp};
|
|
||||||
|
|
||||||
pub struct Evaluator {
|
|
||||||
ast: Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Evaluator {
|
|
||||||
pub fn new(ast: Expr) -> Self {
|
|
||||||
Self {
|
|
||||||
ast
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_expr(&self, expr: Expr) -> i64 {
|
|
||||||
match expr {
|
|
||||||
Expr::Number(n) => n,
|
|
||||||
Expr::Unary { op, right } => {
|
|
||||||
match op {
|
|
||||||
UnaryOp::Neg => -self.eval_expr(*right)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Expr::Binary { op, left, right } => {
|
|
||||||
match op {
|
|
||||||
BinaryOp::Add => self.eval_expr(*left) + self.eval_expr(*right),
|
|
||||||
BinaryOp::Sub => self.eval_expr(*left) - self.eval_expr(*right),
|
|
||||||
BinaryOp::Mul => self.eval_expr(*left) * self.eval_expr(*right),
|
|
||||||
BinaryOp::Div => self.eval_expr(*left) / self.eval_expr(*right),
|
|
||||||
BinaryOp::Mod => self.eval_expr(*left) % self.eval_expr(*right)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
expr => panic!("can't eval expression: {expr:?}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn eval(&self) -> i64 {
|
|
||||||
self.eval_expr(self.ast.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
23
src/lexer.rs
23
src/lexer.rs
|
|
@ -1,4 +1,25 @@
|
||||||
use crate::token::Token;
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Token {
|
||||||
|
Number(i64),
|
||||||
|
Ident(String),
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
|
||||||
|
// Parentheses
|
||||||
|
LParen,
|
||||||
|
RParen,
|
||||||
|
LBrace,
|
||||||
|
RBrace,
|
||||||
|
LBracket,
|
||||||
|
RBracket,
|
||||||
|
|
||||||
|
Semicolon
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Lexer {
|
pub struct Lexer {
|
||||||
source: Vec<u8>,
|
source: Vec<u8>,
|
||||||
|
|
|
||||||
25
src/main.rs
25
src/main.rs
|
|
@ -1,12 +1,7 @@
|
||||||
use std::{fs::File, io::Read};
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
mod token;
|
|
||||||
mod lexer;
|
mod lexer;
|
||||||
use lexer::Lexer;
|
use lexer::Lexer;
|
||||||
mod parser;
|
|
||||||
use parser::Parser;
|
|
||||||
mod eval;
|
|
||||||
use eval::Evaluator;
|
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let args = std::env::args().collect::<Vec<String>>();
|
let args = std::env::args().collect::<Vec<String>>();
|
||||||
|
|
@ -18,24 +13,10 @@ fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
let mut lexer = Lexer::new(&source);
|
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 {
|
loop {
|
||||||
let parsed = parser.parse();
|
match lexer.next() {
|
||||||
match parsed {
|
Some(tok) => print!("{tok:?}, "),
|
||||||
parser::Expr::EOL => break,
|
None => break
|
||||||
_ => {
|
|
||||||
println!("AST: {:?}", parsed);
|
|
||||||
let eval = Evaluator::new(parsed);
|
|
||||||
println!("Eval: {:?}", eval.eval());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
139
src/parser.rs
139
src/parser.rs
|
|
@ -1,139 +0,0 @@
|
||||||
use crate::token::Token;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum BinaryOp {
|
|
||||||
Add,
|
|
||||||
Sub,
|
|
||||||
Mul,
|
|
||||||
Div,
|
|
||||||
Mod
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
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, Clone)]
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
22
src/token.rs
22
src/token.rs
|
|
@ -1,22 +0,0 @@
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
|
||||||
pub enum Token {
|
|
||||||
Number(i64),
|
|
||||||
Ident(String),
|
|
||||||
|
|
||||||
// Operators
|
|
||||||
Add,
|
|
||||||
Sub,
|
|
||||||
Mul,
|
|
||||||
Div,
|
|
||||||
Mod,
|
|
||||||
|
|
||||||
// Parentheses
|
|
||||||
LParen,
|
|
||||||
RParen,
|
|
||||||
LBrace,
|
|
||||||
RBrace,
|
|
||||||
LBracket,
|
|
||||||
RBracket,
|
|
||||||
|
|
||||||
Semicolon
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue