// 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); }
// 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; }
// 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); }