public static CfgLL1ParseTable ToLL1ParseTable(this CfgDocument cfg, IProgress <CfgLL1Progress> progress = null) { CfgLL1ParseTable result = null; var msgs = TryToLL1ParseTable(cfg, progress, out result); CfgException.ThrowIfErrors(msgs); return(result); }
/// <summary> /// Constructs a new instance of the parser /// </summary> /// <param name="parseTable">The parse table to use</param> /// <param name="tokenizer">The tokenizer to use </param> /// <param name="startSymbol">The start symbol</param> public LL1DebugParser(CfgDocument cfg, IEnumerable <Token> tokenizer) { _cfg = cfg; _PopulateAttrs(); _parseTable = cfg.ToLL1ParseTable(); _stack = new Stack <string>(); _errorToken.Symbol = null; Restart(tokenizer); }
public static IList <CfgMessage> TryToLL1ParseTable(this CfgDocument cfg, IProgress <CfgLL1Progress> progress, out CfgLL1ParseTable parseTable) { // 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) if (null != progress) { progress.Report(new CfgLL1Progress(CfgLL1Status.ComputingPredicts, 0)); } var predict = cfg.FillPredict(); if (null != progress) { progress.Report(new CfgLL1Progress(CfgLL1Status.ComputingFollows, 0)); } var follows = cfg.FillFollows(); var result = new List <CfgMessage>(); parseTable = new CfgLL1ParseTable(); var j = 0; foreach (var nt in cfg.EnumNonTerminals()) { var d = new Dictionary <string, CfgLL1ParseTableEntry>(); foreach (var f in predict[nt]) { if (null != f.Symbol) { CfgLL1ParseTableEntry re; re.Rule = f.Rule; CfgLL1ParseTableEntry or; if (d.TryGetValue(f.Symbol, out or)) { result.Add(new CfgMessage(CfgErrorLevel.Error, 1, string.Format( "first first conflict between {0} and {1} on {2}", or.Rule, f.Rule, f.Symbol), f.Rule.Line, f.Rule.Column, f.Rule.Position)); } else { d.Add(f.Symbol, re); } if (null != progress) { progress.Report(new CfgLL1Progress(CfgLL1Status.CreatingParseTable, j)); } ++j; } 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 = cfg.GetAttribute(nt, "followsConflict", "error") as string; if ("error" == fc) { result.Add(new CfgMessage(CfgErrorLevel.Error, -1, string.Format( "first follows conflict between {0} and {1} on {2}", or.Rule, f.Rule, fe), f.Rule.Line, f.Rule.Column, f.Rule.Position)); } else if ("last" == fc) { d[fe] = new CfgLL1ParseTableEntry(f.Rule); } } else { d.Add(fe, new CfgLL1ParseTableEntry(f.Rule)); } if (null != progress) { progress.Report(new CfgLL1Progress(CfgLL1Status.CreatingParseTable, j)); } ++j; } } } parseTable.Add(nt, d); } return(result); }
public static IList <CfgMessage> TryToLL1ParseTable(this CfgDocument cfg, out CfgLL1ParseTable parseTable) => TryToLL1ParseTable(cfg, null, out parseTable);