Пример #1
0
            public bool IsNongreedyExit;              // indicates a nongreedy exit branch (which takes priority in case of ambiguity)

            public void UpdateSet(bool addEOF)
            {
                if (Cases.Count == 0)
                {
                    Set = Set.Empty;
                    if (addEOF)
                    {
                        Set = Set.WithEOF();
                    }
                    AndReq = new Set <AndPred>();
                    return;
                }
                Set = Cases[0].Set;
                var andI = new MSet <AndPred>(Cases[0].AndPreds);

                for (int i = 1; i < Cases.Count; i++)
                {
                    Set = Set.Union(Cases[i].Set);
                    andI.IntersectWith(Cases[i].AndPreds);
                }
                AndReq = (Set <AndPred>)andI;

                if (addEOF)
                {
                    Set = Set.WithEOF();
                }
            }
Пример #2
0
 public TerminalPred Merge(TerminalPred r, bool ignoreActions = false)
 {
     if (!ignoreActions && (PreAction != r.PreAction || PostAction != r.PostAction))
     {
         throw new InvalidOperationException("Internal error: cannot merge TerminalPreds that have actions");
     }
     return(new TerminalPred(Basis, Set.Union(r.Set), true)
     {
         PreAction = PreAction, PostAction = PostAction
     });
 }
Пример #3
0
            protected PredictionTree ComputePredictionTree(KthSet[] kthSets)
            {
                var children   = InternalList <PredictionBranch> .Empty;
                var thisBranch = new List <KthSet>();
                int lookahead  = kthSets[0].LA;

                Debug.Assert(kthSets.All(p => p.LA == lookahead));

                IPGTerminalSet covered = CGH.EmptySet;

                for (;;)
                {
                    thisBranch.Clear();
                    // e.g. given an Alts value of ('0' '0'..'7'+ | '0'..'9'+),
                    // ComputeSetForNextBranch finds the set '0' in the first
                    // iteration (recording both alts in 'thisBranch'), '1'..'9'
                    // on the second iteration, and finally null.
                    IPGTerminalSet set = ComputeSetForNextBranch(kthSets, thisBranch, covered);

                    if (set == null)
                    {
                        break;
                    }

                    if (thisBranch.Count == 1)
                    {
                        var branch = thisBranch[0];
                        children.Add(new PredictionBranch(set, branch.Alt, covered));
                    }
                    else
                    {
                        Debug.Assert(thisBranch.Count > 1);
                        NarrowDownToSet(thisBranch, set);

                        PredictionTreeOrAlt sub;
                        if (thisBranch.Any(ks => ks.HasAnyAndPreds))
                        {
                            sub = ComputeAssertionTree(thisBranch);
                        }
                        else
                        {
                            sub = ComputeNestedPredictionTree(thisBranch);
                        }
                        children.Add(new PredictionBranch(set, sub, covered));
                    }

                    covered = covered.Union(set);
                }
                return(new PredictionTree(lookahead, children, covered));
            }
