diff --git a/loopy/frontend/fortran/translator.py b/loopy/frontend/fortran/translator.py
index 7183d97403552613bdf76169a951dbaa6ec674b0..af08f1dcabdc43055a2c8c285ea8fdd2ec744dd1 100644
--- a/loopy/frontend/fortran/translator.py
+++ b/loopy/frontend/fortran/translator.py
@@ -221,6 +221,8 @@ class F2LoopyTranslator(FTreeWalkerBase):
 
         self.index_dtype = None
 
+        self.block_nest = []
+
     def add_expression_instruction(self, lhs, rhs):
         scope = self.scope_stack[-1]
 
@@ -261,6 +263,7 @@ class F2LoopyTranslator(FTreeWalkerBase):
         scope = Scope(node.name, list(node.args))
         self.scope_stack.append(scope)
 
+        self.block_nest.append("sub")
         for c in node.content:
             self.rec(c)
 
@@ -269,6 +272,11 @@ class F2LoopyTranslator(FTreeWalkerBase):
         self.kernels.append(scope)
 
     def map_EndSubroutine(self, node):
+        if not self.block_nest:
+            raise TranslationError("no subroutine started at this point")
+        if self.block_nest.pop() != "sub":
+            raise TranslationError("mismatched end subroutine")
+
         return []
 
     def map_Implicit(self, node):
@@ -459,115 +467,126 @@ class F2LoopyTranslator(FTreeWalkerBase):
         for c in node.content:
             self.rec(c)
 
+        self.block_nest.append("if")
+
     def map_Else(self, node):
         cond_name = self.conditions.pop()
         self.conditions.append("!" + cond_name)
 
     def map_EndIfThen(self, node):
+        if not self.block_nest:
+            raise TranslationError("no if block started at end do")
+        if self.block_nest.pop() != "if":
+            raise TranslationError("mismatched end if")
+
         self.conditions.pop()
 
     def map_Do(self, node):
         scope = self.scope_stack[-1]
 
-        if node.loopcontrol:
-            loop_var, loop_bounds = node.loopcontrol.split("=")
-            loop_var = loop_var.strip()
-
-            iname_dtype = scope.get_type(loop_var)
-            if self.index_dtype is None:
-                self.index_dtype = iname_dtype
-            else:
-                if self.index_dtype != iname_dtype:
-                    raise LoopyError("type of '%s' (%s) does not agree with prior "
-                            "index type (%s)"
-                            % (loop_var, iname_dtype, self.index_dtype))
-
-            scope.use_name(loop_var)
-            loop_bounds = self.parse_expr(
-                    node,
-                    loop_bounds, min_precedence=self.expr_parser._PREC_FUNC_ARGS)
-
-            if len(loop_bounds) == 2:
-                start, stop = loop_bounds
-                step = 1
-            elif len(loop_bounds) == 3:
-                start, stop, step = loop_bounds
-            else:
-                raise RuntimeError("loop bounds not understood: %s"
-                        % node.loopcontrol)
+        if not node.loopcontrol:
+            raise NotImplementedError("unbounded do loop")
 
-            if step != 1:
-                raise NotImplementedError(
-                        "do loops with non-unit stride")
+        loop_var, loop_bounds = node.loopcontrol.split("=")
+        loop_var = loop_var.strip()
 
