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
|
S -> A
|
||||||
A -> A + A | A - A | M
|
A -> M + A | M - A | M
|
||||||
M -> M * M | M / M | G
|
M -> G * M | G / M | G
|
||||||
G -> ( A ) | P ^ G | ID
|
G -> P ^ G | P
|
||||||
P -> ( A ) | ID
|
P -> ( A ) | ID
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -82,16 +82,14 @@ s1("[S->.A]") --> s2(["[S->A.]"])
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph LR;
|
graph LR;
|
||||||
a1("[A->.A+A] | [A->.A-A] | [A->.M]")
|
a1("[A->.M+A] | [A->.M-A] | [A->.M]")
|
||||||
a2(["[A->M.]"])
|
a3(["[A->M.+A] | [A->M.-A] | [A->M.]"])
|
||||||
a3("[A->A.+A] | [A->A.-A]")
|
a4("[A->M+.A]")
|
||||||
a4("[A->A+.A]")
|
a5(["[A->M+A.]"])
|
||||||
a5(["[A->A+A.]"])
|
a6("[A->M-.A]")
|
||||||
a6("[A->A-.A]")
|
a7(["[A->M-A.]"])
|
||||||
a7(["[A->A-A.]"])
|
|
||||||
|
|
||||||
a1 -- M --> a2
|
a1 -- M --> a3
|
||||||
a1 -- A --> a3
|
|
||||||
a3 -- + --> a4
|
a3 -- + --> a4
|
||||||
a4 -- A --> a5
|
a4 -- A --> a5
|
||||||
a3 -- - --> a6
|
a3 -- - --> a6
|
||||||
@ -100,16 +98,14 @@ a6 -- A --> a7
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph LR;
|
graph LR;
|
||||||
m1("[M->.M*M] | [M->.M/M] | [M->.G]")
|
m1("[M->.G*M] | [M->.G/M] | [M->.G]")
|
||||||
m2(["[M->G.]"])
|
m3(["[M->G.*M] | [M->G./M] | [M->G.]"])
|
||||||
m3("[M->M.*M] | [M->M./M]")
|
m4("[M->G*.M]")
|
||||||
m4("[M->M*.M]")
|
m5(["[M->G*M.]"])
|
||||||
m5(["[M->M*M.]"])
|
m6("[M->G/.M]")
|
||||||
m6("[M->M/.M]")
|
m7(["[M->G/M.]"])
|
||||||
m7(["[M->M/M.]"])
|
|
||||||
|
|
||||||
m1 -- G --> m2
|
m1 -- G --> m3
|
||||||
m1 -- M --> m3
|
|
||||||
m3 -- * --> m4
|
m3 -- * --> m4
|
||||||
m4 -- M --> m5
|
m4 -- M --> m5
|
||||||
m3 -- / --> m6
|
m3 -- / --> m6
|
||||||
@ -118,22 +114,14 @@ m6 -- M --> m7
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph LR;
|
graph LR;
|
||||||
g1("[G->.(A)] | [G->.P^G] | [G->.ID]")
|
g1("[G->.P^G] | [G->.P]")
|
||||||
g2("[G->(.A)]")
|
g5(["[G->P.^G] | [G->P.]"])
|
||||||
g3("[G->(A.)]")
|
|
||||||
g4(["[G->(A).]"])
|
|
||||||
g5("[G->P.^G]")
|
|
||||||
g6("[G->P^.G]")
|
g6("[G->P^.G]")
|
||||||
g7(["[G->P^G.]"])
|
g7(["[G->P^G.]"])
|
||||||
g8(["[G->ID.]"])
|
|
||||||
|
|
||||||
g1 -- "(" --> g2
|
|
||||||
g2 -- A --> g3
|
|
||||||
g3 -- ")" --> g4
|
|
||||||
g1 -- P --> g5
|
g1 -- P --> g5
|
||||||
g5 -- ^ --> g6
|
g5 -- ^ --> g6
|
||||||
g6 -- G --> g7
|
g6 -- G --> g7
|
||||||
g1 -- ID --> g8
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
@ -10,8 +10,8 @@ use crate::lexer::errors::LexerErrors::EmptyTextSequenceError;
|
|||||||
use crate::lexer::fsm::{FSM, get_token};
|
use crate::lexer::fsm::{FSM, get_token};
|
||||||
use crate::lexer::tokens::{OpType, TokenMeta};
|
use crate::lexer::tokens::{OpType, TokenMeta};
|
||||||
|
|
||||||
mod errors;
|
pub mod errors;
|
||||||
mod tokens;
|
pub mod tokens;
|
||||||
mod fsm;
|
mod fsm;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, errors::LexerErrors>;
|
pub type Result<T> = std::result::Result<T, errors::LexerErrors>;
|
||||||
|
@ -4,12 +4,12 @@
|
|||||||
/// * File that the token was parsed in
|
/// * File that the token was parsed in
|
||||||
/// * Line 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
|
/// * Position of the *first character making up the token* in said line
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TokenMeta {
|
pub struct TokenMeta {
|
||||||
pub pos: usize,
|
pub pos: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum OpType {
|
pub enum OpType {
|
||||||
MUL,
|
MUL,
|
||||||
DIV,
|
DIV,
|
||||||
@ -45,7 +45,7 @@ pub enum BrType {
|
|||||||
/// 1. `OBR`: An opening bracket (`(`).
|
/// 1. `OBR`: An opening bracket (`(`).
|
||||||
/// 1. `CBR`: A closing bracket (`)`).
|
/// 1. `CBR`: A closing bracket (`)`).
|
||||||
/// 1. `OP`: An operation. Containing an [Operation Type](OpType).
|
/// 1. `OP`: An operation. Containing an [Operation Type](OpType).
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
ID (TokenMeta, f64),
|
ID (TokenMeta, f64),
|
||||||
OBR (TokenMeta),
|
OBR (TokenMeta),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
mod parser;
|
||||||
|
|
||||||
pub fn test() {
|
pub fn test() {
|
||||||
println!("{}", "hi there");
|
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