public CfgLL1ParseTable ToLLkParseTable() { // Here we populate the outer dictionary with one non-terminal for each key // we populate each inner dictionary with the result terminals and associated // rules of the predict tables except in the case where the predict table // contains null. In that case, we use the follows to get the terminals and // the rule associated with the null predict in order to compute the inner // dictionary. The conflict resolution tables are created as needed. Basically // they are nested parse tables for additional lookahead resolution. // The parser can use these to further resolve conflicts. var predict = FillPredict(); var follows = FillFollows(); var result = new CfgLL1ParseTable(); foreach (var nt in _EnumNonTerminals()) { var d = new Dictionary <string, CfgLL1ParseTableEntry>(); foreach (var f in predict[nt]) { if (null != f.Symbol) { CfgLL1ParseTableEntry or; if (d.TryGetValue(f.Symbol, out or)) { if (null != or.ConflictTable) { } else if (null != or.Rule) { var pt = new CfgLL1ParseTable(); var dd = new Dictionary <string, CfgRule>(); throw new CfgException( string.Format( "FIRST FIRST conflict between {0} and {1} on {2}", or.Rule, f.Rule, f.Symbol)); } } else { or.ConflictTable = null; or.Rule = f.Rule; d.Add(f.Symbol, or); } } else { var ff = follows[nt]; foreach (var fe in ff) { CfgLL1ParseTableEntry or; if (d.TryGetValue(fe, out or)) { // we can override conflict handling with the followsConflict // attribute. If specified (first/last/error - error is default) it will choose // the first or last rule respectively. var fc = AttributeSets.GetAttribute(nt, "followsConflict", "error") as string; if ("error" == fc) { throw new CfgException( string.Format( "FIRST FOLLOWS conflict between {0} and {1} on {2}", or.Rule, f.Rule, fe)); } else if ("last" == fc) { d[fe] = new CfgLL1ParseTableEntry(f.Rule); } } else { d.Add(fe, new CfgLL1ParseTableEntry(f.Rule)); } } } } result.Add(nt, d); } return(result); }
public CfgLL1ParseTable ToLL1ParseTable() { // Here we populate the outer dictionary with one non-terminal for each key // we populate each inner dictionary with the result terminals and associated // rules of the predict tables except in the case where the predict table // contains null. In that case, we use the follows to get the terminals and // the rule associated with the null predict in order to compute the inner // dictionary. The conflict resolution tables are always empty for LL(1) var predict = FillPredict(); var follows = FillFollows(); var exmsgs = new List <CfgMessage>(); var result = new CfgLL1ParseTable(); foreach (var nt in _EnumNonTerminals()) { var d = new Dictionary <string, CfgLL1ParseTableEntry>(); foreach (var f in predict[nt]) { if (null != f.Symbol) { CfgLL1ParseTableEntry re; re.ConflictTable = null; re.Rule = f.Rule; CfgLL1ParseTableEntry or; if (d.TryGetValue(f.Symbol, out or)) { exmsgs.Add(new CfgMessage(CfgErrorLevel.Error, 1, string.Format( "FIRST FIRST conflict between {0} and {1} on {2}", or.Rule, f.Rule, f.Symbol))); } else { d.Add(f.Symbol, re); } } else { var ff = follows[nt]; foreach (var fe in ff) { CfgLL1ParseTableEntry or; if (d.TryGetValue(fe, out or)) { // we can override conflict handling with the followsConflict // attribute. If specified (first/last/error - error is default) it will choose // the first or last rule respectively. var fc = AttributeSets.GetAttribute(nt, "followsConflict", "error") as string; if ("error" == fc) { exmsgs.Add(new CfgMessage(CfgErrorLevel.Error, 2, string.Format( "FIRST FOLLOWS conflict between {0} and {1} on {2}", or.Rule, f.Rule, fe))); } else if ("last" == fc) { d[fe] = new CfgLL1ParseTableEntry(f.Rule); } } else { d.Add(fe, new CfgLL1ParseTableEntry(f.Rule)); } } } } result.Add(nt, d); } CfgException.ThrowIfErrors(exmsgs); return(result); }