feat: partially implemented parser

This commit is contained in:
Yandrik 2021-11-29 22:47:39 +01:00
parent 8df8689ca4
commit f05002fc50
6 changed files with 149 additions and 36 deletions

View File

@ -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

View File

@ -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>;

View File

@ -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),

View File

@ -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
View 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
View 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(())
}
}