Signed-off-by: Jose E. Marchesi <[email protected]>
gcc/ChangeLog
* algol68/a68-low-bits.cc: New file.
* algol68/a68-low-bools.cc: Likewise.
* algol68/a68-low-chars.cc: Likewise.
* algol68/a68-low-complex.cc: Likewise.
* algol68/a68-low-ints.cc: Likewise.
* algol68/a68-low-procs.cc: Likewise.
* algol68/a68-low-reals.cc: Likewise.
* algol68/a68-low-refs.cc: Likewise.
* algol68/a68-low-strings.cc: Likewise.
---
gcc/algol68/a68-low-bits.cc | 297 ++++++++++++++++
gcc/algol68/a68-low-bools.cc | 77 ++++
gcc/algol68/a68-low-chars.cc | 170 +++++++++
gcc/algol68/a68-low-complex.cc | 141 ++++++++
gcc/algol68/a68-low-ints.cc | 327 +++++++++++++++++
gcc/algol68/a68-low-procs.cc | 52 +++
gcc/algol68/a68-low-reals.cc | 620 +++++++++++++++++++++++++++++++++
gcc/algol68/a68-low-refs.cc | 52 +++
gcc/algol68/a68-low-strings.cc | 390 +++++++++++++++++++++
9 files changed, 2126 insertions(+)
create mode 100644 gcc/algol68/a68-low-bits.cc
create mode 100644 gcc/algol68/a68-low-bools.cc
create mode 100644 gcc/algol68/a68-low-chars.cc
create mode 100644 gcc/algol68/a68-low-complex.cc
create mode 100644 gcc/algol68/a68-low-ints.cc
create mode 100644 gcc/algol68/a68-low-procs.cc
create mode 100644 gcc/algol68/a68-low-reals.cc
create mode 100644 gcc/algol68/a68-low-refs.cc
create mode 100644 gcc/algol68/a68-low-strings.cc
diff --git a/gcc/algol68/a68-low-bits.cc b/gcc/algol68/a68-low-bits.cc
new file mode 100644
index 00000000000..465969f9ade
--- /dev/null
+++ b/gcc/algol68/a68-low-bits.cc
@@ -0,0 +1,297 @@
+/* Lowering routines for all things related to BITS values.
+ 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 the yielind of SKIP for the given BITS mode. */
+
+tree
+a68_get_bits_skip_tree (MOID_T *m)
+{
+ tree type;
+
+ if (m == M_BITS)
+ type = a68_bits_type;
+ else if (m == M_LONG_BITS)
+ type = a68_long_bits_type;
+ else if (m == M_LONG_LONG_BITS)
+ type = a68_long_long_bits_type;
+ else if (m == M_SHORT_BITS)
+ type = a68_short_bits_type;
+ else if (m == M_SHORT_SHORT_BITS)
+ type = a68_short_short_bits_type;
+ else
+ gcc_unreachable ();
+
+ return build_int_cst (type, 0);
+}
+
+/* Given a BITS type, compute the number of bits that fit in a value of that
+ type. The result is an INT. */
+
+tree
+a68_bits_width (tree type)
+{
+ return fold_convert (a68_int_type, TYPE_SIZE (type));
+}
+
+/* Given a BITS type, compute the maximum value that can be expressed with that
+ type. */
+
+tree
+a68_bits_maxbits (tree type)
+{
+ return fold_convert (type, TYPE_MAX_VALUE (type));
+}
+
+/* Given a SIZETY INT value VAL, compute and return a SIZETY BITS reflecting
+ its constituent bits.
+
+ In strict Algol 68 the BIN of a negative value is BITS (SKIP).
+
+ In GNU 68 the BIN of a negative value is the constituent bits of the two's
+ complement of the value. */
+
+tree
+a68_bits_bin (MOID_T *m, tree val)
+{
+ tree type = CTYPE (m);
+
+ if (OPTION_STRICT (&A68_JOB))
+ return a68_get_bits_skip_tree (m);
+ else
+ return fold_convert (type, val);
+}
+
+/* Given a SIZETY BITS value BITS, compute and return the corresponding SIZETY
+ INT.
+
+ In strict Algol 68 the ABS of a BITS value reflecting a bit pattern that
+ would correspond a negative integral value is INT (SKIP).
+
+ In GNU 68 the ABS of a BITS value reflecting a bit pattern that would
+ correspond a negative integral value is that negative integral value. */
+
+tree
+a68_bits_abs (MOID_T *m, tree bits)
+{
+ tree type = CTYPE (m);
+
+ if (OPTION_STRICT (&A68_JOB))
+ {
+ tree integral_val = save_expr (fold_convert (type, bits));
+ return fold_build3 (COND_EXPR,
+ type,
+ fold_build2 (LT_EXPR, type, integral_val,
+ build_int_cst (type, 0)),
+ a68_get_int_skip_tree (m),
+ integral_val);
+ }
+ else
+ return fold_convert (type, bits);
+}
+
+/* Given a SIZETY BITS value BITS, shorten it into a SIZETY BITS whose tree
+ type is TYPE. */
+
+tree
+a68_bits_shorten (tree type, tree bits)
+{
+ /* This will truncate at the left, which is what is intended. */
+ return fold_convert (type, bits);
+}
+
+/* Given a SIZETY BITS value BITS, length it into a SIZETY BITS whose tree type
+ is TYPE. */
+
+tree
+a68_bits_leng (tree type, tree bits)
+{
+ /* This will add zeroes to the left, which is what is intended. */
+ return fold_convert (type, bits);
+}
+
+/* Given a SIZETY BITS value BITS, compute and return a new SIZETY BITS whose
+ bits are the logical negation of the bits of BITS. */
+
+tree
+a68_bits_not (tree bits)
+{
+ return fold_build1 (BIT_NOT_EXPR, TREE_TYPE (bits), bits);
+}
+
+/* Given two SIZETY BITS values BITS1 and BITS2, compute and return a new
+ SIZETY BITS whose bits are the `and' of the bits of BITS1 and
+ BITS2. */
+
+tree
+a68_bits_and (tree bits1, tree bits2)
+{
+ return fold_build2 (BIT_AND_EXPR, TREE_TYPE (bits1), bits1, bits2);
+}
+
+/* Given two SIZETY BITS values BITS1 and BITS2, compute and return a new
+ SIZETY BITS whose bits are the inclusive-or of the bits of BITS1 and
+ BITS2. */
+
+tree
+a68_bits_ior (tree bits1, tree bits2)
+{
+ return fold_build2 (BIT_IOR_EXPR, TREE_TYPE (bits1), bits1, bits2);
+}
+
+/* Given two SIZETY BITS values BITS1 and BITS2, compute and return a new
+ SIZETY BITS whose bits are the exclusive-or of the bits of BITS1 and
+ BITS2. */
+
+tree
+a68_bits_xor (tree bits1, tree bits2)
+{
+ return fold_build2 (BIT_XOR_EXPR, TREE_TYPE (bits1), bits1, bits2);
+}
+
+/* Given a position POS of mode INT and a BITS of mode SIZETY BITS, return a
+ BOOL reflecting the state of the bit occupying the position POS in BITS.
+
+ If POS is out of range a run-time error is emitted. */
+
+tree
+a68_bits_elem (NODE_T *p, tree pos, tree bits)
+{
+ pos = save_expr (pos);
+ tree one = build_int_cst (TREE_TYPE (bits), 1);
+
+ tree shift = fold_build2 (MINUS_EXPR, bitsizetype,
+ TYPE_SIZE (TREE_TYPE (bits)),
+ fold_convert (bitsizetype, pos));
+ tree elem = fold_build2 (EQ_EXPR,
+ a68_bool_type,
+ fold_build2 (BIT_AND_EXPR,
+ TREE_TYPE (bits),
+ fold_build2 (RSHIFT_EXPR,
+ TREE_TYPE (bits),
+ bits, shift),
+ one),
+ one);
+
+ /* Do bounds checking if requested. */
+ if (OPTION_BOUNDS_CHECKING (&A68_JOB))
+ {
+ 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_BITSBOUNDSERROR,
+ void_type_node, 3,
+ filename,
+ build_int_cst (unsigned_type_node, lineno),
+ fold_convert (ssizetype, pos));
+ tree check = fold_build2 (TRUTH_AND_EXPR, integer_type_node,
+ fold_build2 (GT_EXPR, integer_type_node,
+ pos, fold_convert (TREE_TYPE
(pos), integer_zero_node)),
+ fold_build2 (LE_EXPR, integer_type_node,
+ fold_convert (bitsizetype, pos),
+ TYPE_SIZE (TREE_TYPE (bits))));
+
+ check = fold_build2_loc (a68_get_node_location (p),
+ TRUTH_ORIF_EXPR,
+ ssizetype,
+ check,
+ fold_build2 (COMPOUND_EXPR, a68_bool_type,
+ call, boolean_false_node));
+ elem = fold_build2 (COMPOUND_EXPR, a68_bool_type,
+ check, elem);
+ }
+
+ return elem;
+}
+
+/* Given two SIZETY BITS values BITS1 and BITS2, return a BOOL value indicating
+ whether all the bits set in BITS1 are also set in BITS2. */
+
+tree
+a68_bits_subset (tree bits1, tree bits2)
+{
+ /* We compute this operation with `A | B == B' as specified by the Report */
+ bits2 = save_expr (bits2);
+ return fold_build2 (EQ_EXPR, a68_bool_type,
+ fold_build2 (BIT_IOR_EXPR, TREE_TYPE (bits1), bits1,
bits2),
+ bits2);
+}
+
+/* Rotate the bits in BITS SHIFT bits to the left if SHIFT is positive, or ABS
+ (SHIFT) bits to the right if SHIFT is negative.
+
+ A run-time error is raised if the count overflows the BITS value. */
+
+tree
+a68_bits_shift (tree shift, tree bits)
+{
+ shift = save_expr (shift);
+ bits = save_expr (bits);
+ return fold_build3 (COND_EXPR,
+ TREE_TYPE (bits),
+ fold_build2 (GE_EXPR, TREE_TYPE (shift),
+ shift, build_int_cst (TREE_TYPE (shift), 0)),
+ fold_build2 (LSHIFT_EXPR, TREE_TYPE (bits),
+ bits, shift),
+ fold_build2 (RSHIFT_EXPR, TREE_TYPE (bits),
+ bits,
+ fold_build1 (ABS_EXPR, TREE_TYPE (shift),
shift)));
+}
+
+/* Given two bits values, build an expression that calculates whether A = B.
*/
+
+tree
+a68_bits_eq (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, EQ_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two bits values, build an expression that calculates whether A /=
+ B. */
+
+tree
+a68_bits_ne (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, NE_EXPR, boolean_type_node, a, b);
+}
diff --git a/gcc/algol68/a68-low-bools.cc b/gcc/algol68/a68-low-bools.cc
new file mode 100644
index 00000000000..000e919407d
--- /dev/null
+++ b/gcc/algol68/a68-low-bools.cc
@@ -0,0 +1,77 @@
+/* Lowering routines for all things related to BOOL values.
+ 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 the yielind of SKIP of a BOOL mode. */
+
+tree
+a68_get_bool_skip_tree (void)
+{
+ return build_int_cst (a68_bool_type, 0);
+}
+
+/* The absolute value of a BOOL is a non-zero INT for TRUE and zero for
+ FALSE. */
+
+tree
+a68_bool_abs (tree val)
+{
+ return fold_convert (a68_int_type, val);
+}
+
+/* Given two boolean values, build an expression that calculates whether A =
B. */
+
+tree
+a68_bool_eq (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, EQ_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two boolean values, build an expression that calculates whether A /=
+ B. */
+
+tree
+a68_bool_ne (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, NE_EXPR, boolean_type_node, a, b);
+}
diff --git a/gcc/algol68/a68-low-chars.cc b/gcc/algol68/a68-low-chars.cc
new file mode 100644
index 00000000000..24449347555
--- /dev/null
+++ b/gcc/algol68/a68-low-chars.cc
@@ -0,0 +1,170 @@
+/* Lowering routines for all things related to STRINGs.
+ 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 the yielind of SKIP of a CHAR mode. */
+
+tree
+a68_get_char_skip_tree (void)
+{
+ return build_int_cst (a68_char_type, ' ');
+}
+
+/* Return the maximum valid character code that can be stored in a CHAR. */
+tree
+a68_char_max (void)
+{
+ /* 0x10FFFF is the maximum valid code point in Unicode. */
+ return build_int_cst (a68_char_type, 0x10FFFF);
+}
+
+/* Given an integral value, if it denotes a char code build the corresponding
+ CHAR. Otherwise raise a run-time error. */
+
+tree
+a68_char_repr (NODE_T *p, tree val)
+{
+ /* UCS-4 (UTF-32) encodes the Unicode code points using the identity
+ function. Valid code points are in the ranges [U+0000,U+D7FF] and
+ [U+E000,U+10FFFF]. */
+
+ tree c = save_expr (val);
+ tree val_type = TREE_TYPE (val);
+
+ /* (c >= 0 && c < 0xd800) */
+ tree range1 = fold_build2 (TRUTH_AND_EXPR, integer_type_node,
+ fold_build2 (GE_EXPR, integer_type_node,
+ c, fold_convert (val_type,
integer_zero_node)),
+ fold_build2 (LT_EXPR, integer_type_node,
+ c, build_int_cst (val_type, 0xd800)));
+ /* (c >= 0xe000 && c < 0x110000) */
+ tree range2 = fold_build2 (TRUTH_AND_EXPR, integer_type_node,
+ fold_build2 (GE_EXPR, integer_type_node,
+ c, build_int_cst (val_type, 0xe000)),
+ fold_build2 (LT_EXPR, integer_type_node,
+ c, build_int_cst (val_type,
0x110000)));
+ tree notvalid = fold_build1 (TRUTH_NOT_EXPR,
+ integer_type_node,
+ fold_build2 (TRUTH_OR_EXPR, integer_type_node,
+ range1, range2));
+
+ /* Call to the runtime run-time error handler. */
+ 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_INVALIDCHARERROR,
+ void_type_node, 3,
+ filename,
+ build_int_cst (unsigned_type_node, lineno),
+ fold_convert (a68_int_type, c));
+
+ /* Return the REPR of the given integer value, or raise run-time error. */
+ return fold_build2 (COMPOUND_EXPR, a68_char_type,
+ fold_build3 (COND_EXPR, integer_type_node,
+ notvalid,
+ call, integer_zero_node),
+ fold_convert (a68_char_type, c));
+}
+
+/* the ABS of a CHAR is an INT containing an unique value for each permissable
+ char value. */
+
+tree
+a68_char_abs (tree val)
+{
+ return fold_convert (a68_int_type, val);
+}
+
+/* Given two characters, build an expression that calculates whether A = B. */
+
+tree
+a68_char_eq (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, EQ_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two characters, build an expression that calculates whether A /=
+ B. */
+
+tree
+a68_char_ne (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, NE_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two characters, build an expression that calculates
+ whether A < B. */
+
+tree
+a68_char_lt (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, LT_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two characters, build an expression that calculates
+ whether A <= B. */
+
+tree
+a68_char_le (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, LE_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two characters, build an expression that calculates
+ whether A > B. */
+
+tree
+a68_char_gt (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, GT_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two characters, build an expression that calculates
+ whether A >= B. */
+
+tree
+a68_char_ge (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, GE_EXPR, boolean_type_node, a, b);
+}
diff --git a/gcc/algol68/a68-low-complex.cc b/gcc/algol68/a68-low-complex.cc
new file mode 100644
index 00000000000..aed1c3c3dab
--- /dev/null
+++ b/gcc/algol68/a68-low-complex.cc
@@ -0,0 +1,141 @@
+/* Lowering routines for all things related to COMPL values.
+ 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"
+
+/* Build a new COMPL value with real part RE and imaginary part IM, of mode
+ MODE. */
+
+tree
+a68_complex_i (MOID_T *mode, tree re, tree im)
+{
+ tree compl_type = CTYPE (mode);
+
+ tree re_field = TYPE_FIELDS (compl_type);
+ tree im_field = TREE_CHAIN (re_field);
+ return build_constructor_va (CTYPE (mode), 2,
+ re_field, re,
+ im_field, im);
+}
+
+/* Given a COMPL value Z, get its real part. */
+
+tree
+a68_complex_re (tree z)
+{
+ tree re_field = TYPE_FIELDS (TREE_TYPE (z));
+ return fold_build3 (COMPONENT_REF, TREE_TYPE (re_field),
+ z, re_field, NULL_TREE);
+}
+
+tree
+a68_complex_im (tree z)
+{
+ tree im_field = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (z)));
+ return fold_build3 (COMPONENT_REF, TREE_TYPE (im_field),
+ z, im_field, NULL_TREE);
+}
+
+/* Return the conjugate of the given complex Z of mode MODE. */
+
+tree
+a68_complex_conj (MOID_T *mode, tree z)
+{
+ tree re_field = TYPE_FIELDS (TREE_TYPE (z));
+ tree complex_type = build_complex_type (TREE_TYPE (re_field), false /* named
*/);
+
+ z = save_expr (z);
+ tree complex = fold_build2 (COMPLEX_EXPR, complex_type,
+ a68_complex_re (z), a68_complex_im (z));
+ tree conj = fold_build1 (CONJ_EXPR, TREE_TYPE (complex), complex);
+
+ return a68_complex_i (mode,
+ fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (z)),
conj),
+ fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (z)),
conj));
+}
+
+/* Widen a real R to a complex of mode MODE. */
+
+tree
+a68_complex_widen_from_real (MOID_T *mode, tree r)
+{
+ tree compl_type = CTYPE (mode);
+ gcc_assert (compl_type != NULL_TREE);
+
+ /* Sanity check. */
+ if (mode == M_COMPLEX)
+ gcc_assert (TREE_TYPE (r) == a68_real_type);
+ else if (mode == M_LONG_COMPLEX)
+ gcc_assert (TREE_TYPE (r) == a68_long_real_type);
+ else if (mode == M_LONG_LONG_COMPLEX)
+ gcc_assert (TREE_TYPE (r) == a68_long_long_real_type);
+ else
+ gcc_unreachable ();
+
+ a68_push_range (mode);
+ tree res = a68_lower_tmpvar ("compl%", compl_type,
+ a68_get_skip_tree (mode));
+
+ /* Look for the "re" field. */
+ tree field_id = a68_get_mangled_identifier ("re");
+ tree field = NULL_TREE;
+ for (tree f = TYPE_FIELDS (compl_type); f; f = DECL_CHAIN (f))
+ {
+ if (field_id == DECL_NAME (f))
+ {
+ field = f;
+ break;
+ }
+ }
+ gcc_assert (field != NULL_TREE);
+
+ /* Set it to the given real value. */
+ a68_add_stmt (fold_build2 (MODIFY_EXPR,
+ TREE_TYPE (r),
+ fold_build3 (COMPONENT_REF,
+ TREE_TYPE (field),
+ res, field,
+ NULL_TREE),
+ r));
+ a68_add_stmt (res);
+ return a68_pop_range ();
+}
diff --git a/gcc/algol68/a68-low-ints.cc b/gcc/algol68/a68-low-ints.cc
new file mode 100644
index 00000000000..d119de9a56b
--- /dev/null
+++ b/gcc/algol68/a68-low-ints.cc
@@ -0,0 +1,327 @@
+/* Lowering routines for all things related to INT values.
+ 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 the yielind of SKIP for the given integral mode. */
+
+tree
+a68_get_int_skip_tree (MOID_T *m)
+{
+ tree type;
+
+ if (m == M_INT)
+ type = a68_int_type;
+ else if (m == M_LONG_INT)
+ type = a68_long_int_type;
+ else if (m == M_LONG_LONG_INT)
+ type = a68_long_long_int_type;
+ else if (m == M_SHORT_INT)
+ type = a68_short_int_type;
+ else if (m == M_SHORT_SHORT_INT)
+ type = a68_short_short_int_type;
+ else
+ gcc_unreachable ();
+
+ return build_int_cst (type, 0);
+}
+
+/* Given an integral type, build the maximum value expressable in that
+ type. */
+
+tree
+a68_int_maxval (tree type)
+{
+ return fold_convert (type, TYPE_MAX_VALUE (type));
+}
+
+/* Given an integral type, build the minimum value expressable in that
+ type. */
+
+tree
+a68_int_minval (tree type)
+{
+ return fold_convert (type, TYPE_MIN_VALUE (type));
+}
+
+/* Given an integral type, build an INT with the number of decimal digits
+ required to represent a value of that typ, not including sign. */
+
+tree
+a68_int_width (tree type)
+{
+ /* Note that log10 (2) is ~ 0.3.
+ Thanks to Andrew Pinski for suggesting using this expression. */
+ return fold_build2 (PLUS_EXPR, a68_int_type,
+ build_int_cst (a68_int_type, 1),
+ fold_build2 (TRUNC_DIV_EXPR,
+ a68_int_type,
+ fold_build2 (MULT_EXPR, a68_int_type,
+ build_int_cst (a68_int_type,
TYPE_PRECISION (type)),
+ build_int_cst (a68_int_type,
3)),
+ build_int_cst (a68_int_type, 10)));
+}
+
+/* Given an integer value VAL, return -1 if it is less than zero, 0 if it is
+ zero and +1 if it is bigger than zero. The built value is always of mode
+ M_INT. */
+
+tree
+a68_int_sign (tree val)
+{
+ tree zero = build_int_cst (TREE_TYPE (val), 0);
+ return fold_build3 (COND_EXPR,
+ a68_int_type,
+ fold_build2 (EQ_EXPR, integer_type_node, val, zero),
+ build_int_cst (a68_int_type, 0),
+ fold_build3 (COND_EXPR,
+ a68_int_type,
+ fold_build2 (GT_EXPR, integer_type_node,
val, zero),
+ build_int_cst (a68_int_type, 1),
+ build_int_cst (a68_int_type, -1)));
+}
+
+/* Absolute value of an integer. */
+
+tree
+a68_int_abs (tree val)
+{
+ return fold_build1 (ABS_EXPR, TREE_TYPE (val), val);
+}
+
+/* Build the integral value lengthened from the value of VAL, from mode
+ FROM_MODE to mode TO_MODE. */
+
+tree
+a68_int_leng (MOID_T *to_mode, MOID_T *from_mode ATTRIBUTE_UNUSED, tree val)
+{
+ /* Lengthening can be done by just a cast. */
+ return fold_convert (CTYPE (to_mode), val);
+}
+
+/* Build the integral value that can be lengthened to the value of VAL, from
+ mode FROM_MODE to mode TO_MODE.
+
+ If VAL cannot be represented in TO_MODE because it is bigger than the most
+ positive value representable in TO_MODE, then it is truncated to that value.
+
+ Likewise, if VAL cannot be represented in TO_MODE because it is less than
+ the most negative value representable in TO_MODE, then it is truncated to
+ that value. */
+
+tree
+a68_int_shorten (MOID_T *to_mode, MOID_T *from_mode ATTRIBUTE_UNUSED, tree val)
+{
+ tree most_positive_value = fold_convert (CTYPE (from_mode),
+ a68_int_maxval (CTYPE (to_mode)));
+ tree most_negative_value = fold_convert (CTYPE (from_mode),
+ a68_int_minval (CTYPE (to_mode)));
+
+ val = save_expr (val);
+ most_positive_value = save_expr (most_positive_value);
+ most_negative_value = save_expr (most_negative_value);
+ return fold_build3 (COND_EXPR, CTYPE (to_mode),
+ fold_build2 (GT_EXPR, a68_bool_type, val,
most_positive_value),
+ fold_convert (CTYPE (to_mode), most_positive_value),
+ fold_build3 (COND_EXPR, CTYPE (to_mode),
+ fold_build2 (LT_EXPR, a68_bool_type, val,
most_negative_value),
+ fold_convert (CTYPE (to_mode),
most_negative_value),
+ fold_convert (CTYPE (to_mode), val)));
+}
+
+/* Given two integral values of mode M, build an expression that calculates the
+ addition of A and B. */
+
+tree
+a68_int_plus (MOID_T *m, tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, PLUS_EXPR, CTYPE (m), a, b);
+}
+
+/* Given two integral values of mode M, build an expression that calculates the
+ subtraction of A by B. */
+
+tree
+a68_int_minus (MOID_T *m, tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, MINUS_EXPR, CTYPE (m), a, b);
+}
+
+/* Given two integral values of mode M, build an expression that calculates the
+ multiplication of A by B. */
+
+tree
+a68_int_mult (MOID_T *m, tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, MULT_EXPR, CTYPE (m), a, b);
+}
+
+/* Given two integral values of mode M, build an expression that calculates the
+ division of A by B. */
+
+tree
+a68_int_div (MOID_T *m, tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, TRUNC_DIV_EXPR, CTYPE (m), a, b);
+}
+
+/* Given two integral values of mode M, build an expression that calculates
+ whether A = B. */
+
+tree
+a68_int_eq (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, EQ_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two integral values of mode M, build an expression that calculates
+ whether A /= B. */
+
+tree
+a68_int_ne (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, NE_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two integral values of mode M, build an expression that calculates
+ whether A < B. */
+
+tree
+a68_int_lt (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, LT_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two integral values of mode M, build an expression that calculates
+ whether A <= B. */
+
+tree
+a68_int_le (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, LE_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two integral values of mode M, build an expression that calculates
+ whether A > B. */
+
+tree
+a68_int_gt (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, GT_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two integral values of mode M, build an expression that calculates
+ whether A >= B. */
+
+tree
+a68_int_ge (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, GE_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two integral values of mode M, build and expression that calculates
the
+ modulus as specified by the Revised Report:
+
+ OP MOD = (L INT a, b) L INT:
+ (INT r = a - a % b * b; r < 0 | r + ABS b | r)
+*/
+
+tree
+a68_int_mod (MOID_T *m, tree a, tree b, location_t loc)
+{
+ a = save_expr (a);
+ b = save_expr (b);
+ tree r = a68_int_minus (m, a, a68_int_mult (m, a68_int_div (m, a, b), b));
+
+ r = save_expr (r);
+ return fold_build3_loc (loc, COND_EXPR, CTYPE (m),
+ a68_int_lt (r, build_int_cst (CTYPE (m), 0)),
+ a68_int_plus (m, r, a68_int_abs (b)),
+ r);
+}
+
+/* Given two integral values values, the first of mode M an the second of mode
+ INT, build an expression that calculates the exponentiation of A by B, as
+ specified by the Revised Report:
+
+ OP ** = (L INT a, INT b) L INT:
+ (b >= 0 | L INT p := L 1; TO b DO p := p * a OD; p)
+*/
+
+tree
+a68_int_pow (MOID_T *m, tree a, tree b, location_t loc)
+{
+ tree zero = build_int_cst (CTYPE (m), 0);
+ tree one = build_int_cst (CTYPE (m), 1);
+
+ a = save_expr (a);
+ b = save_expr (fold_convert (CTYPE (m), b));
+
+ a68_push_range (m);
+ tree index = a68_lower_tmpvar ("index%", CTYPE (m), zero);
+ tree p = a68_lower_tmpvar ("p%", CTYPE (m), one);
+
+ /* Begin of loop body. */
+ a68_push_range (NULL);
+ {
+ /* if (index == b) break; */
+ a68_add_stmt (fold_build1 (EXIT_EXPR,
+ void_type_node,
+ fold_build2 (EQ_EXPR, CTYPE (m),
+ index, b)));
+ a68_add_stmt (fold_build2 (MODIFY_EXPR, CTYPE (m),
+ p, a68_int_mult (m, p, a)));
+
+ /* index++ */
+ a68_add_stmt (fold_build2 (POSTINCREMENT_EXPR, CTYPE (m),
+ index, one));
+ }
+ tree loop_body = a68_pop_range ();
+ a68_add_stmt (fold_build1 (LOOP_EXPR,
+ void_type_node,
+ loop_body));
+ a68_add_stmt (p);
+ tree calculate_p = a68_pop_range ();
+ return fold_build3_loc (loc, COND_EXPR, CTYPE (m),
+ a68_int_ge (b, zero),
+ calculate_p, zero);
+}
diff --git a/gcc/algol68/a68-low-procs.cc b/gcc/algol68/a68-low-procs.cc
new file mode 100644
index 00000000000..cc43d52aa6b
--- /dev/null
+++ b/gcc/algol68/a68-low-procs.cc
@@ -0,0 +1,52 @@
+/* Lowering routines for all things related to procedures.
+ 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 the yielding of SKIP for the given procedure mode. */
+
+tree
+a68_get_proc_skip_tree (MOID_T *m)
+{
+ /* A SKIP for a procecure mode lowers to a NULL pointer to a function. */
+ return build_int_cst (CTYPE (m), 0);
+}
diff --git a/gcc/algol68/a68-low-reals.cc b/gcc/algol68/a68-low-reals.cc
new file mode 100644
index 00000000000..ab0064a4855
--- /dev/null
+++ b/gcc/algol68/a68-low-reals.cc
@@ -0,0 +1,620 @@
+/* Lowering routines for all things related to REAL values.
+ 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 "math.h" /* For log10 */
+
+#include "a68.h"
+
+tree
+a68_get_real_skip_tree (MOID_T *m)
+{
+ tree int_type = NULL_TREE;
+ tree real_type = NULL_TREE;
+
+ if (m == M_REAL)
+ {
+ int_type = a68_int_type;
+ real_type = a68_real_type;
+ }
+ else if (m == M_LONG_REAL)
+ {
+ int_type = a68_long_int_type;
+ real_type = a68_long_real_type;
+ }
+ else if (m == M_LONG_LONG_REAL)
+ {
+ int_type = a68_long_long_int_type;
+ real_type = a68_long_long_real_type;
+ }
+ else
+ gcc_unreachable ();
+
+ return build_real_from_int_cst (real_type,
+ build_int_cst (int_type, 0));
+}
+
+static tree
+addr_of_builtin_decl (enum built_in_function fncode)
+{
+ tree builtin = builtin_decl_explicit (fncode);
+ return fold_build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (builtin)),
builtin);
+}
+
+/* Build PI for the given real type. */
+
+tree
+a68_real_pi (tree type)
+{
+ return build_real (type, dconst_pi ());
+}
+
+/* Given a real type, build the maximum value expresssable with that type. */
+
+tree
+a68_real_maxval (tree type)
+{
+ REAL_VALUE_TYPE max;
+ real_maxval (&max, 0, TYPE_MODE (type));
+ return build_real (type, max);
+}
+
+/* Given a real type, build the minimum value expressable with that type. */
+
+tree
+a68_real_minval (tree type)
+{
+ REAL_VALUE_TYPE min;
+ real_maxval (&min, 1, TYPE_MODE (type));
+ return build_real (type, min);
+}
+
+/* Given a real type, build the smallest value which can be meaningfully added
+ to or substracted from 1. */
+
+tree
+a68_real_smallval (tree type)
+{
+ /* The smallest real value which can be meaningfully added to or subtracted
+ from 1. */
+ const machine_mode mode = TYPE_MODE (type);
+ const struct real_format *fmt = REAL_MODE_FORMAT (mode);
+
+ char buf[128];
+ if (fmt->pnan < fmt->p)
+ snprintf (buf, sizeof (buf), "0x1p%d", fmt->emin - fmt->p);
+ else
+ snprintf (buf, sizeof (buf), "0x1p%d", 1 - fmt->p);
+
+ REAL_VALUE_TYPE res;
+ real_from_string (&res, buf);
+ return build_real (type, res);
+}
+
+/* Given a real type, build an INT with the number of decimal digits required
+ to represent a mantissa, such that a real is not reglected in comparison
+ with 1, not including sign. */
+
+tree
+a68_real_width (tree type)
+{
+ const machine_mode mode = TYPE_MODE (type);
+ const struct real_format *fmt = REAL_MODE_FORMAT (mode);
+ return build_int_cst (a68_int_type, fmt->p);
+}
+
+/* Given a real type, build an INT with the number of decimal digits required
+ to represent a decimal exponent, such that a real can be correctly
+ represented, not including sign. */
+
+tree
+a68_real_exp_width (tree type ATTRIBUTE_UNUSED)
+{
+ const machine_mode mode = TYPE_MODE (type);
+ const struct real_format *fmt = REAL_MODE_FORMAT (mode);
+ const double log10_2 = .30102999566398119521;
+ double log10_b = log10_2;
+ int max_10_exp = fmt->emax * log10_b;
+
+ return build_int_cst (a68_int_type, 1 + log10 (max_10_exp));
+}
+
+/* Given a real value VAL, return -1 if it is less than zero, 0 if it is zero
+ and +1 if it is bigger than zero. The built value is always of mode
+ M_INT. */
+
+tree
+a68_real_sign (tree val)
+{
+ tree zero = build_real (TREE_TYPE (val), dconst0);
+ return fold_build3 (COND_EXPR,
+ a68_int_type,
+ build2 (EQ_EXPR, integer_type_node, val, zero),
+ build_int_cst (a68_int_type, 0),
+ fold_build3 (COND_EXPR,
+ a68_int_type,
+ fold_build2 (GT_EXPR, integer_type_node,
val, zero),
+ build_int_cst (a68_int_type, 1),
+ build_int_cst (a68_int_type, -1)));
+}
+
+/* Absolute value of a real value. */
+
+tree
+a68_real_abs (tree val)
+{
+ return fold_build1 (ABS_EXPR, TREE_TYPE (val), val);
+}
+
+tree
+a68_real_sqrt (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_SQRTF;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_SQRT;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_SQRTL;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+tree
+a68_real_tan (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_TANF;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_TAN;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_TANL;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+tree
+a68_real_sin (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_SINF;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_SIN;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_SINL;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+tree
+a68_real_cos (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_COSF;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_COS;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_COSL;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+tree
+a68_real_acos (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_ACOSF;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_ACOS;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_ACOSL;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+tree
+a68_real_asin (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_ASINF;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_ASIN;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_ASINL;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+tree
+a68_real_atan (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_ATANF;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_ATAN;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_ATANL;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+tree
+a68_real_ln (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_LOGF;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_LOG;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_LOGL;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+tree
+a68_real_log (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_LOG10F;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_LOG10;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_LOG10L;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+tree
+a68_real_exp (tree type)
+{
+ enum built_in_function builtin;
+
+ if (type == float_type_node)
+ builtin = BUILT_IN_EXPF;
+ else if (type == double_type_node)
+ builtin = BUILT_IN_EXP;
+ else if (type == long_double_type_node)
+ builtin = BUILT_IN_EXPL;
+ else
+ gcc_unreachable ();
+
+ return addr_of_builtin_decl (builtin);
+}
+
+/* Build the real value lengthened from the value of VAL, from mode
+ FROM_MODE to mode TO_MODE. */
+
+tree
+a68_real_leng (MOID_T *to_mode, MOID_T *from_mode ATTRIBUTE_UNUSED, tree val)
+{
+ /* Lengthening can be done by just a conversion. */
+ return fold_convert (CTYPE (to_mode), val);
+}
+
+/* Build the real value that can be lengthened to the value of VAL, from mode
+ FROM_MODE to mode TO_MODE.
+
+ If VAL cannot be represented in TO_MODE because it is bigger than the most
+ positive value representable in TO_MODE, then it is truncated to that value.
+
+ Likewise, if VAL cannot be represented in TO_MODE because it is less than
+ the most negative value representable in TO_MODE, then it is truncated to
+ that value. */
+
+tree
+a68_real_shorten (MOID_T *to_mode, MOID_T *from_mode ATTRIBUTE_UNUSED, tree
val)
+{
+ tree most_positive_value = fold_convert (CTYPE (from_mode),
+ a68_real_maxval (CTYPE (to_mode)));
+ tree most_negative_value = fold_convert (CTYPE (from_mode),
+ a68_real_minval (CTYPE (to_mode)));
+
+ val = save_expr (val);
+ most_positive_value = save_expr (most_positive_value);
+ most_negative_value = save_expr (most_negative_value);
+ return fold_build3 (COND_EXPR, CTYPE (to_mode),
+ fold_build2 (GT_EXPR, a68_bool_type, val,
most_positive_value),
+ fold_convert (CTYPE (to_mode), most_positive_value),
+ fold_build3 (COND_EXPR, CTYPE (to_mode),
+ fold_build2 (LT_EXPR, a68_bool_type, val,
most_negative_value),
+ fold_convert (CTYPE (to_mode),
most_negative_value),
+ fold_convert (CTYPE (to_mode), val)));
+}
+
+/* Given a real expression VAL of mode MODE, produce an integral value which is
+ equal to the given real, or the next integer below (more negative than) the
+ given real. */
+
+tree
+a68_real_entier (tree val, MOID_T *to_mode, MOID_T *from_mode)
+{
+ tree fn = NULL_TREE;
+ tree to_type = CTYPE (to_mode);
+
+ if (from_mode == M_REAL)
+ {
+ if (to_type == integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_IFLOORF);
+ else if (to_type == long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LFLOORF);
+ else if (to_type == long_long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LLFLOORF);
+ else
+ gcc_unreachable ();
+ }
+ else if (from_mode == M_LONG_REAL)
+ {
+ if (to_type == integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_IFLOOR);
+ else if (to_type == long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LFLOOR);
+ else if (to_type == long_long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LLFLOOR);
+ else
+ gcc_unreachable ();
+ }
+ else if (from_mode == M_LONG_LONG_REAL)
+ {
+ if (to_type == integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_IFLOORL);
+ else if (to_type == long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LFLOORL);
+ else if (to_type == long_long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LLFLOORL);
+ else
+ gcc_unreachable ();
+ }
+ else
+ gcc_unreachable ();
+
+ return build_call_expr_loc (UNKNOWN_LOCATION, fn, 1, val);
+}
+
+/* Given a real expression VAL of mode MODE, produce an integral value which is
+ the nearest integer to the given real. */
+
+tree
+a68_real_round (tree val, MOID_T *to_mode, MOID_T *from_mode)
+{
+ tree fn = NULL_TREE;
+ tree to_type = CTYPE (to_mode);
+
+ if (from_mode == M_REAL)
+ {
+ if (to_type == integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_IROUNDF);
+ else if (to_type == long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LROUNDF);
+ else if (to_type == long_long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LLROUNDF);
+ else
+ gcc_unreachable ();
+ }
+ else if (from_mode == M_LONG_REAL)
+ {
+ if (to_type == integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_IROUND);
+ else if (to_type == long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LROUND);
+ else if (to_type == long_long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LLROUND);
+ else
+ gcc_unreachable ();
+ }
+ else if (from_mode == M_LONG_LONG_REAL)
+ {
+ if (to_type == integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_IROUNDL);
+ else if (to_type == long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LROUNDL);
+ else if (to_type == long_long_integer_type_node)
+ fn = builtin_decl_explicit (BUILT_IN_LLROUNDL);
+ else
+ gcc_unreachable ();
+ }
+ else
+ gcc_unreachable ();
+
+ return build_call_expr_loc (UNKNOWN_LOCATION, fn, 1, val);
+}
+
+
+/* Given two real values of mode M, build an expression that calculates the
+ addition of A and B. */
+
+tree
+a68_real_plus (MOID_T *m, tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, PLUS_EXPR, CTYPE (m), a, b);
+}
+
+/* Given two real values of mode M, build an expression that calculates the
+ subtraction of A by B. */
+
+tree
+a68_real_minus (MOID_T *m, tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, MINUS_EXPR, CTYPE (m), a, b);
+}
+
+/* Given two real values of mode M, build an expression that calculates the
+ multiplication of A by B. */
+
+tree
+a68_real_mult (MOID_T *m, tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, MULT_EXPR, CTYPE (m), a, b);
+}
+
+/* Given two real values of mode M, build an expression that calculates the
+ division of A by B. */
+
+tree
+a68_real_div (MOID_T *m, tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, RDIV_EXPR, CTYPE (m), a, b);
+}
+
+/* Given two real values of mode M, build an expression that calculates whether
+ A = B. */
+
+tree
+a68_real_eq (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, EQ_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two real values of mode M, build an expression that calculates whether
+ A /= B. */
+
+tree
+a68_real_ne (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, NE_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two real values of mode M, build an expression that calculates whether
+ A < B. */
+
+tree
+a68_real_lt (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, LT_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two real values of mode M, build an expression that calculates
+ whether A <= B. */
+
+tree
+a68_real_le (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, LE_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two real values of mode M, build an expression that calculates whether
+ A > B. */
+
+tree
+a68_real_gt (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, GT_EXPR, boolean_type_node, a, b);
+}
+
+/* Given two real values of mode M, build an expression that calculates whether
+ A >= B. */
+
+tree
+a68_real_ge (tree a, tree b, location_t loc)
+{
+ return fold_build2_loc (loc, GE_EXPR, boolean_type_node, a, b);
+}
+
+/* Exponentiation involving real values.
+
+ REAL <- REAL, REAL
+ REAL <- REAL, INT
+ LONG REAL <- LONG REAL, LONG REAL
+ LONG REAL <- LONG REAL, INT
+ LONG LONG REAL <- LONG LONG REAL, LONG LONG REAL
+ LONG LONG REAL <- LONG LONG REAL, INT */
+
+tree
+a68_real_pow (MOID_T *m, MOID_T *a_mode, MOID_T *b_mode,
+ tree a, tree b, location_t loc)
+{
+ enum built_in_function built_in;
+ if (m == M_REAL)
+ {
+ gcc_assert (a_mode == M_REAL);
+ built_in = b_mode == M_REAL ? BUILT_IN_POWF : BUILT_IN_POWIF;
+ }
+ else if (m == M_LONG_REAL)
+ {
+ gcc_assert (a_mode == M_LONG_REAL);
+ built_in = b_mode == M_LONG_REAL ? BUILT_IN_POW : BUILT_IN_POWI;
+ }
+ else if (m == M_LONG_LONG_REAL)
+ {
+ gcc_assert (a_mode == M_LONG_LONG_REAL);
+ built_in = b_mode == M_LONG_LONG_REAL ? BUILT_IN_POWL : BUILT_IN_POWIL;
+ }
+ else
+ gcc_unreachable ();
+
+ tree call = builtin_decl_explicit (built_in);
+ gcc_assert (call != NULL_TREE);
+ return build_call_expr_loc (loc, call, 2, a, b);
+}
diff --git a/gcc/algol68/a68-low-refs.cc b/gcc/algol68/a68-low-refs.cc
new file mode 100644
index 00000000000..ba9987b57ed
--- /dev/null
+++ b/gcc/algol68/a68-low-refs.cc
@@ -0,0 +1,52 @@
+/* Lowering routines for all things related to names.
+ 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 the yielding of SKIP for the given name mode. */
+
+tree
+a68_get_ref_skip_tree (MOID_T *m)
+{
+ /* Build a NULL pointer. */
+ return build_int_cst (CTYPE (m), 0);
+}
diff --git a/gcc/algol68/a68-low-strings.cc b/gcc/algol68/a68-low-strings.cc
new file mode 100644
index 00000000000..f9fdd56febd
--- /dev/null
+++ b/gcc/algol68/a68-low-strings.cc
@@ -0,0 +1,390 @@
+/* Lowering routines for all things related to STRINGs.
+ 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 the yielding of SKIP for M_STRING. */
+
+tree
+a68_get_string_skip_tree (void)
+{
+ return a68_get_multiple_skip_tree (M_FLEX_ROW_CHAR);
+}
+
+/* Copy chars from STR to ELEMENTS starting at TO_INDEX chars in ELEMENTS. */
+
+static void
+copy_string (tree elements, tree to_index, tree str)
+{
+ tree char_pointer_type = build_pointer_type (a68_char_type);
+ tree num_elems
+ = a68_lower_tmpvar ("num_elems%", sizetype, a68_multiple_num_elems (str));
+
+ tree from_index
+ = a68_lower_tmpvar ("from_index%", sizetype, size_zero_node);
+ tree from_offset
+ = a68_lower_tmpvar ("from_offset%", sizetype, size_zero_node);
+
+ /* Begin of loop body. */
+ a68_push_range (NULL);
+ {
+ /* if (from_index == num_elems) break; */
+ a68_add_stmt (fold_build1 (EXIT_EXPR, void_type_node,
+ fold_build2 (GE_EXPR, sizetype,
+ from_index, num_elems)));
+
+ /* *(elements + to_index) = *(elements + from_index) */
+ tree to_offset = fold_build2 (MULT_EXPR, sizetype,
+ to_index, size_in_bytes (a68_char_type));
+ a68_add_stmt (fold_build2 (MODIFY_EXPR,
+ void_type_node,
+ fold_build2 (MEM_REF, a68_char_type,
+ fold_build2 (POINTER_PLUS_EXPR,
+ char_pointer_type,
+ elements, to_offset),
+ fold_convert (char_pointer_type,
+ integer_zero_node)),
+ fold_build2 (MEM_REF, a68_char_type,
+ fold_build2 (POINTER_PLUS_EXPR,
+ char_pointer_type,
+ a68_multiple_elements
(str),
+ from_offset),
+ fold_convert (char_pointer_type,
+ integer_zero_node))));
+
+ /* from_offset = from_offset + stride */
+ a68_add_stmt (fold_build2 (MODIFY_EXPR, void_type_node,
+ from_offset,
+ fold_build2 (PLUS_EXPR, sizetype,
+ from_offset,
+ a68_multiple_stride (str,
size_zero_node))));
+ /* to_index = to_index + 1 */
+ a68_add_stmt (fold_build2 (POSTINCREMENT_EXPR, sizetype, to_index,
size_one_node));
+
+ /* from_index = from_index + 1 */
+ a68_add_stmt (fold_build2 (POSTINCREMENT_EXPR, sizetype, from_index,
size_one_node));
+ }
+
+ /* End of loop body. */
+ tree loop_body = a68_pop_range ();
+ a68_add_stmt (fold_build1 (LOOP_EXPR,
+ void_type_node,
+ loop_body));
+}
+
+/* Given two STRINGs STR1 and STR2, allocate a new string on the stack with a
+ copy of the concatenated characters of the given string. */
+
+tree
+a68_string_concat (tree str1, tree str2)
+{
+ tree char_pointer_type = build_pointer_type (a68_char_type);
+ static tree string_concat_fndecl;
+
+ if (string_concat_fndecl == NULL_TREE)
+ {
+ string_concat_fndecl
+ = a68_low_toplevel_func_decl ("string_concat",
+ build_function_type_list
(char_pointer_type,
+ TREE_TYPE
(str1),
+ TREE_TYPE
(str2),
+ NULL_TREE));
+ announce_function (string_concat_fndecl);
+
+ tree s1 = a68_low_func_param (string_concat_fndecl, "s1", TREE_TYPE
(str1));
+ tree s2 = a68_low_func_param (string_concat_fndecl, "s2", TREE_TYPE
(str2));
+ DECL_ARGUMENTS (string_concat_fndecl) = chainon (s1, s2);
+
+ a68_push_function_range (string_concat_fndecl, char_pointer_type,
+ true /* top_level */);
+
+ tree n1 = a68_lower_tmpvar ("n1%", sizetype, a68_multiple_num_elems
(s1));
+ tree n2 = a68_lower_tmpvar ("n2%", sizetype, a68_multiple_num_elems
(s2));
+ tree num_elems = a68_lower_tmpvar ("num_elems%", sizetype,
+ fold_build2 (PLUS_EXPR, sizetype, n1,
n2));
+
+ /* First allocate memory for the result string. We need enough space to
+ hold the elements of both strings with a stride of 1S. */
+ tree char_pointer_type = build_pointer_type (a68_char_type);
+ tree elements_size = fold_build2 (MULT_EXPR, sizetype,
+ size_in_bytes (a68_char_type),
+ num_elems);
+ tree elements = a68_lower_tmpvar ("elements%", char_pointer_type,
+ a68_lower_malloc (a68_char_type,
elements_size));
+
+ /* Copy elements. */
+ tree to_index = a68_lower_tmpvar ("to_index%", sizetype, size_zero_node);
+ copy_string (elements, to_index, s1);
+ copy_string (elements, to_index, s2);
+ a68_pop_function_range (elements);
+ }
+
+ /* Build the resulting multiple. */
+ str1 = save_expr (str1);
+ str2 = save_expr (str2);
+ tree n1 = a68_multiple_num_elems (str1);
+ tree n2 = a68_multiple_num_elems (str2);
+ tree num_elems = save_expr (fold_build2 (PLUS_EXPR, sizetype, n1, n2));
+ tree elements_size = fold_build2 (MULT_EXPR, sizetype,
+ size_in_bytes (a68_char_type),
+ num_elems);
+ tree lower_bound = ssize_int (1);
+ tree upper_bound = fold_convert (ssizetype, num_elems);
+ tree elements = build_call_nary (char_pointer_type,
+ fold_build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE
(string_concat_fndecl)),
+ string_concat_fndecl),
+ 2, str1, str2);
+ return a68_row_value (CTYPE (M_STRING), 1 /* dim */,
+ elements, elements_size,
+ &lower_bound, &upper_bound);
+}
+
+/* Given a STRING STR and an INT FACTOR, return STRING concatenated to itself
+ FACTOR - 1 times.
+
+ Negative values of FACTOR are interpreted as zero. */
+
+tree
+a68_string_mult (tree str, tree factor)
+{
+ a68_push_range (M_STRING);
+
+ str = save_expr (str);
+ tree ssize_one_node = ssize_int (1);
+ tree res = a68_lower_tmpvar ("res%", CTYPE (M_STRING), str);
+ tree index = a68_lower_tmpvar ("index%", ssizetype, ssize_one_node);
+
+ /* Begin of loop body. */
+ a68_push_range (NULL);
+
+ /* if (index == FACTOR) break; */
+ a68_add_stmt (fold_build1 (EXIT_EXPR,
+ void_type_node,
+ fold_build2 (GE_EXPR, ssizetype,
+ index,
+ fold_convert (ssizetype, factor))));
+
+ /* res += str */
+ a68_add_stmt (fold_build2 (MODIFY_EXPR, TREE_TYPE (res),
+ res,
+ a68_string_concat (res, str)));
+
+ /* index++ */
+ a68_add_stmt (fold_build2 (POSTINCREMENT_EXPR,
+ ssizetype,
+ index, ssize_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 (res);
+ return a68_pop_range ();
+}
+
+/* Given a CHAR C, build a string whose contents are just that CHAR. */
+
+tree
+a68_string_from_char (tree c)
+{
+ tree lower_bound = ssize_int (1);
+ tree upper_bound = lower_bound;
+ tree char_pointer_type = build_pointer_type (a68_char_type);
+
+ a68_push_range (M_STRING);
+
+ tree elements = a68_lower_tmpvar ("elements%", char_pointer_type,
+ a68_lower_malloc (a68_char_type,
+ size_one_node));
+ a68_add_stmt (fold_build2 (MODIFY_EXPR,
+ void_type_node,
+ fold_build1 (INDIRECT_REF, a68_char_type,
elements),
+ c));
+ a68_add_stmt (a68_row_value (CTYPE (M_STRING), 1 /* dim */,
+ elements,
+ size_in_bytes (a68_char_type),
+ &lower_bound, &upper_bound));
+ return a68_pop_range ();
+}
+
+/* Compare the two given strings lexicographically and return -1 (less than), 0
+ (equal to) or 1 (bigger than) reflecting the result of the comparison. */
+
+tree
+a68_string_cmp (tree s1, tree s2)
+{
+ s1 = save_expr (s1);
+ tree s1_elems = a68_multiple_elements (s1);
+ tree s1_len = a68_multiple_num_elems (s1);
+ tree s1_stride = a68_multiple_stride (s1, size_zero_node);
+
+ s2 = save_expr (s2);
+ tree s2_elems = a68_multiple_elements (s2);
+ tree s2_len = a68_multiple_num_elems (s2);
+ tree s2_stride = a68_multiple_stride (s2, size_zero_node);
+
+ return a68_build_libcall (A68_LIBCALL_U32_CMP2,
+ a68_int_type, 6,
+ s1_elems, s1_len, s1_stride,
+ s2_elems, s2_len, s2_stride);
+}
+
+/* Return a newly allocated UTF-8 string resulting from processing the string
+ breaks in STR. This function assumes the passed string is well-formed (the
+ scanner is in charge of seeing that is true) and just ICEs if it is not. */
+
+char *
+a68_string_process_breaks (const char *str)
+{
+ size_t len = 0;
+ char *res = NULL;
+
+ /* First calculate the size of the resulting string. */
+ for (const char *p = str; *p != '\0';)
+ {
+ if (*p == '\'')
+ {
+ switch (p[1])
+ {
+ case '\'':
+ case 'n':
+ case 'f':
+ case 'r':
+ case 't':
+ len += 1;
+ p += 2;
+ break;
+ case '(':
+ p += 2;
+ while (1)
+ {
+ if (p[0] == ')')
+ {
+ p++;
+ break;
+ }
+ else if (p[0] == ',' || ISSPACE (p[0]))
+ {
+ p++;
+ continue;
+ }
+
+ /* An Unicode codepoint encoded in UTF-8 occupies at most six
+ octets. */
+ len += 6;
+ p += (p[0] == 'u' ? 5 : 9);
+ }
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ len += 1;
+ p += 1;
+ }
+ }
+
+ /* Now and allocate it, adding space for a trailing NULL. */
+ res = (char *) xmalloc (len + 1);
+
+ /* Finally fill it with the result of expanding all the string breaks. */
+ size_t offset = 0;
+ for (const char *p = str; *p != '\0';)
+ {
+ if (*p == '\'')
+ {
+ switch (p[1])
+ {
+ case '\'': res[offset] = '\''; p += 2; offset += 1; break;
+ case 'n': res[offset] = '\n'; p += 2; offset += 1; break;
+ case 't': res[offset] = '\t'; p += 2; offset += 1; break;
+ case 'r': res[offset] = '\r'; p += 2; offset += 1; break;
+ case 'f': res[offset] = '\f'; p += 2; offset += 1; break;
+ case '(':
+ {
+ p += 2;
+ while (1)
+ {
+ if (p[0] == ')')
+ {
+ p++;
+ break;
+ }
+ else if (p[0] == ',' || ISSPACE (p[0]))
+ {
+ p++;
+ continue;
+ }
+
+ /* Skip the u or U. */
+ gcc_assert (p[0] == 'u' || p[0] == 'U');
+ p++;
+
+ char *end;
+ int64_t codepoint = strtol (p, &end, 16);
+ gcc_assert (end > p);
+ p = end;
+ /* Append the UTF-8 encoding of the obtained codepoint to
+ the `res' string. */
+ int n = a68_u8_uctomb ((uint8_t *) res + offset, codepoint,
6);
+ gcc_assert (n > 0);
+ offset += n;
+ }
+ break;
+ }
+ default: gcc_unreachable ();
+ }
+ }
+ else
+ {
+ res[offset] = *p;
+ offset += 1;
+ p += 1;
+ }
+ }
+ res[offset] = '\0';
+
+ return res;
+}
--
2.30.2