Example #1
0
        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;
        }
Example #2
0
        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);
        }