private Operand generate(BaseNode node) throws IRException {
        try {
            switch(node.nodeType()) {
                case BREAK:
                {
                    code.addStatement(
                        new GoToStatement(csi.endOfBlockLabel)
                    );
                    break;
                }
                case CONTINUE:
                {
                    code.addStatement(
                        new GoToStatement(csi.conditionLabel)
                    );
                    break;
                }
                case RETURN:
                {
                    generateReturn((ReturnNode) node);
                    break;
                }
                case FUNCTION_DECL:
                {
                    FunctionDeclNode function = (FunctionDeclNode) node;
                    varTable.add(new NamedVariable(
                        function.name,
                        function.realType()
                    ));
                    generateFunction(function);

                    break;
                }
                case BLOCK:
                {
                    scopes.enterBlock();
                    generateBlock((BlockNode<BaseNode>) node);
                    scopes.leaveBlock();
                    break;
                }
                case BLOCK_DECL:
                {
                    for(VariableDeclNode decl :
                            (BlockDeclNode<VariableDeclNode>) node) {

                        generate(decl);
                    }
                    break;
                }
                case VARIABLE:
                {
                    return new NamedVariableOperand(
                        varTable,
                        varTable.get(((VariableLeaf)node).name)
                    );
                }
                case VAR_DECL:
                {
                    declareVariable((VariableDeclNode) node);

                    break;
                }
                case UNARY_OPERATION:
                {
                    UnaryOperationNode u = (UnaryOperationNode)node;

                    Operand op = generate(u.node);

                    TmpVariableOperand result =
                        new TmpVariableOperand(
                            u.realType(),
                            varTable
                        );

                    code.addStatement(
                        new UnaryOperationStatement(
                            result,
                            op,
                            UnaryOperationStatement.operation(u.operation()))
                    );

                    return result;
                }
                case BINARY_OPERATION:
                {
                    BinaryOperationNode b = (BinaryOperationNode)node;

                    switch(b.operation()) {
                        case ARRAY_ELEMENT:
                        {
                            return generateArrayIndex(b);
                        }
                        /**
                         * tmp1 = ((a.i).j);
                         * a - address or value?
                         * a [MEMBER_SELECT] i - address or value?
                         * (a.i) [MEMBER_SELECT] j - address or value?
                         */
                        case MEMBER_SELECT:
                        {
                            return generateStructField(b);
                        }
                        case MINUS:
                        case DIV:
                        case MUL:
                        case MOD:
                        case PLUS:
                        case BITWISE_SHIFT_RIGHT:
                        case BITWISE_SHIFT_LEFT:
                        case GREATER:
                        case GREATER_OR_EQUAL:
                        case LESS:
                        case LESS_OR_EUQAL:
                        case NOT_EQUAL:
                        case EQUAL:
                        case BITWISE_AND:
                        case BITWISE_XOR:
                        case BITWISE_OR:
                        {
                            Operand left =
                                generate(b.leftChild());
                            Operand right =
                                generate(b.rightChild());

                            return generateBinaryOperation(
                                left,
                                right,
                                b.realType(),
                                BinaryOperationStatement.operation(
                                    b.operation()
                            ));
                        }
                        case BOOL_AND:
                        case BOOL_OR:
                        {
                            return generateBoolExpression(b);
                        }
                        case BITWISE_AND_ASSIGN:
                        case BITWISE_XOR_ASSIGN:
                        case BITWISE_SHIFT_RIGHT_ASSIGN:
                        case BITWISE_SHIFT_LEFT_ASSIGN:
                        case BITWISE_OR_ASSIGN:
                        case MOD_ASSIGN:
                        case DIV_ASSIGN:
                        case MUL_ASSIGN:
                        case MINUS_ASSIGN:
                        case PLUS_ASSIGN:
                        {
                            VariableOperand lhv =
                                generateLeftHandValue(b.leftChild());

                            VariableOperand left =
                                (VariableOperand)generate(b.leftChild());
                            VariableOperand right =
                                (VariableOperand) generate(b.rightChild());

                            if (left.type().is(PrimitiveType.Type.POINTER)) {
                                TmpVariableOperand value =
                                    new TmpVariableOperand(
                                        ((PointerType)left.type()).pointerType,
                                        varTable);

                                code.addStatement(
                                    new UnaryOperationStatement(
                                        left,
                                        value,
                                        UnaryOperationStatement.Operation.DEREF
                                    )
                                );

                                left = value;
                            }

                            Operand result = generateBinaryOperation(
                                left,
                                right,
                                b.realType(),
                                BinaryOperationStatement.operation(b.operation())
                            );


                            if(b.leftChild() instanceof VariableLeaf) {
                                code.addStatement(
                                    new AssignmentStatement(lhv, result)
                                );
                            } else {
                                code.addStatement(
                                    new IndirectAssignmentStatement(lhv, result)
                                );
                            }

                            return result;
                        }
                        case ASSIGN:
                        {
                            return generateAssignment(b);
                        }

                    }

                    break;
                }
                case IF:
                    generateIf((IfNode) node);
                    break;
                case FOR:
                    generateFor((ForNode) node);
                    break;
                case WHILE:
                    generateWhile((WhileNode) node);
                    break;
                case DO_WHILE:
                    generateDoWhile((DoWhileNode) node);
                    break;
                case SWITCH:
                    generateSwitch((SwitchNode) node);
                    break;
                case ELSE:
                {
                    ElseNode e = (ElseNode) node;
                    for(ru.bmstu.iu9.compiler.syntax.tree.Statement stmt :
                            e.block) {

                        generate(stmt.getNode());
                    }
                    break;
                }
                case CONSTANT:
                {
                    ConstantLeaf constant = (ConstantLeaf)node;

                    switch(constant.constantType()) {
                        case INT:
                        {
                            return new ConstantOperand(
                                constant.realType(),
                                ((IntegerConstantLeaf)constant).value);
                        }
                        case DOUBLE:
                        {
                            return new ConstantOperand(
                                constant.realType(),
                                ((DoubleConstantLeaf)constant).value);
                        }
                        case CHAR:
                        {
                            return new ConstantOperand(
                                constant.realType(),
                                ((CharConstantLeaf)constant).value);
                        }
                        case BOOL:
                        {
                            return new ConstantOperand(
                                constant.realType(),
                                ((BoolConstantLeaf)constant).value);
                        }
                        default:
                            // @todo Report an error
                            break;
                    }
                }
                case CALL:
                {
                    return generateCall((CallNode) node);
                }
                default:
                {
                    // @todo Report an error
                    break;
                }
            }
        } catch(IRException ex) {
            throw ex;
        } catch(Exception ex) {
            throw (NonGenerationException)new NonGenerationException(ex)
                    .Log("ru.bmstu.iu9.compiler.ir");
        }
        return null;
    }