Пример #4
0
            protected LNode GeneratePredictionTreeCode(PredictionTree tree, Pair <LNode, string>[] matchingCode, ref Symbol haveLoop)
            {
                var braces = F.Braces();

                Debug.Assert(tree.Children.Count >= 1);
                var alts = (Alts)_currentPred;

                if (tree.Children.Count == 1)
                {
                    return(GetPredictionSubtreeCode(tree.Children[0], matchingCode, ref haveLoop));
                }

                // From the prediction table, we can generate either an if-else chain:
                //
                //   if (la0 >= '0' && la0 <= '7') sub_tree_1();
                //   else if (la0 == '-') sub_tree_2();
                //   else break;
                //
                // or a switch statement:
                //
                //   switch(la0) {
                //   case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
                //     sub_tree_1();
                //     break;
                //   case '-':
                //     sub_tree_2();
                //     break;
                //   default:
                //     goto breakfor;
                //   }
                //
                // Assertion levels always need an if-else chain; lookahead levels
                // consider the complexity of switch vs if and decide which is most
                // appropriate. Generally "if" is slower, but a switch may require
                // too many labels since it doesn't support ranges like "la0 >= 'a'
                // && la0 <= 'z'".
                //
                // This class makes if-else chains directly (using IPGTerminalSet.
                // GenerateTest() to generate the test expressions), but the code
                // generation helper (CGH) is used to generate switch statements
                // because the required code may be more complex.
                //
                // We may or may not be generating code inside a for(;;) loop. If we
                // decide to generate a switch() statement, one of the branches will
                // usually need to break out of the for loop, but "break" can only
                // break out of the switch(). In that case, add "stop:" after the
                // switch() and use "goto stop" instead of "break".

                WList <LNode> block       = new WList <LNode>();
                LNode         laVar       = null;
                MSet <int>    switchCases = new MSet <int>();

                IPGTerminalSet[] branchSets = null;
                bool             should     = false;

                if (tree.UsesLA())
                {
                    laVar = F.Id("la" + tree.Lookahead.ToString());

                    if (!tree.IsAssertionLevel)
                    {
                        IPGTerminalSet covered = CGH.EmptySet;
                        branchSets = tree.Children.Select(branch => {
                            var set = branch.Set.Subtract(covered);
                            covered = covered.Union(branch.Set);
                            return(set);
                        }).ToArray();

                        should = CGH.ShouldGenerateSwitch(branchSets, switchCases, tree.Children.Last.IsErrorBranch);
                        if (!should)
                        {
                            switchCases.Clear();
                        }
                        else if (should && haveLoop == S.For)
                        {
                            // Can't "break" out of the for-loop when there is a nested switch,
                            haveLoop = GSymbol.Get(NextStopLabel());                             // so use "goto stop".
                        }
                    }
                }

                LNode[] branchCode = new LNode[tree.Children.Count];
                for (int i = 0; i < tree.Children.Count; i++)
                {
                    if (tree.Children[i].IsErrorBranch)
                    {
                        if (_recognizerMode)
                        {
                            branchCode[i] = F.Call(S.Return, F.False);
                        }
                        else if (alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value)
                        {
                            Debug.Assert(matchingCode.Length == alts.Arms.Count + 1);
                            branchCode[i] = matchingCode[alts.Arms.Count].A;
                        }
                        else
                        {
                            branchCode[i] = CGH.ErrorBranch(tree.TotalCoverage, tree.Lookahead);
                        }
                    }
                    else
                    {
                        branchCode[i] = GetPredictionSubtreeCode(tree.Children[i], matchingCode, ref haveLoop);
                    }
                }

                var code = GenerateIfElseChain(tree, branchCode, ref laVar, switchCases);

                if (laVar != null)
                {
                    block.Insert(0, F.Assign(laVar, CGH.LA(tree.Lookahead)));
                    _laVarsNeeded |= 1ul << tree.Lookahead;
                }
                else if (should)
                {
                    laVar = CGH.LA(tree.Lookahead);
                }

                if (should)
                {
                    Debug.Assert(switchCases.Count != 0);
                    code = CGH.GenerateSwitch(branchSets, branchCode, switchCases, code ?? F.Missing, laVar);
                }

                block.Add(code);
                return(F.Braces(block.ToVList()));
            }
Пример #5
0
            void ScanTree(PredictionTree tree, Alts alts, DList <Prematched> path)
            {
                int oldCount = path.Count;

                while (path.Count <= tree.Lookahead)
                {
                    path.Add(new Prematched {
                        Terminals = Anything
                    });
                }
                Prematched pm = path.Last;

                if (tree.IsAssertionLevel)
                {
                    foreach (PredictionBranch b in tree.Children)
                    {
                        var old      = pm.AndPreds.Clone();
                        var verified = Enumerable.Aggregate(b.AndPreds, (set1, set2) => (set1.Union(set2)));                         // usually empty if more than one
                        pm.AndPreds.UnionWith(verified);

                        if (b.Sub.Tree != null)
                        {
                            ScanTree(b.Sub.Tree, alts, path);
                        }
                        else
                        {
                            Debug.Assert(b.Sub.Alt != ErrorAlt);
                            if (b.Sub.Alt == ExitAlt)
                            {
                                _apply.ApplyPrematchData(alts.Next, path);
                            }
                            else
                            {
                                _apply.ApplyPrematchData(alts.Arms[b.Sub.Alt], path);
                            }
                        }
                        pm.AndPreds = old;
                    }
                }
                else                 // !IsAssertionLevel (terminal-matching level)
                {
                    bool needErrorBranch = LLPG.NeedsErrorBranch(tree, alts);

                    for (int i = 0; i < tree.Children.Count; i++)
                    {
                        PredictionBranch b   = tree.Children[i];
                        IPGTerminalSet   set = b.Set;
                        if (!needErrorBranch && i + 1 == tree.Children.Count)
                        {
                            // Add all the default cases
                            set = set.Union(tree.TotalCoverage.Inverted());
                        }
                        pm.Terminals = set;
                        if (b.Sub.Tree != null)
                        {
                            ScanTree(b.Sub.Tree, alts, path);
                        }
                        else
                        {
                            if (b.Sub.Alt == ExitAlt)
                            {
                                _apply.ApplyPrematchData(alts.Next, path);
                            }
                            else if (b.Sub.Alt != ErrorAlt)
                            {
                                _apply.ApplyPrematchData(alts.Arms[b.Sub.Alt], path);
                            }
                        }
                    }
                    path.PopLast();
                }
                path.Resize(oldCount);
            }