[flang] First implementation of a parse tree visitor
authorTim Keith <tkeith@nvidia.com>
Fri, 23 Feb 2018 01:00:56 +0000 (17:00 -0800)
committerGitHub <noreply@github.com>
Mon, 26 Feb 2018 22:52:27 +0000 (14:52 -0800)
Original-commit: flang-compiler/f18@0b441831f455b9458a943090d7e9ed334aaf159c
Reviewed-on: https://github.com/flang-compiler/f18/pull/15
Tree-same-pre-rewrite: false

flang/lib/parser/parse-tree-visitor.h [new file with mode: 0644]
flang/tools/f18/test-visitor.cc [new file with mode: 0644]

diff --git a/flang/lib/parser/parse-tree-visitor.h b/flang/lib/parser/parse-tree-visitor.h
new file mode 100644 (file)
index 0000000..95eeb78
--- /dev/null
@@ -0,0 +1,3272 @@
+#ifndef FORTRAN_PARSE_TREE_VISITOR_H_
+#define FORTRAN_PARSE_TREE_VISITOR_H_
+
+#include "format-specification.h"
+#include "parse-tree.h"
+#include <optional>
+#include <tuple>
+#include <variant>
+
+/// Parse tree visitor
+/// Call visit(x, visitor) to visit each node under x.
+///
+/// visitor.pre(x) is called before visiting x and its children are not
+/// visited if it returns false.
+///
+/// visitor.post(x) is called after visiting x.
+
+namespace Fortran {
+namespace parser {
+
+namespace {
+
+// Helpers: generic visitor that is called if there is no specific one
+// and visitors for std::optional, std::list, and Indirection.
+
+template<typename T, typename V> void visit(const T &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visitor.post(x);
+  }
+}
+
+template<typename T, typename V>
+void visit(const std::optional<T> &x, V &visitor) {
+  if (x) {
+    visit(*x, visitor);
+  }
+}
+
+template<typename T, typename V> void visit(const std::list<T> &x, V &visitor) {
+  for (const auto &elem : x) {
+    visit(elem, visitor);
+  }
+}
+
+template<typename T, typename V>
+void visit(const Indirection<T> &x, V &visitor) {
+  visit(*x, visitor);
+}
+
+}  // namespace
+
+template<typename T, typename V> void visit(const Scalar<T> &x, V &visitor) {
+  visit(x.thing, visitor);
+}
+
+template<typename T, typename V> void visit(const Constant<T> &x, V &visitor) {
+  visit(x.thing, visitor);
+}
+
+template<typename T, typename V> void visit(const Integer<T> &x, V &visitor) {
+  visit(x.thing, visitor);
+}
+
+template<typename T, typename V> void visit(const Logical<T> &x, V &visitor) {
+  visit(x.thing, visitor);
+}
+
+template<typename T, typename V>
+void visit(const DefaultChar<T> &x, V &visitor) {
+  visit(x.thing, visitor);
+}
+
+template<typename T, typename V> void visit(const Statement<T> &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.statement, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename T, typename V>
+void visit(const LoopBounds<T> &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.name, visitor);
+    visit(x.lower, visitor);
+    visit(x.upper, visitor);
+    visit(x.step, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AcImpliedDo &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AcImpliedDoControl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AcSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.type, visitor);
+    visit(x.values, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AcValue &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AcValue::Triplet &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AccessId &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AccessStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ActionStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ActualArg &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ActualArg::PercentRef &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ActualArg::PercentVal &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ActualArgSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AllocOpt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AllocOpt::Mold &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AllocOpt::Source &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AllocatableStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AllocateCoarraySpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AllocateObject &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AllocateShapeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AllocateStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Allocation &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AltReturnSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ArithmeticIfStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ArrayConstructor &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ArrayElement &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.base, visitor);
+    visit(x.subscripts, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ArraySpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AssignStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AssignedGotoStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AssignmentStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AssociateConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AssociateStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Association &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AssumedImpliedSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AssumedShapeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AssumedSizeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AsynchronousStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const AttrSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BOZLiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BackspaceStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BasedPointerStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BindAttr &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BindEntity &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BindStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BlockConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BlockData &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BlockDataStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BlockSpecificationPart &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BlockStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BoundsRemapping &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const BoundsSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Call &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CallStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CaseConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CaseConstruct::Case &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CaseSelector &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CaseStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CaseValueRange &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ChangeTeamConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ChangeTeamStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CharLength &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CharLiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const CharLiteralConstantSubstring &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CharSelector &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const CharSelector::LengthAndKind &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.length, visitor);
+    visit(x.kind, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CharVariable &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CloseStmt::CloseSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CoarrayAssociation &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CoarraySpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CodimensionDecl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CodimensionStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CoindexedNamedObject &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.base, visitor);
+    visit(x.imageSelector, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CommonBlockObject &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CommonStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ComplexLiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ComplexPart &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ComponentArraySpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ComponentAttrSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ComponentDataSource &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ComponentDecl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visit(std::get<4>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ComponentDefStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ComponentSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ComputedGotoStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ConcurrentControl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ConcurrentHeader &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ConnectSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ConnectSpec::CharExpr &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ConnectSpec::Newunit &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ConnectSpec::Recl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ConstantValue &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ContiguousStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CriticalConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CriticalStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const CycleStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataComponentDefStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataIDoObject &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataImpliedDo &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataReference &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataStmtConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataStmtObject &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataStmtRepeat &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataStmtSet &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DataStmtValue &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DeallocateStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DeclarationConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DeclarationTypeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const DeclarationTypeSpec::Class &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.derived, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const DeclarationTypeSpec::Record &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const DeclarationTypeSpec::Type &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.derived, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DeferredCoshapeSpecList &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DeferredShapeSpecList &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DefinedOpName &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DefinedOperator &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DerivedTypeDef &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visit(std::get<4>(x.t), visitor);
+    visit(std::get<5>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DerivedTypeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DerivedTypeStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Designator &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const DimensionStmt::Declaration &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DoConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const DummyArg &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ElseIfStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ElseStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ElsewhereStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndAssociateStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndBlockDataStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndBlockStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndChangeTeamStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndCriticalStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndDoStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndForallStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndFunctionStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndIfStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndInterfaceStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndLabel &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndModuleStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndMpSubprogramStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndProgramStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndSelectStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndSubmoduleStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndSubroutineStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndTypeStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndWhereStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EndfileStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EntityDecl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visit(std::get<4>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EntryStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EnumDef &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Enumerator &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EnumeratorDefStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EorLabel &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EquivalenceObject &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EquivalenceStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ErrLabel &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EventPostStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const EventWaitStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const EventWaitStmt::EventWaitSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ExecutableConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ExecutionPartConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ExitStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ExplicitCoshapeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ExplicitShapeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ExponentPart &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::AND &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::Add &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::ComplexConstructor &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::Concat &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::DefinedBinary &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::DefinedUnary &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::Divide &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::EQ &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::EQV &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::GE &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::GT &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::IntrinsicBinary &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::IntrinsicUnary &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::LE &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::LT &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::Multiply &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::NE &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::NEQV &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::NOT &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicUnary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::Negate &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicUnary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::OR &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::Parentheses &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicUnary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::PercentLoc &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::Power &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::Subtract &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicBinary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Expr::UnaryPlus &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(static_cast<const Expr::IntrinsicUnary &>(x), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ExternalStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const FileUnitNumber &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const FinalProcedureStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const FlushStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ForallAssignmentStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ForallBodyConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ForallConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ForallConstructStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ForallStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const FormTeamStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const FormTeamStmt::FormTeamSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Format &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const FormatStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Fortran::ControlEditDesc &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.kind, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const Fortran::DerivedTypeDataEditDesc &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.type, visitor);
+    visit(x.parameters, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Fortran::FormatItem &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const Fortran::IntrinsicTypeDataEditDesc &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.kind, visitor);
+    visit(x.width, visitor);
+    visit(x.digits, visitor);
+    visit(x.exponentWidth, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const FunctionReference &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const FunctionStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const FunctionSubprogram &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visit(std::get<4>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const GenericSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const GenericStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const GotoStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IdExpr &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IdVariable &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IfConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visit(std::get<4>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IfConstruct::ElseBlock &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IfConstruct::ElseIfBlock &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IfStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IfThenStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImageSelector &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImageSelectorSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImageSelectorSpec::Stat &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImageSelectorSpec::Team &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const ImageSelectorSpec::Team_Number &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImplicitPart &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImplicitPartStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImplicitSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImplicitStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImpliedShapeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ImportStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.names, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Initialization &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InputImpliedDo &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InputItem &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InquireSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InquireSpec::CharVar &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InquireSpec::IntVar &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InquireSpec::LogVar &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InquireStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InquireStmt::Iolength &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IntLiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IntegerTypeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IntentStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InterfaceBlock &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InterfaceBody &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InterfaceBody::Function &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const InterfaceBody::Subroutine &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InterfaceSpecification &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InterfaceStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InternalSubprogram &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const InternalSubprogramPart &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IntrinsicStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IntrinsicTypeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const IntrinsicTypeSpec::Character &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.selector, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const IntrinsicTypeSpec::Complex &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.kind, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const IntrinsicTypeSpec::Logical &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.kind, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const IntrinsicTypeSpec::NCharacter &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IntrinsicTypeSpec::Real &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.kind, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IoControlSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const IoControlSpec::Asynchronous &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IoControlSpec::CharExpr &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IoControlSpec::Pos &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IoControlSpec::Rec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IoControlSpec::Size &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const IoUnit &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const KindParam &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LabelDoStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LanguageBindingSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LengthSelector &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LetterSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LocalitySpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LocalitySpec::Local &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LocalitySpec::LocalInit &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LocalitySpec::Shared &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LockStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LockStmt::LockStat &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LogicalLiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LoopControl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const LoopControl::Concurrent &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const MainProgram &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visit(std::get<4>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Map &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const MaskedElsewhereStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Module &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ModuleStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ModuleSubprogram &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ModuleSubprogramPart &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const MpSubprogramStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const MsgVariable &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const NamedConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const NamedConstantDef &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const NamelistStmt::Group &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const NonLabelDoStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const NullifyStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ObjectDecl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Only &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const OpenStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const OptionalStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const OtherSpecificationStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const OutputImpliedDo &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const OutputItem &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ParameterStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ParentIdentifier &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PartRef &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.name, visitor);
+    visit(x.subscripts, visitor);
+    visit(x.imageSelector, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Pass &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PauseStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PointerAssignmentStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const PointerAssignmentStmt::Bounds &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PointerDecl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PointerObject &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PointerStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PositionOrFlushSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PrefixSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PrintStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const PrivateOrSequence &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcAttrSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcComponentAttrSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcComponentDefStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcComponentRef &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcDecl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcInterface &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcPointerInit &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcedureDeclarationStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcedureDesignator &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProcedureStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Program &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProgramUnit &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ProtectedStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ReadStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.iounit, visitor);
+    visit(x.format, visitor);
+    visit(x.controls, visitor);
+    visit(x.items, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const RealLiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.intPart, visitor);
+    visit(x.fraction, visitor);
+    visit(x.exponent, visitor);
+    visit(x.kind, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const RedimensionStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Rename &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Rename::Names &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Rename::Operators &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ReturnStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const RewindStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SaveStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SavedEntity &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SectionSubscript &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SelectCaseStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SelectRankCaseStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SelectRankCaseStmt::Rank &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SelectRankConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const SelectRankConstruct::RankCase &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SelectRankStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SelectTypeConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const SelectTypeConstruct::TypeCase &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SelectTypeStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Selector &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SeparateModuleSubprogram &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visit(std::get<4>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const SignedComplexLiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SignedIntLiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const SignedRealLiteralConstant &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SpecificationConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SpecificationExpr &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SpecificationPart &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StatOrErrmsg &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StatVariable &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StatusExpr &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StmtFunctionStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StopCode &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StopStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StructureComponent &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.base, visitor);
+    visit(x.component, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StructureConstructor &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StructureDef &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StructureField &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const StructureStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Submodule &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SubmoduleStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SubroutineStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SubroutineSubprogram &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visit(std::get<4>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SubscriptTriplet &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Substring &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SubstringRange &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Suffix &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.binding, visitor);
+    visit(x.resultName, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SyncAllStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SyncImagesStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SyncImagesStmt::ImageSet &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SyncMemoryStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const SyncTeamStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TargetStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeAttrSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeAttrSpec::Extends &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.name, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeBoundGenericStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeBoundProcBinding &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeBoundProcDecl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeBoundProcedurePart &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeBoundProcedureStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const TypeBoundProcedureStmt::WithInterface &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.interfaceName, visitor);
+    visit(x.attributes, visitor);
+    visit(x.bindingNames, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const TypeBoundProcedureStmt::WithoutInterface &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.attributes, visitor);
+    visit(x.declarations, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeDeclarationStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeGuardStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeGuardStmt::Guard &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeParamDecl &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeParamDefStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeParamSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeParamValue &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const TypeSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Union &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const UnlockStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const UseStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const ValueStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const Variable &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const VolatileStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const WaitSpec &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const WaitStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.v, visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const WhereBodyConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    std::visit([&](const auto &y) { visit(y, visitor); }, x.u);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const WhereConstruct &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visit(std::get<2>(x.t), visitor);
+    visit(std::get<3>(x.t), visitor);
+    visit(std::get<4>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const WhereConstruct::Elsewhere &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V>
+void visit(const WhereConstruct::MaskedElsewhere &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const WhereConstructStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const WhereStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(std::get<0>(x.t), visitor);
+    visit(std::get<1>(x.t), visitor);
+    visitor.post(x);
+  }
+}
+
+template<typename V> void visit(const WriteStmt &x, V &visitor) {
+  if (visitor.pre(x)) {
+    visit(x.iounit, visitor);
+    visit(x.format, visitor);
+    visit(x.controls, visitor);
+    visit(x.items, visitor);
+    visitor.post(x);
+  }
+}
+
+}  // namespace parser
+}  // namespace Fortran
+#endif  // FORTRAN_PARSE_TREE_VISITOR_H_
diff --git a/flang/tools/f18/test-visitor.cc b/flang/tools/f18/test-visitor.cc
new file mode 100644 (file)
index 0000000..a0179a7
--- /dev/null
@@ -0,0 +1,2032 @@
+#include <iostream>
+#include "../../lib/parser/format-specification.h"
+#include "../../lib/parser/grammar.h"
+#include "../../lib/parser/idioms.h"
+#include "../../lib/parser/indirection.h"
+#include "../../lib/parser/message.h"
+#include "../../lib/parser/parse-state.h"
+#include "../../lib/parser/parse-tree-visitor.h"
+#include "../../lib/parser/parse-tree.h"
+#include "../../lib/parser/preprocessor.h"
+#include "../../lib/parser/prescan.h"
+#include "../../lib/parser/provenance.h"
+#include "../../lib/parser/source.h"
+#include "../../lib/parser/user-state.h"
+#include <cstdint>
+#include <cstdlib>
+#include <list>
+#include <optional>
+#include <sstream>
+#include <stddef.h>
+#include <string>
+
+using namespace Fortran::parser;
+
+// A visitor that visits all nodes in the parse tree and prints their
+// names, with children indented one space relative to their parent.
+class Visitor {
+  int indent_{0};
+  void out(const char *str) {
+    for (int i = 0; i < indent_; ++i) {
+      std::cout << ' ';
+    }
+    std::cout << str << '\n';
+    ++indent_;
+  }
+  void out(const std::string &str) {
+    out(str.c_str());
+  }
+
+public:
+
+  bool pre(const Abstract &x) {
+    out("Abstract");
+    return true;
+  }
+  bool pre(const AcImpliedDo &x) {
+    out("AcImpliedDo");
+    return true;
+  }
+  bool pre(const AcImpliedDoControl &x) {
+    out("AcImpliedDoControl");
+    return true;
+  }
+  bool pre(const AcSpec &x) {
+    out("AcSpec");
+    return true;
+  }
+  bool pre(const AcValue &x) {
+    out("AcValue");
+    return true;
+  }
+  bool pre(const AcValue::Triplet &x) {
+    out("AcValue::Triplet");
+    return true;
+  }
+  bool pre(const AccessId &x) {
+    out("AccessId");
+    return true;
+  }
+  bool pre(const AccessSpec &x) {
+    out("AccessSpec");
+    return true;
+  }
+  bool pre(const AccessStmt &x) {
+    out("AccessStmt");
+    return true;
+  }
+  bool pre(const ActionStmt &x) {
+    out("ActionStmt");
+    return true;
+  }
+  bool pre(const ActualArg &x) {
+    out("ActualArg");
+    return true;
+  }
+  bool pre(const ActualArg::PercentRef &x) {
+    out("ActualArg::PercentRef");
+    return true;
+  }
+  bool pre(const ActualArg::PercentVal &x) {
+    out("ActualArg::PercentVal");
+    return true;
+  }
+  bool pre(const ActualArgSpec &x) {
+    out("ActualArgSpec");
+    return true;
+  }
+  bool pre(const AllocOpt &x) {
+    out("AllocOpt");
+    return true;
+  }
+  bool pre(const AllocOpt::Mold &x) {
+    out("AllocOpt::Mold");
+    return true;
+  }
+  bool pre(const AllocOpt::Source &x) {
+    out("AllocOpt::Source");
+    return true;
+  }
+  bool pre(const Allocatable &x) {
+    out("Allocatable");
+    return true;
+  }
+  bool pre(const AllocatableStmt &x) {
+    out("AllocatableStmt");
+    return true;
+  }
+  bool pre(const AllocateCoarraySpec &x) {
+    out("AllocateCoarraySpec");
+    return true;
+  }
+  bool pre(const AllocateObject &x) {
+    out("AllocateObject");
+    return true;
+  }
+  bool pre(const AllocateShapeSpec &x) {
+    out("AllocateShapeSpec");
+    return true;
+  }
+  bool pre(const AllocateStmt &x) {
+    out("AllocateStmt");
+    return true;
+  }
+  bool pre(const Allocation &x) {
+    out("Allocation");
+    return true;
+  }
+  bool pre(const AltReturnSpec &x) {
+    out("AltReturnSpec");
+    return true;
+  }
+  bool pre(const ArithmeticIfStmt &x) {
+    out("ArithmeticIfStmt");
+    return true;
+  }
+  bool pre(const ArrayConstructor &x) {
+    out("ArrayConstructor");
+    return true;
+  }
+  bool pre(const ArrayElement &x) {
+    out("ArrayElement");
+    return true;
+  }
+  bool pre(const ArraySection &x) {
+    out("ArraySection");
+    return true;
+  }
+  bool pre(const ArraySpec &x) {
+    out("ArraySpec");
+    return true;
+  }
+  bool pre(const AssignStmt &x) {
+    out("AssignStmt");
+    return true;
+  }
+  bool pre(const AssignedGotoStmt &x) {
+    out("AssignedGotoStmt");
+    return true;
+  }
+  bool pre(const AssignmentStmt &x) {
+    out("AssignmentStmt");
+    return true;
+  }
+  bool pre(const AssociateConstruct &x) {
+    out("AssociateConstruct");
+    return true;
+  }
+  bool pre(const AssociateStmt &x) {
+    out("AssociateStmt");
+    return true;
+  }
+  bool pre(const Association &x) {
+    out("Association");
+    return true;
+  }
+  bool pre(const AssumedImpliedSpec &x) {
+    out("AssumedImpliedSpec");
+    return true;
+  }
+  bool pre(const AssumedRankSpec &x) {
+    out("AssumedRankSpec");
+    return true;
+  }
+  bool pre(const AssumedShapeSpec &x) {
+    out("AssumedShapeSpec");
+    return true;
+  }
+  bool pre(const AssumedSizeSpec &x) {
+    out("AssumedSizeSpec");
+    return true;
+  }
+  bool pre(const Asynchronous &x) {
+    out("Asynchronous");
+    return true;
+  }
+  bool pre(const AsynchronousStmt &x) {
+    out("AsynchronousStmt");
+    return true;
+  }
+  bool pre(const AttrSpec &x) {
+    out("AttrSpec");
+    return true;
+  }
+  bool pre(const BOZLiteralConstant &x) {
+    out("BOZLiteralConstant");
+    return true;
+  }
+  bool pre(const BackspaceStmt &x) {
+    out("BackspaceStmt");
+    return true;
+  }
+  bool pre(const BasedPointerStmt &x) {
+    out("BasedPointerStmt");
+    return true;
+  }
+  bool pre(const BindAttr &x) {
+    out("BindAttr");
+    return true;
+  }
+  bool pre(const BindAttr::Deferred &x) {
+    out("BindAttr::Deferred");
+    return true;
+  }
+  bool pre(const BindAttr::Non_Overridable &x) {
+    out("BindAttr::Non_Overridable");
+    return true;
+  }
+  bool pre(const BindEntity &x) {
+    out("BindEntity");
+    return true;
+  }
+  bool pre(const BindStmt &x) {
+    out("BindStmt");
+    return true;
+  }
+  bool pre(const BlockConstruct &x) {
+    out("BlockConstruct");
+    return true;
+  }
+  bool pre(const BlockData &x) {
+    out("BlockData");
+    return true;
+  }
+  bool pre(const BlockDataStmt &x) {
+    out("BlockDataStmt");
+    return true;
+  }
+  bool pre(const BlockSpecificationPart &x) {
+    out("BlockSpecificationPart");
+    return true;
+  }
+  bool pre(const BlockStmt &x) {
+    out("BlockStmt");
+    return true;
+  }
+  bool pre(const BoundsRemapping &x) {
+    out("BoundsRemapping");
+    return true;
+  }
+  bool pre(const BoundsSpec &x) {
+    out("BoundsSpec");
+    return true;
+  }
+  bool pre(const Call &x) {
+    out("Call");
+    return true;
+  }
+  bool pre(const CallStmt &x) {
+    out("CallStmt");
+    return true;
+  }
+  bool pre(const CaseConstruct &x) {
+    out("CaseConstruct");
+    return true;
+  }
+  bool pre(const CaseConstruct::Case &x) {
+    out("CaseConstruct::Case");
+    return true;
+  }
+  bool pre(const CaseSelector &x) {
+    out("CaseSelector");
+    return true;
+  }
+  bool pre(const CaseStmt &x) {
+    out("CaseStmt");
+    return true;
+  }
+  bool pre(const CaseValueRange &x) {
+    out("CaseValueRange");
+    return true;
+  }
+  bool pre(const CaseValueRange::Range &x) {
+    out("CaseValueRange::Range");
+    return true;
+  }
+  bool pre(const ChangeTeamConstruct &x) {
+    out("ChangeTeamConstruct");
+    return true;
+  }
+  bool pre(const ChangeTeamStmt &x) {
+    out("ChangeTeamStmt");
+    return true;
+  }
+  bool pre(const CharLength &x) {
+    out("CharLength");
+    return true;
+  }
+  bool pre(const CharLiteralConstant &x) {
+    out("CharLiteralConstant");
+    return true;
+  }
+  bool pre(const CharLiteralConstantSubstring &x) {
+    out("CharLiteralConstantSubstring");
+    return true;
+  }
+  bool pre(const CharSelector &x) {
+    out("CharSelector");
+    return true;
+  }
+  bool pre(const CharSelector::LengthAndKind &x) {
+    out("CharSelector::LengthAndKind");
+    return true;
+  }
+  bool pre(const CharVariable &x) {
+    out("CharVariable");
+    return true;
+  }
+  bool pre(const CloseStmt &x) {
+    out("CloseStmt");
+    return true;
+  }
+  bool pre(const CloseStmt::CloseSpec &x) {
+    out("CloseStmt::CloseSpec");
+    return true;
+  }
+  bool pre(const CoarrayAssociation &x) {
+    out("CoarrayAssociation");
+    return true;
+  }
+  bool pre(const CoarraySpec &x) {
+    out("CoarraySpec");
+    return true;
+  }
+  bool pre(const CodimensionDecl &x) {
+    out("CodimensionDecl");
+    return true;
+  }
+  bool pre(const CodimensionStmt &x) {
+    out("CodimensionStmt");
+    return true;
+  }
+  bool pre(const CoindexedNamedObject &x) {
+    out("CoindexedNamedObject");
+    return true;
+  }
+  bool pre(const CommonBlockObject &x) {
+    out("CommonBlockObject");
+    return true;
+  }
+  bool pre(const CommonStmt &x) {
+    out("CommonStmt");
+    return true;
+  }
+  bool pre(const ComplexLiteralConstant &x) {
+    out("ComplexLiteralConstant");
+    return true;
+  }
+  bool pre(const ComplexPart &x) {
+    out("ComplexPart");
+    return true;
+  }
+  bool pre(const ComplexPartDesignator &x) {
+    out("ComplexPartDesignator");
+    return true;
+  }
+  bool pre(const ComponentArraySpec &x) {
+    out("ComponentArraySpec");
+    return true;
+  }
+  bool pre(const ComponentAttrSpec &x) {
+    out("ComponentAttrSpec");
+    return true;
+  }
+  bool pre(const ComponentDataSource &x) {
+    out("ComponentDataSource");
+    return true;
+  }
+  bool pre(const ComponentDecl &x) {
+    out("ComponentDecl");
+    return true;
+  }
+  bool pre(const ComponentDefStmt &x) {
+    out("ComponentDefStmt");
+    return true;
+  }
+  bool pre(const ComponentSpec &x) {
+    out("ComponentSpec");
+    return true;
+  }
+  bool pre(const ComputedGotoStmt &x) {
+    out("ComputedGotoStmt");
+    return true;
+  }
+  bool pre(const ConcurrentControl &x) {
+    out("ConcurrentControl");
+    return true;
+  }
+  bool pre(const ConcurrentHeader &x) {
+    out("ConcurrentHeader");
+    return true;
+  }
+  bool pre(const ConnectSpec &x) {
+    out("ConnectSpec");
+    return true;
+  }
+  bool pre(const ConnectSpec::CharExpr &x) {
+    out("ConnectSpec::CharExpr");
+    return true;
+  }
+  bool pre(const ConnectSpec::Newunit &x) {
+    out("ConnectSpec::Newunit");
+    return true;
+  }
+  bool pre(const ConnectSpec::Recl &x) {
+    out("ConnectSpec::Recl");
+    return true;
+  }
+  bool pre(const ConstantValue &x) {
+    out("ConstantValue");
+    return true;
+  }
+  bool pre(const ContainsStmt &x) {
+    out("ContainsStmt");
+    return true;
+  }
+  bool pre(const Contiguous &x) {
+    out("Contiguous");
+    return true;
+  }
+  bool pre(const ContiguousStmt &x) {
+    out("ContiguousStmt");
+    return true;
+  }
+  bool pre(const ContinueStmt &x) {
+    out("ContinueStmt");
+    return true;
+  }
+  bool pre(const CriticalConstruct &x) {
+    out("CriticalConstruct");
+    return true;
+  }
+  bool pre(const CriticalStmt &x) {
+    out("CriticalStmt");
+    return true;
+  }
+  bool pre(const CycleStmt &x) {
+    out("CycleStmt");
+    return true;
+  }
+  bool pre(const DataComponentDefStmt &x) {
+    out("DataComponentDefStmt");
+    return true;
+  }
+  bool pre(const DataIDoObject &x) {
+    out("DataIDoObject");
+    return true;
+  }
+  bool pre(const DataImpliedDo &x) {
+    out("DataImpliedDo");
+    return true;
+  }
+  bool pre(const DataReference &x) {
+    out("DataReference");
+    return true;
+  }
+  bool pre(const DataStmt &x) {
+    out("DataStmt");
+    return true;
+  }
+  bool pre(const DataStmtConstant &x) {
+    out("DataStmtConstant");
+    return true;
+  }
+  bool pre(const DataStmtObject &x) {
+    out("DataStmtObject");
+    return true;
+  }
+  bool pre(const DataStmtRepeat &x) {
+    out("DataStmtRepeat");
+    return true;
+  }
+  bool pre(const DataStmtSet &x) {
+    out("DataStmtSet");
+    return true;
+  }
+  bool pre(const DataStmtValue &x) {
+    out("DataStmtValue");
+    return true;
+  }
+  bool pre(const DeallocateStmt &x) {
+    out("DeallocateStmt");
+    return true;
+  }
+  bool pre(const DeclarationConstruct &x) {
+    out("DeclarationConstruct");
+    return true;
+  }
+  bool pre(const DeclarationTypeSpec &x) {
+    out("DeclarationTypeSpec");
+    return true;
+  }
+  bool pre(const DeclarationTypeSpec::Class &x) {
+    out("DeclarationTypeSpec::Class");
+    return true;
+  }
+  bool pre(const DeclarationTypeSpec::ClassStar &x) {
+    out("DeclarationTypeSpec::ClassStar");
+    return true;
+  }
+  bool pre(const DeclarationTypeSpec::Record &x) {
+    out("DeclarationTypeSpec::Record");
+    return true;
+  }
+  bool pre(const DeclarationTypeSpec::Type &x) {
+    out("DeclarationTypeSpec::Type");
+    return true;
+  }
+  bool pre(const DeclarationTypeSpec::TypeStar &x) {
+    out("DeclarationTypeSpec::TypeStar");
+    return true;
+  }
+  bool pre(const Default &x) {
+    out("Default");
+    return true;
+  }
+  bool pre(const DeferredCoshapeSpecList &x) {
+    out("DeferredCoshapeSpecList");
+    return true;
+  }
+  bool pre(const DeferredShapeSpecList &x) {
+    out("DeferredShapeSpecList");
+    return true;
+  }
+  bool pre(const DefinedOpName &x) {
+    out("DefinedOpName");
+    return true;
+  }
+  bool pre(const DefinedOperator &x) {
+    out("DefinedOperator");
+    return true;
+  }
+  bool pre(const DerivedTypeDef &x) {
+    out("DerivedTypeDef");
+    return true;
+  }
+  bool pre(const DerivedTypeSpec &x) {
+    out("DerivedTypeSpec");
+    return true;
+  }
+  bool pre(const DerivedTypeStmt &x) {
+    out("DerivedTypeStmt");
+    return true;
+  }
+  bool pre(const Designator &x) {
+    out("Designator");
+    return true;
+  }
+  bool pre(const DimensionStmt &x) {
+    out("DimensionStmt");
+    return true;
+  }
+  bool pre(const DimensionStmt::Declaration &x) {
+    out("DimensionStmt::Declaration");
+    return true;
+  }
+  bool pre(const DoConstruct &x) {
+    out("DoConstruct");
+    return true;
+  }
+  bool pre(const DummyArg &x) {
+    out("DummyArg");
+    return true;
+  }
+  bool pre(const ElseIfStmt &x) {
+    out("ElseIfStmt");
+    return true;
+  }
+  bool pre(const ElseStmt &x) {
+    out("ElseStmt");
+    return true;
+  }
+  bool pre(const ElsewhereStmt &x) {
+    out("ElsewhereStmt");
+    return true;
+  }
+  bool pre(const EndAssociateStmt &x) {
+    out("EndAssociateStmt");
+    return true;
+  }
+  bool pre(const EndBlockDataStmt &x) {
+    out("EndBlockDataStmt");
+    return true;
+  }
+  bool pre(const EndBlockStmt &x) {
+    out("EndBlockStmt");
+    return true;
+  }
+  bool pre(const EndChangeTeamStmt &x) {
+    out("EndChangeTeamStmt");
+    return true;
+  }
+  bool pre(const EndCriticalStmt &x) {
+    out("EndCriticalStmt");
+    return true;
+  }
+  bool pre(const EndDoStmt &x) {
+    out("EndDoStmt");
+    return true;
+  }
+  bool pre(const EndEnumStmt &x) {
+    out("EndEnumStmt");
+    return true;
+  }
+  bool pre(const EndForallStmt &x) {
+    out("EndForallStmt");
+    return true;
+  }
+  bool pre(const EndFunctionStmt &x) {
+    out("EndFunctionStmt");
+    return true;
+  }
+  bool pre(const EndIfStmt &x) {
+    out("EndIfStmt");
+    return true;
+  }
+  bool pre(const EndInterfaceStmt &x) {
+    out("EndInterfaceStmt");
+    return true;
+  }
+  bool pre(const EndLabel &x) {
+    out("EndLabel");
+    return true;
+  }
+  bool pre(const EndModuleStmt &x) {
+    out("EndModuleStmt");
+    return true;
+  }
+  bool pre(const EndMpSubprogramStmt &x) {
+    out("EndMpSubprogramStmt");
+    return true;
+  }
+  bool pre(const EndProgramStmt &x) {
+    out("EndProgramStmt");
+    return true;
+  }
+  bool pre(const EndSelectStmt &x) {
+    out("EndSelectStmt");
+    return true;
+  }
+  bool pre(const EndSubmoduleStmt &x) {
+    out("EndSubmoduleStmt");
+    return true;
+  }
+  bool pre(const EndSubroutineStmt &x) {
+    out("EndSubroutineStmt");
+    return true;
+  }
+  bool pre(const EndTypeStmt &x) {
+    out("EndTypeStmt");
+    return true;
+  }
+  bool pre(const EndWhereStmt &x) {
+    out("EndWhereStmt");
+    return true;
+  }
+  bool pre(const EndfileStmt &x) {
+    out("EndfileStmt");
+    return true;
+  }
+  bool pre(const EntityDecl &x) {
+    out("EntityDecl");
+    return true;
+  }
+  bool pre(const EntryStmt &x) {
+    out("EntryStmt");
+    return true;
+  }
+  bool pre(const EnumDef &x) {
+    out("EnumDef");
+    return true;
+  }
+  bool pre(const EnumDefStmt &x) {
+    out("EnumDefStmt");
+    return true;
+  }
+  bool pre(const Enumerator &x) {
+    out("Enumerator");
+    return true;
+  }
+  bool pre(const EnumeratorDefStmt &x) {
+    out("EnumeratorDefStmt");
+    return true;
+  }
+  bool pre(const EorLabel &x) {
+    out("EorLabel");
+    return true;
+  }
+  bool pre(const EquivalenceObject &x) {
+    out("EquivalenceObject");
+    return true;
+  }
+  bool pre(const EquivalenceStmt &x) {
+    out("EquivalenceStmt");
+    return true;
+  }
+  bool pre(const ErrLabel &x) {
+    out("ErrLabel");
+    return true;
+  }
+  bool pre(const ErrorRecovery &x) {
+    out("ErrorRecovery");
+    return true;
+  }
+  bool pre(const EventPostStmt &x) {
+    out("EventPostStmt");
+    return true;
+  }
+  bool pre(const EventWaitStmt &x) {
+    out("EventWaitStmt");
+    return true;
+  }
+  bool pre(const EventWaitStmt::EventWaitSpec &x) {
+    out("EventWaitStmt::EventWaitSpec");
+    return true;
+  }
+  bool pre(const ExecutableConstruct &x) {
+    out("ExecutableConstruct");
+    return true;
+  }
+  bool pre(const ExecutionPartConstruct &x) {
+    out("ExecutionPartConstruct");
+    return true;
+  }
+  bool pre(const ExitStmt &x) {
+    out("ExitStmt");
+    return true;
+  }
+  bool pre(const ExplicitCoshapeSpec &x) {
+    out("ExplicitCoshapeSpec");
+    return true;
+  }
+  bool pre(const ExplicitShapeSpec &x) {
+    out("ExplicitShapeSpec");
+    return true;
+  }
+  bool pre(const ExponentPart &x) {
+    out("ExponentPart");
+    return true;
+  }
+  bool pre(const Expr &x) {
+    out("Expr");
+    return true;
+  }
+  bool pre(const Expr::AND &x) {
+    out("Expr::AND");
+    return true;
+  }
+  bool pre(const Expr::Add &x) {
+    out("Expr::Add");
+    return true;
+  }
+  bool pre(const Expr::ComplexConstructor &x) {
+    out("Expr::ComplexConstructor");
+    return true;
+  }
+  bool pre(const Expr::Concat &x) {
+    out("Expr::Concat");
+    return true;
+  }
+  bool pre(const Expr::DefinedBinary &x) {
+    out("Expr::DefinedBinary");
+    return true;
+  }
+  bool pre(const Expr::DefinedUnary &x) {
+    out("Expr::DefinedUnary");
+    return true;
+  }
+  bool pre(const Expr::Divide &x) {
+    out("Expr::Divide");
+    return true;
+  }
+  bool pre(const Expr::EQ &x) {
+    out("Expr::EQ");
+    return true;
+  }
+  bool pre(const Expr::EQV &x) {
+    out("Expr::EQV");
+    return true;
+  }
+  bool pre(const Expr::GE &x) {
+    out("Expr::GE");
+    return true;
+  }
+  bool pre(const Expr::GT &x) {
+    out("Expr::GT");
+    return true;
+  }
+  bool pre(const Expr::IntrinsicBinary &x) {
+    out("Expr::IntrinsicBinary");
+    return true;
+  }
+  bool pre(const Expr::IntrinsicUnary &x) {
+    out("Expr::IntrinsicUnary");
+    return true;
+  }
+  bool pre(const Expr::LE &x) {
+    out("Expr::LE");
+    return true;
+  }
+  bool pre(const Expr::LT &x) {
+    out("Expr::LT");
+    return true;
+  }
+  bool pre(const Expr::Multiply &x) {
+    out("Expr::Multiply");
+    return true;
+  }
+  bool pre(const Expr::NE &x) {
+    out("Expr::NE");
+    return true;
+  }
+  bool pre(const Expr::NEQV &x) {
+    out("Expr::NEQV");
+    return true;
+  }
+  bool pre(const Expr::NOT &x) {
+    out("Expr::NOT");
+    return true;
+  }
+  bool pre(const Expr::Negate &x) {
+    out("Expr::Negate");
+    return true;
+  }
+  bool pre(const Expr::OR &x) {
+    out("Expr::OR");
+    return true;
+  }
+  bool pre(const Expr::Parentheses &x) {
+    out("Expr::Parentheses");
+    return true;
+  }
+  bool pre(const Expr::PercentLoc &x) {
+    out("Expr::PercentLoc");
+    return true;
+  }
+  bool pre(const Expr::Power &x) {
+    out("Expr::Power");
+    return true;
+  }
+  bool pre(const Expr::Subtract &x) {
+    out("Expr::Subtract");
+    return true;
+  }
+  bool pre(const Expr::UnaryPlus &x) {
+    out("Expr::UnaryPlus");
+    return true;
+  }
+  bool pre(const External &x) {
+    out("External");
+    return true;
+  }
+  bool pre(const ExternalStmt &x) {
+    out("ExternalStmt");
+    return true;
+  }
+  bool pre(const FailImageStmt &x) {
+    out("FailImageStmt");
+    return true;
+  }
+  bool pre(const FileUnitNumber &x) {
+    out("FileUnitNumber");
+    return true;
+  }
+  bool pre(const FinalProcedureStmt &x) {
+    out("FinalProcedureStmt");
+    return true;
+  }
+  bool pre(const FlushStmt &x) {
+    out("FlushStmt");
+    return true;
+  }
+  bool pre(const ForallAssignmentStmt &x) {
+    out("ForallAssignmentStmt");
+    return true;
+  }
+  bool pre(const ForallBodyConstruct &x) {
+    out("ForallBodyConstruct");
+    return true;
+  }
+  bool pre(const ForallConstruct &x) {
+    out("ForallConstruct");
+    return true;
+  }
+  bool pre(const ForallConstructStmt &x) {
+    out("ForallConstructStmt");
+    return true;
+  }
+  bool pre(const ForallStmt &x) {
+    out("ForallStmt");
+    return true;
+  }
+  bool pre(const FormTeamStmt &x) {
+    out("FormTeamStmt");
+    return true;
+  }
+  bool pre(const FormTeamStmt::FormTeamSpec &x) {
+    out("FormTeamStmt::FormTeamSpec");
+    return true;
+  }
+  bool pre(const Format &x) {
+    out("Format");
+    return true;
+  }
+  bool pre(const FormatStmt &x) {
+    out("FormatStmt");
+    return true;
+  }
+  bool pre(const Fortran::ControlEditDesc &x) {
+    out("Fortran::ControlEditDesc");
+    return true;
+  }
+  bool pre(const Fortran::DerivedTypeDataEditDesc &x) {
+    out("Fortran::DerivedTypeDataEditDesc");
+    return true;
+  }
+  bool pre(const Fortran::FormatItem &x) {
+    out("Fortran::FormatItem");
+    return true;
+  }
+  bool pre(const Fortran::FormatSpecification &x) {
+    out("Fortran::FormatSpecification");
+    return true;
+  }
+  bool pre(const Fortran::IntrinsicTypeDataEditDesc &x) {
+    out("Fortran::IntrinsicTypeDataEditDesc");
+    return true;
+  }
+  bool pre(const FunctionReference &x) {
+    out("FunctionReference");
+    return true;
+  }
+  bool pre(const FunctionStmt &x) {
+    out("FunctionStmt");
+    return true;
+  }
+  bool pre(const FunctionSubprogram &x) {
+    out("FunctionSubprogram");
+    return true;
+  }
+  bool pre(const GenericSpec &x) {
+    out("GenericSpec");
+    return true;
+  }
+  bool pre(const GenericSpec::Assignment &x) {
+    out("GenericSpec::Assignment");
+    return true;
+  }
+  bool pre(const GenericSpec::ReadFormatted &x) {
+    out("GenericSpec::ReadFormatted");
+    return true;
+  }
+  bool pre(const GenericSpec::ReadUnformatted &x) {
+    out("GenericSpec::ReadUnformatted");
+    return true;
+  }
+  bool pre(const GenericSpec::WriteFormatted &x) {
+    out("GenericSpec::WriteFormatted");
+    return true;
+  }
+  bool pre(const GenericSpec::WriteUnformatted &x) {
+    out("GenericSpec::WriteUnformatted");
+    return true;
+  }
+  bool pre(const GenericStmt &x) {
+    out("GenericStmt");
+    return true;
+  }
+  bool pre(const GotoStmt &x) {
+    out("GotoStmt");
+    return true;
+  }
+  bool pre(const HollerithLiteralConstant &x) {
+    out("HollerithLiteralConstant");
+    return true;
+  }
+  bool pre(const IdExpr &x) {
+    out("IdExpr");
+    return true;
+  }
+  bool pre(const IdVariable &x) {
+    out("IdVariable");
+    return true;
+  }
+  bool pre(const IfConstruct &x) {
+    out("IfConstruct");
+    return true;
+  }
+  bool pre(const IfConstruct::ElseBlock &x) {
+    out("IfConstruct::ElseBlock");
+    return true;
+  }
+  bool pre(const IfConstruct::ElseIfBlock &x) {
+    out("IfConstruct::ElseIfBlock");
+    return true;
+  }
+  bool pre(const IfStmt &x) {
+    out("IfStmt");
+    return true;
+  }
+  bool pre(const IfThenStmt &x) {
+    out("IfThenStmt");
+    return true;
+  }
+  bool pre(const ImageSelector &x) {
+    out("ImageSelector");
+    return true;
+  }
+  bool pre(const ImageSelectorSpec &x) {
+    out("ImageSelectorSpec");
+    return true;
+  }
+  bool pre(const ImageSelectorSpec::Stat &x) {
+    out("ImageSelectorSpec::Stat");
+    return true;
+  }
+  bool pre(const ImageSelectorSpec::Team &x) {
+    out("ImageSelectorSpec::Team");
+    return true;
+  }
+  bool pre(const ImageSelectorSpec::Team_Number &x) {
+    out("ImageSelectorSpec::Team_Number");
+    return true;
+  }
+  bool pre(const ImplicitPart &x) {
+    out("ImplicitPart");
+    return true;
+  }
+  bool pre(const ImplicitPartStmt &x) {
+    out("ImplicitPartStmt");
+    return true;
+  }
+  bool pre(const ImplicitSpec &x) {
+    out("ImplicitSpec");
+    return true;
+  }
+  bool pre(const ImplicitStmt &x) {
+    out("ImplicitStmt");
+    return true;
+  }
+  bool pre(const ImpliedShapeSpec &x) {
+    out("ImpliedShapeSpec");
+    return true;
+  }
+  bool pre(const ImportStmt &x) {
+    out("ImportStmt");
+    return true;
+  }
+  bool pre(const Initialization &x) {
+    out("Initialization");
+    return true;
+  }
+  bool pre(const InputImpliedDo &x) {
+    out("InputImpliedDo");
+    return true;
+  }
+  bool pre(const InputItem &x) {
+    out("InputItem");
+    return true;
+  }
+  bool pre(const InquireSpec &x) {
+    out("InquireSpec");
+    return true;
+  }
+  bool pre(const InquireSpec::CharVar &x) {
+    out("InquireSpec::CharVar");
+    return true;
+  }
+  bool pre(const InquireSpec::IntVar &x) {
+    out("InquireSpec::IntVar");
+    return true;
+  }
+  bool pre(const InquireSpec::LogVar &x) {
+    out("InquireSpec::LogVar");
+    return true;
+  }
+  bool pre(const InquireStmt &x) {
+    out("InquireStmt");
+    return true;
+  }
+  bool pre(const InquireStmt::Iolength &x) {
+    out("InquireStmt::Iolength");
+    return true;
+  }
+  bool pre(const IntLiteralConstant &x) {
+    out("IntLiteralConstant");
+    return true;
+  }
+  bool pre(const IntegerTypeSpec &x) {
+    out("IntegerTypeSpec");
+    return true;
+  }
+  bool pre(const IntentSpec &x) {
+    out("IntentSpec");
+    return true;
+  }
+  bool pre(const IntentStmt &x) {
+    out("IntentStmt");
+    return true;
+  }
+  bool pre(const InterfaceBlock &x) {
+    out("InterfaceBlock");
+    return true;
+  }
+  bool pre(const InterfaceBody &x) {
+    out("InterfaceBody");
+    return true;
+  }
+  bool pre(const InterfaceBody::Function &x) {
+    out("InterfaceBody::Function");
+    return true;
+  }
+  bool pre(const InterfaceBody::Subroutine &x) {
+    out("InterfaceBody::Subroutine");
+    return true;
+  }
+  bool pre(const InterfaceSpecification &x) {
+    out("InterfaceSpecification");
+    return true;
+  }
+  bool pre(const InterfaceStmt &x) {
+    out("InterfaceStmt");
+    return true;
+  }
+  bool pre(const InternalSubprogram &x) {
+    out("InternalSubprogram");
+    return true;
+  }
+  bool pre(const InternalSubprogramPart &x) {
+    out("InternalSubprogramPart");
+    return true;
+  }
+  bool pre(const Intrinsic &x) {
+    out("Intrinsic");
+    return true;
+  }
+  bool pre(const IntrinsicStmt &x) {
+    out("IntrinsicStmt");
+    return true;
+  }
+  bool pre(const IntrinsicTypeSpec &x) {
+    out("IntrinsicTypeSpec");
+    return true;
+  }
+  bool pre(const IntrinsicTypeSpec::Character &x) {
+    out("IntrinsicTypeSpec::Character");
+    return true;
+  }
+  bool pre(const IntrinsicTypeSpec::Complex &x) {
+    out("IntrinsicTypeSpec::Complex");
+    return true;
+  }
+  bool pre(const IntrinsicTypeSpec::DoubleComplex &x) {
+    out("IntrinsicTypeSpec::DoubleComplex");
+    return true;
+  }
+  bool pre(const IntrinsicTypeSpec::DoublePrecision &x) {
+    out("IntrinsicTypeSpec::DoublePrecision");
+    return true;
+  }
+  bool pre(const IntrinsicTypeSpec::Logical &x) {
+    out("IntrinsicTypeSpec::Logical");
+    return true;
+  }
+  bool pre(const IntrinsicTypeSpec::NCharacter &x) {
+    out("IntrinsicTypeSpec::NCharacter");
+    return true;
+  }
+  bool pre(const IntrinsicTypeSpec::Real &x) {
+    out("IntrinsicTypeSpec::Real");
+    return true;
+  }
+  bool pre(const IoControlSpec &x) {
+    out("IoControlSpec");
+    return true;
+  }
+  bool pre(const IoControlSpec::Asynchronous &x) {
+    out("IoControlSpec::Asynchronous");
+    return true;
+  }
+  bool pre(const IoControlSpec::CharExpr &x) {
+    out("IoControlSpec::CharExpr");
+    return true;
+  }
+  bool pre(const IoControlSpec::Pos &x) {
+    out("IoControlSpec::Pos");
+    return true;
+  }
+  bool pre(const IoControlSpec::Rec &x) {
+    out("IoControlSpec::Rec");
+    return true;
+  }
+  bool pre(const IoControlSpec::Size &x) {
+    out("IoControlSpec::Size");
+    return true;
+  }
+  bool pre(const IoUnit &x) {
+    out("IoUnit");
+    return true;
+  }
+  bool pre(const KindParam &x) {
+    out("KindParam");
+    return true;
+  }
+  bool pre(const KindParam::Kanji &x) {
+    out("KindParam::Kanji");
+    return true;
+  }
+  bool pre(const KindSelector &x) {
+    out("KindSelector");
+    return true;
+  }
+  bool pre(const LabelDoStmt &x) {
+    out("LabelDoStmt");
+    return true;
+  }
+  bool pre(const LanguageBindingSpec &x) {
+    out("LanguageBindingSpec");
+    return true;
+  }
+  bool pre(const LengthSelector &x) {
+    out("LengthSelector");
+    return true;
+  }
+  bool pre(const LetterSpec &x) {
+    out("LetterSpec");
+    return true;
+  }
+  bool pre(const LiteralConstant &x) {
+    out("LiteralConstant");
+    return true;
+  }
+  bool pre(const LocalitySpec &x) {
+    out("LocalitySpec");
+    return true;
+  }
+  bool pre(const LocalitySpec::DefaultNone &x) {
+    out("LocalitySpec::DefaultNone");
+    return true;
+  }
+  bool pre(const LocalitySpec::Local &x) {
+    out("LocalitySpec::Local");
+    return true;
+  }
+  bool pre(const LocalitySpec::LocalInit &x) {
+    out("LocalitySpec::LocalInit");
+    return true;
+  }
+  bool pre(const LocalitySpec::Shared &x) {
+    out("LocalitySpec::Shared");
+    return true;
+  }
+  bool pre(const LockStmt &x) {
+    out("LockStmt");
+    return true;
+  }
+  bool pre(const LockStmt::LockStat &x) {
+    out("LockStmt::LockStat");
+    return true;
+  }
+  bool pre(const LogicalLiteralConstant &x) {
+    out("LogicalLiteralConstant");
+    return true;
+  }
+  bool pre(const LoopControl &x) {
+    out("LoopControl");
+    return true;
+  }
+  bool pre(const LoopControl::Concurrent &x) {
+    out("LoopControl::Concurrent");
+    return true;
+  }
+  bool pre(const MainProgram &x) {
+    out("MainProgram");
+    return true;
+  }
+  bool pre(const Map &x) {
+    out("Map");
+    return true;
+  }
+  bool pre(const Map::EndMapStmt &x) {
+    out("Map::EndMapStmt");
+    return true;
+  }
+  bool pre(const Map::MapStmt &x) {
+    out("Map::MapStmt");
+    return true;
+  }
+  bool pre(const MaskedElsewhereStmt &x) {
+    out("MaskedElsewhereStmt");
+    return true;
+  }
+  bool pre(const Module &x) {
+    out("Module");
+    return true;
+  }
+  bool pre(const ModuleStmt &x) {
+    out("ModuleStmt");
+    return true;
+  }
+  bool pre(const ModuleSubprogram &x) {
+    out("ModuleSubprogram");
+    return true;
+  }
+  bool pre(const ModuleSubprogramPart &x) {
+    out("ModuleSubprogramPart");
+    return true;
+  }
+  bool pre(const MpSubprogramStmt &x) {
+    out("MpSubprogramStmt");
+    return true;
+  }
+  bool pre(const MsgVariable &x) {
+    out("MsgVariable");
+    return true;
+  }
+  bool pre(const NamedConstant &x) {
+    out("NamedConstant");
+    return true;
+  }
+  bool pre(const NamedConstantDef &x) {
+    out("NamedConstantDef");
+    return true;
+  }
+  bool pre(const NamelistStmt &x) {
+    out("NamelistStmt");
+    return true;
+  }
+  bool pre(const NamelistStmt::Group &x) {
+    out("NamelistStmt::Group");
+    return true;
+  }
+  bool pre(const NoPass &x) {
+    out("NoPass");
+    return true;
+  }
+  bool pre(const NonLabelDoStmt &x) {
+    out("NonLabelDoStmt");
+    return true;
+  }
+  bool pre(const NullInit &x) {
+    out("NullInit");
+    return true;
+  }
+  bool pre(const NullifyStmt &x) {
+    out("NullifyStmt");
+    return true;
+  }
+  bool pre(const ObjectDecl &x) {
+    out("ObjectDecl");
+    return true;
+  }
+  bool pre(const Only &x) {
+    out("Only");
+    return true;
+  }
+  bool pre(const OpenStmt &x) {
+    out("OpenStmt");
+    return true;
+  }
+  bool pre(const Optional &x) {
+    out("Optional");
+    return true;
+  }
+  bool pre(const OptionalStmt &x) {
+    out("OptionalStmt");
+    return true;
+  }
+  bool pre(const OtherSpecificationStmt &x) {
+    out("OtherSpecificationStmt");
+    return true;
+  }
+  bool pre(const OutputImpliedDo &x) {
+    out("OutputImpliedDo");
+    return true;
+  }
+  bool pre(const OutputItem &x) {
+    out("OutputItem");
+    return true;
+  }
+  bool pre(const Parameter &x) {
+    out("Parameter");
+    return true;
+  }
+  bool pre(const ParameterStmt &x) {
+    out("ParameterStmt");
+    return true;
+  }
+  bool pre(const ParentIdentifier &x) {
+    out("ParentIdentifier");
+    return true;
+  }
+  bool pre(const PartRef &x) {
+    out("PartRef");
+    return true;
+  }
+  bool pre(const Pass &x) {
+    out("Pass");
+    return true;
+  }
+  bool pre(const PauseStmt &x) {
+    out("PauseStmt");
+    return true;
+  }
+  bool pre(const Pointer &x) {
+    out("Pointer");
+    return true;
+  }
+  bool pre(const PointerAssignmentStmt &x) {
+    out("PointerAssignmentStmt");
+    return true;
+  }
+  bool pre(const PointerAssignmentStmt::Bounds &x) {
+    out("PointerAssignmentStmt::Bounds");
+    return true;
+  }
+  bool pre(const PointerDecl &x) {
+    out("PointerDecl");
+    return true;
+  }
+  bool pre(const PointerObject &x) {
+    out("PointerObject");
+    return true;
+  }
+  bool pre(const PointerStmt &x) {
+    out("PointerStmt");
+    return true;
+  }
+  bool pre(const PositionOrFlushSpec &x) {
+    out("PositionOrFlushSpec");
+    return true;
+  }
+  bool pre(const PrefixSpec &x) {
+    out("PrefixSpec");
+    return true;
+  }
+  bool pre(const PrefixSpec::Elemental &x) {
+    out("PrefixSpec::Elemental");
+    return true;
+  }
+  bool pre(const PrefixSpec::Impure &x) {
+    out("PrefixSpec::Impure");
+    return true;
+  }
+  bool pre(const PrefixSpec::Module &x) {
+    out("PrefixSpec::Module");
+    return true;
+  }
+  bool pre(const PrefixSpec::Non_Recursive &x) {
+    out("PrefixSpec::Non_Recursive");
+    return true;
+  }
+  bool pre(const PrefixSpec::Pure &x) {
+    out("PrefixSpec::Pure");
+    return true;
+  }
+  bool pre(const PrefixSpec::Recursive &x) {
+    out("PrefixSpec::Recursive");
+    return true;
+  }
+  bool pre(const PrintStmt &x) {
+    out("PrintStmt");
+    return true;
+  }
+  bool pre(const PrivateOrSequence &x) {
+    out("PrivateOrSequence");
+    return true;
+  }
+  bool pre(const PrivateStmt &x) {
+    out("PrivateStmt");
+    return true;
+  }
+  bool pre(const ProcAttrSpec &x) {
+    out("ProcAttrSpec");
+    return true;
+  }
+  bool pre(const ProcComponentAttrSpec &x) {
+    out("ProcComponentAttrSpec");
+    return true;
+  }
+  bool pre(const ProcComponentDefStmt &x) {
+    out("ProcComponentDefStmt");
+    return true;
+  }
+  bool pre(const ProcComponentRef &x) {
+    out("ProcComponentRef");
+    return true;
+  }
+  bool pre(const ProcDecl &x) {
+    out("ProcDecl");
+    return true;
+  }
+  bool pre(const ProcInterface &x) {
+    out("ProcInterface");
+    return true;
+  }
+  bool pre(const ProcPointerInit &x) {
+    out("ProcPointerInit");
+    return true;
+  }
+  bool pre(const ProcedureDeclarationStmt &x) {
+    out("ProcedureDeclarationStmt");
+    return true;
+  }
+  bool pre(const ProcedureDesignator &x) {
+    out("ProcedureDesignator");
+    return true;
+  }
+  bool pre(const ProcedureStmt &x) {
+    out("ProcedureStmt");
+    return true;
+  }
+  bool pre(const Program &x) {
+    out("Program");
+    return true;
+  }
+  bool pre(const ProgramUnit &x) {
+    out("ProgramUnit");
+    return true;
+  }
+  bool pre(const Protected &x) {
+    out("Protected");
+    return true;
+  }
+  bool pre(const ProtectedStmt &x) {
+    out("ProtectedStmt");
+    return true;
+  }
+  bool pre(const ReadStmt &x) {
+    out("ReadStmt");
+    return true;
+  }
+  bool pre(const RealLiteralConstant &x) {
+    out("RealLiteralConstant");
+    return true;
+  }
+  bool pre(const RedimensionStmt &x) {
+    out("RedimensionStmt");
+    return true;
+  }
+  bool pre(const Rename &x) {
+    out("Rename");
+    return true;
+  }
+  bool pre(const Rename::Names &x) {
+    out("Rename::Names");
+    return true;
+  }
+  bool pre(const Rename::Operators &x) {
+    out("Rename::Operators");
+    return true;
+  }
+  bool pre(const ReturnStmt &x) {
+    out("ReturnStmt");
+    return true;
+  }
+  bool pre(const RewindStmt &x) {
+    out("RewindStmt");
+    return true;
+  }
+  bool pre(const Save &x) {
+    out("Save");
+    return true;
+  }
+  bool pre(const SaveStmt &x) {
+    out("SaveStmt");
+    return true;
+  }
+  bool pre(const SavedEntity &x) {
+    out("SavedEntity");
+    return true;
+  }
+  bool pre(const SectionSubscript &x) {
+    out("SectionSubscript");
+    return true;
+  }
+  bool pre(const SelectCaseStmt &x) {
+    out("SelectCaseStmt");
+    return true;
+  }
+  bool pre(const SelectRankCaseStmt &x) {
+    out("SelectRankCaseStmt");
+    return true;
+  }
+  bool pre(const SelectRankCaseStmt::Rank &x) {
+    out("SelectRankCaseStmt::Rank");
+    return true;
+  }
+  bool pre(const SelectRankConstruct &x) {
+    out("SelectRankConstruct");
+    return true;
+  }
+  bool pre(const SelectRankConstruct::RankCase &x) {
+    out("SelectRankConstruct::RankCase");
+    return true;
+  }
+  bool pre(const SelectRankStmt &x) {
+    out("SelectRankStmt");
+    return true;
+  }
+  bool pre(const SelectTypeConstruct &x) {
+    out("SelectTypeConstruct");
+    return true;
+  }
+  bool pre(const SelectTypeConstruct::TypeCase &x) {
+    out("SelectTypeConstruct::TypeCase");
+    return true;
+  }
+  bool pre(const SelectTypeStmt &x) {
+    out("SelectTypeStmt");
+    return true;
+  }
+  bool pre(const Selector &x) {
+    out("Selector");
+    return true;
+  }
+  bool pre(const SeparateModuleSubprogram &x) {
+    out("SeparateModuleSubprogram");
+    return true;
+  }
+  bool pre(const SequenceStmt &x) {
+    out("SequenceStmt");
+    return true;
+  }
+  bool pre(const SignedComplexLiteralConstant &x) {
+    out("SignedComplexLiteralConstant");
+    return true;
+  }
+  bool pre(const SignedIntLiteralConstant &x) {
+    out("SignedIntLiteralConstant");
+    return true;
+  }
+  bool pre(const SignedRealLiteralConstant &x) {
+    out("SignedRealLiteralConstant");
+    return true;
+  }
+  bool pre(const SpecificationConstruct &x) {
+    out("SpecificationConstruct");
+    return true;
+  }
+  bool pre(const SpecificationExpr &x) {
+    out("SpecificationExpr");
+    return true;
+  }
+  bool pre(const SpecificationPart &x) {
+    out("SpecificationPart");
+    return true;
+  }
+  bool pre(const Star &x) {
+    out("Star");
+    return true;
+  }
+  bool pre(const StatOrErrmsg &x) {
+    out("StatOrErrmsg");
+    return true;
+  }
+  bool pre(const StatVariable &x) {
+    out("StatVariable");
+    return true;
+  }
+  bool pre(const StatusExpr &x) {
+    out("StatusExpr");
+    return true;
+  }
+  bool pre(const StmtFunctionStmt &x) {
+    out("StmtFunctionStmt");
+    return true;
+  }
+  bool pre(const StopCode &x) {
+    out("StopCode");
+    return true;
+  }
+  bool pre(const StopStmt &x) {
+    out("StopStmt");
+    return true;
+  }
+  bool pre(const StructureComponent &x) {
+    out("StructureComponent");
+    return true;
+  }
+  bool pre(const StructureConstructor &x) {
+    out("StructureConstructor");
+    return true;
+  }
+  bool pre(const StructureDef &x) {
+    out("StructureDef");
+    return true;
+  }
+  bool pre(const StructureDef::EndStructureStmt &x) {
+    out("StructureDef::EndStructureStmt");
+    return true;
+  }
+  bool pre(const StructureField &x) {
+    out("StructureField");
+    return true;
+  }
+  bool pre(const StructureStmt &x) {
+    out("StructureStmt");
+    return true;
+  }
+  bool pre(const Submodule &x) {
+    out("Submodule");
+    return true;
+  }
+  bool pre(const SubmoduleStmt &x) {
+    out("SubmoduleStmt");
+    return true;
+  }
+  bool pre(const SubroutineStmt &x) {
+    out("SubroutineStmt");
+    return true;
+  }
+  bool pre(const SubroutineSubprogram &x) {
+    out("SubroutineSubprogram");
+    return true;
+  }
+  bool pre(const SubscriptTriplet &x) {
+    out("SubscriptTriplet");
+    return true;
+  }
+  bool pre(const Substring &x) {
+    out("Substring");
+    return true;
+  }
+  bool pre(const SubstringRange &x) {
+    out("SubstringRange");
+    return true;
+  }
+  bool pre(const Suffix &x) {
+    out("Suffix");
+    return true;
+  }
+  bool pre(const SyncAllStmt &x) {
+    out("SyncAllStmt");
+    return true;
+  }
+  bool pre(const SyncImagesStmt &x) {
+    out("SyncImagesStmt");
+    return true;
+  }
+  bool pre(const SyncImagesStmt::ImageSet &x) {
+    out("SyncImagesStmt::ImageSet");
+    return true;
+  }
+  bool pre(const SyncMemoryStmt &x) {
+    out("SyncMemoryStmt");
+    return true;
+  }
+  bool pre(const SyncTeamStmt &x) {
+    out("SyncTeamStmt");
+    return true;
+  }
+  bool pre(const Target &x) {
+    out("Target");
+    return true;
+  }
+  bool pre(const TargetStmt &x) {
+    out("TargetStmt");
+    return true;
+  }
+  bool pre(const TypeAttrSpec &x) {
+    out("TypeAttrSpec");
+    return true;
+  }
+  bool pre(const TypeAttrSpec::BindC &x) {
+    out("TypeAttrSpec::BindC");
+    return true;
+  }
+  bool pre(const TypeAttrSpec::Extends &x) {
+    out("TypeAttrSpec::Extends");
+    return true;
+  }
+  bool pre(const TypeBoundGenericStmt &x) {
+    out("TypeBoundGenericStmt");
+    return true;
+  }
+  bool pre(const TypeBoundProcBinding &x) {
+    out("TypeBoundProcBinding");
+    return true;
+  }
+  bool pre(const TypeBoundProcDecl &x) {
+    out("TypeBoundProcDecl");
+    return true;
+  }
+  bool pre(const TypeBoundProcedurePart &x) {
+    out("TypeBoundProcedurePart");
+    return true;
+  }
+  bool pre(const TypeBoundProcedureStmt &x) {
+    out("TypeBoundProcedureStmt");
+    return true;
+  }
+  bool pre(const TypeBoundProcedureStmt::WithInterface &x) {
+    out("TypeBoundProcedureStmt::WithInterface");
+    return true;
+  }
+  bool pre(const TypeBoundProcedureStmt::WithoutInterface &x) {
+    out("TypeBoundProcedureStmt::WithoutInterface");
+    return true;
+  }
+  bool pre(const TypeDeclarationStmt &x) {
+    out("TypeDeclarationStmt");
+    return true;
+  }
+  bool pre(const TypeGuardStmt &x) {
+    out("TypeGuardStmt");
+    return true;
+  }
+  bool pre(const TypeGuardStmt::Guard &x) {
+    out("TypeGuardStmt::Guard");
+    return true;
+  }
+  bool pre(const TypeParamDecl &x) {
+    out("TypeParamDecl");
+    return true;
+  }
+  bool pre(const TypeParamDefStmt &x) {
+    out("TypeParamDefStmt");
+    return true;
+  }
+  bool pre(const TypeParamInquiry &x) {
+    out("TypeParamInquiry");
+    return true;
+  }
+  bool pre(const TypeParamSpec &x) {
+    out("TypeParamSpec");
+    return true;
+  }
+  bool pre(const TypeParamValue &x) {
+    out("TypeParamValue");
+    return true;
+  }
+  bool pre(const TypeParamValue::Deferred &x) {
+    out("TypeParamValue::Deferred");
+    return true;
+  }
+  bool pre(const TypeSpec &x) {
+    out("TypeSpec");
+    return true;
+  }
+  bool pre(const Union &x) {
+    out("Union");
+    return true;
+  }
+  bool pre(const Union::EndUnionStmt &x) {
+    out("Union::EndUnionStmt");
+    return true;
+  }
+  bool pre(const Union::UnionStmt &x) {
+    out("Union::UnionStmt");
+    return true;
+  }
+  bool pre(const UnlockStmt &x) {
+    out("UnlockStmt");
+    return true;
+  }
+  bool pre(const UseStmt &x) {
+    out("UseStmt");
+    return true;
+  }
+  bool pre(const Value &x) {
+    out("Value");
+    return true;
+  }
+  bool pre(const ValueStmt &x) {
+    out("ValueStmt");
+    return true;
+  }
+  bool pre(const Variable &x) {
+    out("Variable");
+    return true;
+  }
+  bool pre(const Volatile &x) {
+    out("Volatile");
+    return true;
+  }
+  bool pre(const VolatileStmt &x) {
+    out("VolatileStmt");
+    return true;
+  }
+  bool pre(const WaitSpec &x) {
+    out("WaitSpec");
+    return true;
+  }
+  bool pre(const WaitStmt &x) {
+    out("WaitStmt");
+    return true;
+  }
+  bool pre(const WhereBodyConstruct &x) {
+    out("WhereBodyConstruct");
+    return true;
+  }
+  bool pre(const WhereConstruct &x) {
+    out("WhereConstruct");
+    return true;
+  }
+  bool pre(const WhereConstruct::Elsewhere &x) {
+    out("WhereConstruct::Elsewhere");
+    return true;
+  }
+  bool pre(const WhereConstruct::MaskedElsewhere &x) {
+    out("WhereConstruct::MaskedElsewhere");
+    return true;
+  }
+  bool pre(const WhereConstructStmt &x) {
+    out("WhereConstructStmt");
+    return true;
+  }
+  bool pre(const WhereStmt &x) {
+    out("WhereStmt");
+    return true;
+  }
+  bool pre(const WriteStmt &x) {
+    out("WriteStmt");
+    return true;
+  }
+
+  template<typename T>
+  bool pre(const LoopBounds<T> &x) {
+    out("LoopBounds");
+    return true;
+  }
+  template<typename T>
+  bool pre(const Statement<T> &x) {
+    out("Statement");
+    return true;
+  }
+  bool pre(const int &x) {
+    out(std::string{"int: "} + std::to_string(x));
+    return true;
+  }
+  bool pre(const std::uint64_t &x) {
+    out(std::string{"std::uint64_t: "} + std::to_string(x));
+    return true;
+  }
+  bool pre(const std::string &x) {
+    out(std::string{"std::string: "} + x);
+    return true;
+  }
+  bool pre(const std::int64_t &x) {
+    out(std::string{"std::int64_t: "} + std::to_string(x));
+    return true;
+  }
+  bool pre(const char &x) {
+    out(std::string{"char: "} + x);
+    return true;
+  }
+  bool pre(const Sign &x) {
+    out(std::string{"Sign: "} + (x == Sign::Positive ? "+" : "-"));
+    return true;
+  }
+
+  template<typename T>
+  bool pre(const T &x) {
+    out("generic");
+    return true;
+  }
+
+  template<typename T>
+  void post(const T &) {
+    --indent_;
+  }
+};
+
+int main(int argc, char *const argv[]) {
+  if (argc != 2) {
+    std::cerr << "Expected 1 source file, got " << (argc - 1) << "\n";
+    return EXIT_FAILURE;
+  }
+
+  std::string path{argv[1]};
+  AllSources allSources;
+  std::stringstream error;
+  const auto *sourceFile = allSources.Open(path, &error);
+  if (!sourceFile) {
+    std::cerr << error.str() << '\n';
+    return 1;
+  }
+
+  ProvenanceRange range{allSources.AddIncludedFile(
+      *sourceFile, ProvenanceRange{})};
+  Messages messages{allSources};
+  CookedSource cooked{&allSources};
+  Preprocessor preprocessor{&allSources};
+  bool prescanOk{Prescanner{&messages, &cooked, &preprocessor}.Prescan(range)};
+  messages.Emit(std::cerr);
+  if (!prescanOk) {
+    return EXIT_FAILURE;
+  }
+  cooked.Marshal();
+  ParseState state{cooked};
+  UserState ustate;
+  std::optional<Program> result{program.Parse(&state)};
+  if (!result.has_value() || state.anyErrorRecovery()) {
+    std::cerr << "parse FAILED\n";
+    state.messages()->Emit(std::cerr);
+    return EXIT_FAILURE;
+  }
+
+  Visitor visitor;
+  visit(*result, visitor);
+  return EXIT_SUCCESS;
+}