diff --git a/src/bin/book.rs b/src/bin/book.rs index 95a704f..23f33b0 100644 --- a/src/bin/book.rs +++ b/src/bin/book.rs @@ -1,4 +1,3 @@ -use ll_grammar::Skippable; use rcompiler::prelude::*; use regex::Match; use std::collections::HashMap; diff --git a/src/cfg/ll_grammar.rs b/src/cfg/ll_grammar.rs index eded17a..058f14a 100644 --- a/src/cfg/ll_grammar.rs +++ b/src/cfg/ll_grammar.rs @@ -47,7 +47,7 @@ impl Grammar &self, none_terminal: &N, terminal: &Option, - ) -> Option<(usize, &Vec>)> { + ) -> Option<(usize, &Vec>)> { assert!( self.ll_parse_table.is_some(), "Please call gen_parse_table before this!" @@ -102,7 +102,8 @@ impl< // content of the vec: // - first element: all of them combined represent the complete stack, of the parser. // - secount element: rule has to able to derive the code defined, by its inner childs and the unparsed code from the accompanying first element. - let mut stack: Vec<(Vec>, ParseTree)> = vec![( + type StackElem = (Vec>, ParseTree); + let mut stack: Vec> = vec![( vec![Sentential::NoneTerminal(self.grammar.start.clone())], ParseTree::new(None), )]; @@ -142,10 +143,10 @@ impl< // take next none terminal and apply rule from parse table. Some(Sentential::NoneTerminal(none_term)) => { // load rule - let Some((id, new_rule)) = self - .grammar - .ll_parse_table(&none_term, &next.as_ref().map(|f| f.clone().into())) - else { + let Some((id, new_rule)) = self.grammar.ll_parse_table( + &none_term, + &next.as_ref().map(|f| f.clone().into()), + ) else { // no rule return Err(format!( "Unexpected token: {}", @@ -155,8 +156,7 @@ impl< }; // reverse rule: because, uses vec as stack, but reversed - let new_rule_rev = - new_rule.iter().rev().map(|f| f.clone()).collect::>(); + let new_rule_rev = new_rule.iter().rev().cloned().collect::>(); // memorize current state/rule for later stack.push(state.unwrap()); // process next rule @@ -177,7 +177,7 @@ impl< return Ok(state.unwrap().1); } // still code left, but not excepted - return Err(format!("Expected end of file.")); + return Err("Expected end of file.".to_string()); }; last.1.childs.push(NodeChild::Child(state.unwrap().1)); } @@ -185,7 +185,7 @@ impl< } // should not be possible, because every other path pushes to the stack back or returns None => { - return Err(format!("Err: EOS")); + return Err("Err: EOS".to_string()); } } } diff --git a/src/cfg/lr0.rs b/src/cfg/lr0.rs index 84d1633..cca8361 100644 --- a/src/cfg/lr0.rs +++ b/src/cfg/lr0.rs @@ -6,8 +6,13 @@ use std::{ use super::{Grammar, Sentential}; +pub type RL0Automaton = + HashMap>, Vec<(Sentential, Weak>)>>; + +pub type RL0Rule = (N, Vec>, usize); + #[derive(Debug, Eq, PartialEq)] -pub struct LR0State(HashSet<(N, Vec>, usize)>); +pub struct LR0State(HashSet>); impl LR0State { pub fn next_kernel(&self, read: &Sentential) -> Self { @@ -31,7 +36,7 @@ impl LR0State { } impl Hash for LR0State { fn hash(&self, state: &mut H) { - let mut a: Vec<&(N, Vec>, usize)> = self.0.iter().collect(); + let mut a: Vec<&RL0Rule> = self.0.iter().collect(); a.sort(); for s in a.iter() { s.hash(state); @@ -69,8 +74,7 @@ where } pub fn gen_lr0_automaton(&mut self) { - let mut out: HashMap>, Vec<(Sentential, Weak>)>> = - HashMap::new(); + let mut out: RL0Automaton = HashMap::new(); let mut start_state = LR0State(HashSet::new()); if let Some(rule) = self.rules.get(&self.start) { for to in rule { diff --git a/src/cfg/mod.rs b/src/cfg/mod.rs index 71071a3..20c7586 100644 --- a/src/cfg/mod.rs +++ b/src/cfg/mod.rs @@ -1,10 +1,9 @@ use std::{ collections::{HashMap, HashSet}, hash::Hash, - rc::{Rc, Weak}, }; -use lr0::LR0State; +use lr0::RL0Automaton; pub mod ll_grammar; pub mod lr0; @@ -83,8 +82,7 @@ pub struct Grammar>, Vec<(Sentential, Weak>)>>>, + pub lr0_automaton: Option>, } impl Grammar { @@ -93,7 +91,7 @@ impl Grammar Sentential::Terminal(_) => false, Sentential::NoneTerminal(nt) => self .rules - .get(&nt) + .get(nt) .map(|f| f.iter().any(|v| v.is_empty())) .unwrap_or(false), } @@ -189,7 +187,7 @@ impl Grammar } pub fn gen_follow(&mut self) { - if self.first == None { + if self.first.is_none() { self.gen_first(); } let mut follow: HashMap>> = HashMap::new(); @@ -204,47 +202,25 @@ impl Grammar // and if A -> aBb and e in First(b) add Follow(A) to Follow(B) if to.len() >= 2 { for i in 0..(to.len() - 1) { - let slice = to[i + 1..].iter().map(|f| f.clone()).collect::>(); - match to.get(i) { - Some(Sentential::NoneTerminal(b)) => { - let mut set = self.first(&slice); - if set.contains(&None) { - if let Some(set) = follow.get(from).cloned() { - follow - .entry(b.clone()) - .and_modify(|e| { - for val in set.iter() { - change |= e.insert(val.clone()); - } - }) - .or_insert_with(|| { - change = true; - set - }); - } + let slice = to[i + 1..].to_vec(); + if let Some(Sentential::NoneTerminal(b)) = to.get(i) { + let mut set = self.first(&slice); + if set.contains(&None) { + if let Some(set) = follow.get(from).cloned() { + follow + .entry(b.clone()) + .and_modify(|e| { + for val in set.iter() { + change |= e.insert(val.clone()); + } + }) + .or_insert_with(|| { + change = true; + set + }); } - set.remove(&None); - follow - .entry(b.clone()) - .and_modify(|e| { - for val in set.iter() { - change |= e.insert(val.clone()); - } - }) - .or_insert_with(|| { - change = true; - set - }); } - _ => (), - } - } - } - // b - // and if A -> aB add Follow(A) to Follow(B) - match to.last() { - Some(Sentential::NoneTerminal(b)) => { - if let Some(set) = follow.get(from).cloned() { + set.remove(&None); follow .entry(b.clone()) .and_modify(|e| { @@ -258,7 +234,23 @@ impl Grammar }); } } - _ => (), + } + // b + // and if A -> aB add Follow(A) to Follow(B) + if let Some(Sentential::NoneTerminal(b)) = to.last() { + if let Some(set) = follow.get(from).cloned() { + follow + .entry(b.clone()) + .and_modify(|e| { + for val in set.iter() { + change |= e.insert(val.clone()); + } + }) + .or_insert_with(|| { + change = true; + set + }); + } } } } @@ -275,7 +267,7 @@ impl Grammar self.follow .as_ref() .unwrap() - .get(&none_termianl) + .get(none_termianl) .cloned() .unwrap_or(HashSet::new()) } diff --git a/src/main.rs b/src/main.rs index 8119a72..6c8bc6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -94,13 +94,13 @@ token_scanner!( Some(Dot) } r"^[0-9]+.[0-9]*" : |_, m: Match<'_>| { - m.as_str().parse::<_>().ok().map(|f| Float(f)) + m.as_str().parse::<_>().ok().map(Float) } 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)) + m.as_str().parse::<_>().ok().map(Int) } ); @@ -124,10 +124,7 @@ enum NoneTerminals { impl Skippable for NoneTerminals { fn skippable(&self) -> bool { use NoneTerminals::*; - match self { - P | Li | Ei | Si | Ti | Fi | IF | Sem => true, - _ => false, - } + matches!(self, P | Li | Ei | Si | Ti | Fi | IF | Sem) } } diff --git a/src/scanner.rs b/src/scanner.rs index f1976bd..2c21d41 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -6,7 +6,7 @@ macro_rules! token_scanner { $regex:tt : $code:expr )*) => { impl $crate::scanner::MatchNext<$name> for $name { - fn match_next(code: &String) -> Option<(Self, usize)> { + fn match_next(code: &str) -> Option<(Self, usize)> { use $name::*; use regex::Regex; $( @@ -25,7 +25,7 @@ macro_rules! token_scanner { } pub trait MatchNext { - fn match_next(code: &String) -> Option<(T, usize)>; + fn match_next(code: &str) -> Option<(T, usize)>; } pub struct Scanner + PartialEq> {