cleanup parse tree

This commit is contained in:
jusax23 2024-11-02 21:07:39 +01:00
parent f649edf9a5
commit 686e43448a
Signed by: jusax23
GPG key ID: 499E2AA870C1CD41
3 changed files with 111 additions and 30 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
/target /target
log*

View file

@ -436,6 +436,12 @@ impl<
// //
pub trait Skippable {
fn skippable(&self) -> bool {
false
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum NodeChild<N, S> { pub enum NodeChild<N, S> {
Child(ParseTree<N, S>), Child(ParseTree<N, S>),
@ -457,3 +463,41 @@ impl<N, S> ParseTree<N, S> {
} }
} }
} }
impl<N: Skippable + Debug, S: Debug> ParseTree<N, S> {
/// cleanup the parse tree
/// does not work on a subtree
pub fn clean(self) -> Self {
self.clean_internal()
.expect("Clean only works on the main tree.")
}
/// internal clean
/// main node must not have a rule.
fn clean_internal(self) -> Result<Self, Vec<NodeChild<N, S>>> {
let childs = self
.childs
.into_iter()
.flat_map(|elem| match elem {
NodeChild::Child(parse_tree) => match parse_tree.clean_internal() {
Ok(tree) => [NodeChild::Child(tree)].into(),
Err(content) => content,
},
NodeChild::Data(d) => [NodeChild::Data(d)].into(),
})
.collect();
if let Some((rule, _)) = &self.rule {
if rule.skippable() {
return Err(childs);
}
if childs.is_empty() {
return Err(childs);
}
}
Ok(Self {
rule: self.rule,
childs,
})
}
}

View file

@ -1,7 +1,7 @@
mod double_enum; mod double_enum;
mod ll_grammar; mod ll_grammar;
mod scanner; mod scanner;
use ll_grammar::{LLGrammar, Sentential}; use ll_grammar::{LLGrammar, Sentential, Skippable};
use regex::{Match, Regex}; use regex::{Match, Regex};
use scanner::Scanner; use scanner::Scanner;
use std::collections::HashMap; use std::collections::HashMap;
@ -29,6 +29,7 @@ double_enum!(
Dot, Dot,
Ident(String), Ident(String),
Int(i64), Int(i64),
Str(String),
Float(f64), Float(f64),
} }
); );
@ -98,6 +99,9 @@ scanner!(
r"^[0-9]+.[0-9]*" : |_, m: Match<'_>| { r"^[0-9]+.[0-9]*" : |_, m: Match<'_>| {
m.as_str().parse::<_>().ok().map(|f| Float(f)) m.as_str().parse::<_>().ok().map(|f| Float(f))
} }
r#"^"(([^"\\]|(\\[a-z\\"]))*)""# : |capture: regex::Captures<'_>, _| {
capture.get(1).map(|m| Str(m.as_str().to_string()))
}
r"^[0-9]+" : |_, m: Match<'_>| { r"^[0-9]+" : |_, m: Match<'_>| {
m.as_str().parse::<_>().ok().map(|i| Int(i)) m.as_str().parse::<_>().ok().map(|i| Int(i))
} }
@ -105,16 +109,29 @@ scanner!(
#[derive(Debug, PartialEq, Eq, Hash, Clone)] #[derive(Debug, PartialEq, Eq, Hash, Clone)]
enum NoneTerminals { enum NoneTerminals {
P, // Program, ; separated P, // Program, ; separated
L, // Line of code L, // Line of code
Li, // line extended for assignments Li, // line extended for assignments
IF, // if helper IF, // if helper
E, // Expression Sem, // optional semicolon
Ei, // Expression extended additive E, // Expression
T, // Term, only containing Factors Ei, // Expression extended additive
Ti, // Term extend multiplicative T, // math term
F, // Factor Ti, // meth term extended
FI, // Factor extended with complex types and operators S, // Summand, only containing Factors
Si, // Summand extend multiplicative
F, // Factor
Fi, // Factor extended with complex types and operators
}
impl Skippable for NoneTerminals {
fn skippable(&self) -> bool {
use NoneTerminals::*;
match self {
P | Li | Ei | Si | Ti | Fi | IF | Sem => true,
_ => false,
}
}
} }
impl<T> From<NoneTerminals> for Sentential<T, NoneTerminals> { impl<T> From<NoneTerminals> for Sentential<T, NoneTerminals> {
@ -134,38 +151,50 @@ fn grammer() -> LLGrammar<NoneTerminals, BareTokens> {
use NoneTerminals::*; use NoneTerminals::*;
ll_grammar![ ll_grammar![
start: P; start: P;
P -> L,Semicolon,P; P -> L,P;
P -> ; P -> ;
L -> While,E,LQBrace,P,RQBrace; L -> While,E,LQBrace,P,RQBrace,Sem;
L -> If,E,LQBrace,P,RQBrace,IF; L -> If,E,LQBrace,P,RQBrace,IF;
IF -> ; IF -> Sem;
IF -> Else,LQBrace,P,RQBrace; IF -> Else,LQBrace,P,RQBrace,Sem;
L -> Ident,FI,Li; Sem -> ;
Li -> Assign,E; Sem -> Semicolon;
Li -> ; L -> Ident,Fi,Li;
Li -> Assign,E,Semicolon;
Li -> Semicolon;
E -> T,Ei; E -> T,Ei;
Ei -> Eq,T,Ei; Ei -> Eq,T,Ei;
Ei -> Neq,T,Ei; Ei -> Neq,T,Ei;
Ei -> Add,T,Ei;
Ei -> Sub,T,Ei;
Ei -> ; Ei -> ;
T -> F,Ti;
Ti -> Mul,F,Ti; T -> S,Ti;
Ti -> Div,F,Ti; Ti -> Add,S,Ti;
Ti -> Sub,S,Ti;
Ti -> ; Ti -> ;
S -> F,Si;
Si -> Mul,F,Si;
Si -> Div,F,Si;
Si -> ;
F -> LBrace, E, RBrace; F -> LBrace, E, RBrace;
F -> Int; F -> Int;
F -> Float; F -> Float;
F -> Ident,FI; F -> Str;
FI -> ; F -> Ident,Fi;
FI -> LBrace,E,RBrace;
FI -> Dot, FI; Fi -> ;
FI -> LSBrace,E,RSBrace; Fi -> LBrace,E,RBrace;
Fi -> Dot, Fi;
Fi -> LSBrace,E,RSBrace;
] ]
} }
fn main() { fn main() {
let code = String::from("a = 4; while a != 5 { a = a+1; }; if a == 5 { a = 4; } else {a = 5;};"); let code = String::from(
"a = 4; while a != 5 { a = (a+1) * 4; }; if a == 5 { a = \"abs123\"; } else {a = 5;}",
);
let mut m = Scanner::<Tokens>::new(code).with_skipping(Tokens::WhiteSpace); let mut m = Scanner::<Tokens>::new(code).with_skipping(Tokens::WhiteSpace);
let mut grammar = grammer(); let mut grammar = grammer();
@ -176,5 +205,11 @@ fn main() {
println!("conflict: {conflict}"); println!("conflict: {conflict}");
println!("prase table: {:?}", grammar.parse_table); println!("prase table: {:?}", grammar.parse_table);
println!("parse\n\n"); println!("parse\n\n");
println!("parsed: {:?}", grammar.parser(&mut m.iter_mut()).parse()) println!(
"parsed: {:?}",
grammar
.parser(&mut m.iter_mut())
.parse()
.map(|tree| tree.clean())
)
} }