static ICollection <LRItem> _FillLRMove(this CfgDocument cfg, IEnumerable <LRItem> itemSet, object input, IProgress <CfgLalr1Progress> progress, ICollection <LRItem> result = null) { if (null == result) { result = new HashSet <LRItem>(); } int i = 0; foreach (var item in itemSet) { if (null != progress) { progress.Report(new CfgLalr1Progress(CfgLalr1Status.ComputingMove, i)); } var next = item.RightIndex < item.Rule.Right.Count ? item.Rule.Right[item.RightIndex] : null; if (item.RightIndex < item.Rule.Right.Count) { if (Equals(next, input)) { var lri = new LRItem(item.Rule, item.RightIndex + 1); result.Add(lri); } } ++i; } _FillLRClosureInPlace(cfg, progress, result); return(result); }
public override void Apply(LanguageData language, LRItem owner) { //Create custom action and put it into state.Actions table var state = owner.State; var action = new CustomParserAction(language, state, _executeMethod); _previewMethod?.Invoke(action); if (!state.BuilderData.IsInadequate) { // adequate state, with a single possible action which is DefaultAction state.DefaultAction = action; } else if (owner.Core.Current != null) { //shift action state.Actions[owner.Core.Current] = action; } else { foreach (var lkh in owner.Lookaheads) { state.Actions[lkh] = action; } } //We consider all conflicts handled by the action state.BuilderData.Conflicts.Clear(); }
public override void Apply(LanguageData language, LRItem owner) { var state = owner.State; var allConflicts = state.BuilderData.Conflicts; if (allConflicts.Count == 0) { return; } //Find all conflicts that can be resolved by operator precedence // SL does not support Find extension, so we do it with explicit loop var operConflicts = allConflicts.Where(c => c.Flags.IsSet(TermFlags.IsOperator)).ToList(); foreach (var conflict in operConflicts) { var newState = state.BuilderData.GetNextState(conflict); var reduceItems = state.BuilderData.ReduceItems.SelectByLookahead(conflict).ToList(); if (newState == null || reduceItems.Count != 1) { // This cannot be fixed by precedence continue; } state.Actions[conflict] = new PrecedenceBasedParserAction(conflict, newState, reduceItems[0].Core.Production); allConflicts.Remove(conflict); } }
public override void Apply(LanguageData language, LRItem owner) { var state = owner.State; var conflicts = state.BuilderData.Conflicts; if (conflicts.Count == 0) return; switch (ActionType) { case PreferredActionType.Shift: var currTerm = owner.Core.Current as Terminal; if (currTerm == null || !conflicts.Contains(currTerm)) return; //nothing to do //Current term for shift item (hint owner) is a conflict - resolve it with shift action var newState = owner.ShiftedItem.State; var shiftAction = new ShiftParserAction(owner); state.Actions[currTerm] = shiftAction; conflicts.Remove(currTerm); return; case PreferredActionType.Reduce: if (!owner.Core.IsFinal) return; //we take care of reduce items only here //we have a reduce item with "Reduce" hint. Check if any of lookaheads are in conflict ReduceParserAction reduceAction = null; foreach (var lkhead in owner.Lookaheads) if (conflicts.Contains(lkhead)) { if (reduceAction == null) reduceAction = new ReduceParserAction(owner.Core.Production); state.Actions[lkhead] = reduceAction; conflicts.Remove(lkhead); } return; }//switch }//method
public override void Apply(LanguageData language, LRItem owner) { //Check that owner is not final - we can imply precedence only in shift context var curr = owner.Core.Current; if (curr == null) return; //mark the state, to make sure we do stuff in Term_Shifting event handler only in appropriate states owner.State.CustomFlags |= ImpliedPrecedenceCustomFlag; curr.Shifting += Term_Shifting; }
public ReduceAction(ParseTable <T> table, LRItem <T> reduceItem) : base(table) { if (reduceItem != null) { ReduceItem = reduceItem; } else { throw new ArgumentNullException("reduceItem", "Must be non-null"); } }
public AcceptAction(ParseTable <T> table, LRItem <T> acceptItem) : base(table) { if (acceptItem != null) { AcceptItem = acceptItem; } else { throw new ArgumentNullException("acceptItem", "Must be non-null"); } }
public override void Apply(LanguageData language, LRItem owner) { //Check that owner is not final - we can imply precedence only in shift context var curr = owner.Core.Current; if (curr == null) { return; } //mark the state, to make sure we do stuff in Term_Shifting event handler only in appropriate states owner.State.CustomFlags |= ParserStateFlags.ImpliedPrecedence; curr.Shifting += Term_Shifting; }
public override void Apply(LanguageData language, LRItem owner) { var state = owner.State; var conflicts = state.BuilderData.Conflicts; if (conflicts.Count == 0) { return; } switch (_actionType) { case PreferredActionType.Shift: var currTerm = owner.Core.Current as Terminal; if (currTerm == null || !conflicts.Contains(currTerm)) { //nothing to do return; } //Current term for shift item (hint owner) is a conflict - resolve it with shift action var shiftAction = new ShiftParserAction(owner); state.Actions[currTerm] = shiftAction; conflicts.Remove(currTerm); return; case PreferredActionType.Reduce: if (!owner.Core.IsFinal) { //we take care of reduce items only here return; } //we have a reduce item with "Reduce" hint. Check if any of lookaheads are in conflict ReduceParserAction reduceAction = null; foreach (var lkhead in owner.Lookaheads) { if (conflicts.Contains(lkhead)) { if (reduceAction == null) { reduceAction = new ReduceParserAction(owner.Core.Production); } state.Actions[lkhead] = reduceAction; conflicts.Remove(lkhead); } } return; default: throw new ArgumentOutOfRangeException(); } }
//Creates closure items with "spontaneously generated" lookaheads private bool AddClosureItems(ParserState state) { bool result = false; //note that we change collection while we iterate thru it, so we have to use "for i" loop for (int i = 0; i < state.Items.Count; i++) { LRItem item = state.Items[i]; BnfTerm currTerm = item.Core.Current; if (currTerm == null || !(currTerm is NonTerminal)) { continue; } //1. Add normal closure items NtData currInfo = (NtData)currTerm.ParserData; foreach (Production prod in currInfo.Productions) { LR0Item core = prod.LR0Items[0]; //item at zero index is the one that starts with dot LRItem newItem = TryFindItem(state, core); if (newItem == null) { newItem = new LRItem(state, core); state.Items.Add(newItem); result = true; } #region Comments on lookaheads processing // The general idea of generating ("spontaneously") the lookaheads is the following: // Let's the original item be in the form // [A -> alpha . B beta , lset] // where <B> is a non-terminal and <lset> is a set of lookaheads, // <beta> is some string (B's tail in our terminology) // Then the closure item on non-teminal B is an item // [B -> x, firsts(beta + lset)] // (the lookahead set is expression after the comma). // To generate lookaheads on a closure item, we simply take "firsts" // from the tail <beta> of the NonTerminal <B>. // Normally if tail <beta> is nullable we would add ("propagate") // the <lset> lookaheads from <A> to <B>. // We dont' do it right here - we simply add a propagation link. // We propagate all lookaheads later in a separate process. #endregion newItem.NewLookaheads.AddRange(item.Core.TailFirsts); if (item.Core.TailIsNullable && !item.PropagateTargets.Contains(newItem)) { item.PropagateTargets.Add(newItem); } } //foreach prod } //for i (LRItem) return(result); }
public override void Apply(LanguageData language, LRItem owner) { //Create custom action and put it into state.Actions table var state = owner.State; var action = new CustomParserAction(language, state, _executeMethod); if (_previewMethod != null) _previewMethod(action); if (!state.BuilderData.IsInadequate) // adequate state, with a single possible action which is DefaultAction state.DefaultAction = action; else if (owner.Core.Current != null) //shift action state.Actions[owner.Core.Current] = action; else foreach (var lkh in owner.Lookaheads) state.Actions[lkh] = action; //We consider all conflicts handled by the action state.BuilderData.Conflicts.Clear(); } //method
public override void Apply(LanguageData language, LRItem owner) { var state = owner.State; var allConflicts = state.BuilderData.Conflicts; if (allConflicts.Count == 0) return; //Find all conflicts that can be resolved by operator precedence // SL does not support Find extension, so we do it with explicit loop var operConflicts = new List<Terminal>(); foreach(var c in allConflicts) if (c.Flags.IsSet(TermFlags.IsOperator)) operConflicts.Add(c); foreach (var conflict in operConflicts) { var newState = state.BuilderData.GetNextState(conflict); var reduceItem = state.BuilderData.ReduceItems.SelectByLookahead(conflict).First(); //should be only one state.Actions[conflict] = new PrecedenceBasedParserAction(conflict, newState, reduceItem.Core.Production); allConflicts.Remove(conflict); }//foreach conflict }
public override void Apply(LanguageData language, LRItem owner) { var state = owner.State; if (!state.BuilderData.IsInadequate) return; //the state is adequate, we don't need to do anything var conflicts = state.BuilderData.Conflicts; // Note that we remove lookaheads from the state conflicts set at the end of this method - to let parser builder know // that this conflict is taken care of. // On the other hand we may call this method multiple times for different LRItems if we have multiple hints in the same state. // Since we remove lookahead from conflicts on the first call, on the consequitive calls it will not be a conflict - // but we still need to add a new conditional entry to a conditional parser action for this lookahead. // Thus we process the lookahead anyway, even if it is not a conflict. // if (conflicts.Count == 0) return; -- this is a wrong thing to do switch (_actionType) { case PreferredActionType.Reduce: if (!owner.Core.IsFinal) return; //it is reduce action; find lookaheads in conflict var lkhs = owner.Lookaheads; if (lkhs.Count == 0) return; //if no conflicts then nothing to do var reduceAction = new ReduceParserAction(owner.Core.Production); var reduceCondEntry = new ConditionalParserAction.ConditionalEntry(CheckCondition, reduceAction, _description); foreach (var lkh in lkhs) { AddConditionalEntry(state, lkh, reduceCondEntry); if (conflicts.Contains(lkh)) conflicts.Remove(lkh); } break; case PreferredActionType.Shift: var curr = owner.Core.Current as Terminal; if (curr == null) return; //it is either reduce item, or curr is a NonTerminal - we cannot shift it var shiftAction = new ShiftParserAction(owner); var shiftCondEntry = new ConditionalParserAction.ConditionalEntry(CheckCondition, shiftAction, _description); AddConditionalEntry(state, curr, shiftCondEntry); if (conflicts.Contains(curr)) conflicts.Remove(curr); break; } } //method
private void CreateParserStates() { Data.States.Clear(); _stateHash = new ParserStateTable(); CreateInitialAndFinalStates(); string augmRootKey = Data.AugmentedRoot.Key; // Iterate through states (while new ones are created) and create shift transitions and new states for (int index = 0; index < Data.States.Count; index++) { ParserState state = Data.States[index]; AddClosureItems(state); //Get keys of all possible shifts ShiftTable shiftTable = GetStateShifts(state); //Each key in shifts dict is an input element // Value is LR0ItemList of shifted LR0Items for this input element. foreach (string input in shiftTable.Keys) { LR0ItemList shiftedCoreItems = shiftTable[input]; ParserState newState = FindOrCreateState(shiftedCoreItems); ActionRecord newAction = new ActionRecord(input, ParserActionType.Shift, newState, null); state.Actions[input] = newAction; //link original LRItems in original state to derived LRItems in newState foreach (LR0Item coreItem in shiftedCoreItems) { LRItem fromItem = FindItem(state, coreItem.Production, coreItem.Position - 1); LRItem toItem = FindItem(newState, coreItem.Production, coreItem.Position); if (!fromItem.PropagateTargets.Contains(toItem)) { fromItem.PropagateTargets.Add(toItem); } //copy hints from core items into the newAction newAction.ShiftItems.Add(fromItem); } //foreach coreItem } //foreach input } //for index Data.FinalState = Data.InitialState.Actions[augmRootKey].NewState; } //method
static void _FillLRClosureInPlace(CfgDocument cfg, IProgress <CfgLalr1Progress> progress, ICollection <LRItem> result) { var done = false; while (!done) { done = true; var l = result.ToArray(); for (var i = 0; i < l.Length; i++) { if (null != progress) { progress.Report(new CfgLalr1Progress(CfgLalr1Status.ComputingClosure, i)); } var item = l[i]; var next = item.RightIndex < item.Rule.Right.Count ? item.Rule.Right[item.RightIndex] : null; if (item.RightIndex < item.Rule.Right.Count) { if (cfg.IsNonTerminal(next)) { for (int jc = cfg.Rules.Count, j = 0; j < jc; ++j) { var r = cfg.Rules[j]; if (r.Left == next) { var lri = new LRItem(r, 0); if (!result.Contains(lri)) { done = false; result.Add(lri); } } } } } } } }
} //method private void ResolveConflictByHints(ParserState state, Terminal conflict) { var stateData = state.BuilderData; //reduce hints var reduceItems = stateData.ReduceItems.SelectByLookahead(conflict); foreach (var reduceItem in reduceItems) { if (reduceItem.Core.Hints.Find(h => h.HintType == HintType.ResolveToReduce) != null) { state.Actions[conflict] = new ParserAction(ParserActionType.Reduce, null, reduceItem.Core.Production); state.BuilderData.ResolvedConflicts.Add(conflict); return; } } //shift hints var shiftItems = stateData.ShiftItems.SelectByCurrent(conflict); foreach (var shiftItem in shiftItems) { if (shiftItem.Core.Hints.Find(h => h.HintType == HintType.ResolveToShift) != null) { //shift action is already there state.BuilderData.ResolvedConflicts.Add(conflict); return; } } //code hints // first prepare data for conflict action: reduceProduction (for possible reduce) and newState (for possible shift) var reduceProduction = reduceItems.First().Core.Production; //take first of reduce productions ParserState newState = (state.Actions.ContainsKey(conflict) ? state.Actions[conflict].NewState : null); // Get all items that might contain hints; var allItems = new LRItemList(); allItems.AddRange(state.BuilderData.ShiftItems.SelectByCurrent(conflict)); allItems.AddRange(state.BuilderData.ReduceItems.SelectByLookahead(conflict)); // Scan all items and try to find hint with resolution type Code foreach (var item in allItems) { if (item.Core.Hints.Find(h => h.HintType == HintType.ResolveInCode) != null) { state.Actions[conflict] = new ParserAction(ParserActionType.Code, newState, reduceProduction); state.BuilderData.ResolvedConflicts.Add(conflict); return; } } //custom hints // find custom grammar hints and build custom conflict resolver var customHints = new List <CustomGrammarHint>(); var hintItems = new Dictionary <CustomGrammarHint, LRItem>(); LRItem defaultItem = null; // the first item with no hints foreach (var item in allItems) { var hints = item.Core.Hints.OfType <CustomGrammarHint>(); foreach (var hint in hints) { customHints.Add(hint); hintItems[hint] = item; } if (defaultItem == null && !hints.Any()) { defaultItem = item; } } // if there are custom hints, build conflict resolver if (customHints.Count > 0) { state.Actions[conflict] = new ParserAction(newState, reduceProduction, args => { // examine all custom hints and select the first production that matched foreach (var customHint in customHints) { if (customHint.Match(args)) { var item = hintItems[customHint]; // If the ReduceProduction was clear, then use the default production following the hints if (args.ReduceProduction == null) { args.ReduceProduction = item.Core.Production; } return; } } // no hints matched, select default LRItem if (defaultItem != null) { args.ReduceProduction = defaultItem.Core.Production; args.Result = args.NewShiftState != null ? ParserActionType.Shift : ParserActionType.Reduce; return; } // prefer Reduce if Shift operation is not available args.Result = args.NewShiftState != null ? ParserActionType.Shift : ParserActionType.Reduce; // TODO: figure out what to do next }); state.BuilderData.ResolvedConflicts.Add(conflict); return; } }
public ShiftParserAction(LRItem item) : this(item.Core.Current, item.ShiftedItem.State) { }
/// <summary> Gives a chance to a custom code in hint to interfere in parser automaton construction.</summary> /// <param name="language">The LanguageData instance.</param> /// <param name="owner">The <see cref="LRItem"/> that "owns" the hint. </param> /// <remarks> /// The most common purpose of this method (it's overrides) is to resolve the conflicts /// by adding specific actions into State.Actions dictionary. /// The owner parameter represents the position in the grammar expression where the hint /// is found. The parser state is available through owner.State property. /// </remarks> public virtual void Apply(LanguageData language, LRItem owner) { // owner.State -- the parser state // owner.State.BuilderData.Conflicts -- as set of conflict terminals // owner.State.Actions -- a dictionary of actions in the current state. }
public override void Apply(LanguageData language, LRItem owner) { var state = owner.State; if (!state.BuilderData.IsInadequate) { return; //the state is adequate, we don't need to do anything } var conflicts = state.BuilderData.Conflicts; // Note that we remove lookaheads from the state conflicts set at the end of this method - to let parser builder know // that this conflict is taken care of. // On the other hand we may call this method multiple times for different LRItems if we have multiple hints in the same state. // Since we remove lookahead from conflicts on the first call, on the consequitive calls it will not be a conflict - // but we still need to add a new conditional entry to a conditional parser action for this lookahead. // Thus we process the lookahead anyway, even if it is not a conflict. // if (conflicts.Count == 0) return; -- this is a wrong thing to do switch (_actionType) { case PreferredActionType.Reduce: if (!owner.Core.IsFinal) { return; } //it is reduce action; find lookaheads in conflict var lkhs = owner.Lookaheads; if (lkhs.Count == 0) { return; //if no conflicts then nothing to do } var reduceAction = new ReduceParserAction(owner.Core.Production); var reduceCondEntry = new ConditionalParserAction.ConditionalEntry(CheckCondition, reduceAction, _description); foreach (var lkh in lkhs) { AddConditionalEntry(state, lkh, reduceCondEntry); if (conflicts.Contains(lkh)) { conflicts.Remove(lkh); } } break; case PreferredActionType.Shift: var curr = owner.Core.Current as Terminal; if (curr == null) { return; //it is either reduce item, or curr is a NonTerminal - we cannot shift it } var shiftAction = new ShiftParserAction(owner); var shiftCondEntry = new ConditionalParserAction.ConditionalEntry(CheckCondition, shiftAction, _description); AddConditionalEntry(state, curr, shiftCondEntry); if (conflicts.Contains(curr)) { conflicts.Remove(curr); } break; default: throw new ArgumentOutOfRangeException(); } }
protected override LRItemSetCollection ComputeItemSetCollection() { var(collection, gotoSymbol) = ComputeLR0ItemSetKernelsCollectionAndGotoLookup(); // Determine propagation of lookaheads, and initialze lookaheads based on spontaneous generation // (page 270-275, dragon book 2nd ed.) collection.StartState.Single().Lookaheads.Add(Eof); var rulePropagations = new Dictionary <(int state, LRItem item), HashSet <(int state, LRItem item)> >(); // For all states foreach (var itemset in collection) { var gotosForState = gotoSymbol[itemset.Index]; // For every kernel item foreach (var kernelitem in itemset) { var itemKey = (state : itemset.Index, item : kernelitem); // Create an item set with a dummy lookahead. // This dummy item set is based on the current state (current item set). var dummyLookahead = Unknown.AsSingletonEnumerable(); var dummyItem = new LRItem(kernelitem.Rule, kernelitem.Marker, dummyLookahead); var dummyItemSet = new LRItemSet(dummyItem.AsSingletonEnumerable()); var j = LR1Closure(dummyItemSet); // For every symbol/state in the goto list foreach (var gotokvp in gotosForState) { // What would be the next state? var gotoItemSet = collection[gotokvp.Value]; var gotoItemLookup = gotoItemSet.ToDictionary(g => g, g => g); // Find the items in the dummy set with the marker before this symbol. foreach (var b in j.Where(bb => bb.Marker < bb.Length && bb.Rule.Symbols[bb.Marker].Equals(gotokvp.Key))) { // Get the item corresponding to the goto state with the marker advanced over the current symbol. var gotoItem = gotoItemLookup[new LRItem(b.Rule, b.Marker + 1)]; // Note if lookaheads are propagated to the next item if (b.Lookaheads.Any(l => l.CompareTo(Unknown) == 0)) { if (!rulePropagations.ContainsKey(itemKey)) { rulePropagations[itemKey] = new HashSet <(int, LRItem)>(); } rulePropagations[itemKey].Add((gotoItemSet.Index, gotoItem)); } gotoItem.Lookaheads.UnionWith( b.Lookaheads.Where(l => l.CompareTo(Unknown) != 0) ); } } } } bool changed; do { changed = false; foreach (var state in collection) { foreach (var item in state) { var itemKey = (state.Index, item); if (!rulePropagations.TryGetValue(itemKey, out var propagated)) { continue; } foreach (var key in propagated) { if (key.item.Lookaheads.TryUnionWith(item.Lookaheads)) { changed = true; } } } } } while (changed); // Close all the kernels for (var i = 0; i < collection.Count; i++) { collection[i] = LR1Closure(collection[i]); collection[i].Index = i; } return(collection); }