1 module gamma.input.earley.Parser; 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.Symbol; 9 import gamma.grammar.SymbolNode; 10 import gamma.grammar.Terminal; 11 import gamma.grammar.affixes.Composite; 12 import gamma.grammar.affixes.Term; 13 import gamma.grammar.affixes.Variable; 14 import gamma.input.earley.AffixForm; 15 import gamma.input.earley.Item; 16 import gamma.input.earley.ItemSet; 17 import std.range; 18 19 /** 20 * If the item is of the form [ <i>B</i> → β •, <i>k</i> ] then for each item [ <i>A</i> → 21 * α • <i>B</i> γ, <i>j</i> ] in the Earley set denoted by <i>k</i> an item [ <i>A</i> → 22 * α <i>B</i> • γ, <i>j</i> ] is added to the current Earley set. 23 * 24 * If the item is of the form [ <i>A</i> → α • <i>B</i> γ, <i>j</i> ] then for each alternative 25 * <i>B</i> → β an item [ <i>B</i> → • β, <i>k</i> ] is added to the current Earley set, 26 * which is denoted by <i>k</i>. 27 * 28 * If the item is of the form [ <i>A</i> → α • <i>X</i> γ, <i>i</i> ] where <i>X</i> equals 29 * the current symbol then an item [ <i>A</i> → α <i>X</i> • γ, <i>i</i> ] is added to the next 30 * Earley set. 31 */ 32 public class Parser 33 { 34 private Grammar grammar; 35 36 private Variable[] variablesIterator; 37 38 // TODO: eliminate attributes 'startSymbol' and 'endSymbol' 39 40 private Nonterminal startSymbol; 41 42 private Terminal endSymbol; 43 44 /** 45 * @param grammar 46 */ 47 public this(Grammar grammar) 48 { 49 this.grammar = grammar; 50 51 GrammarBuilder grammarBuilder; 52 53 this.startSymbol = grammarBuilder.buildNonterminal("S'"); 54 this.endSymbol = grammarBuilder.buildTerminal("$"); 55 } 56 57 /** 58 * @param startSymbol 59 * @param affixForm 60 * @return 61 */ 62 public Term parse(Nonterminal startSymbol, AffixForm affixForm) 63 { 64 Node[] rhs; 65 66 rhs ~= new SymbolNode(startSymbol, null); 67 rhs ~= new SymbolNode(this.endSymbol, null); 68 69 Alternative alternative = new Alternative(new SymbolNode(this.startSymbol, null), rhs, null); 70 SymbolNode[] symbolNodes = affixForm.symbolNodes; 71 72 symbolNodes ~= new SymbolNode(this.endSymbol, null); 73 74 ItemSet itemSet = ItemSet.initialItemSet(alternative, grammar); 75 76 foreach (symbolNode; symbolNodes) 77 { 78 Symbol symbol = symbolNode.symbol; 79 80 itemSet = ItemSet.nextItemSet(itemSet, symbol, grammar); 81 82 // TODO: report syntax errors 83 } 84 if (affixForm.variables !is null) 85 this.variablesIterator = affixForm.variables; 86 if (itemSet.items.empty) 87 return null; 88 else 89 return term(itemSet.items[0].prevItem); 90 } 91 92 public Term term(Item item) 93 in (cast(Nonterminal) item.prevItem.symbol) 94 { 95 import std.array : array; 96 97 if (item.subItem is null) 98 { 99 Variable variable = this.variablesIterator.back; 100 101 assert(cast(Nonterminal) item.prevItem.symbol == variable.nonterminal); 102 103 return variable; 104 } 105 else 106 { 107 Term[] terms; 108 109 for (item = item.subItem; item.prevItem !is null; item = item.prevItem) 110 if (cast(Nonterminal) item.prevItem.symbol) 111 terms ~= term(item); 112 terms = terms.retro.array; 113 return new Composite(item.alternative, terms); 114 } 115 } 116 }