コード例 #1
0
        // Builds an LL(1) parse table using the First and Follow sets for the grammar
        // returns null if CFG is not LL(1)
        public ParseTable CreateLL1ParseTable()
        {
            ComputeFirstSets();
            ComputeFollowSets();

            if (Program.debug)
            {
                Console.WriteLine("=========================================================");
            }

            ParseTable parseTable = new ParseTable();

            // for each nonterminal in the grammar and each production rule for the nonterminal
            foreach (Nonterminal var in productions.Keys)
            {
                foreach (ISymbol[] varProduction in productions[var])
                {
                    if (Program.debug)
                    {
                        Console.WriteLine("CFG: LL(1) table gen, var = " + var + " prod = " + SymbolsToString(varProduction));
                    }

                    ISet <Terminal> productionFirst = First(varProduction);
                    // add an entry to the parse table for each terminal in the first set of the production
                    foreach (Terminal term in productionFirst)
                    {
                        if (term != Terminal.EPSILON)
                        {
                            if (parseTable.Get(var, term) != null) // LL(1) violation
                            {
                                if (Program.debug)
                                {
                                    Console.WriteLine("CFG: LL(1) violation at (First) [" + var + "," + term + "]");
                                    Console.WriteLine("\tWas: " + SymbolsToString(parseTable.Get(var, term)));
                                    Console.WriteLine("\tNew: " + SymbolsToString(varProduction));
                                }
                                return(null);
                            }
                            else
                            {
                                parseTable.Add(var, term, varProduction);
                            }
                        }
                    }
                    // if epsilon can be derived from the production
                    // add an entry to the parse table for each terminal in the follow set of the nonterminal as well
                    if (productionFirst.Contains(Terminal.EPSILON))
                    {
                        foreach (Terminal term in Follow(var))
                        {
                            if (parseTable.Get(var, term) != null) // LL(1) violation
                            {
                                if (Program.debug)
                                {
                                    Console.WriteLine("CFG: LL(1) violation at (Follow) [" + var + "," + term + "]");
                                    Console.WriteLine("\tWas: " + SymbolsToString(parseTable.Get(var, term)));
                                    Console.WriteLine("\tNew: " + SymbolsToString(varProduction));
                                }
                                return(null);
                            }
                            else
                            {
                                parseTable.Add(var, term, varProduction);
                            }
                        }
                    }
                }
            }

            if (Program.debug)
            {
                foreach (Nonterminal var in nonterminals)
                {
                    foreach (Terminal term in terminals)
                    {
                        if (parseTable.Get(var, term) != null)
                        {
                            Console.WriteLine("CFG: LL(1) Table[" + var + "][" + term + "] = " + SymbolsToString(parseTable.Get(var, term)));
                        }
                    }
                }
            }

            return(parseTable);
        }
コード例 #2
0
ファイル: CFG.cs プロジェクト: psaikko/interpreter-project
        // Builds an LL(1) parse table using the First and Follow sets for the grammar
        // returns null if CFG is not LL(1)
        public ParseTable CreateLL1ParseTable()
        {
            ComputeFirstSets();
            ComputeFollowSets();

            if (Program.debug)
                Console.WriteLine("=========================================================");

            ParseTable parseTable = new ParseTable();

            // for each nonterminal in the grammar and each production rule for the nonterminal
            foreach (Nonterminal var in productions.Keys)
            {
                foreach (ISymbol[] varProduction in productions[var])
                {
                    if (Program.debug)
                        Console.WriteLine("CFG: LL(1) table gen, var = " + var + " prod = " + SymbolsToString(varProduction));

                    ISet<Terminal> productionFirst = First(varProduction);
                    // add an entry to the parse table for each terminal in the first set of the production
                    foreach (Terminal term in productionFirst)
                    {
                        if (term != Terminal.EPSILON)
                        {
                            if (parseTable.Get(var, term) != null) // LL(1) violation
                            {
                                if (Program.debug)
                                {
                                    Console.WriteLine("CFG: LL(1) violation at (First) [" + var + "," + term + "]");
                                    Console.WriteLine("\tWas: " + SymbolsToString(parseTable.Get(var, term)));
                                    Console.WriteLine("\tNew: " + SymbolsToString(varProduction));
                                }
                                return null;
                            }
                            else
                            {
                                parseTable.Add(var, term, varProduction);
                            }
                        }
                    }
                    // if epsilon can be derived from the production
                    // add an entry to the parse table for each terminal in the follow set of the nonterminal as well
                    if (productionFirst.Contains(Terminal.EPSILON))
                    {
                        foreach (Terminal term in Follow(var))
                        {
                            if (parseTable.Get(var, term) != null) // LL(1) violation
                            {
                                if (Program.debug)
                                {
                                    Console.WriteLine("CFG: LL(1) violation at (Follow) [" + var + "," + term + "]");
                                    Console.WriteLine("\tWas: " + SymbolsToString(parseTable.Get(var, term)));
                                    Console.WriteLine("\tNew: " + SymbolsToString(varProduction));
                                }
                                return null;
                            }
                            else
                            {
                                parseTable.Add(var, term, varProduction);
                            }
                        }
                    }
                }
            }

            if (Program.debug)
                foreach (Nonterminal var in nonterminals)
                    foreach (Terminal term in terminals)
                        if (parseTable.Get(var, term) != null)
                            Console.WriteLine("CFG: LL(1) Table[" + var + "][" + term + "] = " + SymbolsToString(parseTable.Get(var, term)));

            return parseTable;
        }
