cleanup parse tree
This commit is contained in:
parent
f649edf9a5
commit
686e43448a
3 changed files with 111 additions and 30 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
|||
/target
|
||||
|
||||
log*
|
|
@ -436,6 +436,12 @@ impl<
|
|||
|
||||
//
|
||||
|
||||
pub trait Skippable {
|
||||
fn skippable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum NodeChild<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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
95
src/main.rs
95
src/main.rs
|
@ -1,7 +1,7 @@
|
|||
mod double_enum;
|
||||
mod ll_grammar;
|
||||
mod scanner;
|
||||
use ll_grammar::{LLGrammar, Sentential};
|
||||
use ll_grammar::{LLGrammar, Sentential, Skippable};
|
||||
use regex::{Match, Regex};
|
||||
use scanner::Scanner;
|
||||
use std::collections::HashMap;
|
||||
|
@ -29,6 +29,7 @@ double_enum!(
|
|||
Dot,
|
||||
Ident(String),
|
||||
Int(i64),
|
||||
Str(String),
|
||||
Float(f64),
|
||||
}
|
||||
);
|
||||
|
@ -98,6 +99,9 @@ scanner!(
|
|||
r"^[0-9]+.[0-9]*" : |_, m: Match<'_>| {
|
||||
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<'_>| {
|
||||
m.as_str().parse::<_>().ok().map(|i| Int(i))
|
||||
}
|
||||
|
@ -105,16 +109,29 @@ scanner!(
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
enum NoneTerminals {
|
||||
P, // Program, ; separated
|
||||
L, // Line of code
|
||||
Li, // line extended for assignments
|
||||
IF, // if helper
|
||||
E, // Expression
|
||||
Ei, // Expression extended additive
|
||||
T, // Term, only containing Factors
|
||||
Ti, // Term extend multiplicative
|
||||
F, // Factor
|
||||
FI, // Factor extended with complex types and operators
|
||||
P, // Program, ; separated
|
||||
L, // Line of code
|
||||
Li, // line extended for assignments
|
||||
IF, // if helper
|
||||
Sem, // optional semicolon
|
||||
E, // Expression
|
||||
Ei, // Expression extended additive
|
||||
T, // math term
|
||||
Ti, // meth term extended
|
||||
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> {
|
||||
|
@ -134,38 +151,50 @@ fn grammer() -> LLGrammar<NoneTerminals, BareTokens> {
|
|||
use NoneTerminals::*;
|
||||
ll_grammar![
|
||||
start: P;
|
||||
P -> L,Semicolon,P;
|
||||
P -> L,P;
|
||||
P -> ;
|
||||
L -> While,E,LQBrace,P,RQBrace;
|
||||
L -> While,E,LQBrace,P,RQBrace,Sem;
|
||||
L -> If,E,LQBrace,P,RQBrace,IF;
|
||||
IF -> ;
|
||||
IF -> Else,LQBrace,P,RQBrace;
|
||||
L -> Ident,FI,Li;
|
||||
Li -> Assign,E;
|
||||
Li -> ;
|
||||
IF -> Sem;
|
||||
IF -> Else,LQBrace,P,RQBrace,Sem;
|
||||
Sem -> ;
|
||||
Sem -> Semicolon;
|
||||
L -> Ident,Fi,Li;
|
||||
Li -> Assign,E,Semicolon;
|
||||
Li -> Semicolon;
|
||||
|
||||
E -> T,Ei;
|
||||
Ei -> Eq,T,Ei;
|
||||
Ei -> Neq,T,Ei;
|
||||
Ei -> Add,T,Ei;
|
||||
Ei -> Sub,T,Ei;
|
||||
Ei -> ;
|
||||
T -> F,Ti;
|
||||
Ti -> Mul,F,Ti;
|
||||
Ti -> Div,F,Ti;
|
||||
|
||||
T -> S,Ti;
|
||||
Ti -> Add,S,Ti;
|
||||
Ti -> Sub,S,Ti;
|
||||
Ti -> ;
|
||||
|
||||
S -> F,Si;
|
||||
Si -> Mul,F,Si;
|
||||
Si -> Div,F,Si;
|
||||
Si -> ;
|
||||
|
||||
F -> LBrace, E, RBrace;
|
||||
F -> Int;
|
||||
F -> Float;
|
||||
F -> Ident,FI;
|
||||
FI -> ;
|
||||
FI -> LBrace,E,RBrace;
|
||||
FI -> Dot, FI;
|
||||
FI -> LSBrace,E,RSBrace;
|
||||
F -> Str;
|
||||
F -> Ident,Fi;
|
||||
|
||||
Fi -> ;
|
||||
Fi -> LBrace,E,RBrace;
|
||||
Fi -> Dot, Fi;
|
||||
Fi -> LSBrace,E,RSBrace;
|
||||
]
|
||||
}
|
||||
|
||||
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 grammar = grammer();
|
||||
|
@ -176,5 +205,11 @@ fn main() {
|
|||
println!("conflict: {conflict}");
|
||||
println!("prase table: {:?}", grammar.parse_table);
|
||||
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())
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue