Parseur d'expression et affichage du résultat avec l'ASTPrinter.

This commit is contained in:
2024-05-16 22:45:40 +02:00
parent 72ef4e3bbf
commit b4d2170eb4
4 changed files with 230 additions and 10 deletions

View File

@@ -7,6 +7,8 @@ mod scanner;
mod token; mod token;
mod token_type; mod token_type;
mod expr; mod expr;
mod astprinter;
mod parser;
use crate::rlox_interpreter::RLoxInterpreter; use crate::rlox_interpreter::RLoxInterpreter;
@@ -34,4 +36,4 @@ fn main() {
// https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust // https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust
// Pause : // 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
View 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
}
}
}
}

View File

@@ -1,6 +1,9 @@
use std::{fs, io}; use std::{fs, io};
use crate::EX_OK; use crate::EX_OK;
use std::io::Write; use std::io::Write;
use crate::astprinter::ASTPrinter;
use crate::expr::ExprVisitor;
use crate::parser::Parser;
use crate::scanner::Scanner; use crate::scanner::Scanner;
@@ -40,15 +43,15 @@ impl RLoxInterpreter {
fn run(&self, src: String) -> i32 { fn run(&self, src: String) -> i32 {
let mut scanner = Scanner::new( src ); let mut scanner = Scanner::new( src );
scanner.scan_tokens(); scanner.scan_tokens();
let mut current_line = 0;
for t in scanner.tokens { let mut parser = Parser::new( scanner.tokens );
if t.line!=current_line { match parser.parse() {
current_line = t.line; Some(expr) => {
println!("-- line {} --------------------", current_line); let printer = ASTPrinter;
} printer.visit_expr(&expr);
println!("{}\t{}\t{}", t.token_type, t.lexeme, t.literal); },
None => println!("An error occurred while parsing expression.")
} }
EX_OK EX_OK

View File

@@ -1,6 +1,6 @@
use crate::token_type::TokenType; use crate::token_type::TokenType;
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Token { pub struct Token {
pub token_type: TokenType, pub token_type: TokenType,
pub lexeme: String, pub lexeme: String,