  private static boolean checkControlFlow(Statement statement, Set<Variable> initializedVariables) throws ConceptualException
  {
    if (statement instanceof AssignStatement)
    {
      AssignStatement assign = (AssignStatement) statement;
      checkUninitializedVariables(assign.getExpression(), initializedVariables);
      initializedVariables.add(assign.getResolvedVariable());
      return false;
    }
    else if (statement instanceof Block)
    {
      boolean returned = false;
      for (Statement s : ((Block) statement).getStatements())
      {
        if (returned)
        {
          throw new ConceptualException("Unreachable code", s.getLexicalPhrase());
        }
        returned = checkControlFlow(s, initializedVariables);
      }
      return returned;
    }
    else if (statement instanceof IfStatement)
    {
      IfStatement ifStatement = (IfStatement) statement;
      checkUninitializedVariables(ifStatement.getExpression(), initializedVariables);
      Statement thenClause = ifStatement.getThenClause();
      Statement elseClause = ifStatement.getElseClause();
      if (elseClause == null)
      {
        Set<Variable> thenClauseVariables = new HashSet<Variable>(initializedVariables);
        checkControlFlow(thenClause, thenClauseVariables);
        return false;
      }
      Set<Variable> thenClauseVariables = new HashSet<Variable>(initializedVariables);
      Set<Variable> elseClauseVariables = new HashSet<Variable>(initializedVariables);
      boolean returned = checkControlFlow(thenClause, thenClauseVariables) & checkControlFlow(elseClause, elseClauseVariables);
      for (Variable var : thenClauseVariables)
      {
        if (elseClauseVariables.contains(var))
        {
          initializedVariables.add(var);
        }
      }
      return returned;
    }
    else if (statement instanceof ReturnStatement)
    {
      checkUninitializedVariables(((ReturnStatement) statement).getExpression(), initializedVariables);
      return true;
    }
    else if (statement instanceof VariableDefinition)
    {
      VariableDefinition definition = (VariableDefinition) statement;
      if (definition.getExpression() != null)
      {
        checkUninitializedVariables(definition.getExpression(), initializedVariables);
        initializedVariables.add(definition.getVariable());
      }
      return false;
    }
    else if (statement instanceof WhileStatement)
    {
      WhileStatement whileStatement = (WhileStatement) statement;
      checkUninitializedVariables(whileStatement.getExpression(), initializedVariables);
      Set<Variable> loopVariables = new HashSet<Variable>(initializedVariables);
      return checkControlFlow(whileStatement.getStatement(), loopVariables);
    }
    throw new ConceptualException("Internal control flow checking error: Unknown statement type", statement.getLexicalPhrase());
  }

  private static boolean checkControlFlow(Statement statement, Set<Variable> initializedVariables) throws ConceptualException
  {
    if (statement instanceof AssignStatement)
    {
      AssignStatement assign = (AssignStatement) statement;
      checkUninitializedVariables(assign.getExpression(), initializedVariables);
      initializedVariables.add(assign.getResolvedVariable());
      return false;
    }
    else if (statement instanceof Block)
    {
      boolean returned = false;
      for (Statement s : ((Block) statement).getStatements())
      {
        if (returned)
        {
          throw new ConceptualException("Unreachable code", s.getLexicalPhrase());
        }
        returned = checkControlFlow(s, initializedVariables);
      }
      return returned;
    }
    else if (statement instanceof IfStatement)
    {
      IfStatement ifStatement = (IfStatement) statement;
      checkUninitializedVariables(ifStatement.getExpression(), initializedVariables);
      Statement thenClause = ifStatement.getThenClause();
      Statement elseClause = ifStatement.getElseClause();
      if (elseClause == null)
      {
        Set<Variable> thenClauseVariables = new HashSet<Variable>(initializedVariables);
        checkControlFlow(thenClause, thenClauseVariables);
        return false;
      }
      Set<Variable> thenClauseVariables = new HashSet<Variable>(initializedVariables);
      Set<Variable> elseClauseVariables = new HashSet<Variable>(initializedVariables);
      boolean thenReturned = checkControlFlow(thenClause, thenClauseVariables);
      boolean elseReturned = checkControlFlow(elseClause, elseClauseVariables);
      if (!thenReturned && !elseReturned)
      {
        for (Variable var : thenClauseVariables)
        {
          if (elseClauseVariables.contains(var))
          {
            initializedVariables.add(var);
          }
        }
      }
      else if (!thenReturned && elseReturned)
      {
        initializedVariables.addAll(thenClauseVariables);
      }
      else if (thenReturned && !elseReturned)
      {
        initializedVariables.addAll(elseClauseVariables);
      }
      return thenReturned && elseReturned;
    }
    else if (statement instanceof ReturnStatement)
    {
      checkUninitializedVariables(((ReturnStatement) statement).getExpression(), initializedVariables);
      return true;
    }
    else if (statement instanceof VariableDefinition)
    {
      VariableDefinition definition = (VariableDefinition) statement;
      if (definition.getExpression() != null)
      {
        checkUninitializedVariables(definition.getExpression(), initializedVariables);
        initializedVariables.add(definition.getVariable());
      }
      return false;
    }
    else if (statement instanceof WhileStatement)
    {
      WhileStatement whileStatement = (WhileStatement) statement;
      checkUninitializedVariables(whileStatement.getExpression(), initializedVariables);
      Set<Variable> loopVariables = new HashSet<Variable>(initializedVariables);
      return checkControlFlow(whileStatement.getStatement(), loopVariables);
    }
    throw new ConceptualException("Internal control flow checking error: Unknown statement type", statement.getLexicalPhrase());
  }
