Пример #1
0
        public Parser ToLL1Parser(IEnumerable <Token> tokenizer = null)
        {
            var parseTable = ToLL1ParseTable();
            var syms       = new List <string>();

            FillSymbols(syms);
            var nodeFlags = new int[syms.Count];

            for (var i = 0; i < nodeFlags.Length; ++i)
            {
                var o = AttributeSets.GetAttribute(syms[i], "hidden", false);
                if (o is bool && (bool)o)
                {
                    nodeFlags[i] |= 2;
                }
                o = AttributeSets.GetAttribute(syms[i], "collapsed", false);
                if (o is bool && (bool)o)
                {
                    nodeFlags[i] |= 1;
                }
            }
            var attrSets = new KeyValuePair <string, object> [syms.Count][];

            for (var i = 0; i < attrSets.Length; i++)
            {
                AttributeSet attrs;
                if (AttributeSets.TryGetValue(syms[i], out attrs))
                {
                    attrSets[i] = new KeyValuePair <string, object> [attrs.Count];
                    var j = 0;
                    foreach (var attr in attrs)
                    {
                        attrSets[i][j] = new KeyValuePair <string, object>(attr.Key, attr.Value);
                        ++j;
                    }
                }
                else
                {
                    attrSets[i] = null;                    // new KeyValuePair<string, object>[0];
                }
            }
            var initCfg = new int[] { GetIdOfSymbol(StartSymbol), FillNonTerminals().Count };

            return(new LL1TableParser(parseTable.ToLL1Array(syms), initCfg, syms.ToArray(), nodeFlags, attrSets, tokenizer));
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }