Beispiel #1
0
        public static IList <CfgMessage> EliminateFirstFirstConflicts(this CfgDocument cfg)
        {
            var result = new List <CfgMessage>();

            foreach (var nt in new List <string>(cfg.EnumNonTerminals()))
            {
                var rules  = cfg.FillNonTerminalRules(nt);
                var rights = new List <IList <string> >();
                foreach (var rule in rules)
                {
                    rights.Add(rule.Right);
                }
                while (true)
                {
                    var pfx = rights.GetLongestCommonPrefix();
                    if (pfx.IsNullOrEmpty())
                    {
                        break;
                    }
                    // obv first first conflict
                    var nnt = _GetLeftFactorId(cfg, nt);

                    var suffixes = new List <IList <string> >();
                    foreach (var rule in rules)
                    {
                        if (rule.Right.StartsWith(pfx))
                        {
                            rights.Remove(rule.Right);
                            suffixes.Add(new List <string>(rule.Right.Range(pfx.Count)));
                            cfg.Rules.Remove(rule);
                            result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Removed rule {0} because it is part of a first-first conflict.", rule), rule.Line, rule.Column, rule.Position));
                        }
                    }

                    var newRule = new CfgRule(nt);
                    newRule.Right.AddRange(pfx);
                    newRule.Right.Add(nnt);

                    if (!cfg.Rules.Contains(newRule))
                    {
                        cfg.Rules.Add(newRule);
                    }
                    result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Added rule {0} to resolve first-first conflict.", newRule), 0, 0, 0));
                    foreach (var suffix in suffixes)
                    {
                        newRule = new CfgRule(nnt);
                        newRule.Right.AddRange(suffix);

                        if (!cfg.Rules.Contains(newRule))
                        {
                            cfg.Rules.Add(newRule);
                        }
                        result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Added rule {0} to resolve first-first conflict.", newRule), 0, 0, 0));
                    }

                    _SetAttribute(cfg, nnt, "collapsed", true);
                }
            }
            return(result);
        }
Beispiel #2
0
        static Lrfa _ToLrfa(CfgDocument cfg, IProgress <CfgLalr1Progress> progress)
        {
            if (null != progress)
            {
                progress.Report(new CfgLalr1Progress(CfgLalr1Status.ComputingStates, 0));
            }
            // TODO: this takes a long time sometimes
            var map = new Dictionary <ICollection <LRItem>, Lrfa>(_LRItemSetComparer.Default);
            // create an augmented grammar - add rule {start} -> [[StartId]]
            var start = new CfgRule(cfg.GetAugmentedStartId(cfg.StartSymbol), new string[] { cfg.StartSymbol });
            var cl    = new HashSet <LRItem>();

            cl.Add(new LRItem(start, 0));
            _FillLRClosureInPlace(cfg, progress, cl);
            var lrfa  = new Lrfa(true, cl);
            var items = cl.Count;

            map.Add(cl, lrfa);
            var done = false;
            var oc   = 0;

            while (!done)
            {
                done = true;
                var arr = map.Keys.ToArray();
                for (var i = 0; i < arr.Length; ++i)
                {
                    var itemSet = arr[i];
                    foreach (var item in itemSet)
                    {
                        var next = item.RightIndex < item.Rule.Right.Count ? item.Rule.Right[item.RightIndex] : null;
                        if (item.RightIndex < item.Rule.Right.Count)
                        {
                            var n = _FillLRMove(cfg, itemSet, next, progress);
                            if (!_ContainsItemSet(map.Keys, n))
                            {
                                done = false;
                                var npda = new Lrfa(true, n);
                                map.Add(n, npda);
                                items += n.Count;
                                if (null != progress)
                                {
                                    progress.Report(new CfgLalr1Progress(CfgLalr1Status.ComputingConfigurations, items));
                                }
                            }
                            map[itemSet].Transitions[next] = map[n];
                        }
                    }
                }
                if (!done)
                {
                    oc = map.Count;
                    if (null != progress)
                    {
                        progress.Report(new CfgLalr1Progress(CfgLalr1Status.ComputingStates, oc));
                    }
                }
            }
            return(lrfa);
        }
Beispiel #3
0
 public CfgLL1Conflict(CfgLL1ConflictKind kind, CfgRule rule1, CfgRule rule2, string symbol)
 {
     Kind   = kind;
     Rule1  = rule1 ?? throw new ArgumentNullException("rule1");
     Rule2  = rule2 ?? throw new ArgumentNullException("rule2");
     Symbol = symbol;
 }
Beispiel #4
0
        public static IList <CfgMessage> EliminateFirstFollowsConflicts(this CfgDocument cfg)
        {
            var result    = new List <CfgMessage>();
            var conflicts = cfg.FillLL1Conflicts();

            for (int ic = conflicts.Count, i = 0; i < ic; ++i)
            {
                var conflict = conflicts[i];
                if (CfgLL1ConflictKind.FirstFollows == conflict.Kind)
                {
                    if (conflict.Rule1.IsNil || conflict.Rule2.IsNil)
                    {
                        var rule = conflict.Rule1.IsNil ? conflict.Rule1 : conflict.Rule2;
                        // we might be able to do something about this.
                        var refs = cfg.FillReferencesToSymbol(rule.Left);
                        var ntr  = cfg.FillNonTerminalRules(rule.Left);
                        for (int jc = refs.Count, j = 0; j < jc; ++j)
                        {
                            for (int kc = ntr.Count, k = 0; k < kc; ++k)
                            {
                                var ntrr = ntr[k];
                                var r    = refs[j];
                                var rr   = new CfgRule(r.Left, r.Right.Replace(rule.Left, ntrr.Right));
                                if (!cfg.Rules.Contains(rr))
                                {
                                    cfg.Rules.Add(rr);
                                }
                                result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Concat("Added rule ", rr.ToString(), " to resolve first-follows conflict."), rr.Line, rr.Column, rr.Position));
                            }
                            result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Concat("Removed rule ", refs[j].ToString(), " to resolve first-follows conflict."), refs[j].Line, refs[j].Column, refs[j].Position));
                            cfg.Rules.Remove(refs[j]);
                        }
                        for (int jc = ntr.Count, j = 0; j < jc; ++j)
                        {
                            cfg.Rules.Remove(ntr[j]);
                            result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Concat("Removed rule ", ntr[j].ToString(), " to resolve first-follows conflict."), ntr[j].Line, ntr[j].Column, ntr[j].Position));
                        }
                    }
                }
            }
            return(result);
        }
Beispiel #5
0
        public static IList <CfgMessage> TryToLalr1ParseTable(this CfgDocument cfg, IProgress <CfgLalr1Progress> progress, out CfgLalr1ParseTable parseTable)
        {
            var result  = new List <CfgMessage>();
            var start   = cfg.GetAugmentedStartId(cfg.StartSymbol);
            var lrfa    = _ToLrfa(cfg, progress);
            var trnsCfg = _ToLRTransitionGrammar(cfg, lrfa, progress);

            trnsCfg.RebuildCache();
            var closure = new List <Lrfa>();

            parseTable = new CfgLalr1ParseTable();

            var itemSets = new List <ICollection <LRItem> >();

            lrfa.FillClosure(closure);
            var i = 0;

            foreach (var p in closure)
            {
                itemSets.Add(p.AcceptSymbol);
                parseTable.Add(new Dictionary <string, (int RuleOrStateId, string Left, string[] Right)>());
                ++i;
            }
            i = 0;
            foreach (var p in closure)
            {
                foreach (var trn in p.Transitions)
                {
                    var idx = closure.IndexOf(trn.Value);
                    parseTable[i].Add(
                        trn.Key,
                        (idx, null, null)
                        );
                }
                foreach (var item in p.AcceptSymbol)
                {
                    if (Equals(item.Rule.Left, start) && item.RightIndex == item.Rule.Right.Count)
                    {
                        parseTable[i].Add(
                            "#EOS",
                            (-1, null, null));
                        break;
                    }
                }
                ++i;
            }
            var follows = trnsCfg.FillFollows();
            // work on our reductions now
            var map = new Dictionary <CfgRule, ICollection <string> >(_TransitionMergeRuleComparer.Default);

            foreach (var rule in trnsCfg.Rules)
            {
                ICollection <string> f;
                if (!map.TryGetValue(rule, out f))
                {
                    map.Add(rule, follows[rule.Left]);
                }
                else
                {
                    foreach (var o in follows[rule.Left])
                    {
                        if (!f.Contains(o))
                        {
                            f.Add(o);
                        }
                    }
                }
            }
            var j = 0;

            foreach (var mapEntry in map)
            {
                if (null != progress)
                {
                    progress.Report(new CfgLalr1Progress(CfgLalr1Status.ComputingReductions, j));
                }
                var rule  = mapEntry.Key;
                var lr    = _LrtSymbol.Parse(rule.Right[rule.Right.Count - 1]);
                var left  = _LrtSymbol.Parse(rule.Left).Id;
                var right = new List <string>();
                foreach (var s in rule.Right)
                {
                    right.Add(_LrtSymbol.Parse(s).Id);
                }
                var newRule = new CfgRule(left, right);
                if (!Equals(left, start))
                {
                    foreach (var f in mapEntry.Value)
                    {
                        // build the rule data
                        var rr = new string[newRule.Right.Count];
                        for (var ri = 0; ri < rr.Length; ri++)
                        {
                            rr[ri] = newRule.Right[ri];
                        }

                        var iid = _LrtSymbol.Parse(f).Id;
                        (int RuleOrStateId, string Left, string[] Right)tuple;
                        var rid = cfg.Rules.IndexOf(newRule);

                        var newTuple = (RuleOrStateId : rid, Left : newRule.Left, Right : rr);
                        // this gets rid of duplicate entries which crop up in the table
                        if (!parseTable[lr.To].TryGetValue(iid, out tuple))
                        {
                            parseTable[lr.To].Add(_LrtSymbol.Parse(f).Id,
                                                  newTuple);
                        }
                        else
                        {
                            // TODO: Verify this - may need the dragon book
                            if (null == tuple.Right)
                            {
                                var nr  = cfg.Rules[rid];
                                var msg = new CfgMessage(CfgErrorLevel.Warning, -1, string.Format("Shift-Reduce conflict on rule {0}, token {1}", nr, iid), nr.Line, nr.Column, nr.Position);
                                if (!result.Contains(msg))
                                {
                                    result.Add(msg);
                                }
                            }
                            else
                            {
                                if (rid != newTuple.RuleOrStateId)
                                {
                                    var nr  = cfg.Rules[rid];
                                    var msg = new CfgMessage(CfgErrorLevel.Error, -1, string.Format("Reduce-Reduce conflict on rule {0}, token {1}", nr, iid), nr.Line, nr.Column, nr.Position);
                                    if (!result.Contains(msg))
                                    {
                                        result.Add(msg);
                                    }
                                }
                            }
                        }
                    }
                }
                ++j;
            }
            return(result);
        }
Beispiel #6
0
 public LRItem(CfgRule rule, int rightIndex)
 {
     Rule       = rule;
     RightIndex = rightIndex;
 }
Beispiel #7
0
        public static IList <CfgMessage> EliminateLeftRecursion(this CfgDocument cfg)
        {
            var result = new List <CfgMessage>();
            var done   = false;

            while (!done)
            {
                done = true;
                var ic = cfg.Rules.Count;
                for (var i = 0; i < ic; ++i)
                {
                    var rule = cfg.Rules[i];
                    if (rule.IsDirectlyLeftRecursive)
                    {
                        cfg.Rules.Remove(rule);
                        result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Removed rule {0} because it is directly left recursive.", rule), rule.Line, rule.Column, rule.Position));

                        var newId = _GetRightAssocId(cfg, rule.Left);

                        var col = new List <string>();
                        var c   = rule.Right.Count;
                        for (var j = 1; j < c; ++j)
                        {
                            col.Add(rule.Right[j]);
                        }
                        col.Add(newId);
                        var o = cfg.GetAttribute(rule.Left, "collapsed", false);
                        if (o is bool && (bool)o)
                        {
                            _SetAttribute(cfg, newId, "collapsed", true);
                        }
                        else
                        {
                            _SetAttribute(cfg, newId, "substitute", rule.Left);
                        }

                        var newRule = new CfgRule(newId);
                        for (int jc = col.Count, j = 0; j < jc; ++j)
                        {
                            newRule.Right.Add(col[j]);
                        }
                        if (!cfg.Rules.Contains(newRule))
                        {
                            cfg.Rules.Add(newRule);
                        }
                        result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Added rule {1} to replace rule {0}", rule, newRule), rule.Line, rule.Column, rule.Position));

                        var rr = new CfgRule(newId);
                        if (!cfg.Rules.Contains(rr))
                        {
                            cfg.Rules.Add(rr);
                        }
                        result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Added rule {1} to replace rule {0}", rule, rr), rule.Line, rule.Column, rule.Position));

                        foreach (var r in cfg.Rules)
                        {
                            if (Equals(r.Left, rule.Left))
                            {
                                if (!r.IsDirectlyLeftRecursive)
                                {
                                    r.Right.Add(newId);
                                }
                            }
                        }
                    }

                    /*else if (_IsIndirectlyLeftRecursive(rule))
                     * {
                     *      result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Concat("Rule ", rule, " modified because it was indirectly left recursive.")));
                     *      Rules.Remove(rule);
                     *      var jc = rule.Right.Count;
                     *      var append = new List<string>(jc - 1);
                     *      for (var j = 1; j < jc; ++j)
                     *              append.Add(rule.Right[j]);
                     *      // do indirect left recursion elimination.
                     *      // first make it directly left recursive.
                     *      var dstRules = FillNonTerminalRules(rule.Right[0]);
                     *      foreach (var drule in dstRules)
                     *      {
                     *              var newRule = new CfgRule(rule.Left);
                     *              // now add the stuff from the dst rule;
                     *              newRule.Right.AddRange(drule.Right);
                     *              newRule.Right.AddRange(append);
                     *              if (!Rules.Contains(newRule))
                     *                      Rules.Add(newRule);
                     *              done = false;
                     *              var nt = GetTransformId(rule.Left);
                     *              var allRules = FillNonTerminalRules(rule.Left);
                     *              foreach (var ar in allRules)
                     *              {
                     *                      // Section 2.3, 3.2
                     *                      // TODO: This needs lots more testing
                     *
                     *                      if (ar.IsNil || !Equals(ar.Right[0], rule.Left))
                     *                      {
                     *                              var nar = new CfgRule(rule.Left);
                     *                              nar.Right.AddRange(ar.Right);
                     *                              nar.Right.Add(nt);
                     *                              if (!Rules.Contains(nar))
                     *                                      Rules.Add(nar);
                     *                              Rules.Remove(ar);
                     *                      }
                     *                      else
                     *                      {
                     *                              ar.Right.RemoveAt(0);
                     *                              ar.Left = nt;
                     *                              ar.Right.Add(nt);
                     *                              var nr2 = new CfgRule(nt);
                     *                              if (!Rules.Contains(nr2))
                     *                                      Rules.Add(nr2);
                     *                      }
                     *                      //}
                     *
                     *              }
                     *
                     *              result.AddRange(EliminateUnderivableRules());
                     *
                     *              break;
                     *
                     *      }
                     *      if (!done)
                     *              break;
                     * }*/
                }
            }
            return(result);
        }
