Ejemplo n.º 1
0
 // 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));
     }
 }
Ejemplo n.º 2
0
        // creates an appropriate Expression object from an abstract syntax tree node
        public static Expression FromTreeNode(IParseNode ASTNode,
                                              Dictionary <String, Terminal> terms,
                                              Dictionary <String, Nonterminal> vars)
        {
            if (ASTNode is ParseTree)
            {
                ParseTree subtree = ASTNode as ParseTree;
                if (subtree.Nonterminal != vars["expression"])
                {
                    throw new Exception("EXPECTED EXPRESSION NODE");
                }

                switch (subtree.Children.Count)
                {
                case 1:
                    IParseNode child = subtree.Children[0];
                    if (child is ParseLeaf)     // identifier or literal
                    {
                        return(ExprFromLeaf(child as ParseLeaf));
                    }
                    else     // another expr
                    {
                        return(FromTreeNode(child, terms, vars));
                    }

                case 2:     // unary operation
                {
                    IParseNode op     = subtree.Children[0];
                    ParseLeaf  opLeaf = op as ParseLeaf;
                    if (opLeaf == null)
                    {
                        throw new Exception("MALFORMED AST");
                    }

                    IParseNode opnd = subtree.Children[1];
                    Expression baseExpr;
                    if (opnd is ParseLeaf)
                    {
                        baseExpr = ExprFromLeaf(opnd as ParseLeaf);
                    }
                    else
                    {
                        baseExpr = FromTreeNode(opnd as ParseTree, terms, vars);
                    }
                    return(new UnaryOp(opLeaf.Token.Lexeme[0], baseExpr, opLeaf.Token));
                }

                case 3:     // binary operation
                {
                    IParseNode op     = subtree.Children[1];
                    ParseLeaf  opLeaf = op as ParseLeaf;
                    if (opLeaf == null)
                    {
                        throw new Exception("MALFORMED AST");
                    }

                    IParseNode lhs = subtree.Children[0];
                    IParseNode rhs = subtree.Children[2];
                    Expression lhsExpr, rhsExpr;
                    if (lhs is ParseLeaf)
                    {
                        lhsExpr = ExprFromLeaf(lhs as ParseLeaf);
                    }
                    else
                    {
                        lhsExpr = FromTreeNode(lhs as ParseTree, terms, vars);
                    }
                    if (rhs is ParseLeaf)
                    {
                        rhsExpr = ExprFromLeaf(rhs as ParseLeaf);
                    }
                    else
                    {
                        rhsExpr = FromTreeNode(rhs as ParseTree, terms, vars);
                    }
                    return(new BinaryOp(lhsExpr, opLeaf.Token.Lexeme[0], rhsExpr, opLeaf.Token));
                }

                default:
                    throw new Exception("MALFORMED AST");
                }
            }
            else
            {
                throw new Exception("EXPECTED LEAF NODE");
            }
        }
Ejemplo n.º 3
0
        // 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");
                    }
                }
            }
        }
Ejemplo n.º 4
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);
        }