Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ParserDataBuilder_HelperClasses.cs
Go to the documentation of this file.
1 #region License
2 /* **********************************************************************************
3  * Copyright (c) Roman Ivantsov
4  * This source code is subject to terms and conditions of the MIT License
5  * for Irony. A copy of the license can be found in the License.txt file
6  * at the root of this distribution.
7  * By using this source code in any fashion, you are agreeing to be bound by the terms of the
8  * MIT License.
9  * You must not remove this notice from this software.
10  * **********************************************************************************/
11 #endregion
12 
13 using System;
14 using System.Collections.Generic;
15 using System.Text;
16 using System.Diagnostics;
17 
18 //Helper data classes for ParserDataBuilder
19 // Note about using LRItemSet vs LRItemList.
20 // It appears that in many places the LRItemList would be a better (and faster) choice than LRItemSet.
21 // Many of the sets are actually lists and don't require hashset's functionality.
22 // But surprisingly, using LRItemSet proved to have much better performance (twice faster for lookbacks/lookaheads computation), so LRItemSet
23 // is used everywhere.
24 namespace Irony.Parsing.Construction {
25 
26  internal class ParserStateData {
27  public readonly ParserState State;
28  public readonly LRItemSet AllItems = new LRItemSet();
29  public readonly LRItemSet ShiftItems = new LRItemSet();
30  public readonly LRItemSet ReduceItems = new LRItemSet();
31  public readonly LRItemSet InitialItems = new LRItemSet();
32  public readonly BnfTermSet ShiftTerms = new BnfTermSet();
33  public readonly TerminalSet ShiftTerminals = new TerminalSet();
34  public readonly TerminalSet Conflicts = new TerminalSet();
35  public readonly TerminalSet ResolvedConflicts = new TerminalSet();
36  public readonly bool IsInadequate;
37  public LR0ItemSet AllCores = new LR0ItemSet();
38 
39  //used for creating canonical states from core set
40  public ParserStateData(ParserState state, LR0ItemSet kernelCores) {
41  State = state;
42  foreach (var core in kernelCores)
43  AddItem(core);
44  IsInadequate = ReduceItems.Count > 1 || ReduceItems.Count == 1 && ShiftItems.Count > 0;
45  }
46 
47  public void AddItem(LR0Item core) {
48  //Check if a core had been already added. If yes, simply return
49  if(!AllCores.Add(core))return ;
50  //Create new item, add it to AllItems, InitialItems, ReduceItems or ShiftItems
51  var item = new LRItem(State, core);
52  AllItems.Add(item);
53  if (item.Core.IsFinal)
54  ReduceItems.Add(item);
55  else
56  ShiftItems.Add(item);
57  if (item.Core.IsInitial)
58  InitialItems.Add(item);
59  if (core.IsFinal) return;
60  //Add current term to ShiftTerms
61  if (!ShiftTerms.Add(core.Current)) return;
62  if (core.Current is Terminal)
63  ShiftTerminals.Add(core.Current as Terminal);
64  //If current term (core.Current) is a new non-terminal, expand it
65  var currNt = core.Current as NonTerminal;
66  if (currNt == null) return;
67  foreach(var prod in currNt.Productions)
68  AddItem(prod.LR0Items[0]);
69  }//method
70 
71  public TransitionTable Transitions {
72  get {
73  if(_transitions == null)
74  _transitions = new TransitionTable();
75  return _transitions;
76  }
77  } TransitionTable _transitions;
78 
79  //A set of states reachable through shifts over nullable non-terminals. Computed on demand
80  public ParserStateSet ReadStateSet {
81  get {
82  if(_readStateSet == null) {
83  _readStateSet = new ParserStateSet();
84  foreach(var shiftTerm in State.BuilderData.ShiftTerms)
85  if (shiftTerm.FlagIsSet(TermFlags.IsNullable)) {
86  var targetState = State.Actions[shiftTerm].NewState;
87  _readStateSet.Add(targetState);
88  _readStateSet.UnionWith(targetState.BuilderData.ReadStateSet); //we shouldn't get into loop here, the chain of reads is finite
89  }
90  }//if
91  return _readStateSet;
92  }
93  } ParserStateSet _readStateSet;
94 
95 
96  public TerminalSet GetShiftReduceConflicts() {
97  var result = new TerminalSet();
98  result.UnionWith(Conflicts);
99  result.IntersectWith(ShiftTerminals);
100  return result;
101  }
102  public TerminalSet GetReduceReduceConflicts() {
103  var result = new TerminalSet();
104  result.UnionWith(Conflicts);
105  result.ExceptWith(ShiftTerminals);
106  return result;
107  }
108 
109  }//class
110 
111  //An object representing inter-state transitions. Defines Includes, IncludedBy that are used for efficient lookahead computation
112  internal class Transition {
113  public readonly ParserState FromState;
114  public readonly ParserState ToState;
115  public readonly NonTerminal OverNonTerminal;
116  public readonly LRItemSet Items;
117  public readonly TransitionSet Includes = new TransitionSet();
118  public readonly TransitionSet IncludedBy = new TransitionSet();
119  int _hashCode;
120 
121  public Transition(ParserState fromState, NonTerminal overNonTerminal) {
122  FromState = fromState;
123  OverNonTerminal = overNonTerminal;
124  ToState = FromState.Actions[overNonTerminal].NewState;
125  _hashCode = unchecked(FromState.GetHashCode() - overNonTerminal.GetHashCode());
126  FromState.BuilderData.Transitions.Add(overNonTerminal, this);
127  Items = FromState.BuilderData.ShiftItems.SelectByCurrent(overNonTerminal);
128  foreach(var item in Items) {
129  item.Transition = this;
130  }
131 
132  }//constructor
133 
134  public void Include(Transition other) {
135  if (other == this) return;
136  if (!IncludeTransition(other)) return;
137  //include children
138  foreach(var child in other.Includes) {
139  IncludeTransition(child);
140  }
141  }
142  private bool IncludeTransition(Transition other) {
143  if (!Includes.Add(other)) return false;
144  other.IncludedBy.Add(this);
145  //propagate "up"
146  foreach(var incBy in IncludedBy)
147  incBy.IncludeTransition(other);
148  return true;
149  }
150 
151  public override string ToString() {
152  return FromState.Name + " -> (over " + OverNonTerminal.Name + ") -> " + ToState.Name;
153  }
154  public override int GetHashCode() {
155  return _hashCode;
156  }
157  }//class
158 
159  internal class TransitionSet : HashSet<Transition> { }
160  internal class TransitionList : List<Transition> { }
161  internal class TransitionTable : Dictionary<NonTerminal, Transition> { }
162 
163  internal class LRItem {
164  public readonly ParserState State;
165  public readonly LR0Item Core;
166  //these properties are used in lookahead computations
167  public LRItem ShiftedItem;
168  public Transition Transition;
169  int _hashCode;
170 
171  //Lookahead info for reduce items
172  public TransitionSet Lookbacks = new TransitionSet();
173  public TerminalSet Lookaheads = new TerminalSet();
174 
175  public LRItem(ParserState state, LR0Item core) {
176  State = state;
177  Core = core;
178  _hashCode = unchecked(state.GetHashCode() + core.GetHashCode());
179  }
180  public override string ToString() {
181  return Core.ToString();
182  }
183  public override int GetHashCode() {
184  return _hashCode;
185  }
186 
187  }//LRItem class
188 
189  internal class LRItemList : List<LRItem> {}
190 
191  internal class LRItemSet : HashSet<LRItem> {
192 
193  public LRItem FindByCore(LR0Item core) {
194  foreach (LRItem item in this)
195  if (item.Core == core) return item;
196  return null;
197  }
198  public LRItemSet SelectByCurrent(BnfTerm current) {
199  var result = new LRItemSet();
200  foreach (var item in this)
201  if (item.Core.Current == current)
202  result.Add(item);
203  return result;
204  }
205 
206  public LR0ItemSet GetShiftedCores() {
207  var result = new LR0ItemSet();
208  foreach (var item in this)
209  if (item.Core.ShiftedItem != null)
210  result.Add(item.Core.ShiftedItem);
211  return result;
212  }
213  public LRItemSet SelectByLookahead(Terminal lookahead) {
214  var result = new LRItemSet();
215  foreach (var item in this)
216  if (item.Lookaheads.Contains(lookahead))
217  result.Add(item);
218  return result;
219  }
220 
221  }//class
222 
223  public partial class LR0Item {
224  public readonly Production Production;
225  public readonly int Position;
226  public readonly BnfTerm Current;
227  public bool TailIsNullable;
228  public GrammarHintList Hints = new GrammarHintList();
229 
230  //automatically generated IDs - used for building keys for lists of kernel LR0Items
231  // which in turn are used to quickly lookup parser states in hash
232  internal readonly int ID;
233 
234  public LR0Item(int id, Production production, int position, GrammarHintList hints) {
235  ID = id;
236  Production = production;
237  Position = position;
238  Current = (Position < Production.RValues.Count) ? Production.RValues[Position] : null;
239  if (hints != null)
240  Hints.AddRange(hints);
241  _hashCode = ID.ToString().GetHashCode();
242  }//method
243 
244  public LR0Item ShiftedItem {
245  get {
246  if (Position >= Production.LR0Items.Count - 1)
247  return null;
248  else
249  return Production.LR0Items[Position + 1];
250  }
251  }
252  public bool IsKernel {
253  get { return Position > 0; }
254  }
255  public bool IsInitial {
256  get { return Position == 0; }
257  }
258  public bool IsFinal {
259  get { return Position == Production.RValues.Count; }
260  }
261  public override string ToString() {
262  return Production.ProductionToString(Production, Position);
263  }
264  public override int GetHashCode() {
265  return _hashCode;
266  } int _hashCode;
267 
268  }//LR0Item
269 
270  internal class LR0ItemList : List<LR0Item> { }
271  internal class LR0ItemSet : HashSet<LR0Item> { }
272 
273 
274 
275 }//namespace
Normal nonterminal
readonly BnfTermList RValues
Definition: ParserData.cs:138
LR0Item(int id, Production production, int position, GrammarHintList hints)