// Create appropriate statement object from abstract syntax tree node public static Statement FromTreeNode(IParseNode ASTNode, Dictionary <String, Terminal> terms, Dictionary <String, Nonterminal> vars) { ParseTree subtree = ASTNode as ParseTree; if (subtree == null) { throw new Exception("EXPECTED TREE NODE"); } if (subtree.Nonterminal != vars["statement"]) { throw new Exception("EXPECTED STATEMENT NODE"); } if (subtree.Children[0] is ParseTree) // -------------------------------------------------- Declaration { ParseTree declTree = subtree.Children[0] as ParseTree; ParseLeaf idLeaf = declTree.Children[0] as ParseLeaf; ParseLeaf typeLeaf = declTree.Children[1] as ParseLeaf; if (idLeaf == null || typeLeaf == null) { throw new Exception("BAD AST STRUCTURE"); } Token idToken = idLeaf.Token; Token typeToken = typeLeaf.Token; string identifier = idToken.Lexeme; ValueType type = Value.TypeFromString(typeToken.Lexeme); switch (declTree.Children.Count) { case 2: // ------------------------------------------------------------------------ simple declaration return(new Statement.DeclarationStmt(identifier, type, idToken)); case 3: // ------------------------------------------------------------------------ declaration with assignment ParseLeaf valueLeaf = declTree.Children[2] as ParseLeaf; Expression expr = Expression.FromTreeNode(declTree.Children[2], terms, vars); return(new Statement.DeclarationStmt(identifier, type, idToken, expr)); default: throw new Exception("BAD AST STRUCTURE"); } } else // Assignment / read / print / assert / for statement { ParseLeaf firstChild = subtree.Children[0] as ParseLeaf; if (firstChild.Terminal.MatchedTokenType != null && firstChild.Terminal.MatchedTokenType.Name == "identifier") // --------------------- assignment or for { if (subtree.Children.Count == 2) // ----------------------------------------------- assignment { return(new AssignStmt(firstChild.Token.Lexeme, Expression.FromTreeNode(subtree.Children[1], terms, vars), firstChild.Token)); } else if (subtree.Children.Count == 4) // ------------------------------------------ for { List <Statement> block = new List <Statement>(); ParseTree blockChild = subtree.Children[3] as ParseTree; foreach (IParseNode blockSubtree in blockChild.Children) { block.Add(Statement.FromTreeNode(blockSubtree, terms, vars)); } if (blockChild == null) { throw new Exception("MALFORMED AST"); } return(new ForStmt(firstChild.Token.Lexeme, Expression.FromTreeNode(subtree.Children[1], terms, vars), Expression.FromTreeNode(subtree.Children[2], terms, vars), block, firstChild.Token)); } else { throw new Exception("MALFORMED AST"); } } else { if (subtree.Children.Count != 2) { throw new Exception("MALFORMED AST"); } switch (firstChild.Token.Lexeme) { case "assert": // ------------------------------------------------------------- assert return(new AssertStmt(Expression.FromTreeNode( subtree.Children[1], terms, vars), firstChild.Token)); case "print": // -------------------------------------------------------------- print return(new PrintStmt(Expression.FromTreeNode( subtree.Children[1], terms, vars), firstChild.Token)); case "read": // --------------------------------------------------------------- read ParseLeaf secondChild = subtree.Children[1] as ParseLeaf; if (secondChild == null) { throw new Exception("MALFORMED AST"); } return(new ReadStmt(secondChild.Token.Lexeme, firstChild.Token)); default: throw new Exception("UNEXPECTED STATEMENT TYPE"); } } } }
public Runnable ProcessParseTree(ParseTree parseTree, IEnumerable <Error> parseErrors, bool isValidParseTree) { Runnable prog = new Runnable(); foreach (Error err in parseErrors) { prog.errors.Add(err); } // can't construct AST if parse tree is bad if (!isValidParseTree) { return(prog); } // first remove unnecessary symbols ; : .. ( ) := and epsilons String[] pruneTokens = { "(", ")", ";", ":", "..", ":=", "var", "in", "for", "end", "do" }; Predicate <IParseNode> isUnnecessaryTerminal = n => (n is ParseLeaf) ? (n as ParseLeaf).Token == null || pruneTokens.Contains((n as ParseLeaf).Token.Lexeme) : false; parseTree.RemoveNodes(isUnnecessaryTerminal); // remove any tree nodes with no children Predicate <IParseNode> isEmptyNonterminal = v => (v is ParseTree) ? (v as ParseTree).Children.Count == 0 : false; parseTree.RemoveNodes(isEmptyNonterminal); // refactor // STMTS->STMTS_HEAD STMTS_TAIL to STMTS->(STMT)+ // DECL->"var" <IDENT> ":" <TYPE> ASSIGN to DECL->"var" <IDENT> ":" <TYPE> [":=" <EXPR>] // EXPR->UNARY|OPND BINARY to EXPR-> unary_op OPND | OPND | OPND binary_op OPND // OPND-><INT>|<STRING>|<IDENT>|<EXPR> to just <INT>|<STRING>|<IDENT>|<EXPR> Nonterminal[] pruneVariables = new Nonterminal[] { nonterminals["statements_head"], nonterminals["statements_tail"], nonterminals["unary_operation"], nonterminals["binary_operation"], nonterminals["declaration_assignment"], nonterminals["operand"] }; Predicate <IParseNode> isUnnecessaryNonterminal = n => (n is ParseTree) ? pruneVariables.Contains((n as ParseTree).Nonterminal) : false; parseTree.RemoveNodes(isUnnecessaryNonterminal); if (Program.debug) { Console.WriteLine(parseTree); } // AST is formed at this point, so do semantic checks // find declarations, produce errors if identifier declared multiple times foreach (IParseNode node in parseTree.Nodes()) { if (node is ParseTree) { ParseTree subtree = node as ParseTree; if (subtree.Nonterminal == nonterminals["declaration"]) { ParseLeaf idLeaf = (subtree.Children[0] as ParseLeaf); ParseLeaf typeLeaf = (subtree.Children[1] as ParseLeaf); Token idToken = idLeaf.Token; Token typeToken = typeLeaf.Token; string identifier = idToken.Lexeme; ValueType type = Value.TypeFromString(typeToken.Lexeme); Statement.DeclarationStmt declaration; switch (subtree.Children.Count) { case 2: // simple declaration declaration = new Statement.DeclarationStmt(identifier, type, idToken); break; case 3: // declaration with assignment ParseLeaf valueLeaf = (subtree.Children[2] as ParseLeaf); Expression expr = Expression.FromTreeNode(subtree.Children[2], terminals, nonterminals); declaration = new Statement.DeclarationStmt(identifier, type, idToken, expr); break; default: throw new Exception("BAD AST STRUCTURE"); } if (prog.declarations.ContainsKey(identifier)) { prog.errors.Add(new SemanticError(idToken, identifier + " multiply defined")); } else { prog.declarations[identifier] = declaration; } } } } // check that variables are defined before use foreach (IParseNode node in parseTree.Nodes()) { if (node is ParseLeaf) { ParseLeaf leaf = node as ParseLeaf; Token leafToken = leaf.Token; if (leafToken.Type == tokenTypes["identifier"]) { string identifier = leafToken.Lexeme; Position idPosition = leafToken.TextPosition; if (!prog.declarations.ContainsKey(identifier)) { prog.errors.Add(new SemanticError(leafToken, identifier + " never defined")); } else if (idPosition.CompareTo(prog.declarations[identifier].Token.TextPosition) < 0) { prog.errors.Add(new SemanticError(leafToken, identifier + " not defined before use")); } } } } // add statements to runnable ParseTree statementListNode = parseTree.Children[0] as ParseTree; foreach (IParseNode statementNode in statementListNode.Children) { prog.statements.Add(Statement.FromTreeNode(statementNode, terminals, nonterminals)); } // check that for-loop control variables are not modified inside the for-loop foreach (Statement stmt in prog.statements) { if (stmt is Statement.ForStmt) { Statement.ForStmt forStmt = stmt as Statement.ForStmt; Stack <Statement> stmtStack = new Stack <Statement>(); foreach (Statement substmt in forStmt.Block) { stmtStack.Push(substmt); } while (stmtStack.Count != 0) { Statement s = stmtStack.Pop(); if (s is Statement.AssignStmt) { Statement.AssignStmt assignment = s as Statement.AssignStmt; if (assignment.Identifier == forStmt.Identifier) { prog.errors.Add(new SemanticError(assignment.Token, forStmt.Identifier + " cannot be modified inside for-loop")); } } else if (s is Statement.DeclarationStmt) { Statement.DeclarationStmt declaration = s as Statement.DeclarationStmt; if (declaration.Identifier == forStmt.Identifier) { prog.errors.Add(new SemanticError(declaration.Token, forStmt.Identifier + " cannot be modified inside for-loop")); } } else if (s is Statement.ForStmt) { Statement.ForStmt nestedFor = s as Statement.ForStmt; if (nestedFor.Identifier == forStmt.Identifier) { prog.errors.Add(new SemanticError(nestedFor.Token, forStmt.Identifier + " cannot be modified inside for-loop")); } foreach (Statement substmt in nestedFor.Block) { stmtStack.Push(substmt); } } } } } // typecheck each statement foreach (Statement stmt in prog.statements) { stmt.TypeCheck(prog); } return(prog); }