compiler_course_helper/grammar/
parse.rs1use crate::Grammar;
2
3impl Grammar {
4 pub fn parse(grammar: &str) -> Result<Self, String> {
5 let mut g = Self::new();
6
7 let mut raw_productions: Vec<(usize, &str)> = Vec::new();
8
9 let mut previous_left: Option<usize> = None;
10 for (i, line) in grammar.lines().enumerate() {
11 if line.chars().all(|c| c.is_whitespace()) {
12 continue;
13 }
14 let parts: Vec<&str> = line.split("->").collect();
15 if parts.len() > 2 {
16 return Err(format!("Line {}: too many \"->\"", i + 1));
17 }
18 let (left, rights): (usize, &str) = if parts.len() == 2 {
19 let left_str = parts[0].trim();
20 if left_str.split_whitespace().count() != 1 {
21 return Err(format!("Line {}: left side contains whitespace", i + 1));
22 } else if left_str.is_empty() {
23 return Err(format!("Line {}: empty left side", i + 1));
24 } else {
25 (
26 if let Some(idx) = g.get_symbol_index(left_str) {
27 idx
28 } else {
29 g.add_non_terminal(left_str)
30 },
31 parts[1].trim(),
32 )
33 }
34 } else {
35 if let Some(idx) = previous_left {
36 (idx, parts[0].trim()[1..].trim())
37 } else {
38 return Err(format!("Line {}: cannot find left side", i + 1));
39 }
40 };
41
42 previous_left = Some(left);
43
44 raw_productions.push((left, rights));
45 }
46
47 for (left, rights) in raw_productions {
48 for right in rights.split("|") {
49 let symbols = right
50 .split_whitespace()
51 .map(|s| {
52 if let Some(idx) = g.get_symbol_index(s) {
53 idx
54 } else {
55 g.add_terminal(s.to_string())
56 }
57 })
58 .collect();
59 g.add_production(left, symbols);
60 }
61 }
62
63 let start_symbol: Option<usize> = if let Some(nt) = g.non_terminal_iter().next() {
64 Some(g.symbol_table[&nt.name])
65 } else {
66 None
67 };
68 g.start_symbol = start_symbol;
69
70 Ok(g)
71 }
72}