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