コード例 #3
0
        // Parse the given stream of tokens
        public ParseTree Parse(IEnumerable <Token> tokenSource)
        {
            isValidParseTree = true;
            errors           = new List <Error>();

            Stack <ISymbol> symbolStack = new Stack <ISymbol>();

            symbolStack.Push(Terminal.EOF);
            symbolStack.Push(start);

            ParseTree          parseTree = new ParseTree(start);
            Stack <IParseNode> treeStack = new Stack <IParseNode>();

            treeStack.Push(new ParseLeaf(Terminal.EOF));
            treeStack.Push(parseTree);

            IEnumerator <Token> tokenStream = tokenSource.GetEnumerator();

            tokenStream.MoveNext();

            while (symbolStack.Count > 0)
            {
                if (Program.debug)
                {
                    Console.WriteLine("=========================================================");
                    Console.WriteLine("  PARSE: Stack " + SymbolsToString(symbolStack));
                    Console.WriteLine("  PARSE: expecting " + symbolStack.Peek());
                    Console.WriteLine("  PARSE: token " + tokenStream.Current);
                }

                // ignore error tokens
                if (tokenStream.Current.Type == TokenType.ERROR)
                {
                    if (Program.debug)
                    {
                        Console.WriteLine("  PARSE: skipping error token");
                    }
                    errors.Add(new LexicalError(tokenStream.Current));
                    tokenStream.MoveNext();
                    continue;
                }

                if (symbolStack.Peek() is Terminal)
                {
                    Terminal  term = symbolStack.Peek() as Terminal;
                    ParseLeaf leaf = treeStack.Peek() as ParseLeaf;

                    if (term == Terminal.EPSILON)
                    {
                        // epsilon production was used, exclude from parse tree
                        if (Program.debug)
                        {
                            Console.WriteLine("  PARSE: ignore epsilon");
                        }
                        symbolStack.Pop();
                        treeStack.Pop();
                    }
                    else if (term.Matches(tokenStream.Current))
                    {
                        // current token matches the top of the parse stack, add it to parse tree
                        if (Program.debug)
                        {
                            Console.WriteLine("  PARSE: Terminal match");
                        }
                        leaf.Token = tokenStream.Current;
                        tokenStream.MoveNext();
                        symbolStack.Pop();
                        treeStack.Pop();
                    }
                    else
                    {
                        // current token does no match, recover from error
                        if (Program.debug)
                        {
                            Console.WriteLine("  PARSE: Error, Terminal mismatch");
                        }
                        errors.Add(new SyntaxError(tokenStream.Current));
                        Synchronize(symbolStack, treeStack, tokenStream);
                    }
                }
                else // top of stack is a nonterminal
                {
                    Nonterminal var     = symbolStack.Pop() as Nonterminal;
                    IParseNode  popped  = treeStack.Pop();
                    ParseTree   subtree = popped as ParseTree;

                    ISymbol[] production = table.Get(var, tokenStream.Current);

                    if (production == null)
                    {
                        // cannot derive the current token from the nonterminal at the top of the stack
                        if (Program.debug)
                        {
                            Console.WriteLine("  PARSE: Error, No such production");
                        }

                        symbolStack.Push(var);
                        treeStack.Push(popped);

                        errors.Add(new SyntaxError(tokenStream.Current));
                        Synchronize(symbolStack, treeStack, tokenStream);
                    }
                    else
                    {
                        // use the production specified by the parse table, add node to parse tree
                        if (Program.debug)
                        {
                            Console.WriteLine("  PARSE: Using production " + SymbolsToString(production));
                        }

                        for (int i = production.Length - 1; i >= 0; i--)
                        {
                            IParseNode treeChild;
                            if (production[i] is Terminal)
                            {
                                treeChild = new ParseLeaf(production[i] as Terminal);
                            }
                            else
                            {
                                treeChild = new ParseTree(production[i] as Nonterminal);
                            }
                            subtree.Children.Insert(0, treeChild);
                            treeStack.Push(treeChild);
                            symbolStack.Push(production[i]);
                        }
                    }
                }
            }

            if (Program.debug)
            {
                Console.WriteLine(parseTree);
            }

            return(parseTree);
        }