예제 #1
0
파일: LL1.cs 프로젝트: wushian/pck
        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);
        }
예제 #2
0
 /// <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);
 }
예제 #3
0
파일: LL1.cs 프로젝트: wushian/pck
        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);
        }
예제 #4
0
파일: LL1.cs 프로젝트: wushian/pck
 public static IList <CfgMessage> TryToLL1ParseTable(this CfgDocument cfg, out CfgLL1ParseTable parseTable)
 => TryToLL1ParseTable(cfg, null, out parseTable);