/// <summary> /// 返回指定状态的唯一可行归约。 /// </summary> /// <param name="actions">要寻找唯一归约的状态动作。</param> /// <returns>如果指定状态中只有一个归约是可行的,则返回唯一的可行归约; /// 否则返回错误动作。</returns> private static ParseAction FindUniqueReduction(ParseAction[] actions) { ParseAction action = ParseAction.Error; for (int i = 1; i < actions.Length; i++) { switch (actions[i].ActionType) { case ParseActionType.Accept: case ParseActionType.Shift: return(ParseAction.Error); case ParseActionType.Reduce: if (action.ActionType == ParseActionType.Error) { action = actions[i]; } else if (action.Index != actions[i].Index) { return(ParseAction.Error); } break; } } return(action); }
/// <summary> /// 分析当前的符号。 /// </summary> /// <param name="token">要分析的符号。</param> public override void Parse(Token <T> token) { if (token.IsEndOfFile) { if (stateStack.Count == 1) { return; } } while (true) { int state = stateStack.Peek(); ParseAction action = GetAction(state, token.Id); switch (action.ActionType) { case ParseActionType.Shift: Shift(token, action.Index); goto ReduceByUnique; case ParseActionType.Reduce: Reduce(action.Index); break; case ParseActionType.Accept: stateStack.Pop(); result = tokenStack.Pop(); return; case ParseActionType.Error: ReportError(state, token); // ErrorRecovery(state, token.Id); return; } } ReduceByUnique: // 尝试根据唯一归约进行归约。 while (true) { int state = stateStack.Peek(); ParseAction action = rule.States[state].Actions[Constants.UniqueIdx]; switch (action.ActionType) { case ParseActionType.Reduce: Reduce(action.Index); break; case ParseActionType.Error: return; } } }
/// <summary> /// 分析并尝试解决动作中的冲突。 /// </summary> /// <param name="grammar">语法分析器使用的语法。</param> /// <param name="index">当前状态的索引。</param> /// <param name="actionList">动作列表。</param> /// <returns>解决冲突后的动作列表。</returns> private ParseAction[] ResolveActions(Grammar <T> grammar, int index, List <Tuple <LRItem <T>, ParseAction> >[] actionList) { ParseAction[] actions = new ParseAction[actionCount]; for (int i = 1; i < actionCount; i++) { List <Tuple <LRItem <T>, ParseAction> > list = actionList[i]; int cnt = list.Count; if (cnt == 0) { continue; } if (cnt == 1) { actions[i] = list[0].Item2; continue; } // 当前的终结符。 T sym = (T)Enum.ToObject(typeof(T), i - Constants.TokenOffset); List <ParserConflictItem> conflictItems = new List <ParserConflictItem>(); conflictItems.Add(new ParserConflictItem(list[0].Item1.ToString(), list[0].Item2)); ParseAction action = list[0].Item2; int actionIdx = 0; for (int j = 1; j < list.Count; j++) { if (action.ActionType == ParseActionType.Reduce) { if (list[j].Item2.ActionType == ParseActionType.Shift) { int assocCmp = grammar.CompareAssociativity(productions[action.Index], sym); // 冲突时采用移入。 if (assocCmp == 0) { action = list[j].Item2; conflictItems.Add(new ParserConflictItem(list[j].Item1.ToString(), list[j].Item2)); } else if (assocCmp == -1) { action = list[j].Item2; conflictItems.RemoveAt(actionIdx); actionIdx = conflictItems.Count; conflictItems.Add(new ParserConflictItem(list[j].Item1.ToString(), list[j].Item2)); } } else { int assocCmp = grammar.CompareAssociativity(productions[action.Index], list[j].Item1.Production); if (assocCmp == -1) { action = list[j].Item2; conflictItems.RemoveAt(actionIdx); actionIdx = conflictItems.Count; conflictItems.Add(new ParserConflictItem(list[j].Item1.ToString(), list[j].Item2)); } else if (assocCmp == 0) { // 冲突时采用标号较小的规则。 if (list[j].Item2.Index < action.Index) { action = list[j].Item2; } conflictItems.Add(new ParserConflictItem(list[j].Item1.ToString(), list[j].Item2)); } } } else if (list[j].Item2.ActionType == ParseActionType.Reduce) { int assocCmp = grammar.CompareAssociativity(productions[action.Index], sym); // 冲突时采用移入。 if (assocCmp == 1) { action = list[j].Item2; conflictItems.RemoveAt(actionIdx); actionIdx = conflictItems.Count; conflictItems.Add(new ParserConflictItem(list[j].Item1.ToString(), list[j].Item2)); } else if (assocCmp == 0) { conflictItems.Add(new ParserConflictItem(list[j].Item1.ToString(), list[j].Item2)); } } } if (conflictItems.Count > 1) { conflicts.Add(new ParserConflict(index, sym.ToString(), actionIdx, conflictItems.ToArray())); } actions[i] = action; } actions[Constants.UniqueIdx] = FindUniqueReduction(actions); return(actions); }
/// <summary> /// 构造 LALR 语法分析表。 /// </summary> /// <param name="grammar">语法分析器使用的语法。</param> /// <param name="itemsets">LR 项集族。</param> private void BuildLRTable(Grammar <T> grammar, List <LRItemset <T> > itemsets) { int stateCnt = itemsets.Count; this.states = new StateData[stateCnt]; int gotoCnt = grammar.NonTerminals.Count; for (int i = 0; i < stateCnt; i++) { List <Tuple <LRItem <T>, ParseAction> >[] actions = new List <Tuple <LRItem <T>, ParseAction> > [actionCount]; for (int j = 0; j < actionCount; j++) { actions[j] = new List <Tuple <LRItem <T>, ParseAction> >(); } LRItemset <T> itemset = itemsets[i]; foreach (LRItem <T> item in itemset.Items) { if (item.Index < item.Production.Body.Count) { // 移入动作。 Symbol <T> sym = item.Production.Body[item.Index]; Terminal <T> tSym = sym as Terminal <T>; if (tSym != null) { int targetIndex = itemset.Goto[tSym]; actions[tSym.Index + Constants.TokenOffset].Add( new Tuple <LRItem <T>, ParseAction>(item, ParseAction.Shift(targetIndex))); } } else if (item.Production.Head != grammar.AugmentedStart) { // 归约动作。 int targetIndex = item.Production.Index; foreach (Terminal <T> sym in item.Forwards) { actions[sym.Index + Constants.TokenOffset].Add( new Tuple <LRItem <T>, ParseAction>(item, ParseAction.Reduce(targetIndex))); } } else if (item.Forwards.Contains(EndOfFile) && actions[Constants.EOFIdx].Count == 0) { // 接受动作。 actions[Constants.EOFIdx].Add(new Tuple <LRItem <T>, ParseAction>(item, ParseAction.Accept)); } } // 生成 GOTO 转换。 int[] gotos = new int[gotoCnt]; foreach (NonTerminal <T> sym in grammar.NonTerminals) { int state; if (!itemset.Goto.TryGetValue(sym, out state)) { state = Constants.DeadState; } gotos[sym.Index] = state; } string[] originRules = new string[itemset.Items.Count]; for (int j = 0; j < originRules.Length; j++) { originRules[j] = itemset.Items[j].ToString(); } this.states[i] = new StateData(ResolveActions(grammar, i, actions), gotos, originRules); } }
/// <summary> /// 使用指定的产生式和动作初始化 <see cref="ParserConflictItem"/> 结构的新实例。 /// </summary> /// <param name="production">产生冲突的产生式。</param> /// <param name="action">冲突的动作。</param> public ParserConflictItem(string production, ParseAction action) { this.production = production; this.action = action; }