feat: partially implemented parser
This commit is contained in:
parent
8df8689ca4
commit
f05002fc50
50
grammar.md
50
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
|
||||
|
@ -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<T> = std::result::Result<T, errors::LexerErrors>;
|
||||
|
@ -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),
|
||||
|
@ -1,5 +1,6 @@
|
||||
pub mod lexer;
|
||||
pub mod errors;
|
||||
mod parser;
|
||||
|
||||
pub fn test() {
|
||||
println!("{}", "hi there");
|
||||
|
13
src/parser/errors.rs
Normal file
13
src/parser/errors.rs
Normal file
@ -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),
|
||||
}
|
111
src/parser/mod.rs
Normal file
111
src/parser/mod.rs
Normal file
@ -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<T> = result::Result<T, errors::ParserErrors>;
|
||||
|
||||
pub struct TokenBox {
|
||||
lexer: lexer::Lexer,
|
||||
cur_token: Option<Token>,
|
||||
regress: bool, // whether the last token should be outputted when reading a new token
|
||||
}
|
||||
|
||||
impl TokenBox {
|
||||
fn read_token(&mut self) -> Result<&Option<Token>> {
|
||||
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<Token>) -> Result<&Token> {
|
||||
match &maybe_token {
|
||||
&Some(token) => Ok(token),
|
||||
&None => Err(ParserErrors::MissingTokenError),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(mut lexer: lexer::Lexer) -> Result<f64> {
|
||||
let mut tbox = TokenBox { lexer, cur_token: None, regress: false };
|
||||
s_proc(&mut tbox)
|
||||
}
|
||||
|
||||
pub fn s_proc(tbox: &mut TokenBox) -> Result<f64> {
|
||||
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<f64> {
|
||||
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<f64> {
|
||||
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<f64> {
|
||||
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<f64> {
|
||||
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(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user