1 using Mercury.Nucleus.Collections;
2 using Mercury.Nucleus.Trees;
3 using Mercury.Scanning;
5 using System.Collections.Generic;
8 namespace Mercury.Syntax
34 ParserResult Parse(IList<Token> tokens, IList<Rule> scanresult);
44 internal class ChartParserInternal
48 #region [ ReferenceComparer ]
50 private class ReferenceComparer : IEqualityComparer<object>
52 public new bool Equals(
object x,
object y)
53 {
return object.ReferenceEquals(x, y); }
55 public int GetHashCode(
object obj)
56 {
return obj.GetHashCode(); }
63 private UniqueListMultiDictionary<Edge, EdgeDerivation> edges = null;
64 private UniqueListMultiDictionary<Edge, Tree<Symbol>> allTrees = null;
66 private List<Edge> chart = null;
67 private Queue<Edge> agenda = null;
69 private List<Edge> activeEdges = null;
70 private List<Edge> passiveEdges = null;
71 private List<Tree<Symbol>> finalTrees = null;
72 private List<Tree<Symbol>> terminalTrees = null;
74 private List<Token> input = null;
75 private List<Symbol> data = null;
77 private HashSet<EdgeDerivation> explored = null;
78 private HashSet<EdgeDerivation> locked = null;
82 private void AddEdge(Edge edge, EdgeDerivation eder)
84 if (!edges.ContainsKey(edge)) agenda.Enqueue(edge);
85 edges.Add(edge, eder);
88 private bool IsFinalEdge(Edge edge)
92 && (edge.Right == input.Count)
93 && (edge.Rule.LHS.Equals(Grammar.Root));
96 #region [ Chart Parsing Methods ]
98 private void Initialize()
100 edges =
new UniqueListMultiDictionary<Edge, EdgeDerivation>();
101 chart =
new List<Edge>();
102 agenda =
new Queue<Edge>();
104 activeEdges =
new List<Edge>();
105 passiveEdges =
new List<Edge>();
107 for (
int rix = 0; rix < Grammar.EpsilonRules.Count; ++rix)
108 for (
int ix = 0; ix <= input.Count; ++ix)
109 AddEdge(
new Edge(Grammar.EpsilonRules[rix], 0, ix, ix), EdgeDerivation.Initial());
111 for (
int rix = 0; rix < Grammar.TerminalRules.Count; ++rix)
113 Rule rule = Grammar.TerminalRules[rix];
115 for (
int ix = 0; ix < input.Count; ++ix)
116 if (data[ix].Name == rule.RHS[0].Name)
117 AddEdge(
new Edge(rule, 0, ix, ix), EdgeDerivation.Initial());
121 private void CombineEdges(Edge source, Edge additional)
123 if ((source.Right == additional.Left) && (source.NextSymbol.Equals(additional.Rule.LHS)))
124 AddEdge(
new Edge(source.Rule, source.Dot + 1, source.Left, additional.Right),
125 EdgeDerivation.Fundamental(source, additional));
128 private void FundamentalA(Edge agendaEdge)
130 if (agendaEdge.IsActive)
return;
132 for (
int ix = 0; ix < activeEdges.Count; ++ix)
133 CombineEdges(activeEdges[ix], agendaEdge);
136 private void FundamentalB(Edge agendaEdge)
138 if (agendaEdge.IsPassive)
return;
140 for (
int ix = 0; ix < passiveEdges.Count; ++ix)
141 CombineEdges(agendaEdge, passiveEdges[ix]);
144 private void ScanInput(Edge agendaEdge)
146 if (agendaEdge.IsPassive
147 || (agendaEdge.NextSymbol.Type !=
SymbolType.Terminal)
148 || (data.Count <= agendaEdge.Right)
149 || !(data[agendaEdge.Right].Name == agendaEdge.NextSymbol.Name))
152 AddEdge(
new Edge(agendaEdge.Rule, agendaEdge.Dot + 1, agendaEdge.Left, agendaEdge.Right + 1),
153 EdgeDerivation.Scanning(agendaEdge));
158 if (agendaEdge.IsActive)
return;
160 foreach(Rule rule
in Grammar.RulesWithInitial(agendaEdge.Rule.LHS))
161 AddEdge(
new Edge(rule, 0, agendaEdge.Left, agendaEdge.Left), EdgeDerivation.Prediction());
166 #region [ Derivation Tree Generators ]
168 private void CreateTrees(Edge edge)
170 foreach(var derivation
in edges[edge])
172 if (explored.Contains(derivation) || !locked.Add(derivation))
continue;
174 var temp =
new List<Tree<Symbol>>();
175 switch(derivation.Derivation)
177 case DerivationType.Initial:
178 case DerivationType.Prediction:
179 Tree<Symbol> newTree = edge.Rule.IsEpsilon
180 ?
new Tree<Symbol>(edge.Rule.LHS,
new [] { terminalTrees[terminalTrees.Count - 1] })
181 :
new Tree<Symbol>(edge.Rule.LHS);
183 allTrees.Add(edge, newTree);
186 case DerivationType.Scanning:
187 CreateTrees(derivation.Source);
188 for (
int ix = 0; ix < allTrees.GetValuesCount(derivation.Source); ++ix)
189 allTrees.Add(edge,
new Tree<Symbol>(allTrees.GetValue(derivation.Source, ix),
190 new[] { terminalTrees[edge.Right - 1] }));
193 case DerivationType.Fundamental:
194 CreateTrees(derivation.Source);
195 CreateTrees(derivation.Additional);
196 for (
int src = 0; src < allTrees.GetValuesCount(derivation.Source); ++src)
197 for (
int add = 0; add < allTrees.GetValuesCount(derivation.Additional); ++add)
198 allTrees.Add(edge,
new Tree<Symbol>(allTrees.GetValue(derivation.Source, src),
199 new[] { allTrees.GetValue(derivation.Additional, add) }));
203 explored.Add(derivation);
204 locked.Remove(derivation);
208 private void CreateDerivationTrees()
210 allTrees =
new UniqueListMultiDictionary<Edge, Tree<Symbol>>();
211 terminalTrees =
new List<Tree<Symbol>>();
212 finalTrees =
new List<Tree<Symbol>>();
214 locked =
new HashSet<EdgeDerivation>(
new ReferenceComparer());
215 explored =
new HashSet<EdgeDerivation>(
new ReferenceComparer());
217 input.ForEach(x => terminalTrees.Add(
new Tree<Symbol>(
new Symbol(x))));
218 terminalTrees.Add(
new Tree<Symbol>(Grammar.Epsilon));
220 foreach (var edge
in chart.Where(e => IsFinalEdge(e)))
223 finalTrees.AddRange(allTrees[edge]);
238 public ChartParserInternal(ExtendedGrammar grammar)
240 if (grammar == null)
throw new ArgumentNullException(
"grammar");
248 public ExtendedGrammar Grammar {
get;
private set; }
259 public ParserResult Parse(IList<Token> tokens)
261 input =
new List<Token>(tokens);
262 data = input.Select(x =>
new Symbol(x)).ToList();
266 while (agenda.Count != 0)
268 Edge a_edge = agenda.Dequeue();
270 FundamentalA(a_edge);
271 FundamentalB(a_edge);
277 if (a_edge.IsActive) activeEdges.Add(a_edge);
278 else passiveEdges.Add(a_edge);
281 CreateDerivationTrees();
283 return new ParserResult()
285 Accepted = finalTrees.Count > 0,
302 private ExtendedGrammar extgrammar;
311 extgrammar = ExtendedGrammarBuilder.ExtendGrammar(grammar);
324 {
return (
new ChartParserInternal(extgrammar)).Parse(tokens); }
328 var gb =
new ExtendedGrammarBuilder(extgrammar);
330 for (
int ix = 0; ix < scanresult.Count; ++ix)
331 gb.AddRule(scanresult[ix]);
333 return (
new ChartParserInternal(gb.GetExtendedGrammar())).Parse(tokens);
Thread-safe wrapper for ChartParserInternal class.
Creates a derivation tree from the list of input tokens
SymbolType
Represents a type of symbol. Implemented as Flags since Symbol type inference is ambiguous.
ParserResult Parse(IList< Token > tokens)
Creates a trees (in Mercury.Syntax.ParserResult) from the tokens
ChartParser(Grammar grammar)
Chart Parser constructor
Represents the result returned by the parser.
Edge created by prediction
Represents a Context-Free Grammar. This is an immutable class, to create a grammar use Mercury...
ParserResult Parse(IList< Token > tokens, IList< Rule > scanresult)
Creates a trees (in Mercury.Syntax.ParserResult) from the tokens with the support of Mercury...