1 module gamma.parsgen.lalr1.ParserGrammarBuilder;
2 
3 import gamma.grammar.Alternative;
4 import gamma.grammar.Grammar;
5 import gamma.grammar.GrammarBuilder;
6 import gamma.grammar.Node;
7 import gamma.grammar.Nonterminal;
8 import gamma.grammar.Rule;
9 import gamma.grammar.Symbol;
10 import gamma.grammar.SymbolNode;
11 import gamma.grammar.Terminal;
12 import gamma.parsgen.lalr1.PredicateFilter;
13 
14 public Grammar extendedCfgFromHyperGrammar(Grammar hyperGrammar,
15     bool[Symbol] lexicalHyperNonterminals,
16     PredicateFilter predicateFilter)
17 {
18     auto grammarBuilder = GrammarBuilder();
19     Symbol originalStartSymbol = grammarBuilder.buildNonterminal(hyperGrammar.startSymbol.toString);
20     Nonterminal extStartSymbol = grammarBuilder.buildNonterminal("(start)");
21 
22     // --- Go ahead with rest of parser generation... ---
23     {
24         Terminal bottom = grammarBuilder.buildTerminal("(end)");
25         Node[] rhs = [new SymbolNode(originalStartSymbol, null), new SymbolNode(bottom, null)];
26 
27         grammarBuilder.add(
28             new Alternative(new SymbolNode(extStartSymbol, null), rhs, null));
29     }
30 
31     // Filter the pure CFG out of the hyperGrammar using
32     // - help from Analyser which nonterminal symbols are "lexical nonterminals"; and
33     // - help from PredicateFilter which RHS symbol occurrences are "predicates".
34     // Any Alternative/Rule the lhs of which is not a Nonterminal of the parser CFG is skipped.
35     // For the remaining RHS's, SymbolNode's are
36     // - not copied to the corresponding target CFG RHS if they represent a "predicate";
37     // - copied to the target CFG as a Terminal if they represent a "lexical nonterminal";
38     // - copied to the target CFG as a Nonterminal otherwise.
39     foreach (hyperRule; hyperGrammar.rules)
40     {
41         foreach (hyperAlt; hyperRule.alternatives)
42         {
43             if (hyperAlt.lhs.symbol in lexicalHyperNonterminals)
44                 break;
45             if (predicateFilter.isPredicate(hyperAlt.lhs))
46                 break;
47 
48             Nonterminal lhs = grammarBuilder.buildNonterminal(hyperAlt.lhs.symbol.toString);
49             Node[] rhs;
50 
51             foreach (rhsNode; hyperAlt.rhs)
52             {
53                 assert(cast(SymbolNode) rhsNode);
54 
55                 SymbolNode node = cast(SymbolNode) rhsNode;
56 
57                 if (predicateFilter.isPredicate(node))
58                     continue;
59 
60                 Symbol sym;
61 
62                 if (node.symbol in lexicalHyperNonterminals
63                     || cast(Terminal)(cast(SymbolNode) node).symbol)
64                     sym = grammarBuilder.buildTerminal(node.symbol.toString);
65                 else
66                     sym = grammarBuilder.buildNonterminal(node.symbol.toString);
67                 rhs ~= new SymbolNode(sym, node.position);
68             }
69             grammarBuilder
70                 .add(new Alternative(new SymbolNode(lhs, hyperAlt.lhs.position), rhs, hyperAlt.position));
71         }
72     }
73 
74     return grammarBuilder.getGrammar(extStartSymbol);
75 }