public ITreeNode Program()
        {
            ITreeNode programNode = new ErrorNode();

            switch (curTokenType)
            {
                case TokenType.BEGINBL:
                    Match(ref matchToken, TokenType.BEGINBL);
                    ITreeNode someStatement = Program();
                    BlockNode block = new BlockNode();
                    block.addStatement(someStatement);
                    while (curTokenType != TokenType.ENDBL)
                    {
                        someStatement = Program();
                        block.addStatement(someStatement);
                    }
                    Match(ref matchToken, TokenType.ENDBL);
                    programNode = block;
                    break;
                case TokenType.LABEL:
                    Match(ref matchToken, TokenType.LABEL);
                    LabelNode labeledBlock = new LabelNode(matchToken.getValue());
                    ITreeNode labeledStatement;
                    do
                    {
                        labeledStatement = Program();
                        labeledBlock.addStatement(labeledStatement);
                    }
                    while (curTokenType != TokenType.EOF);
                    programNode = labeledBlock;
                    break;
                case TokenType.INTDEC:
                    Match(ref matchToken, TokenType.INTDEC);
                    Match(ref matchToken, TokenType.ID);
                    programNode = new IdentifierDeclarationNode(IdentifierType.INT, matchToken.getValue());
                    Match(ref matchToken, TokenType.EOS);
                    break;
                case TokenType.BOOLDEC:
                    Match(ref matchToken, TokenType.BOOLDEC);
                    Match(ref matchToken, TokenType.ID);
                    programNode = new IdentifierDeclarationNode(IdentifierType.BOOL, matchToken.getValue());
                    Match(ref matchToken, TokenType.EOS);
                    break;
                case TokenType.FOR:
                    Match(ref matchToken, TokenType.FOR);
                    Match(ref matchToken, TokenType.LPAREN);
                    AssignmentNode init = (AssignmentNode)Program();
                    AssignmentNode step = (AssignmentNode)Program();
                    BooleanExpressionNode condition = (BooleanExpressionNode)BooleanExpression();
                    Match(ref matchToken, TokenType.RPAREN);
                    BlockNode forBody = (BlockNode)Program();
                    programNode = new ForNode(init, step, condition, forBody);
                    break;
                /*case TokenType.FUN:
                    Match(ref matchToken, TokenType.FUN);
                    IdentifierNode id = (IdentifierNode)Factor();
                    programNode = new FunctionNode(id);
                    Match(ref matchToken, TokenType.EOS);
                    break;*/
                case TokenType.GOTO:
                    Match(ref matchToken, TokenType.GOTO);
                    Match(ref matchToken, TokenType.ID);
                    IdentifierNode gotoLabel = new IdentifierNode(matchToken.getValue(), IdentifierType.LABEL);
                    programNode = new GotoNode(gotoLabel);
                    Match(ref matchToken, TokenType.EOS);
                    break;
                case TokenType.ID:
                    Match(ref matchToken, TokenType.ID);
                    IdentifierNode assignId = new IdentifierNode(matchToken.getValue(), IdentifierType.UNKNOWN);
                    Match(ref matchToken, TokenType.ASSIGN);
                    BooleanExpressionNode assignValue = (BooleanExpressionNode)BooleanExpression();
                    programNode = new AssignmentNode(assignId, assignValue);
                    Match(ref matchToken, TokenType.EOS);
                    break;
                case TokenType.IF:
                    Match(ref matchToken, TokenType.IF);
                    ITreeNode thenBranch;
                    ITreeNode elseBranch;

                    Match(ref matchToken, TokenType.LPAREN);
                    BooleanExpressionNode ifCondition = (BooleanExpressionNode)BooleanExpression();
                    Match(ref matchToken, TokenType.RPAREN);
                    Match(ref matchToken, TokenType.THEN);
                    thenBranch = (BlockNode)Program();
                    if (curTokenType == TokenType.ELSE)
                    {
                        Match(ref matchToken, TokenType.ELSE);
                        elseBranch = (BlockNode)Program();
                    }
                    else
                    {
                        elseBranch = new BlankNode();
                    }
                    programNode = new IfNode(ifCondition, thenBranch, elseBranch);
                    break;
                /*case TokenType.LET:
                    Match(ref matchToken, TokenType.LET);
                    IdentifierNode shortId = (IdentifierNode)Factor();
                    Match(ref matchToken, TokenType.ASSIGN);
                    BooleanExpressionNode subst = (BooleanExpressionNode)BooleanExpression();
                    Match(ref matchToken, TokenType.IN);
                    BooleanExpressionNode target = (BooleanExpressionNode)BooleanExpression();
                    programNode = new LetNode(shortId, subst, target);
                    Match(ref matchToken, TokenType.EOS);
                    break;*/
                case TokenType.PRINT:
                    Match(ref matchToken, TokenType.PRINT);
                    Match(ref matchToken, TokenType.LPAREN);
                    BooleanExpressionNode printArgument = (BooleanExpressionNode)BooleanExpression();
                    Match(ref matchToken, TokenType.RPAREN);
                    programNode = new PrintNode(printArgument);
                    Match(ref matchToken, TokenType.EOS);
                    break;
                case TokenType.WHILE:
                    Match(ref matchToken, TokenType.WHILE);
                    Match(ref matchToken, TokenType.LPAREN);
                    BooleanExpressionNode whileCondition = (BooleanExpressionNode)BooleanExpression();
                    Match(ref matchToken, TokenType.RPAREN);
                    BlockNode whileBody = (BlockNode)Program();
                    programNode = new WhileNode(whileCondition, whileBody);
                    break;
                case TokenType.EOF:
                    programNode = new BlankNode();
                    break;
                default:
                    Expect(TokenType.UNKNOWN, lookAheadToken);
                    break;
            }
            return programNode;
        }