compiler_course_helper/grammar/
grammar.rs1use std::collections::{HashMap, HashSet};
2
3#[derive(Debug, Clone)]
4pub struct NonTerminal {
5 pub index: usize,
6 pub name: String,
7 pub first: HashSet<usize>,
8 pub follow: HashSet<usize>,
9 pub nullable: bool,
10 pub productions: Vec<Vec<usize>>,
11}
12
13impl NonTerminal {
14 pub fn new(index: usize, name: String) -> Self {
15 Self {
16 index,
17 name,
18 first: HashSet::new(),
19 follow: HashSet::new(),
20 nullable: false,
21 productions: Vec::new(),
22 }
23 }
24}
25
26#[derive(Debug, Clone)]
27pub enum Symbol {
28 NonTerminal(NonTerminal),
29 Terminal(String),
30}
31
32impl Symbol {
33 pub fn non_terminal(&self) -> Option<&NonTerminal> {
34 match self {
35 Symbol::NonTerminal(e) => Some(e),
36 Symbol::Terminal(_) => None,
37 }
38 }
39
40 pub fn mut_non_terminal(&mut self) -> Option<&mut NonTerminal> {
41 match self {
42 Symbol::NonTerminal(e) => Some(e),
43 Symbol::Terminal(_) => None,
44 }
45 }
46}
47
48#[derive(Debug, Clone)]
49pub struct Grammar {
50 valid_nullable_first_follow: bool,
51 pub symbols: Vec<Symbol>,
52 pub symbol_table: HashMap<String, usize>,
53 pub start_symbol: Option<usize>,
54}
55
56impl Grammar {
57 pub fn new() -> Self {
58 let mut g = Self {
59 valid_nullable_first_follow: false,
60 symbols: Vec::new(),
61 symbol_table: HashMap::new(),
62 start_symbol: None,
63 };
64
65 let e_idx = g.add_non_terminal(super::EPSILON);
66 g.symbols[e_idx].mut_non_terminal().unwrap().nullable = true;
67 g.symbol_table.insert("ε".to_string(), e_idx);
68
69 g.add_terminal(super::END_MARK.to_string());
70
71 g
72 }
73
74 pub fn get_symbol_by_name(&self, name: &str) -> &Symbol {
75 &self.symbols[self.symbol_table[name]]
76 }
77
78 pub fn terminal_iter(&self) -> impl Iterator<Item = &String> {
79 self.symbols.iter().filter_map(|s| {
80 if let Symbol::Terminal(name) = s {
81 Some(name)
82 } else {
83 None
84 }
85 })
86 }
87
88 pub fn non_terminal_iter(&self) -> impl Iterator<Item = &NonTerminal> {
89 self.symbols.iter().filter_map(|s| s.non_terminal()).skip(1)
90 }
91
92 pub fn non_terminal_iter_mut(&mut self) -> impl Iterator<Item = &mut NonTerminal> {
93 self.symbols
94 .iter_mut()
95 .filter_map(|s| s.mut_non_terminal())
96 .skip(1)
97 }
98
99 pub fn get_symbol_index(&self, name: &str) -> Option<usize> {
100 self.symbol_table.get(name).cloned()
101 }
102
103 pub fn add_non_terminal(&mut self, name: &str) -> usize {
104 let idx = self.symbols.len();
105 self.symbols
106 .push(Symbol::NonTerminal(NonTerminal::new(idx, name.to_string())));
107 self.symbol_table.insert(name.to_string(), idx);
108 idx
109 }
110
111 pub fn add_terminal(&mut self, name: String) -> usize {
112 let idx = self.symbols.len();
113 self.symbols.push(Symbol::Terminal(name.clone()));
114 self.symbol_table.insert(name, idx);
115 idx
116 }
117
118 pub fn add_production(&mut self, left: usize, right: Vec<usize>) {
119 self.symbols[left]
120 .mut_non_terminal()
121 .unwrap()
122 .productions
123 .push(right);
124 }
125
126 pub fn get_symbol_name(&self, index: usize) -> &str {
127 match &self.symbols[index] {
128 Symbol::NonTerminal(e) => e.name.as_str(),
129 Symbol::Terminal(e) => e.as_str(),
130 }
131 }
132
133 pub fn get_symbol_prime_name(&self, mut name: String) -> String {
134 while self.symbol_table.contains_key(&name) {
135 name.push('\'');
136 }
137 name
138 }
139
140 pub fn invalidate_nullable_first_follow(&mut self) {
141 self.valid_nullable_first_follow = false;
142 self.reset_nullable_first_follow();
143 }
144
145 pub fn is_nullable_first_follow_valid(&self) -> bool {
146 self.valid_nullable_first_follow
147 }
148
149 pub fn validate_nullable_first_follow(&mut self) {
150 self.valid_nullable_first_follow = true;
151 }
152
153 pub fn production_to_vec_str(&self, production: &Vec<usize>) -> Vec<&str> {
154 production
155 .iter()
156 .map(|idx| self.get_symbol_name(*idx))
157 .collect()
158 }
159}