-            if not isinstance(step, int):
-                raise TranslationError(
-                        "non-constant steps not supported: %s" % step)
-
-            from loopy.symbolic import get_dependencies
-            loop_bound_deps = (
-                    get_dependencies(start)
-                    | get_dependencies(stop)
-                    | get_dependencies(step))
-
-            # {{{ find a usable loopy-side loop name
-
-            loopy_loop_var = loop_var
-            loop_var_suffix = None
-            while True:
-                already_used = False
-                for iset in scope.index_sets:
-                    if loopy_loop_var in iset.get_var_dict(dim_type.set):
-                        already_used = True
-                        break
-
-                if not already_used:
+        iname_dtype = scope.get_type(loop_var)
+        if self.index_dtype is None:
+            self.index_dtype = iname_dtype
+        else:
+            if self.index_dtype != iname_dtype:
+                raise LoopyError("type of '%s' (%s) does not agree with prior "
+                        "index type (%s)"
+                        % (loop_var, iname_dtype, self.index_dtype))
+
+        scope.use_name(loop_var)
+        loop_bounds = self.parse_expr(
+                node,
+                loop_bounds, min_precedence=self.expr_parser._PREC_FUNC_ARGS)
+
+        if len(loop_bounds) == 2:
+            start, stop = loop_bounds
+            step = 1
+        elif len(loop_bounds) == 3:
+            start, stop, step = loop_bounds
+        else:
+            raise RuntimeError("loop bounds not understood: %s"
+                    % node.loopcontrol)
+
+        if step != 1:
+            raise NotImplementedError(
+                    "do loops with non-unit stride")
+
+        if not isinstance(step, int):
+            raise TranslationError(
+                    "non-constant steps not supported: %s" % step)
+
+        from loopy.symbolic import get_dependencies
+        loop_bound_deps = (
+                get_dependencies(start)
+                | get_dependencies(stop)
+                | get_dependencies(step))
+
+        # {{{ find a usable loopy-side loop name
+
+        loopy_loop_var = loop_var
+        loop_var_suffix = None
+        while True:
+            already_used = False
+            for iset in scope.index_sets:
+                if loopy_loop_var in iset.get_var_dict(dim_type.set):
+                    already_used = True
                     break
 
-                if loop_var_suffix is None:
-                    loop_var_suffix = 0
+            if not already_used:
+                break
 
-                loop_var_suffix += 1
-                loopy_loop_var = loop_var + "_%d" % loop_var_suffix
+            if loop_var_suffix is None:
+                loop_var_suffix = 0
 
-            # }}}
+            loop_var_suffix += 1
+            loopy_loop_var = loop_var + "_%d" % loop_var_suffix
 
-            space = isl.Space.create_from_names(self.isl_context,
-                    set=[loopy_loop_var], params=list(loop_bound_deps))
-
-            from loopy.isl_helpers import iname_rel_aff
-            from loopy.symbolic import aff_from_expr
-            index_set = (
-                    isl.BasicSet.universe(space)
-                    .add_constraint(
-                        isl.Constraint.inequality_from_aff(
-                            iname_rel_aff(space,
-                                loopy_loop_var, ">=",
-                                aff_from_expr(space, 0))))
-                    .add_constraint(
-                        isl.Constraint.inequality_from_aff(
-                            iname_rel_aff(space,
-                                loopy_loop_var, "<=",
-                                aff_from_expr(space, stop-start)))))
-
-            from pymbolic import var
-            scope.active_iname_aliases[loop_var] = \
-                    var(loopy_loop_var) + start
-            scope.active_loopy_inames.add(loopy_loop_var)
-
-            scope.index_sets.append(index_set)
-
-            for c in node.content:
-                self.rec(c)
-
-            del scope.active_iname_aliases[loop_var]
-            scope.active_loopy_inames.remove(loopy_loop_var)
+        # }}}
 
-        else:
-            raise NotImplementedError("unbounded do loop")
+        space = isl.Space.create_from_names(self.isl_context,
+                set=[loopy_loop_var], params=list(loop_bound_deps))
+
+        from loopy.isl_helpers import iname_rel_aff
+        from loopy.symbolic import aff_from_expr
+        index_set = (
+                isl.BasicSet.universe(space)
+                .add_constraint(
+                    isl.Constraint.inequality_from_aff(
+                        iname_rel_aff(space,
+                            loopy_loop_var, ">=",
+                            aff_from_expr(space, 0))))
+                .add_constraint(
+                    isl.Constraint.inequality_from_aff(
+                        iname_rel_aff(space,
+                            loopy_loop_var, "<=",
+                            aff_from_expr(space, stop-start)))))
+
+        from pymbolic import var
+        scope.active_iname_aliases[loop_var] = \
+                var(loopy_loop_var) + start
+        scope.active_loopy_inames.add(loopy_loop_var)
+
+        scope.index_sets.append(index_set)
+
+        self.block_nest.append("do")
+
+        for c in node.content:
+            self.rec(c)
+
+        del scope.active_iname_aliases[loop_var]
+        scope.active_loopy_inames.remove(loopy_loop_var)
 
     def map_EndDo(self, node):
-        pass
+        if not self.block_nest:
+            raise TranslationError("no do loop started at end do")
+        if self.block_nest.pop() != "do":
+            raise TranslationError("mismatched end do")
 
     def map_Continue(self, node):
         raise NotImplementedError("continue")