// Creates an indentifier or value expression from an abstract syntax tree leaf private static Expression ExprFromLeaf(ParseLeaf leaf) { if (leaf == null) throw new Exception("MALFORMED AST"); if (leaf.Token.Type.Name == "identifier") return new IdentifierExpr(leaf.Token.Lexeme, leaf.Token); else return new ValueExpr(new Value(leaf.Token.Type.Name, leaf.Token.Lexeme), leaf.Token); }
// 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; }
// 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); }