diff --git a/grammar.md b/grammar.md index 47bbfca..41d72fb 100644 --- a/grammar.md +++ b/grammar.md @@ -29,9 +29,9 @@ init -- "otherwise" --> error[[error]] ``` S -> A -A -> A + A | A - A | M -M -> M * M | M / M | G -G -> ( A ) | P ^ G | ID +A -> M + A | M - A | M +M -> G * M | G / M | G +G -> P ^ G | P P -> ( A ) | ID ``` @@ -82,16 +82,14 @@ s1("[S->.A]") --> s2(["[S->A.]"]) ```mermaid graph LR; -a1("[A->.A+A] | [A->.A-A] | [A->.M]") -a2(["[A->M.]"]) -a3("[A->A.+A] | [A->A.-A]") -a4("[A->A+.A]") -a5(["[A->A+A.]"]) -a6("[A->A-.A]") -a7(["[A->A-A.]"]) +a1("[A->.M+A] | [A->.M-A] | [A->.M]") +a3(["[A->M.+A] | [A->M.-A] | [A->M.]"]) +a4("[A->M+.A]") +a5(["[A->M+A.]"]) +a6("[A->M-.A]") +a7(["[A->M-A.]"]) -a1 -- M --> a2 -a1 -- A --> a3 +a1 -- M --> a3 a3 -- + --> a4 a4 -- A --> a5 a3 -- - --> a6 @@ -100,16 +98,14 @@ a6 -- A --> a7 ```mermaid graph LR; -m1("[M->.M*M] | [M->.M/M] | [M->.G]") -m2(["[M->G.]"]) -m3("[M->M.*M] | [M->M./M]") -m4("[M->M*.M]") -m5(["[M->M*M.]"]) -m6("[M->M/.M]") -m7(["[M->M/M.]"]) +m1("[M->.G*M] | [M->.G/M] | [M->.G]") +m3(["[M->G.*M] | [M->G./M] | [M->G.]"]) +m4("[M->G*.M]") +m5(["[M->G*M.]"]) +m6("[M->G/.M]") +m7(["[M->G/M.]"]) -m1 -- G --> m2 -m1 -- M --> m3 +m1 -- G --> m3 m3 -- * --> m4 m4 -- M --> m5 m3 -- / --> m6 @@ -118,22 +114,14 @@ m6 -- M --> m7 ```mermaid graph LR; -g1("[G->.(A)] | [G->.P^G] | [G->.ID]") -g2("[G->(.A)]") -g3("[G->(A.)]") -g4(["[G->(A).]"]) -g5("[G->P.^G]") +g1("[G->.P^G] | [G->.P]") +g5(["[G->P.^G] | [G->P.]"]) g6("[G->P^.G]") g7(["[G->P^G.]"]) -g8(["[G->ID.]"]) -g1 -- "(" --> g2 -g2 -- A --> g3 -g3 -- ")" --> g4 g1 -- P --> g5 g5 -- ^ --> g6 g6 -- G --> g7 -g1 -- ID --> g8 ``` ```mermaid diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index b238760..b54a144 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -10,8 +10,8 @@ use crate::lexer::errors::LexerErrors::EmptyTextSequenceError; use crate::lexer::fsm::{FSM, get_token}; use crate::lexer::tokens::{OpType, TokenMeta}; -mod errors; -mod tokens; +pub mod errors; +pub mod tokens; mod fsm; pub type Result = std::result::Result; diff --git a/src/lexer/tokens.rs b/src/lexer/tokens.rs index a9b064e..f20370c 100644 --- a/src/lexer/tokens.rs +++ b/src/lexer/tokens.rs @@ -4,12 +4,12 @@ /// * File that the token was parsed in /// * Line that the token was parsed in /// * Position of the *first character making up the token* in said line -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TokenMeta { pub pos: usize, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum OpType { MUL, DIV, @@ -45,7 +45,7 @@ pub enum BrType { /// 1. `OBR`: An opening bracket (`(`). /// 1. `CBR`: A closing bracket (`)`). /// 1. `OP`: An operation. Containing an [Operation Type](OpType). -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Token { ID (TokenMeta, f64), OBR (TokenMeta), diff --git a/src/lib.rs b/src/lib.rs index 0e5d4cb..b0a77fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod lexer; pub mod errors; +mod parser; pub fn test() { println!("{}", "hi there"); diff --git a/src/parser/errors.rs b/src/parser/errors.rs new file mode 100644 index 0000000..342643d --- /dev/null +++ b/src/parser/errors.rs @@ -0,0 +1,13 @@ +use thiserror::Error; +use crate::lexer::errors::LexerErrors; +use crate::lexer::tokens::Token; + +#[derive(Debug, Error)] +pub enum ParserErrors { + #[error("unexpected token: {0:?} in procedure {1}")] + UnexpectedTokenError(Token, String), + #[error("input ended prematurely")] + MissingTokenError, + #[error("lexer error")] + LexerError(#[from] LexerErrors), +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs new file mode 100644 index 0000000..7ba9655 --- /dev/null +++ b/src/parser/mod.rs @@ -0,0 +1,111 @@ +use std::result; + +use tokens::{OpType, Token}; + +use crate::lexer; +use crate::lexer::tokens; +use crate::parser::errors::ParserErrors; +use crate::parser::errors::ParserErrors::UnexpectedTokenError; + +mod errors; + +type Result = result::Result; + +pub struct TokenBox { + lexer: lexer::Lexer, + cur_token: Option, + regress: bool, // whether the last token should be outputted when reading a new token +} + +impl TokenBox { + fn read_token(&mut self) -> Result<&Option> { + if self.regress { + // if 'regressing' as in going back in time once, just set it to false (as in done) + self.regress = false; + } else { + // if not, read the next token from the lexer + self.cur_token = self.lexer.next()?; + } + Ok(&self.cur_token) + } + + fn regress(&mut self) { + self.regress = true; + } +} + +fn expect_token(maybe_token: &Option) -> Result<&Token> { + match &maybe_token { + &Some(token) => Ok(token), + &None => Err(ParserErrors::MissingTokenError), + } +} + +pub fn parse(mut lexer: lexer::Lexer) -> Result { + let mut tbox = TokenBox { lexer, cur_token: None, regress: false }; + s_proc(&mut tbox) +} + +pub fn s_proc(tbox: &mut TokenBox) -> Result { + let mut result = a_proc(tbox)?; + match tbox.read_token()? { + None => Ok(result), + Some(token) => Err(ParserErrors::UnexpectedTokenError(token.clone(), String::from("S"))), + } +} + +fn a_proc(tbox: &mut TokenBox) -> Result { + let mut result = m_proc(tbox)?; + match &tbox.read_token()? { + Some(Token::OP(_, OpType::ADD)) => Ok(result + a_proc(tbox)?), + Some(Token::OP(_, OpType::SUB)) => Ok(result - a_proc(tbox)?), + None => Ok(result), + Some(token) => Err(ParserErrors::UnexpectedTokenError(token.clone(), String::from("A"))) + } +} + +fn m_proc(tbox: &mut TokenBox) -> Result { + let mut result = g_proc(tbox)?; + match &tbox.read_token()? { + Some(Token::OP(_, OpType::MUL)) => Ok(result * m_proc(tbox)?), + Some(Token::OP(_, OpType::DIV)) => Ok(result / m_proc(tbox)?), + None => Ok(result), + Some(token) => Err(UnexpectedTokenError(token.clone(), String::from("M"))), + } +} + +fn g_proc(tbox: &mut TokenBox) -> Result { + let mut result = p_proc(tbox)?; + match tbox.read_token()? { + Some(Token::OP(_, OpType::POW)) => Ok(result.powf(g_proc(tbox)?)), + None => Ok(result), + Some(token) => Err(UnexpectedTokenError(token.clone(), String::from("G"))), + } +} + +fn p_proc(tbox: &mut TokenBox) -> Result { + match expect_token(tbox.read_token()?)? { + Token::OBR(_) => { + let result = a_proc(tbox)?; + match expect_token(tbox.read_token()?)? { + Token::CBR(_) => Ok(result), + token => Err(UnexpectedTokenError(token.clone(), String::from("P"))), + } + }, + Token::ID(_, val) => Ok(*val), + token => Err(ParserErrors::UnexpectedTokenError(token.clone(), String::from("P"))), + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn simple_formula() -> Result<()> { + let res = parse(lexer::Lexer::new("15+3"))?; + println!("res: {}", res); + assert_eq!(res, 18.0); + Ok(()) + } +}