Parseur d'expression et affichage du résultat avec l'ASTPrinter.
This commit is contained in:
@@ -7,6 +7,8 @@ mod scanner;
|
||||
mod token;
|
||||
mod token_type;
|
||||
mod expr;
|
||||
mod astprinter;
|
||||
mod parser;
|
||||
|
||||
use crate::rlox_interpreter::RLoxInterpreter;
|
||||
|
||||
@@ -34,4 +36,4 @@ fn main() {
|
||||
// https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust
|
||||
|
||||
// Pause :
|
||||
// http://www.craftinginterpreters.com/representing-code.html#working-with-trees
|
||||
// http://www.craftinginterpreters.com/parsing-expressions.html implémentation de comparison
|
||||
|
||||
215
src/parser.rs
Normal file
215
src/parser.rs
Normal file
@@ -0,0 +1,215 @@
|
||||
use crate::expr::{Binary, Expr, Grouping, Unary};
|
||||
use crate::expr::Literal::{LiteralBool, LiteralNumber, LiteralString};
|
||||
use crate::token::Token;
|
||||
use crate::token_type::TokenType;
|
||||
|
||||
pub struct Parser {
|
||||
tokens: Vec<Token>,
|
||||
current: usize
|
||||
}
|
||||
|
||||
pub struct ParseError {
|
||||
message: String
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new( t_init: Vec<Token >) -> Self {
|
||||
Parser {
|
||||
tokens: t_init,
|
||||
current: 0
|
||||
}
|
||||
}
|
||||
|
||||
fn match_token( &mut self, token_type_list: &[TokenType] ) -> bool {
|
||||
for token_type in token_type_list {
|
||||
if self.check(token_type) {
|
||||
self.advance();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn check(&self, token_type: &TokenType) -> bool {
|
||||
if self.is_at_end() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return self.peek().token_type==*token_type;
|
||||
}
|
||||
|
||||
fn advance(&mut self) -> Token {
|
||||
if !self.is_at_end() {
|
||||
self.current += 1;
|
||||
}
|
||||
return self.previous();
|
||||
}
|
||||
|
||||
fn is_at_end(&self) -> bool {
|
||||
return self.peek().token_type==TokenType::Eof;
|
||||
}
|
||||
|
||||
fn peek(&self) -> Token {
|
||||
return self.tokens[self.current].clone();
|
||||
}
|
||||
|
||||
fn previous(&self) -> Token {
|
||||
return self.tokens[self.current - 1].clone();
|
||||
}
|
||||
|
||||
fn consume(&mut self, token_type: &TokenType, message: String) -> Result<(), ParseError> {
|
||||
if self.check(token_type) {
|
||||
self.advance();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(ParseError {
|
||||
message
|
||||
})
|
||||
}
|
||||
|
||||
fn synchronise(&mut self) {
|
||||
self.advance();
|
||||
|
||||
while !self.is_at_end() {
|
||||
if self.previous().token_type == TokenType::Semicolon {
|
||||
return;
|
||||
}
|
||||
|
||||
match self.peek().token_type {
|
||||
TokenType::Class => return,
|
||||
TokenType::Fun => return,
|
||||
TokenType::Var => return,
|
||||
TokenType::For => return,
|
||||
TokenType::If => return,
|
||||
TokenType::While => return,
|
||||
TokenType::Print => return,
|
||||
TokenType::Return => return,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.advance();
|
||||
}
|
||||
}
|
||||
|
||||
fn expression(&mut self) -> Result<Expr,ParseError> {
|
||||
self.equality()
|
||||
}
|
||||
|
||||
fn equality(&mut self) -> Result<Expr,ParseError> {
|
||||
let mut expr: Expr = self.comparison()?;
|
||||
|
||||
while self.match_token( &[TokenType::BangEqual, TokenType::EqualEqual]) {
|
||||
let operator: Token = self.previous();
|
||||
let right: Expr = self.comparison()?;
|
||||
expr = Expr::BinaryExpr(Binary{
|
||||
left: Box::new(expr),
|
||||
operator,
|
||||
right: Box::new(right)
|
||||
});
|
||||
}
|
||||
|
||||
return Ok(expr);
|
||||
}
|
||||
|
||||
fn comparison(&mut self) -> Result<Expr,ParseError> {
|
||||
let mut expr = self.term()?;
|
||||
|
||||
while self.match_token(&[TokenType::Greater, TokenType::GreaterEqual, TokenType::Less, TokenType::LessEqual]) {
|
||||
let operator = self.previous();
|
||||
let right = self.term()?;
|
||||
expr = Expr::BinaryExpr(Binary{
|
||||
left: Box::new(expr),
|
||||
operator,
|
||||
right: Box::new(right)
|
||||
});
|
||||
}
|
||||
|
||||
return Ok(expr);
|
||||
}
|
||||
|
||||
fn term(&mut self) -> Result<Expr,ParseError> {
|
||||
let mut expr = self.factor()?;
|
||||
|
||||
while self.match_token(&[TokenType::Minus, TokenType::Plus]) {
|
||||
let operator = self.previous();
|
||||
let right = self.factor()?;
|
||||
expr = Expr::BinaryExpr(Binary{
|
||||
left: Box::new(expr),
|
||||
operator,
|
||||
right: Box::new(right)
|
||||
});
|
||||
}
|
||||
|
||||
return Ok(expr);
|
||||
}
|
||||
|
||||
fn factor(&mut self) -> Result<Expr,ParseError> {
|
||||
let mut expr = self.unary()?;
|
||||
|
||||
while self.match_token(&[TokenType::Star, TokenType::Slash]) {
|
||||
let operator = self.previous();
|
||||
let right = self.unary()?;
|
||||
expr = Expr::BinaryExpr(Binary{
|
||||
left: Box::new(expr),
|
||||
operator,
|
||||
right: Box::new(right)
|
||||
});
|
||||
}
|
||||
|
||||
return Ok(expr);
|
||||
}
|
||||
|
||||
fn unary(&mut self) -> Result<Expr,ParseError> {
|
||||
if self.match_token(&[TokenType::Bang, TokenType::Minus]) {
|
||||
let operator = self.previous();
|
||||
let right = self.unary()?;
|
||||
return Ok(Expr::UnaryExpr(Unary {
|
||||
operator,
|
||||
right: Box::new(right)
|
||||
}));
|
||||
}
|
||||
|
||||
self.primary()
|
||||
}
|
||||
|
||||
fn primary(&mut self) -> Result<Expr,ParseError> {
|
||||
if self.match_token(&[TokenType::False]) {
|
||||
return Ok(Expr::LiteralExpr(LiteralBool(false)));
|
||||
}
|
||||
if self.match_token(&[TokenType::True]) {
|
||||
return Ok(Expr::LiteralExpr(LiteralBool(true)));
|
||||
}
|
||||
if self.match_token(&[TokenType::Nil]) {
|
||||
return Ok(Expr::LiteralExpr(LiteralBool(false)));
|
||||
}
|
||||
if self.match_token(&[TokenType::Number]) {
|
||||
return Ok(Expr::LiteralExpr(LiteralNumber(self.previous().literal.parse::<f64>().unwrap())));
|
||||
}
|
||||
if self.match_token(&[TokenType::String]) {
|
||||
return Ok(Expr::LiteralExpr(LiteralString(self.previous().literal)));
|
||||
}
|
||||
if self.match_token(&[TokenType::LeftParen]) {
|
||||
let expr = self.expression()?;
|
||||
self.consume(&TokenType::RightParen, String::from("Expect ')' after expression."))?;
|
||||
return Ok(Expr::GroupingExpr(Grouping {
|
||||
expression: Box::new(expr)
|
||||
}));
|
||||
} else {
|
||||
Err(ParseError {
|
||||
message: String::from("Unexpected token : expression expected.")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(&mut self) -> Option<Expr> {
|
||||
match self.expression() {
|
||||
Ok(expr) => Some(expr),
|
||||
Err(error) => {
|
||||
println!("Error while parsing expression : {}",error.message);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
use std::{fs, io};
|
||||
use crate::EX_OK;
|
||||
use std::io::Write;
|
||||
use crate::astprinter::ASTPrinter;
|
||||
use crate::expr::ExprVisitor;
|
||||
use crate::parser::Parser;
|
||||
|
||||
use crate::scanner::Scanner;
|
||||
|
||||
@@ -40,15 +43,15 @@ impl RLoxInterpreter {
|
||||
|
||||
fn run(&self, src: String) -> i32 {
|
||||
let mut scanner = Scanner::new( src );
|
||||
|
||||
scanner.scan_tokens();
|
||||
let mut current_line = 0;
|
||||
for t in scanner.tokens {
|
||||
if t.line!=current_line {
|
||||
current_line = t.line;
|
||||
println!("-- line {} --------------------", current_line);
|
||||
}
|
||||
println!("{}\t{}\t{}", t.token_type, t.lexeme, t.literal);
|
||||
|
||||
let mut parser = Parser::new( scanner.tokens );
|
||||
match parser.parse() {
|
||||
Some(expr) => {
|
||||
let printer = ASTPrinter;
|
||||
printer.visit_expr(&expr);
|
||||
},
|
||||
None => println!("An error occurred while parsing expression.")
|
||||
}
|
||||
|
||||
EX_OK
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::token_type::TokenType;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Token {
|
||||
pub token_type: TokenType,
|
||||
pub lexeme: String,
|
||||
|
||||
Reference in New Issue
Block a user