Signed-off-by: Jose E. Marchesi <jema...@gnu.org>

gcc/ChangeLog

        * algol68/a68-low.cc: New file.
        * algol68/a68-low-misc.cc: Likewise.
---
 gcc/algol68/a68-low-misc.cc |  213 +++++++
 gcc/algol68/a68-low.cc      | 1153 +++++++++++++++++++++++++++++++++++
 2 files changed, 1366 insertions(+)
 create mode 100644 gcc/algol68/a68-low-misc.cc
 create mode 100644 gcc/algol68/a68-low.cc

diff --git a/gcc/algol68/a68-low-misc.cc b/gcc/algol68/a68-low-misc.cc
new file mode 100644
index 00000000000..e2ad5cb412b
--- /dev/null
+++ b/gcc/algol68/a68-low-misc.cc
@@ -0,0 +1,213 @@
+/* Lower miscellaneous tree nodes to GENERIC.
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   Written by Jose E. Marchesi.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#define INCLUDE_MEMORY
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "tm.h"
+#include "function.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "varasm.h"
+#include "predict.h"
+#include "stor-layout.h"
+#include "tree-iterator.h"
+#include "stringpool.h"
+#include "print-tree.h"
+#include "gimplify.h"
+#include "dumpfile.h"
+#include "convert.h"
+
+#include "a68.h"
+
+/* Lower an assertion.
+
+     assertion : assert symbol, enclosed clause.
+*/
+
+tree
+a68_lower_assertion (NODE_T *p, LOW_CTX_T ctx)
+{
+  if (!OPTION_ASSERT (&A68_JOB))
+    return a68_get_empty();
+
+  /* Build the call to the assert run-time function.  */
+  unsigned int lineno = NUMBER (LINE (INFO (p)));
+  const char *filename_str = FILENAME (LINE (INFO (p)));
+  tree filename = build_string_literal (strlen (filename_str) + 1,
+                                       filename_str);
+  tree call = a68_build_libcall (A68_LIBCALL_ASSERT,
+                                void_type_node, 2,
+                                filename,
+                                build_int_cst (unsigned_type_node, lineno));
+  /* Check condition and call assert if required.  */
+  tree assertion = fold_build2_loc (a68_get_node_location (p),
+                                   COMPOUND_EXPR,
+                                   a68_void_type,
+                                   build2_loc (a68_get_node_location (p),
+                                               TRUTH_ORIF_EXPR,
+                                               a68_int_type,
+                                               a68_lower_tree (NEXT (SUB (p)), 
ctx),
+                                               fold_build2 (COMPOUND_EXPR,
+                                                            a68_int_type,
+                                                            call,
+                                                            build_int_cst 
(a68_int_type, 0))),
+                                   a68_get_empty ());
+  TREE_SIDE_EFFECTS (assertion) = 1;
+  return assertion;
+}
+
+/* Lower a jump to a label.
+
+     jump : goto symbol, identifier;
+            identifier.
+
+   A jump lowers into a ({ GOTO_EXPR; EMPTY }).  */
+
+tree
+a68_lower_jump (NODE_T *p, LOW_CTX_T ctx)
+{
+  NODE_T *label_identifier = SUB (p);
+  MOID_T *jump_mode = MOID (p);
+  if (!IS (label_identifier, IDENTIFIER))
+    FORWARD (label_identifier);
+
+  /* Create LABEL_DECL if necessary and chain it in both current block and bind
+     expression.  */
+  if (TAX_TREE_DECL (TAX (label_identifier)) == NULL_TREE)
+    {
+      tree label_decl = build_decl (a68_get_node_location (label_identifier),
+                                   LABEL_DECL,
+                                   a68_get_mangled_identifier (NSYMBOL 
(label_identifier)),
+                                   void_type_node);
+      TAX_TREE_DECL (TAX (label_identifier)) = label_decl;
+    }
+
+  MOID (label_identifier) = M_VOID;
+  return fold_build2_loc (a68_get_node_location (p),
+                         COMPOUND_EXPR,
+                         CTYPE (jump_mode),
+                         fold_build1_loc (a68_get_node_location (p),
+                                          GOTO_EXPR,
+                                          void_type_node,
+                                          a68_lower_tree (label_identifier, 
ctx)),
+                         a68_get_skip_tree (jump_mode));
+}
+
+/* Lower a parameter into a chain of PARAM_DECLs.
+
+     parameter : declarer, identifier;
+                 parameter, comma symbol, identifier.
+*/
+
+tree
+a68_lower_parameter (NODE_T *p, LOW_CTX_T ctx)
+{
+  tree prev_parm_decls = NULL_TREE;
+  NODE_T *identifier = NO_NODE;
+  if (IS (SUB (p), PARAMETER))
+    {
+      prev_parm_decls = a68_lower_tree (SUB (p), ctx);
+      identifier = NEXT (NEXT (SUB (p)));
+    }
+  else
+    identifier = NEXT (SUB (p));
+
+  /* Create the PARM_DECL.  */
+  tree parm_decl = build_decl (a68_get_node_location (p),
+                              PARM_DECL,
+                              a68_get_mangled_identifier (NSYMBOL 
(identifier)),
+                              CTYPE (MOID (identifier)));
+  DECL_CONTEXT (parm_decl) = current_function_decl;
+  DECL_ARG_TYPE (parm_decl) = TREE_TYPE (parm_decl);
+  TAX_TREE_DECL (TAX (identifier)) = parm_decl;
+
+  layout_decl (parm_decl, 0);
+
+  if (prev_parm_decls != NULL)
+    return chainon (prev_parm_decls, parm_decl);
+  else
+    return parm_decl;
+}
+
+/* Lower a list of parameters into a chain of PARAM_DECLs.
+
+        parameter list : parameter;
+                         parameter list; comma symbol; parameter.
+*/
+
+tree
+a68_lower_parameter_list (NODE_T *p, LOW_CTX_T ctx)
+{
+  tree parm_decl = NULL_TREE;
+  tree prev_parm_decls = NULL_TREE;
+  if (IS (SUB (p), PARAMETER_LIST))
+    {
+      prev_parm_decls = a68_lower_tree (SUB (p), ctx);
+      parm_decl = a68_lower_tree (NEXT (NEXT (SUB (p))), ctx);
+    }
+  else
+    parm_decl = a68_lower_tree (SUB (p), ctx);
+
+  gcc_assert (parm_decl != NULL_TREE);
+  if (prev_parm_decls != NULL)
+    return chainon (prev_parm_decls, parm_decl);
+  else
+    return parm_decl;
+}
+
+/* Lower a parameter pack into a chain of PARAM_DECLs.
+
+     parameter pack : open symbol, parameter list, close symbol.
+*/
+
+tree
+a68_lower_parameter_pack (NODE_T *p, LOW_CTX_T ctx)
+{
+  /* Lower the contained PARAMETER_LIST.  */
+  return a68_lower_tree (NEXT (SUB (p)), ctx);
+}
+
+/* Lower an applied operator.
+
+   Applied operators lower into a function object that gets one argument in
+   case of monadic operators, or two arguments in case of dyadic operators.  */
+
+tree
+a68_lower_operator (NODE_T *p, LOW_CTX_T ctx ATTRIBUTE_UNUSED)
+{
+  /* This is an user defined operator.  Handle it in a similar way than applied
+     identifiers.  */
+  tree func_decl = TAX_TREE_DECL (TAX (p));
+  if (func_decl == NULL_TREE)
+    {
+      if (IN_PROC (TAX (p)))
+       func_decl = a68_make_proc_identity_declaration_decl (p);
+      else
+       func_decl = a68_make_identity_declaration_decl (p);
+      TAX_TREE_DECL (TAX (p)) = func_decl;
+    }
+  return func_decl;
+}
diff --git a/gcc/algol68/a68-low.cc b/gcc/algol68/a68-low.cc
new file mode 100644
index 00000000000..69376081b03
--- /dev/null
+++ b/gcc/algol68/a68-low.cc
@@ -0,0 +1,1153 @@
+/* Lower the Algol 68 parse tree to GENERIC.
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   Written by Jose E. Marchesi.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#define INCLUDE_MEMORY
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "tm.h"
+#include "function.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "varasm.h"
+#include "predict.h"
+#include "stor-layout.h"
+#include "tree-iterator.h"
+#include "stringpool.h"
+#include "print-tree.h"
+#include "gimplify.h"
+#include "dumpfile.h"
+#include "convert.h"
+
+#include "a68.h"
+
+/* Return a tree with an identifier for the mangled version of a given
+   name.  */
+
+tree
+a68_get_mangled_identifier (const char *name)
+{
+  char *mangled_name = (char *) alloca (strlen (name) + 1);
+  memcpy (mangled_name, name, strlen (name) + 1);
+
+  /* Avoid MONADS and NOMADS.  */
+  for (char *p = mangled_name; *p != '\0'; ++p)
+    {
+      if (strchr (MONADS, *p) != NULL || strchr (NOMADS, *p) != NULL
+         || strchr (":=", *p))
+       *p = '_';
+    }
+
+  return get_identifier (mangled_name);
+}
+
+/* Return a tree with the EMPTY value.
+
+   EMPTY is the only denotation of the VOID mode.  It is used in unions to
+   denote "no value".  It must have size zero, so it lowers into an empty
+   constructor with zero elements of type void.  This is what GNU C uses to
+   implement the empty struct extension.  */
+
+tree
+a68_get_empty (void)
+{
+  return build_constructor (a68_void_type, NULL);
+}
+
+/* Return a tree with the yielding of SKIP of a given mode.
+
+   SKIP stands for some value of some given mode.  It shall be used only in a
+   context where the compiler can determine the mode.
+
+   The particular value to which it elaborates is non-important, but this
+   compiler always uses the same values.  See the a68_get_ref_*_tree functions
+   for details on what values are these.  */
+
+tree
+a68_get_skip_tree (MOID_T *m)
+{
+  tree expr = NULL_TREE;
+
+  while (EQUIVALENT (m) != NO_MOID)
+    m = EQUIVALENT (m);
+
+  if (IS_INTEGRAL (m))
+    expr = a68_get_int_skip_tree (m);
+  else if (m == M_CHAR)
+    expr = a68_get_char_skip_tree ();
+  else if (m == M_BOOL)
+    expr = a68_get_bool_skip_tree ();
+  else if (IS_REAL (m))
+    expr = a68_get_real_skip_tree (m);
+  else if (IS_BITS (m))
+    expr = a68_get_bits_skip_tree (m);
+  else if (IS_REF (m))
+    expr = a68_get_ref_skip_tree (m);
+  else if (IS (m, PROC_SYMBOL))
+    expr = a68_get_proc_skip_tree (m);
+  else if (IS_STRUCT (m))
+    expr = a68_get_struct_skip_tree (m);
+  else if (IS_UNION (m))
+    expr = a68_get_union_skip_tree (m);
+  else if (IS_FLEXETY_ROW (m))
+    expr = a68_get_multiple_skip_tree (m);
+  else if (m == M_STRING)
+      expr = a68_get_string_skip_tree ();
+  else if (m == M_ROWS  || IS (m, SERIES_MODE))
+    {
+      /* XXX assert that all modes in the series are rows? */
+      tree rows_type = CTYPE (M_ROWS);
+      tree dim_field = TYPE_FIELDS (rows_type);
+      tree triplets_field = TREE_CHAIN (dim_field);
+      tree null_pointer = build_int_cst (TREE_TYPE (triplets_field), 0);
+      expr = build_constructor_va (rows_type, 2,
+                                  dim_field, size_zero_node,
+                                  triplets_field, null_pointer);
+    }
+  else if (m == M_VOID || m == M_HIP)
+    expr = a68_get_empty ();
+  else
+    {
+      fatal_error (UNKNOWN_LOCATION,
+                  "get skip tree: cannot compute SKIP for mode %s",
+                  a68_moid_to_string (m, MOID_ERROR_WIDTH, NODE (m), true));
+      gcc_unreachable ();
+    }
+
+  return expr;
+}
+
+/* Given a tree node EXP holding a value of mode M:
+
+   *NUM_REFS is set to the number of REFs in M.
+
+   *NUM_POINTERS is set to the number of pointers in the type of EXP that
+   correspond to the REFs in M.  */
+
+void
+a68_ref_counts (tree exp, MOID_T *m, int *num_refs, int *num_pointers)
+{
+  /* Count REFs in M and pointers in the type of EXP.  Note that VAR_DECLs
+     corresponding to REF PROC are of type pointer, so these should not count
+     for the count!  */
+
+  /* Make sure we are accessing the real mode definition.  */
+  while (EQUIVALENT (m) != NO_MOID)
+    m = EQUIVALENT (m);
+
+  *num_refs = 0;
+  *num_pointers = 0;
+  for (MOID_T *s = m; s != NO_MOID && IS_REF (s); s = SUB (s))
+    *num_refs += 1;
+  for (tree p = TREE_TYPE (exp);
+       p != NULL_TREE && POINTER_TYPE_P (p) && TREE_CODE (TREE_TYPE (p)) != 
FUNCTION_TYPE;
+       p = TREE_TYPE (p))
+    *num_pointers += 1;
+
+  gcc_assert (*num_refs >= *num_pointers);
+}
+
+/* The Algol 68 variable declaration
+
+     [LOC|HEAP] AMODE foo;
+
+   Is in principle equivalent to the identity declaration
+
+     REF AMODE foo = [LOC|HEAP] AMODE;
+
+   In both cases the object ascribed to the defining identifier `foo' is of
+   mode REF AMODE.  The ascribed object is a name which is created by a
+   generator implied in the actual declarer in the first case, and an explicit
+   generator in the initialization expression in the second case.
+
+   However, this front-end implements these two cases differently in order to
+   reduce the amount of both indirect addressing and of storage:
+
+   - The variable declaration `[LOC|HEAP] AMODE foo;' lowers into a VAR_DECL
+     with type ATYPE provided that the generator is LOC and that it contains no
+     rows.  Accessing it requires direct addressing.  When its address is
+     required, an ADDR_EXPR shall be used.
+
+   - The identity declaration `REF AMODE foo = LOC AMODE;' lowers into a
+     VAR_DECL with type *ATYPE.  Accessing it requires indirect addressing.  It
+     is effectively a pointer.
+
+   This introduces the complication that an expression (the VAR_DECL) whose
+   type is TYPE can appear in a place where *TYPE is expected.  This function,
+   given the required mode and an expression, adds as many ADDR_EXPR to EXPR as
+   necessary so the resulting value is of the required type.  Other than this
+   nuisance, the parser guarantees that the entities have the right type at the
+   location they appear, so a call to a68_consolidate_ref is all must be needed
+   at any point in the lowering process to guarantee a valid value for the
+   context.
+
+   This function expects:
+   - That the type of EXPR is zero or more pointers to a base type BTYPE.
+   - That the mode M is zero or more REFs to a base non-ref mode AMODE.
+   - That the number of pointers in the type of EXPR is less or equal than the
+     number of REFs in the mode M.
+   - That BTYPE and AMODE are equivalent.  */
+
+tree
+a68_consolidate_ref (MOID_T *m, tree expr)
+{
+  int num_refs, num_pointers;
+  a68_ref_counts (expr, m, &num_refs, &num_pointers);
+
+  /* Address EXPR as many times as necessary to match the number of REFs in the
+     desired mode.  */
+  while (num_pointers < num_refs)
+    {
+      if (TREE_CODE (expr) == COMPOUND_EXPR)
+       {
+         /* (..., x) -> (..., &x) */
+         //      gcc_assert (TREE_CODE (TREE_OPERAND (expr, 0)) == 
MODIFY_EXPR);
+         //      gcc_assert (VAR_P (TREE_OPERAND (expr, 1)));
+         TREE_OPERAND (expr, 1) = a68_consolidate_ref (m, TREE_OPERAND (expr, 
1));
+         TREE_TYPE (expr) = TREE_TYPE (TREE_OPERAND (expr, 1));
+       }
+      else
+       {
+         /* x -> &x */
+         if (TREE_CODE (expr) == INDIRECT_REF)
+           /* expr is an indirection.  Remove the pointer rather than adding
+              an addr.  This avoids &* situations and marking stuff as
+              addressable unnecessarily.  */
+           expr = TREE_OPERAND (expr,0);
+         else
+           {
+             TREE_ADDRESSABLE (expr) = true;
+             expr = fold_build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE 
(expr)), expr);
+           }
+       }
+      num_pointers += 1;
+    }
+
+  return expr;
+}
+
+/* Make a declaration for an anonymous routine of mode MODE.  */
+
+tree
+a68_make_anonymous_routine_decl (MOID_T *mode)
+{
+  /* The CTYPE of MODE is a pointer to a function.  We need the pointed
+     function type for the FUNCTION_DECL.  */
+  tree func_type = TREE_TYPE (CTYPE (mode));
+  tree func_decl = build_decl (UNKNOWN_LOCATION,
+                              FUNCTION_DECL,
+                              NULL_TREE /* name, set below.  */,
+                              func_type);
+  char *name = xasprintf ("routine%d", DECL_UID (func_decl));
+  DECL_NAME (func_decl) = a68_get_mangled_identifier (name);
+  free (name);
+  DECL_EXTERNAL (func_decl) = 0;
+  DECL_STATIC_CHAIN (func_decl) = !a68_in_global_range ();
+  /* Nested functions should be addressable.
+     XXX this should be propagated to their containing functions, so for now
+     we mark them all as addressable.  */
+  TREE_ADDRESSABLE (func_decl) = 1;
+  /* A nested function is not global.  */
+  TREE_PUBLIC (func_decl) = a68_in_global_range ();
+  TREE_STATIC (func_decl) = 1;
+
+  return func_decl;
+}
+
+/* Make a declaration for a constant procedure or operator.  */
+
+tree
+a68_make_proc_identity_declaration_decl (NODE_T *identifier)
+{
+  /* The CTYPE of MODE is a pointer to a function.  We need the pointed
+     function type for the FUNCTION_DECL.  */
+  tree func_type = TREE_TYPE (CTYPE (MOID (identifier)));
+  tree func_decl = build_decl (UNKNOWN_LOCATION,
+                              FUNCTION_DECL,
+                              a68_get_mangled_identifier (NSYMBOL 
(identifier)),
+                              func_type);
+  DECL_EXTERNAL (func_decl) = 0;
+  DECL_STATIC_CHAIN (func_decl) = !a68_in_global_range ();
+  /* Nested functions should be addressable.
+     XXX this should be propagated to their containing functions, so for now
+     we mark them all as addressable.  */
+  TREE_ADDRESSABLE (func_decl) = 1;
+  /* A nested function is not global.  */
+  TREE_PUBLIC (func_decl) = a68_in_global_range ();
+  TREE_STATIC (func_decl) = 1;
+
+  return func_decl;
+}
+
+/* Make a declaration for an identity declaration.  */
+
+tree
+a68_make_identity_declaration_decl (NODE_T *identifier)
+{
+  tree type = CTYPE (MOID (identifier));
+
+  tree decl = build_decl (a68_get_node_location (identifier),
+                         VAR_DECL,
+                         a68_get_mangled_identifier (NSYMBOL (identifier)),
+                         type);
+  TREE_PUBLIC (decl) = 0;
+#if 0
+  if (!IS_REF (MOID (identifier)))
+    TREE_CONSTANT (decl) = 1;
+#endif
+  DECL_INITIAL (decl) = a68_get_skip_tree (MOID (identifier));
+  return decl;
+}
+
+/* Make a declaration for a variable declaration.
+   The mode of the given identifier is expected to be a REF AMODE.  */
+
+tree
+a68_make_variable_declaration_decl (NODE_T *identifier)
+{
+  gcc_assert (IS_REF (MOID (identifier)));
+
+  MOID_T *mode = MOID (identifier);
+  bool use_pointer = ((HEAP (TAX (identifier)) == HEAP_SYMBOL)
+                     || HAS_ROWS (SUB (MOID (identifier))));
+  tree type = use_pointer ? CTYPE (mode) : CTYPE (SUB (mode));
+  tree decl = build_decl (a68_get_node_location (identifier),
+                         VAR_DECL,
+                         a68_get_mangled_identifier (NSYMBOL (identifier)),
+                         type);
+  TREE_PUBLIC (decl) = 0;
+  DECL_INITIAL (decl) = a68_get_skip_tree (use_pointer ? mode : SUB (mode));
+  return decl;
+}
+
+/* Do a checked indirection.
+
+   P is a tree node used for its location information.
+   EXP is an expression that gets indirected.
+   EXP_MODE is the mode of exp.  */
+
+tree
+a68_checked_indirect_ref (NODE_T *p, tree exp, MOID_T *exp_mode)
+{
+  tree exp_type = TREE_TYPE (exp);
+  tree nil_check = NULL_TREE;
+
+  if (OPTION_NIL_CHECKING (&A68_JOB))
+    {
+      exp = save_expr (exp);
+      tree consolidated_exp = a68_consolidate_ref (exp_mode, exp);
+
+      /* Check whether we are dereferencing NIL.  */
+      unsigned int lineno = NUMBER (LINE (INFO (p)));
+      const char *filename_str = FILENAME (LINE (INFO (p)));
+      tree filename = build_string_literal (strlen (filename_str) + 1,
+                                           filename_str);
+      tree call = a68_build_libcall (A68_LIBCALL_DEREFNIL,
+                                        void_type_node, 2,
+                                        filename,
+                                        build_int_cst (unsigned_type_node, 
lineno));
+      call = fold_build2 (COMPOUND_EXPR, a68_bool_type, call, 
boolean_false_node);
+      nil_check = fold_build2 (NE_EXPR, exp_type,
+                              consolidated_exp,
+                              build_int_cst (exp_type, 0));
+      nil_check = fold_build2 (TRUTH_ORIF_EXPR, exp_type,
+                              nil_check, call);
+    }
+
+  tree deref = fold_build1 (INDIRECT_REF, TREE_TYPE (exp_type), exp);
+  if (nil_check == NULL_TREE)
+    return deref;
+  else
+    return fold_build2 (COMPOUND_EXPR, TREE_TYPE (deref),
+                       nil_check, deref);
+}
+
+/* Deref a given expression EXP whose mode is MOID (P).
+
+   The value to dereference always corresponds to a name, but it may consist
+   of:
+
+   - Not a pointer, in which case corresponds to a name lowered to a VAR_DECL.
+
+   - A pointer to a function, in which case corresponds to a name of mode REF
+     PROC, lowered to a VAR_DECL.
+
+   - Any other pointer corresponds to a name lowered to a VAR_DECL that is a
+     pointer.
+
+   In the first two cases, in both r-value and l-value situations the expected
+   result is achieved by just returning the value: in r-value the decl denotes
+   the value, in l-value the decl denotes the (direct) address of the
+   value.  */
+
+tree
+a68_low_deref (tree exp, NODE_T *p)
+{
+  int num_refs, num_pointers;
+  a68_ref_counts (exp, MOID (p), &num_refs, &num_pointers);
+
+  if (num_refs > num_pointers)
+    return exp;
+  else
+    {
+      gcc_assert (num_refs == num_pointers);
+      return a68_checked_indirect_ref (p, exp, MOID (p));
+    }
+}
+
+/* Get a deep-copy of a given Algol 68 value EXP.  */
+
+tree
+a68_low_dup (tree expr, bool use_heap)
+{
+  tree dup = NULL_TREE;
+  tree type = TREE_TYPE (expr);
+
+  /* XXX */
+  use_heap = true;
+
+  /* Determine the mode corresponding to the type of EXPR.  */
+  MOID_T *m = a68_type_moid (type);
+  gcc_assert (m != NO_MOID);
+  while (EQUIVALENT (m) != NO_MOID)
+    m = EQUIVALENT (m);
+
+  if (A68_ROW_TYPE_P (type))
+    {
+      /* We need to copy the elements as well as the descriptor.  There is no
+        need to check bounds.  */
+
+      /* Deflexe the mode as appropriate.  */
+      while (IS_FLEX (m))
+       m = SUB (m);
+      gcc_assert (IS_ROW (m) || m == M_STRING);
+
+      a68_push_range (NULL);
+
+      /* First allocate space for the dupped elements.  */
+      expr = save_expr (expr);
+      tree elements = a68_multiple_elements (expr);
+      tree element_pointer_type = TREE_TYPE (elements);
+      tree element_type = TREE_TYPE (element_pointer_type);
+      tree new_elements_size = save_expr (a68_multiple_elements_size (expr));
+      tree new_elements = a68_lower_tmpvar ("new_elements%",
+                                           TREE_TYPE (elements),
+                                           (use_heap
+                                            ? a68_lower_malloc (TREE_TYPE 
(TREE_TYPE (elements)),
+                                                                
new_elements_size)
+                                            : a68_lower_alloca (TREE_TYPE 
(TREE_TYPE (elements)),
+                                                                
new_elements_size)));
+
+      /* Then copy the elements.
+
+        If the mode of the elements stored in the multiple dont have rows,
+        then we can just use memcpy.  Otherwise, we have to loop and recurse
+        to dup all the elements in the multiple one by one.
+
+        The above applies to multiples of any number of dimensions.  */
+      if (m == M_STRING || !HAS_ROWS (SUB (m)))
+       {
+         a68_add_stmt (a68_lower_memcpy (new_elements,
+                                         elements,
+                                         new_elements_size));
+         a68_add_stmt (new_elements);
+       }
+      else
+       {
+         /* Note that num_elems includes elements that are not accessible due
+            to trimming.  */
+         tree num_elems = a68_lower_tmpvar ("numelems%", size_type_node,
+                                            fold_build2 (TRUNC_DIV_EXPR, 
sizetype,
+                                                         new_elements_size,
+                                                         size_in_bytes 
(element_type)));
+         tree orig_elements = a68_lower_tmpvar ("orig_elements%",
+                                                element_pointer_type, 
elements);
+         tree index = a68_lower_tmpvar ("index%", size_type_node, 
size_zero_node);
+
+         /* Begin of loop body.  */
+         a68_push_range (NULL);
+
+         /* if (index == num_elems) break; */
+         a68_add_stmt (fold_build1 (EXIT_EXPR,
+                                    void_type_node,
+                                    fold_build2 (EQ_EXPR,
+                                                 size_type_node,
+                                                 index, num_elems)));
+         /* new_elements[index] = elements[index] */
+         tree offset = fold_build2 (MULT_EXPR, sizetype,
+                                    index, size_in_bytes (element_type));
+         tree new_elem_lvalue = fold_build2 (MEM_REF, element_type,
+                                             fold_build2 (POINTER_PLUS_EXPR,
+                                                          element_pointer_type,
+                                                          new_elements,
+                                                          offset),
+                                             fold_convert 
(element_pointer_type,
+                                                           integer_zero_node));
+         tree elem = fold_build2 (MEM_REF, element_type,
+                                  fold_build2 (POINTER_PLUS_EXPR,
+                                               element_pointer_type,
+                                               orig_elements,
+                                               offset),
+                                  fold_convert (element_pointer_type,
+                                                integer_zero_node));
+         a68_add_stmt (fold_build2 (MODIFY_EXPR, element_type,
+                                    new_elem_lvalue,
+                                    a68_low_dup (elem, use_heap)));
+         /* index++ */
+         a68_add_stmt (fold_build2 (POSTINCREMENT_EXPR,
+                                    size_type_node,
+                                    index, size_one_node));
+         tree loop_body = a68_pop_range ();
+         /* End of loop body.  */
+
+         a68_add_stmt (fold_build1 (LOOP_EXPR,
+                                    void_type_node,
+                                    loop_body));
+         a68_add_stmt (new_elements);
+       }
+
+      new_elements = a68_pop_range ();
+      TREE_TYPE (new_elements) = element_pointer_type;
+
+      /* Now build a descriptor pointing to the dupped elements and return it.
+        Note that the descriptor is always allocated on the stack.  */
+      dup = a68_row_value_raw (type,
+                              a68_multiple_triplets (expr),
+                              new_elements,
+                              new_elements_size);
+    }
+  else if (!HAS_ROWS (m))
+    {
+      /* Non-multiple values that do not contain rows do not need to be dupped,
+        since they can be just moved around using the semantics of
+        MODIFY_EXPR.  */
+      dup = expr;
+    }
+  else if (A68_STRUCT_TYPE_P (type))
+    {
+      /* Since struct value can contain multiples and unions and other values
+        that require deep copy, we cannot simply rely on the C semantics of a
+        MODIFY_EXPR.  */
+      tree struct_type = type;
+      vec <constructor_elt, va_gc> *ce = NULL;
+
+      expr = save_expr (expr);
+      for (tree field = TYPE_FIELDS (struct_type);
+          field;
+          field = TREE_CHAIN (field))
+       {
+         CONSTRUCTOR_APPEND_ELT (ce, field,
+                                 a68_low_dup (fold_build3 (COMPONENT_REF,
+                                                           TREE_TYPE (field),
+                                                           expr,
+                                                           field,
+                                                           NULL_TREE),
+                                              use_heap));
+       }
+      dup = build_constructor (struct_type, ce);
+    }
+  else if (A68_UNION_TYPE_P (type))
+    {
+      /* We need to recurse in whatever type corresponding to the active mode
+        in the united value.  This shall be done at run-time by using a series
+        of
+
+          IF overhead IS index of mode blah in union
+          THEN dup = dup_type (CTYPE (mode blah in union))
+          FI
+      */
+
+      MOID_T *union_mode = a68_type_moid (type);
+
+      a68_push_range (union_mode);
+      dup = a68_lower_tmpvar ("dup%", type, expr);
+
+      tree cunion_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (type)));
+      tree field_decl = TYPE_FIELDS (cunion_type);
+      while (EQUIVALENT (union_mode) != NO_MOID)
+       union_mode = EQUIVALENT (union_mode);
+      for (PACK_T *pack = PACK (union_mode); pack != NO_PACK; FORWARD (pack))
+       {
+         tree continue_label_decl = build_decl (UNKNOWN_LOCATION,
+                                                LABEL_DECL,
+                                                NULL, /* Set below.  */
+                                                void_type_node);
+         char *label_name = xasprintf ("continue%d%%", DECL_UID 
(continue_label_decl));
+         DECL_NAME (continue_label_decl) = get_identifier (label_name);
+         free (label_name);
+
+         a68_add_decl (continue_label_decl);
+
+         a68_add_stmt (fold_build2 (TRUTH_ORIF_EXPR,
+                                    integer_type_node,
+                                    fold_build2 (EQ_EXPR,
+                                                 integer_type_node,
+                                                 a68_union_overhead (dup),
+                                                 size_int 
(a68_united_mode_index (union_mode, MOID (pack)))),
+                                    fold_build2 (COMPOUND_EXPR,
+                                                 integer_type_node,
+                                                 build1 (GOTO_EXPR, 
void_type_node, continue_label_decl),
+                                                 integer_zero_node)));
+         a68_add_stmt (fold_build2 (MODIFY_EXPR, type,
+                                    fold_build3 (COMPONENT_REF,
+                                                 TREE_TYPE (field_decl),
+                                                 a68_union_cunion (dup),
+                                                 field_decl,
+                                                 NULL_TREE),
+                                    a68_low_dup (fold_build3 (COMPONENT_REF,
+                                                              TREE_TYPE 
(field_decl),
+                                                              a68_union_cunion 
(dup),
+                                                              field_decl,
+                                                              NULL_TREE),
+                                                 use_heap)));
+         a68_add_stmt (build1 (LABEL_EXPR, void_type_node, 
continue_label_decl));
+         field_decl = TREE_CHAIN (field_decl);
+       }
+
+      a68_add_stmt (dup);
+      dup = a68_pop_range ();
+    }
+  else
+    /* Not an Algol 68 value.  */
+    gcc_unreachable ();
+
+  return dup;
+}
+
+/* Lower code to ascribe the value yielded by the expression in RHS to the
+   defining identifier implied by the LHS, which is a VAR_DECL tree.  MODE is
+   the mode of the value to be ascribed.  */
+
+tree
+a68_low_ascription (MOID_T *mode, tree lhs, tree rhs)
+{
+  gcc_assert (VAR_P (lhs));
+
+  tree type = CTYPE (mode);
+  if (IS (mode, PROC_SYMBOL))
+    {
+      /* A pointer to a function, or a function, is expected at the right hand
+        side.  We need a pointer for the left hand side..  */
+      if (TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE)
+       {
+         type = build_pointer_type (type);
+         rhs = fold_build1 (ADDR_EXPR, type, rhs);
+       }
+    }
+
+  if (HAS_ROWS (mode))
+    rhs = a68_low_dup (rhs);
+  return fold_build2 (MODIFY_EXPR, type, lhs, rhs);
+}
+
+/* Perform an assignation of RHS to LHS.
+
+   MODE_RHS is the mode of the rhs.
+   MODE_LHS is the mode of the lhs.
+
+   MODE_LHS shall be REF [FLEX] MODE_LHS.  */
+
+tree
+a68_low_assignation (NODE_T *p,
+                    tree lhs, MOID_T *mode_lhs,
+                    tree rhs, MOID_T *mode_rhs)
+{
+  NODE_T *lhs_node = SUB (p);
+  tree assignation = NULL_TREE;
+  tree orig_rhs = rhs;
+
+  if (IS_FLEXETY_ROW (mode_rhs))
+    {
+      /* Make a deep copy of the rhs.  Note that we have to use the heap
+        because the scope of the lhs may be older than the scope of the rhs.
+        XXX this can be ommitted if a68_multiple_copy_elems below supports
+        overlapping multiples.  */
+      if (HAS_ROWS (mode_rhs))
+       rhs = a68_low_dup (rhs, true /* use_heap */);
+      rhs = save_expr (rhs);
+
+      /* Determine whether the REF [FLEX] MODE_LHS is flexible.  */
+      if (SUB (mode_lhs) == M_STRING || IS_FLEX (SUB (mode_lhs)))
+       {
+         /* Assigning to a flexible name updates descriptor with new bounds
+            and also sets the elements to the dup of the rhs.  No boundscheck
+            is peformed.  XXX but bound checking in contained values may be
+            necessary, ghost elements.  */
+         if (POINTER_TYPE_P (TREE_TYPE (lhs))
+             && TREE_TYPE (TREE_TYPE (lhs)) == TREE_TYPE (rhs))
+           {
+             /* Make sure to not evaluate the expression yielding the pointer
+                more than once.  */
+             lhs = save_expr (lhs);
+             tree deref_lhs = a68_checked_indirect_ref (lhs_node, lhs, 
mode_lhs);
+             assignation = fold_build2 (COMPOUND_EXPR,
+                                        TREE_TYPE (lhs),
+                                        fold_build2 (MODIFY_EXPR, TREE_TYPE 
(lhs),
+                                                     deref_lhs, rhs),
+                                        lhs);
+           }
+         else
+           {
+             /* The lhs is either a variable or a component ref as a l-value.  
It
+                is ok to evaluate it as an r-value as well as doing so 
inroduces
+                no side-effects.  */
+             assignation = fold_build2 (COMPOUND_EXPR,
+                                        TREE_TYPE (lhs),
+                                        fold_build2 (MODIFY_EXPR, TREE_TYPE 
(lhs),
+                                                     lhs, rhs),
+                                        lhs);
+           }
+       }
+      else
+       {
+         /* Dereference the multiple at the left-hand side.  This may require
+            indirection.  */
+
+         tree effective_lhs;
+         if (POINTER_TYPE_P (TREE_TYPE (lhs)))
+           {
+             /* The name at the lhs is a pointer.  */
+             gcc_assert (TREE_TYPE (TREE_TYPE (lhs)) == TREE_TYPE (rhs));
+             lhs = save_expr (lhs);
+             effective_lhs = a68_checked_indirect_ref (lhs_node, lhs, 
mode_lhs);
+           }
+         else
+           {
+             /* The name at the lhs is either a variable or a component ref as
+                a l-value.  It is ok to evaluate it as an r-value as well as
+                doing so introduces no side-effects.  */
+             effective_lhs = lhs;
+           }
+
+         /* Copy over the elements in a loop.  The space occupied by the
+            previous elements stored in the lhs multiple will be recovered by
+            either stack shrinkage or garbage collected.  */
+         tree copy_elements = a68_multiple_copy_elems (mode_rhs, 
effective_lhs, rhs);
+         assignation = fold_build2 (COMPOUND_EXPR,
+                                    TREE_TYPE (lhs),
+                                    copy_elements,
+                                    lhs);
+
+         /* Check the bounds of the multiple at the rhs to make sure they are
+            the same than the bounds of the multiple already referred by the
+            lhs.  If the bounds don't match then emit a run-time error.  */
+         if (OPTION_BOUNDS_CHECKING (&A68_JOB))
+           assignation = fold_build2 (COMPOUND_EXPR,
+                                      TREE_TYPE (assignation),
+                                      a68_multiple_bounds_check_equal (p,
+                                                                       
effective_lhs,
+                                                                       rhs),
+                                      assignation);
+
+       }
+    }
+  else
+    {
+      /* First make sure we got a pointer in the RHS in case it is a name.  */
+      rhs = a68_consolidate_ref (mode_rhs, rhs);
+
+      /* The assignation implies copying the entire value being assigned, so
+        make sure we do a deep copy whenever needed.  Note that we have to use
+        the heap because the scope of the lhs may be older than the scope of
+        the rhs.  */
+      if (HAS_ROWS (mode_rhs))
+       rhs = a68_low_dup (rhs, true /* use_heap */);
+
+      if (POINTER_TYPE_P (TREE_TYPE (lhs))
+         && TREE_TYPE (TREE_TYPE (lhs)) == TREE_TYPE (rhs))
+       {
+         /* If the left hand side is a pointer, deref it, but return the
+            pointer.  Make sure to not evaluate the expression yielding the
+            pointer more than once.  */
+         lhs = save_expr (lhs);
+         tree deref_lhs = a68_checked_indirect_ref (lhs_node, lhs, mode_lhs);
+         assignation = fold_build2 (COMPOUND_EXPR,
+                                    TREE_TYPE (lhs),
+                                    fold_build2 (MODIFY_EXPR, TREE_TYPE (lhs),
+                                                 deref_lhs, rhs),
+                                    lhs);
+       }
+      else
+       {
+         /* Otherwise the lhs is either a variable or a component ref as an
+            l-value.  It is ok to evaluate it as an r-value as well as doing
+            so introduces no side-effects.  */
+         assignation = fold_build2 (COMPOUND_EXPR,
+                                    TREE_TYPE (lhs),
+                                    fold_build2 (MODIFY_EXPR, TREE_TYPE (lhs),
+                                                 lhs, rhs),
+                                    lhs);
+       }
+    }
+
+  /* Since it is been assigned to a name, the rhs is no longer constant.  */
+  if (A68_ROW_TYPE_P (TREE_TYPE (orig_rhs)) || A68_STRUCT_TYPE_P (TREE_TYPE 
(orig_rhs)))
+    TREE_CONSTANT (orig_rhs) = 0;
+  return assignation;
+}
+
+/* Build a tree that copies SIZE bytes from SRC into DST.  */
+
+tree
+a68_lower_memcpy (tree dst, tree src, tree size)
+{
+  return build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCPY), 3,
+                         dst, src, size);
+}
+
+/* Build a tree that allocates SIZE bytes on the stack and returns a *TYPE
+   pointer to it.  */
+
+tree
+a68_lower_alloca (tree type, tree size)
+{
+  tree call = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+  call = build_call_expr_loc (UNKNOWN_LOCATION, call, 2,
+                             size,
+                             size_int (TYPE_ALIGN (type)));
+  call = fold_convert (build_pointer_type (type), call);
+  return call;
+}
+
+
+/* Build a tree that allocates SIZE bytes on the heap and returns a *TYPE
+   pointer to it.  */
+
+tree
+a68_lower_malloc (tree type, tree size)
+{
+  return fold_convert (build_pointer_type (type),
+                      a68_build_libcall (A68_LIBCALL_MALLOC, ptr_type_node,
+                                         1, size));
+}
+
+/* Build code for a temporary variable named NAME, of type TYPE and initialized
+   to INIT.  Returns the decl node for the temporary.  */
+
+tree
+a68_lower_tmpvar (const char *name, tree type, tree init)
+{
+  tree tmpvar = build_decl (UNKNOWN_LOCATION,
+                           VAR_DECL,
+                           get_identifier (name),
+                           type);
+  DECL_ARTIFICIAL (tmpvar) = 1;
+  DECL_IGNORED_P (tmpvar) = 1;
+  a68_add_decl (tmpvar);
+  a68_add_decl_expr (fold_build1 (DECL_EXPR, type, tmpvar));
+  a68_add_stmt (fold_build2 (INIT_EXPR, type, tmpvar, init));
+  return tmpvar;
+}
+
+/* Build a FUNC_DECL for a top-level non-public function and return it.  */
+
+tree
+a68_low_toplevel_func_decl (const char *name, tree fntype)
+{
+  tree fndecl = build_decl (UNKNOWN_LOCATION,
+                           FUNCTION_DECL,
+                           NULL /* set below */,
+                           fntype);
+  char *_name = xasprintf ("__ga68_%s%d", name, DECL_UID (fndecl));
+  DECL_NAME (fndecl) = get_identifier (_name);
+  free (_name);
+  DECL_EXTERNAL (fndecl) = 0;
+  TREE_PUBLIC (fndecl) = 0;
+  TREE_STATIC (fndecl) = 1;
+
+  return fndecl;
+}
+
+/* Build a PARM_DECL whose context is TYPE with the given NAME.  */
+
+tree
+a68_low_func_param (tree fndecl, const char *name, tree type)
+{
+  tree param = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+                          get_identifier (name), type);
+  DECL_CONTEXT (param) = fndecl;
+  DECL_ARG_TYPE (param) = TREE_TYPE (param);
+  layout_decl (param, 0);
+  return param;
+}
+
+/* Lower a particular program.
+
+     particular program : label, enclosed clause; enclosed clause.
+
+   This handler always returns NULL_TREE.  */
+
+static tree
+lower_particular_program (NODE_T *p,
+                         LOW_CTX_T ctx ATTRIBUTE_UNUSED)
+{
+  /* Create the main function that conforms the particular program.  */
+  tree main_decl = build_decl (a68_get_node_location (p),
+                              FUNCTION_DECL,
+                              get_identifier ("__algol68_main"),
+                              build_function_type (void_type_node,
+                                                   void_list_node));
+  DECL_EXTERNAL (main_decl) = 0;
+  TREE_PUBLIC (main_decl) = 1;
+  TREE_STATIC (main_decl) = 1;
+
+  a68_push_function_range (main_decl,
+                          void_type_node /* result_type */);
+
+  /* Lower the body of the function.  */
+  NODE_T *enclosed_clause = (IS (SUB (p), ENCLOSED_CLAUSE)
+                            ? SUB (p) : NEXT (SUB (p)));
+  tree body_expr = a68_lower_tree (enclosed_clause, ctx);
+  a68_pop_function_range (body_expr);
+  return NULL_TREE;
+}
+
+/* Lower the given tree P using the given context CTX.  */
+
+tree
+a68_lower_tree (NODE_T *p, LOW_CTX_T ctx)
+{
+#if 0
+  for (int i = 0; i < ctx.level; ++i)
+    printf (" ");
+  printf ("LOWER TREE: %d::%s\n",
+         NUMBER (p), a68_attribute_name (ATTRIBUTE (p)));
+#endif
+  ctx.level++;
+
+  tree res = NULL_TREE;
+
+  if (p == NO_NODE)
+    gcc_unreachable ();
+
+  switch (ATTRIBUTE (p))
+    {
+    case PARTICULAR_PROGRAM:
+      res = lower_particular_program (p, ctx);
+      break;
+      /* Clauses */
+    case ENCLOSED_CLAUSE:
+      res = a68_lower_enclosed_clause (p, ctx);
+      break;
+    case CLOSED_CLAUSE:
+      res = a68_lower_closed_clause (p, ctx);
+      break;
+    case PARALLEL_CLAUSE:
+      res = a68_lower_parallel_clause (p, ctx);
+      break;
+    case COLLATERAL_CLAUSE:
+      res = a68_lower_collateral_clause (p, ctx);
+      break;
+    case UNIT_LIST:
+      res = a68_lower_unit_list (p, ctx);
+      break;
+    case CONDITIONAL_CLAUSE:
+      res = a68_lower_conditional_clause (p, ctx);
+      break;
+    case ENQUIRY_CLAUSE:
+      res = a68_lower_enquiry_clause (p, ctx);
+      break;
+    case CASE_CLAUSE:
+      res = a68_lower_case_clause (p, ctx);
+      break;
+    case CONFORMITY_CLAUSE:
+      res = a68_lower_conformity_clause (p, ctx);
+      break;
+    case LOOP_CLAUSE:
+      res = a68_lower_loop_clause (p, ctx);
+      break;
+    case SERIAL_CLAUSE:
+      res = a68_lower_serial_clause (p, ctx);
+      break;
+    case INITIALISER_SERIES:
+      res = a68_lower_initialiser_series (p, ctx);
+      break;
+    case EXIT_SYMBOL:
+      res = a68_lower_completer (p, ctx);
+      break;
+    case LABELED_UNIT:
+      res = a68_lower_labeled_unit (p, ctx);
+      break;
+    case LABEL:
+      res = a68_lower_label (p, ctx);
+      break;
+      /* Declarations.  */
+    case DECLARATION_LIST:
+      res = a68_lower_declaration_list (p, ctx);
+      break;
+    case DECLARER:
+      res = a68_lower_declarer (p, ctx);
+      break;
+    case IDENTITY_DECLARATION:
+      res = a68_lower_identity_declaration (p, ctx);
+      break;
+    case VARIABLE_DECLARATION:
+      res = a68_lower_variable_declaration (p, ctx);
+      break;
+    case PROCEDURE_DECLARATION:
+      res = a68_lower_procedure_declaration (p, ctx);
+      break;
+    case PROCEDURE_VARIABLE_DECLARATION:
+      res = a68_lower_procedure_variable_declaration (p, ctx);
+      break;
+    case PRIORITY_DECLARATION:
+      res = a68_lower_priority_declaration (p, ctx);
+      break;
+    case BRIEF_OPERATOR_DECLARATION:
+      res = a68_lower_brief_operator_declaration (p, ctx);
+      break;
+    case OPERATOR_DECLARATION:
+      res = a68_lower_operator_declaration (p, ctx);
+      break;
+    case MODE_DECLARATION:
+      res = a68_lower_mode_declaration (p, ctx);
+      break;
+      /* Units. */
+    case UNIT:
+      res = a68_lower_unit (p, ctx);
+      break;
+    case ROUTINE_TEXT:
+      res = a68_lower_routine_text (p, ctx);
+      break;
+    case ASSIGNATION:
+      res = a68_lower_assignation (p, ctx);
+      break;
+    case TERTIARY:
+      res = a68_lower_tertiary (p, ctx);
+      break;
+    case MONADIC_FORMULA:
+      res = a68_lower_monadic_formula (p, ctx);
+      break;
+    case FORMULA:
+      res = a68_lower_formula (p, ctx);
+      break;
+    case SECONDARY:
+      res = a68_lower_secondary (p, ctx);
+      break;
+    case SLICE:
+      res = a68_lower_slice (p, ctx);
+      break;
+    case SELECTION:
+      res = a68_lower_selection (p, ctx);
+      break;
+    case PRIMARY:
+      res = a68_lower_primary (p, ctx);
+      break;
+    case GENERATOR:
+      res = a68_lower_generator (p, ctx);
+      break;
+    case CALL:
+      res = a68_lower_call (p, ctx);
+      break;
+    case CAST:
+      res = a68_lower_cast (p, ctx);
+      break;
+    case AND_FUNCTION:
+    case OR_FUNCTION:
+      res = a68_lower_logic_function (p, ctx);
+      break;
+    case IDENTITY_RELATION:
+      res = a68_lower_identity_relation (p, ctx);
+      break;
+    case EMPTY_SYMBOL:
+      res = a68_lower_empty (p, ctx);
+      break;
+    case NIHIL:
+      res = a68_lower_nihil (p, ctx);
+      break;
+    case SKIP:
+      res = a68_lower_skip (p, ctx);
+      break;
+    case DENOTATION:
+      res = a68_lower_denotation (p, ctx);
+      break;
+    case IDENTIFIER:
+      res = a68_lower_identifier (p, ctx);
+      break;
+      /* Coercions.  */
+    case ROWING:
+      res = a68_lower_rowing (p, ctx);
+      break;
+    case WIDENING:
+      res = a68_lower_widening (p, ctx);
+      break;
+    case DEPROCEDURING:
+      res = a68_lower_deproceduring (p, ctx);
+      break;
+    case PROCEDURING:
+      res = a68_lower_proceduring (p, ctx);
+      break;
+    case VOIDING:
+      res = a68_lower_voiding (p, ctx);
+      break;
+    case DEREFERENCING:
+      res = a68_lower_dereferencing (p, ctx);
+      break;
+      /* Others. */
+    case UNITING:
+      res = a68_lower_uniting (p, ctx);
+      break;
+    case JUMP:
+      res = a68_lower_jump (p, ctx);
+      break;
+    case PARAMETER:
+      res = a68_lower_parameter (p, ctx);
+      break;
+    case PARAMETER_LIST:
+      res = a68_lower_parameter_list (p, ctx);
+      break;
+    case PARAMETER_PACK:
+      res = a68_lower_parameter_pack (p, ctx);
+      break;
+    case OPERATOR:
+      res = a68_lower_operator (p, ctx);
+      break;
+    case ASSERTION:
+      res = a68_lower_assertion (p, ctx);
+      break;
+    case STOP:
+      res = NULL_TREE;
+      break;
+    default:
+      fatal_error (a68_get_node_location (p), "cannot lower node %s",
+                  a68_attribute_name (ATTRIBUTE (p)));
+      gcc_unreachable ();
+      break;
+    }
+
+  return res;
+}
+
+/* Lower an Algol 68 complete parse tree to a GENERIC tree.  */
+
+tree
+a68_lower_top_tree (NODE_T *p)
+{
+  LOW_CTX_T top_ctx;
+
+  top_ctx.declarer = NULL;
+  top_ctx.proc_decl_identifier = NO_NODE;
+  top_ctx.level = 0;
+  return a68_lower_tree (p, top_ctx);
+}
-- 
2.30.2

Reply via email to