Beispiel #8
0
        public static IList <CfgMessage> TryPrepareLL1(this CfgDocument cfg, IProgress <CfgLL1Progress> progress = null)
        {
            const int   repeat = 2;
            var         result = new List <CfgMessage>();
            CfgDocument old    = cfg;

            for (int j = 0; j < repeat; ++j)
            {
                if (null != progress)
                {
                    progress.Report(new CfgLL1Progress(CfgLL1Status.Factoring, j));
                }
                // if 20 times doesn't sort out this grammar it's not LL(1)
                // the math is such that we don't know unless we try
                // and the tries can go on forever.
                for (int i = 0; i < 20; ++i)
                {
                    if (cfg.IsDirectlyLeftRecursive)
                    {
                        result.AddRange(EliminateLeftRecursion(cfg));
                    }
                    var cc = FillLL1Conflicts(cfg);
                    if (_HasFirstFollowsConflicts(cc))
                    {
                        result.AddRange(EliminateFirstFollowsConflicts(cfg));
                    }
                    cc = FillLL1Conflicts(cfg);
                    if (_HasFirstFirstConflicts(cc))
                    {
                        result.AddRange(EliminateFirstFirstConflicts(cfg));
                    }
                    //result.AddRange(EliminateUnderivableRules());
                    cc = cfg.FillLL1Conflicts();
                    if (0 == cc.Count && !cfg.IsDirectlyLeftRecursive)
                    {
                        break;
                    }
                    if (old.Equals(cfg))
                    {
                        break;
                    }
                    old = cfg.Clone();
                }
            }
            if (cfg.IsDirectlyLeftRecursive)
            {
                // search for a directly recursive rule so we can report location info
                CfgRule r = null;
                for (int ic = cfg.Rules.Count, i = 0; i < ic; ++i)
                {
                    var rr = cfg.Rules[i];
                    if (rr.IsDirectlyLeftRecursive)
                    {
                        r = rr;
                        break;
                    }
                }
                result.Add(new CfgMessage(CfgErrorLevel.Error, -1, "Grammar is unresolvably and directly left recursive and cannot be parsed with an LL parser.", r.Line, r.Column, r.Position));
            }
            var fc = cfg.FillLL1Conflicts();

            foreach (var f in fc)
            {
                result.Add(new CfgMessage(CfgErrorLevel.Error, -1, string.Format("Grammar has unresolvable first-{0} conflict between {1} and {2} on symbol {3}", f.Kind == CfgLL1ConflictKind.FirstFirst ? "first" : "follows", f.Rule1, f.Rule2, f.Symbol), f.Rule2.Line, f.Rule2.Column, f.Rule2.Position));
            }
            cfg.TryValidateLL1(result);
            return(result);
        }
Beispiel #9
0
 public CfgLL1ParseTableEntry(CfgRule rule)
 {
     Rule = rule;
 }