aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPer Bothner <bothner@gcc.gnu.org>1998-08-27 13:51:39 -0700
committerPer Bothner <bothner@gcc.gnu.org>1998-08-27 13:51:39 -0700
commit3c79b2da6ba52fe9ae2ec45f9ed6774f3366db93 (patch)
tree3e221460a1bf1a44a2e3a008fead9cd61b440bc6
parent360c5f1547ccd947d760a18f59817b38e0a47fd3 (diff)
downloadgcc-3c79b2da6ba52fe9ae2ec45f9ed6774f3366db93.zip
gcc-3c79b2da6ba52fe9ae2ec45f9ed6774f3366db93.tar.gz
gcc-3c79b2da6ba52fe9ae2ec45f9ed6774f3366db93.tar.bz2
Migrate from devo/gcc/ch. From-SVN: r22038
-rw-r--r--gcc/ch/README42
-rw-r--r--gcc/ch/actions.c1820
-rw-r--r--gcc/ch/chill.in130
-rw-r--r--gcc/ch/config-lang.in34
-rwxr-xr-xgcc/ch/configure644
-rw-r--r--gcc/ch/convert.c1231
-rw-r--r--gcc/ch/decl.c5176
-rw-r--r--gcc/ch/expr.c4493
-rw-r--r--gcc/ch/lang-specs.h42
-rw-r--r--gcc/ch/lang.c306
-rw-r--r--gcc/ch/parse.c4237
-rw-r--r--gcc/ch/runtime/allmem.c73
-rw-r--r--gcc/ch/runtime/andps.c76
-rw-r--r--gcc/ch/runtime/auxtypes.h45
-rw-r--r--gcc/ch/runtime/basicio.c467
-rw-r--r--gcc/ch/runtime/bitstring.h29
-rw-r--r--gcc/ch/runtime/cause.c48
-rw-r--r--gcc/ch/runtime/concatps.c93
-rw-r--r--gcc/ch/runtime/copyps.c111
-rw-r--r--gcc/ch/runtime/eqps.c88
-rw-r--r--gcc/ch/runtime/fileio.h153
-rw-r--r--gcc/ch/runtime/flsetps.c107
-rw-r--r--gcc/ch/runtime/format.h71
-rw-r--r--gcc/ch/runtime/getassoc.c37
-rw-r--r--gcc/ch/runtime/gettextaccess.c31
-rw-r--r--gcc/ch/runtime/getusage.c40
-rw-r--r--gcc/ch/runtime/inps.c65
-rw-r--r--gcc/ch/runtime/ioerror.c45
-rw-r--r--gcc/ch/runtime/ioerror.h161
-rw-r--r--gcc/ch/runtime/iomodes.h251
-rw-r--r--gcc/ch/runtime/ltps.c86
-rw-r--r--gcc/ch/runtime/ltstr.c55
-rw-r--r--gcc/ch/runtime/rts.h52
-rw-r--r--gcc/ch/runtime/sliceps.c65
-rw-r--r--gcc/ch/runtime/unhex.c57
-rw-r--r--gcc/ch/runtime/unhex1.c58
-rw-r--r--gcc/ch/satisfy.c628
-rw-r--r--gcc/ch/tasking.c3423
-rw-r--r--gcc/ch/timing.c494
-rw-r--r--gcc/ch/typeck.c3905
40 files changed, 28969 insertions, 0 deletions
diff --git a/gcc/ch/README b/gcc/ch/README
new file mode 100644
index 0000000..3dba977
--- /dev/null
+++ b/gcc/ch/README
@@ -0,0 +1,42 @@
+This directory contains the GNU front-end for the Chill language,
+contributed by Cygnus Solutions.
+
+Chill is the "CCITT High-Level Language", where CCITT is the old
+name for what is now ITU, the International Telecommunications Union.
+It is is language in the Modula2 family, and targets many of the
+same applications as Ada (especially large embedded systems).
+Chill was never used much in the United States, but is still
+being used in Europe, Brazil, Korea, and other places.
+
+Chill has been standardized by a series of reports/standards.
+The GNU implementation mostly follows the 1988 version of
+the language, with some backwards compatibility options for
+the 1984 version, and some other extensions. However, it
+does not implement all of the features of any standard.
+The most recent standard is ?, available from ?.
+
+The GNU Chill implementation is not being actively developed.
+Cygnus has one customer we are maintaining Chill for,
+but we are not planning on putting major work into Chill.
+This Net release is for educational purposes (as an example
+of a different Gcc front-end), and for those who find it useful.
+It is an unsupported hacker release. Bug reports without
+patches are likely to get ignored. Questions may get answered or
+ignored depending on our mood! If you want to try your luck,
+you can send a note to David Brolley <brolley@cygnus.com> or
+Per Bothner <bothner@cygnus.com>.
+
+One known problem is that we only support native builds of GNU Chill.
+If you need a cross-compiler, you will find various problems,
+including the directory structure, and the setjmp-based exception
+handling mechanism.
+
+The Chill run-time system is in the runtime sub-directory.
+Notice rts.c contains a poor main's implementation of Chill
+"processes" (threads). It is not added to libchill.a.
+We only use it for testing. (Our customer uses a different
+implementation for product work.)
+
+The GNU Chill implementation was primarily written by
+Per Bothner, along with Bill Cox, Wilfried Moser, Michael
+Tiemann, and David Brolley.
diff --git a/gcc/ch/actions.c b/gcc/ch/actions.c
new file mode 100644
index 0000000..79bacf0
--- /dev/null
+++ b/gcc/ch/actions.c
@@ -0,0 +1,1820 @@
+/* Implement actions for CHILL.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+ Authors: Per Bothner, Bill Cox, Michael Tiemann, Michael North
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <limits.h>
+#include "config.h"
+#include "tree.h"
+#include "rtl.h"
+#include "expr.h"
+#include "ch-tree.h"
+#include "lex.h"
+#include "flags.h"
+#include "actions.h"
+#include "obstack.h"
+#include "assert.h"
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+/* reserved tag definitions */
+
+#define TYPE_ID "id"
+#define TAG_OBJECT "chill_object"
+#define TAG_CLASS "chill_class"
+
+extern int flag_short_enums;
+extern int current_nesting_level;
+
+extern tree build_chill_compound_expr PROTO((tree));
+extern tree build_chill_exception_decl PROTO((char *));
+extern tree convert PROTO((tree, tree));
+extern rtx emit_line_note_force PROTO((char *, int));
+extern void error PROTO((char *, ...));
+extern void error_with_decl PROTO((tree, char *, ...));
+extern rtx gen_nop PROTO((void));
+extern tree get_identifier PROTO((char *));
+extern void pedwarn PROTO((char *, ...));
+extern void sorry PROTO((char *, ...));
+extern void warning PROTO((char *, ...));
+
+extern struct obstack *expression_obstack, permanent_obstack;
+extern struct obstack *current_obstack, *saveable_obstack;
+
+/* This flag is checked throughout the non-CHILL-specific
+ in the front end. */
+tree chill_integer_type_node;
+tree chill_unsigned_type_node;
+
+/* Never used. Referenced from c-typeck.c, which we use. */
+int current_function_returns_value = 0;
+int current_function_returns_null = 0;
+
+/* data imported from toplev.c */
+
+extern char *dump_base_name;
+
+/* set from command line parameter, to exit after
+ grant file written, generating no code. */
+int grant_only_flag = 0;
+
+char *
+lang_identify ()
+{
+ return "chill";
+}
+
+
+void
+init_chill ()
+{
+}
+
+void
+print_lang_statistics ()
+{
+}
+
+
+void
+lang_finish ()
+{
+#if 0
+ extern int errorcount, sorrycount;
+
+ /* this should be the last action in compiling a module.
+ If there are other actions to be performed at lang_finish
+ please insert before this */
+
+ /* FIXME: in case of a syntax error, this leaves the grant file incomplete */
+ /* for the moment we print a warning in case of errors and
+ continue granting */
+ if ((errorcount || sorrycount) && grant_count)
+ {
+ warning ("%d errors, %d sorries, do granting", errorcount, sorrycount);
+ errorcount = sorrycount = 0;
+ }
+#endif
+}
+
+void
+chill_check_decl (decl)
+ tree decl;
+{
+ tree type = TREE_TYPE (decl);
+ static int alreadyWarned = 0;
+
+ if (TREE_CODE (type) == RECORD_TYPE) /* && TREE_STATIC_TEMPLATE (type)) */
+ {
+ if (!alreadyWarned)
+ {
+ error ("GNU compiler does not support statically allocated objects");
+ alreadyWarned = 1;
+ }
+ error_with_decl (decl, "`%s' cannot be statically allocated");
+ }
+}
+
+/* Comparison function for sorting identifiers in RAISES lists.
+ Note that because IDENTIFIER_NODEs are unique, we can sort
+ them by address, saving an indirection. */
+static int
+id_cmp (p1, p2)
+ tree *p1, *p2;
+{
+ return (int)TREE_VALUE (*p1) - (int)TREE_VALUE (*p2);
+}
+
+/* Build the FUNCTION_TYPE or METHOD_TYPE which may raise exceptions
+ listed in RAISES. */
+tree
+build_exception_variant (type, raises)
+ tree type, raises;
+{
+ int i;
+ tree v = TYPE_MAIN_VARIANT (type);
+ tree t, t2;
+ int constp = TYPE_READONLY (type);
+ int volatilep = TYPE_VOLATILE (type);
+
+ if (!raises)
+ return build_type_variant (v, constp, volatilep);
+
+ if (TREE_CHAIN (raises))
+ { /* Sort the list */
+ tree *a = (tree *)alloca ((list_length (raises)+1) * sizeof (tree));
+ for (i = 0, t = raises; t; t = TREE_CHAIN (t), i++)
+ a[i] = t;
+ /* NULL terminator for list. */
+ a[i] = NULL_TREE;
+ qsort (a, i, sizeof (tree), id_cmp);
+ while (i--)
+ TREE_CHAIN (a[i]) = a[i+1];
+ raises = a[0];
+ }
+
+ for (v = TYPE_NEXT_VARIANT (v); v; v = TYPE_NEXT_VARIANT (v))
+ {
+ if (TYPE_READONLY (v) != constp
+ || TYPE_VOLATILE (v) != volatilep)
+ continue;
+
+ t = raises;
+ t2 = TYPE_RAISES_EXCEPTIONS (v);
+ while (t && t2)
+ {
+ if (TREE_TYPE (t) == TREE_TYPE (t2))
+ {
+ t = TREE_CHAIN (t);
+ t2 = TREE_CHAIN (t2);
+ }
+ else break;
+ }
+ if (t || t2)
+ continue;
+ /* List of exceptions raised matches previously found list.
+
+ @@ Nice to free up storage used in consing up the
+ @@ list of exceptions raised. */
+ return v;
+ }
+
+ /* Need to build a new variant. */
+ if (TREE_PERMANENT (type))
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ v = copy_node (type);
+ pop_obstacks ();
+ }
+ else
+ v = copy_node (type);
+
+ TYPE_NEXT_VARIANT (v) = TYPE_NEXT_VARIANT (type);
+ TYPE_NEXT_VARIANT (type) = v;
+ if (raises && ! TREE_PERMANENT (raises))
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ raises = copy_list (raises);
+ pop_obstacks ();
+ }
+ TYPE_RAISES_EXCEPTIONS (v) = raises;
+ return v;
+}
+#if 0
+
+tree
+build_rts_call (name, type, args)
+ char *name;
+ tree type, args;
+{
+ tree decl = lookup_name (get_identifier (name));
+ tree converted_args = NULL_TREE;
+ tree result, length = NULL_TREE;
+
+ assert (decl != NULL_TREE);
+ while (args)
+ {
+ tree arg = TREE_VALUE (args);
+ if (TREE_CODE (TREE_TYPE (arg)) == SET_TYPE
+ || TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE)
+ {
+ length = size_in_bytes (TREE_TYPE (arg));
+ arg = build_chill_addr_expr (arg, (char *)0);
+ }
+ converted_args = tree_cons (NULL_TREE, arg, converted_args);
+ args = TREE_CHAIN (args);
+ }
+ if (length != NULL_TREE)
+ converted_args = tree_cons (NULL_TREE, length, converted_args);
+ converted_args = nreverse (converted_args);
+ result = build_chill_function_call (decl, converted_args);
+ if (TREE_CODE (type) == SET_TYPE || TREE_CODE (type) == ARRAY_TYPE)
+ result = build1 (INDIRECT_REF, type, result);
+ else
+ result = convert (type, result);
+ return result;
+}
+#endif
+
+/*
+ * queue name of unhandled exception
+ * to avoid multiple unhandled warnings
+ * in one compilation module
+ */
+
+struct already_type
+{
+ struct already_type *next;
+ char *name;
+};
+
+static struct already_type *already_warned = 0;
+
+static void
+warn_unhandled (ex)
+ char *ex;
+{
+ struct already_type *p = already_warned;
+
+ while (p)
+ {
+ if (!strcmp (p->name, ex))
+ return;
+ p = p->next;
+ }
+
+ /* not yet warned */
+ p = (struct already_type *)xmalloc (sizeof (struct already_type));
+ p->next = already_warned;
+ p->name = (char *)xmalloc (strlen (ex) + 1);
+ strcpy (p->name, ex);
+ already_warned = p;
+ pedwarn ("causing unhandled exception `%s' (this is flaged only once)", ex);
+}
+
+/*
+ * build a call to the following function:
+ * void __cause_ex1 (char* ex, const char *file,
+ * const unsigned lineno);
+ * if the exception is handled or
+ * void __unhandled_ex (char *ex, char *file, unsigned lineno)
+ * if the exception is not handled.
+ */
+tree
+build_cause_exception (exp_name, warn_if_unhandled)
+ tree exp_name;
+ int warn_if_unhandled;
+{
+ /* We don't use build_rts_call() here, because the string (array of char)
+ would be followed by its length in the parameter list built by
+ build_rts_call, and the runtime routine doesn't want a length parameter.*/
+ tree exp_decl = build_chill_exception_decl (IDENTIFIER_POINTER (exp_name));
+ tree function, fname, lineno, result;
+ int handled = is_handled (exp_name);
+
+ switch (handled)
+ {
+ case 0:
+ /* no handler */
+ if (warn_if_unhandled)
+ warn_unhandled (IDENTIFIER_POINTER (exp_name));
+ function = lookup_name (get_identifier ("__unhandled_ex"));
+ fname = force_addr_of (get_chill_filename ());
+ lineno = get_chill_linenumber ();
+ break;
+ case 1:
+ /* local handler */
+ function = lookup_name (get_identifier ("__cause_ex1"));
+ fname = force_addr_of (get_chill_filename ());
+ lineno = get_chill_linenumber ();
+ break;
+ case 2:
+ /* function may propagate this exception */
+ function = lookup_name (get_identifier ("__cause_ex1"));
+ fname = lookup_name (get_identifier (CALLER_FILE));
+ if (fname == NULL_TREE)
+ fname = error_mark_node;
+ lineno = lookup_name (get_identifier (CALLER_LINE));
+ if (lineno == NULL_TREE)
+ lineno = error_mark_node;
+ break;
+ }
+ result =
+ build_chill_function_call (function,
+ tree_cons (NULL_TREE, build_chill_addr_expr (exp_decl, (char *)0),
+ tree_cons (NULL_TREE, fname,
+ tree_cons (NULL_TREE, lineno, NULL_TREE))));
+ return result;
+}
+
+void
+expand_cause_exception (exp_name)
+ tree exp_name;
+{
+ expand_expr_stmt (build_cause_exception (exp_name, 1));
+}
+
+/* If CONDITION is true, raise EXCEPTION (an IDENTIFIER_NODE);
+ otherwise return EXPR. */
+
+tree
+check_expression (expr, condition, exception)
+ tree expr, condition, exception;
+{
+ if (integer_zerop (condition))
+ return expr;
+ else
+ return build (COMPOUND_EXPR, TREE_TYPE (expr),
+ fold (build (TRUTH_ANDIF_EXPR, boolean_type_node,
+ condition, build_cause_exception (exception, 0))),
+ expr);
+}
+
+/* Return an expression for VALUE < LO_LIMIT || VALUE > HI_LIMIT,
+ somewhat optimized and with some warnings suppressed.
+ If LO_LIMIT or HI_LIMIT is NULL_TREE, assume that (sub-)test passes. */
+
+tree
+test_range (value, lo_limit, hi_limit)
+ tree value, lo_limit, hi_limit;
+{
+ if (lo_limit || hi_limit)
+ {
+ int old_inhibit_warnings = inhibit_warnings;
+ tree lo_check, hi_check, check;
+
+ /* This is a hack so that `shorten_compare' doesn't warn the
+ user about useless range checks that are too much work to
+ optimize away here. */
+ inhibit_warnings = 1;
+
+ lo_check = lo_limit ?
+ fold (build_compare_discrete_expr (LT_EXPR, value, lo_limit)) :
+ boolean_false_node; /* fake passing the check */
+
+ hi_check = hi_limit ?
+ fold (build_compare_discrete_expr (GT_EXPR, value, hi_limit)) :
+ boolean_false_node; /* fake passing the check */
+
+ if (lo_check == boolean_false_node)
+ check = hi_check;
+ else if (hi_check == boolean_false_node)
+ check = lo_check;
+ else
+ check = fold (build (TRUTH_ORIF_EXPR, boolean_type_node,
+ lo_check, hi_check));
+
+ inhibit_warnings = old_inhibit_warnings;
+ return check;
+ }
+ else
+ return boolean_false_node;
+}
+
+/* Return EXPR, except if range_checking is on, return an expression
+ that also checks that value >= low_limit && value <= hi_limit.
+ If LO_LIMIT or HI_LIMIT is NULL_TREE, assume that test passes. */
+
+tree
+check_range (expr, value, lo_limit, hi_limit)
+ tree expr, value, lo_limit, hi_limit;
+{
+ tree check = test_range (value, lo_limit, hi_limit);
+ if (!integer_zerop (check))
+ {
+ if (current_function_decl == NULL_TREE)
+ {
+ if (TREE_CODE (check) == INTEGER_CST)
+ error ("range failure (not inside function)");
+ else
+ warning ("possible range failure (not inside function)");
+ }
+ else
+ {
+ if (TREE_CODE (check) == INTEGER_CST)
+ warning ("expression will always cause RANGEFAIL");
+ if (range_checking)
+ expr = check_expression (expr, check,
+ ridpointers[(int) RID_RANGEFAIL]);
+ }
+ }
+ return expr;
+}
+
+/* Same as EXPR, except raise EMPTY if EXPR is NULL. */
+
+tree
+check_non_null (expr)
+ tree expr;
+{
+ if (empty_checking)
+ {
+ expr = save_if_needed (expr);
+ return check_expression (expr,
+ build_compare_expr (EQ_EXPR,
+ expr, null_pointer_node),
+ ridpointers[(int) RID_EMPTY]);
+ }
+ return expr;
+}
+
+/*
+ * There are four conditions to generate a runtime check:
+ * 1) assigning a longer INT to a shorter (signs irrelevant)
+ * 2) assigning a signed to an unsigned
+ * 3) assigning an unsigned to a signed of the same size.
+ * 4) TYPE is a discrete subrange
+ */
+tree
+chill_convert_for_assignment (type, expr, place)
+ tree type, expr;
+ char *place; /* location description for error messages */
+{
+ tree ttype = type;
+ tree etype = TREE_TYPE (expr);
+ tree result;
+
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return expr;
+ if (TREE_CODE (expr) == TYPE_DECL)
+ {
+ error ("right hand side of assignment is a mode");
+ return error_mark_node;
+ }
+
+ if (! CH_COMPATIBLE (expr, type))
+ {
+ error ("incompatible modes in %s", place);
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ ttype = TREE_TYPE (ttype);
+ if (etype && TREE_CODE (etype) == REFERENCE_TYPE)
+ etype = TREE_TYPE (etype);
+
+ if (etype
+ && (CH_STRING_TYPE_P (ttype)
+ || (chill_varying_type_p (ttype)
+ && CH_STRING_TYPE_P (CH_VARYING_ARRAY_TYPE (ttype))))
+ && (CH_STRING_TYPE_P (etype)
+ || (chill_varying_type_p (etype)
+ && CH_STRING_TYPE_P (CH_VARYING_ARRAY_TYPE (etype)))))
+ {
+ tree cond;
+ if (range_checking)
+ expr = save_if_needed (expr);
+ cond = string_assignment_condition (ttype, expr);
+ if (TREE_CODE (cond) == INTEGER_CST)
+ {
+ if (integer_zerop (cond))
+ {
+ error ("bad string length in %s", place);
+ return error_mark_node;
+ }
+ /* Otherwise, the condition is always true, so no runtime test. */
+ }
+ else if (range_checking)
+ expr = check_expression (expr,
+ invert_truthvalue (cond),
+ ridpointers[(int) RID_RANGEFAIL]);
+ }
+
+ if (range_checking
+ && discrete_type_p (ttype)
+ && etype != NULL_TREE
+ && discrete_type_p (etype))
+ {
+ int cond1 = tree_int_cst_lt (TYPE_SIZE (ttype),
+ TYPE_SIZE (etype));
+ int cond2 = TREE_UNSIGNED (ttype)
+ && (! TREE_UNSIGNED (etype));
+ int cond3 = (! TREE_UNSIGNED (type))
+ && TREE_UNSIGNED (etype)
+ && tree_int_cst_equal (TYPE_SIZE (ttype),
+ TYPE_SIZE (etype));
+ int cond4 = TREE_TYPE (ttype)
+ && discrete_type_p (TREE_TYPE (ttype));
+
+ if (cond1 || cond2 || cond3 || cond4)
+ {
+ tree type_min = TYPE_MIN_VALUE (ttype);
+ tree type_max = TYPE_MAX_VALUE (ttype);
+
+ expr = save_if_needed (expr);
+ if (expr && type_min && type_max)
+ expr = check_range (expr, expr, type_min, type_max);
+ }
+ }
+ result = convert (type, expr);
+
+ /* If the type is a array of PACK bits and the expression is an array constructor,
+ then build a CONSTRUCTOR for a bitstring. Bitstrings are zero based, so
+ decrement the value of each CONSTRUCTOR element by the amount of the lower
+ bound of the array. */
+ if (TREE_CODE (type) == ARRAY_TYPE && TYPE_PACKED (type)
+ && TREE_CODE (result) == CONSTRUCTOR)
+ {
+ tree domain_min = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
+ tree new_list = NULL_TREE;
+ long index;
+ tree element;
+ for (element = TREE_OPERAND (result, 1);
+ element != NULL_TREE;
+ element = TREE_CHAIN (element))
+ {
+ if (!tree_int_cst_equal (TREE_VALUE (element), integer_zero_node))
+ {
+ tree purpose = TREE_PURPOSE (element);
+ switch (TREE_CODE (purpose))
+ {
+ case INTEGER_CST:
+ new_list = tree_cons (NULL_TREE,
+ size_binop (MINUS_EXPR, purpose, domain_min),
+ new_list);
+ break;
+ case RANGE_EXPR:
+ for (index = TREE_INT_CST_LOW (TREE_OPERAND (purpose, 0));
+ index <= TREE_INT_CST_LOW (TREE_OPERAND (purpose, 1));
+ index++)
+ new_list = tree_cons (NULL_TREE,
+ size_binop (MINUS_EXPR,
+ build_int_2 (index, 0),
+ domain_min),
+ new_list);
+ break;
+ default:
+ abort ();
+ }
+ }
+ }
+ TREE_OPERAND (result, 1) = nreverse (new_list);
+ TREE_TYPE (result) = build_bitstring_type (TYPE_SIZE (type));
+ }
+
+ return result;
+}
+
+/* Check that EXPR has valid type for a RETURN or RESULT expression,
+ converting to the right type. ACTION is "RESULT" or "RETURN". */
+
+static tree
+adjust_return_value (expr, action)
+ tree expr;
+ char *action;
+{
+ tree type = TREE_TYPE (TREE_TYPE (current_function_decl));
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ if (CH_LOCATION_P (expr))
+ {
+ if (! CH_READ_COMPATIBLE (TREE_TYPE (type),
+ TREE_TYPE (expr)))
+ {
+ error ("mode mismatch in %s expression", action);
+ return error_mark_node;
+ }
+ return convert (type, expr);
+ }
+ else
+ {
+ error ("%s expression must be referable", action);
+ return error_mark_node;
+ }
+ }
+ else if (! CH_COMPATIBLE (expr, type))
+ {
+ error ("mode mismatch in %s expression", action);
+ return error_mark_node;
+ }
+ return convert (type, expr);
+}
+
+void
+chill_expand_result (expr, result_or_return)
+ tree expr;
+ int result_or_return;
+{
+ tree type;
+ char *action_name = result_or_return ? "RESULT" : "RETURN";
+
+ if (pass == 1)
+ return;
+
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return;
+
+ CH_FUNCTION_SETS_RESULT (current_function_decl) = 1;
+
+ if (chill_at_module_level || global_bindings_p ())
+ error ("%s not allowed outside a PROC", action_name);
+
+ result_never_set = 0;
+
+ if (chill_result_decl == NULL_TREE)
+ {
+ error ("%s action in PROC with no declared RESULTS", action_name);
+ return;
+ }
+ type = TREE_TYPE (chill_result_decl);
+
+ if (TREE_CODE (type) == ERROR_MARK)
+ return;
+
+ expr = adjust_return_value (expr, action_name);
+
+ expand_expr_stmt (build_chill_modify_expr (chill_result_decl, expr));
+}
+
+/*
+ * error if EXPR not NULL and procedure doesn't
+ * have a return type;
+ * warning if EXPR NULL,
+ * procedure *has* a return type, and a previous
+ * RESULT actions hasn't saved a return value.
+ */
+void
+chill_expand_return (expr, implicit)
+ tree expr;
+ int implicit; /* 1 if an implicit return at end of function. */
+{
+ tree valtype;
+
+ if (expr != NULL_TREE && TREE_CODE (expr) == ERROR_MARK)
+ return;
+ if (chill_at_module_level || global_bindings_p ())
+ {
+ error ("RETURN not allowed outside PROC");
+ return;
+ }
+
+ if (pass == 1)
+ return;
+
+ result_never_set = 0;
+
+ valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
+ if (TREE_CODE (valtype) == VOID_TYPE)
+ {
+ if (expr != NULL_TREE)
+ error ("RETURN with a value, in PROC returning void");
+ expand_null_return ();
+ }
+ else if (TREE_CODE (valtype) != ERROR_MARK)
+ {
+ if (expr == NULL_TREE)
+ {
+ if (!CH_FUNCTION_SETS_RESULT (current_function_decl)
+ && !implicit)
+ warning ("RETURN with no value and no RESULT action in procedure");
+ expr = chill_result_decl;
+ }
+ else
+ expr = adjust_return_value (expr, "RETURN");
+ expr = build (MODIFY_EXPR, valtype,
+ DECL_RESULT (current_function_decl),
+ expr);
+ TREE_SIDE_EFFECTS (expr) = 1;
+ expand_return (expr);
+ }
+}
+
+void
+lookup_and_expand_goto (name)
+ tree name;
+{
+ if (name == NULL_TREE || TREE_CODE (name) == ERROR_MARK)
+ return;
+ if (!ignoring)
+ {
+ tree decl = lookup_name (name);
+ if (decl == NULL || TREE_CODE (decl) != LABEL_DECL)
+ error ("no label named `%s'", IDENTIFIER_POINTER (name));
+ else if (DECL_CONTEXT (decl) != current_function_decl)
+ error ("cannot GOTO label `%s' outside current function",
+ IDENTIFIER_POINTER (name));
+ else
+ {
+ TREE_USED (decl) = 1;
+ expand_goto_except_cleanup (DECL_ACTION_NESTING_LEVEL (decl));
+ expand_goto (decl);
+ }
+ }
+}
+
+void
+lookup_and_handle_exit (name)
+ tree name;
+{
+ if (name == NULL_TREE || TREE_CODE (name) == ERROR_MARK)
+ return;
+ if (!ignoring)
+ {
+ tree label = munge_exit_label (name);
+ tree decl = lookup_name (label);
+ if (decl == NULL || TREE_CODE (decl) != LABEL_DECL)
+ error ("no EXITable label named `%s'", IDENTIFIER_POINTER (name));
+ else if (DECL_CONTEXT (decl) != current_function_decl)
+ error ("cannot EXIT label `%s' outside current function",
+ IDENTIFIER_POINTER (name));
+ else
+ {
+ TREE_USED (decl) = 1;
+ expand_goto_except_cleanup (DECL_ACTION_NESTING_LEVEL (decl));
+ expand_goto (decl);
+ }
+ }
+}
+
+/* ELSE-range handling: The else-range is a chain of trees which collectively
+ represent the ranges to be tested for the (ELSE) case label. Each element in
+ the chain represents a range to be tested. The boundaries of the range are
+ represented by INTEGER_CST trees in the PURPOSE and VALUE fields. */
+
+/* This function updates the else-range by removing the given integer constant. */
+static tree
+update_else_range_for_int_const (else_range, label)
+ tree else_range, label;
+{
+ int lowval, highval;
+ int label_value = TREE_INT_CST_LOW (label);
+ tree this_range, prev_range, new_range;
+
+ /* First, find the range element containing the integer, if it exists. */
+ prev_range = NULL_TREE;
+ for (this_range = else_range ;
+ this_range != NULL_TREE;
+ this_range = TREE_CHAIN (this_range))
+ {
+ lowval = TREE_INT_CST_LOW (TREE_PURPOSE (this_range));
+ highval = TREE_INT_CST_LOW (TREE_VALUE (this_range));
+ if (label_value >= lowval && label_value <= highval)
+ break;
+ prev_range = this_range;
+ }
+
+ /* If a range element containing the integer was found, then update the range. */
+ if (this_range != NULL_TREE)
+ {
+ tree next = TREE_CHAIN (this_range);
+ if (label_value == lowval)
+ {
+ /* The integer is the lower bound of the range element. If it is also the
+ upper bound, then remove this range element, otherwise update it. */
+ if (label_value == highval)
+ {
+ if (prev_range == NULL_TREE)
+ else_range = next;
+ else
+ TREE_CHAIN (prev_range) = next;
+ }
+ else
+ TREE_PURPOSE (this_range) = build_int_2 (label_value + 1, 0);
+ }
+ else if (label_value == highval)
+ {
+ /* The integer is the upper bound of the range element, so ajust it. */
+ TREE_VALUE (this_range) = build_int_2 (label_value - 1, 0);
+ }
+ else
+ {
+ /* The integer is in the middle of the range element, so split it. */
+ new_range = tree_cons (
+ build_int_2 (label_value + 1, 0), TREE_VALUE (this_range), next);
+ TREE_VALUE (this_range) = build_int_2 (label_value - 1, 0);
+ TREE_CHAIN (this_range) = new_range;
+ }
+ }
+ return else_range;
+}
+
+/* Update the else-range to remove a range of values/ */
+static tree
+update_else_range_for_range (else_range, low_target, high_target)
+ tree else_range, low_target, high_target;
+{
+ tree this_range, prev_range, new_range, next_range;
+ int low_range_val, high_range_val;
+ int low_target_val = TREE_INT_CST_LOW (low_target);
+ int high_target_val = TREE_INT_CST_LOW (high_target);
+
+ /* find the first else-range element which overlaps the target range. */
+ prev_range = NULL_TREE;
+ for (this_range = else_range ;
+ this_range != NULL_TREE;
+ this_range = TREE_CHAIN (this_range))
+ {
+ low_range_val = TREE_INT_CST_LOW (TREE_PURPOSE (this_range));
+ high_range_val = TREE_INT_CST_LOW (TREE_VALUE (this_range));
+ if (low_target_val >= low_range_val && low_target_val <= high_range_val
+ || high_target_val >= low_range_val && high_target_val <= high_range_val)
+ break;
+ prev_range = this_range;
+ }
+ if (this_range == NULL_TREE)
+ return else_range;
+
+ /* This first else-range element might be truncated at the top or completely
+ contain the target range. */
+ if (low_range_val < low_target_val)
+ {
+ next_range = TREE_CHAIN (this_range);
+ if (high_range_val > high_target_val)
+ {
+ new_range = tree_cons (
+ build_int_2 (high_target_val + 1, 0), TREE_VALUE (this_range), next_range);
+ TREE_VALUE (this_range) = build_int_2 (low_target_val - 1, 0);
+ TREE_CHAIN (this_range) = new_range;
+ return else_range;
+ }
+
+ TREE_VALUE (this_range) = build_int_2 (low_target_val - 1, 0);
+ if (next_range == NULL_TREE)
+ return else_range;
+
+ prev_range = this_range;
+ this_range = next_range;
+ high_range_val = TREE_INT_CST_LOW (TREE_VALUE (this_range));
+ }
+
+ /* There may then follow zero or more else-range elements which are completely
+ contained in the target range. */
+ while (high_range_val <= high_target_val)
+ {
+ this_range = TREE_CHAIN (this_range);
+ if (prev_range == NULL_TREE)
+ else_range = this_range;
+ else
+ TREE_CHAIN (prev_range) = this_range;
+
+ if (this_range == NULL_TREE)
+ return else_range;
+ high_range_val = TREE_INT_CST_LOW (TREE_VALUE (this_range));
+ }
+
+ /* Finally, there may be a else-range element which is truncated at the bottom. */
+ low_range_val = TREE_INT_CST_LOW (TREE_PURPOSE (this_range));
+ if (low_range_val <= high_target_val)
+ TREE_PURPOSE (this_range) = build_int_2 (high_target_val + 1, 0);
+
+ return else_range;
+}
+
+static tree
+update_else_range_for_range_expr (else_range, label)
+ tree else_range, label;
+{
+ if (TREE_OPERAND (label, 0) == NULL_TREE)
+ {
+ if (TREE_OPERAND (label, 1) == NULL_TREE)
+ else_range = NULL_TREE; /* (*) -- matches everything */
+ }
+ else
+ else_range = update_else_range_for_range (
+ else_range, TREE_OPERAND (label, 0), TREE_OPERAND (label, 1));
+
+ return else_range;
+}
+
+static tree
+update_else_range_for_type (else_range, label)
+ tree else_range, label;
+{
+ tree type = TREE_TYPE (label);
+ else_range = update_else_range_for_range (
+ else_range, TYPE_MIN_VALUE (type), TYPE_MAX_VALUE (type));
+ return else_range;
+}
+
+static tree
+compute_else_range (selector, alternatives, selector_no)
+ tree selector, alternatives;
+ int selector_no;
+{
+ /* Start with an else-range that spans the entire range of the selector type. */
+ tree type = TREE_TYPE (TREE_VALUE (selector));
+ tree range = tree_cons (TYPE_MIN_VALUE (type), TYPE_MAX_VALUE (type), NULL_TREE);
+
+ /* Now remove the values represented by each case lebel specified for that
+ selector. The remaining range is the else-range. */
+ for ( ; alternatives != NULL_TREE; alternatives = TREE_CHAIN (alternatives))
+ {
+ tree label;
+ tree label_list = TREE_PURPOSE (alternatives);
+ int this_selector;
+ for (this_selector = 0; this_selector < selector_no ; ++this_selector)
+ label_list = TREE_CHAIN (label_list);
+
+ for (label = TREE_VALUE (label_list);
+ label != NULL_TREE;
+ label = TREE_CHAIN (label))
+ {
+ tree label_value = TREE_VALUE (label);
+ if (TREE_CODE (label_value) == INTEGER_CST)
+ range = update_else_range_for_int_const (range, label_value);
+ else if (TREE_CODE (label_value) == RANGE_EXPR)
+ range = update_else_range_for_range_expr (range, label_value);
+ else if (TREE_CODE (label_value) == TYPE_DECL)
+ range = update_else_range_for_type (range, label_value);
+
+ if (range == NULL_TREE)
+ break;
+ }
+ }
+
+ return range;
+}
+
+void
+compute_else_ranges (selectors, alternatives)
+ tree selectors, alternatives;
+{
+ tree selector;
+ int selector_no = 0;
+
+ for (selector = selectors; selector != NULL_TREE; selector = TREE_CHAIN (selector))
+ {
+ if (ELSE_LABEL_SPECIFIED (selector))
+ TREE_PURPOSE (selector) =
+ compute_else_range (selector, alternatives, selector_no);
+ selector_no++;
+ }
+}
+
+static tree
+check_case_value (label_value, selector)
+ tree label_value, selector;
+{
+ if (TREE_CODE (label_value) == ERROR_MARK)
+ return label_value;
+ if (TREE_CODE (selector) == ERROR_MARK)
+ return selector;
+
+ /* Z.200 (6.4 Case action) says: "The class of any discrete expression
+ in the case selector list must be compatible with the corresponding
+ (by position) class of the resulting list of classes of the case label
+ list occurrences ...". We don't actually construct the resulting
+ list of classes, but this test should be more-or-less equivalent.
+ I think... */
+ if (!CH_COMPATIBLE_CLASSES (selector, label_value))
+ {
+ error ("case selector not compatible with label");
+ return error_mark_node;
+ }
+
+ /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
+ STRIP_TYPE_NOPS (label_value);
+
+ if (TREE_CODE (label_value) != INTEGER_CST)
+ {
+ error ("case label does not reduce to an integer constant");
+ return error_mark_node;
+ }
+
+ constant_expression_warning (label_value);
+ return label_value;
+}
+
+void
+chill_handle_case_default ()
+{
+ tree duplicate;
+ register tree label = build_decl (LABEL_DECL, NULL_TREE,
+ NULL_TREE);
+ int success = pushcase (NULL_TREE, 0, label, &duplicate);
+
+ if (success == 1)
+ error ("ELSE label not within a CASE statement");
+#if 0
+ else if (success == 2)
+ {
+ error ("multiple default labels found in a CASE statement");
+ error_with_decl (duplicate, "this is the first ELSE label");
+ }
+#endif
+}
+
+/* Handle cases label such as (I:J): or (modename): */
+
+static void
+chill_handle_case_label_range (min_value, max_value, selector)
+ tree min_value, max_value, selector;
+{
+ register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ min_value = check_case_value (min_value, selector);
+ max_value = check_case_value (max_value, selector);
+ if (TREE_CODE (min_value) != ERROR_MARK
+ && TREE_CODE (max_value) != ERROR_MARK)
+ {
+ tree duplicate;
+ int success = pushcase_range (min_value, max_value,
+ convert, label, &duplicate);
+ if (success == 1)
+ error ("label found outside of CASE statement");
+ else if (success == 2)
+ {
+ error ("duplicate CASE value");
+ error_with_decl (duplicate, "this is the first entry for that value");
+ }
+ else if (success == 3)
+ error ("CASE value out of range");
+ else if (success == 4)
+ error ("empty range");
+ else if (success == 5)
+ error ("label within scope of cleanup or variable array");
+ }
+}
+
+void
+chill_handle_case_label (label_value, selector)
+ tree label_value, selector;
+{
+ if (label_value == NULL_TREE
+ || TREE_CODE (label_value) == ERROR_MARK)
+ return;
+ if (TREE_CODE (label_value) == RANGE_EXPR)
+ {
+ if (TREE_OPERAND (label_value, 0) == NULL_TREE)
+ chill_handle_case_default (); /* i.e. (ELSE): or (*): */
+ else
+ chill_handle_case_label_range (TREE_OPERAND (label_value, 0),
+ TREE_OPERAND (label_value, 1),
+ selector);
+ }
+ else if (TREE_CODE (label_value) == TYPE_DECL)
+ {
+ tree type = TREE_TYPE (label_value);
+ if (! discrete_type_p (type))
+ error ("mode in label is not discrete");
+ else
+ chill_handle_case_label_range (TYPE_MIN_VALUE (type),
+ TYPE_MAX_VALUE (type),
+ selector);
+ }
+ else
+ {
+ register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ label_value = check_case_value (label_value, selector);
+
+ if (TREE_CODE (label_value) != ERROR_MARK)
+ {
+ tree duplicate;
+ int success = pushcase (label_value, convert, label, &duplicate);
+ if (success == 1)
+ error ("label not within a CASE statement");
+ else if (success == 2)
+ {
+ error ("duplicate case value");
+ error_with_decl (duplicate,
+ "this is the first entry for that value");
+ }
+ else if (success == 3)
+ error ("CASE value out of range");
+ else if (success == 4)
+ error ("empty range");
+ else if (success == 5)
+ error ("label within scope of cleanup or variable array");
+ }
+ }
+}
+
+int
+chill_handle_single_dimension_case_label (
+ selector, label_spec, expand_exit_needed, caseaction_flag
+)
+ tree selector, label_spec;
+ int *expand_exit_needed, *caseaction_flag;
+{
+ tree labels, one_label;
+ int no_completeness_check = 0;
+
+ if (*expand_exit_needed || *caseaction_flag == 1)
+ {
+ expand_exit_something ();
+ *expand_exit_needed = 0;
+ }
+
+ for (labels = label_spec; labels != NULL_TREE; labels = TREE_CHAIN (labels))
+ for (one_label = TREE_VALUE (labels); one_label != NULL_TREE;
+ one_label = TREE_CHAIN (one_label))
+ {
+ if (TREE_VALUE (one_label) == case_else_node)
+ no_completeness_check = 1;
+
+ chill_handle_case_label (TREE_VALUE (one_label), selector);
+ }
+
+ *caseaction_flag = 1;
+
+ return no_completeness_check;
+}
+
+static tree
+chill_handle_multi_case_label_range (low, high, selector)
+ tree low, high, selector;
+{
+ tree low_expr, high_expr, and_expr;
+ tree selector_type;
+ int low_target_val, high_target_val;
+ int low_type_val, high_type_val;
+
+ /* we can eliminate some tests is the low and/or high value in the given range
+ are outside the range of the selector type. */
+ low_target_val = TREE_INT_CST_LOW (low);
+ high_target_val = TREE_INT_CST_LOW (high);
+ selector_type = TREE_TYPE (selector);
+ low_type_val = TREE_INT_CST_LOW (TYPE_MIN_VALUE (selector_type));
+ high_type_val = TREE_INT_CST_LOW (TYPE_MAX_VALUE (selector_type));
+
+ if (low_target_val > high_type_val || high_target_val < low_type_val)
+ return boolean_false_node; /* selector never in range */
+
+ if (low_type_val >= low_target_val)
+ {
+ if (high_type_val <= high_target_val)
+ return boolean_true_node; /* always in the range */
+ return build_compare_expr (LE_EXPR, selector, high);
+ }
+
+ if (high_type_val <= high_target_val)
+ return build_compare_expr (GE_EXPR, selector, low);
+
+ /* The target range in completely within the range of the selector, but we
+ might be able to save a test if the upper bound is the same as the lower
+ bound. */
+ if (low_target_val == high_target_val)
+ return build_compare_expr (EQ_EXPR, selector, low);
+
+ /* No optimizations possible. Just generate tests against the upper and lower
+ bound of the target */
+ low_expr = build_compare_expr (GE_EXPR, selector, low);
+ high_expr = build_compare_expr (LE_EXPR, selector, high);
+ and_expr = build_chill_binary_op (TRUTH_ANDIF_EXPR, low_expr, high_expr);
+
+ return and_expr;
+}
+
+static tree
+chill_handle_multi_case_else_label (selector)
+ tree selector;
+{
+ tree else_range, selector_value, selector_type;
+ tree low, high, larg;
+
+ else_range = TREE_PURPOSE (selector);
+ if (else_range == NULL_TREE)
+ return boolean_false_node; /* no values in ELSE range */
+
+ /* Test each of the ranges in the else-range chain */
+ selector_value = TREE_VALUE (selector);
+ selector_type = TREE_TYPE (selector_value);
+ low = convert (selector_type, TREE_PURPOSE (else_range));
+ high = convert (selector_type, TREE_VALUE (else_range));
+ larg = chill_handle_multi_case_label_range (low, high, selector_value);
+
+ for (else_range = TREE_CHAIN (else_range);
+ else_range != NULL_TREE;
+ else_range = TREE_CHAIN (else_range))
+ {
+ tree rarg;
+ low = convert (selector_type, TREE_PURPOSE (else_range));
+ high = convert (selector_type, TREE_VALUE (else_range));
+ rarg = chill_handle_multi_case_label_range (low, high, selector_value);
+ larg = build_chill_binary_op (TRUTH_ORIF_EXPR, larg, rarg);
+ }
+
+ return larg;
+}
+
+static tree
+chill_handle_multi_case_label (selector, label)
+ tree selector, label;
+{
+ tree expr;
+
+ if (label == NULL_TREE || TREE_CODE (label) == ERROR_MARK)
+ return;
+
+ if (TREE_CODE (label) == INTEGER_CST)
+ {
+ int target_val = TREE_INT_CST_LOW (label);
+ tree selector_type = TREE_TYPE (TREE_VALUE (selector));
+ int low_type_val = TREE_INT_CST_LOW (TYPE_MIN_VALUE (selector_type));
+ int high_type_val = TREE_INT_CST_LOW (TYPE_MAX_VALUE (selector_type));
+ if (target_val < low_type_val || target_val > high_type_val)
+ expr = boolean_false_node;
+ else
+ expr = build_compare_expr (EQ_EXPR, TREE_VALUE (selector), label);
+ }
+ else if (TREE_CODE (label) == RANGE_EXPR)
+ {
+ if (TREE_OPERAND (label, 0) == NULL_TREE)
+ {
+ if (TREE_OPERAND (label, 1) == NULL_TREE)
+ expr = boolean_true_node; /* (*) -- matches everything */
+ else
+ expr = chill_handle_multi_case_else_label (selector);
+ }
+ else
+ {
+ tree low = TREE_OPERAND (label, 0);
+ tree high = TREE_OPERAND (label, 1);
+ if (TREE_CODE (low) != INTEGER_CST)
+ {
+ error ("Lower bound of range must be a discrete literal expression");
+ expr = error_mark_node;
+ }
+ if (TREE_CODE (high) != INTEGER_CST)
+ {
+ error ("Upper bound of range must be a discrete literal expression");
+ expr = error_mark_node;
+ }
+ if (expr != error_mark_node)
+ {
+ expr = chill_handle_multi_case_label_range (
+ low, high, TREE_VALUE (selector));
+ }
+ }
+ }
+ else if (TREE_CODE (label) == TYPE_DECL)
+ {
+ tree type = TREE_TYPE (label);
+ if (! discrete_type_p (type))
+ {
+ error ("mode in label is not discrete");
+ expr = error_mark_node;
+ }
+ else
+ expr = chill_handle_multi_case_label_range (
+ TYPE_MIN_VALUE (type), TYPE_MAX_VALUE (type), TREE_VALUE (selector));
+ }
+ else
+ {
+ error ("The CASE label is not valid");
+ expr = error_mark_node;
+ }
+
+ return expr;
+}
+
+static tree
+chill_handle_multi_case_label_list (selector, labels)
+ tree selector, labels;
+{
+ tree one_label, selector_value, larg, rarg;
+
+ one_label = TREE_VALUE (labels);
+ larg = chill_handle_multi_case_label (selector, TREE_VALUE (one_label));
+
+ for (one_label = TREE_CHAIN (one_label);
+ one_label != NULL_TREE;
+ one_label = TREE_CHAIN (one_label))
+ {
+ rarg = chill_handle_multi_case_label (selector, TREE_VALUE (one_label));
+ larg = build_chill_binary_op (TRUTH_ORIF_EXPR, larg, rarg);
+ }
+
+ return larg;
+}
+
+tree
+build_multi_case_selector_expression (selector_list, label_spec)
+ tree selector_list, label_spec;
+{
+ tree labels, selector, larg, rarg;
+
+ labels = label_spec;
+ selector = selector_list;
+ larg = chill_handle_multi_case_label_list(selector, labels);
+
+ for (labels = TREE_CHAIN (labels), selector = TREE_CHAIN (selector);
+ labels != NULL_TREE && selector != NULL_TREE;
+ labels = TREE_CHAIN (labels), selector = TREE_CHAIN (selector))
+ {
+ rarg = chill_handle_multi_case_label_list(selector, labels);
+ larg = build_chill_binary_op (TRUTH_ANDIF_EXPR, larg, rarg);
+ }
+
+ if (labels != NULL_TREE || selector != NULL_TREE)
+ error ("The number of CASE selectors does not match the number of CASE label lists");
+
+ return larg;
+}
+
+#define BITARRAY_TEST(ARRAY, INDEX) \
+ ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
+ & (1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR)))
+#define BITARRAY_SET(ARRAY, INDEX) \
+ ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
+ |= 1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR))
+
+extern HOST_WIDE_INT all_cases_count PROTO((tree, int*));
+extern void mark_seen_cases PROTO((tree, unsigned char*, long, int));
+
+/* CASES_SEEN is a set (bitarray) of length COUNT.
+ For each element that is zero, print an error message,
+ assume the element have the given TYPE. */
+
+static void
+print_missing_cases (type, cases_seen, count)
+ tree type;
+ unsigned char *cases_seen;
+ long count;
+{
+ long i;
+ for (i = 0; i < count; i++)
+ {
+ if (BITARRAY_TEST(cases_seen, i) == 0)
+ {
+ char buf[20];
+ long x = i;
+ long j;
+ tree t = type;
+ char *err_val_name = "???";
+ if (TYPE_MIN_VALUE (t)
+ && TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST)
+ x += TREE_INT_CST_LOW (TYPE_MIN_VALUE (t));
+ while (TREE_TYPE (t) != NULL_TREE)
+ t = TREE_TYPE (t);
+ switch (TREE_CODE (t))
+ {
+ tree v;
+ case BOOLEAN_TYPE:
+ err_val_name = x ? "TRUE" : "FALSE";
+ break;
+ case CHAR_TYPE:
+ if ((x >= ' ' && x < 127) && x != '\'' && x != '^')
+ sprintf (buf, "'%c'", x);
+ else
+ sprintf (buf, "'^(%d)'", x);
+ err_val_name = buf;
+ j = i;
+ while (j < count && !BITARRAY_TEST(cases_seen, j))
+ j++;
+ if (j > i + 1)
+ {
+ long y = x+j-i-1;
+ err_val_name += strlen (err_val_name);
+ if ((y >= ' ' && y < 127) && y != '\'' && y != '^')
+ sprintf (err_val_name, "%s:'%c'", buf, y);
+ else
+ sprintf (err_val_name, "%s:'^(%d)'", buf, y);
+ i = j - 1;
+ }
+ break;
+ case ENUMERAL_TYPE:
+ for (v = TYPE_VALUES (t); v && x; v = TREE_CHAIN (v))
+ x--;
+ if (v)
+ err_val_name = IDENTIFIER_POINTER (TREE_PURPOSE (v));
+ break;
+ default:
+ j = i;
+ while (j < count && !BITARRAY_TEST(cases_seen, j))
+ j++;
+ if (j == i + 1)
+ sprintf (buf, "%d", x);
+ else
+ sprintf (buf, "%d:%d", x, x+j-i-1);
+ i = j - 1;
+ err_val_name = buf;
+ break;
+ }
+ error ("incomplete CASE - %s not handled", err_val_name);
+ }
+ }
+}
+
+void
+check_missing_cases (type)
+ tree type;
+{
+ int is_sparse;
+ /* For each possible selector value. a one iff it has been matched
+ by a case value alternative. */
+ unsigned char *cases_seen;
+ /* The number of possible selector values. */
+ HOST_WIDE_INT size = all_cases_count (type, &is_sparse);
+ long bytes_needed = (size+HOST_BITS_PER_CHAR)/HOST_BITS_PER_CHAR;
+
+ if (size == -1)
+ warning ("CASE selector with variable range");
+ else if (size < 0 || size > 600000
+ /* We deliberately use malloc here - not xmalloc. */
+ || (cases_seen = (char*) malloc (bytes_needed)) == NULL)
+ warning ("too many cases to do CASE completeness testing");
+ else
+ {
+ bzero (cases_seen, bytes_needed);
+ mark_seen_cases (type, cases_seen, size, is_sparse);
+ print_missing_cases (type, cases_seen, size);
+ free (cases_seen);
+ }
+}
+
+/*
+ * We build an expression tree here because, in many contexts,
+ * we don't know the type of result that's desired. By the
+ * time we get to expanding the tree, we do know.
+ */
+tree
+build_chill_case_expr (exprlist, casealtlist_expr,
+ optelsecase_expr)
+ tree exprlist, casealtlist_expr, optelsecase_expr;
+{
+ return build (CASE_EXPR, NULL_TREE, exprlist,
+ optelsecase_expr ?
+ tree_cons (NULL_TREE,
+ optelsecase_expr,
+ casealtlist_expr) :
+ casealtlist_expr);
+}
+
+/* This function transforms the selector_list and alternatives into a COND_EXPR. */
+tree
+build_chill_multi_dimension_case_expr (selector_list, alternatives, else_expr)
+ tree selector_list, alternatives, else_expr;
+{
+ tree expr;
+
+ selector_list = check_case_selector_list (selector_list);
+
+ if (alternatives == NULL_TREE)
+ return NULL_TREE;
+
+ alternatives = nreverse (alternatives);
+ /* alternatives represents the CASE label specifications and resulting values in
+ the reverse order in which they appeared.
+ If there is an ELSE expression, then use it. If there is no
+ ELSE expression, make the last alternative (which is the first in the list)
+ into the ELSE expression. This is safe because, if the CASE is complete
+ (as required), then the last condition need not be checked anyway. */
+ if (else_expr != NULL_TREE)
+ expr = else_expr;
+ else
+ {
+ expr = TREE_VALUE (alternatives);
+ alternatives = TREE_CHAIN (alternatives);
+ }
+
+ for ( ; alternatives != NULL_TREE; alternatives = TREE_CHAIN (alternatives))
+ {
+ tree value = TREE_VALUE (alternatives);
+ tree labels = TREE_PURPOSE (alternatives);
+ tree cond = build_multi_case_selector_expression(selector_list, labels);
+ expr = build_nt (COND_EXPR, cond, value, expr);
+ }
+
+ return expr;
+}
+
+
+/* This is called with the assumption that RHS has been stabilized.
+ It has one purpose: to iterate through the CHILL list of LHS's */
+void
+expand_assignment_action (loclist, modifycode, rhs)
+ tree loclist;
+ enum chill_tree_code modifycode;
+ tree rhs;
+{
+ if (loclist == NULL_TREE || TREE_CODE (loclist) == ERROR_MARK
+ || rhs == NULL_TREE || TREE_CODE (rhs) == ERROR_MARK)
+ return;
+
+ if (TREE_CHAIN (loclist) != NULL_TREE)
+ { /* Multiple assignment */
+ tree target;
+ if (TREE_TYPE (rhs) != NULL_TREE)
+ rhs = save_expr (rhs);
+ else if (TREE_CODE (rhs) == CONSTRUCTOR)
+ error ("type of tuple cannot be implicit in multiple assignent");
+ else if (TREE_CODE (rhs) == CASE_EXPR || TREE_CODE (rhs) == COND_EXPR)
+ error ("conditional expression cannot be used in multiple assignent");
+ else
+ error ("internal error - unknown type in multiple assignment");
+
+ if (modifycode != NOP_EXPR)
+ {
+ error ("no operator allowed in multiple assignment,");
+ modifycode = NOP_EXPR;
+ }
+
+ for (target = TREE_CHAIN (loclist); target; target = TREE_CHAIN (target))
+ {
+ if (!CH_EQUIVALENT (TREE_TYPE (TREE_VALUE (target)),
+ TREE_TYPE (TREE_VALUE (loclist))))
+ {
+ error
+ ("location modes in multiple assignment are not equivalent");
+ break;
+ }
+ }
+ }
+ for ( ; loclist != NULL_TREE; loclist = TREE_CHAIN (loclist))
+ chill_expand_assignment (TREE_VALUE (loclist), modifycode, rhs);
+}
+
+void
+chill_expand_assignment (lhs, modifycode, rhs)
+ tree lhs;
+ enum chill_tree_code modifycode;
+ tree rhs;
+{
+ tree loc;
+
+ while (TREE_CODE (lhs) == COMPOUND_EXPR)
+ {
+ expand_expr (TREE_OPERAND (lhs, 0), const0_rtx, VOIDmode, 0);
+ emit_queue ();
+ lhs = TREE_OPERAND (lhs, 1);
+ }
+
+ if (TREE_CODE (lhs) == ERROR_MARK)
+ return;
+
+ /* errors for assignment to BUFFER, EVENT locations.
+ what about SIGNALs? FIXME: Need similar test in
+ build_chill_function_call. */
+ if (TREE_CODE (lhs) == IDENTIFIER_NODE)
+ {
+ tree decl = lookup_name (lhs);
+ if (decl)
+ {
+ tree type = TREE_TYPE (decl);
+ if (CH_IS_BUFFER_MODE (type) || CH_IS_EVENT_MODE (type))
+ {
+ error ("You may not assign a value to a BUFFER or EVENT location");
+ return;
+ }
+ }
+ }
+
+ if (TYPE_READONLY_PROPERTY (TREE_TYPE (lhs)) || TREE_READONLY (lhs))
+ {
+ error ("can't assign value to READonly location");
+ return;
+ }
+ if (CH_TYPE_NONVALUE_P (TREE_TYPE (lhs)))
+ {
+ error ("cannot assign to location with non-value property");
+ return;
+ }
+
+ if (TREE_CODE (TREE_TYPE (lhs)) == REFERENCE_TYPE)
+ lhs = convert_from_reference (lhs);
+
+ /* check for lhs is a location */
+ loc = lhs;
+ while (1)
+ {
+ if (TREE_CODE (loc) == SLICE_EXPR)
+ loc = TREE_OPERAND (loc, 0);
+ else if (TREE_CODE (loc) == SET_IN_EXPR)
+ loc = TREE_OPERAND (loc, 1);
+ else
+ break;
+ }
+ if (! CH_LOCATION_P (loc))
+ {
+ error ("lefthand side of assignment is not a location");
+ return;
+ }
+
+ /* If a binary op has been requested, combine the old LHS value with
+ the RHS producing the value we should actually store into the LHS. */
+
+ if (modifycode != NOP_EXPR)
+ {
+ lhs = stabilize_reference (lhs);
+ /* This is to handle border-line cases such
+ as: LHS OR := [I]. This seems to be permitted
+ by the letter of Z.200, though it violates
+ its spirit, since LHS:=LHS OR [I] is
+ *not* legal. */
+ if (TREE_TYPE (rhs) == NULL_TREE)
+ rhs = convert (TREE_TYPE (lhs), rhs);
+ rhs = build_chill_binary_op (modifycode, lhs, rhs);
+ }
+
+ rhs = chill_convert_for_assignment (TREE_TYPE (lhs), rhs, "assignment");
+
+ /* handle the LENGTH (vary_array) := expr action */
+ loc = lhs;
+ if (TREE_CODE (loc) == NOP_EXPR)
+ loc = TREE_OPERAND (loc, 0);
+ if (TREE_CODE (loc) == COMPONENT_REF
+ && chill_varying_type_p (TREE_TYPE (TREE_OPERAND (loc, 0)))
+ && DECL_NAME (TREE_OPERAND (loc, 1)) == var_length_id)
+ {
+ expand_varying_length_assignment (TREE_OPERAND (loc, 0), rhs);
+ }
+ else if (TREE_CODE (lhs) == SLICE_EXPR)
+ {
+ tree func = lookup_name (get_identifier ("__pscpy"));
+ tree dst = TREE_OPERAND (lhs, 0);
+ tree dst_offset = TREE_OPERAND (lhs, 1);
+ tree length = TREE_OPERAND (lhs, 2);
+ tree src, src_offset;
+ if (TREE_CODE (rhs) == SLICE_EXPR)
+ {
+ src = TREE_OPERAND (rhs, 0);
+ /* Should check that the TREE_OPERAND (src, 0) is
+ the same as length and powerserlen (src). FIXME */
+ src_offset = TREE_OPERAND (rhs, 1);
+ }
+ else
+ {
+ src = rhs;
+ src_offset = integer_zero_node;
+ }
+ expand_expr_stmt (build_chill_function_call (func,
+ tree_cons (NULL_TREE, force_addr_of (dst),
+ tree_cons (NULL_TREE, powersetlen (dst),
+ tree_cons (NULL_TREE, convert (long_unsigned_type_node, dst_offset),
+ tree_cons (NULL_TREE, force_addr_of (src),
+ tree_cons (NULL_TREE, powersetlen (src),
+ tree_cons (NULL_TREE, convert (long_unsigned_type_node, src_offset),
+ tree_cons (NULL_TREE, convert (long_unsigned_type_node, length),
+ NULL_TREE)))))))));
+ }
+
+ else if (TREE_CODE (lhs) == SET_IN_EXPR)
+ {
+ tree from_pos = save_expr (TREE_OPERAND (lhs, 0));
+ tree set = TREE_OPERAND (lhs, 1);
+ tree domain = TYPE_DOMAIN (TREE_TYPE (set));
+ tree set_length = size_binop (PLUS_EXPR,
+ size_binop (MINUS_EXPR,
+ TYPE_MAX_VALUE (domain),
+ TYPE_MIN_VALUE (domain)),
+ integer_one_node);
+ tree filename = force_addr_of (get_chill_filename());
+
+ if (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE)
+ sorry("bitstring slice");
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (
+ get_identifier ("__setbitpowerset")),
+ tree_cons (NULL_TREE, build_chill_addr_expr (set, "powerset"),
+ tree_cons (NULL_TREE, set_length,
+ tree_cons (NULL_TREE, TYPE_MIN_VALUE (domain),
+ tree_cons (NULL_TREE, convert (long_integer_type_node, from_pos),
+ tree_cons (NULL_TREE, rhs,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, get_chill_linenumber(),
+ NULL_TREE)))))))));
+ }
+
+ /* Handle arrays of packed bitfields. Currently, this is limited to bitfields
+ which are 1 bit wide, so use the powerset runtime function. */
+ else if (TREE_CODE (lhs) == PACKED_ARRAY_REF)
+ {
+ tree from_pos = save_expr (TREE_OPERAND (lhs, 1));
+ tree array = TREE_OPERAND (lhs, 0);
+ tree domain = TYPE_DOMAIN (TREE_TYPE (array));
+ tree array_length = size_binop (PLUS_EXPR,
+ size_binop (MINUS_EXPR,
+ TYPE_MAX_VALUE (domain),
+ TYPE_MIN_VALUE (domain)),
+ integer_one_node);
+ tree filename = force_addr_of (get_chill_filename());
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (
+ get_identifier ("__setbitpowerset")),
+ tree_cons (NULL_TREE, build_chill_addr_expr (array, "packed bitfield array"),
+ tree_cons (NULL_TREE, convert (long_unsigned_type_node, array_length),
+ tree_cons (NULL_TREE, convert (long_integer_type_node,
+ TYPE_MIN_VALUE (domain)),
+ tree_cons (NULL_TREE, convert (long_integer_type_node, from_pos),
+ tree_cons (NULL_TREE, build1 (CONVERT_EXPR, boolean_type_node, rhs),
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, get_chill_linenumber(),
+ NULL_TREE)))))))));
+ }
+
+ /* The following is probably superceded by the
+ above code for SET_IN_EXPR. FIXME! */
+ else if (TREE_CODE (lhs) == BIT_FIELD_REF)
+ {
+ tree set = TREE_OPERAND (lhs, 0);
+ tree numbits = TREE_OPERAND (lhs, 1);
+ tree from_pos = save_expr (TREE_OPERAND (lhs, 2));
+ tree domain = TYPE_DOMAIN (TREE_TYPE (set));
+ tree set_length = size_binop (PLUS_EXPR,
+ size_binop (MINUS_EXPR,
+ TYPE_MAX_VALUE (domain),
+ TYPE_MIN_VALUE (domain)),
+ integer_one_node);
+ tree filename = force_addr_of (get_chill_filename());
+ tree to_pos;
+ switch (TREE_CODE (TREE_TYPE (rhs)))
+ {
+ case SET_TYPE:
+ to_pos = size_binop (MINUS_EXPR,
+ size_binop (PLUS_EXPR, from_pos, numbits),
+ integer_one_node);
+ break;
+ case BOOLEAN_TYPE:
+ to_pos = from_pos;
+ break;
+ default:
+ abort ();
+ }
+
+ if (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE)
+ sorry("bitstring slice");
+ expand_expr_stmt (
+ build_chill_function_call( lookup_name (
+ get_identifier ("__setbitpowerset")),
+ tree_cons (NULL_TREE, build_chill_addr_expr (set, "powerset"),
+ tree_cons (NULL_TREE, set_length,
+ tree_cons (NULL_TREE, TYPE_MIN_VALUE (domain),
+ tree_cons (NULL_TREE, from_pos,
+ tree_cons (NULL_TREE, rhs,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, get_chill_linenumber(),
+ NULL_TREE)))))))));
+ }
+
+ else
+ expand_expr_stmt (build_chill_modify_expr (lhs, rhs));
+}
+
+/* Also assumes that rhs has been stabilized */
+void
+expand_varying_length_assignment (lhs, rhs)
+ tree lhs, rhs;
+{
+ tree base_array, min_domain_val;
+
+ pedwarn ("LENGTH on left-hand-side is non-portable");
+
+ if (! CH_LOCATION_P (lhs))
+ {
+ error ("Can only set LENGTH of array location");
+ return;
+ }
+
+ /* cause a RANGE exception if rhs would cause a 'hole' in the array. */
+ rhs = valid_array_index_p (lhs, rhs, "new array length too large", 1);
+
+ base_array = CH_VARYING_ARRAY_TYPE (TREE_TYPE (lhs));
+ min_domain_val = TYPE_MIN_VALUE (TYPE_DOMAIN (base_array));
+
+ lhs = build_component_ref (lhs, var_length_id);
+ rhs = size_binop (MINUS_EXPR, rhs, min_domain_val);
+
+ expand_expr_stmt (build_chill_modify_expr (lhs, rhs));
+}
+
+void
+push_action ()
+{
+ push_handler ();
+ if (ignoring)
+ return;
+ emit_line_note (input_filename, lineno);
+}
diff --git a/gcc/ch/chill.in b/gcc/ch/chill.in
new file mode 100644
index 0000000..62b73d5
--- /dev/null
+++ b/gcc/ch/chill.in
@@ -0,0 +1,130 @@
+#!/bin/sh
+# Compile GNU Chill programs.
+: || exec /bin/sh -f $0 $argv:q
+
+# The compiler name might be different when doing cross-compilation
+# (this should be configured)
+gcc_name=gcc
+whatgcc=gcc
+speclang=-xnone
+startfile=chillrt0
+gnuchill_script_flags=
+gnuchill_version=unknown
+extraflags=
+
+# replace the command name by the name of the new command
+progname=`basename $0`
+case "$0" in
+ */*)
+ gcc=`echo $0 | sed -e "s;/[^/]*$;;"`/$gcc_name
+ ;;
+ *)
+ gcc=$gcc_name
+ ;;
+esac
+
+# $first is yes for first arg, no afterwards.
+first=yes
+# If next arg is the argument of an option, $quote is non-empty.
+# More precisely, it is the option that wants an argument.
+quote=
+# $library is made empty to disable use of libchill.
+library="-lchill"
+libpath=chillrt
+numargs=$#
+
+for arg
+do
+ if [ $first = yes ]
+ then
+ # Need some 1st arg to `set' which does not begin with `-'.
+ # We get rid of it after the loop ends.
+ set gcc
+ first=no
+ fi
+ # If you have to ask what this does, you should not edit this file. :-)
+ # The ``S'' at the start is so that echo -nostdinc does not eat the
+ # -nostdinc.
+ arg=`echo "S$arg" | sed "s/^S//; s/'/'\\\\\\\\''/g"`
+ if [ x$quote != x ]
+ then
+ quote=
+ else
+ quote=
+ case $arg in
+ -nostdlib)
+ # Inhibit linking with -lchill.
+ library=
+ libpath=
+ startfile=
+ ;;
+ -B*)
+ gcc=`echo $arg | sed -e "s/^-B//"`$gcc_name
+ ;;
+ -[bBVDUoeTuIYmLiA] | -Tdata | -Xlinker)
+ # these switches take following word as argument,
+ # so don't treat it as a file name.
+ quote=$arg
+ ;;
+ -[cSEM] | -MM)
+ # Don't specify libraries if we won't link,
+ # since that would cause a warning.
+ library=
+ libpath=
+ startfile=
+ ;;
+ -x*)
+ speclang=$arg
+ ;;
+ -v)
+ # catch `chill -v'
+ if [ $numargs = 1 ] ; then
+ library=
+ libpath=
+ startfile=
+ fi
+ echo "GNUCHILL version $gnuchill_version"
+ ;;
+ -fgrant-only | -fchill-grant-only)
+ #inhibit production of an object file
+ extraflags="-S -o /dev/null"
+ library=
+ libpath=
+ startfile=
+ ;;
+ -*)
+ # Pass other options through; they don't need -x and aren't inputs.
+ ;;
+ *)
+ # If file ends in .i, put options around it.
+ # But not if a specified -x option is currently active.
+ case "$speclang $arg" in -xnone\ *.[i])
+ set "$@" -xchill "'$arg'" -xnone
+ continue
+ esac
+ ;;
+ esac
+ fi
+ set "$@" "'$arg'"
+done
+
+# Get rid of that initial 1st arg
+if [ $first = no ]; then
+ shift
+else
+ echo "$0: No input files specified."
+ exit 1
+fi
+
+if [ x$quote != x ]
+then
+ echo "$0: argument to \`$quote' missing"
+ exit 1
+fi
+
+# The '-ansi' flag prevents cpp from changing this:
+# NEWMODE x = SET (sun, mon, thu, wed, thu, fri, sat);
+#to this:
+# NEWMODE x = SET (1, mon, thu, wed, thu, fri, sat);
+#which is a CHILL syntax error.
+eval $whatgcc -ansi $gnuchill_script_flags $startfile "$@" $libpath $library $extraflags
diff --git a/gcc/ch/config-lang.in b/gcc/ch/config-lang.in
new file mode 100644
index 0000000..48be2d9
--- /dev/null
+++ b/gcc/ch/config-lang.in
@@ -0,0 +1,34 @@
+# Top level configure fragment for GNU CHILL.
+# Copyright (C) 1994 Free Software Foundation, Inc.
+
+#This file is part of GNU CC.
+
+#GNU CC 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 2, or (at your option)
+#any later version.
+
+#GNU CC 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 GNU CC; see the file COPYING. If not, write to
+#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language - name of language as it would appear in $(LANGUAGES)
+# compilers - value to add to $(COMPILERS)
+# stagestuff - files to add to $(STAGESTUFF)
+# diff_excludes - files to ignore when building diffs between two versions.
+
+language="CHILL"
+
+compilers="cc1chill"
+
+stagestuff="chill chill-cross cc1chill"
+
+diff_excludes="-x -x ch/chill.info*"
diff --git a/gcc/ch/configure b/gcc/ch/configure
new file mode 100755
index 0000000..1179770
--- /dev/null
+++ b/gcc/ch/configure
@@ -0,0 +1,644 @@
+#!/bin/sh
+# Configuration script for GNU CHILL
+# Copyright (C) 1994 Free Software Foundation, Inc.
+
+#This file is part of GNU CC.
+
+#GNU CC 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 2, or (at your option)
+#any later version.
+
+#GNU CC 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 GNU CC; see the file COPYING. If not, write to
+#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#
+# Shell script to create proper links to machine-dependent files in
+# preparation for compiling gcc.
+#
+# Options: --srcdir=DIR specifies directory where sources are.
+# --host=HOST specifies host configuration.
+# --target=TARGET specifies target configuration.
+# --build=TARGET specifies configuration of machine you are
+# using to compile GCC.
+# --prefix=DIR specifies directory to install in.
+# --local-prefix=DIR specifies directory to put local ./include in.
+# --exec-prefix=DIR specifies directory to install executables in.
+# --with-gnu-ld arrange to work with GNU ld.
+# --with-gnu-as arrange to work with GAS.
+# --with-stabs arrange to use stabs instead of host debug format.
+# --with-elf arrange to use elf instead of host debug format.
+# --nfp assume system has no FPU.
+#
+# If configure succeeds, it leaves its status in config.status.
+# If configure fails after disturbing the status quo,
+# config.status is removed.
+#
+
+progname=$0
+# Configure the runtime and regression-test directories
+SUBDIRS="runtime utils"
+SUBDIRS="$SUBDIRS testsuite/compile"
+SUBDIRS="$SUBDIRS testsuite/execute"
+SUBDIRS="$SUBDIRS testsuite/execute/telebras"
+SUBDIRS="$SUBDIRS testsuite/noncompile"
+SUBDIRS="$SUBDIRS testsuite/examples"
+SUBDIRS="$SUBDIRS testsuite/execute/oe"
+SUBDIRS="$SUBDIRS testsuite/compile/elektra"
+SUBDIRS="$SUBDIRS testsuite/compile/votrics"
+
+# Default --srcdir to the directory where the script is found,
+# if a directory was specified.
+# The second sed call is to convert `.//configure' to `./configure'.
+srcdir=`echo $0 | sed 's|//|/|' | sed 's|/[^/]*$||'`
+if [ x$srcdir = x$0 ]
+then
+srcdir=
+fi
+
+host=
+
+# Default prefix to /usr/local.
+prefix=/usr/local
+
+# local_prefix specifies where to find the directory /usr/local/include
+# We don't use $(prefix) for this
+# because we always want GCC to search /usr/local/include
+# even if GCC is installed somewhere other than /usr/local.
+# Think THREE TIMES before specifying any other value for this!
+# DO NOT make this use $prefix!
+local_prefix=/usr/local
+# CYGNUS LOCAL: for our purposes, this must be prefix. This is apparently
+# only done for the benefit of glibc, and we don't use glibc.
+local_prefix='$(prefix)'
+# Default is to let the Makefile set exec_prefix from $(prefix)
+exec_prefix='$(prefix)'
+
+# CYGNUS LOCAL. Default to nothing.
+program_transform_name=
+program_transform_set=
+site=
+
+remove=rm
+hard_link=ln
+symbolic_link='ln -s'
+copy=cp
+
+# Record all the arguments, to write them in config.status.
+arguments=$*
+
+#for Test
+#remove="echo rm"
+#hard_link="echo ln"
+#symbolic_link="echo ln -s"
+
+target=
+host=
+build=
+
+for arg in $*;
+do
+ case $next_arg in
+ --srcdir)
+ srcdir=$arg
+ next_arg=
+ ;;
+ --host)
+ host=$arg
+ next_arg=
+ ;;
+ --target)
+ target=$arg
+ next_arg=
+ ;;
+ --build)
+ build=$arg
+ next_arg=
+ ;;
+ --prefix)
+ prefix=$arg
+ next_arg=
+ ;;
+ --local-prefix)
+ local_prefix=$arg
+ next_arg=
+ ;;
+ --exec-prefix)
+ exec_prefix=$arg
+ next_arg=
+ ;;
+ --program-transform-name) # CYGNUS LOCAL
+ # Double any backslashes or dollar signs in the argument.
+ if [ -n "${arg}" ] ; then
+ program_transform_name="${program_transform_name} -e `echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`"
+ fi
+ program_transform_set=yes
+ next_arg=
+ ;;
+ --program-prefix) # CYGNUS LOCAL
+ if [ -n "${arg}" ]; then
+ program_transform_name="${program_transform_name} -e s,^,`echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`,"
+ fi
+ program_transform_set=yes
+ next_arg=
+ ;;
+ --program-suffix) # CYGNUS LOCAL
+ if [ -n "${arg}" ]; then
+ program_transform_name="${program_transform_name} -e s,\$\$,`echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`,"
+ fi
+ program_transform_set=yes
+ next_arg=
+ ;;
+ --site) # CYGNUS LOCAL
+ site=${arg}
+ next_arg=
+ ;;
+ --x-*)
+ next_arg=
+ ;;
+ *)
+ case $arg in
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s)
+ next_arg=--srcdir
+ ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*)
+ srcdir=`echo $arg | sed 's/-*s[a-z]*=//'`
+ ;;
+ -host | --host | --hos | --ho | --h)
+ next_arg=--host
+ ;;
+ -host=* | --host=* | --hos=* | --ho=* | --h=*)
+ host=`echo $arg | sed 's/-*h[a-z]*=//'`
+ ;;
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ next_arg=--target
+ ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target=`echo $arg | sed 's/-*t[a-z]*=//'`
+ ;;
+ -build | --build | --buil | --bui | --bu | --b)
+ next_arg=--build
+ ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*)
+ build=`echo $arg | sed 's/-*b[a-z]*=//'`
+ ;;
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ next_arg=--prefix
+ ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=`echo $arg | sed 's/-*p[a-z]*=//'`
+ ;;
+ -local-prefix | --local-prefix | --local-prefi | --local-pref | --local-pre \
+ | --local-pr | --local-p | --local- | --local | --loc | --lo | --l)
+ next_arg=--local-prefix
+ ;;
+ -local-prefix=* | --local-prefix=* | --local-prefi=* | --local-pref=* \
+ | --local-pre=* | --local-pr=* | --local-p=* | --local-=* | --local=* \
+ | --loc=* | --lo=* | --l=*)
+ local_prefix=`echo $arg | sed 's/-*l[-a-z]*=//'`
+ ;;
+ -exec-prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre \
+ | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e)
+ next_arg=--exec-prefix
+ ;;
+ -exec-prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* \
+ | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* \
+ | --exe=* | --ex=* | --e=*)
+ exec_prefix=`echo $arg | sed 's/-*e[-a-z]*=//'`
+ ;;
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- | --program-transform \
+ | --program-transfor | --program-transfo | --program-transf \
+ | --program-trans | --program-tran | --program-tra \
+ | --program-tr | --program-t)
+ next_arg=--program-transform-name
+ # CYGNUS LOCAL
+ ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* | --program-transfo=* \
+ | --program-transf=* | --program-trans=* | --program-tran=* \
+ | --program-tra=* | --program-tr=* | --program-t=*)
+ # CYGNUS LOCAL
+ arg=`echo ${arg} | sed -e 's/^[-a-z_]*=//'`
+ # Double any \ or $ in the argument.
+ if [ -n "${arg}" ] ; then
+ program_transform_name="${program_transform_name} -e `echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`"
+ fi
+ program_transform_set=yes
+ ;;
+ -program-prefix | --program-prefix | --program-prefi \
+ | --program-pref | --program-pre | --program-pr \
+ | --program-p)
+ next_arg=--program-prefix
+ # CYGNUS LOCAL
+ ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* \
+ | --program-p=*)
+ # CYGNUS LOCAL
+ arg=`echo ${arg} | sed -e 's/^[-a-z_]*=//'`
+ if [ -n "${arg}" ]; then
+ program_transform_name="${program_transform_name} -e s,^,`echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`,"
+ fi
+ program_transform_set=yes
+ ;;
+ -program-suffix | --program-suffix | --program-suffi \
+ | --program-suff | --program-suf | --program-su \
+ | --program-s)
+ next_arg=--program-suffix
+ # CYGNUS LOCAL
+ ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* \
+ | --program-s=*)
+ # CYGNUS LOCAL
+ arg=`echo ${arg} | sed -e 's/^[-a-z_]*=//'`
+ if [ -n "${arg}" ]; then
+ program_transform_name="${program_transform_name} -e s,\$\$,`echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`,"
+ fi
+ program_transform_set=yes
+ ;;
+ -site | --site | --sit) # CYGNUS LOCAL
+ next_arg=--site
+ ;;
+ -site=* | --site=* | --sit=* | --si=*) # CYGNUS LOCAL
+ site=`echo ${arg} | sed 's/^[-a-z]*=//'`
+ ;;
+ -with-gnu-ld | --with-gnu-ld | --with-gnu-l)
+ gnu_ld=yes
+ ;;
+ -gas | --gas | --ga | --g | -with-gnu-as | --with-gnu-as | -with-gnu-a)
+ gas=yes
+ ;;
+ -nfp | --nfp | --nf | --n)
+ nfp=yes
+ ;;
+ -with-stabs | -with-stab | -with-sta | -with-st | -with-s \
+ | --with-stabs | --with-stab | --with-sta | --with-st | --with-s \
+ | -stabs | -stab | -sta | -st \
+ | --stabs | --stab | --sta | --st)
+ stabs=yes
+ ;;
+ -with-elf | -with-el | -with-se \
+ | --with-elf | --with-el | --with-e \
+ | -elf | -el | -e \
+ |--elf | --el | --e)
+ elf=yes
+ ;;
+ -with-* | --with-*) ;; #ignored
+ -without-* | --without-*) ;; #ignored
+ -enable-* | --enable-*) ;; #ignored
+ -x | --x) ;; # ignored
+ -x-*=* | --x-*=*) ;; # ignored
+ -x-* | --x-*)
+ next_arg=--x-ignored # ignored
+ ;;
+ --he*) ;; # ignored for now (--help)
+ --vers*) ;; # ignored for now (--version)
+ -v | -verb* | --verb*) ;; # ignored for now (--verbose)
+ --program-*) ;; #ignored (--program-prefix, --program-suffix)
+ --c*) ;; #ignored (--cache-file)
+ --q*) ;; #ignored (--quiet)
+ --si*) ;; #ignored (--silent)
+ -*)
+ echo "Invalid option \`$arg'" 1>&2
+ exit 1
+ ;;
+ *)
+# Allow configure HOST TARGET
+ if [ x$host = x ]
+ then
+ host=$target
+ fi
+ target=$arg
+ ;;
+ esac
+ esac
+done
+
+# Find the source files, if location was not specified.
+if [ x$srcdir = x ]
+then
+ srcdirdefaulted=1
+ srcdir=.
+ if [ ! -r tree.c ]
+ then
+ srcdir=..
+ fi
+fi
+
+if [ ! -r ${srcdir}/grant.c ]
+then
+ if [ x$srcdirdefaulted = x ]
+ then
+ echo "$progname: Can't find CHILL frontend sources in \`${srcdir}'" 1>&2
+ else
+ echo "$progname: Can't find CHILL frontend sources in \`.' or \`..'" 1>&2
+ fi
+ exit 1
+fi
+
+# Make sure that scripts are executable
+[ -w ${srcdir} -a -f ${srcdir}/regression.sh ] && \
+ chmod +x ${srcdir}/regression.sh
+[ -w ${srcdir} -a -f ${srcdir}/regression.prpt ] && \
+ chmod +x ${srcdir}/regression.prpt
+[ -w ${srcdir} -a -f ${srcdir}/regression.awk3 ] && \
+ chmod +x ${srcdir}/regression.awk3
+
+if [ -r ${srcdir}/config.status ] && [ x$srcdir != x. ]
+then
+ echo "$progname: \`configure' has been run in \`${srcdir}'" 1>&2
+ exit 1
+fi
+
+host_xmake_file=
+host_truncate_target=
+
+# Complain if an arg is missing
+if [ x$build = x ]
+then
+ # If host was specified, always use it for build also to avoid
+ # confusion. If someone wants a cross compiler where build != host,
+ # then they must specify build explicitly. Since this case is
+ # extremely rare, it does not matter that it is slightly inconvenient.
+ if [ x$host != x ]
+ then
+ build=$host
+
+ # This way of testing the result of a command substitution is
+ # defined by Posix.2 (section 3.9.1) as well as traditional shells.
+ elif build=`${srcdir}/../config.guess`
+ then
+ echo "This appears to be a ${build} system." 1>&2
+
+ elif [ x$target != x ]
+ then
+ echo 'Config.guess failed to determine the host type. Defaulting to target.'
+ build=$target
+ else
+ echo 'Config.guess failed to determine the host type. You need to specify one.' 1>&2
+ echo "\
+Usage: `basename $progname` [--host=HOST] [--build=BUILD]
+ [--prefix=DIR] [--gxx-include-dir=DIR] [--local-pref=DIR] [--exec-pref=DIR]
+ [--with-gnu-as] [--with-gnu-ld] [--with-stabs] [--with-elf] [--nfp] TARGET" 1>&2
+ echo "Where HOST, TARGET and BUILD are three-part configuration names " 1>&2
+ if [ -r config.status ]
+ then
+ tail +2 config.status 1>&2
+ fi
+ exit 1
+ fi
+fi
+
+# If $host was not specified, use $build.
+if [ x$host = x ]
+then
+ host=$build
+fi
+
+# If $target was not specified, use $host.
+if [ x$target = x ]
+then
+ target=$host
+fi
+
+# Validate the specs, and canonicalize them.
+canon_build=`/bin/sh $srcdir/../config.sub $build` || exit 1
+canon_host=`/bin/sh $srcdir/../config.sub $host` || exit 1
+canon_target=`/bin/sh $srcdir/../config.sub $target` || exit 1
+
+rm -f config.bak
+if [ -f config.status ]; then mv -f config.status config.bak; fi
+
+#
+# For the current directory and all of the designated SUBDIRS,
+# do the rest of the script...
+#
+if [ ! -d testsuite ] ; then mkdir testsuite; fi
+_SUBDIRS=
+for d in $SUBDIRS; do
+ [ -d $srcdir/$d ] && _SUBDIRS="$_SUBDIRS $d"
+done
+
+savesrcdir=$srcdir
+STARTDIR=`pwd`
+
+for subdir in $_SUBDIRS
+do
+ tmake_file=
+ host_xmake_file=
+ oldsrcdir=$savesrcdir
+
+ # ${invsubdir} is inverse of ${subdir), *with* trailing /, if needed.
+ invsubdir=`echo ${subdir}/ | sed -e 's|\./||g' -e 's|[^/]*/|../|g'`
+
+ # Re-adjust the path
+ # Also create a .gdbinit file which runs the one in srcdir
+ # and tells GDB to look there for source files.
+
+ case $oldsrcdir in
+ ".") srcdir=. ;;
+ /*) # absolute path
+ srcdir=${oldsrcdir}/${subdir} ;;
+ *) # otherwise relative
+ srcdir=${invsubdir}${oldsrcdir}/${subdir} ;;
+ esac
+
+ if [ -r ${oldsrcdir}/${subdir}/.gdbinit -a ${oldsrcdir} != "." ] ; then
+ cat > ${subdir}/.gdbinit <<EOF
+dir .
+dir ${srcdir}
+source ${srcdir}/.gdbinit
+EOF
+ fi
+
+ case $oldsrcdir in
+ /*) ;;
+ *) oldsrcdir=${invsubdir}${oldsrcdir} ;;
+ esac
+ mainsrcdir=${oldsrcdir}/..
+ test -d $subdir || mkdir $subdir
+ cd $subdir
+ #
+ # Create Makefile.tem from Makefile.in.
+ # Make it set VPATH if necessary so that the sources are found.
+ # Also change its value of srcdir.
+ rm -f Makefile.tem
+ echo "VPATH = ${srcdir}" \
+ | cat - ${srcdir}/Makefile.in \
+ | sed "s@^srcdir = \.@srcdir = ${srcdir}@" > Makefile.tem
+
+ # Conditionalize the makefile for this host machine.
+ if [ -f ${mainsrcdir}/config/${host_xmake_file} ]
+ then
+ rm -f Makefile.xx
+ sed -e "/####host/ r ${mainsrcdir}/config/${host_xmake_file}" Makefile.tem > Makefile.xx
+ echo "Merged ${host_xmake_file}."
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ else
+ # Say in the makefile that there is no host_xmake_file,
+ # by using a name which (when interpreted relative to $srcdir/config)
+ # will duplicate another dependency: $srcdir/Makefile.in.
+ host_xmake_file=../Makefile.in
+ fi
+
+ # Define variables host_canonical, build_canonical, and target_canonical
+ # because some Cygnus local changes in the Makefile depend on them.
+ echo host_canonical = ${canon_host} > Makefile.xx
+ echo target_canonical = ${canon_target} >> Makefile.xx
+ echo build_canonical = ${canon_build} >> Makefile.xx
+ cat Makefile.tem >> Makefile.xx
+ mv Makefile.xx Makefile.tem
+
+ # Conditionalize the makefile for this target machine.
+ if [ -f ${mainsrcdir}/config/${tmake_file} ]
+ then
+ rm -f Makefile.xx
+ sed -e "/####target/ r ${mainsrcdir}/config/${tmake_file}" Makefile.tem > Makefile.xx
+ echo "Merged ${tmake_file}."
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ else
+ # Say in the makefile that there is no tmake_file,
+ # by using a name which (when interpreted relative to $srcdir/config)
+ # will duplicate another dependency: $srcdir/Makefile.in.
+ tmake_file=../Makefile.in
+ fi
+
+ # CYGNUS LOCAL
+ # Conditionalize the makefile for this site.
+ if [ -f ${mainsrcdir}/config/ms-${site} ]
+ then
+ rm -f Makefile.xx
+ sed -e "/####site/ r ${mainsrcdir}/config/ms-${site}" Makefile.tem > Makefile.xx
+ echo "Merged ms-${site}."
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ fi
+
+ # CYGNUS LOCAL
+ # If this is a cross compilation, and we have newlib in the build
+ # tree, then define inhibit_libc in LIBGCC2_CFLAGS. This will cause
+ # __eprintf to be left out of libgcc.a, but that's OK because newlib
+ # has its own version of assert.h.
+ if [ x$host != x$target ]; then
+ sed -e 's/^\(LIBGCC2_CFLAGS[ ]*=[ ]*\)/\1-Dinhibit_libc /' Makefile.tem > Makefile.tem2
+ rm -f Makefile.tem
+ mv Makefile.tem2 Makefile.tem
+ fi
+
+ # Remove all formfeeds, since some Makes get confused by them.
+ # Also arrange to give the variables `target', `host_xmake_file',
+ # `tmake_file', `prefix', `local_prefix', `exec_prefix', `FIXINCLUDES'
+ # and `INSTALL_HEADERS_DIR' values in the Makefile from the values
+ # they have in this script.
+ # CYGNUS LOCAL: FLOAT_H, CROSS_FLOAT_H, objdir
+ rm -f Makefile.xx
+ sed -e "s/ //" -e "s/^target=.*$/target=${target}/" \
+ -e "s|^xmake_file=.*$|xmake_file=${host_xmake_file}|" \
+ -e "s|^tmake_file=.*$|tmake_file=${tmake_file}|" \
+ -e "s|^version=.*$|version=${version}|" \
+ -e "s|^prefix[ ]*=.*|prefix = $prefix|" \
+ -e "s|^local_prefix[ ]*=.*|local_prefix = $local_prefix|" \
+ -e "s|^exec_prefix[ ]*=.*|exec_prefix = $exec_prefix|" \
+ -e "s|^objdir[ ]*=.*|objdir=`pwd`|" \
+ Makefile.tem > Makefile.xx
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+
+ # Install Makefile for real, after making final changes.
+ # Define macro CROSS_COMPILE in compilation if this is a cross-compiler.
+ # Also use all.cross instead of all.internal, and add cross-make to Makefile.
+ if [ x$canon_host = x$canon_target ]
+ then
+ rm -f Makefile
+ if [ x$canon_host = x$canon_build ]
+ then
+ mv Makefile.tem Makefile
+ else
+ # When building gcc with a cross-compiler, we need to fix a
+ # few things.
+ echo "build= $build" > Makefile
+ sed -e "/####build/ r ${mainsrcdir}/build-make" Makefile.tem >> Makefile
+ rm -f Makefile.tem Makefile.xx
+ fi
+ else
+ rm -f Makefile
+ echo "CROSS=-DCROSS_COMPILE" > Makefile
+ sed -e "/####cross/ r ${mainsrcdir}/cross-make" Makefile.tem >> Makefile
+ rm -f Makefile.tem Makefile.xx
+ fi
+
+ echo "Created \`$subdir/Makefile'."
+
+ if [ xx${vint} != xx ]
+ then
+ vintmsg=" (vint)"
+ fi
+
+ # Describe the chosen configuration in config.status.
+ # Make that file a shellscript which will reestablish the same configuration.
+
+ rm -f config.bak
+ if [ -f config.status ]; then mv -f config.status config.bak; fi
+
+ echo "#!/bin/sh
+ # This directory was configured as follows:
+cd $invsubdir; ${progname}" $arguments > config.new
+ echo echo host=$canon_host target=$canon_target build=$canon_build >> config.new
+ chmod a+x config.new
+
+ # If we aren't executing the configure script in .
+ if [ x$subdir != x. ]
+ then
+ if [ -f $srcdir/configure ]
+ then
+ echo "Running \`${CONFIG_SHELL-sh} $srcdir/configure $arguments\'"
+ ${CONFIG_SHELL-sh} $srcdir/configure $arguments
+ echo "${srcdir}/configure" $arguments >> config.new
+ echo echo host=$canon_host target=$canon_target build=$canon_build >> config.new
+ fi
+ fi
+
+ if [ -f config.bak ] && cmp config.bak config.new >/dev/null 2>/dev/null;
+ then
+ mv -f config.bak config.status
+ rm -f config.new
+ else
+ mv -f config.new config.status
+ rm -f config.bak
+ fi
+
+ cd $STARTDIR
+done # end of current-dir SUBDIRS loop
+
+srcdir=$savesrcdir
+
+# Describe the chosen configuration in config.status.
+# Make that file a shellscript which will reestablish the same configuration.
+echo "#!/bin/sh
+# This directory was configured as follows:
+${progname}" $arguments > config.new
+echo echo host=$canon_host target=$canon_target build=$canon_build >> config.new
+chmod a+x config.new
+if [ -f config.bak ] && cmp config.bak config.new >/dev/null 2>/dev/null;
+then
+ mv -f config.bak config.status
+ rm -f config.new
+else
+ mv -f config.new config.status
+ rm -f config.bak
+fi
+
+exit 0
diff --git a/gcc/ch/convert.c b/gcc/ch/convert.c
new file mode 100644
index 0000000..d865336
--- /dev/null
+++ b/gcc/ch/convert.c
@@ -0,0 +1,1231 @@
+/* Language-level data type conversion for GNU CHILL.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file contains the functions for converting CHILL expressions
+ to different data types. The only entry point is `convert'.
+ Every language front end must have a `convert' function
+ but what kind of conversions it does will depend on the language. */
+
+#include "config.h"
+#include "tree.h"
+#include "ch-tree.h"
+#include "flags.h"
+#include "convert.h"
+#include "lex.h"
+
+extern void error PROTO((char *, ...));
+extern tree initializer_constant_valid_p PROTO((tree, tree));
+extern tree bit_one_node, bit_zero_node;
+extern tree string_one_type_node;
+extern tree bitstring_one_type_node;
+
+static tree
+convert_to_reference (reftype, expr)
+ tree reftype, expr;
+{
+ while (TREE_CODE (expr) == NOP_EXPR) /* RETYPE_EXPR */
+ expr = TREE_OPERAND (expr, 0);
+
+ if (! CH_LOCATION_P (expr))
+ error("internal error: trying to make loc-identity with non-location");
+ else
+ {
+ mark_addressable (expr);
+ return fold (build1 (ADDR_EXPR, reftype, expr));
+ }
+
+ return error_mark_node;
+}
+
+tree
+convert_from_reference (expr)
+ tree expr;
+{
+ tree e = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr);
+ TREE_READONLY (e) = TREE_READONLY (expr);
+ return e;
+}
+
+/* Convert EXPR to a boolean type. */
+
+static tree
+convert_to_boolean (type, expr)
+ tree type, expr;
+{
+ register tree intype = TREE_TYPE (expr);
+
+ if (integer_zerop (expr))
+ return boolean_false_node;
+ if (integer_onep (expr))
+ return boolean_true_node;
+
+ /* Convert a singleton bitstring to a Boolean.
+ Needed if flag_old_strings. */
+ if (CH_BOOLS_ONE_P (intype))
+ {
+ if (TREE_CODE (expr) == CONSTRUCTOR)
+ {
+ tree valuelist = TREE_OPERAND (expr, 1);
+ if (valuelist == NULL_TREE)
+ return boolean_false_node;
+ if (TREE_CHAIN (valuelist) == NULL_TREE
+ && TREE_PURPOSE (valuelist) == NULL_TREE
+ && integer_zerop (TREE_VALUE (valuelist)))
+ return boolean_true_node;
+ }
+ return build_chill_bitref (expr,
+ build_tree_list (NULL_TREE,
+ integer_zero_node));
+ }
+
+ if (INTEGRAL_TYPE_P (intype))
+ return build1 (CONVERT_EXPR, type, expr);
+
+ error ("cannot convert to a boolean mode");
+ return boolean_false_node;
+}
+
+/* Convert EXPR to a char type. */
+
+static tree
+convert_to_char (type, expr)
+ tree type, expr;
+{
+ register tree intype = TREE_TYPE (expr);
+ register enum chill_tree_code form = TREE_CODE (intype);
+
+ if (form == CHAR_TYPE)
+ return build1 (NOP_EXPR, type, expr);
+
+ /* Convert a singleton string to a char.
+ Needed if flag_old_strings. */
+ if (CH_CHARS_ONE_P (intype))
+ {
+ if (TREE_CODE (expr) == STRING_CST)
+ {
+ expr = build_int_2 ((unsigned char)TREE_STRING_POINTER(expr)[0], 0);
+ TREE_TYPE (expr) = char_type_node;
+ return expr;
+ }
+ else
+ return build (ARRAY_REF, char_type_node, expr, integer_zero_node);
+
+ }
+
+ /* For now, assume it will always fit */
+ if (form == INTEGER_TYPE)
+ return build1 (CONVERT_EXPR, type, expr);
+
+ error ("cannot convert to a char mode");
+
+ {
+ register tree tem = build_int_2 (0, 0);
+ TREE_TYPE (tem) = type;
+ return tem;
+ }
+}
+
+tree
+base_type_size_in_bytes (type)
+ tree type;
+{
+ if (type == NULL_TREE
+ || TREE_CODE (type) == ERROR_MARK
+ || TREE_CODE (type) != ARRAY_TYPE)
+ return error_mark_node;
+ return size_in_bytes (TREE_TYPE (type));
+}
+
+/*
+ * build a singleton array type, of TYPE objects.
+ */
+tree
+build_array_type_for_scalar (type)
+ tree type;
+{
+ /* KLUDGE */
+ if (type == char_type_node)
+ return build_string_type (type, integer_one_node);
+
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+
+ return build_chill_array_type
+ (type,
+ tree_cons (NULL_TREE,
+ build_chill_range_type (NULL_TREE,
+ integer_zero_node, integer_zero_node),
+ NULL_TREE),
+ 0, NULL_TREE);
+
+}
+
+#if 0
+static tree
+unreferenced_type_of (type)
+ tree type;
+{
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+ while (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ return type;
+}
+#endif
+
+
+/* Remove from *LISTP the first TREE_LIST node whose TREE_PURPOSE == KEY.
+ Return the TREE_LIST node, or NULL_TREE on failure. */
+
+static tree
+remove_tree_element (key, listp)
+ tree *listp;
+ tree key;
+{
+ tree node = *listp;
+ for ( ; node; listp = &TREE_CHAIN (node), node = *listp)
+ {
+ if (TREE_PURPOSE (node) == key)
+ {
+ *listp = TREE_CHAIN (node);
+ TREE_CHAIN (node) = NULL_TREE;
+ return node;
+ }
+ }
+ return NULL_TREE;
+}
+
+/* This is quite the same as check_range in actions.c, but with
+ different error message. */
+
+static tree
+check_ps_range (value, lo_limit, hi_limit)
+ tree value;
+ tree lo_limit;
+ tree hi_limit;
+{
+ tree check = test_range (value, lo_limit, hi_limit);
+
+ if (!integer_zerop (check))
+ {
+ if (TREE_CODE (check) == INTEGER_CST)
+ {
+ error ("powerset tuple element out of range");
+ return error_mark_node;
+ }
+ else
+ value = check_expression (value, check,
+ ridpointers[(int) RID_RANGEFAIL]);
+ }
+ return value;
+}
+
+static tree
+digest_powerset_tuple (type, inits)
+ tree type;
+ tree inits;
+{
+ tree list;
+ tree result;
+ tree domain = TYPE_DOMAIN (type);
+ int i = 0;
+ int is_erroneous = 0, is_constant = 1, is_simple = 1;
+ if (domain == NULL_TREE || TREE_CODE (domain) == ERROR_MARK)
+ return error_mark_node;
+ for (list = TREE_OPERAND (inits, 1); list; list = TREE_CHAIN (list), i++)
+ {
+ tree val = TREE_VALUE (list);
+ if (TREE_CODE (val) == ERROR_MARK)
+ {
+ is_erroneous = 1;
+ continue;
+ }
+ if (!TREE_CONSTANT (val))
+ is_constant = 0;
+ else if (!initializer_constant_valid_p (val, TREE_TYPE (val)))
+ is_simple = 0;
+ if (! CH_COMPATIBLE (val, domain))
+ {
+ error ("incompatible member of powerset tuple (at position #%d)", i);
+ is_erroneous = 1;
+ continue;
+ }
+ /* check range of value */
+ val = check_ps_range (val, TYPE_MIN_VALUE (domain),
+ TYPE_MAX_VALUE (domain));
+ if (TREE_CODE (val) == ERROR_MARK)
+ {
+ is_erroneous = 1;
+ continue;
+ }
+
+ /* Updating the list in place is in principle questionable,
+ but I can't think how it could hurt. */
+ TREE_VALUE (list) = convert (domain, val);
+
+ val = TREE_PURPOSE (list);
+ if (val == NULL_TREE)
+ continue;
+
+ if (TREE_CODE (val) == ERROR_MARK)
+ {
+ is_erroneous = 1;
+ continue;
+ }
+ if (! CH_COMPATIBLE (val, domain))
+ {
+ error ("incompatible member of powerset tuple (at position #%d)", i);
+ is_erroneous = 1;
+ continue;
+ }
+ val = check_ps_range (val, TYPE_MIN_VALUE (domain),
+ TYPE_MAX_VALUE (domain));
+ if (TREE_CODE (val) == ERROR_MARK)
+ {
+ is_erroneous = 1;
+ continue;
+ }
+ TREE_PURPOSE (list) = convert (domain, val);
+ if (!TREE_CONSTANT (val))
+ is_constant = 0;
+ else if (!initializer_constant_valid_p (val, TREE_TYPE (val)))
+ is_simple = 0;
+ }
+ result = build (CONSTRUCTOR, type, NULL_TREE, TREE_OPERAND (inits, 1));
+ if (is_erroneous)
+ return error_mark_node;
+ if (is_constant)
+ TREE_CONSTANT (result) = 1;
+ if (is_constant && is_simple)
+ TREE_STATIC (result) = 1;
+ return result;
+}
+
+static tree
+digest_structure_tuple (type, inits)
+ tree type;
+ tree inits;
+{
+ tree elements = CONSTRUCTOR_ELTS (inits);
+ tree values = NULL_TREE;
+ int is_constant = 1;
+ int is_simple = 1;
+ int is_erroneous = 0;
+ tree field;
+ int labelled_elements = 0;
+ int unlabelled_elements = 0;
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (TREE_TYPE (field)) != UNION_TYPE)
+ { /* Regular fixed field. */
+ tree value = remove_tree_element (DECL_NAME (field), &elements);
+
+ if (value)
+ labelled_elements++;
+ else if (elements && TREE_PURPOSE (elements) == NULL_TREE)
+ {
+ value = elements;
+ elements = TREE_CHAIN (elements);
+ unlabelled_elements++;
+ }
+
+ if (value)
+ {
+ tree val;
+ char msg[120];
+ sprintf (msg, "initializer for field `%.80s'",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
+ val = chill_convert_for_assignment (TREE_TYPE (field),
+ TREE_VALUE (value), msg);
+ if (TREE_CODE (val) == ERROR_MARK)
+ is_erroneous = 1;
+ else
+ {
+ TREE_VALUE (value) = val;
+ TREE_CHAIN (value) = values;
+ TREE_PURPOSE (value) = field;
+ values = value;
+ if (TREE_CODE (val) == ERROR_MARK)
+ is_erroneous = 1;
+ else if (!TREE_CONSTANT (val))
+ is_constant = 0;
+ else if (!initializer_constant_valid_p (val,
+ TREE_TYPE (val)))
+ is_simple = 0;
+ }
+ }
+ else
+ {
+ pedwarn ("no initializer value for fixed field `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
+ }
+ }
+ else
+ {
+ tree variant;
+ tree selected_variant = NULL_TREE;
+ tree variant_values = NULL_TREE;
+
+ /* In a tagged variant structure mode, try to figure out
+ (from the fixed fields), which is the selected variant. */
+ if (TYPE_TAGFIELDS (TREE_TYPE (field)))
+ {
+ for (variant = TYPE_FIELDS (TREE_TYPE (field));
+ variant; variant = TREE_CHAIN (variant))
+ {
+ tree tag_labels = TYPE_TAG_VALUES (TREE_TYPE (variant));
+ tree tag_fields = TYPE_TAGFIELDS (TREE_TYPE (field));
+ if (DECL_NAME (variant) == ELSE_VARIANT_NAME)
+ {
+ selected_variant = variant;
+ break;
+ }
+ for (; tag_labels && tag_fields;
+ tag_labels = TREE_CHAIN (tag_labels),
+ tag_fields = TREE_CHAIN (tag_fields))
+ {
+ tree tag_value = values;
+ int found = 0;
+ tree tag_decl = TREE_VALUE (tag_fields);
+ tree tag_value_set = TREE_VALUE (tag_labels);
+ for ( ; tag_value; tag_value = TREE_CHAIN (tag_value))
+ {
+ if (TREE_PURPOSE (tag_value) == tag_decl)
+ {
+ tag_value = TREE_VALUE (tag_value);
+ break;
+ }
+ }
+ if (!tag_value || TREE_CODE (tag_value) != INTEGER_CST)
+ {
+ pedwarn ("non-constant value for tag field `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (tag_decl)));
+ goto get_values;
+ }
+
+ /* Check if the value of the tag (as given in a
+ previous field) matches the case label list. */
+ for (; tag_value_set;
+ tag_value_set = TREE_CHAIN (tag_value_set))
+ {
+ if (tree_int_cst_equal (TREE_VALUE (tag_value_set),
+ tag_value))
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ break;
+ }
+ if (!tag_fields)
+ {
+ selected_variant = variant;
+ break;
+ }
+ }
+ }
+ get_values:
+ for (variant = TYPE_FIELDS (TREE_TYPE (field));
+ variant; variant = TREE_CHAIN (variant))
+ {
+ tree vfield0 = TYPE_FIELDS (TREE_TYPE (variant));
+ tree vfield;
+ for (vfield = vfield0; vfield; vfield = TREE_CHAIN (vfield))
+ {
+ tree value = remove_tree_element (DECL_NAME (vfield),
+ &elements);
+
+ if (value)
+ labelled_elements++;
+ else if (variant == selected_variant
+ && elements && TREE_PURPOSE (elements) == NULL_TREE)
+ {
+ value = elements;
+ elements = TREE_CHAIN (elements);
+ unlabelled_elements++;
+ }
+
+ if (value)
+ {
+ if (selected_variant && selected_variant != variant)
+ {
+ error ("field `%s' in wrong variant",
+ IDENTIFIER_POINTER (DECL_NAME (vfield)));
+ is_erroneous = 1;
+ }
+ else
+ {
+ if (!selected_variant && vfield != vfield0)
+ pedwarn ("missing variant fields (at least `%s')",
+ IDENTIFIER_POINTER (DECL_NAME (vfield0)));
+ selected_variant = variant;
+ if (CH_COMPATIBLE (TREE_VALUE (value),
+ TREE_TYPE (vfield)))
+ {
+ tree val = convert (TREE_TYPE (vfield),
+ TREE_VALUE (value));
+ TREE_PURPOSE (value) = vfield;
+ TREE_VALUE (value) = val;
+ TREE_CHAIN (value) = variant_values;
+ variant_values = value;
+ if (TREE_CODE (val) == ERROR_MARK)
+ is_erroneous = 1;
+ else if (!TREE_CONSTANT (val))
+ is_constant = 0;
+ else if (!initializer_constant_valid_p
+ (val, TREE_TYPE (val)))
+ is_simple = 0;
+ }
+ else
+ {
+ is_erroneous = 1;
+ error ("bad initializer for field `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (vfield)));
+ }
+ }
+ }
+ else if (variant == selected_variant)
+ {
+ pedwarn ("no initializer value for variant field `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
+ }
+ }
+ }
+ if (selected_variant == NULL_TREE)
+ pedwarn ("no selected variant");
+ else
+ {
+ variant_values = build (CONSTRUCTOR,
+ TREE_TYPE (selected_variant),
+ NULL_TREE, nreverse (variant_values));
+ variant_values
+ = build (CONSTRUCTOR, TREE_TYPE (field), NULL_TREE,
+ build_tree_list (selected_variant, variant_values));
+ values = tree_cons (field, variant_values, values);
+ }
+ }
+ }
+
+ if (labelled_elements && unlabelled_elements)
+ pedwarn ("mixture of labelled and unlabelled tuple elements");
+
+ /* Check for unused initializer elements. */
+ unlabelled_elements = 0;
+ for ( ; elements != NULL_TREE; elements = TREE_CHAIN (elements))
+ {
+ if (TREE_PURPOSE (elements) == NULL_TREE)
+ unlabelled_elements++;
+ else
+ {
+ if (IDENTIFIER_POINTER (TREE_PURPOSE (elements)) == 0)
+ error ("probably not a structure tuple");
+ else
+ error ("excess initializer for field `%s'",
+ IDENTIFIER_POINTER (TREE_PURPOSE (elements)));
+ is_erroneous = 1;
+ }
+ }
+ if (unlabelled_elements)
+ {
+ error ("excess unnamed initializers");
+ is_erroneous = 1;
+ }
+
+ CONSTRUCTOR_ELTS (inits) = nreverse (values);
+ TREE_TYPE (inits) = type;
+ if (is_erroneous)
+ return error_mark_node;
+ if (is_constant)
+ TREE_CONSTANT (inits) = 1;
+ if (is_constant && is_simple)
+ TREE_STATIC (inits) = 1;
+ return inits;
+}
+
+/* Return a Chill representation of the INTEGER_CST VAL.
+ The result may be in a static buffer, */
+
+char *
+display_int_cst (val)
+ tree val;
+{
+ static char buffer[50];
+ HOST_WIDE_INT x;
+ tree fields;
+ if (TREE_CODE (val) != INTEGER_CST)
+ return "<not a constant>";
+
+ x = TREE_INT_CST_LOW (val);
+
+ switch (TREE_CODE (TREE_TYPE (val)))
+ {
+ case BOOLEAN_TYPE:
+ if (x == 0)
+ return "FALSE";
+ if (x == 1)
+ return "TRUE";
+ goto int_case;
+ case CHAR_TYPE:
+ if (x == '^')
+ strcpy (buffer, "'^^'");
+ else if (x == '\n')
+ strcpy (buffer, "'^J'");
+ else if (x < ' ' || x > '~')
+ sprintf (buffer, "'^(%u)'", x);
+ else
+ sprintf (buffer, "'%c'", x);
+ return buffer;
+ case ENUMERAL_TYPE:
+ for (fields = TYPE_VALUES (TREE_TYPE (val)); fields != NULL_TREE;
+ fields = TREE_CHAIN (fields))
+ {
+ if (tree_int_cst_equal (TREE_VALUE (fields), val))
+ return IDENTIFIER_POINTER (TREE_PURPOSE (fields));
+ }
+ goto int_case;
+ case POINTER_TYPE:
+ if (x == 0)
+ return "NULL";
+ goto int_case;
+ int_case:
+ default:
+ /* This code is derived from print-tree.c:print_code_brief. */
+ if (TREE_INT_CST_HIGH (val) == 0)
+ sprintf (buffer,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ "%1u",
+#else
+ "%1lu",
+#endif
+ x);
+ else if (TREE_INT_CST_HIGH (val) == -1 && TREE_INT_CST_LOW (val) != 0)
+ sprintf (buffer,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ "-%1u",
+#else
+ "-%1lu",
+#endif
+ -x);
+ else
+ sprintf (buffer,
+#if HOST_BITS_PER_WIDE_INT == 64
+#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+ "H'%lx%016lx",
+#else
+ "H'%x%016x",
+#endif
+#else
+#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+ "H'%lx%08lx",
+#else
+ "H'%x%08x",
+#endif
+#endif
+ TREE_INT_CST_HIGH (val), TREE_INT_CST_LOW (val));
+ return buffer;
+ }
+}
+
+static tree
+digest_array_tuple (type, init, allow_missing_elements)
+ tree type;
+ tree init;
+ int allow_missing_elements;
+{
+ tree element = CONSTRUCTOR_ELTS (init);
+ int is_constant = 1;
+ int is_simple = 1;
+ tree element_type = TREE_TYPE (type);
+ tree default_value = NULL_TREE;
+ tree element_list = NULL_TREE;
+ tree domain_min;
+ tree domain_max;
+ tree *ptr = &element_list;
+ int errors = 0;
+ int labelled_elements = 0;
+ int unlabelled_elements = 0;
+ tree first, last = NULL_TREE;
+
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+
+ domain_min = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
+ domain_max = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+
+ if (domain_min == NULL || TREE_CODE (domain_min) != INTEGER_CST)
+ {
+ error ("non-constant start index for tuple");
+ return error_mark_node;
+ }
+ if (TREE_CODE (domain_max) != INTEGER_CST)
+ is_constant = 0;
+
+ if (TREE_CODE (type) != ARRAY_TYPE)
+ abort ();
+
+ for ( ; element != NULL_TREE; element = TREE_CHAIN (element))
+ {
+ tree purpose = TREE_PURPOSE (element);
+ tree value = TREE_VALUE (element);
+
+ if (purpose == NULL_TREE)
+ {
+ if (last == NULL_TREE)
+ first = domain_min;
+ else
+ {
+ HOST_WIDE_INT new_lo, new_hi;
+ add_double (TREE_INT_CST_LOW (last), TREE_INT_CST_HIGH (last),
+ 1, 0,
+ &new_lo, &new_hi);
+ first = build_int_2 (new_lo, new_hi);
+ TREE_TYPE (first) = TYPE_DOMAIN (type);
+ }
+ last = first;
+ unlabelled_elements++;
+ }
+ else
+ {
+ labelled_elements++;
+ if (TREE_CODE (purpose) == INTEGER_CST)
+ first = last = purpose;
+ else if (TREE_CODE (purpose) == TYPE_DECL
+ && discrete_type_p (TREE_TYPE (purpose)))
+ {
+ first = TYPE_MIN_VALUE (TREE_TYPE (purpose));
+ last = TYPE_MAX_VALUE (TREE_TYPE (purpose));
+ }
+ else if (TREE_CODE (purpose) != RANGE_EXPR)
+ {
+ error ("invalid array tuple label");
+ errors++;
+ continue;
+ }
+ else if (TREE_OPERAND (purpose, 0) == NULL_TREE)
+ first = last = NULL_TREE; /* Default value. */
+ else
+ {
+ first = TREE_OPERAND (purpose, 0);
+ last = TREE_OPERAND (purpose, 1);
+ }
+ if ((first != NULL && TREE_CODE (first) != INTEGER_CST)
+ || (last != NULL && TREE_CODE (last) != INTEGER_CST))
+ {
+ error ("non-constant array tuple index range");
+ errors++;
+ }
+ }
+
+ if (! CH_COMPATIBLE (value, element_type))
+ {
+ char *err_val_name = first ? display_int_cst (first) : "(default)";
+ error ("incompatible array tuple element %s", err_val_name);
+ value = error_mark_node;
+ }
+ else
+ value = convert (element_type, value);
+ if (TREE_CODE (value) == ERROR_MARK)
+ errors++;
+ else if (!TREE_CONSTANT (value))
+ is_constant = 0;
+ else if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
+ is_simple = 0;
+
+ if (first == NULL_TREE)
+ {
+ if (default_value != NULL)
+ {
+ error ("multiple (*) or (ELSE) array tuple labels");
+ errors++;
+ }
+ default_value = value;
+ continue;
+ }
+
+ if (first != last && tree_int_cst_lt (last, first))
+ {
+ error ("empty range in array tuple");
+ errors++;
+ continue;
+ }
+
+ ptr = &element_list;
+
+#define MAYBE_RANGE_OP(PURPOSE, OPNO) \
+ (TREE_CODE (PURPOSE) == RANGE_EXPR ? TREE_OPERAND (PURPOSE, OPNO): PURPOSE)
+#define CONSTRUCTOR_ELT_LO(ELT) MAYBE_RANGE_OP (TREE_PURPOSE (ELT), 0)
+#define CONSTRUCTOR_ELT_HI(ELT) MAYBE_RANGE_OP (TREE_PURPOSE (ELT), 1)
+ while (*ptr && tree_int_cst_lt (last,
+ CONSTRUCTOR_ELT_LO (*ptr)))
+ ptr = &TREE_CHAIN (*ptr);
+ if (*ptr && ! tree_int_cst_lt (CONSTRUCTOR_ELT_HI (*ptr), first))
+ {
+ char *err_val_name = display_int_cst (first);
+ error ("array tuple has duplicate index %s", err_val_name);
+ errors++;
+ continue;
+ }
+ if ((ptr == &element_list && tree_int_cst_lt (domain_max, last))
+ || (*ptr == NULL_TREE && tree_int_cst_lt (first, domain_min)))
+ {
+ if (purpose)
+ error ("array tuple index out of range");
+ else if (errors == 0)
+ error ("too many array tuple values");
+ errors++;
+ continue;
+ }
+ if (! tree_int_cst_lt (first, last))
+ purpose = first;
+ else if (purpose == NULL_TREE || TREE_CODE (purpose) != RANGE_EXPR)
+ purpose = build_nt (RANGE_EXPR, first, last);
+ *ptr = tree_cons (purpose, value, *ptr);
+ }
+
+ element_list = nreverse (element_list);
+
+ /* For each missing element, set it to the default value,
+ if there is one. Otherwise, emit an error. */
+
+ if (errors == 0
+ && (!allow_missing_elements || default_value != NULL_TREE))
+ {
+ /* Iterate over each *gap* between specified elements/ranges. */
+ tree prev_elt;
+ if (element_list &&
+ tree_int_cst_equal (CONSTRUCTOR_ELT_LO (element_list), domain_min))
+ {
+ ptr = &TREE_CHAIN (element_list);
+ prev_elt = element_list;
+ }
+ else
+ {
+ prev_elt = NULL_TREE;
+ ptr = &element_list;
+ }
+ for (;;)
+ {
+ tree first, last;
+ /* Calculate the first element of the gap. */
+ if (prev_elt == NULL_TREE)
+ first = domain_min;
+ else
+ {
+ first = CONSTRUCTOR_ELT_HI (prev_elt);
+ if (tree_int_cst_equal (first, domain_max))
+ break; /* We're done. Avoid overflow below. */
+ first = copy_node (first);
+ add_double (TREE_INT_CST_LOW (first), TREE_INT_CST_HIGH (first),
+ 1, 0,
+ &TREE_INT_CST_LOW (first),
+ &TREE_INT_CST_HIGH (first));
+ }
+ /* Calculate the last element of the gap. */
+ if (*ptr)
+ {
+ /* Actually end up with correct type. */
+ last = size_binop (MINUS_EXPR,
+ CONSTRUCTOR_ELT_LO (*ptr),
+ integer_one_node);
+ }
+ else
+ last = domain_max;
+ if (TREE_CODE (last) == INTEGER_CST && tree_int_cst_lt (last, first))
+ ; /* Empty "gap" - no missing elements. */
+ else if (default_value)
+ {
+ tree purpose;
+ if (tree_int_cst_equal (first, last))
+ purpose = first;
+ else
+ purpose = build_nt (RANGE_EXPR, first, last);
+ *ptr = tree_cons (purpose, default_value, *ptr);
+ }
+ else
+ {
+ char *err_val_name = display_int_cst (first);
+ if (TREE_CODE (last) != INTEGER_CST)
+ error ("dynamic array tuple without (*) or (ELSE)");
+ else if (tree_int_cst_equal (first, last))
+ error ("missing array tuple element %s", err_val_name);
+ else
+ {
+ char *first_name = (char *)
+ xmalloc (strlen (err_val_name) + 1);
+ strcpy (first_name, err_val_name);
+ err_val_name = display_int_cst (last);
+ error ("missing array tuple elements %s : %s",
+ first_name, err_val_name);
+ free (first_name);
+ }
+ errors++;
+ }
+ if (*ptr == NULL_TREE)
+ break;
+ prev_elt = *ptr;
+ ptr = &TREE_CHAIN (*ptr);
+ }
+ }
+ if (errors)
+ return error_mark_node;
+
+ element = build (CONSTRUCTOR, type, NULL_TREE, element_list);
+ TREE_CONSTANT (element) = is_constant;
+ if (is_constant && is_simple)
+ TREE_STATIC (element) = 1;
+ if (labelled_elements && unlabelled_elements)
+ pedwarn ("mixture of labelled and unlabelled tuple elements");
+ return element;
+}
+
+/* This function is needed because no-op CHILL conversions are not fully
+ understood by the initialization machinery. This function should only
+ be called when a conversion truly is a no-op. */
+
+static tree
+convert1 (type, expr)
+ tree type, expr;
+{
+ int was_constant = TREE_CONSTANT (expr);
+ STRIP_NOPS (expr);
+ was_constant |= TREE_CONSTANT (expr);
+ expr = copy_node (expr);
+ TREE_TYPE (expr) = type;
+ if (TREE_CONSTANT (expr) != was_constant) abort ();
+ TREE_CONSTANT (expr) = was_constant;
+ return expr;
+}
+
+/* Create an expression whose value is that of EXPR,
+ converted to type TYPE. The TREE_TYPE of the value
+ is always TYPE. This function implements all reasonable
+ conversions; callers should filter out those that are
+ not permitted by the language being compiled.
+
+ In CHILL, we assume that the type is Compatible with the
+ Class of expr, and generally complain otherwise.
+ However, convert is more general (e.g. allows enum<->int
+ conversion), so there should probably be at least two routines.
+ Maybe add something like convert_for_assignment. FIXME. */
+
+tree
+convert (type, expr)
+ tree type, expr;
+{
+ register tree e = expr;
+ register enum chill_tree_code code;
+ char *errstr;
+ int type_varying;
+
+ if (e == NULL_TREE || TREE_CODE (e) == ERROR_MARK)
+ return error_mark_node;
+
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+
+ code = TREE_CODE (type);
+
+ if (type == TREE_TYPE (e))
+ return e;
+
+ if (TREE_TYPE (e) != NULL_TREE
+ && TREE_CODE (TREE_TYPE (e)) == REFERENCE_TYPE)
+ e = convert_from_reference (e);
+
+ /* Support for converting *to* a reference type is limited;
+ it is only here as a convenience for loc-identity declarations,
+ and loc parameters. */
+ if (code == REFERENCE_TYPE)
+ return convert_to_reference (type, e);
+
+ /* if expression was untyped because of its context (an if_expr or case_expr
+ in a tuple, perhaps) just apply the type */
+ if (TREE_TYPE (e) && TREE_CODE (TREE_TYPE (e)) == ERROR_MARK)
+ {
+ TREE_TYPE (e) = type;
+ return e;
+ }
+
+ /* Turn a NULL keyword into [0, 0] for an instance */
+ if (CH_IS_INSTANCE_MODE (type) && expr == null_pointer_node)
+ {
+ tree field0 = TYPE_FIELDS (type);
+ tree field1 = TREE_CHAIN (field0);
+ e = build (CONSTRUCTOR, type, NULL_TREE,
+ tree_cons (field0, integer_zero_node,
+ tree_cons (field1, integer_zero_node,
+ NULL_TREE)));
+ TREE_CONSTANT (e) = 1;
+ TREE_STATIC (e) = 1;
+ return e;
+ }
+
+ /* Turn a pointer into a function pointer for a procmode */
+ if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+ && expr == null_pointer_node)
+ return convert1 (type, expr);
+
+ /* turn function_decl expression into a pointer to
+ that function */
+ if (TREE_CODE (expr) == FUNCTION_DECL
+ && TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ {
+ e = build1 (ADDR_EXPR, type, expr);
+ TREE_CONSTANT (e) = 1;
+ return e;
+ }
+
+ if (TREE_TYPE (e) && TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE)
+ e = varying_to_slice (e);
+ type_varying = chill_varying_type_p (type);
+
+ /* Convert a char to a singleton string.
+ Needed for compatibility with 1984 version of Z.200. */
+ if (TREE_TYPE (e) && TREE_CODE (TREE_TYPE (e)) == CHAR_TYPE
+ && (CH_CHARS_ONE_P (type) || type_varying))
+ {
+ if (TREE_CODE (e) == INTEGER_CST)
+ {
+ char ch = TREE_INT_CST_LOW (e);
+ e = build_chill_string (1, &ch);
+ }
+ else
+ e = build (CONSTRUCTOR, string_one_type_node, NULL_TREE,
+ tree_cons (NULL_TREE, e, NULL_TREE));
+ }
+
+ /* Convert a Boolean to a singleton bitstring.
+ Needed for compatibility with 1984 version of Z.200. */
+ if (TREE_TYPE (e) && TREE_CODE (TREE_TYPE (e)) == BOOLEAN_TYPE
+ && (CH_BOOLS_ONE_P (type) || type_varying))
+ {
+ if (TREE_CODE (e) == INTEGER_CST)
+ e = integer_zerop (e) ? bit_zero_node : bit_one_node;
+ else
+ e = build (COND_EXPR, bitstring_one_type_node,
+ e, bit_one_node, bit_zero_node);
+ }
+
+ if (type_varying)
+ {
+ tree nentries;
+ tree field0 = TYPE_FIELDS (type);
+ tree field1 = TREE_CHAIN (field0);
+ tree orig_e = e;
+ tree target_array_type = TREE_TYPE (field1);
+ tree needed_padding;
+ tree padding_max_size = 0;
+ int orig_e_constant = TREE_CONSTANT (orig_e);
+ if (TREE_TYPE (e) != NULL_TREE
+ && TREE_CODE (TREE_TYPE (e)) == ARRAY_TYPE)
+ {
+ /* Note that array_type_nelts returns 1 less than the size. */
+ nentries = array_type_nelts (TREE_TYPE (e));
+ needed_padding = size_binop (MINUS_EXPR,
+ array_type_nelts (target_array_type),
+ nentries);
+ if (TREE_CODE (needed_padding) != INTEGER_CST)
+ {
+ padding_max_size = size_in_bytes (TREE_TYPE (e));
+ if (TREE_CODE (padding_max_size) != INTEGER_CST)
+ padding_max_size = TYPE_ARRAY_MAX_SIZE (TREE_TYPE (e));
+ }
+ nentries = size_binop (PLUS_EXPR, nentries, integer_one_node);
+ }
+ else if (TREE_CODE (e) == CONSTRUCTOR)
+ {
+ HOST_WIDE_INT init_cnt = 0;
+ tree chaser = CONSTRUCTOR_ELTS (e);
+ for ( ; chaser; chaser = TREE_CHAIN (chaser))
+ init_cnt++; /* count initializer elements */
+ nentries = build_int_2 (init_cnt, 0);
+ needed_padding = integer_zero_node;
+ if (TREE_TYPE (e) == NULL_TREE)
+ e = digest_array_tuple (TREE_TYPE (field1), e, 1);
+ orig_e_constant = TREE_CONSTANT (e);
+ }
+ else
+ {
+ error ("initializer is not an array or string mode");
+ return error_mark_node;
+ }
+#if 0
+ FIXME check that nentries will fit in type;
+#endif
+ if (!integer_zerop (needed_padding))
+ {
+ tree padding, padding_type, padding_range;
+ if (TREE_CODE (needed_padding) == INTEGER_CST
+ && (long)TREE_INT_CST_LOW (needed_padding) < 0)
+ {
+ error ("destination is too small");
+ return error_mark_node;
+ }
+ padding_range = build_chill_range_type (NULL_TREE, integer_one_node,
+ needed_padding);
+ padding_type
+ = build_simple_array_type (TREE_TYPE (target_array_type),
+ padding_range, NULL_TREE);
+ TYPE_ARRAY_MAX_SIZE (padding_type) = padding_max_size;
+ if (CH_CHARS_TYPE_P (target_array_type))
+ MARK_AS_STRING_TYPE (padding_type);
+ padding = build (UNDEFINED_EXPR, padding_type);
+ if (TREE_CONSTANT (e))
+ e = build_chill_binary_op (CONCAT_EXPR, e, padding);
+ else
+ e = build (CONCAT_EXPR, target_array_type, e, padding);
+ }
+ e = convert (TREE_TYPE (field1), e);
+ /* We build this constructor by hand (rather than going through
+ digest_structure_tuple), to avoid some type-checking problem.
+ E.g. type may have non-null novelty, but its field1 will
+ have non-novelty. */
+ e = build (CONSTRUCTOR, type, NULL_TREE,
+ tree_cons (field0, nentries,
+ build_tree_list (field1, e)));
+ /* following was wrong, cause orig_e never will be TREE_CONSTANT. e
+ may become constant after digest_array_tuple. */
+ if (TREE_CONSTANT (nentries) && orig_e_constant) /* TREE_CONSTANT (orig_e)) */
+ {
+ TREE_CONSTANT (e) = 1;
+ if (TREE_STATIC (nentries) && TREE_STATIC (orig_e))
+ TREE_STATIC (e) = 1;
+ }
+ }
+ if (TREE_TYPE (e) == NULL_TREE)
+ {
+ if (TREE_CODE (e) == CONSTRUCTOR)
+ {
+ if (TREE_CODE (type) == SET_TYPE)
+ return digest_powerset_tuple (type, e);
+ if (TREE_CODE (type) == RECORD_TYPE)
+ return digest_structure_tuple (type, e);
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return digest_array_tuple (type, e, 0);
+ fatal ("internal error - bad CONSTRUCTOR passed to convert");
+ }
+ else if (TREE_CODE (e) == COND_EXPR)
+ e = build (COND_EXPR, type,
+ TREE_OPERAND (e, 0),
+ convert (type, TREE_OPERAND (e, 1)),
+ convert (type, TREE_OPERAND (e, 2)));
+ else if (TREE_CODE (e) == CASE_EXPR)
+ TREE_TYPE (e) = type;
+ else
+ {
+ error ("internal error: unknown type of expression");
+ return error_mark_node;
+ }
+ }
+
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e))
+ || (CH_NOVELTY (type) != NULL_TREE
+ && CH_NOVELTY (type) == CH_NOVELTY (TREE_TYPE (e))))
+ return convert1 (type, e);
+
+ if (TREE_CODE (TREE_TYPE (e)) == VOID_TYPE)
+ {
+ error ("void value not ignored as it ought to be");
+ return error_mark_node;
+ }
+ if (code == VOID_TYPE)
+ return build1 (CONVERT_EXPR, type, e);
+
+ if (code == SET_TYPE)
+ return convert1 (type, e);
+
+ if (code == INTEGER_TYPE || code == ENUMERAL_TYPE)
+ {
+ if (flag_old_strings)
+ {
+ if (CH_CHARS_ONE_P (TREE_TYPE (e)))
+ e = convert_to_char (char_type_node, e);
+ else if (CH_BOOLS_ONE_P (TREE_TYPE (e)))
+ e = convert_to_boolean (boolean_type_node, e);
+ }
+ return fold (convert_to_integer (type, e));
+ }
+ if (code == POINTER_TYPE)
+ return fold (convert_to_pointer (type, e));
+ if (code == REAL_TYPE)
+ return fold (convert_to_real (type, e));
+ if (code == BOOLEAN_TYPE)
+ return fold (convert_to_boolean (type, e));
+ if (code == CHAR_TYPE)
+ return fold (convert_to_char (type, e));
+
+ if (code == ARRAY_TYPE && TYPE_MODE (type) != TYPE_MODE (TREE_TYPE (e)))
+ {
+ /* The mode of the expression is different from that of the type.
+ Earlier checks should have tested against different lengths.
+ But even if the lengths are the same, it is possible that one
+ type is a static type (and hence could be say SImode), while the
+ other type is dynamic type (and hence is BLKmode).
+ This causes problems when emitting instructions. */
+ tree ee = build1 (INDIRECT_REF, type,
+ build1 (NOP_EXPR, build_pointer_type (type),
+ build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (e)),
+ e)));
+ TREE_READONLY (ee) = TYPE_READONLY (type);
+ return ee;
+ }
+
+ /* The default! */
+ return convert1 (type, e);
+}
+
+/* Return an expression whose value is EXPR, but whose class is CLASS. */
+
+tree
+convert_to_class (class, expr)
+ struct ch_class class;
+ tree expr;
+{
+ switch (class.kind)
+ {
+ case CH_NULL_CLASS:
+ case CH_ALL_CLASS:
+ return expr;
+ case CH_DERIVED_CLASS:
+ if (TREE_TYPE (expr) != class.mode)
+ expr = convert (class.mode, expr);
+ if (!CH_DERIVED_FLAG (expr))
+ {
+ expr = copy_node (expr);
+ CH_DERIVED_FLAG (expr) = 1;
+ }
+ return expr;
+ case CH_VALUE_CLASS:
+ case CH_REFERENCE_CLASS:
+ if (TREE_TYPE (expr) != class.mode)
+ expr = convert (class.mode, expr);
+ if (CH_DERIVED_FLAG (expr))
+ {
+ expr = copy_node (expr);
+ CH_DERIVED_FLAG (expr) = 0;
+ }
+ return expr;
+ }
+ return expr;
+}
diff --git a/gcc/ch/decl.c b/gcc/ch/decl.c
new file mode 100644
index 0000000..57842b0
--- /dev/null
+++ b/gcc/ch/decl.c
@@ -0,0 +1,5176 @@
+/* Process declarations and variables for GNU CHILL compiler.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+
+ This file is part of GNU CC.
+
+ GNU CC 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 2, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* Process declarations and symbol lookup for CHILL front end.
+ Also constructs types; the standard scalar types at initialization,
+ and structure, union, array and enum types when they are declared. */
+
+/* NOTES on Chill name resolution
+
+ Chill allows one to refer to an identifier that is declared later in
+ the same Group. Hence, a single pass over the code (as in C) is
+ insufficient.
+
+ This implementation uses two complete passes over the source code,
+ plus some extra passes over internal data structures.
+
+ Loosely, during pass 1, a 'scope' object is created for each Chill
+ reach. Each scope object contains a list of 'decl' objects,
+ one for each 'defining occurrence' in the reach. (This list
+ is in the 'remembered_decls' field of each scope.)
+ The scopes and their decls are replayed in pass 2: As each reach
+ is entered, the decls saved from pass 1 are made visible.
+
+ There are some exceptions. Declarations that cannot be referenced
+ before their declaration (i.e. whose defining occurrence precede
+ their reach), can be deferred to pass 2. These include formal
+ parameter declarations, and names defined in a DO action.
+
+ During pass 2, as each scope is entered, we must make visible all
+ the declarations defined in the scope, before we generate any code.
+ We must also simplify the declarations from pass 1: For example
+ a VAR_DECL may have a array type whose bounds are expressions;
+ these need to be folded. But of course the expressions may contain
+ identifiers that may be defined later in the scope - or even in
+ a different module.
+
+ The "satisfy" process has two main phases:
+
+ 1: Binding. Each identifier *referenced* in a declaration (i.e. in
+ a mode or the RHS of a synonum declaration) must be bound to its
+ defining occurrence. This may need to be linking via
+ grants and/or seizes (which are represented by ALIAS_DECLs).
+ A further complication is handling implied name strings.
+
+ 2: Layout. Each CONST_DECL or TYPE_DECL *referenced* in a declaration
+ must than be replaced by its value (or type). Constants must be
+ folded. Types and declarstions must be laid out. DECL_RTL must be set.
+ While doing this, we must watch out for circular dependencies.
+
+ If a scope contains nested modulions, then the Binding phase must be
+ done for each nested module (recursively) before the Layout phase
+ can start for that scope. As an example of why this is needed, consider:
+
+ M1: MODULE
+ DCL a ARRAY [1:y] int; -- This should have 7 elements.
+ SYN x = 5;
+ SEIZE y;
+ END M1;
+ M2: MODULE
+ SYN x = 2;
+ SYN y = x + 5;
+ GRANT y;
+ END M2;
+
+ Here, the 'x' in "x + 5" must be Bound to the 'x' in module M2.
+ This must be done before we can Layout a.
+ The reason this is an issue is that we do *not* have a lookup
+ (or hash) table per scope (or module). Instead we have a single
+ global table we we keep adding and removing bindings from.
+ (This is both for speed, and because of gcc history.)
+
+ Note that a SEIZE generates a declaration in the current scope,
+ linked to something in the surrounding scope. Determining (binding)
+ the link must be done in pass 2. On the other hand, a GRANT
+ generates a declaration in the surrounding scope, linked to
+ something in the current scope. This linkage is Bound in pass 1.
+
+ The sequence for the above example is:
+ - Enter the declarations of M1 (i.e. {a, x, y}) into the hash table.
+ - For each of {a, x, y}, examine dependent expression (the
+ rhs of x, the bounds of a), and Bind any identifiers to
+ the current declarations (as found in the hash table). Specifically,
+ the 'y' in the array bounds of 'a' is bound to the 'y' declared by
+ the SEIZE declaration. Also, 'y' is Bound to the implicit
+ declaration in the global scope (generated from the GRANT in M2).
+ - Remove the bindings for M1 (i.e. {a, x, y}) from the hash table.
+ - Enter the declarations of M2 (i.e. {x, y}) into the hash table.
+ - For each of {x, y} examine the dependent expressions (the rhs of
+ x and y), and Bind any identifiers to their current declarartions
+ (in this case the 'x' in "x + 5" is bound to the 'x' that is 2.
+ - Remove the bindings for M2 (i.e. {x, y}) from the hash table.
+ - Perform Layout for M1: This requires the size of a, which
+ requires the value of y. The 'y' is Bound to the implicit
+ declaration in the global scope, which is Bound to the declaration
+ of y in M2. We now require the value of this 'y', which is "x + 5"
+ where x is bound to the x in M2 (thanks to our previous Binding
+ phase). So we get that the value of y is 7.
+ - Perform layout of M2. This implies calculating (constant folding)
+ the value of y - but we already did that, so we're done.
+
+ An example illustating the problem with implied names:
+
+ M1: MODULE
+ SEIZE y;
+ use(e); -- e is implied by y.
+ END M1;
+ M2: MODULE
+ GRANT y;
+ SYNMODE y = x;
+ SEIZE x;
+ END M2;
+ M3: MODULE
+ GRANT x;
+ SYNMODE x = SET (e);
+ END M3;
+
+ This implies that determining the implied name e in M1
+ must be done after Binding of y to x in M2.
+
+ Yet another nasty:
+ M1: MODULE
+ SEIZE v;
+ DCL a ARRAY(v:v) int;
+ END M1;
+ M2: MODULE
+ GRANT v;
+ SEIZE x;
+ SYN v x = e;
+ END M2;
+ M3: MODULE
+ GRANT x;
+ SYNMODE x = SET(e);
+ END M3;
+
+ This one implies that determining the implied name e in M2,
+ must be done before Layout of a in M1.
+
+ These two examples togother indicate the determining implieed
+ names requries yet another phase.
+ - Bind strong names in M1.
+ - Bind strong names in M2.
+ - Bind strong names in M3.
+ - Determine weak names implied by SEIZEs in M1.
+ - Bind the weak names in M1.
+ - Determine weak names implied by SEIZEs in M2.
+ - Bind the weak names in M2.
+ - Determine weak names implied by SEIZEs in M3.
+ - Bind the weak names in M3.
+ - Layout M1.
+ - Layout M2.
+ - Layout M3.
+
+ We must bind the strong names in every module before we can determine
+ weak names in any module (because of seized/granted synmode/newmodes).
+ We must bind the weak names in every module before we can do Layout
+ in any module.
+
+ Sigh.
+
+ */
+
+/* ??? not all decl nodes are given the most useful possible
+ line numbers. For example, the CONST_DECLs for enum values. */
+
+#include <stdio.h>
+#include "config.h"
+#include "tree.h"
+#include "flags.h"
+#include "ch-tree.h"
+#include "lex.h"
+#include "obstack.h"
+#include "input.h"
+#include "rtl.h"
+
+#define IS_UNKNOWN_TYPE(type) (TYPE_SIZE(type)==0)
+#define BUILTIN_NESTING_LEVEL (-1)
+
+/* For backward compatibility, we define Chill INT to be the same
+ as SHORT (i.e. 16 bits), at least if C INT is the same as LONG.
+ This is a lose. */
+#define CHILL_INT_IS_SHORT (INT_TYPE_SIZE==LONG_TYPE_SIZE)
+
+extern int ignore_case;
+extern tree process_type;
+extern struct obstack *saveable_obstack;
+extern tree signal_code;
+extern int special_UC;
+
+extern void tasking_init PROTO((void));
+extern void error PROTO((char *, ...));
+extern void error_with_decl PROTO((tree, char *, ...));
+extern void expand_decl PROTO((tree));
+static tree get_next_decl PROTO((void));
+extern tree get_parm_decls PROTO((void));
+extern void end_temporary_allocation PROTO((void));
+extern void indent_to PROTO((FILE *, int));
+#ifdef RTX_CODE
+extern rtx label_rtx PROTO((tree));
+#endif
+extern tree lookup_name_for_seizing PROTO((tree));
+extern tree lookup_name_current_level PROTO((tree));
+extern int operand_equal_p PROTO((tree, tree, int));
+extern void pedwarn_with_decl PROTO((tree, char *, ...));
+extern void print_node PROTO((FILE *, char *, tree, int));
+extern void push_granted PROTO((tree, tree));
+extern void push_obstacks PROTO((struct obstack *, struct obstack *));
+extern void rest_of_decl_compilation PROTO((tree, char *, int, int));
+extern void sorry PROTO((char *, ...));
+static void save_decl PROTO((tree));
+extern void start_identifier_warnings PROTO((void));
+extern void temporary_allocation PROTO((void));
+extern void warning PROTO((char *, ...));
+
+extern struct obstack permanent_obstack;
+extern int in_pseudo_module;
+
+struct module *current_module = NULL;
+struct module *first_module = NULL;
+struct module **next_module = &first_module;
+
+extern int in_pseudo_module;
+
+int module_number = 0;
+
+/* This is only used internally (by signed_type). */
+
+tree signed_boolean_type_node;
+
+tree global_function_decl = NULL_TREE;
+
+/* This is a temportary used by RESULT to store its value.
+ Note we cannot directly use DECL_RESULT for two reasons:
+ a) If DECL_RESULT is a register, it may get clobbered by a
+ subsequent function call; and
+ b) if the function returns a struct, we might (visibly) modify the
+ destination before we're supposed to. */
+tree chill_result_decl;
+
+int result_never_set;
+
+/* forward declarations */
+static void pushdecllist PROTO((tree, int));
+static int init_nonvalue_struct PROTO((tree));
+static int init_nonvalue_array PROTO((tree));
+
+int current_nesting_level = BUILTIN_NESTING_LEVEL;
+int current_module_nesting_level = 0;
+
+/* Lots of declarations copied from c-decl.c. */
+/* ??? not all decl nodes are given the most useful possible
+ line numbers. For example, the CONST_DECLs for enum values. */
+
+#if 0
+/* In grokdeclarator, distinguish syntactic contexts of declarators. */
+enum decl_context
+{ NORMAL, /* Ordinary declaration */
+ FUNCDEF, /* Function definition */
+ PARM, /* Declaration of parm before function body */
+ FIELD, /* Declaration inside struct or union */
+ BITFIELD, /* Likewise but with specified width */
+ TYPENAME}; /* Typename (inside cast or sizeof) */
+#endif
+
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+
+#ifndef SHORT_TYPE_SIZE
+#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
+#endif
+
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_LONG_TYPE_SIZE
+#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef WCHAR_UNSIGNED
+#define WCHAR_UNSIGNED 0
+#endif
+
+#ifndef FLOAT_TYPE_SIZE
+#define FLOAT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+/* We let tm.h override the types used here, to handle trivial differences
+ such as the choice of unsigned int or long unsigned int for size_t.
+ When machines start needing nontrivial differences in the size type,
+ it would be best to do something here to figure out automatically
+ from other information what type to use. */
+
+#ifndef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "long int"
+#endif
+
+#ifndef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+#endif
+
+/* a node which has tree code ERROR_MARK, and whose type is itself.
+ All erroneous expressions are replaced with this node. All functions
+ that accept nodes as arguments should avoid generating error messages
+ if this node is one of the arguments, since it is undesirable to get
+ multiple error messages from one error in the input. */
+
+tree error_mark_node;
+
+/* INTEGER_TYPE and REAL_TYPE nodes for the standard data types */
+
+tree short_integer_type_node;
+tree integer_type_node;
+tree long_integer_type_node;
+tree long_long_integer_type_node;
+
+tree short_unsigned_type_node;
+tree unsigned_type_node;
+tree long_unsigned_type_node;
+tree long_long_unsigned_type_node;
+
+tree ptrdiff_type_node;
+
+tree unsigned_char_type_node;
+tree signed_char_type_node;
+tree char_type_node;
+tree wchar_type_node;
+tree signed_wchar_type_node;
+tree unsigned_wchar_type_node;
+
+tree float_type_node;
+tree double_type_node;
+tree long_double_type_node;
+
+tree complex_integer_type_node;
+tree complex_float_type_node;
+tree complex_double_type_node;
+tree complex_long_double_type_node;
+
+tree intQI_type_node;
+tree intHI_type_node;
+tree intSI_type_node;
+tree intDI_type_node;
+tree intTI_type_node;
+
+tree unsigned_intQI_type_node;
+tree unsigned_intHI_type_node;
+tree unsigned_intSI_type_node;
+tree unsigned_intDI_type_node;
+tree unsigned_intTI_type_node;
+
+/* a VOID_TYPE node. */
+
+tree void_type_node;
+tree void_list_node;
+
+/* Nodes for types `void *' and `const void *'. */
+tree ptr_type_node, const_ptr_type_node;
+
+/* type of initializer structure, which points to
+ a module's module-level code, and to the next
+ such structure. */
+tree initializer_type;
+
+/* type of a CHILL predefined value builtin routine */
+tree chill_predefined_function_type;
+
+/* type `int ()' -- used for implicit declaration of functions. */
+
+tree default_function_type;
+
+#if 0
+/* function types `double (double)' and `double (double, double)', etc. */
+
+tree double_ftype_double, double_ftype_double_double;
+tree int_ftype_int, long_ftype_long;
+
+/* Function type `void (void *, void *, int)' and similar ones */
+
+tree void_ftype_ptr_ptr_int, int_ftype_ptr_ptr_int, void_ftype_ptr_int_int;
+
+/* Function type `char *(char *, char *)' and similar ones */
+tree string_ftype_ptr_ptr, int_ftype_string_string;
+
+/* Function type `int (const void *, const void *, size_t)' */
+tree int_ftype_cptr_cptr_sizet;
+#endif
+
+char **boolean_code_name;
+
+/* Two expressions that are constants with value zero.
+ The first is of type `int', the second of type `void *'. */
+
+tree integer_zero_node;
+tree null_pointer_node;
+
+/* A node for the integer constant 1. */
+tree integer_one_node;
+
+/* A node for the integer constant -1. */
+tree integer_minus_one_node;
+
+/* Nodes for boolean constants TRUE and FALSE. */
+tree boolean_true_node, boolean_false_node;
+
+tree string_one_type_node; /* The type of CHARS(1). */
+tree bitstring_one_type_node; /* The type of BOOLS(1). */
+tree bit_zero_node; /* B'0' */
+tree bit_one_node; /* B'1' */
+
+/* Nonzero if we have seen an invalid cross reference
+ to a struct, union, or enum, but not yet printed the message. */
+
+tree pending_invalid_xref;
+/* File and line to appear in the eventual error message. */
+char *pending_invalid_xref_file;
+int pending_invalid_xref_line;
+
+/* After parsing the declarator that starts a function definition,
+ `start_function' puts here the list of parameter names or chain of decls.
+ `store_parm_decls' finds it here. */
+
+static tree current_function_parms;
+
+/* Nonzero when store_parm_decls is called indicates a varargs function.
+ Value not meaningful after store_parm_decls. */
+
+static int c_function_varargs;
+
+/* The FUNCTION_DECL for the function currently being compiled,
+ or 0 if between functions. */
+tree current_function_decl;
+
+/* These are irrelevant for Chill, but are referenced from from c-typeck.c. */
+int warn_format;
+int warn_traditional;
+int warn_bad_function_cast;
+
+/* Identifiers that hold VAR_LENGTH and VAR_DATA. */
+tree var_length_id, var_data_id;
+
+tree case_else_node;
+
+/* For each binding contour we allocate a scope structure
+ * which records the names defined in that contour.
+ * Contours include:
+ * 0) the global one
+ * 1) one for each function definition,
+ * where internal declarations of the parameters appear.
+ * 2) one for each compound statement,
+ * to record its declarations.
+ *
+ * The current meaning of a name can be found by searching the levels from
+ * the current one out to the global one.
+ */
+
+/* To communicate between pass 1 and 2, we maintain a list of "scopes".
+ Each scope corrresponds to a nested source scope/block that contain
+ that can contain declarations. The TREE_VALUE of the scope points
+ to the list of declarations declared in that scope.
+ The TREE_PURPOSE of the scope points to the surrounding scope.
+ (We may need to handle nested modules later. FIXME)
+ The TREE_CHAIN field contains a list of scope as they are seen
+ in chronological order. (Reverse order during first pass,
+ but it is reverse before pass 2.) */
+
+struct scope
+{
+ /* The enclosing scope. */
+ struct scope *enclosing;
+
+ /* The next scope, in chronlogical order. */
+ struct scope *next;
+
+ /* A chain of DECLs constructed using save_decl during pass 1. */
+ tree remembered_decls;
+
+ /* A chain of _DECL nodes for all variables, constants, functions,
+ and typedef types belong to this scope. */
+ tree decls;
+
+ /* List of declarations that have been granted into this scope. */
+ tree granted_decls;
+
+ /* List of implied (weak) names. */
+ tree weak_decls;
+
+ /* For each level, a list of shadowed outer-level local definitions
+ to be restored when this level is popped.
+ Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and
+ whose TREE_VALUE is its old definition (a kind of ..._DECL node). */
+ tree shadowed;
+
+ /* For each level (except not the global one),
+ a chain of BLOCK nodes for all the levels
+ that were entered and exited one level down. */
+ tree blocks;
+
+ /* The BLOCK node for this level, if one has been preallocated.
+ If 0, the BLOCK is allocated (if needed) when the level is popped. */
+ tree this_block;
+
+ /* The binding level which this one is contained in (inherits from). */
+ struct scope *level_chain;
+
+ /* Nonzero for a level that corresponds to a module. */
+ char module_flag;
+
+ /* Zero means called from backend code. */
+ char two_pass;
+
+ /* The modules that are directly enclosed by this scope
+ are chained together. */
+ struct scope* first_child_module;
+ struct scope** tail_child_module;
+ struct scope* next_sibling_module;
+};
+
+/* The outermost binding level, for pre-defined (builtin) names. */
+
+static struct scope builtin_scope = { NULL, NULL, NULL_TREE};
+
+struct scope *global_scope;
+
+/* The binding level currently in effect. */
+
+static struct scope *current_scope = &builtin_scope;
+
+/* The most recently seen scope. */
+struct scope *last_scope = &builtin_scope;
+
+/* Binding level structures are initialized by copying this one. */
+
+static struct scope clear_scope
+ = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0};
+
+/* Chain of decls accessible through IDENTIFIER_OUTER_VALUE.
+ Decls with the same DECL_NAME are adjacent in the chain. */
+
+static tree outer_decls = NULL_TREE;
+
+/* Forward declarations. */
+
+tree pushdecl ();
+tree builtin_function ();
+
+tree lookup_name_current_level ();
+static void layout_array_type ();
+
+/* C-specific option variables. */
+
+/* Nonzero means allow type mismatches in conditional expressions;
+ just make their values `void'. */
+
+int flag_cond_mismatch;
+
+/* Nonzero means give `double' the same size as `float'. */
+
+int flag_short_double;
+
+/* Nonzero means don't recognize the keyword `asm'. */
+
+int flag_no_asm;
+
+/* Nonzero means don't recognize any builtin functions. */
+
+int flag_no_builtin;
+
+/* Nonzero means don't recognize the non-ANSI builtin functions.
+ -ansi sets this. */
+
+int flag_no_nonansi_builtin;
+
+/* Nonzero means do some things the same way PCC does. */
+
+int flag_traditional;
+
+/* Nonzero means to allow single precision math even if we're generally
+ being traditional. */
+int flag_allow_single_precision = 0;
+
+/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */
+
+int flag_signed_bitfields = 1;
+int explicit_flag_signed_bitfields = 0;
+
+/* Nonzero means handle `#ident' directives. 0 means ignore them. */
+
+int flag_no_ident = 0;
+
+/* Nonzero means warn about implicit declarations. */
+
+int warn_implicit;
+
+/* Nonzero means give string constants the type `const char *'
+ to get extra warnings from them. These warnings will be too numerous
+ to be useful, except in thoroughly ANSIfied programs. */
+
+int warn_write_strings;
+
+/* Nonzero means warn about pointer casts that can drop a type qualifier
+ from the pointer target type. */
+
+int warn_cast_qual;
+
+/* Nonzero means warn about sizeof(function) or addition/subtraction
+ of function pointers. */
+
+int warn_pointer_arith;
+
+/* Nonzero means warn for non-prototype function decls
+ or non-prototyped defs without previous prototype. */
+
+int warn_strict_prototypes;
+
+/* Nonzero means warn for any global function def
+ without separate previous prototype decl. */
+
+int warn_missing_prototypes;
+
+/* Nonzero means warn about multiple (redundant) decls for the same single
+ variable or function. */
+
+int warn_redundant_decls = 0;
+
+/* Nonzero means warn about extern declarations of objects not at
+ file-scope level and about *all* declarations of functions (whether
+ extern or static) not at file-scope level. Note that we exclude
+ implicit function declarations. To get warnings about those, use
+ -Wimplicit. */
+
+int warn_nested_externs = 0;
+
+/* Warn about a subscript that has type char. */
+
+int warn_char_subscripts = 0;
+
+/* Warn if a type conversion is done that might have confusing results. */
+
+int warn_conversion;
+
+/* Warn if adding () is suggested. */
+
+int warn_parentheses;
+
+/* Warn if initializer is not completely bracketed. */
+
+int warn_missing_braces;
+
+/* Define the special tree codes that we use. */
+
+/* Table indexed by tree code giving a string containing a character
+ classifying the tree code. Possibilities are
+ t, d, s, c, r, <, 1 and 2. See ch-tree.def for details. */
+
+#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
+
+ char chill_tree_code_type[] = {
+ 'x',
+#include "ch-tree.def"
+ };
+#undef DEFTREECODE
+
+/* Table indexed by tree code giving number of expression
+ operands beyond the fixed part of the node structure.
+ Not used for types or decls. */
+
+#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
+
+int chill_tree_code_length[] = {
+ 0,
+#include "ch-tree.def"
+ };
+#undef DEFTREECODE
+
+
+/* Names of tree components.
+ Used for printing out the tree and error messages. */
+#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
+
+char *chill_tree_code_name[] = {
+ "@@dummy",
+#include "ch-tree.def"
+ };
+#undef DEFTREECODE
+
+/* Nonzero means `$' can be in an identifier.
+ See cccp.c for reasons why this breaks some obscure ANSI C programs. */
+
+#ifndef DOLLARS_IN_IDENTIFIERS
+#define DOLLARS_IN_IDENTIFIERS 0
+#endif
+int dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 1;
+
+/* An identifier that is used internally to indicate
+ an "ALL" prefix for granting or seizing.
+ We use "*" rather than the external name "ALL", partly for convenience,
+ and partly to avoid case senstivity problems. */
+
+tree ALL_POSTFIX;
+
+void
+allocate_lang_decl (t)
+ tree t;
+{
+ /* Nothing needed */
+}
+
+void
+copy_lang_decl (node)
+ tree node;
+{
+ /* Nothing needed */
+}
+
+tree
+build_lang_decl (code, name, type)
+ enum chill_tree_code code;
+ tree name;
+ tree type;
+{
+ return build_decl (code, name, type);
+}
+
+/* Decode the string P as a language-specific option for C.
+ Return the number of strings consumed for a valid option.
+ Return 0 for an invalid option. */
+
+int
+c_decode_option (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *p = argv[0];
+ if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional"))
+ {
+ flag_traditional = 1;
+ flag_writable_strings = 1;
+#if DOLLARS_IN_IDENTIFIERS > 0
+ dollars_in_ident = 1;
+#endif
+ }
+ else if (!strcmp (p, "-fnotraditional") || !strcmp (p, "-fno-traditional"))
+ {
+ flag_traditional = 0;
+ flag_writable_strings = 0;
+ dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 1;
+ }
+ else if (!strcmp (p, "-fsigned-char"))
+ flag_signed_char = 1;
+ else if (!strcmp (p, "-funsigned-char"))
+ flag_signed_char = 0;
+ else if (!strcmp (p, "-fno-signed-char"))
+ flag_signed_char = 0;
+ else if (!strcmp (p, "-fno-unsigned-char"))
+ flag_signed_char = 1;
+ else if (!strcmp (p, "-fsigned-bitfields")
+ || !strcmp (p, "-fno-unsigned-bitfields"))
+ {
+ flag_signed_bitfields = 1;
+ explicit_flag_signed_bitfields = 1;
+ }
+ else if (!strcmp (p, "-funsigned-bitfields")
+ || !strcmp (p, "-fno-signed-bitfields"))
+ {
+ flag_signed_bitfields = 0;
+ explicit_flag_signed_bitfields = 1;
+ }
+ else if (!strcmp (p, "-fshort-enums"))
+ flag_short_enums = 1;
+ else if (!strcmp (p, "-fno-short-enums"))
+ flag_short_enums = 0;
+ else if (!strcmp (p, "-fcond-mismatch"))
+ flag_cond_mismatch = 1;
+ else if (!strcmp (p, "-fno-cond-mismatch"))
+ flag_cond_mismatch = 0;
+ else if (!strcmp (p, "-fshort-double"))
+ flag_short_double = 1;
+ else if (!strcmp (p, "-fno-short-double"))
+ flag_short_double = 0;
+ else if (!strcmp (p, "-fasm"))
+ flag_no_asm = 0;
+ else if (!strcmp (p, "-fno-asm"))
+ flag_no_asm = 1;
+ else if (!strcmp (p, "-fbuiltin"))
+ flag_no_builtin = 0;
+ else if (!strcmp (p, "-fno-builtin"))
+ flag_no_builtin = 1;
+ else if (!strcmp (p, "-fno-ident"))
+ flag_no_ident = 1;
+ else if (!strcmp (p, "-fident"))
+ flag_no_ident = 0;
+ else if (!strcmp (p, "-ansi"))
+ flag_no_asm = 1, flag_no_nonansi_builtin = 1, dollars_in_ident = 0;
+ else if (!strcmp (p, "-Wimplicit"))
+ warn_implicit = 1;
+ else if (!strcmp (p, "-Wno-implicit"))
+ warn_implicit = 0;
+ else if (!strcmp (p, "-Wwrite-strings"))
+ warn_write_strings = 1;
+ else if (!strcmp (p, "-Wno-write-strings"))
+ warn_write_strings = 0;
+ else if (!strcmp (p, "-Wcast-qual"))
+ warn_cast_qual = 1;
+ else if (!strcmp (p, "-Wno-cast-qual"))
+ warn_cast_qual = 0;
+ else if (!strcmp (p, "-Wpointer-arith"))
+ warn_pointer_arith = 1;
+ else if (!strcmp (p, "-Wno-pointer-arith"))
+ warn_pointer_arith = 0;
+ else if (!strcmp (p, "-Wstrict-prototypes"))
+ warn_strict_prototypes = 1;
+ else if (!strcmp (p, "-Wno-strict-prototypes"))
+ warn_strict_prototypes = 0;
+ else if (!strcmp (p, "-Wmissing-prototypes"))
+ warn_missing_prototypes = 1;
+ else if (!strcmp (p, "-Wno-missing-prototypes"))
+ warn_missing_prototypes = 0;
+ else if (!strcmp (p, "-Wredundant-decls"))
+ warn_redundant_decls = 1;
+ else if (!strcmp (p, "-Wno-redundant-decls"))
+ warn_redundant_decls = 0;
+ else if (!strcmp (p, "-Wnested-externs"))
+ warn_nested_externs = 1;
+ else if (!strcmp (p, "-Wno-nested-externs"))
+ warn_nested_externs = 0;
+ else if (!strcmp (p, "-Wchar-subscripts"))
+ warn_char_subscripts = 1;
+ else if (!strcmp (p, "-Wno-char-subscripts"))
+ warn_char_subscripts = 0;
+ else if (!strcmp (p, "-Wconversion"))
+ warn_conversion = 1;
+ else if (!strcmp (p, "-Wno-conversion"))
+ warn_conversion = 0;
+ else if (!strcmp (p, "-Wparentheses"))
+ warn_parentheses = 1;
+ else if (!strcmp (p, "-Wno-parentheses"))
+ warn_parentheses = 0;
+ else if (!strcmp (p, "-Wreturn-type"))
+ warn_return_type = 1;
+ else if (!strcmp (p, "-Wno-return-type"))
+ warn_return_type = 0;
+ else if (!strcmp (p, "-Wcomment"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wno-comment"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wcomments"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wno-comments"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wtrigraphs"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wno-trigraphs"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wimport"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wno-import"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wmissing-braces"))
+ warn_missing_braces = 1;
+ else if (!strcmp (p, "-Wno-missing-braces"))
+ warn_missing_braces = 0;
+ else if (!strcmp (p, "-Wall"))
+ {
+ extra_warnings = 1;
+ /* We save the value of warn_uninitialized, since if they put
+ -Wuninitialized on the command line, we need to generate a
+ warning about not using it without also specifying -O. */
+ if (warn_uninitialized != 1)
+ warn_uninitialized = 2;
+ warn_implicit = 1;
+ warn_return_type = 1;
+ warn_unused = 1;
+ warn_char_subscripts = 1;
+ warn_parentheses = 1;
+ warn_missing_braces = 1;
+ }
+ else
+ return 0;
+
+ return 1;
+}
+
+/* Hooks for print_node. */
+
+void
+print_lang_decl (file, node, indent)
+ FILE *file;
+ tree node;
+ int indent;
+{
+ indent_to (file, indent + 3);
+ fprintf (file, "nesting_level %d ", DECL_NESTING_LEVEL (node));
+ if (DECL_WEAK_NAME (node))
+ fprintf (file, "weak_name ");
+ if (CH_DECL_SIGNAL (node))
+ fprintf (file, "decl_signal ");
+ print_node (file, "tasking_code",
+ (tree)DECL_TASKING_CODE_DECL (node), indent + 4);
+}
+
+
+void
+print_lang_type (file, node, indent)
+ FILE *file;
+ tree node;
+ int indent;
+{
+ tree temp;
+
+ indent_to (file, indent + 3);
+ if (CH_IS_BUFFER_MODE (node))
+ fprintf (file, "buffer_mode ");
+ if (CH_IS_EVENT_MODE (node))
+ fprintf (file, "event_mode ");
+
+ if (CH_IS_EVENT_MODE (node) || CH_IS_BUFFER_MODE (node))
+ {
+ temp = max_queue_size (node);
+ if (temp)
+ print_node_brief (file, "qsize", temp, indent + 4);
+ }
+}
+
+void
+print_lang_identifier (file, node, indent)
+ FILE *file;
+ tree node;
+ int indent;
+{
+ print_node (file, "local", IDENTIFIER_LOCAL_VALUE (node), indent + 4);
+ print_node (file, "outer", IDENTIFIER_OUTER_VALUE (node), indent + 4);
+ print_node (file, "implicit", IDENTIFIER_IMPLICIT_DECL (node), indent + 4);
+ print_node (file, "error locus", IDENTIFIER_ERROR_LOCUS (node), indent + 4);
+ print_node (file, "signal_dest", IDENTIFIER_SIGNAL_DEST (node), indent + 4);
+ indent_to (file, indent + 3);
+ if (IDENTIFIER_SIGNAL_DATA(node))
+ fprintf (file, "signal_data ");
+}
+
+/* initialise non-value struct */
+
+static int
+init_nonvalue_struct (expr)
+ tree expr;
+{
+ tree type = TREE_TYPE (expr);
+ tree field;
+ int res = 0;
+
+ if (CH_IS_BUFFER_MODE (type))
+ {
+ expand_expr_stmt (
+ build_chill_modify_expr (
+ build_component_ref (expr, get_identifier ("__buffer_data")),
+ null_pointer_node));
+ return 1;
+ }
+ else if (CH_IS_EVENT_MODE (type))
+ {
+ expand_expr_stmt (
+ build_chill_modify_expr (
+ build_component_ref (expr, get_identifier ("__event_data")),
+ null_pointer_node));
+ return 1;
+ }
+ else if (CH_IS_ASSOCIATION_MODE (type))
+ {
+ expand_expr_stmt (
+ build_chill_modify_expr (expr,
+ chill_convert_for_assignment (type, association_init_value,
+ "association")));
+ return 1;
+ }
+ else if (CH_IS_ACCESS_MODE (type))
+ {
+ init_access_location (expr, type);
+ return 1;
+ }
+ else if (CH_IS_TEXT_MODE (type))
+ {
+ init_text_location (expr, type);
+ return 1;
+ }
+
+ for (field = TYPE_FIELDS (type); field != NULL_TREE; field = TREE_CHAIN (field))
+ {
+ type = TREE_TYPE (field);
+ if (CH_TYPE_NONVALUE_P (type))
+ {
+ tree exp = build_component_ref (expr, DECL_NAME (field));
+ if (TREE_CODE (type) == RECORD_TYPE)
+ res |= init_nonvalue_struct (exp);
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ res |= init_nonvalue_array (exp);
+ }
+ }
+ return res;
+}
+
+/* initialize non-value array */
+/* do it with DO FOR unique-id IN expr; ... OD; */
+static int
+init_nonvalue_array (expr)
+ tree expr;
+{
+ tree tmpvar = get_unique_identifier ("NONVALINIT");
+ tree type;
+ int res = 0;
+
+ push_loop_block ();
+ build_loop_iterator (tmpvar, expr, NULL_TREE, NULL_TREE, 0, 1, 0);
+ nonvalue_begin_loop_scope ();
+ build_loop_start (NULL_TREE);
+ tmpvar = lookup_name (tmpvar);
+ type = TREE_TYPE (tmpvar);
+ if (CH_TYPE_NONVALUE_P (type))
+ {
+ if (TREE_CODE (type) == RECORD_TYPE)
+ res |= init_nonvalue_struct (tmpvar);
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ res |= init_nonvalue_array (tmpvar);
+ }
+ build_loop_end ();
+ nonvalue_end_loop_scope ();
+ pop_loop_block ();
+ return res;
+}
+
+/* This excessive piece of code sets DECL_NESTING_LEVEL (DECL) to LEVEL. */
+
+void
+set_nesting_level (decl, level)
+ tree decl;
+ int level;
+{
+ static tree *small_ints = NULL;
+ static int max_small_ints = 0;
+
+ if (level < 0)
+ decl->decl.vindex = NULL_TREE;
+ else
+ {
+ if (level >= max_small_ints)
+ {
+ int new_max = level + 20;
+ if (small_ints == NULL)
+ small_ints = (tree*)xmalloc (new_max * sizeof(tree));
+ else
+ small_ints = (tree*)xrealloc (small_ints, new_max * sizeof(tree));
+ while (max_small_ints < new_max)
+ small_ints[max_small_ints++] = NULL_TREE;
+ }
+ if (small_ints[level] == NULL_TREE)
+ {
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ small_ints[level] = build_int_2 (level, 0);
+ pop_obstacks ();
+ }
+ /* set DECL_NESTING_LEVEL */
+ decl->decl.vindex = small_ints[level];
+ }
+}
+
+/* OPT_EXTERNAL is non-zero when the declaration is at module level.
+ * OPT_EXTERNAL == 2 means implicitly grant it.
+ */
+void
+do_decls (names, type, opt_static, lifetime_bound, opt_init, opt_external)
+ tree names;
+ tree type;
+ int opt_static;
+ int lifetime_bound;
+ tree opt_init;
+ int opt_external;
+{
+ if (names == NULL_TREE || TREE_CODE (names) == TREE_LIST)
+ {
+ for (; names != NULL_TREE; names = TREE_CHAIN (names))
+ do_decl (TREE_VALUE (names), type, opt_static, lifetime_bound,
+ opt_init, opt_external);
+ }
+ else if (TREE_CODE (names) != ERROR_MARK)
+ do_decl (names, type, opt_static, lifetime_bound, opt_init, opt_external);
+}
+
+tree
+do_decl (name, type, is_static, lifetime_bound, opt_init, opt_external)
+ tree name, type;
+ int is_static;
+ int lifetime_bound;
+ tree opt_init;
+ int opt_external;
+{
+ tree decl;
+
+ if (current_function_decl == global_function_decl
+ && ! lifetime_bound /*&& opt_init != NULL_TREE*/)
+ seen_action = 1;
+
+ if (pass < 2)
+ {
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ decl = make_node (VAR_DECL);
+ DECL_NAME (decl) = name;
+ TREE_TYPE (decl) = type;
+ DECL_ASSEMBLER_NAME (decl) = name;
+
+ /* Try to put things in common when possible.
+ Tasking variables must go into common. */
+ DECL_COMMON (decl) = 1;
+ DECL_EXTERNAL (decl) = opt_external > 0;
+ TREE_PUBLIC (decl) = opt_external > 0;
+ TREE_STATIC (decl) = is_static;
+
+ if (pass == 0)
+ {
+ /* We have to set this here, since we build the decl w/o
+ calling `build_decl'. */
+ DECL_INITIAL (decl) = opt_init;
+ pushdecl (decl);
+ finish_decl (decl);
+ }
+ else
+ {
+ save_decl (decl);
+ pop_obstacks ();
+ }
+ DECL_INITIAL (decl) = opt_init;
+ if (opt_external > 1 || in_pseudo_module)
+ push_granted (DECL_NAME (decl), decl);
+ }
+ else /* pass == 2 */
+ {
+ tree temp = NULL_TREE;
+ int init_it = 0;
+
+ decl = get_next_decl ();
+
+ if (name != DECL_NAME (decl))
+ abort ();
+
+ type = TREE_TYPE (decl);
+
+ push_obstacks_nochange ();
+ if (TYPE_READONLY_PROPERTY (type))
+ {
+ if (CH_TYPE_NONVALUE_P (type))
+ {
+ error_with_decl (decl, "`%s' must not be declared readonly");
+ opt_init = NULL_TREE; /* prevent subsequent errors */
+ }
+ else if (opt_init == NULL_TREE && !opt_external)
+ error("declaration of readonly variable without initialization");
+ }
+ TREE_READONLY (decl) = TYPE_READONLY (type);
+
+ if (!opt_init && chill_varying_type_p (type))
+ {
+ tree fixed_part_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (type)));
+ if (fixed_part_type != NULL_TREE && TREE_CODE (fixed_part_type) != ERROR_MARK)
+ {
+ if (CH_CHARS_TYPE_P (fixed_part_type))
+ opt_init = build_chill_string (0, "");
+ else
+ opt_init = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE);
+ lifetime_bound = 1;
+ }
+ }
+
+ if (opt_init)
+ {
+ if (CH_TYPE_NONVALUE_P (type))
+ {
+ error_with_decl (decl,
+ "no initialisation allowed for `%s'");
+ temp = NULL_TREE;
+ }
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ { /* A loc-identity declaration */
+ if (! CH_LOCATION_P (opt_init))
+ {
+ error_with_decl (decl,
+ "value for loc-identity `%s' is not a location");
+ temp = NULL_TREE;
+ }
+ else if (! CH_READ_COMPATIBLE (TREE_TYPE (type),
+ TREE_TYPE (opt_init)))
+ {
+ error_with_decl (decl,
+ "location for `%s' not read-compatible");
+ temp = NULL_TREE;
+ }
+ else
+ temp = convert (type, opt_init);
+ }
+ else
+ { /* Normal location declaration */
+ char place[80];
+ sprintf (place, "`%.60s' initializer",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ temp = chill_convert_for_assignment (type, opt_init, place);
+ }
+ }
+ else if (CH_TYPE_NONVALUE_P (type))
+ {
+ temp = NULL_TREE;
+ init_it = 1;
+ }
+ DECL_INITIAL (decl) = NULL_TREE;
+
+ if (temp != NULL_TREE && TREE_CODE (temp) != ERROR_MARK)
+ {
+ /* The same for stack variables (assuming no nested modules). */
+ if (lifetime_bound || !is_static)
+ {
+ if (is_static && ! TREE_CONSTANT (temp))
+ error_with_decl (decl, "nonconstant initializer for `%s'");
+ else
+ DECL_INITIAL (decl) = temp;
+ }
+ }
+ finish_decl (decl);
+ /* Initialize the variable unless initialized statically. */
+ if ((!is_static || ! lifetime_bound) &&
+ temp != NULL_TREE && TREE_CODE (temp) != ERROR_MARK)
+ {
+ int was_used = TREE_USED (decl);
+ emit_line_note (input_filename, lineno);
+ expand_expr_stmt (build_chill_modify_expr (decl, temp));
+ /* Don't let the initialization count as "using" the variable. */
+ TREE_USED (decl) = was_used;
+ if (current_function_decl == global_function_decl)
+ build_constructor = 1;
+ }
+ else if (init_it && TREE_CODE (type) != ERROR_MARK)
+ {
+ /* Initialize variables with non-value type */
+ int was_used = TREE_USED (decl);
+ int something_initialised = 0;
+
+ emit_line_note (input_filename, lineno);
+ if (TREE_CODE (type) == RECORD_TYPE)
+ something_initialised = init_nonvalue_struct (decl);
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ something_initialised = init_nonvalue_array (decl);
+ if (! something_initialised)
+ {
+ error ("do_decl: internal error: don't know what to initialize");
+ abort ();
+ }
+ /* Don't let the initialization count as "using" the variable. */
+ TREE_USED (decl) = was_used;
+ if (current_function_decl == global_function_decl)
+ build_constructor = 1;
+ }
+ }
+ return decl;
+}
+
+/*
+ * ARGTYPES is a tree_list of formal argument types. TREE_VALUE
+ * is the type tree for each argument, while the attribute is in
+ * TREE_PURPOSE.
+ */
+tree
+build_chill_function_type (return_type, argtypes, exceptions, recurse_p)
+ tree return_type, argtypes, exceptions, recurse_p;
+{
+ tree ftype, arg;
+
+ if (exceptions != NULL_TREE)
+ {
+ /* if we have exceptions we add 2 arguments, callers filename
+ and linenumber. These arguments will be added automatically
+ when calling a function which may raise exceptions. */
+ argtypes = chainon (argtypes,
+ build_tree_list (NULL_TREE, ridpointers[(int) RID_PTR]));
+ argtypes = chainon (argtypes,
+ build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]));
+}
+
+ /* Indicate the argument list is complete. */
+ argtypes = chainon (argtypes,
+ build_tree_list (NULL_TREE, void_type_node));
+
+ /* INOUT and OUT parameters must be a REFERENCE_TYPE since
+ we'll be passing a temporary's address at call time. */
+ for (arg = argtypes; arg; arg = TREE_CHAIN (arg))
+ if (TREE_PURPOSE (arg) == ridpointers[(int) RID_LOC]
+ || TREE_PURPOSE (arg) == ridpointers[(int) RID_OUT]
+ || TREE_PURPOSE (arg) == ridpointers[(int) RID_INOUT]
+ )
+ TREE_VALUE (arg) =
+ build_chill_reference_type (TREE_VALUE (arg));
+
+ /* Cannot use build_function_type, because if does hash-canonlicalization. */
+ ftype = make_node (FUNCTION_TYPE);
+ TREE_TYPE (ftype) = return_type ? return_type : void_type_node ;
+ TYPE_ARG_TYPES (ftype) = argtypes;
+
+ if (exceptions)
+ ftype = build_exception_variant (ftype, exceptions);
+
+ if (recurse_p)
+ sorry ("RECURSIVE PROCs");
+
+ return ftype;
+}
+
+/*
+ * ARGTYPES is a tree_list of formal argument types.
+ */
+tree
+push_extern_function (name, typespec, argtypes, exceptions, granting)
+ tree name, typespec, argtypes, exceptions;
+ int granting; /* If 0 do pushdecl(); if 1 do push_granted(). */
+{
+ tree ftype, fndecl;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ if (pass < 2)
+ {
+ ftype = build_chill_function_type (typespec, argtypes,
+ exceptions, NULL_TREE);
+
+ fndecl = build_decl (FUNCTION_DECL, name, ftype);
+
+ DECL_EXTERNAL(fndecl) = 1;
+ TREE_STATIC (fndecl) = 1;
+ TREE_PUBLIC (fndecl) = 1;
+ if (pass == 0)
+ {
+ pushdecl (fndecl);
+ finish_decl (fndecl);
+ }
+ else
+ {
+ save_decl (fndecl);
+ pop_obstacks ();
+ }
+ make_function_rtl (fndecl);
+ }
+ else
+ {
+ fndecl = get_next_decl ();
+ finish_decl (fndecl);
+ }
+#if 0
+
+ if (granting)
+ push_granted (name, decl);
+ else
+ pushdecl(decl);
+#endif
+ return fndecl;
+}
+
+
+
+void
+push_extern_process (name, argtypes, exceptions, granting)
+ tree name, argtypes, exceptions;
+ int granting;
+{
+ tree decl, func, arglist;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ if (pass < 2)
+ {
+ tree proc_struct = make_process_struct (name, argtypes);
+ arglist = (argtypes == NULL_TREE) ? NULL_TREE :
+ tree_cons (NULL_TREE,
+ build_chill_pointer_type (proc_struct), NULL_TREE);
+ }
+ else
+ arglist = NULL_TREE;
+
+ func = push_extern_function (name, NULL_TREE, arglist,
+ exceptions, granting);
+
+ /* declare the code variable */
+ decl = generate_tasking_code_variable (name, &process_type, 1);
+ CH_DECL_PROCESS (func) = 1;
+ /* remember the code variable in the function decl */
+ DECL_TASKING_CODE_DECL (func) = (struct lang_decl *)decl;
+
+ add_taskstuff_to_list (decl, "_TT_Process", NULL_TREE, func, NULL_TREE);
+}
+
+void
+push_extern_signal (signame, sigmodelist, optsigdest)
+ tree signame, sigmodelist, optsigdest;
+{
+ tree decl, sigtype;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ sigtype =
+ build_signal_struct_type (signame, sigmodelist, optsigdest);
+
+ /* declare the code variable outside the process */
+ decl = generate_tasking_code_variable (signame, &signal_code, 1);
+ add_taskstuff_to_list (decl, "_TT_Signal", NULL_TREE, sigtype, NULL_TREE);
+}
+
+void
+print_mode (mode)
+ tree mode;
+{
+ while (mode != NULL_TREE)
+ {
+ switch (TREE_CODE (mode))
+ {
+ case POINTER_TYPE:
+ printf (" REF ");
+ mode = TREE_TYPE (mode);
+ break;
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ printf (" %s ", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (mode))));
+ mode = NULL_TREE;
+ break;
+ case ARRAY_TYPE:
+ {
+ tree itype = TYPE_DOMAIN (mode);
+ if (CH_STRING_TYPE_P (mode))
+ printf (" STRING (%d) OF ",
+ TREE_INT_CST_LOW (TYPE_MAX_VALUE (itype)));
+ else
+ printf (" ARRAY (%d:%d) OF ",
+ TREE_INT_CST_LOW (TYPE_MIN_VALUE (itype)),
+ TREE_INT_CST_LOW (TYPE_MAX_VALUE (itype)));
+ mode = TREE_TYPE (mode);
+ break;
+ }
+ case RECORD_TYPE:
+ {
+ tree fields = TYPE_FIELDS (mode);
+ printf (" RECORD (");
+ while (fields != NULL_TREE)
+ {
+ printf (" %s:", IDENTIFIER_POINTER (DECL_NAME (fields)));
+ print_mode (TREE_TYPE (fields));
+ if (TREE_CHAIN (fields))
+ printf (",");
+ fields = TREE_CHAIN (fields);
+ }
+ printf (")");
+ mode = NULL_TREE;
+ break;
+ }
+ default:
+ abort ();
+ }
+ }
+}
+
+tree
+chill_munge_params (nodes, type, attr)
+ tree nodes, type, attr;
+{
+ tree node;
+ if (pass == 1)
+ {
+ /* Convert the list of identifiers to a list of types. */
+ for (node = nodes; node != NULL_TREE; node = TREE_CHAIN (node))
+ {
+ TREE_VALUE (node) = type; /* this was the identifier node */
+ TREE_PURPOSE (node) = attr;
+ }
+ }
+ return nodes;
+}
+
+/* Push the declarations described by SYN_DEFS into the current scope. */
+void
+push_syndecl (name, mode, value)
+ tree name, mode, value;
+{
+ if (pass == 1)
+ {
+ tree decl = make_node (CONST_DECL);
+ DECL_NAME (decl) = name;
+ DECL_ASSEMBLER_NAME (decl) = name;
+ TREE_TYPE (decl) = mode;
+ DECL_INITIAL (decl) = value;
+ TREE_READONLY (decl) = 1;
+ save_decl (decl);
+ if (in_pseudo_module)
+ push_granted (DECL_NAME (decl), decl);
+ }
+ else /* pass == 2 */
+ get_next_decl ();
+}
+
+
+
+/* Push the declarations described by (MODENAME,MODE) into the current scope.
+ MAKE_NEWMODE is 1 for NEWMODE, 0 for SYNMODE, and
+ -1 for internal use (in which case the mode does not need to be copied). */
+
+tree
+push_modedef (modename, mode, make_newmode)
+ tree modename;
+ tree mode; /* ignored if pass==2. */
+ int make_newmode;
+{
+ tree newdecl, newmode;
+
+ if (pass == 1)
+ {
+ /* FIXME: need to check here for SYNMODE fred fred; */
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ newdecl = build_lang_decl (TYPE_DECL, modename, mode);
+
+ if (make_newmode >= 0)
+ {
+ newmode = make_node (LANG_TYPE);
+ TREE_TYPE (newmode) = mode;
+ TREE_TYPE (newdecl) = newmode;
+ TYPE_NAME (newmode) = newdecl;
+ if (make_newmode > 0)
+ CH_NOVELTY (newmode) = newdecl;
+ }
+
+ save_decl (newdecl);
+ pop_obstacks ();
+
+ }
+ else /* pass == 2 */
+ {
+ /* FIXME: need to check here for SYNMODE fred fred; */
+ newdecl = get_next_decl ();
+ if (DECL_NAME (newdecl) != modename)
+ abort ();
+ if (TREE_CODE (TREE_TYPE (newdecl)) != ERROR_MARK)
+ {
+ /* ASSOCIATION, ACCESS, TEXT, BUFFER, and EVENT must not be READOnly */
+ if (TREE_READONLY (TREE_TYPE (newdecl)) &&
+ (CH_IS_ASSOCIATION_MODE (TREE_TYPE (newdecl)) ||
+ CH_IS_ACCESS_MODE (TREE_TYPE (newdecl)) ||
+ CH_IS_TEXT_MODE (TREE_TYPE (newdecl)) ||
+ CH_IS_BUFFER_MODE (TREE_TYPE (newdecl)) ||
+ CH_IS_EVENT_MODE (TREE_TYPE (newdecl))))
+ error_with_decl (newdecl, "`%s' must not be READonly");
+ rest_of_decl_compilation (newdecl, NULL_PTR,
+ global_bindings_p (), 0);
+ }
+ }
+ return newdecl;
+}
+
+/* Return a chain of FIELD_DECLs for the names in NAMELIST. All of
+ of type TYPE. When NAMELIST is passed in from the parser, it is
+ in reverse order.
+ LAYOUT is (NULL_TREE, integer_one_node, integer_zero_node, tree_list),
+ meaning (default, pack, nopack, POS (...) ). */
+
+tree
+grok_chill_fixedfields (namelist, type, layout)
+ tree namelist, type;
+ tree layout;
+{
+ tree decls = NULL_TREE;
+
+ if (layout != NULL_TREE && TREE_CHAIN (namelist) != NULL_TREE)
+ {
+ if (layout != integer_one_node && layout != integer_zero_node)
+ {
+ layout = NULL_TREE;
+ error ("POS may not be specified for a list of field declarations");
+ }
+ }
+
+ /* we build the chain of FIELD_DECLs backwards, effectively
+ unreversing the reversed names in NAMELIST. */
+ for (; namelist; namelist = TREE_CHAIN (namelist))
+ {
+ tree decl = build_decl (FIELD_DECL,
+ TREE_VALUE (namelist), type);
+ DECL_INITIAL (decl) = layout;
+ TREE_CHAIN (decl) = decls;
+ decls = decl;
+ }
+
+ return decls;
+}
+
+struct tree_pair
+{
+ tree value;
+ tree decl;
+};
+
+
+/* Function to help qsort sort variant labels by value order. */
+static int
+label_value_cmp (x, y)
+ struct tree_pair *x, *y;
+{
+ return TREE_INT_CST_LOW (x->value) - TREE_INT_CST_LOW (y->value);
+}
+
+tree
+make_chill_variants (tagfields, body, variantelse)
+ tree tagfields;
+ tree body;
+ tree variantelse;
+{
+ tree utype;
+ tree first = NULL_TREE;
+ for (; body; body = TREE_CHAIN (body))
+ {
+ tree decls = TREE_VALUE (body);
+ tree labellist = TREE_PURPOSE (body);
+
+ if (labellist != NULL_TREE
+ && TREE_CODE (TREE_VALUE (labellist)) == TREE_LIST
+ && TREE_VALUE (TREE_VALUE (labellist)) == case_else_node
+ && TREE_CHAIN (labellist) == NULL_TREE)
+ {
+ if (variantelse)
+ error ("(ELSE) case label as well as ELSE variant");
+ variantelse = decls;
+ }
+ else
+ {
+ tree rtype = start_struct (RECORD_TYPE, NULL_TREE);
+ rtype = finish_struct (rtype, decls);
+
+ first = chainon (first, build_decl (FIELD_DECL, NULL_TREE, rtype));
+
+ TYPE_TAG_VALUES (rtype) = labellist;
+ }
+ }
+
+ if (variantelse != NULL_TREE)
+ {
+ tree rtype = start_struct (RECORD_TYPE, NULL_TREE);
+ rtype = finish_struct (rtype, variantelse);
+ first = chainon (first,
+ build_decl (FIELD_DECL,
+ ELSE_VARIANT_NAME, rtype));
+ }
+
+ utype = start_struct (UNION_TYPE, NULL_TREE);
+ utype = finish_struct (utype, first);
+ TYPE_TAGFIELDS (utype) = tagfields;
+ return utype;
+}
+
+tree
+layout_chill_variants (utype)
+ tree utype;
+{
+ tree first = TYPE_FIELDS (utype);
+ int nlabels = 0, label_index = 0;
+ struct tree_pair *label_value_array;
+ tree decl;
+ extern int errorcount;
+
+ if (TYPE_SIZE (utype))
+ return utype;
+
+ for (decl = first; decl; decl = TREE_CHAIN (decl))
+ {
+ tree tagfields = TYPE_TAGFIELDS (utype);
+ tree t = TREE_TYPE (decl);
+ tree taglist = TYPE_TAG_VALUES (t);
+ if (DECL_NAME (decl) == ELSE_VARIANT_NAME)
+ continue;
+ if (tagfields == NULL_TREE)
+ continue;
+ for ( ; tagfields != NULL_TREE && taglist != NULL_TREE;
+ tagfields = TREE_CHAIN (tagfields), taglist = TREE_CHAIN (taglist))
+ {
+ tree labellist = TREE_VALUE (taglist);
+ for (; labellist; labellist = TREE_CHAIN (labellist))
+ {
+ int compat_error = 0;
+ tree label_value = TREE_VALUE (labellist);
+ if (TREE_CODE (label_value) == RANGE_EXPR)
+ {
+ if (TREE_OPERAND (label_value, 0) != NULL_TREE)
+ {
+ if (!CH_COMPATIBLE (TREE_OPERAND (label_value, 0),
+ TREE_TYPE (TREE_VALUE (tagfields)))
+ || !CH_COMPATIBLE (TREE_OPERAND (label_value, 1),
+ TREE_TYPE (TREE_VALUE (tagfields))))
+ compat_error = 1;
+ }
+ }
+ else if (TREE_CODE (label_value) == TYPE_DECL)
+ {
+ if (!CH_COMPATIBLE (label_value,
+ TREE_TYPE (TREE_VALUE (tagfields))))
+ compat_error = 1;
+ }
+ else if (TREE_CODE (label_value) == INTEGER_CST)
+ {
+ if (!CH_COMPATIBLE (label_value,
+ TREE_TYPE (TREE_VALUE (tagfields))))
+ compat_error = 1;
+ }
+ if (compat_error)
+ {
+ if (TYPE_FIELDS (t) == NULL_TREE)
+ error ("inconsistent modes between labels and tag field");
+ else
+ error_with_decl (TYPE_FIELDS (t),
+ "inconsistent modes between labels and tag field");
+ }
+ nlabels++;
+ }
+ }
+ if (tagfields != NULL_TREE)
+ error ("too few tag labels");
+ if (taglist != NULL_TREE)
+ error ("too many tag labels");
+ }
+
+ /* Check for duplicate label values. */
+ label_value_array = (struct tree_pair *)alloca (nlabels * sizeof (struct tree_pair));
+ for (decl = first; decl; decl = TREE_CHAIN (decl))
+ {
+ tree t = TREE_TYPE (decl);
+ /* Only one tag (first case_label_list) supported, for now. */
+ tree labellist = TYPE_TAG_VALUES (t);
+ if (labellist)
+ labellist = TREE_VALUE (labellist);
+
+ for (; labellist != NULL_TREE; labellist = TREE_CHAIN (labellist))
+ {
+ struct tree_pair p;
+
+ tree x = TREE_VALUE (labellist);
+ if (TREE_CODE (x) == RANGE_EXPR)
+ {
+ if (TREE_OPERAND (x, 0) != NULL_TREE)
+ {
+ if (TREE_CODE (TREE_OPERAND (x, 0)) != INTEGER_CST)
+ error ("case label lower limit is not a discrete constant expression");
+ if (TREE_CODE (TREE_OPERAND (x, 1)) != INTEGER_CST)
+ error ("case label upper limit is not a discrete constant expression");
+ }
+ continue;
+ }
+ else if (TREE_CODE (x) == TYPE_DECL)
+ continue;
+ else if (TREE_CODE (x) == ERROR_MARK)
+ continue;
+ else if (TREE_CODE (x) != INTEGER_CST) /* <-- FIXME: what about CONST_DECLs? */
+ {
+ error ("case label must be a discrete constant expression");
+ continue;
+ }
+
+ if (TREE_CODE (x) == CONST_DECL)
+ x = DECL_INITIAL (x);
+ if (TREE_CODE (x) != INTEGER_CST) abort ();
+ p.value = x;
+ p.decl = decl;
+ if (p.decl == NULL_TREE)
+ p.decl = TREE_VALUE (labellist);
+ label_value_array[label_index++] = p;
+ }
+ }
+ if (errorcount == 0)
+ {
+ int limit;
+ qsort (label_value_array,
+ label_index, sizeof (struct tree_pair), label_value_cmp);
+ limit = label_index - 1;
+ for (label_index = 0; label_index < limit; label_index++)
+ {
+ if (tree_int_cst_equal (label_value_array[label_index].value,
+ label_value_array[label_index+1].value))
+ {
+ error_with_decl (label_value_array[label_index].decl,
+ "variant label declared here...");
+ error_with_decl (label_value_array[label_index+1].decl,
+ "...is duplicated here");
+ }
+ }
+ }
+ layout_type (utype);
+ return utype;
+}
+
+/* Convert a TREE_LIST of tag field names into a list of
+ field decls, found from FIXED_FIELDS, re-using the input list. */
+
+tree
+lookup_tag_fields (tag_field_names, fixed_fields)
+ tree tag_field_names;
+ tree fixed_fields;
+{
+ tree list;
+ for (list = tag_field_names; list != NULL_TREE; list = TREE_CHAIN (list))
+ {
+ tree decl = fixed_fields;
+ for ( ; decl != NULL_TREE; decl = TREE_CHAIN (decl))
+ {
+ if (DECL_NAME (decl) == TREE_VALUE (list))
+ {
+ TREE_VALUE (list) = decl;
+ break;
+ }
+ }
+ if (decl == NULL_TREE)
+ {
+ error ("no field (yet) for tag %s",
+ IDENTIFIER_POINTER (TREE_VALUE (list)));
+ TREE_VALUE (list) = error_mark_node;
+ }
+ }
+ return tag_field_names;
+}
+
+/* If non-NULL, TAGFIELDS is the tag fields for this variant record.
+ BODY is a TREE_LIST of (optlabels, fixed fields).
+ If non-null, VARIANTELSE is a fixed field for the else part of the
+ variant record. */
+
+tree
+grok_chill_variantdefs (tagfields, body, variantelse)
+ tree tagfields, body, variantelse;
+{
+ tree t;
+
+ t = make_chill_variants (tagfields, body, variantelse);
+ if (pass != 1)
+ t = layout_chill_variants (t);
+ return build_decl (FIELD_DECL, NULL_TREE, t);
+}
+
+/*
+ In pass 1, PARMS is a list of types (with attributes).
+ In pass 2, PARMS is a chain of PARM_DECLs.
+ */
+
+int
+start_chill_function (label, rtype, parms, exceptlist, attrs)
+ tree label, rtype, parms, exceptlist, attrs;
+{
+ tree decl, fndecl, type, result_type, func_type;
+ int nested = current_function_decl != 0;
+ if (pass == 1)
+ {
+ func_type
+ = build_chill_function_type (rtype, parms, exceptlist, 0);
+ fndecl = build_decl (FUNCTION_DECL, label, func_type);
+
+ save_decl (fndecl);
+
+ /* Make the init_value nonzero so pushdecl knows this is not tentative.
+ error_mark_node is replaced below (in poplevel) with the BLOCK. */
+ DECL_INITIAL (fndecl) = error_mark_node;
+
+ DECL_EXTERNAL (fndecl) = 0;
+
+ /* This function exists in static storage.
+ (This does not mean `static' in the C sense!) */
+ TREE_STATIC (fndecl) = 1;
+
+ for (; attrs != NULL_TREE; attrs = TREE_CHAIN (attrs))
+ {
+ if (TREE_VALUE (attrs) == ridpointers[RID_GENERAL])
+ CH_DECL_GENERAL (fndecl) = 1;
+ else if (TREE_VALUE (attrs) == ridpointers[RID_SIMPLE])
+ CH_DECL_SIMPLE (fndecl) = 1;
+ else if (TREE_VALUE (attrs) == ridpointers[RID_RECURSIVE])
+ CH_DECL_RECURSIVE (fndecl) = 1;
+ else if (TREE_VALUE (attrs) == ridpointers[RID_INLINE])
+ DECL_INLINE (fndecl) = 1;
+ else
+ abort ();
+ }
+ }
+ else /* pass == 2 */
+ {
+ fndecl = get_next_decl ();
+ if (DECL_NAME (fndecl) != label)
+ abort (); /* outta sync - got wrong decl */
+ func_type = TREE_TYPE (fndecl);
+ if (TYPE_RAISES_EXCEPTIONS (func_type) != NULL_TREE)
+ {
+ /* In this case we have to add 2 parameters.
+ See build_chill_function_type (pass == 1). */
+ tree arg;
+
+ arg = make_node (PARM_DECL);
+ DECL_ASSEMBLER_NAME (arg) = DECL_NAME (arg) = get_identifier (CALLER_FILE);
+ DECL_IGNORED_P (arg) = 1;
+ parms = chainon (parms, arg);
+
+ arg = make_node (PARM_DECL);
+ DECL_ASSEMBLER_NAME (arg) = DECL_NAME (arg) = get_identifier (CALLER_LINE);
+ DECL_IGNORED_P (arg) = 1;
+ parms = chainon (parms, arg);
+ }
+ }
+
+ current_function_decl = fndecl;
+ result_type = TREE_TYPE (func_type);
+ if (CH_TYPE_NONVALUE_P (result_type))
+ error ("non-value mode may only returned by LOC");
+
+ pushlevel (1); /* Push parameters. */
+
+ if (pass == 2)
+ {
+ DECL_ARGUMENTS (fndecl) = parms;
+ for (decl = DECL_ARGUMENTS (fndecl), type = TYPE_ARG_TYPES (func_type);
+ decl != NULL_TREE;
+ decl = TREE_CHAIN (decl), type = TREE_CHAIN (type))
+ {
+ /* check here that modes with the non-value property (like
+ BUFFER's, EVENT's, ASSOCIATION's, ACCESS's, or TEXT's) only
+ gets passed by LOC */
+ tree argtype = TREE_VALUE (type);
+ tree argattr = TREE_PURPOSE (type);
+
+ if (TREE_CODE (argtype) == REFERENCE_TYPE)
+ argtype = TREE_TYPE (argtype);
+
+ if (TREE_CODE (argtype) != ERROR_MARK &&
+ TREE_CODE_CLASS (TREE_CODE (argtype)) != 't')
+ {
+ error_with_decl (decl, "mode of `%s' is not a mode");
+ TREE_VALUE (type) = error_mark_node;
+ }
+
+ if (CH_TYPE_NONVALUE_P (argtype) &&
+ argattr != ridpointers[(int) RID_LOC])
+ error_with_decl (decl, "`%s' may only be passed by LOC");
+ TREE_TYPE (decl) = TREE_VALUE (type);
+ DECL_ARG_TYPE (decl) = TREE_TYPE (decl);
+ DECL_CONTEXT (decl) = fndecl;
+ TREE_READONLY (decl) = TYPE_READONLY (argtype);
+ layout_decl (decl, 0);
+ }
+
+ pushdecllist (DECL_ARGUMENTS (fndecl), 0);
+
+ DECL_RESULT (current_function_decl)
+ = build_decl (RESULT_DECL, NULL_TREE, result_type);
+
+#if 0
+ /* Write a record describing this function definition to the prototypes
+ file (if requested). */
+ gen_aux_info_record (fndecl, 1, 0, prototype);
+#endif
+
+ if (fndecl != global_function_decl || seen_action)
+ {
+ /* Initialize the RTL code for the function. */
+ init_function_start (fndecl, input_filename, lineno);
+
+ /* Set up parameters and prepare for return, for the function. */
+ expand_function_start (fndecl, 0);
+ }
+
+ if (!nested)
+ /* Allocate further tree nodes temporarily during compilation
+ of this function only. */
+ temporary_allocation ();
+
+ /* If this fcn was already referenced via a block-scope `extern' decl (or
+ an implicit decl), propagate certain information about the usage. */
+ if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl)))
+ TREE_ADDRESSABLE (current_function_decl) = 1;
+ }
+
+ /* Z.200 requires that formal parameter names be defined in
+ the same block as the procedure body.
+ We could do this by keeping boths sets of DECLs in the same
+ scope, but we would have to be careful to not merge the
+ two chains (e.g. DECL_ARGUEMENTS musr not contains locals).
+ Instead, we just make sure they have the same nesting_level. */
+ current_nesting_level--;
+ pushlevel (1); /* Push local variables. */
+
+ if (pass == 2 && (fndecl != global_function_decl || seen_action))
+ {
+ /* generate label for possible 'exit' */
+ expand_start_bindings (1);
+
+ result_never_set = 1;
+ }
+
+ if (TREE_CODE (result_type) == VOID_TYPE)
+ chill_result_decl = NULL_TREE;
+ else
+ {
+ /* We use the same name as the keyword.
+ This makes it easy to print and change the RESULT from gdb. */
+ char *result_str = (ignore_case || ! special_UC) ? "result" : "RESULT";
+ if (pass == 2 && TREE_CODE (result_type) == ERROR_MARK)
+ TREE_TYPE (current_scope->remembered_decls) = result_type;
+ chill_result_decl = do_decl (get_identifier (result_str),
+ result_type, 0, 0, 0, 0);
+ DECL_CONTEXT (chill_result_decl) = fndecl;
+ }
+
+ return 1;
+}
+
+/* For checking purpose added pname as new argument
+ MW Wed Oct 14 14:22:10 1992 */
+void
+finish_chill_function ()
+{
+ register tree fndecl = current_function_decl;
+ tree outer_function = decl_function_context (fndecl);
+ int nested;
+ if (outer_function == NULL_TREE && fndecl != global_function_decl)
+ outer_function = global_function_decl;
+ nested = current_function_decl != global_function_decl;
+ if (pass == 2 && (fndecl != global_function_decl || seen_action))
+ expand_end_bindings (getdecls (), 1, 0);
+
+ /* pop out of function */
+ poplevel (1, 1, 0);
+ current_nesting_level++;
+ /* pop out of its parameters */
+ poplevel (1, 0, 1);
+
+ if (pass == 2)
+ {
+ /* TREE_READONLY (fndecl) = 1;
+ This caused &foo to be of type ptr-to-const-function which
+ then got a warning when stored in a ptr-to-function variable. */
+
+ BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
+
+ /* Must mark the RESULT_DECL as being in this function. */
+
+ DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
+
+ if (fndecl != global_function_decl || seen_action)
+ {
+ /* Generate rtl for function exit. */
+ expand_function_end (input_filename, lineno, 0);
+
+ /* So we can tell if jump_optimize sets it to 1. */
+ can_reach_end = 0;
+
+ /* Run the optimizers and output assembler code for this function. */
+ rest_of_compilation (fndecl);
+ }
+
+ if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested)
+ {
+ /* Stop pointing to the local nodes about to be freed. */
+ /* But DECL_INITIAL must remain nonzero so we know this
+ was an actual function definition. */
+ /* For a nested function, this is done in pop_chill_function_context. */
+ DECL_INITIAL (fndecl) = error_mark_node;
+ DECL_ARGUMENTS (fndecl) = 0;
+ }
+ }
+ current_function_decl = outer_function;
+}
+
+/* process SEIZE */
+
+/* Points to the head of the _DECLs read from seize files. */
+#if 0
+static tree seized_decls;
+
+static tree processed_seize_files = 0;
+#endif
+
+void
+chill_seize (old_prefix, new_prefix, postfix)
+ tree old_prefix, new_prefix, postfix;
+{
+ if (pass == 1)
+ {
+ tree decl = build_alias_decl (old_prefix, new_prefix, postfix);
+ DECL_SEIZEFILE(decl) = use_seizefile_name;
+ save_decl (decl);
+ }
+ else /* pass == 2 */
+ {
+ /* Do nothing - get_next_decl automatically ignores ALIAS_DECLs */
+ }
+}
+#if 0
+
+/*
+ * output a debug dump of a scope structure
+ */
+void
+debug_scope (sp)
+ struct scope *sp;
+{
+ if (sp == (struct scope *)NULL)
+ {
+ fprintf (stderr, "null scope ptr\n");
+ return;
+ }
+ fprintf (stderr, "enclosing 0x%x ", sp->enclosing);
+ fprintf (stderr, "next 0x%x ", sp->next);
+ fprintf (stderr, "remembered_decls 0x%x ", sp->remembered_decls);
+ fprintf (stderr, "decls 0x%x\n", sp->decls);
+ fprintf (stderr, "shadowed 0x%x ", sp->shadowed);
+ fprintf (stderr, "blocks 0x%x ", sp->blocks);
+ fprintf (stderr, "this_block 0x%x ", sp->this_block);
+ fprintf (stderr, "level_chain 0x%x\n", sp->level_chain);
+ fprintf (stderr, "module_flag %c ", sp->module_flag ? 'T' : 'F');
+ fprintf (stderr, "first_child_module 0x%x ", sp->first_child_module);
+ fprintf (stderr, "next_sibling_module 0x%x\n", sp->next_sibling_module);
+ if (sp->remembered_decls != NULL_TREE)
+ {
+ tree temp;
+ fprintf (stderr, "remembered_decl chain:\n");
+ for (temp = sp->remembered_decls; temp; temp = TREE_CHAIN (temp))
+ debug_tree (temp);
+ }
+}
+#endif
+
+static void
+save_decl (decl)
+ tree decl;
+{
+ if (current_function_decl != global_function_decl)
+ DECL_CONTEXT (decl) = current_function_decl;
+
+ TREE_CHAIN (decl) = current_scope->remembered_decls;
+ current_scope->remembered_decls = decl;
+#if 0
+ fprintf (stderr, "\n\nsave_decl 0x%x\n", decl);
+ debug_scope (current_scope); /* ************* */
+#endif
+ set_nesting_level (decl, current_nesting_level);
+}
+
+static tree
+get_next_decl ()
+{
+ tree decl;
+ do
+ {
+ decl = current_scope->remembered_decls;
+ current_scope->remembered_decls = TREE_CHAIN (decl);
+ /* We ignore ALIAS_DECLs, because push_scope_decls
+ can convert a single ALIAS_DECL representing 'SEIZE ALL'
+ into one ALIAS_DECL for each seizeable name.
+ This means we lose the nice one-to-one mapping
+ between pass 1 decls and pass 2 decls.
+ (Perhaps ALIAS_DECLs should not be on the remembered_decls list.) */
+ } while (decl && TREE_CODE (decl) == ALIAS_DECL);
+ return decl;
+}
+
+/* At the end of pass 1, we reverse the chronological chain of scopes. */
+
+void
+switch_to_pass_2 ()
+{
+ extern int errorcount, sorrycount;
+ if (current_scope != &builtin_scope)
+ abort ();
+ last_scope = &builtin_scope;
+ builtin_scope.remembered_decls = nreverse (builtin_scope.remembered_decls);
+ write_grant_file ();
+
+#if 0
+ if (errorcount || sorrycount)
+ exit (FATAL_EXIT_CODE);
+ else
+#endif
+ if (grant_only_flag)
+ exit (SUCCESS_EXIT_CODE);
+
+ pass = 2;
+ module_number = 0;
+ next_module = &first_module;
+}
+
+/*
+ * Called during pass 2, when we're processing actions, to
+ * generate a temporary variable. These don't need satisfying
+ * because they're compiler-generated and always declared
+ * before they're used.
+ */
+tree
+decl_temp1 (name, type, opt_static, opt_init,
+ opt_external, opt_public)
+ tree name, type;
+ int opt_static;
+ tree opt_init;
+ int opt_external, opt_public;
+{
+ int orig_pass = pass; /* be cautious */
+ tree mydecl;
+
+ pass = 1;
+ mydecl = do_decl (name, type, opt_static, opt_static,
+ opt_init, opt_external);
+
+ if (opt_public)
+ TREE_PUBLIC (mydecl) = 1;
+ pass = 2;
+ do_decl (name, type, opt_static, opt_static, opt_init, opt_external);
+
+ pass = orig_pass;
+ return mydecl;
+}
+
+/* True if we're reading a seizefile, but we haven't seen a SPEC MODULE yet.
+ For backwards compatibility, we treat declarations in such a context
+ as implicity granted. */
+
+tree
+set_module_name (name)
+ tree name;
+{
+ module_number++;
+ if (name == NULL_TREE)
+ {
+ /* NOTE: build_prefix_clause assumes a generated
+ module starts with a '_'. */
+ char buf[20];
+ sprintf (buf, "_MODULE_%d", module_number);
+ name = get_identifier (buf);
+ }
+ return name;
+}
+
+tree
+push_module (name, is_spec_module)
+ tree name;
+ int is_spec_module;
+{
+ struct module *new_module;
+ if (pass == 1)
+ {
+ new_module = (struct module*) permalloc (sizeof (struct module));
+ new_module->prev_module = current_module;
+
+ *next_module = new_module;
+ }
+ else
+ {
+ new_module = *next_module;
+ }
+ next_module = &new_module->next_module;
+
+ new_module->procedure_seen = 0;
+ new_module->is_spec_module = is_spec_module;
+ new_module->name = name;
+ if (current_module)
+ new_module->prefix_name
+ = get_identifier3 (IDENTIFIER_POINTER (current_module->prefix_name),
+ "__", IDENTIFIER_POINTER (name));
+ else
+ new_module->prefix_name = name;
+
+ new_module->granted_decls = NULL_TREE;
+ new_module->nesting_level = current_nesting_level + 1;
+
+ current_module = new_module;
+ current_module_nesting_level = new_module->nesting_level;
+ in_pseudo_module = name ? 0 : 1;
+
+ pushlevel (1);
+
+ current_scope->module_flag = 1;
+
+ *current_scope->enclosing->tail_child_module = current_scope;
+ current_scope->enclosing->tail_child_module
+ = &current_scope->next_sibling_module;
+
+ /* Rename the global function to have the same name as
+ the first named non-spec module. */
+ if (!is_spec_module
+ && IDENTIFIER_POINTER (name)[0] != '_'
+ && IDENTIFIER_POINTER (DECL_NAME (global_function_decl))[0] == '_')
+ {
+ tree fname = get_identifier3 ("", IDENTIFIER_POINTER (name), "_");
+ DECL_NAME (global_function_decl) = fname;
+ DECL_ASSEMBLER_NAME (global_function_decl) = fname;
+ }
+
+ return name; /* may have generated a name */
+}
+/* Make a copy of the identifier NAME, replacing each '!' by '__'. */
+tree
+fix_identifier (name)
+ tree name;
+{
+ char *buf = (char*)alloca (2 * IDENTIFIER_LENGTH (name) + 1);
+ int fixed = 0;
+ register char *dptr = buf;
+ register char *sptr = IDENTIFIER_POINTER (name);
+ for (; *sptr; sptr++)
+ {
+ if (*sptr == '!')
+ {
+ *dptr++ = '_';
+ *dptr++ = '_';
+ fixed++;
+ }
+ else
+ *dptr++ = *sptr;
+ }
+ *dptr = '\0';
+ return fixed ? get_identifier (buf) : name;
+}
+
+void
+find_granted_decls ()
+{
+ if (pass == 1)
+ {
+ /* Match each granted name to a granted decl. */
+
+ tree alias = current_module->granted_decls;
+ tree next_alias, decl;
+ /* This is an O(M*N) algorithm. FIXME! */
+ for (; alias; alias = next_alias)
+ {
+ int found = 0;
+ next_alias = TREE_CHAIN (alias);
+ for (decl = current_scope->remembered_decls;
+ decl; decl = TREE_CHAIN (decl))
+ {
+ tree new_name = (! DECL_NAME (decl)) ? NULL_TREE :
+ decl_check_rename (alias,
+ DECL_NAME (decl));
+
+ if (!new_name)
+ continue;
+ /* A Seized declaration is not grantable. */
+ if (TREE_CODE (decl) == ALIAS_DECL && !CH_DECL_GRANTED (decl))
+ continue;
+ found = 1;
+ if (global_bindings_p ())
+ TREE_PUBLIC (decl) = 1;
+ if (DECL_ASSEMBLER_NAME (decl) == NULL_TREE)
+ DECL_ASSEMBLER_NAME (decl) = fix_identifier (new_name);
+ if (DECL_POSTFIX_ALL (alias))
+ {
+ tree new_alias
+ = build_alias_decl (NULL_TREE, NULL_TREE, new_name);
+ TREE_CHAIN (new_alias) = TREE_CHAIN (alias);
+ TREE_CHAIN (alias) = new_alias;
+ DECL_ABSTRACT_ORIGIN (new_alias) = decl;
+ DECL_SOURCE_LINE (new_alias) = 0;
+ DECL_SEIZEFILE (new_alias) = DECL_SEIZEFILE (alias);
+ }
+ else
+ {
+ DECL_ABSTRACT_ORIGIN (alias) = decl;
+ break;
+ }
+ }
+ if (!found)
+ {
+ error_with_decl (alias, "Nothing named `%s' to grant.");
+ DECL_ABSTRACT_ORIGIN (alias) = error_mark_node;
+ }
+ }
+ }
+}
+
+void
+pop_module ()
+{
+ tree decl;
+ struct scope *module_scope = current_scope;
+
+ poplevel (0, 0, 0);
+
+ if (pass == 1)
+ {
+ /* Write out the grant file. */
+ if (!current_module->is_spec_module)
+ {
+ /* After reversal, TREE_CHAIN (last_old_decl) is the oldest
+ decl of the current module. */
+ write_spec_module (module_scope->remembered_decls,
+ current_module->granted_decls);
+ }
+
+ /* Move the granted decls into the enclosing scope. */
+ if (current_scope == global_scope)
+ {
+ tree next_decl;
+ for (decl = current_module->granted_decls; decl; decl = next_decl)
+ {
+ tree name = DECL_NAME (decl);
+ next_decl = TREE_CHAIN (decl);
+ if (name != NULL_TREE)
+ {
+ tree old_decl = IDENTIFIER_OUTER_VALUE (name);
+ set_nesting_level (decl, current_nesting_level);
+ if (old_decl != NULL_TREE)
+ {
+ pedwarn_with_decl (decl, "duplicate grant for `%s'");
+ pedwarn_with_decl (old_decl, "previous grant for `%s'");
+ TREE_CHAIN (decl) = TREE_CHAIN (old_decl);
+ TREE_CHAIN (old_decl) = decl;
+ }
+ else
+ {
+ TREE_CHAIN (decl) = outer_decls;
+ outer_decls = decl;
+ IDENTIFIER_OUTER_VALUE (name) = decl;
+ }
+ }
+ }
+ }
+ else
+ current_scope->granted_decls = chainon (current_module->granted_decls,
+ current_scope->granted_decls);
+ }
+
+ chill_check_no_handlers (); /* Sanity test */
+ current_module = current_module->prev_module;
+ current_module_nesting_level = current_module ?
+ current_module->nesting_level : 0;
+ in_pseudo_module = 0;
+}
+
+/* Nonzero if we are currently in the global binding level. */
+
+int
+global_bindings_p ()
+{
+ /* We return -1 here for the sake of variable_size() in ../stor-layout.c. */
+ return (current_function_decl == NULL_TREE
+ || current_function_decl == global_function_decl) ? -1 : 0;
+}
+
+/* Nonzero if the current level needs to have a BLOCK made. */
+
+int
+kept_level_p ()
+{
+ return current_scope->decls != 0;
+}
+
+/* Make DECL visible.
+ Save any existing definition.
+ Check redefinitions at the same level.
+ Suppress error messages if QUIET is true. */
+
+void
+proclaim_decl (decl, quiet)
+ tree decl;
+ int quiet;
+{
+ tree name = DECL_NAME (decl);
+ if (name)
+ {
+ tree old_decl = IDENTIFIER_LOCAL_VALUE (name);
+ if (old_decl == NULL) ; /* No duplication */
+ else if (DECL_NESTING_LEVEL (old_decl) != current_nesting_level)
+ {
+ /* Record for restoration when this binding level ends. */
+ current_scope->shadowed
+ = tree_cons (name, old_decl, current_scope->shadowed);
+ }
+ else if (DECL_WEAK_NAME (decl))
+ return;
+ else if (!DECL_WEAK_NAME (old_decl))
+ {
+ tree base_decl = decl, base_old_decl = old_decl;
+ while (TREE_CODE (base_decl) == ALIAS_DECL)
+ base_decl = DECL_ABSTRACT_ORIGIN (base_decl);
+ while (TREE_CODE (base_old_decl) == ALIAS_DECL)
+ base_old_decl = DECL_ABSTRACT_ORIGIN (base_old_decl);
+ /* Note that duplicate definitions are allowed for set elements
+ of similar set modes. See Z200 (1988) 12.2.2.
+ However, if the types are identical, we are defining the
+ same name multiple times in the same SET, which is naughty. */
+ if (!quiet && base_decl != base_old_decl)
+ {
+ if (TREE_CODE (base_decl) != CONST_DECL
+ || TREE_CODE (base_old_decl) != CONST_DECL
+ || !CH_DECL_ENUM (base_decl)
+ || !CH_DECL_ENUM (base_old_decl)
+ || TREE_TYPE (base_decl) == TREE_TYPE (base_old_decl)
+ || !CH_SIMILAR (TREE_TYPE (base_decl),
+ TREE_TYPE(base_old_decl)))
+ {
+ error_with_decl (decl, "duplicate definition `%s'");
+ error_with_decl (old_decl, "previous definition of `%s'");
+ }
+ }
+ }
+ IDENTIFIER_LOCAL_VALUE (name) = decl;
+ }
+ /* Should be redundant most of the time ... */
+ set_nesting_level (decl, current_nesting_level);
+}
+
+/* Return tree_cons (NULL_TREE, ELEMENT, LIST) unless ELEMENT
+ is already in LIST, in which case return LIST. */
+
+static tree
+maybe_acons (element, list)
+ tree element, list;
+{
+ tree pair;
+ for (pair = list; pair; pair = TREE_CHAIN (pair))
+ if (element == TREE_VALUE (pair))
+ return list;
+ return tree_cons (NULL_TREE, element, list);
+}
+
+struct path
+{
+ struct path *prev;
+ tree node;
+};
+
+/* Look for implied types (enumeral types) implied by TYPE (a decl or type).
+ Add these to list.
+ Use old_path to guard against cycles. */
+
+tree
+find_implied_types (type, old_path, list)
+ tree type;
+ struct path *old_path;
+ tree list;
+{
+ struct path path[1], *link;
+ if (type == NULL_TREE)
+ return list;
+ path[0].prev = old_path;
+ path[0].node = type;
+
+ /* Check for a cycle. Something more clever might be appropriate. FIXME? */
+ for (link = old_path; link; link = link->prev)
+ if (link->node == type)
+ return list;
+
+ switch (TREE_CODE (type))
+ {
+ case ENUMERAL_TYPE:
+ return maybe_acons (type, list);
+ case LANG_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case INTEGER_TYPE:
+ return find_implied_types (TREE_TYPE (type), path, list);
+ case SET_TYPE:
+ return find_implied_types (TYPE_DOMAIN (type), path, list);
+ case FUNCTION_TYPE:
+#if 0
+ case PROCESS_TYPE:
+#endif
+ { tree t;
+ list = find_implied_types (TREE_TYPE (type), path, list);
+ for (t = TYPE_ARG_TYPES (type); t != NULL_TREE; t = TREE_CHAIN (t))
+ list = find_implied_types (TREE_VALUE (t), path, list);
+ return list;
+ }
+ case ARRAY_TYPE:
+ list = find_implied_types (TYPE_DOMAIN (type), path, list);
+ return find_implied_types (TREE_TYPE (type), path, list);
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ { tree fields;
+ for (fields = TYPE_FIELDS (type); fields != NULL_TREE;
+ fields = TREE_CHAIN (fields))
+ list = find_implied_types (TREE_TYPE (fields), path, list);
+ return list;
+ }
+
+ case IDENTIFIER_NODE:
+ return find_implied_types (lookup_name (type), path, list);
+ break;
+ case ALIAS_DECL:
+ return find_implied_types (DECL_ABSTRACT_ORIGIN (type), path, list);
+ case VAR_DECL:
+ case FUNCTION_DECL:
+ case TYPE_DECL:
+ return find_implied_types (TREE_TYPE (type), path, list);
+ default:
+ return list;
+ }
+}
+
+/* Make declarations in current scope visible.
+ Also, expand SEIZEs, and make correspondong ALIAS_DECLs visible. */
+
+static void
+push_scope_decls (quiet)
+ int quiet; /* If 1, we're pre-scanning, so suppress errors. */
+{
+ tree decl;
+
+ /* First make everything except 'SEIZE ALL' names visible, before
+ handling 'SEIZE ALL'. (This makes it easier to check 'seizable'). */
+ for (decl = current_scope->remembered_decls; decl; decl = TREE_CHAIN (decl))
+ {
+ if (TREE_CODE (decl) == ALIAS_DECL)
+ {
+ if (DECL_POSTFIX_ALL (decl))
+ continue;
+ if (DECL_ABSTRACT_ORIGIN (decl) == NULL_TREE)
+ {
+ tree val = lookup_name_for_seizing (decl);
+ if (val == NULL_TREE)
+ {
+ error_with_file_and_line
+ (DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl),
+ "cannot SEIZE `%s'",
+ IDENTIFIER_POINTER (DECL_OLD_NAME (decl)));
+ val = error_mark_node;
+ }
+ DECL_ABSTRACT_ORIGIN (decl) = val;
+ }
+ }
+ proclaim_decl (decl, quiet);
+ }
+
+ pushdecllist (current_scope->granted_decls, quiet);
+
+ /* Now handle SEIZE ALLs. */
+ for (decl = current_scope->remembered_decls; decl; )
+ {
+ tree next_decl = TREE_CHAIN (decl);
+ if (TREE_CODE (decl) == ALIAS_DECL
+ && DECL_ABSTRACT_ORIGIN (decl) == NULL_TREE
+ && DECL_POSTFIX_ALL (decl))
+ {
+ /* We saw a "SEIZE ALL". Replace it be a SEIZE for each
+ declaration visible in the surrounding scope.
+ Note that this complicates get_next_decl(). */
+ tree candidate;
+ tree last_new_alias = decl;
+ DECL_ABSTRACT_ORIGIN (decl) = error_mark_node;
+ if (current_scope->enclosing == global_scope)
+ candidate = outer_decls;
+ else
+ candidate = current_scope->enclosing->decls;
+ for ( ; candidate; candidate = TREE_CHAIN (candidate))
+ {
+ tree seizename = DECL_NAME (candidate);
+ tree new_name;
+ tree new_alias;
+ if (!seizename)
+ continue;
+ new_name = decl_check_rename (decl, seizename);
+ if (!new_name)
+ continue;
+
+ /* Check if candidate is seizable. */
+ if (lookup_name (new_name) != NULL_TREE)
+ continue;
+
+ new_alias = build_alias_decl (NULL_TREE,NULL_TREE, new_name);
+ TREE_CHAIN (new_alias) = TREE_CHAIN (last_new_alias);
+ TREE_CHAIN (last_new_alias) = new_alias;
+ last_new_alias = new_alias;
+ DECL_ABSTRACT_ORIGIN (new_alias) = candidate;
+ DECL_SOURCE_LINE (new_alias) = 0;
+
+ proclaim_decl (new_alias, quiet);
+ }
+ }
+ decl = next_decl;
+ }
+
+ /* Link current_scope->remembered_decls at the head of the
+ current_scope->decls list (just like pushdecllist, but
+ without calling proclaim_decl, since we've already done that). */
+ if ((decl = current_scope->remembered_decls) != NULL_TREE)
+ {
+ while (TREE_CHAIN (decl) != NULL_TREE)
+ decl = TREE_CHAIN (decl);
+ TREE_CHAIN (decl) = current_scope->decls;
+ current_scope->decls = current_scope->remembered_decls;
+ }
+}
+
+static void
+pop_scope_decls (decls_limit, shadowed_limit)
+ tree decls_limit, shadowed_limit;
+{
+ /* Remove the temporary bindings we made. */
+ tree link = current_scope->shadowed;
+ tree decl = current_scope->decls;
+ if (decl != decls_limit)
+ {
+ while (decl != decls_limit)
+ {
+ tree next = TREE_CHAIN (decl);
+ if (DECL_NAME (decl))
+ {
+ /* If the ident. was used or addressed via a local extern decl,
+ don't forget that fact. */
+ if (DECL_EXTERNAL (decl))
+ {
+ if (TREE_USED (decl))
+ TREE_USED (DECL_NAME (decl)) = 1;
+ if (TREE_ADDRESSABLE (decl))
+ TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (decl)) = 1;
+ }
+ IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) = 0;
+ }
+ if (next == decls_limit)
+ {
+ TREE_CHAIN (decl) = NULL_TREE;
+ break;
+ }
+ decl = next;
+ }
+ current_scope->decls = decls_limit;
+ }
+
+ /* Restore all name-meanings of the outer levels
+ that were shadowed by this level. */
+ for ( ; link != shadowed_limit; link = TREE_CHAIN (link))
+ IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+ current_scope->shadowed = shadowed_limit;
+}
+
+/* Return list of weak names (as ALIAS_DECLs) implied by IMPLIED_TYPES. */
+
+static tree
+build_implied_names (implied_types)
+ tree implied_types;
+{
+ tree aliases = NULL_TREE;
+
+ for ( ; implied_types; implied_types = TREE_CHAIN (implied_types))
+ {
+ tree enum_type = TREE_VALUE (implied_types);
+ tree link = TYPE_VALUES (enum_type);
+ if (TREE_CODE (enum_type) != ENUMERAL_TYPE)
+ abort ();
+
+ for ( ; link; link = TREE_CHAIN (link))
+ {
+ /* We don't handle renaming/prefixes (Blue Book p 163) FIXME */
+ /* Note that before enum_type is laid out, TREE_VALUE (link)
+ is a CONST_DECL, while after it is laid out,
+ TREE_VALUE (link) is an INTEGER_CST. Either works. */
+ tree alias
+ = build_alias_decl (NULL_TREE, NULL_TREE, TREE_PURPOSE (link));
+ DECL_ABSTRACT_ORIGIN (alias) = TREE_VALUE (link);
+ DECL_WEAK_NAME (alias) = 1;
+ TREE_CHAIN (alias) = aliases;
+ aliases = alias;
+ /* Strictlt speaking, we should have a pointer from the alias
+ to the decl, so we can make sure that the alias is only
+ visible when the decl is. FIXME */
+ }
+ }
+ return aliases;
+}
+
+static void
+bind_sub_modules (do_weak)
+ int do_weak;
+{
+ tree decl;
+ int save_module_nesting_level = current_module_nesting_level;
+ struct scope *saved_scope = current_scope;
+ struct scope *nested_module = current_scope->first_child_module;
+
+ while (nested_module != NULL)
+ {
+ tree saved_shadowed = nested_module->shadowed;
+ tree saved_decls = nested_module->decls;
+ current_nesting_level++;
+ current_scope = nested_module;
+ current_module_nesting_level = current_nesting_level;
+ if (do_weak == 0)
+ push_scope_decls (1);
+ else
+ {
+ tree implied_types = NULL_TREE;
+ /* Push weak names implied by decls in current_scope. */
+ for (decl = current_scope->remembered_decls;
+ decl; decl = TREE_CHAIN (decl))
+ if (TREE_CODE (decl) == ALIAS_DECL)
+ implied_types = find_implied_types (decl, NULL, implied_types);
+ for (decl = current_scope->granted_decls;
+ decl; decl = TREE_CHAIN (decl))
+ implied_types = find_implied_types (decl, NULL, implied_types);
+ current_scope->weak_decls = build_implied_names (implied_types);
+ pushdecllist (current_scope->weak_decls, 1);
+ }
+
+ bind_sub_modules (do_weak);
+ for (decl = current_scope->remembered_decls;
+ decl; decl = TREE_CHAIN (decl))
+ satisfy_decl (decl, 1);
+ pop_scope_decls (saved_decls, saved_shadowed);
+ current_nesting_level--;
+ nested_module = nested_module->next_sibling_module;
+ }
+
+ current_scope = saved_scope;
+ current_module_nesting_level = save_module_nesting_level;
+}
+
+/* Enter a new binding level.
+ If two_pass==0, assume we are called from non-Chill-specific parts
+ of the compiler. These parts assume a single pass.
+ If two_pass==1, we're called from Chill parts of the compiler.
+*/
+
+void
+pushlevel (two_pass)
+ int two_pass;
+{
+ register struct scope *newlevel;
+
+ current_nesting_level++;
+ if (!two_pass)
+ {
+ newlevel = (struct scope *)xmalloc (sizeof(struct scope));
+ *newlevel = clear_scope;
+ newlevel->enclosing = current_scope;
+ current_scope = newlevel;
+ }
+ else if (pass < 2)
+ {
+ newlevel = (struct scope *)permalloc (sizeof(struct scope));
+ *newlevel = clear_scope;
+ newlevel->tail_child_module = &newlevel->first_child_module;
+ newlevel->enclosing = current_scope;
+ current_scope = newlevel;
+ last_scope->next = newlevel;
+ last_scope = newlevel;
+ }
+ else /* pass == 2 */
+ {
+ tree decl;
+ newlevel = current_scope = last_scope = last_scope->next;
+
+ push_scope_decls (0);
+ pushdecllist (current_scope->weak_decls, 0);
+
+ /* If this is not a module scope, scan ahead for locally nested
+ modules. (If this is a module, that's already done.) */
+ if (!current_scope->module_flag)
+ {
+ bind_sub_modules (0);
+ bind_sub_modules (1);
+ }
+
+ for (decl = current_scope->remembered_decls;
+ decl; decl = TREE_CHAIN (decl))
+ satisfy_decl (decl, 0);
+ }
+
+ /* Add this level to the front of the chain (stack) of levels that
+ are active. */
+
+ newlevel->level_chain = current_scope;
+ current_scope = newlevel;
+
+ newlevel->two_pass = two_pass;
+}
+
+/* Exit a binding level.
+ Pop the level off, and restore the state of the identifier-decl mappings
+ that were in effect when this level was entered.
+
+ If KEEP is nonzero, this level had explicit declarations, so
+ and create a "block" (a BLOCK node) for the level
+ to record its declarations and subblocks for symbol table output.
+
+ If FUNCTIONBODY is nonzero, this level is the body of a function,
+ so create a block as if KEEP were set and also clear out all
+ label names.
+
+ If REVERSE is nonzero, reverse the order of decls before putting
+ them into the BLOCK. */
+
+tree
+poplevel (keep, reverse, functionbody)
+ int keep;
+ int reverse;
+ int functionbody;
+{
+ register tree link;
+ /* The chain of decls was accumulated in reverse order.
+ Put it into forward order, just for cleanliness. */
+ tree decls;
+ tree subblocks;
+ tree block = 0;
+ tree decl;
+ int block_previously_created;
+
+ if (current_scope == NULL)
+ return error_mark_node;
+
+ subblocks = current_scope->blocks;
+
+ /* Get the decls in the order they were written.
+ Usually current_scope->decls is in reverse order.
+ But parameter decls were previously put in forward order. */
+
+ if (reverse)
+ current_scope->decls
+ = decls = nreverse (current_scope->decls);
+ else
+ decls = current_scope->decls;
+
+ if (pass == 2)
+ {
+ /* Output any nested inline functions within this block
+ if they weren't already output. */
+
+ for (decl = decls; decl; decl = TREE_CHAIN (decl))
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && ! TREE_ASM_WRITTEN (decl)
+ && DECL_INITIAL (decl) != 0
+ && TREE_ADDRESSABLE (decl))
+ {
+ /* If this decl was copied from a file-scope decl
+ on account of a block-scope extern decl,
+ propagate TREE_ADDRESSABLE to the file-scope decl. */
+ if (DECL_ABSTRACT_ORIGIN (decl) != 0)
+ TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1;
+ else
+ {
+ push_function_context ();
+ output_inline_function (decl);
+ pop_function_context ();
+ }
+ }
+
+ /* Clear out the meanings of the local variables of this level. */
+ pop_scope_decls (NULL_TREE, NULL_TREE);
+
+ /* If there were any declarations or structure tags in that level,
+ or if this level is a function body,
+ create a BLOCK to record them for the life of this function. */
+
+ block = 0;
+ block_previously_created = (current_scope->this_block != 0);
+ if (block_previously_created)
+ block = current_scope->this_block;
+ else if (keep || functionbody)
+ block = make_node (BLOCK);
+ if (block != 0)
+ {
+ tree *ptr;
+ BLOCK_VARS (block) = decls;
+
+ /* Splice out ALIAS_DECL and LABEL_DECLs,
+ since instantiate_decls can't handle them. */
+ for (ptr = &BLOCK_VARS (block); *ptr; )
+ {
+ decl = *ptr;
+ if (TREE_CODE (decl) == ALIAS_DECL
+ || TREE_CODE (decl) == LABEL_DECL)
+ *ptr = TREE_CHAIN (decl);
+ else
+ ptr = &TREE_CHAIN(*ptr);
+ }
+
+ BLOCK_SUBBLOCKS (block) = subblocks;
+ remember_end_note (block);
+ }
+
+ /* In each subblock, record that this is its superior. */
+
+ for (link = subblocks; link; link = TREE_CHAIN (link))
+ BLOCK_SUPERCONTEXT (link) = block;
+
+ }
+
+ /* If the level being exited is the top level of a function,
+ check over all the labels, and clear out the current
+ (function local) meanings of their names. */
+
+ if (pass == 2 && functionbody)
+ {
+ /* If this is the top level block of a function,
+ the vars are the function's parameters.
+ Don't leave them in the BLOCK because they are
+ found in the FUNCTION_DECL instead. */
+
+ BLOCK_VARS (block) = 0;
+
+#if 0
+ /* Clear out the definitions of all label names,
+ since their scopes end here,
+ and add them to BLOCK_VARS. */
+
+ for (link = named_labels; link; link = TREE_CHAIN (link))
+ {
+ register tree label = TREE_VALUE (link);
+
+ if (DECL_INITIAL (label) == 0)
+ {
+ error_with_decl (label, "label `%s' used but not defined");
+ /* Avoid crashing later. */
+ define_label (input_filename, lineno,
+ DECL_NAME (label));
+ }
+ else if (warn_unused && !TREE_USED (label))
+ warning_with_decl (label, "label `%s' defined but not used");
+ IDENTIFIER_LABEL_VALUE (DECL_NAME (label)) = 0;
+
+ /* Put the labels into the "variables" of the
+ top-level block, so debugger can see them. */
+ TREE_CHAIN (label) = BLOCK_VARS (block);
+ BLOCK_VARS (block) = label;
+ }
+#endif
+ }
+
+ if (pass < 2)
+ {
+ current_scope->remembered_decls
+ = nreverse (current_scope->remembered_decls);
+ current_scope->granted_decls = nreverse (current_scope->granted_decls);
+ }
+
+ current_scope = current_scope->enclosing;
+ current_nesting_level--;
+
+ if (pass < 2)
+ {
+ return NULL_TREE;
+ }
+
+ /* Dispose of the block that we just made inside some higher level. */
+ if (functionbody)
+ DECL_INITIAL (current_function_decl) = block;
+ else if (block)
+ {
+ if (!block_previously_created)
+ current_scope->blocks
+ = chainon (current_scope->blocks, block);
+ }
+ /* If we did not make a block for the level just exited,
+ any blocks made for inner levels
+ (since they cannot be recorded as subblocks in that level)
+ must be carried forward so they will later become subblocks
+ of something else. */
+ else if (subblocks)
+ current_scope->blocks
+ = chainon (current_scope->blocks, subblocks);
+
+ if (block)
+ TREE_USED (block) = 1;
+ return block;
+}
+
+/* Delete the node BLOCK from the current binding level.
+ This is used for the block inside a stmt expr ({...})
+ so that the block can be reinserted where appropriate. */
+
+void
+delete_block (block)
+ tree block;
+{
+ tree t;
+ if (current_scope->blocks == block)
+ current_scope->blocks = TREE_CHAIN (block);
+ for (t = current_scope->blocks; t;)
+ {
+ if (TREE_CHAIN (t) == block)
+ TREE_CHAIN (t) = TREE_CHAIN (block);
+ else
+ t = TREE_CHAIN (t);
+ }
+ TREE_CHAIN (block) = NULL;
+ /* Clear TREE_USED which is always set by poplevel.
+ The flag is set again if insert_block is called. */
+ TREE_USED (block) = 0;
+}
+
+/* Insert BLOCK at the end of the list of subblocks of the
+ current binding level. This is used when a BIND_EXPR is expanded,
+ to handle the BLOCK node inside teh BIND_EXPR. */
+
+void
+insert_block (block)
+ tree block;
+{
+ TREE_USED (block) = 1;
+ current_scope->blocks
+ = chainon (current_scope->blocks, block);
+}
+
+/* Set the BLOCK node for the innermost scope
+ (the one we are currently in). */
+
+void
+set_block (block)
+ register tree block;
+{
+ current_scope->this_block = block;
+}
+
+/* Record a decl-node X as belonging to the current lexical scope.
+ Check for errors (such as an incompatible declaration for the same
+ name already seen in the same scope).
+
+ Returns either X or an old decl for the same name.
+ If an old decl is returned, it may have been smashed
+ to agree with what X says. */
+
+tree
+pushdecl (x)
+ tree x;
+{
+ register tree t;
+ register tree name = DECL_NAME (x);
+ register struct scope *b = current_scope;
+
+ DECL_CONTEXT (x) = current_function_decl;
+ /* A local extern declaration for a function doesn't constitute nesting.
+ A local auto declaration does, since it's a forward decl
+ for a nested function coming later. */
+ if (TREE_CODE (x) == FUNCTION_DECL && DECL_INITIAL (x) == 0
+ && DECL_EXTERNAL (x))
+ DECL_CONTEXT (x) = 0;
+
+ if (name)
+ proclaim_decl (x, 0);
+
+ if (TREE_CODE (x) == TYPE_DECL && DECL_SOURCE_LINE (x) == 0
+ && TYPE_NAME (TREE_TYPE (x)) == 0)
+ TYPE_NAME (TREE_TYPE (x)) = x;
+
+ /* Put decls on list in reverse order.
+ We will reverse them later if necessary. */
+ TREE_CHAIN (x) = b->decls;
+ b->decls = x;
+
+ return x;
+}
+
+/* Make DECLS (a chain of decls) visible in the current_scope. */
+
+static void
+pushdecllist (decls, quiet)
+ tree decls;
+ int quiet;
+{
+ tree last = NULL_TREE, decl;
+
+ for (decl = decls; decl != NULL_TREE;
+ last = decl, decl = TREE_CHAIN (decl))
+ {
+ proclaim_decl (decl, quiet);
+ }
+
+ if (last)
+ {
+ TREE_CHAIN (last) = current_scope->decls;
+ current_scope->decls = decls;
+ }
+}
+
+/* Like pushdecl, only it places X in GLOBAL_SCOPE, if appropriate. */
+
+tree
+pushdecl_top_level (x)
+ tree x;
+{
+ register tree t;
+ register struct scope *b = current_scope;
+
+ current_scope = global_scope;
+ t = pushdecl (x);
+ current_scope = b;
+ return t;
+}
+
+/* Define a label, specifying the location in the source file.
+ Return the LABEL_DECL node for the label, if the definition is valid.
+ Otherwise return 0. */
+
+tree
+define_label (filename, line, name)
+ char *filename;
+ int line;
+ tree name;
+{
+ tree decl;
+
+ if (pass == 1)
+ {
+ decl = build_decl (LABEL_DECL, name, void_type_node);
+
+ /* A label not explicitly declared must be local to where it's ref'd. */
+ DECL_CONTEXT (decl) = current_function_decl;
+
+ DECL_MODE (decl) = VOIDmode;
+
+ /* Say where one reference is to the label,
+ for the sake of the error if it is not defined. */
+ DECL_SOURCE_LINE (decl) = line;
+ DECL_SOURCE_FILE (decl) = filename;
+
+ /* Mark label as having been defined. */
+ DECL_INITIAL (decl) = error_mark_node;
+
+ DECL_ACTION_NESTING_LEVEL (decl) = action_nesting_level;
+
+ save_decl (decl);
+ }
+ else
+ {
+ decl = get_next_decl ();
+ /* Make sure every label has an rtx. */
+
+ label_rtx (decl);
+ expand_label (decl);
+ }
+ return decl;
+}
+
+/* Return the list of declarations of the current level.
+ Note that this list is in reverse order unless/until
+ you nreverse it; and when you do nreverse it, you must
+ store the result back using `storedecls' or you will lose. */
+
+tree
+getdecls ()
+{
+ /* This is a kludge, so that dbxout_init can get the predefined types,
+ which are in the builtin_scope, though when it is called,
+ the current_scope is the global_scope.. */
+ if (current_scope == global_scope)
+ return builtin_scope.decls;
+ return current_scope->decls;
+}
+
+#if 0
+/* Store the list of declarations of the current level.
+ This is done for the parameter declarations of a function being defined,
+ after they are modified in the light of any missing parameters. */
+
+static void
+storedecls (decls)
+ tree decls;
+{
+ current_scope->decls = decls;
+}
+#endif
+
+/* Look up NAME in the current binding level and its superiors
+ in the namespace of variables, functions and typedefs.
+ Return a ..._DECL node of some kind representing its definition,
+ or return 0 if it is undefined. */
+
+tree
+lookup_name (name)
+ tree name;
+{
+ register tree val = IDENTIFIER_LOCAL_VALUE (name);
+
+ if (val == NULL_TREE)
+ return NULL_TREE;
+ if (TREE_CODE_CLASS (TREE_CODE (val)) == 'c')
+ return val;
+ if (DECL_NESTING_LEVEL (val) > BUILTIN_NESTING_LEVEL
+ && DECL_NESTING_LEVEL (val) < current_module_nesting_level)
+ {
+ return NULL_TREE;
+ }
+ while (TREE_CODE (val) == ALIAS_DECL)
+ {
+ val = DECL_ABSTRACT_ORIGIN (val);
+ if (TREE_CODE (val) == ERROR_MARK)
+ return NULL_TREE;
+ }
+ if (TREE_CODE (val) == BASED_DECL)
+ {
+ return build_chill_indirect_ref (DECL_ABSTRACT_ORIGIN (val),
+ TREE_TYPE (val), 1);
+ }
+ if (TREE_CODE (val) == WITH_DECL)
+ return build_component_ref (DECL_ABSTRACT_ORIGIN (val), DECL_NAME (val));
+ return val;
+}
+
+/* Similar to `lookup_name' but look only at current binding level. */
+
+tree
+lookup_name_current_level (name)
+ tree name;
+{
+ register tree val = IDENTIFIER_LOCAL_VALUE (name);
+ if (val && DECL_NESTING_LEVEL (val) == current_nesting_level)
+ return val;
+ return NULL_TREE;
+}
+
+tree
+lookup_name_for_seizing (seize_decl)
+ tree seize_decl;
+{
+ tree name = DECL_OLD_NAME (seize_decl);
+ register tree val;
+ val = IDENTIFIER_LOCAL_VALUE (name);
+ if (val == NULL_TREE || DECL_NESTING_LEVEL (val) == BUILTIN_NESTING_LEVEL)
+ {
+ val = IDENTIFIER_OUTER_VALUE (name);
+ if (val == NULL_TREE)
+ return NULL_TREE;
+ if (TREE_CHAIN (val) && DECL_NAME (TREE_CHAIN (val)) == name)
+ { /* More than one decl with the same name has been granted
+ into the same global scope. Pick the one (we hope) that
+ came from a seizefile the matches the most recent
+ seizefile (as given by DECL_SEIZEFILE (seize_decl).) */
+ tree d, best = NULL_TREE;
+ for (d = val; d != NULL_TREE && DECL_NAME (d) == name;
+ d = TREE_CHAIN (d))
+ if (DECL_SEIZEFILE (d) == DECL_SEIZEFILE (seize_decl))
+ {
+ if (best)
+ {
+ error_with_decl (seize_decl,
+ "ambiguous choice for seize `%s' -");
+ error_with_decl (best, " - can seize this `%s' -");
+ error_with_decl (d, " - or this granted decl `%s'");
+ return NULL_TREE;
+ }
+ best = d;
+ }
+ if (best == NULL_TREE)
+ {
+ error_with_decl (seize_decl,
+ "ambiguous choice for seize `%s' -");
+ error_with_decl (val, " - can seize this `%s' -");
+ error_with_decl (TREE_CHAIN (val),
+ " - or this granted decl `%s'");
+ return NULL_TREE;
+ }
+ val = best;
+ }
+ }
+#if 0
+ /* We don't need to handle this, as long as we
+ resolve the seize targets before pushing them. */
+ if (DECL_NESTING_LEVEL (val) >= current_module_nesting_level)
+ {
+ /* VAL was declared inside current module. We need something
+ from the scope *enclosing* the current module, so search
+ through the shadowed declarations. */
+ /* TODO - FIXME */
+ }
+#endif
+ if (current_module && current_module->prev_module
+ && DECL_NESTING_LEVEL (val)
+ < current_module->prev_module->nesting_level)
+ {
+
+ /* It's declared in a scope enclosing the module enclosing
+ the current module. Hence it's not visible. */
+ return NULL_TREE;
+ }
+ while (TREE_CODE (val) == ALIAS_DECL)
+ {
+ val = DECL_ABSTRACT_ORIGIN (val);
+ if (TREE_CODE (val) == ERROR_MARK)
+ return NULL_TREE;
+ }
+ return val;
+}
+
+/* Create the predefined scalar types of C,
+ and some nodes representing standard constants (0, 1, (void *)0).
+ Initialize the global binding level.
+ Make definitions for built-in primitive functions. */
+
+void
+init_decl_processing ()
+{
+ int wchar_type_size;
+ tree bool_ftype_int_ptr_int;
+ tree bool_ftype_int_ptr_int_int;
+ tree bool_ftype_luns_ptr_luns_long;
+ tree bool_ftype_luns_ptr_luns_long_ptr_int;
+ tree bool_ftype_ptr_int_ptr_int;
+ tree bool_ftype_ptr_int_ptr_int_int;
+ tree find_bit_ftype;
+ tree bool_ftype_ptr_ptr_int;
+ tree bool_ftype_ptr_ptr_luns;
+ tree bool_ftype_ptr_ptr_ptr_luns;
+ tree endlink;
+ tree int_ftype_int;
+ tree int_ftype_int_int;
+ tree int_ftype_int_ptr_int;
+ tree int_ftype_ptr;
+ tree int_ftype_ptr_int;
+ tree int_ftype_ptr_int_int_ptr_int;
+ tree int_ftype_ptr_luns_long_ptr_int;
+ tree int_ftype_ptr_ptr_int;
+ tree int_ftype_ptr_ptr_luns;
+ tree long_ftype_ptr_luns;
+ tree memcpy_ftype;
+ tree memcmp_ftype;
+ tree ptr_ftype_ptr_int_int;
+ tree ptr_ftype_ptr_ptr_int;
+ tree ptr_ftype_ptr_ptr_int_ptr_int;
+ tree real_ftype_real;
+ tree temp;
+ tree void_ftype_cptr_cptr_int;
+ tree void_ftype_long_int_ptr_int_ptr_int;
+ tree void_ftype_ptr;
+ tree void_ftype_ptr_int_int_int_int;
+ tree void_ftype_ptr_int_ptr_int_int_int;
+ tree void_ftype_ptr_int_ptr_int_ptr_int;
+ tree void_ftype_ptr_luns_long_long_bool_ptr_int;
+ tree void_ftype_ptr_luns_ptr_luns_luns_luns;
+ tree void_ftype_ptr_ptr_ptr_int;
+ tree void_ftype_ptr_ptr_ptr_luns;
+ tree void_ftype_refptr_int_ptr_int;
+ tree void_ftype_void;
+ tree void_ftype_ptr_ptr_int;
+ tree void_ftype_ptr_luns_luns_cptr_luns_luns_luns;
+ tree ptr_ftype_luns_ptr_int;
+ tree double_ftype_double;
+
+ extern int set_alignment;
+
+ /* allow 0-255 enums to occupy only a byte */
+ flag_short_enums = 1;
+
+ current_function_decl = NULL;
+
+ set_alignment = BITS_PER_UNIT;
+
+ ALL_POSTFIX = get_identifier ("*");
+ string_index_type_dummy = get_identifier("%string-index%");
+
+ var_length_id = get_identifier (VAR_LENGTH);
+ var_data_id = get_identifier (VAR_DATA);
+
+ /* This is the *C* int type. */
+ integer_type_node = make_signed_type (INT_TYPE_SIZE);
+
+ if (CHILL_INT_IS_SHORT)
+ long_integer_type_node = integer_type_node;
+ else
+ long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
+
+ unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
+ long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
+ long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
+ long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
+
+ /* `unsigned long' is the standard type for sizeof.
+ Note that stddef.h uses `unsigned long',
+ and this must agree, even of long and int are the same size. */
+#ifndef SIZE_TYPE
+ sizetype = long_unsigned_type_node;
+#else
+ {
+ char *size_type_c_name = SIZE_TYPE;
+ if (strncmp (size_type_c_name, "long long ", 10) == 0)
+ sizetype = long_long_unsigned_type_node;
+ else if (strncmp (size_type_c_name, "long ", 5) == 0)
+ sizetype = long_unsigned_type_node;
+ else
+ sizetype = unsigned_type_node;
+ }
+#endif
+
+ TREE_TYPE (TYPE_SIZE (integer_type_node)) = sizetype;
+ TREE_TYPE (TYPE_SIZE (unsigned_type_node)) = sizetype;
+ TREE_TYPE (TYPE_SIZE (long_unsigned_type_node)) = sizetype;
+ TREE_TYPE (TYPE_SIZE (long_integer_type_node)) = sizetype;
+ TREE_TYPE (TYPE_SIZE (long_long_integer_type_node)) = sizetype;
+ TREE_TYPE (TYPE_SIZE (long_long_unsigned_type_node)) = sizetype;
+
+ error_mark_node = make_node (ERROR_MARK);
+ TREE_TYPE (error_mark_node) = error_mark_node;
+
+ short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
+ short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
+ signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
+ unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
+ intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
+ intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
+ intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
+ intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
+ intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
+ unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
+ unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
+ unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode));
+ unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
+ unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+
+ float_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_FLOAT],
+ float_type_node));
+ layout_type (float_type_node);
+
+ double_type_node = make_node (REAL_TYPE);
+ if (flag_short_double)
+ TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE;
+ else
+ TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_DOUBLE],
+ double_type_node));
+ layout_type (double_type_node);
+
+ long_double_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
+ layout_type (long_double_type_node);
+
+ complex_integer_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_integer_type_node) = integer_type_node;
+ layout_type (complex_integer_type_node);
+
+ complex_float_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_float_type_node) = float_type_node;
+ layout_type (complex_float_type_node);
+
+ complex_double_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_double_type_node) = double_type_node;
+ layout_type (complex_double_type_node);
+
+ complex_long_double_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
+ layout_type (complex_long_double_type_node);
+
+ integer_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (integer_zero_node) = integer_type_node;
+ integer_one_node = build_int_2 (1, 0);
+ TREE_TYPE (integer_one_node) = integer_type_node;
+ integer_minus_one_node = build_int_2 (-1, -1);
+ TREE_TYPE (integer_minus_one_node) = integer_type_node;
+
+ size_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (size_zero_node) = sizetype;
+ size_one_node = build_int_2 (1, 0);
+ TREE_TYPE (size_one_node) = sizetype;
+
+ void_type_node = make_node (VOID_TYPE);
+ pushdecl (build_decl (TYPE_DECL,
+ ridpointers[(int) RID_VOID], void_type_node));
+ layout_type (void_type_node); /* Uses integer_zero_node */
+ /* We are not going to have real types in C with less than byte alignment,
+ so we might as well not have any types that claim to have it. */
+ TYPE_ALIGN (void_type_node) = BITS_PER_UNIT;
+
+ null_pointer_node = build_int_2 (0, 0);
+ TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
+ layout_type (TREE_TYPE (null_pointer_node));
+
+ /* This is for wide string constants. */
+ wchar_type_node = short_unsigned_type_node;
+ wchar_type_size = TYPE_PRECISION (wchar_type_node);
+ signed_wchar_type_node = type_for_size (wchar_type_size, 0);
+ unsigned_wchar_type_node = type_for_size (wchar_type_size, 1);
+
+ default_function_type
+ = build_function_type (integer_type_node, NULL_TREE);
+
+ ptr_type_node = build_pointer_type (void_type_node);
+ const_ptr_type_node
+ = build_pointer_type (build_type_variant (void_type_node, 1, 0));
+
+ void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+ boolean_type_node = make_node (BOOLEAN_TYPE);
+ TYPE_PRECISION (boolean_type_node) = 1;
+ fixup_unsigned_type (boolean_type_node);
+ boolean_false_node = TYPE_MIN_VALUE (boolean_type_node);
+ boolean_true_node = TYPE_MAX_VALUE (boolean_type_node);
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_BOOL],
+ boolean_type_node));
+
+ /* TRUE and FALSE have the BOOL derived class */
+ CH_DERIVED_FLAG (boolean_true_node) = 1;
+ CH_DERIVED_FLAG (boolean_false_node) = 1;
+
+ signed_boolean_type_node = make_node (BOOLEAN_TYPE);
+ temp = build_int_2 (-1, -1);
+ TREE_TYPE (temp) = signed_boolean_type_node;
+ TYPE_MIN_VALUE (signed_boolean_type_node) = temp;
+ temp = build_int_2 (0, 0);
+ TREE_TYPE (temp) = signed_boolean_type_node;
+ TYPE_MAX_VALUE (signed_boolean_type_node) = temp;
+ layout_type (signed_boolean_type_node);
+
+
+ bitstring_one_type_node = build_bitstring_type (integer_one_node);
+ bit_zero_node = build (CONSTRUCTOR, bitstring_one_type_node, NULL_TREE,
+ NULL_TREE);
+ bit_one_node = build (CONSTRUCTOR, bitstring_one_type_node, NULL_TREE,
+ build_tree_list (NULL_TREE, integer_zero_node));
+
+ char_type_node = make_node (CHAR_TYPE);
+ TYPE_PRECISION (char_type_node) = CHAR_TYPE_SIZE;
+ fixup_unsigned_type (char_type_node);
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_CHAR],
+ char_type_node));
+
+ if (CHILL_INT_IS_SHORT)
+ {
+ chill_integer_type_node = short_integer_type_node;
+ chill_unsigned_type_node = short_unsigned_type_node;
+ }
+ else
+ {
+ chill_integer_type_node = integer_type_node;
+ chill_unsigned_type_node = unsigned_type_node;
+ }
+
+ string_one_type_node = build_string_type (char_type_node, integer_one_node);
+
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_BYTE],
+ signed_char_type_node));
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_UBYTE],
+ unsigned_char_type_node));
+
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_INT],
+ chill_integer_type_node));
+
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_UINT],
+ chill_unsigned_type_node));
+
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_LONG],
+ long_integer_type_node));
+
+ sizetype = long_integer_type_node;
+#if 0
+ ptrdiff_type_node
+ = TREE_TYPE (IDENTIFIER_LOCAL_VALUE (get_identifier (PTRDIFF_TYPE)));
+#endif
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_ULONG],
+ long_unsigned_type_node));
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_REAL],
+ float_type_node));
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_LONG_REAL],
+ double_type_node));
+ pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_PTR],
+ ptr_type_node));
+
+ IDENTIFIER_LOCAL_VALUE (ridpointers[(int)RID_TRUE]) =
+ boolean_true_node;
+ IDENTIFIER_LOCAL_VALUE (ridpointers[(int)RID_FALSE]) =
+ boolean_false_node;
+ IDENTIFIER_LOCAL_VALUE (ridpointers[(int)RID_NULL]) =
+ null_pointer_node;
+
+ /* The second operand is set to non-NULL to distinguish
+ (ELSE) from (*). Used when writing grant files. */
+ case_else_node = build (RANGE_EXPR,
+ NULL_TREE, NULL_TREE, boolean_false_node);
+
+ pushdecl (temp = build_decl (TYPE_DECL,
+ get_identifier ("__tmp_initializer"),
+ build_init_struct ()));
+ DECL_SOURCE_LINE (temp) = 0;
+ initializer_type = TREE_TYPE (temp);
+
+ bcopy (chill_tree_code_type,
+ tree_code_type + (int) LAST_AND_UNUSED_TREE_CODE,
+ (((int) LAST_CHILL_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE)
+ * sizeof (char)));
+ bcopy (chill_tree_code_length,
+ tree_code_length + (int) LAST_AND_UNUSED_TREE_CODE,
+ (((int) LAST_CHILL_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE)
+ * sizeof (int)));
+ bcopy (chill_tree_code_name,
+ tree_code_name + (int) LAST_AND_UNUSED_TREE_CODE,
+ (((int) LAST_CHILL_TREE_CODE - (int) LAST_AND_UNUSED_TREE_CODE)
+ * sizeof (char *)));
+ boolean_code_name = (char **) xmalloc (sizeof (char *) * (int) LAST_CHILL_TREE_CODE);
+ bzero (boolean_code_name, sizeof (char *) * (int) LAST_CHILL_TREE_CODE);
+
+ boolean_code_name[EQ_EXPR] = "=";
+ boolean_code_name[NE_EXPR] = "/=";
+ boolean_code_name[LT_EXPR] = "<";
+ boolean_code_name[GT_EXPR] = ">";
+ boolean_code_name[LE_EXPR] = "<=";
+ boolean_code_name[GE_EXPR] = ">=";
+ boolean_code_name[SET_IN_EXPR] = "in";
+ boolean_code_name[TRUTH_ANDIF_EXPR] = "andif";
+ boolean_code_name[TRUTH_ORIF_EXPR] = "orif";
+ boolean_code_name[TRUTH_AND_EXPR] = "and";
+ boolean_code_name[TRUTH_OR_EXPR] = "or";
+ boolean_code_name[BIT_AND_EXPR] = "and";
+ boolean_code_name[BIT_IOR_EXPR] = "or";
+ boolean_code_name[BIT_XOR_EXPR] = "xor";
+
+ endlink = void_list_node;
+
+ chill_predefined_function_type
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink));
+
+ bool_ftype_int_ptr_int
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+ bool_ftype_int_ptr_int
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))));
+ bool_ftype_int_ptr_int_int
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))));
+ bool_ftype_luns_ptr_luns_long
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, long_integer_type_node,
+ endlink)))));
+ bool_ftype_luns_ptr_luns_long_ptr_int
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, long_integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))));
+ bool_ftype_ptr_ptr_int
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+ bool_ftype_ptr_ptr_luns
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ endlink))));
+ bool_ftype_ptr_ptr_ptr_luns
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ endlink)))));
+ bool_ftype_ptr_int_ptr_int
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))));
+ bool_ftype_ptr_int_ptr_int_int
+ = build_function_type (boolean_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))));
+ find_bit_ftype
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+ int_ftype_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink));
+ int_ftype_int_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)));
+ int_ftype_int_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+ int_ftype_ptr
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ endlink));
+ int_ftype_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)));
+
+ long_ftype_ptr_luns
+ = build_function_type (long_integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ endlink)));
+
+ int_ftype_ptr_int_int_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))));
+
+ int_ftype_ptr_luns_long_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, long_integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))));
+
+ int_ftype_ptr_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+ int_ftype_ptr_ptr_luns
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ endlink))));
+ memcpy_ftype /* memcpy/memmove prototype */
+ = build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, const_ptr_type_node,
+ tree_cons (NULL_TREE, sizetype,
+ endlink))));
+ memcmp_ftype /* memcmp prototype */
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, sizetype,
+ endlink))));
+
+ ptr_ftype_ptr_int_int
+ = build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+ ptr_ftype_ptr_ptr_int
+ = build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+ ptr_ftype_ptr_ptr_int_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))));
+ real_ftype_real
+ = build_function_type (float_type_node,
+ tree_cons (NULL_TREE, float_type_node,
+ endlink));
+
+ void_ftype_ptr
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node, endlink));
+
+ void_ftype_cptr_cptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, const_ptr_type_node,
+ tree_cons (NULL_TREE, const_ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+
+ void_ftype_refptr_int_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, build_reference_type(ptr_type_node),
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))));
+
+ void_ftype_ptr_ptr_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))));
+ void_ftype_ptr_ptr_ptr_luns
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ endlink)))));
+ void_ftype_ptr_int_int_int_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))));
+ void_ftype_ptr_luns_long_long_bool_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, long_integer_type_node,
+ tree_cons (NULL_TREE, long_integer_type_node,
+ tree_cons (NULL_TREE, boolean_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))))));
+ void_ftype_ptr_int_ptr_int_int_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))));
+ void_ftype_ptr_luns_ptr_luns_luns_luns
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ endlink)))))));
+ void_ftype_ptr_int_ptr_int_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))));
+ void_ftype_long_int_ptr_int_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, long_integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))));
+ void_ftype_void
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, void_type_node,
+ endlink));
+
+ void_ftype_ptr_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+
+ void_ftype_ptr_luns_luns_cptr_luns_luns_luns
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, const_ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ endlink))))))));
+
+ ptr_ftype_luns_ptr_int
+ = build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, long_unsigned_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+
+ double_ftype_double
+ = build_function_type (double_type_node,
+ tree_cons (NULL_TREE, double_type_node,
+ endlink));
+
+/* These are compiler-internal function calls, not intended
+ to be directly called by user code */
+ builtin_function ("__allocate", ptr_ftype_luns_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("_allocate_global_memory", void_ftype_refptr_int_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("_allocate_memory", void_ftype_refptr_int_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__andpowerset", bool_ftype_ptr_ptr_ptr_luns,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__bitsetpowerset", void_ftype_ptr_int_int_int_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__cardpowerset", long_ftype_ptr_luns,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__cause_ex1", void_ftype_cptr_cptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__concatstring", ptr_ftype_ptr_ptr_int_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__continue", void_ftype_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__diffpowerset", void_ftype_ptr_ptr_ptr_luns,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__eqpowerset", bool_ftype_ptr_ptr_luns,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__ffsetclrpowerset", find_bit_ftype,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__flsetclrpowerset", find_bit_ftype,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__flsetpowerset", int_ftype_ptr_luns_long_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__ffsetpowerset", int_ftype_ptr_luns_long_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__inbitstring", bool_ftype_luns_ptr_luns_long_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__inpowerset", bool_ftype_luns_ptr_luns_long,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__lepowerset", bool_ftype_ptr_ptr_luns,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__ltpowerset", bool_ftype_ptr_ptr_luns,
+ NOT_BUILT_IN, NULL_PTR);
+ /* Currently under experimentation. */
+ builtin_function ("memmove", memcpy_ftype,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("memcmp", memcmp_ftype,
+ NOT_BUILT_IN, NULL_PTR);
+
+ /* this comes from c-decl.c (init_decl_processing) */
+ builtin_function ("__builtin_alloca",
+ build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE,
+ sizetype,
+ endlink)),
+ BUILT_IN_ALLOCA, "alloca");
+
+ builtin_function ("memset", ptr_ftype_ptr_int_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__notpowerset", bool_ftype_ptr_ptr_luns,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__orpowerset", bool_ftype_ptr_ptr_ptr_luns,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__psslice", void_ftype_ptr_int_ptr_int_int_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__pscpy", void_ftype_ptr_luns_luns_cptr_luns_luns_luns,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("_return_memory", void_ftype_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__setbitpowerset", void_ftype_ptr_luns_long_long_bool_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__terminate", void_ftype_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__unhandled_ex", void_ftype_cptr_cptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__xorpowerset", bool_ftype_ptr_ptr_ptr_luns,
+ NOT_BUILT_IN, NULL_PTR);
+
+ /* declare floating point functions */
+ builtin_function ("__sin", double_ftype_double, NOT_BUILT_IN, "sin");
+ builtin_function ("__cos", double_ftype_double, NOT_BUILT_IN, "cos");
+ builtin_function ("__tan", double_ftype_double, NOT_BUILT_IN, "tan");
+ builtin_function ("__asin", double_ftype_double, NOT_BUILT_IN, "asin");
+ builtin_function ("__acos", double_ftype_double, NOT_BUILT_IN, "acos");
+ builtin_function ("__atan", double_ftype_double, NOT_BUILT_IN, "atan");
+ builtin_function ("__exp", double_ftype_double, NOT_BUILT_IN, "exp");
+ builtin_function ("__log", double_ftype_double, NOT_BUILT_IN, "log");
+ builtin_function ("__log10", double_ftype_double, NOT_BUILT_IN, "log10");
+ builtin_function ("__sqrt", double_ftype_double, NOT_BUILT_IN, "sqrt");
+
+ tasking_init ();
+ timing_init ();
+ inout_init ();
+
+ /* These are predefined value builtin routine calls, built
+ by the compiler, but over-ridable by user procedures of
+ the same names. Note the lack of a leading underscore. */
+ builtin_function ((ignore_case || ! special_UC) ? "abs" : "ABS",
+ chill_predefined_function_type,
+ BUILT_IN_CH_ABS, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "abstime" : "ABSTIME",
+ chill_predefined_function_type,
+ BUILT_IN_ABSTIME, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "allocate" : "ALLOCATE",
+ chill_predefined_function_type,
+ BUILT_IN_ALLOCATE, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "allocate_memory" : "ALLOCATE_MEMORY",
+ chill_predefined_function_type,
+ BUILT_IN_ALLOCATE_MEMORY, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "addr" : "ADDR",
+ chill_predefined_function_type,
+ BUILT_IN_ADDR, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "allocate_global_memory" : "ALLOCATE_GLOBAL_MEMORY",
+ chill_predefined_function_type,
+ BUILT_IN_ALLOCATE_GLOBAL_MEMORY, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "arccos" : "ARCCOS",
+ chill_predefined_function_type,
+ BUILT_IN_ARCCOS, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "arcsin" : "ARCSIN",
+ chill_predefined_function_type,
+ BUILT_IN_ARCSIN, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "arctan" : "ARCTAN",
+ chill_predefined_function_type,
+ BUILT_IN_ARCTAN, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "card" : "CARD",
+ chill_predefined_function_type,
+ BUILT_IN_CARD, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "cos" : "COS",
+ chill_predefined_function_type,
+ BUILT_IN_CH_COS, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "days" : "DAYS",
+ chill_predefined_function_type,
+ BUILT_IN_DAYS, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "descr" : "DESCR",
+ chill_predefined_function_type,
+ BUILT_IN_DESCR, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "getstack" : "GETSTACK",
+ chill_predefined_function_type,
+ BUILT_IN_GETSTACK, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "exp" : "EXP",
+ chill_predefined_function_type,
+ BUILT_IN_EXP, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "hours" : "HOURS",
+ chill_predefined_function_type,
+ BUILT_IN_HOURS, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "inttime" : "INTTIME",
+ chill_predefined_function_type,
+ BUILT_IN_INTTIME, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "length" : "LENGTH",
+ chill_predefined_function_type,
+ BUILT_IN_LENGTH, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "log" : "LOG",
+ chill_predefined_function_type,
+ BUILT_IN_LOG, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "lower" : "LOWER",
+ chill_predefined_function_type,
+ BUILT_IN_LOWER, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "ln" : "LN",
+ chill_predefined_function_type,
+ BUILT_IN_LN, NULL_PTR);
+ /* Note: these are *not* the C integer MAX and MIN. They're
+ for powerset arguments. */
+ builtin_function ((ignore_case || ! special_UC) ? "max" : "MAX",
+ chill_predefined_function_type,
+ BUILT_IN_MAX, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "millisecs" : "MILLISECS",
+ chill_predefined_function_type,
+ BUILT_IN_MILLISECS, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "min" : "MIN",
+ chill_predefined_function_type,
+ BUILT_IN_MIN, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "minutes" : "MINUTES",
+ chill_predefined_function_type,
+ BUILT_IN_MINUTES, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "num" : "NUM",
+ chill_predefined_function_type,
+ BUILT_IN_NUM, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "pred" : "PRED",
+ chill_predefined_function_type,
+ BUILT_IN_PRED, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "return_memory" : "RETURN_MEMORY",
+ chill_predefined_function_type,
+ BUILT_IN_RETURN_MEMORY, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "secs" : "SECS",
+ chill_predefined_function_type,
+ BUILT_IN_SECS, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "sin" : "SIN",
+ chill_predefined_function_type,
+ BUILT_IN_CH_SIN, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "size" : "SIZE",
+ chill_predefined_function_type,
+ BUILT_IN_SIZE, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "sqrt" : "SQRT",
+ chill_predefined_function_type,
+ BUILT_IN_SQRT, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "succ" : "SUCC",
+ chill_predefined_function_type,
+ BUILT_IN_SUCC, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "tan" : "TAN",
+ chill_predefined_function_type,
+ BUILT_IN_TAN, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "terminate" : "TERMINATE",
+ chill_predefined_function_type,
+ BUILT_IN_TERMINATE, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "upper" : "UPPER",
+ chill_predefined_function_type,
+ BUILT_IN_UPPER, NULL_PTR);
+
+ build_chill_descr_type ();
+ build_chill_inttime_type ();
+
+ endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE);
+
+ start_identifier_warnings ();
+
+ pass = 1;
+}
+
+/* Return a definition for a builtin function named NAME and whose data type
+ is TYPE. TYPE should be a function type with argument types.
+ FUNCTION_CODE tells later passes how to compile calls to this function.
+ See tree.h for its possible values.
+
+ If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
+ the name to be called if we can't opencode the function. */
+
+tree
+builtin_function (name, type, function_code, library_name)
+ char *name;
+ tree type;
+ enum built_in_function function_code;
+ char *library_name;
+{
+ tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type);
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ /* If -traditional, permit redefining a builtin function any way you like.
+ (Though really, if the program redefines these functions,
+ it probably won't work right unless compiled with -fno-builtin.) */
+ if (flag_traditional && name[0] != '_')
+ DECL_BUILT_IN_NONANSI (decl) = 1;
+ if (library_name)
+ DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name);
+ make_decl_rtl (decl, NULL_PTR, 1);
+ pushdecl (decl);
+ if (function_code != NOT_BUILT_IN)
+ {
+ DECL_BUILT_IN (decl) = 1;
+ DECL_SET_FUNCTION_CODE (decl, function_code);
+ }
+
+ return decl;
+}
+
+/* Print a warning if a constant expression had overflow in folding.
+ Invoke this function on every expression that the language
+ requires to be a constant expression. */
+
+void
+constant_expression_warning (value)
+ tree value;
+{
+ if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
+ || TREE_CODE (value) == COMPLEX_CST)
+ && TREE_CONSTANT_OVERFLOW (value) && pedantic)
+ pedwarn ("overflow in constant expression");
+}
+
+
+/* Finish processing of a declaration;
+ If the length of an array type is not known before,
+ it must be determined now, from the initial value, or it is an error. */
+
+void
+finish_decl (decl)
+ tree decl;
+{
+ register tree type = TREE_TYPE (decl);
+ int was_incomplete = (DECL_SIZE (decl) == 0);
+ int temporary = allocation_temporary_p ();
+
+ /* Pop back to the obstack that is current for this binding level.
+ This is because MAXINDEX, rtl, etc. to be made below
+ must go in the permanent obstack. But don't discard the
+ temporary data yet. */
+ pop_obstacks ();
+#if 0 /* pop_obstacks was near the end; this is what was here. */
+ if (current_scope == global_scope && temporary)
+ end_temporary_allocation ();
+#endif
+
+ if (TREE_CODE (decl) == VAR_DECL)
+ {
+ if (DECL_SIZE (decl) == 0
+ && TYPE_SIZE (TREE_TYPE (decl)) != 0)
+ layout_decl (decl, 0);
+
+ if (DECL_SIZE (decl) == 0 && TREE_CODE (TREE_TYPE (decl)) != ERROR_MARK)
+ {
+ error_with_decl (decl, "storage size of `%s' isn't known");
+ TREE_TYPE (decl) = error_mark_node;
+ }
+
+ if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
+ && DECL_SIZE (decl) != 0)
+ {
+ if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
+ constant_expression_warning (DECL_SIZE (decl));
+ }
+ }
+
+ /* Output the assembler code and/or RTL code for variables and functions,
+ unless the type is an undefined structure or union.
+ If not, it will get done when the type is completed. */
+
+ if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ /* The last argument (at_end) is set to 1 as a kludge to force
+ assemble_variable to be called. */
+ if (TREE_CODE (TREE_TYPE (decl)) != ERROR_MARK)
+ rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 1);
+
+ /* Compute the RTL of a decl if not yet set.
+ (For normal user variables, satisfy_decl sets it.) */
+ if (! TREE_STATIC (decl) && ! DECL_EXTERNAL (decl))
+ {
+ if (was_incomplete)
+ {
+ /* If we used it already as memory, it must stay in memory. */
+ TREE_ADDRESSABLE (decl) = TREE_USED (decl);
+ /* If it's still incomplete now, no init will save it. */
+ if (DECL_SIZE (decl) == 0)
+ DECL_INITIAL (decl) = 0;
+ expand_decl (decl);
+ }
+ }
+ }
+
+ if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ rest_of_decl_compilation (decl, NULL_PTR,
+ global_bindings_p (), 0);
+ }
+
+ /* ??? After 2.3, test (init != 0) instead of TREE_CODE. */
+ if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
+ && temporary && TREE_PERMANENT (decl))
+ {
+ /* We need to remember that this array HAD an initialization,
+ but discard the actual temporary nodes,
+ since we can't have a permanent node keep pointing to them. */
+ /* We make an exception for inline functions, since it's
+ normal for a local extern redeclaration of an inline function
+ to have a copy of the top-level decl's DECL_INLINE. */
+ if (DECL_INITIAL (decl) != 0)
+ DECL_INITIAL (decl) = error_mark_node;
+ }
+
+#if 0
+ /* Resume permanent allocation, if not within a function. */
+ /* The corresponding push_obstacks_nochange is in start_decl,
+ and in push_parm_decl and in grokfield. */
+ pop_obstacks ();
+#endif
+
+ /* If we have gone back from temporary to permanent allocation,
+ actually free the temporary space that we no longer need. */
+ if (temporary && !allocation_temporary_p ())
+ permanent_allocation (0);
+
+ /* At the end of a declaration, throw away any variable type sizes
+ of types defined inside that declaration. There is no use
+ computing them in the following function definition. */
+ if (current_scope == global_scope)
+ get_pending_sizes ();
+}
+
+/* If DECL has a cleanup, build and return that cleanup here.
+ This is a callback called by expand_expr. */
+
+tree
+maybe_build_cleanup (decl)
+ tree decl;
+{
+ /* There are no cleanups in C. */
+ return NULL_TREE;
+}
+
+/* Make TYPE a complete type based on INITIAL_VALUE.
+ Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
+ 2 if there was no information (in which case assume 1 if DO_DEFAULT). */
+
+int
+complete_array_type (type, initial_value, do_default)
+ tree type, initial_value;
+ int do_default;
+{
+ /* Only needed so we can link with ../c-typeck.c. */
+ abort ();
+}
+
+/* Make sure that the tag NAME is defined *in the current binding level*
+ at least as a forward reference.
+ CODE says which kind of tag NAME ought to be.
+
+ We also do a push_obstacks_nochange
+ whose matching pop is in finish_struct. */
+
+tree
+start_struct (code, name)
+ enum chill_tree_code code;
+ tree name;
+{
+ /* If there is already a tag defined at this binding level
+ (as a forward reference), just return it. */
+
+ register tree ref = 0;
+
+ push_obstacks_nochange ();
+ if (current_scope == global_scope)
+ end_temporary_allocation ();
+
+ /* Otherwise create a forward-reference just so the tag is in scope. */
+
+ ref = make_node (code);
+/* pushtag (name, ref); */
+ return ref;
+}
+
+#if 0
+/* Function to help qsort sort FIELD_DECLs by name order. */
+
+static int
+field_decl_cmp (x, y)
+ tree *x, *y;
+{
+ return (long)DECL_NAME (*x) - (long)DECL_NAME (*y);
+}
+#endif
+/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
+ FIELDLIST is a chain of FIELD_DECL nodes for the fields.
+
+ We also do a pop_obstacks to match the push in start_struct. */
+
+tree
+finish_struct (t, fieldlist)
+ register tree t, fieldlist;
+{
+ register tree x;
+
+ /* Install struct as DECL_CONTEXT of each field decl.
+ Also process specified field sizes.
+ Set DECL_FIELD_SIZE to the specified size, or 0 if none specified.
+ The specified size is found in the DECL_INITIAL.
+ Store 0 there, except for ": 0" fields (so we can find them
+ and delete them, below). */
+
+ for (x = fieldlist; x; x = TREE_CHAIN (x))
+ {
+ DECL_CONTEXT (x) = t;
+ DECL_FIELD_SIZE (x) = 0;
+ }
+
+ TYPE_FIELDS (t) = fieldlist;
+
+ if (pass != 1)
+ t = layout_chill_struct_type (t);
+
+ /* The matching push is in start_struct. */
+ pop_obstacks ();
+
+ return t;
+}
+
+/* Lay out the type T, and its element type, and so on. */
+
+static void
+layout_array_type (t)
+ tree t;
+{
+ if (TYPE_SIZE (t) != 0)
+ return;
+ if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+ layout_array_type (TREE_TYPE (t));
+ layout_type (t);
+}
+
+/* Begin compiling the definition of an enumeration type.
+ NAME is its name (or null if anonymous).
+ Returns the type object, as yet incomplete.
+ Also records info about it so that build_enumerator
+ may be used to declare the individual values as they are read. */
+
+tree
+start_enum (name)
+ tree name;
+{
+ register tree enumtype;
+
+ /* If this is the real definition for a previous forward reference,
+ fill in the contents in the same object that used to be the
+ forward reference. */
+
+#if 0
+ /* The corresponding pop_obstacks is in finish_enum. */
+ push_obstacks_nochange ();
+ /* If these symbols and types are global, make them permanent. */
+ if (current_scope == global_scope)
+ end_temporary_allocation ();
+#endif
+
+ enumtype = make_node (ENUMERAL_TYPE);
+/* pushtag (name, enumtype); */
+ return enumtype;
+}
+
+/* Determine the precision this type needs. */
+unsigned
+get_type_precision (minnode, maxnode)
+ tree minnode, maxnode;
+{
+ unsigned precision = 0;
+
+ if (TREE_INT_CST_HIGH (minnode) >= 0
+ ? tree_int_cst_lt (TYPE_MAX_VALUE (unsigned_type_node), maxnode)
+ : (tree_int_cst_lt (minnode, TYPE_MIN_VALUE (integer_type_node))
+ || tree_int_cst_lt (TYPE_MAX_VALUE (integer_type_node), maxnode)))
+ precision = TYPE_PRECISION (long_long_integer_type_node);
+ else
+ {
+ HOST_WIDE_INT maxvalue = TREE_INT_CST_LOW (maxnode);
+ HOST_WIDE_INT minvalue = TREE_INT_CST_LOW (minnode);
+
+ if (maxvalue > 0)
+ precision = floor_log2 (maxvalue) + 1;
+ if (minvalue < 0)
+ {
+ /* Compute number of bits to represent magnitude of a negative value.
+ Add one to MINVALUE since range of negative numbers
+ includes the power of two. */
+ unsigned negprecision = floor_log2 (-minvalue - 1) + 1;
+ if (negprecision > precision)
+ precision = negprecision;
+ precision += 1; /* room for sign bit */
+ }
+
+ if (!precision)
+ precision = 1;
+ }
+ return precision;
+}
+
+void
+layout_enum (enumtype)
+ tree enumtype;
+{
+ register tree pair, tem;
+ tree minnode = 0, maxnode = 0;
+ unsigned precision = 0;
+
+ /* Do arithmetic using double integers, but don't use fold/build. */
+ union tree_node enum_next_node;
+ /* This is 1 plus the last enumerator constant value. */
+ tree enum_next_value = &enum_next_node;
+
+ /* Nonzero means that there was overflow computing enum_next_value. */
+ int enum_overflow = 0;
+
+ tree values = TYPE_VALUES (enumtype);
+
+ if (TYPE_SIZE (enumtype) != NULL_TREE)
+ return;
+
+ /* Initialize enum_next_value to zero. */
+ TREE_TYPE (enum_next_value) = integer_type_node;
+ TREE_INT_CST_LOW (enum_next_value) = TREE_INT_CST_LOW (integer_zero_node);
+ TREE_INT_CST_HIGH (enum_next_value) = TREE_INT_CST_HIGH (integer_zero_node);
+
+ /* After processing and defining all the values of an enumeration type,
+ install their decls in the enumeration type and finish it off.
+
+ TYPE_VALUES currently contains a list of (purpose: NAME, value: DECL).
+ This gets converted to a list of (purpose: NAME, value: VALUE). */
+
+
+ /* For each enumerator, calculate values, if defaulted.
+ Convert to correct type (the enumtype).
+ Also, calculate the minimum and maximum values. */
+
+ for (pair = values; pair; pair = TREE_CHAIN (pair))
+ {
+ tree decl = TREE_VALUE (pair);
+ tree value = DECL_INITIAL (decl);
+
+ /* Remove no-op casts from the value. */
+ if (value != NULL_TREE)
+ STRIP_TYPE_NOPS (value);
+
+ if (value != NULL_TREE)
+ {
+ if (TREE_CODE (value) == INTEGER_CST)
+ {
+ constant_expression_warning (value);
+ if (tree_int_cst_lt (value, integer_zero_node))
+ {
+ error ("enumerator value for `%s' is less then 0",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ value = error_mark_node;
+ }
+ }
+ else
+ {
+ error ("enumerator value for `%s' not integer constant",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ value = error_mark_node;
+ }
+ }
+
+ if (value != error_mark_node)
+ {
+ if (value == NULL_TREE) /* Default based on previous value. */
+ {
+ value = enum_next_value;
+ if (enum_overflow)
+ error ("overflow in enumeration values");
+ }
+ value = build_int_2 (TREE_INT_CST_LOW (value),
+ TREE_INT_CST_HIGH (value));
+ TREE_TYPE (value) = enumtype;
+ DECL_INITIAL (decl) = value;
+ CH_DERIVED_FLAG (value) = 1;
+
+ if (pair == values)
+ minnode = maxnode = value;
+ else
+ {
+ if (tree_int_cst_lt (maxnode, value))
+ maxnode = value;
+ if (tree_int_cst_lt (value, minnode))
+ minnode = value;
+ }
+
+ /* Set basis for default for next value. */
+ add_double (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value), 1, 0,
+ &TREE_INT_CST_LOW (enum_next_value),
+ &TREE_INT_CST_HIGH (enum_next_value));
+ enum_overflow = tree_int_cst_lt (enum_next_value, value);
+ }
+ else
+ DECL_INITIAL (decl) = value; /* error_mark_node */
+ }
+
+ /* Fix all error_mark_nodes in enum. Increment maxnode and assign value.
+ This is neccessary to make a duplicate value check in the enum */
+ for (pair = values; pair; pair = TREE_CHAIN (pair))
+ {
+ tree decl = TREE_VALUE (pair);
+ if (DECL_INITIAL (decl) == error_mark_node)
+ {
+ tree value;
+ add_double (TREE_INT_CST_LOW (maxnode), TREE_INT_CST_HIGH (maxnode), 1, 0,
+ &TREE_INT_CST_LOW (enum_next_value),
+ &TREE_INT_CST_HIGH (enum_next_value));
+ value = build_int_2 (TREE_INT_CST_LOW (enum_next_value),
+ TREE_INT_CST_HIGH (enum_next_value));
+ TREE_TYPE (value) = enumtype;
+ CH_DERIVED_FLAG (value) = 1;
+ DECL_INITIAL (decl) = value;
+
+ maxnode = value;
+ }
+ }
+
+ /* Now check if we have duplicate values within the enum */
+ for (pair = values; pair; pair = TREE_CHAIN (pair))
+ {
+ tree succ;
+ tree decl1 = TREE_VALUE (pair);
+ tree val1 = DECL_INITIAL (decl1);
+
+ for (succ = TREE_CHAIN (pair); succ; succ = TREE_CHAIN (succ))
+ {
+ if (pair != succ)
+ {
+ tree decl2 = TREE_VALUE (succ);
+ tree val2 = DECL_INITIAL (decl2);
+ if (tree_int_cst_equal (val1, val2))
+ error ("enumerators `%s' and `%s' have equal values",
+ IDENTIFIER_POINTER (DECL_NAME (decl1)),
+ IDENTIFIER_POINTER (DECL_NAME (decl2)));
+ }
+ }
+ }
+
+ TYPE_MIN_VALUE (enumtype) = minnode;
+ TYPE_MAX_VALUE (enumtype) = maxnode;
+
+ precision = get_type_precision (minnode, maxnode);
+
+ if (flag_short_enums || precision > TYPE_PRECISION (integer_type_node))
+ /* Use the width of the narrowest normal C type which is wide enough. */
+ TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size (precision, 1));
+ else
+ TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
+
+ layout_type (enumtype);
+
+#if 0
+ /* An enum can have some negative values; then it is signed. */
+ TREE_UNSIGNED (enumtype) = ! tree_int_cst_lt (minnode, integer_zero_node);
+#else
+ /* Z200/1988 page 19 says:
+ For each pair of integer literal expression e1, e2 in the set list NUM (e1)
+ and NUM (e2) must deliver different non-negative results */
+ TREE_UNSIGNED (enumtype) = 1;
+#endif
+
+ for (pair = values; pair; pair = TREE_CHAIN (pair))
+ {
+ tree decl = TREE_VALUE (pair);
+ DECL_SIZE (decl) = TYPE_SIZE (enumtype);
+ DECL_ALIGN (decl) = TYPE_ALIGN (enumtype);
+
+ /* Set the TREE_VALUE to the name, rather than the decl,
+ since that is what the rest of the compiler expects. */
+ TREE_VALUE (pair) = DECL_INITIAL (decl);
+ }
+
+ /* Fix up all variant types of this enum type. */
+ for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem))
+ {
+ TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
+ TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
+ TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
+ TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
+ TYPE_MODE (tem) = TYPE_MODE (enumtype);
+ TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
+ TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
+ TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
+ }
+
+#if 0
+ /* This matches a push in start_enum. */
+ pop_obstacks ();
+#endif
+}
+
+tree
+finish_enum (enumtype, values)
+ register tree enumtype, values;
+{
+ TYPE_VALUES (enumtype) = values = nreverse (values);
+
+ /* If satisfy_decl is called on one of the enum CONST_DECLs,
+ this will make sure that the enumtype gets laid out then. */
+ for ( ; values; values = TREE_CHAIN (values))
+ TREE_TYPE (TREE_VALUE (values)) = enumtype;
+
+ return enumtype;
+}
+
+
+/* Build and install a CONST_DECL for one value of the
+ current enumeration type (one that was begun with start_enum).
+ Return a tree-list containing the CONST_DECL and its value.
+ Assignment of sequential values by default is handled here. */
+
+tree
+build_enumerator (name, value)
+ tree name, value;
+{
+ register tree decl;
+ int named = name != NULL_TREE;
+
+ if (pass == 2)
+ {
+ if (name)
+ (void) get_next_decl ();
+ return NULL_TREE;
+ }
+
+ if (name == NULL_TREE)
+ {
+ static int unnamed_value_warned = 0;
+ static int next_dummy_enum_value = 0;
+ char buf[20];
+ if (!unnamed_value_warned)
+ {
+ unnamed_value_warned = 1;
+ warning ("undefined value in SET mode is obsolete and deprecated.");
+ }
+ sprintf (buf, "__star_%d", next_dummy_enum_value++);
+ name = get_identifier (buf);
+ }
+
+ decl = build_decl (CONST_DECL, name, integer_type_node);
+ CH_DECL_ENUM (decl) = 1;
+ DECL_INITIAL (decl) = value;
+ if (named)
+ {
+ if (pass == 0)
+ {
+ push_obstacks_nochange ();
+ pushdecl (decl);
+ finish_decl (decl);
+ }
+ else
+ save_decl (decl);
+ }
+ return build_tree_list (name, decl);
+
+#if 0
+ tree old_value = lookup_name_current_level (name);
+
+ if (old_value != NULL_TREE
+ && TREE_CODE (old_value)=!= CONST_DECL
+ && (value == NULL_TREE || operand_equal_p (value, old_value, 1)))
+ {
+ if (value == NULL_TREE)
+ {
+ if (TREE_CODE (old_value) == CONST_DECL)
+ value = DECL_INITIAL (old_value);
+ else
+ abort ();
+ }
+ return saveable_tree_cons (old_value, value, NULL_TREE);
+ }
+#endif
+}
+
+/* Record that this function is going to be a varargs function.
+ This is called before store_parm_decls, which is too early
+ to call mark_varargs directly. */
+
+void
+c_mark_varargs ()
+{
+ c_function_varargs = 1;
+}
+
+/* Function needed for CHILL interface. */
+tree
+get_parm_decls ()
+{
+ return current_function_parms;
+}
+
+/* Save and restore the variables in this file and elsewhere
+ that keep track of the progress of compilation of the current function.
+ Used for nested functions. */
+
+struct c_function
+{
+ struct c_function *next;
+ struct scope *scope;
+ tree chill_result_decl;
+ int result_never_set;
+};
+
+struct c_function *c_function_chain;
+
+/* Save and reinitialize the variables
+ used during compilation of a C function. */
+
+void
+push_chill_function_context ()
+{
+ struct c_function *p
+ = (struct c_function *) xmalloc (sizeof (struct c_function));
+
+ push_function_context ();
+
+ p->next = c_function_chain;
+ c_function_chain = p;
+
+ p->scope = current_scope;
+ p->chill_result_decl = chill_result_decl;
+ p->result_never_set = result_never_set;
+}
+
+/* Restore the variables used during compilation of a C function. */
+
+void
+pop_chill_function_context ()
+{
+ struct c_function *p = c_function_chain;
+#if 0
+ tree link;
+ /* Bring back all the labels that were shadowed. */
+ for (link = shadowed_labels; link; link = TREE_CHAIN (link))
+ if (DECL_NAME (TREE_VALUE (link)) != 0)
+ IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)))
+ = TREE_VALUE (link);
+#endif
+
+ pop_function_context ();
+
+ c_function_chain = p->next;
+
+ current_scope = p->scope;
+ chill_result_decl = p->chill_result_decl;
+ result_never_set = p->result_never_set;
+
+ free (p);
+}
+
+/* Following from Jukka Virtanen's GNU Pascal */
+/* To implement WITH statement:
+
+ 1) Call shadow_record_fields for each record_type element in the WITH
+ element list. Each call creates a new binding level.
+
+ 2) construct a component_ref for EACH field in the record,
+ and store it to the IDENTIFIER_LOCAL_VALUE after adding
+ the old value to the shadow list
+
+ 3) let lookup_name do the rest
+
+ 4) pop all of the binding levels after the WITH statement ends.
+ (restoring old local values) You have to keep track of the number
+ of times you called it.
+*/
+
+/*
+ * Save an arbitrary tree-expression as the IDENTIFIER_LOCAL_VALUE
+ * of a name. Save the name's previous value. Check for name
+ * collisions with another value under the same name at the same
+ * nesting level. This is used to implement the DO WITH construct
+ * and the temporary for the location iteration loop.
+ */
+void
+save_expr_under_name (name, expr)
+ tree name, expr;
+{
+ tree alias = build_alias_decl (NULL_TREE, NULL_TREE, name);
+
+ DECL_ABSTRACT_ORIGIN (alias) = expr;
+ TREE_CHAIN (alias) = NULL_TREE;
+ pushdecllist (alias, 0);
+}
+
+void
+do_based_decl (name, mode, base_var)
+ tree name, mode, base_var;
+{
+ tree decl;
+ if (pass == 1)
+ {
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ decl = make_node (BASED_DECL);
+ DECL_NAME (decl) = name;
+ TREE_TYPE (decl) = mode;
+ DECL_ABSTRACT_ORIGIN (decl) = base_var;
+ save_decl (decl);
+ pop_obstacks ();
+ }
+ else
+ {
+ tree base_decl;
+ decl = get_next_decl ();
+ if (name != DECL_NAME (decl))
+ abort();
+ /* FIXME: This isn't a complete test */
+ base_decl = lookup_name (base_var);
+ if (base_decl == NULL_TREE)
+ error ("BASE variable never declared");
+ else if (TREE_CODE (base_decl) == FUNCTION_DECL)
+ error ("cannot BASE a variable on a PROC/PROCESS name");
+ }
+}
+
+void
+do_based_decls (names, mode, base_var)
+ tree names, mode, base_var;
+{
+ if (names == NULL_TREE || TREE_CODE (names) == TREE_LIST)
+ {
+ for (; names != NULL_TREE; names = TREE_CHAIN (names))
+ do_based_decl (names, mode, base_var);
+ }
+ else if (TREE_CODE (names) != ERROR_MARK)
+ do_based_decl (names, mode, base_var);
+}
+
+/*
+ * Declare the fields so that lookup_name() will find them as
+ * component refs for Pascal WITH or CHILL DO WITH.
+ *
+ * Proceeds to the inner layers of Pascal/CHILL variant record
+ *
+ * Internal routine of shadow_record_fields ()
+ */
+static void
+handle_one_level (parent, fields)
+ tree parent, fields;
+{
+ tree field, name;
+
+ switch (TREE_CODE (TREE_TYPE (parent)))
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ for (field = fields; field; field = TREE_CHAIN (field)) {
+ name = DECL_NAME (field);
+ if (name == NULL_TREE || name == ELSE_VARIANT_NAME)
+ /* proceed through variant part */
+ handle_one_level (parent, TYPE_FIELDS (TREE_TYPE (field)));
+ else
+ {
+ tree field_alias = make_node (WITH_DECL);
+ DECL_NAME (field_alias) = name;
+ TREE_TYPE (field_alias) = TREE_TYPE (field);
+ DECL_ABSTRACT_ORIGIN (field_alias) = parent;
+ TREE_CHAIN (field_alias) = NULL_TREE;
+ pushdecllist (field_alias, 0);
+ }
+ }
+ break;
+ default:
+ error ("INTERNAL ERROR: handle_one_level is broken");
+ }
+}
+
+/*
+ * For each FIELD_DECL node in a RECORD_TYPE, we have to declare
+ * a name so that lookup_name will find a COMPONENT_REF node
+ * when the name is referenced. This happens in Pascal WITH statement.
+ */
+void
+shadow_record_fields (struct_val)
+ tree struct_val;
+{
+ tree type, parent;
+
+ if (pass == 1 || struct_val == NULL_TREE)
+ return;
+
+ handle_one_level (struct_val, TYPE_FIELDS (TREE_TYPE (struct_val)));
+}
+
+static char exception_prefix [] = "__Ex_";
+
+tree
+build_chill_exception_decl (name)
+ char *name;
+{
+ tree decl, ex_name, ex_init, ex_type;
+ int name_len = strlen (name);
+ char *ex_string = (char *)
+ alloca (strlen (exception_prefix) + name_len + 1);
+
+ sprintf(ex_string, "%s%s", exception_prefix, name);
+ ex_name = get_identifier (ex_string);
+ decl = IDENTIFIER_LOCAL_VALUE (ex_name);
+ if (decl)
+ return decl;
+
+ /* finish_decl is too eager about switching back to the
+ ambient context. This decl's rtl must live in the permanent_obstack. */
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ push_obstacks_nochange ();
+ ex_type = build_array_type (char_type_node,
+ build_index_2_type (integer_zero_node,
+ build_int_2 (name_len, 0)));
+ decl = build_lang_decl (VAR_DECL, ex_name, ex_type);
+ ex_init = build_string (name_len, name);
+ TREE_TYPE (ex_init) = ex_type;
+ DECL_INITIAL (decl) = ex_init;
+ TREE_READONLY (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ pushdecl_top_level (decl);
+ finish_decl (decl);
+ pop_obstacks (); /* Return to the ambient context. */
+ return decl;
+}
+
+extern tree module_init_list;
+
+/*
+ * This function is called from the parser to preface the entire
+ * compilation. It contains module-level actions and reach-bound
+ * initialization.
+ */
+void
+start_outer_function ()
+{
+ start_chill_function (pass < 2 ? get_identifier ("_GLOBAL_")
+ : DECL_NAME (global_function_decl),
+ void_type_node, NULL_TREE, NULL_TREE, NULL_TREE);
+ global_function_decl = current_function_decl;
+ global_scope = current_scope;
+ chill_at_module_level = 1;
+}
+
+/* This function finishes the global_function_decl, and if it is non-empty
+ * (as indiacted by seen_action), adds it to module_init_list.
+ */
+void
+finish_outer_function ()
+{
+ /* If there was module-level code in this module (not just function
+ declarations), we allocate space for this module's init list entry,
+ and fill in the module's function's address. */
+
+ extern tree initializer_type;
+ char *fname_str = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
+ char *init_entry_name = (char *)xmalloc ((unsigned)(strlen (fname_str) + 20));
+ tree init_entry_id;
+ tree init_entry_decl;
+ tree initializer;
+
+ finish_chill_function ();
+
+ chill_at_module_level = 0;
+
+
+ if (!seen_action)
+ return;
+
+ sprintf (init_entry_name, "__tmp_%s_init_entry", fname_str);
+ init_entry_id = get_identifier (init_entry_name);
+
+ init_entry_decl = build1 (ADDR_EXPR,
+ TREE_TYPE (TYPE_FIELDS (initializer_type)),
+ global_function_decl);
+ TREE_CONSTANT (init_entry_decl) = 1;
+ initializer = build (CONSTRUCTOR, initializer_type, NULL_TREE,
+ tree_cons (NULL_TREE, init_entry_decl,
+ build_tree_list (NULL_TREE,
+ null_pointer_node)));
+ TREE_CONSTANT (initializer) = 1;
+ init_entry_decl
+ = do_decl (init_entry_id, initializer_type, 1, 1, initializer, 0);
+ DECL_SOURCE_LINE (init_entry_decl) = 0;
+ if (pass == 1)
+ /* tell chill_finish_compile that there's
+ module-level code to be processed. */
+ module_init_list = integer_one_node;
+ else if (build_constructor)
+ module_init_list = tree_cons (global_function_decl,
+ init_entry_decl,
+ module_init_list);
+
+ make_decl_rtl (global_function_decl, NULL, 0);
+}
diff --git a/gcc/ch/expr.c b/gcc/ch/expr.c
new file mode 100644
index 0000000..16b1e3c
--- /dev/null
+++ b/gcc/ch/expr.c
@@ -0,0 +1,4493 @@
+/* Convert language-specific tree expression to rtl instructions,
+ for GNU CHILL compiler.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "config.h"
+#include <stdio.h>
+#include "rtl.h"
+#include "tree.h"
+#include "flags.h"
+#include "expr.h"
+#include "ch-tree.h"
+#include "assert.h"
+#include "lex.h"
+#include "convert.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+extern char **boolean_code_name;
+extern int flag_old_strings;
+extern tree long_unsigned_type_node;
+extern int ignore_case;
+extern int special_UC;
+
+extern void check_for_full_enumeration_handling PROTO((tree));
+extern void chill_handle_case_default PROTO((void));
+extern void error PROTO((char *, ...));
+extern void error_with_decl PROTO((tree, char *, ...));
+extern void fatal PROTO((char *, ...));
+extern void sorry PROTO((char *, ...));
+extern tree stabilize_reference PROTO((tree));
+extern void warning PROTO((char *, ...));
+
+/* definitions for duration built-ins */
+#define MILLISECS_MULTIPLIER 1
+#define SECS_MULTIPLIER MILLISECS_MULTIPLIER * 1000
+#define MINUTES_MULTIPLIER SECS_MULTIPLIER * 60
+#define HOURS_MULTIPLIER MINUTES_MULTIPLIER * 60
+#define DAYS_MULTIPLIER HOURS_MULTIPLIER * 24
+
+/* the maximum value for each of the calls */
+#define MILLISECS_MAX 0xffffffff
+#define SECS_MAX 4294967
+#define MINUTES_MAX 71582
+#define HOURS_MAX 1193
+#define DAYS_MAX 49
+
+/* forward declaration */
+rtx chill_expand_expr PROTO((tree, rtx, enum machine_mode,
+ enum expand_modifier));
+
+/* variable to hold the type the DESCR built-in returns */
+static tree descr_type = NULL_TREE;
+
+
+/* called from ch-lex.l */
+void
+init_chill_expand ()
+{
+ lang_expand_expr = chill_expand_expr;
+}
+
+/* Take the address of something that needs to be passed by reference. */
+tree
+force_addr_of (value)
+ tree value;
+{
+ /* FIXME. Move to memory, if needed. */
+ if (TREE_CODE (value) == INDIRECT_REF)
+ return convert_to_pointer (ptr_type_node, TREE_OPERAND (value, 0));
+ mark_addressable (value);
+ return build1 (ADDR_EXPR, ptr_type_node, value);
+}
+
+/* Check that EXP has a known type. */
+
+tree
+check_have_mode (exp, context)
+ tree exp;
+ char *context;
+{
+ if (TREE_CODE (exp) != ERROR_MARK && TREE_TYPE (exp) == NULL_TREE)
+ {
+ if (TREE_CODE (exp) == CONSTRUCTOR)
+ error ("tuple without specified mode not allowed in %s", context);
+ else if (TREE_CODE (exp) == COND_EXPR || TREE_CODE (exp) == CASE_EXPR)
+ error ("conditional expression not allowed in %s", context);
+ else
+ error ("internal error: unknown expression mode in %s", context);
+
+ return error_mark_node;
+ }
+ return exp;
+}
+
+/* Check that EXP is discrete. Handle conversion if flag_old_strings. */
+
+tree
+check_case_selector (exp)
+ tree exp;
+{
+ if (exp != NULL_TREE && TREE_TYPE (exp) != NULL_TREE)
+ exp = convert_to_discrete (exp);
+ if (exp)
+ return exp;
+ error ("CASE selector is not a discrete expression");
+ return error_mark_node;
+}
+
+tree
+check_case_selector_list (list)
+ tree list;
+{
+ tree selector, exp, return_list = NULL_TREE;
+
+ for (selector = list; selector != NULL_TREE; selector = TREE_CHAIN (selector))
+ {
+ exp = check_case_selector (TREE_VALUE (selector));
+ if (exp == error_mark_node)
+ {
+ return_list = error_mark_node;
+ break;
+ }
+ return_list = tree_cons (TREE_PURPOSE (selector), exp, return_list);
+ }
+
+ return nreverse(return_list);
+}
+
+tree
+chill_expand_case_expr (expr)
+ tree expr;
+{
+ tree selector_list = TREE_OPERAND (expr, 0), selector;
+ tree alternatives = TREE_OPERAND (expr, 1);
+ tree type = TREE_TYPE (expr);
+ int else_seen = 0;
+ tree result;
+
+ if (TREE_CODE (selector_list) != TREE_LIST
+ || TREE_CODE (alternatives) != TREE_LIST)
+ abort();
+ if (TREE_CHAIN (selector_list) != NULL_TREE)
+ abort ();
+
+ /* make a temp for the case result */
+ result = decl_temp1 (get_unique_identifier ("CASE_EXPR"),
+ type, 0, NULL_TREE, 0, 0);
+
+ selector = check_case_selector (TREE_VALUE (selector_list));
+
+ expand_start_case (1, selector, TREE_TYPE (selector), "CASE expression");
+
+ alternatives = nreverse (alternatives);
+ for ( ; alternatives != NULL_TREE; alternatives = TREE_CHAIN (alternatives))
+ {
+ tree labels = TREE_PURPOSE (alternatives), t;
+
+ if (labels == NULL_TREE)
+ {
+ chill_handle_case_default ();
+ else_seen++;
+ }
+ else
+ {
+ tree label;
+ if (labels != NULL_TREE)
+ {
+ for (label = TREE_VALUE (labels);
+ label != NULL_TREE; label = TREE_CHAIN (label))
+ chill_handle_case_label (TREE_VALUE (label), selector);
+ labels = TREE_CHAIN (labels);
+ if (labels != NULL_TREE)
+ error ("The number of CASE selectors does not match the number "
+ "of CASE label lists");
+
+ }
+ }
+
+ t = build (MODIFY_EXPR, type, result,
+ convert (type, TREE_VALUE (alternatives)));
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr_stmt (t);
+ expand_exit_something ();
+ }
+
+ if (!else_seen)
+ {
+ chill_handle_case_default ();
+ expand_exit_something ();
+#if 0
+ expand_raise ();
+#endif
+
+ check_missing_cases (TREE_TYPE (selector));
+ }
+
+ expand_end_case (selector);
+ return result;
+}
+
+/* Hook used by expand_expr to expand CHILL-specific tree codes. */
+
+rtx
+chill_expand_expr (exp, target, tmode, modifier)
+ tree exp;
+ rtx target;
+ enum machine_mode tmode;
+ enum expand_modifier modifier;
+{
+ tree type = TREE_TYPE (exp);
+ register enum machine_mode mode = TYPE_MODE (type);
+ register enum tree_code code = TREE_CODE (exp);
+ rtx original_target = target;
+ rtx op0, op1;
+ int ignore = target == const0_rtx;
+ char *lib_func; /* name of library routine */
+
+ if (ignore)
+ target = 0, original_target = 0;
+
+ /* No sense saving up arithmetic to be done
+ if it's all in the wrong mode to form part of an address.
+ And force_operand won't know whether to sign-extend or zero-extend. */
+
+ if (mode != Pmode && modifier == EXPAND_SUM)
+ modifier = EXPAND_NORMAL;
+
+ switch (code)
+ {
+ case STRING_EQ_EXPR:
+ case STRING_LT_EXPR:
+ {
+ rtx func = gen_rtx (SYMBOL_REF, Pmode,
+ code == STRING_EQ_EXPR ? "__eqstring"
+ : "__ltstring");
+ tree exp0 = TREE_OPERAND (exp, 0);
+ tree exp1 = TREE_OPERAND (exp, 1);
+ tree size0, size1;
+ rtx op0, op1, siz0, siz1;
+ if (chill_varying_type_p (TREE_TYPE (exp0)))
+ {
+ exp0 = save_if_needed (exp0);
+ size0 = convert (integer_type_node,
+ build_component_ref (exp0, var_length_id));
+ exp0 = build_component_ref (exp0, var_data_id);
+ }
+ else
+ size0 = size_in_bytes (TREE_TYPE (exp0));
+ if (chill_varying_type_p (TREE_TYPE (exp1)))
+ {
+ exp1 = save_if_needed (exp1);
+ size1 = convert (integer_type_node,
+ build_component_ref (exp1, var_length_id));
+ exp1 = build_component_ref (exp1, var_data_id);
+ }
+ else
+ size1 = size_in_bytes (TREE_TYPE (exp1));
+
+ op0 = expand_expr (force_addr_of (exp0),
+ NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
+ op1 = expand_expr (force_addr_of (exp1),
+ NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
+ siz0 = expand_expr (size0, NULL_RTX, VOIDmode, 0);
+ siz1 = expand_expr (size1, NULL_RTX, VOIDmode, 0);
+ return emit_library_call_value (func, target,
+ 0, QImode, 4,
+ op0, GET_MODE (op0),
+ siz0, TYPE_MODE (sizetype),
+ op1, GET_MODE (op1),
+ siz1, TYPE_MODE (sizetype));
+ }
+
+ case CASE_EXPR:
+ return expand_expr (chill_expand_case_expr (exp),
+ NULL_RTX, VOIDmode, 0);
+ break;
+
+ case SLICE_EXPR:
+ {
+ tree func_call;
+ tree array = TREE_OPERAND (exp, 0);
+ tree min_value = TREE_OPERAND (exp, 1);
+ tree length = TREE_OPERAND (exp, 2);
+ tree new_type = TREE_TYPE (exp);
+ tree temp = decl_temp1 (get_unique_identifier ("BITSTRING"),
+ new_type, 0, NULL_TREE, 0, 0);
+ if (! CH_REFERABLE (array) && TYPE_MODE (TREE_TYPE (array)) != BLKmode)
+ array = decl_temp1 (get_unique_identifier ("BSTRINGVAL"),
+ TREE_TYPE (array), 0, array, 0, 0);
+ func_call = build_chill_function_call (
+ lookup_name (get_identifier ("__psslice")),
+ tree_cons (NULL_TREE,
+ build_chill_addr_expr (temp, (char *)0),
+ tree_cons (NULL_TREE, length,
+ tree_cons (NULL_TREE,
+ force_addr_of (array),
+ tree_cons (NULL_TREE, powersetlen (array),
+ tree_cons (NULL_TREE, convert (integer_type_node, min_value),
+ tree_cons (NULL_TREE, length, NULL_TREE)))))));
+ expand_expr (func_call, const0_rtx, VOIDmode, 0);
+ emit_queue ();
+ return expand_expr (temp, ignore ? const0_rtx : target,
+ VOIDmode, 0);
+ }
+
+ /* void __concatstring (char *out, char *left, unsigned left_len,
+ char *right, unsigned right_len) */
+ case CONCAT_EXPR:
+ {
+ tree exp0 = TREE_OPERAND (exp, 0);
+ tree exp1 = TREE_OPERAND (exp, 1);
+ rtx size0, size1;
+ rtx targetx;
+
+ if (TREE_CODE (exp1) == UNDEFINED_EXPR)
+ {
+ if (TYPE_MODE (TREE_TYPE (exp0)) == BLKmode
+ && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+ {
+ rtx temp = expand_expr (exp0, target, tmode, modifier);
+ if (temp == target || target == NULL_RTX)
+ return temp;
+ emit_block_move (target, temp, expr_size (exp0),
+ TYPE_ALIGN (TREE_TYPE(exp0)) / BITS_PER_UNIT);
+ return target;
+ }
+ else
+ {
+ exp0 = force_addr_of (exp0);
+ exp0 = convert (build_pointer_type (TREE_TYPE (exp)), exp0);
+ exp0 = build1 (INDIRECT_REF, TREE_TYPE (exp), exp0);
+ return expand_expr (exp0,
+ NULL_RTX, Pmode, EXPAND_CONST_ADDRESS);
+ }
+ }
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ /* No need to handle scalars or varying strings here, since that
+ was done in convert or build_concat_expr. */
+ size0 = expand_expr (size_in_bytes (TREE_TYPE (exp0)),
+ NULL_RTX, Pmode, EXPAND_CONST_ADDRESS);
+
+ size1 = expand_expr (size_in_bytes (TREE_TYPE (exp1)),
+ NULL_RTX, Pmode, EXPAND_CONST_ADDRESS);
+
+ /* build a temp for the result, target is its address */
+ if (target == NULL_RTX)
+ {
+ tree type0 = TREE_TYPE (exp0);
+ tree type1 = TREE_TYPE (exp1);
+ int len0 = int_size_in_bytes (type0);
+ int len1 = int_size_in_bytes (type1);
+
+ if (len0 < 0 && TYPE_ARRAY_MAX_SIZE (type0)
+ && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type0)) == INTEGER_CST)
+ len0 = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type0));
+
+ if (len1 < 0 && TYPE_ARRAY_MAX_SIZE (type1)
+ && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type1)) == INTEGER_CST)
+ len1 = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type1));
+
+ if (len0 < 0 || len1 < 0)
+ fatal ("internal error - don't know how much space is needed for concatenation");
+ target = assign_stack_temp (mode, len0 + len1, 0);
+ preserve_temp_slots (target);
+ }
+ }
+ else if (TREE_CODE (type) == SET_TYPE)
+ {
+ if (target == NULL_RTX)
+ {
+ target = assign_stack_temp (mode, int_size_in_bytes (type), 0);
+ preserve_temp_slots (target);
+ }
+ }
+ else
+ abort ();
+
+ if (GET_CODE (target) == MEM)
+ targetx = target;
+ else
+ targetx = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
+
+ /* expand 1st operand to a pointer to the array */
+ op0 = expand_expr (force_addr_of (exp0),
+ NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
+
+ /* expand 2nd operand to a pointer to the array */
+ op1 = expand_expr (force_addr_of (exp1),
+ NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
+
+ if (TREE_CODE (type) == SET_TYPE)
+ {
+ size0 = expand_expr (powersetlen (exp0),
+ NULL_RTX, VOIDmode, 0);
+ size1 = expand_expr (powersetlen (exp1),
+ NULL_RTX, VOIDmode, 0);
+
+ emit_library_call (gen_rtx(SYMBOL_REF, Pmode, "__concatps"),
+ 0, Pmode, 5, XEXP (targetx, 0), Pmode,
+ op0, GET_MODE (op0),
+ convert_to_mode (TYPE_MODE (sizetype),
+ size0, TREE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype),
+ op1, GET_MODE (op1),
+ convert_to_mode (TYPE_MODE (sizetype),
+ size1, TREE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
+ }
+ else
+ {
+ /* copy left, then right array to target */
+ emit_library_call (gen_rtx(SYMBOL_REF, Pmode, "__concatstring"),
+ 0, Pmode, 5, XEXP (targetx, 0), Pmode,
+ op0, GET_MODE (op0),
+ convert_to_mode (TYPE_MODE (sizetype),
+ size0, TREE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype),
+ op1, GET_MODE (op1),
+ convert_to_mode (TYPE_MODE (sizetype),
+ size1, TREE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
+ }
+ if (targetx != target)
+ emit_move_insn (target, targetx);
+ return target;
+ }
+
+ /* FIXME: the set_length computed below is a compile-time constant;
+ you'll need to re-write that part for VARYING bit arrays, and
+ possibly the set pointer will need to be adjusted to point past
+ the word containing its dynamic length. */
+
+ /* void __notpowerset (char *out, char *src,
+ unsigned long bitlength) */
+ case SET_NOT_EXPR:
+ {
+
+ tree expr = TREE_OPERAND (exp, 0);
+ tree tsize = powersetlen (expr);
+ rtx targetx;
+
+ if (TREE_CODE (TREE_TYPE (expr)) != SET_TYPE)
+ tsize = fold (build (MULT_EXPR, sizetype, tsize,
+ size_int (BITS_PER_UNIT)));
+
+ /* expand 1st operand to a pointer to the set */
+ op0 = expand_expr (force_addr_of (expr),
+ NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
+
+ /* build a temp for the result, target is its address */
+ if (target == NULL_RTX)
+ {
+ target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)),
+ int_size_in_bytes (TREE_TYPE (exp)),
+ 0);
+ preserve_temp_slots (target);
+ }
+ if (GET_CODE (target) == MEM)
+ targetx = target;
+ else
+ targetx = assign_stack_temp (GET_MODE (target),
+ GET_MODE_SIZE (GET_MODE (target)),
+ 0);
+ emit_library_call (gen_rtx(SYMBOL_REF, Pmode, "__notpowerset"),
+ 0, VOIDmode, 3, XEXP (targetx, 0), Pmode,
+ op0, GET_MODE (op0),
+ expand_expr (tsize, NULL_RTX, MEM,
+ EXPAND_CONST_ADDRESS),
+ TYPE_MODE (long_unsigned_type_node));
+ if (targetx != target)
+ emit_move_insn (target, targetx);
+ return target;
+ }
+
+ case SET_DIFF_EXPR:
+ lib_func = "__diffpowerset";
+ goto format_2;
+
+ case SET_IOR_EXPR:
+ lib_func = "__orpowerset";
+ goto format_2;
+
+ case SET_XOR_EXPR:
+ lib_func = "__xorpowerset";
+ goto format_2;
+
+ /* void __diffpowerset (char *out, char *left, char *right,
+ unsigned bitlength) */
+ case SET_AND_EXPR:
+ lib_func = "__andpowerset";
+ format_2:
+ {
+ tree expr = TREE_OPERAND (exp, 0);
+ tree tsize = powersetlen (expr);
+ rtx targetx;
+
+ if (TREE_CODE (TREE_TYPE (expr)) != SET_TYPE)
+ tsize = fold (build (MULT_EXPR, long_unsigned_type_node,
+ tsize,
+ size_int (BITS_PER_UNIT)));
+
+ /* expand 1st operand to a pointer to the set */
+ op0 = expand_expr (force_addr_of (expr),
+ NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
+
+ /* expand 2nd operand to a pointer to the set */
+ op1 = expand_expr (force_addr_of (TREE_OPERAND (exp, 1)),
+ NULL_RTX, MEM,
+ EXPAND_CONST_ADDRESS);
+
+/* FIXME: re-examine this code - the unary operator code above has recently
+ (93/03/12) been changed a lot. Should this code also change? */
+ /* build a temp for the result, target is its address */
+ if (target == NULL_RTX)
+ {
+ target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)),
+ int_size_in_bytes (TREE_TYPE (exp)),
+ 0);
+ preserve_temp_slots (target);
+ }
+ if (GET_CODE (target) == MEM)
+ targetx = target;
+ else
+ targetx = assign_stack_temp (GET_MODE (target),
+ GET_MODE_SIZE (GET_MODE (target)), 0);
+ emit_library_call (gen_rtx(SYMBOL_REF, Pmode, lib_func),
+ 0, VOIDmode, 4, XEXP (targetx, 0), Pmode,
+ op0, GET_MODE (op0), op1, GET_MODE (op1),
+ expand_expr (tsize, NULL_RTX, MEM,
+ EXPAND_CONST_ADDRESS),
+ TYPE_MODE (long_unsigned_type_node));
+ if (target != targetx)
+ emit_move_insn (target, targetx);
+ return target;
+ }
+
+ case SET_IN_EXPR:
+ {
+ extern tree lookup_name PROTO((tree));
+ tree set = TREE_OPERAND (exp, 1);
+ tree pos = convert (long_unsigned_type_node, TREE_OPERAND (exp, 0));
+ tree set_type = TREE_TYPE (set);
+ tree set_length = discrete_count (TYPE_DOMAIN (set_type));
+ tree min_val = convert (long_integer_type_node,
+ TYPE_MIN_VALUE (TYPE_DOMAIN (set_type)));
+ tree fcall;
+
+ /* FIXME: Function-call not needed if pos and width are constant! */
+ if (! mark_addressable (set))
+ {
+ error ("powerset is not addressable");
+ return const0_rtx;
+ }
+ /* we use different functions for bitstrings and powersets */
+ if (CH_BOOLS_TYPE_P (set_type))
+ fcall =
+ build_chill_function_call (
+ lookup_name (get_identifier ("__inbitstring")),
+ tree_cons (NULL_TREE,
+ convert (long_unsigned_type_node, pos),
+ tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR, build_pointer_type (set_type), set),
+ tree_cons (NULL_TREE,
+ convert (long_unsigned_type_node, set_length),
+ tree_cons (NULL_TREE, min_val,
+ tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()),
+ build_tree_list (NULL_TREE, get_chill_linenumber ())))))));
+ else
+ fcall =
+ build_chill_function_call (
+ lookup_name (get_identifier ("__inpowerset")),
+ tree_cons (NULL_TREE,
+ convert (long_unsigned_type_node, pos),
+ tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR, build_pointer_type (set_type), set),
+ tree_cons (NULL_TREE,
+ convert (long_unsigned_type_node, set_length),
+ build_tree_list (NULL_TREE, min_val)))));
+ return expand_expr (fcall, NULL_RTX, VOIDmode, 0);
+ }
+
+ case PACKED_ARRAY_REF:
+ {
+ extern tree lookup_name PROTO((tree));
+ tree array = TREE_OPERAND (exp, 0);
+ tree pos = save_expr (TREE_OPERAND (exp, 1));
+ tree array_type = TREE_TYPE (array);
+ tree array_length = discrete_count (TYPE_DOMAIN (array_type));
+ tree min_val = convert (long_integer_type_node,
+ TYPE_MIN_VALUE (TYPE_DOMAIN (array_type)));
+ tree fcall;
+
+ /* FIXME: Function-call not needed if pos and width are constant! */
+ /* TODO: make sure this makes sense. */
+ if (! mark_addressable (array))
+ {
+ error ("array is not addressable");
+ return const0_rtx;
+ }
+ fcall =
+ build_chill_function_call (
+ lookup_name (get_identifier ("__inpowerset")),
+ tree_cons (NULL_TREE,
+ convert (long_unsigned_type_node, pos),
+ tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR, build_pointer_type (array_type), array),
+ tree_cons (NULL_TREE,
+ convert (long_unsigned_type_node, array_length),
+ build_tree_list (NULL_TREE, min_val)))));
+ return expand_expr (fcall, NULL_RTX, VOIDmode, 0);
+ }
+
+ case UNDEFINED_EXPR:
+ if (target == 0)
+ {
+ target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)),
+ int_size_in_bytes (TREE_TYPE (exp)), 0);
+ preserve_temp_slots (target);
+ }
+ /* We don't actually need to *do* anything ... */
+ return target;
+
+ default:
+ break;
+ }
+
+ /* NOTREACHED */
+ return NULL;
+}
+
+/* Check that the argument list has a length in [min_length .. max_length].
+ (max_length == -1 means "infinite".)
+ If so return the actual length.
+ Otherwise, return an error message and return -1. */
+
+static int
+check_arglist_length (args, min_length, max_length, name)
+ tree args;
+ int min_length;
+ int max_length;
+ tree name;
+{
+ int length = list_length (args);
+ if (length < min_length)
+ error ("Too few arguments in call to `%s'", IDENTIFIER_POINTER (name));
+ else if (max_length != -1 && length > max_length)
+ error ("Too many arguments in call to `%s'", IDENTIFIER_POINTER (name));
+ else
+ return length;
+ return -1;
+}
+
+/*
+ * This is the code from c-typeck.c, with the C-specific cruft
+ * removed (possibly I just didn't understand it, but it was
+ * apparently simply discarding part of my LIST).
+ */
+static tree
+internal_build_compound_expr (list, first_p)
+ tree list;
+ int first_p;
+{
+ register tree rest;
+
+ if (TREE_CHAIN (list) == 0)
+ return TREE_VALUE (list);
+
+ rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
+
+ if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
+ return rest;
+
+ return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
+}
+
+
+/* Given a list of expressions, return a compound expression
+ that performs them all and returns the value of the last of them. */
+/* FIXME: this should be merged with the C version */
+tree
+build_chill_compound_expr (list)
+ tree list;
+{
+ return internal_build_compound_expr (list, TRUE);
+}
+
+/* Given an expression PTR for a pointer, return an expression
+ for the value pointed to.
+ do_empty_check is 0, don't perform a NULL pointer check,
+ else do it. */
+
+tree
+build_chill_indirect_ref (ptr, mode, do_empty_check)
+ tree ptr;
+ tree mode;
+ int do_empty_check;
+{
+ register tree type;
+
+ if (ptr == NULL_TREE || TREE_CODE (ptr) == ERROR_MARK)
+ return ptr;
+ if (mode != NULL_TREE && TREE_CODE (mode) == ERROR_MARK)
+ return error_mark_node;
+
+ type = TREE_TYPE (ptr);
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ type = TREE_TYPE (type);
+ ptr = convert (type, ptr);
+ }
+
+ /* check for ptr is really a POINTER */
+ if (TREE_CODE (type) != POINTER_TYPE)
+ {
+ error ("cannot dereference, not a pointer.");
+ return error_mark_node;
+ }
+
+ if (mode && TREE_CODE (mode) == IDENTIFIER_NODE)
+ {
+ tree decl = lookup_name (mode);
+ if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL)
+ {
+ if (pass == 2)
+ error ("missing '.' operator or undefined mode name `%s'.",
+ IDENTIFIER_POINTER (mode));
+#if 0
+ error ("You have forgotten the '.' operator which must");
+ error (" precede a STRUCT field reference, or `%s' is an undefined mode",
+ IDENTIFIER_POINTER (mode));
+#endif
+ return error_mark_node;
+ }
+ }
+
+ if (mode)
+ {
+ mode = get_type_of (mode);
+ ptr = convert (build_pointer_type (mode), ptr);
+ }
+ else if (type == ptr_type_node)
+ {
+ error ("Can't dereference PTR value using unary `->'.");
+ return error_mark_node;
+ }
+
+ if (do_empty_check)
+ ptr = check_non_null (ptr);
+
+ type = TREE_TYPE (ptr);
+
+ if (TREE_CODE (type) == POINTER_TYPE)
+ {
+ if (TREE_CODE (ptr) == ADDR_EXPR
+ && !flag_volatile
+ && (TREE_TYPE (TREE_OPERAND (ptr, 0))
+ == TREE_TYPE (type)))
+ return TREE_OPERAND (ptr, 0);
+ else
+ {
+ tree t = TREE_TYPE (type);
+ register tree ref = build1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (t), ptr);
+
+ if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE)
+ {
+ error ("dereferencing pointer to incomplete type");
+ return error_mark_node;
+ }
+ if (TREE_CODE (t) == VOID_TYPE)
+ warning ("dereferencing `void *' pointer");
+
+ /* We *must* set TREE_READONLY when dereferencing a pointer to const,
+ so that we get the proper error message if the result is used
+ to assign to. Also, &* is supposed to be a no-op.
+ And ANSI C seems to specify that the type of the result
+ should be the const type. */
+ /* A de-reference of a pointer to const is not a const. It is valid
+ to change it via some other pointer. */
+ TREE_READONLY (ref) = TYPE_READONLY (t);
+ TREE_SIDE_EFFECTS (ref)
+ = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (ptr) || flag_volatile;
+ TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t) || flag_volatile;
+ return ref;
+ }
+ }
+ else if (TREE_CODE (ptr) != ERROR_MARK)
+ error ("invalid type argument of `->'");
+ return error_mark_node;
+}
+
+/* NODE is a COMPONENT_REF whose mode is an IDENTIFIER,
+ which is replaced by the proper FIELD_DECL.
+ Also do the right thing for variant records. */
+
+tree
+resolve_component_ref (node)
+ tree node;
+{
+ tree datum = TREE_OPERAND (node, 0);
+ tree field_name = TREE_OPERAND (node, 1);
+ tree type = TREE_TYPE (datum);
+ tree field;
+ if (TREE_CODE (datum) == ERROR_MARK)
+ return error_mark_node;
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ type = TREE_TYPE (type);
+ TREE_OPERAND (node, 0) = datum = convert (type, datum);
+ }
+ if (TREE_CODE (type) != RECORD_TYPE)
+ {
+ error ("operand of '.' is not a STRUCT");
+ return error_mark_node;
+ }
+
+ TREE_READONLY (node) = TREE_READONLY (datum);
+ TREE_SIDE_EFFECTS (node) = TREE_SIDE_EFFECTS (datum);
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ {
+ tree variant;
+ for (variant = TYPE_FIELDS (TREE_TYPE (field));
+ variant; variant = TREE_CHAIN (variant))
+ {
+ tree vfield;
+ for (vfield = TYPE_FIELDS (TREE_TYPE (variant));
+ vfield; vfield = TREE_CHAIN (vfield))
+ {
+ if (DECL_NAME (vfield) == field_name)
+ { /* Found a variant field */
+ datum = build (COMPONENT_REF, TREE_TYPE (field),
+ datum, field);
+ datum = build (COMPONENT_REF, TREE_TYPE (variant),
+ datum, variant);
+ TREE_OPERAND (node, 0) = datum;
+ TREE_OPERAND (node, 1) = vfield;
+ TREE_TYPE (node) = TREE_TYPE (vfield);
+ TREE_READONLY (node) |= TYPE_READONLY (TREE_TYPE (node));
+#if 0
+ if (flag_testing_tags)
+ {
+ tree tagtest = NOT IMPLEMENTED;
+ tree tagf = ridpointers[(int) RID_RANGEFAIL];
+ node = check_expression (node, tagtest,
+ tagf);
+ }
+#endif
+ return node;
+ }
+ }
+ }
+ }
+
+ if (DECL_NAME (field) == field_name)
+ { /* Found a fixed field */
+ TREE_OPERAND (node, 1) = field;
+ TREE_TYPE (node) = TREE_TYPE (field);
+ TREE_READONLY (node) |= TYPE_READONLY (TREE_TYPE (node));
+ return fold (node);
+ }
+ }
+
+ error ("No field named `%s'", IDENTIFIER_POINTER (field_name));
+ return error_mark_node;
+}
+
+tree
+build_component_ref (datum, field_name)
+ tree datum, field_name;
+{
+ tree node = build_nt (COMPONENT_REF, datum, field_name);
+ if (pass != 1)
+ node = resolve_component_ref (node);
+ return node;
+}
+
+/*
+ function checks (for build_chill_component_ref) if a given
+ type is really an instance type. CH_IS_INSTANCE_MODE is not
+ strict enough in this case, i.e. SYNMODE foo = STRUCT (a, b UINT)
+ is compatible to INSTANCE. */
+
+static int
+is_really_instance (type)
+ tree type;
+{
+ tree decl = TYPE_NAME (type);
+
+ if (decl == NULL_TREE)
+ /* this is not an instance */
+ return 0;
+
+ if (DECL_NAME (decl) == ridpointers[(int)RID_INSTANCE])
+ /* this is an instance */
+ return 1;
+
+ if (TYPE_FIELDS (type) == TYPE_FIELDS (instance_type_node))
+ /* we have a NEWMODE'd instance */
+ return 1;
+
+ return 0;
+}
+
+/* This function is called by the parse.
+ Here we check if the user tries to access a field in a type which is
+ layouted as a structure but isn't like INSTANCE, BUFFER, EVENT, ASSOCIATION,
+ ACCESS, TEXT, or VARYING array or character string.
+ We don't do this in build_component_ref cause this function gets
+ called from the compiler to access fields in one of the above mentioned
+ modes. */
+tree
+build_chill_component_ref (datum, field_name)
+ tree datum, field_name;
+{
+ tree type = TREE_TYPE (datum);
+ if ((type != NULL_TREE && TREE_CODE (type) == RECORD_TYPE) &&
+ ((CH_IS_INSTANCE_MODE (type) && is_really_instance (type)) ||
+ CH_IS_BUFFER_MODE (type) ||
+ CH_IS_EVENT_MODE (type) || CH_IS_ASSOCIATION_MODE (type) ||
+ CH_IS_ACCESS_MODE (type) || CH_IS_TEXT_MODE (type) ||
+ chill_varying_type_p (type)))
+ {
+ error ("operand of '.' is not a STRUCT");
+ return error_mark_node;
+ }
+ return build_component_ref (datum, field_name);
+}
+
+/*
+ * Check for invalid binary operands & unary operands
+ * RIGHT is 1 if checking right operand or unary operand;
+ * it is 0 if checking left operand.
+ *
+ * return 1 if the given operand is NOT compatible as the
+ * operand of the given operator
+ *
+ * return 0 if they might be compatible
+ */
+static int
+invalid_operand (code, type, right)
+ enum chill_tree_code code;
+ tree type;
+ int right; /* 1 if right operand */
+{
+ switch ((int)code)
+ {
+ case ADDR_EXPR:
+ break;
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_NOT_EXPR:
+ case BIT_XOR_EXPR:
+ goto relationals;
+ case CASE_EXPR:
+ break;
+ case CEIL_MOD_EXPR:
+ goto numerics;
+ case CONCAT_EXPR: /* must be static or varying char array */
+ if (TREE_CODE (type) == CHAR_TYPE)
+ return 0;
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE)
+ return 0;
+ if (!chill_varying_type_p (type))
+ return 1;
+ if (TREE_CODE (TREE_TYPE (CH_VARYING_ARRAY_TYPE (type)))
+ == CHAR_TYPE)
+ return 0;
+ else
+ return 1;
+ /* note: CHILL conditional expressions (COND_EXPR) won't come
+ * through here; they're routed straight to C-specific code */
+ case EQ_EXPR:
+ return 0; /* ANYTHING can be compared equal */
+ case FLOOR_MOD_EXPR:
+ if (TREE_CODE (type) == REAL_TYPE)
+ return 1;
+ goto numerics;
+ case GE_EXPR:
+ case GT_EXPR:
+ goto relatables;
+ case SET_IN_EXPR:
+ if (TREE_CODE (type) == SET_TYPE)
+ return 0;
+ else
+ return 1;
+ case PACKED_ARRAY_REF:
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return 0;
+ else
+ return 1;
+ case LE_EXPR:
+ case LT_EXPR:
+ relatables:
+ switch ((int)TREE_CODE(type)) /* right operand must be set/bitarray type */
+ {
+ case ARRAY_TYPE:
+ if (TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE)
+ return 0;
+ else
+ return 1;
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ case COMPLEX_TYPE:
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ case OFFSET_TYPE:
+ case POINTER_TYPE:
+ case REAL_TYPE:
+ case SET_TYPE:
+ return 0;
+ case FILE_TYPE:
+ case FUNCTION_TYPE:
+ case GRANT_TYPE:
+ case LANG_TYPE:
+ case METHOD_TYPE:
+ return 1;
+ case RECORD_TYPE:
+ if (chill_varying_type_p (type)
+ && TREE_CODE (TREE_TYPE (CH_VARYING_ARRAY_TYPE (type))) == CHAR_TYPE)
+ return 0;
+ else
+ return 1;
+ case REFERENCE_TYPE:
+ case SEIZE_TYPE:
+ case UNION_TYPE:
+ case VOID_TYPE:
+ return 1;
+ }
+ break;
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ goto numerics;
+ case NEGATE_EXPR:
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ return 0;
+ else
+ goto numerics;
+ case NE_EXPR:
+ return 0; /* ANYTHING can be compared unequal */
+ case NOP_EXPR:
+ return 0; /* ANYTHING can be converted */
+ case PLUS_EXPR:
+ numerics:
+ switch ((int)TREE_CODE(type)) /* left operand must be discrete type */
+ {
+ case ARRAY_TYPE:
+ if (right || TREE_CODE (TREE_TYPE (type)) != BOOLEAN_TYPE)
+ return 1;
+ else
+ return 0;
+ case CHAR_TYPE:
+ return right;
+ case BOOLEAN_TYPE:
+ case COMPLEX_TYPE:
+ case FILE_TYPE:
+ case FUNCTION_TYPE:
+ case GRANT_TYPE:
+ case LANG_TYPE:
+ case METHOD_TYPE:
+ case RECORD_TYPE:
+ case REFERENCE_TYPE:
+ case SEIZE_TYPE:
+ case UNION_TYPE:
+ case VOID_TYPE:
+ return 1;
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ case OFFSET_TYPE:
+ case POINTER_TYPE:
+ case REAL_TYPE:
+ case SET_TYPE:
+ return 0;
+ }
+ break;
+ case RANGE_EXPR:
+ break;
+
+ case REPLICATE_EXPR:
+ switch ((int)TREE_CODE(type)) /* right operand must be set/bitarray type */
+ {
+ case COMPLEX_TYPE:
+ case FILE_TYPE:
+ case FUNCTION_TYPE:
+ case GRANT_TYPE:
+ case LANG_TYPE:
+ case METHOD_TYPE:
+ case OFFSET_TYPE:
+ case POINTER_TYPE:
+ case RECORD_TYPE:
+ case REAL_TYPE:
+ case SEIZE_TYPE:
+ case UNION_TYPE:
+ case VOID_TYPE:
+ return 1;
+ case ARRAY_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ case REFERENCE_TYPE:
+ case SET_TYPE:
+ return 0;
+ }
+
+ case TRUNC_DIV_EXPR:
+ goto numerics;
+ case TRUNC_MOD_EXPR:
+ if (TREE_CODE (type) == REAL_TYPE)
+ return 1;
+ goto numerics;
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_NOT_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_OR_EXPR:
+ relationals:
+ switch ((int)TREE_CODE(type)) /* left operand must be discrete type */
+ {
+ case ARRAY_TYPE:
+ case CHAR_TYPE:
+ case COMPLEX_TYPE:
+ case ENUMERAL_TYPE:
+ case FILE_TYPE:
+ case FUNCTION_TYPE:
+ case GRANT_TYPE:
+ case INTEGER_TYPE:
+ case LANG_TYPE:
+ case METHOD_TYPE:
+ case OFFSET_TYPE:
+ case POINTER_TYPE:
+ case REAL_TYPE:
+ case RECORD_TYPE:
+ case REFERENCE_TYPE:
+ case SEIZE_TYPE:
+ case UNION_TYPE:
+ case VOID_TYPE:
+ return 1;
+ case BOOLEAN_TYPE:
+ case SET_TYPE:
+ return 0;
+ }
+ break;
+
+ default:
+ return 1; /* perhaps you forgot to add a new DEFTREECODE? */
+ }
+ return 1;
+}
+
+
+static int
+invalid_right_operand (code, type)
+ enum chill_tree_code code;
+ tree type;
+{
+ return invalid_operand (code, type, 1);
+}
+
+tree
+build_chill_abs (expr)
+ tree expr;
+{
+ tree temp;
+
+ if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+ || discrete_type_p (TREE_TYPE (expr)))
+ temp = fold (build1 (ABS_EXPR, TREE_TYPE (expr), expr));
+ else
+ {
+ error("ABS argument must be discrete or real mode");
+ return error_mark_node;
+ }
+ /* FIXME: should call
+ * cond_type_range_exception (temp);
+ */
+ return temp;
+}
+
+tree
+build_chill_abstime (exprlist)
+ tree exprlist;
+{
+ int mask = 0, i, numargs;
+ tree args = NULL_TREE;
+ tree filename, lineno;
+ int had_errors = 0;
+ tree tmp;
+
+ if (exprlist != NULL_TREE && TREE_CODE (exprlist) == ERROR_MARK)
+ return error_mark_node;
+
+ /* check for integer expressions */
+ i = 1;
+ tmp = exprlist;
+ while (tmp != NULL_TREE)
+ {
+ tree exp = TREE_VALUE (tmp);
+
+ if (exp == NULL_TREE || TREE_CODE (exp) == ERROR_MARK)
+ had_errors = 1;
+ else if (TREE_CODE (TREE_TYPE (exp)) != INTEGER_TYPE)
+ {
+ error ("argument %d to ABSTIME must be of integer type.", i);
+ had_errors = 1;
+ }
+ tmp = TREE_CHAIN (tmp);
+ i++;
+ }
+ if (had_errors)
+ return error_mark_node;
+
+ numargs = list_length (exprlist);
+ for (i = 0; i < numargs; i++)
+ mask |= (1 << i);
+
+ /* make it all arguments */
+ for (i = numargs; i < 6; i++)
+ exprlist = tree_cons (NULL_TREE, integer_zero_node, exprlist);
+
+ args = tree_cons (NULL_TREE, build_int_2 (mask, 0), exprlist);
+
+ filename = force_addr_of (get_chill_filename ());
+ lineno = get_chill_linenumber ();
+ args = chainon (args, tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, lineno, NULL_TREE)));
+
+ return build_chill_function_call (
+ lookup_name (get_identifier ("_abstime")), args);
+}
+
+
+tree
+build_allocate_memory_call (ptr, size)
+ tree ptr, size;
+{
+ int err = 0;
+
+ /* check for ptr is referable */
+ if (! CH_REFERABLE (ptr))
+ {
+ error ("parameter 1 must be referable.");
+ err++;
+ }
+ /* check for pointer */
+ else if (TREE_CODE (TREE_TYPE (ptr)) != POINTER_TYPE)
+ {
+ error ("mode mismatch in parameter 1.");
+ err++;
+ }
+
+ /* check for size > 0 if it is a constant */
+ if (TREE_CODE (size) == INTEGER_CST && TREE_INT_CST_LOW (size) <= 0)
+ {
+ error ("parameter 2 must be a positive integer.");
+ err++;
+ }
+ if (err)
+ return error_mark_node;
+
+ if (TREE_TYPE (ptr) != ptr_type_node)
+ ptr = build_chill_cast (ptr_type_node, ptr);
+
+ return build_chill_function_call (
+ lookup_name (get_identifier ("_allocate_memory")),
+ tree_cons (NULL_TREE, ptr,
+ tree_cons (NULL_TREE, size,
+ tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()),
+ tree_cons (NULL_TREE, get_chill_linenumber (),
+ NULL_TREE)))));
+}
+
+
+tree
+build_allocate_global_memory_call (ptr, size)
+ tree ptr, size;
+{
+ int err = 0;
+
+ /* check for ptr is referable */
+ if (! CH_REFERABLE (ptr))
+ {
+ error ("parameter 1 must be referable.");
+ err++;
+ }
+ /* check for pointer */
+ else if (TREE_CODE (TREE_TYPE (ptr)) != POINTER_TYPE)
+ {
+ error ("mode mismatch in parameter 1.");
+ err++;
+ }
+
+ /* check for size > 0 if it is a constant */
+ if (TREE_CODE (size) == INTEGER_CST && TREE_INT_CST_LOW (size) <= 0)
+ {
+ error ("parameter 2 must be a positive integer.");
+ err++;
+ }
+ if (err)
+ return error_mark_node;
+
+ if (TREE_TYPE (ptr) != ptr_type_node)
+ ptr = build_chill_cast (ptr_type_node, ptr);
+
+ return build_chill_function_call (
+ lookup_name (get_identifier ("_allocate_global_memory")),
+ tree_cons (NULL_TREE, ptr,
+ tree_cons (NULL_TREE, size,
+ tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()),
+ tree_cons (NULL_TREE, get_chill_linenumber (),
+ NULL_TREE)))));
+}
+
+
+tree
+build_return_memory (ptr)
+ tree ptr;
+{
+ /* check input */
+ if (ptr == NULL_TREE || TREE_CODE (ptr) == ERROR_MARK)
+ return error_mark_node;
+
+ /* check for pointer */
+ if (TREE_CODE (TREE_TYPE (ptr)) != POINTER_TYPE)
+ {
+ error ("mode mismatch in parameter 1.");
+ return error_mark_node;
+ }
+
+ if (TREE_TYPE (ptr) != ptr_type_node)
+ ptr = build_chill_cast (ptr_type_node, ptr);
+
+ return build_chill_function_call (
+ lookup_name (get_identifier ("_return_memory")),
+ tree_cons (NULL_TREE, ptr,
+ tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()),
+ tree_cons (NULL_TREE, get_chill_linenumber (),
+ NULL_TREE))));
+}
+
+
+/* Compute the number of runtime members of the
+ * given powerset.
+ */
+tree
+build_chill_card (powerset)
+ tree powerset;
+{
+ if (pass == 2)
+ {
+ tree temp;
+ tree card_func = lookup_name (get_identifier ("__cardpowerset"));
+
+ if (powerset == NULL_TREE || TREE_CODE (powerset) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (powerset) == IDENTIFIER_NODE)
+ powerset = lookup_name (powerset);
+
+ if (TREE_CODE (TREE_TYPE(powerset)) == SET_TYPE)
+ { int size;
+
+ /* Do constant folding, if possible. */
+ if (TREE_CODE (powerset) == CONSTRUCTOR & TREE_CONSTANT (powerset)
+ && (size = int_size_in_bytes (TREE_TYPE (powerset))) >= 0)
+ {
+ int bit_size = size * BITS_PER_UNIT;
+ char* buffer = (char*) alloca (bit_size);
+ temp = get_set_constructor_bits (powerset, buffer, bit_size);
+ if (!temp)
+ { int i;
+ int count = 0;
+ for (i = 0; i < bit_size; i++)
+ if (buffer[i])
+ count++;
+ temp = build_int_2 (count, 0);
+ TREE_TYPE (temp) = TREE_TYPE (TREE_TYPE (card_func));
+ return temp;
+ }
+ }
+ temp = build_chill_function_call (card_func,
+ tree_cons (NULL_TREE, force_addr_of (powerset),
+ tree_cons (NULL_TREE, powersetlen (powerset), NULL_TREE)));
+ /* FIXME: should call
+ * cond_type_range_exception (op0);
+ */
+ return temp;
+ }
+ error("CARD argument must be powerset mode");
+ return error_mark_node;
+ }
+ return NULL_TREE;
+}
+
+/* function to build the type needed for the DESCR-built-in
+ */
+
+void build_chill_descr_type ()
+{
+ tree decl1, decl2;
+
+ if (descr_type != NULL_TREE)
+ /* already done */
+ return;
+
+ decl1 = build_decl (FIELD_DECL, get_identifier ("datap"), ptr_type_node);
+ decl2 = build_decl (FIELD_DECL, get_identifier ("len"),
+ TREE_TYPE (lookup_name (
+ get_identifier ((ignore_case || ! special_UC) ? "ulong" : "ULONG"))));
+ TREE_CHAIN (decl1) = decl2;
+ TREE_CHAIN (decl2) = NULL_TREE;
+ decl2 = build_chill_struct_type (decl1);
+ descr_type = build_decl (TYPE_DECL, get_identifier ("__tmp_DESCR_type"), decl2);
+ pushdecl (descr_type);
+ DECL_SOURCE_LINE (descr_type) = 0;
+ satisfy_decl (descr_type, 0);
+}
+
+/* build a pointer to a descriptor.
+ * descriptor = STRUCT (datap PTR,
+ * len ULONG);
+ * This descriptor is build in variable descr_type.
+ */
+
+tree
+build_chill_descr (expr)
+ tree expr;
+{
+ if (pass == 2)
+ {
+ tree tuple, decl, descr_var, datap, len, tmp;
+ int is_static;
+
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+
+ /* check for expression is referable */
+ if (! CH_REFERABLE (expr))
+ {
+ error ("expression for DESCR-builtin must be referable.");
+ return error_mark_node;
+ }
+
+ mark_addressable (expr);
+#if 0
+ datap = build1 (ADDR_EXPR, build_chill_pointer_type (descr_type), expr);
+#else
+ datap = build_chill_arrow_expr (expr, 1);
+#endif
+ len = size_in_bytes (TREE_TYPE (expr));
+
+ descr_var = get_unique_identifier ("DESCR");
+ tuple = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE, datap,
+ tree_cons (NULL_TREE, len, NULL_TREE)));
+
+ is_static = (current_function_decl == global_function_decl) && TREE_STATIC (expr);
+ decl = decl_temp1 (descr_var, TREE_TYPE (descr_type), is_static,
+ tuple, 0, 0);
+#if 0
+ tmp = force_addr_of (decl);
+#else
+ tmp = build_chill_arrow_expr (decl, 1);
+#endif
+ return tmp;
+ }
+ return NULL_TREE;
+}
+
+/* this function process the builtin's
+ MILLISECS, SECS, MINUTES, HOURS and DAYS.
+ The built duration value is in milliseconds. */
+
+tree
+build_chill_duration (expr, multiplier, fnname, maxvalue)
+ tree expr;
+ unsigned long multiplier;
+ tree fnname;
+ unsigned long maxvalue;
+{
+ tree temp;
+
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)
+ {
+ error ("argument to `%s' must be of integer type.", IDENTIFIER_POINTER (fnname));
+ return error_mark_node;
+ }
+
+ temp = convert (duration_timing_type_node, expr);
+ temp = fold (build (MULT_EXPR, duration_timing_type_node,
+ temp, build_int_2 (multiplier, 0)));
+
+ if (range_checking)
+ temp = check_range (temp, expr, integer_zero_node, build_int_2 (maxvalue, 0));
+
+ return temp;
+}
+
+/* build function call to one of the floating point functions */
+static tree
+build_chill_floatcall (expr, chillname, funcname)
+ tree expr;
+ char *chillname;
+ char *funcname;
+{
+ tree result;
+ tree type;
+
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+
+ /* look if expr is a REAL_TYPE */
+ type = TREE_TYPE (expr);
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+ if (TREE_CODE (type) != REAL_TYPE)
+ {
+ error ("argument 1 to `%s' must be of floating point mode", chillname);
+ return error_mark_node;
+ }
+ result = build_chill_function_call (
+ lookup_name (get_identifier (funcname)),
+ tree_cons (NULL_TREE, expr, NULL_TREE));
+ return result;
+}
+
+/* common function for ALLOCATE and GETSTACK */
+static tree
+build_allocate_getstack (mode, value, chill_name, fnname, filename, linenumber)
+ tree mode;
+ tree value;
+ char *chill_name;
+ char *fnname;
+ tree filename;
+ tree linenumber;
+{
+ tree type, result;
+ tree expr = NULL_TREE;
+ tree args, tmpvar, fncall, ptr, init, outlist = NULL_TREE;
+
+ if (mode == NULL_TREE || TREE_CODE (mode) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (mode) == TYPE_DECL)
+ type = TREE_TYPE (mode);
+ else
+ type = mode;
+
+ /* check if we have a mode */
+ if (TREE_CODE_CLASS (TREE_CODE (type)) != 't')
+ {
+ error ("First argument to `%s' must be a mode", chill_name);
+ return error_mark_node;
+ }
+
+ /* check if we have a value if type is READonly */
+ if (TYPE_READONLY_PROPERTY (type) && value == NULL_TREE)
+ {
+ error ("READonly modes for %s must have a value", chill_name);
+ return error_mark_node;
+ }
+
+ if (value != NULL_TREE)
+ {
+ if (TREE_CODE (value) == ERROR_MARK)
+ return error_mark_node;
+ expr = chill_convert_for_assignment (type, value, "assignment");
+ }
+
+ /* build function arguments */
+ if (filename == NULL_TREE)
+ args = tree_cons (NULL_TREE, size_in_bytes (type), NULL_TREE);
+ else
+ args = tree_cons (NULL_TREE, size_in_bytes (type),
+ tree_cons (NULL_TREE, force_addr_of (filename),
+ tree_cons (NULL_TREE, linenumber, NULL_TREE)));
+
+ ptr = build_chill_pointer_type (type);
+ tmpvar = decl_temp1 (get_unique_identifier (chill_name),
+ ptr, 0, NULL_TREE, 0, 0);
+ fncall = build_chill_function_call (
+ lookup_name (get_identifier (fnname)), args);
+ outlist = tree_cons (NULL_TREE,
+ build_chill_modify_expr (tmpvar, fncall), outlist);
+ if (expr == NULL_TREE)
+ {
+ /* set allocated memory to 0 */
+ fncall = build_chill_function_call (
+ lookup_name (get_identifier ("memset")),
+ tree_cons (NULL_TREE, convert (ptr_type_node, tmpvar),
+ tree_cons (NULL_TREE, integer_zero_node,
+ tree_cons (NULL_TREE, size_in_bytes (type), NULL_TREE))));
+ outlist = tree_cons (NULL_TREE, fncall, outlist);
+ }
+ else
+ {
+ /* write the init value to allocated memory */
+ outlist = tree_cons (NULL_TREE,
+ build_chill_modify_expr (build_chill_indirect_ref (tmpvar, NULL_TREE, 0),
+ expr),
+ outlist);
+ }
+ outlist = tree_cons (NULL_TREE, tmpvar, outlist);
+ result = build_chill_compound_expr (nreverse (outlist));
+ return result;
+}
+
+/* process the ALLOCATE built-in */
+tree
+build_chill_allocate (mode, value)
+ tree mode;
+ tree value;
+{
+ return build_allocate_getstack (mode, value, "ALLOCATE", "__allocate",
+ get_chill_filename (), get_chill_linenumber ());
+}
+
+/* process the GETSTACK built-in */
+tree
+build_chill_getstack (mode, value)
+ tree mode;
+ tree value;
+{
+ return build_allocate_getstack (mode, value, "GETSTACK", "__builtin_alloca",
+ NULL_TREE, NULL_TREE);
+}
+
+/* process the TERMINATE built-in */
+tree
+build_chill_terminate (ptr)
+ tree ptr;
+{
+ tree result;
+ tree type;
+
+ if (ptr == NULL_TREE || TREE_CODE (ptr) == ERROR_MARK)
+ return error_mark_node;
+
+ type = TREE_TYPE (ptr);
+ if (type == NULL_TREE || TREE_CODE (type) != POINTER_TYPE)
+ {
+ error ("argument to TERMINATE must be a reference primitive value");
+ return error_mark_node;
+ }
+ result = build_chill_function_call (
+ lookup_name (get_identifier ("__terminate")),
+ tree_cons (NULL_TREE, convert (ptr_type_node, ptr),
+ tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()),
+ tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))));
+ return result;
+}
+
+/* build the type passed to _inttime function */
+void
+build_chill_inttime_type ()
+{
+ tree idxlist;
+ tree arrtype;
+ tree decl;
+
+ idxlist = build_tree_list (NULL_TREE,
+ build_chill_range_type (NULL_TREE,
+ integer_zero_node,
+ build_int_2 (5, 0)));
+ arrtype = build_chill_array_type (ptr_type_node, idxlist, 0, NULL_TREE);
+
+ decl = build_decl (TYPE_DECL, get_identifier ("__tmp_INTTIME_type"), arrtype);
+ pushdecl (decl);
+ DECL_SOURCE_LINE (decl) = 0;
+ satisfy_decl (decl, 0);
+}
+
+tree
+build_chill_inttime (t, loclist)
+ tree t, loclist;
+{
+ int had_errors = 0, cnt;
+ tree tmp;
+ tree init = NULL_TREE;
+ int numargs;
+ tree tuple, var;
+
+ if (t == NULL_TREE || TREE_CODE (t) == ERROR_MARK)
+ return error_mark_node;
+ if (loclist == NULL_TREE || TREE_CODE (loclist) == ERROR_MARK)
+ return error_mark_node;
+
+ /* check first argument to be NEWMODE TIME */
+ if (TREE_TYPE (t) != abs_timing_type_node)
+ {
+ error ("argument 1 to INTTIME must be of mode TIME.");
+ had_errors = 1;
+ }
+
+ cnt = 2;
+ tmp = loclist;
+ while (tmp != NULL_TREE)
+ {
+ tree loc = TREE_VALUE (tmp);
+ char errmsg[200];
+ char *p, *p1;
+ int write_error = 0;
+
+ sprintf (errmsg, "argument %d to INTTIME must be ", cnt);
+ p = errmsg + strlen (errmsg);
+ p1 = p;
+
+ if (loc == NULL_TREE || TREE_CODE (loc) == ERROR_MARK)
+ had_errors = 1;
+ else
+ {
+ if (! CH_REFERABLE (loc))
+ {
+ strcpy (p, "referable");
+ p += strlen (p);
+ write_error = 1;
+ had_errors = 1;
+ }
+ if (TREE_CODE (TREE_TYPE (loc)) != INTEGER_TYPE)
+ {
+ if (p != p1)
+ {
+ strcpy (p, " and ");
+ p += strlen (p);
+ }
+ strcpy (p, "of integer type");
+ write_error = 1;
+ had_errors = 1;
+ }
+ /* FIXME: what's about ranges can't hold the result ?? */
+ if (write_error)
+ error ("%s.", errmsg);
+ }
+ /* next location */
+ tmp = TREE_CHAIN (tmp);
+ cnt++;
+ }
+
+ if (had_errors)
+ return error_mark_node;
+
+ /* make it always 6 arguments */
+ numargs = list_length (loclist);
+ for (cnt = numargs; cnt < 6; cnt++)
+ init = tree_cons (NULL_TREE, null_pointer_node, init);
+
+ /* append the given one's */
+ tmp = loclist;
+ while (tmp != NULL_TREE)
+ {
+ init = chainon (init,
+ build_tree_list (NULL_TREE,
+ build_chill_descr (TREE_VALUE (tmp))));
+ tmp = TREE_CHAIN (tmp);
+ }
+
+ tuple = build_nt (CONSTRUCTOR, NULL_TREE, init);
+ var = decl_temp1 (get_unique_identifier ("INTTIME"),
+ TREE_TYPE (lookup_name (get_identifier ("__tmp_INTTIME_type"))),
+ 0, tuple, 0, 0);
+
+ return build_chill_function_call (
+ lookup_name (get_identifier ("_inttime")),
+ tree_cons (NULL_TREE, t,
+ tree_cons (NULL_TREE, force_addr_of (var),
+ NULL_TREE)));
+}
+
+
+/* Compute the runtime length of the given string variable
+ * or expression.
+ */
+tree
+build_chill_length (expr)
+ tree expr;
+{
+ if (pass == 2)
+ {
+ tree type;
+
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (expr) == IDENTIFIER_NODE)
+ expr = lookup_name (expr);
+
+ type = TREE_TYPE (expr);
+
+ if (TREE_CODE(type) == ERROR_MARK)
+ return type;
+ if (chill_varying_type_p (type))
+ {
+ tree temp = convert (integer_type_node,
+ build_component_ref (expr, var_length_id));
+ /* FIXME: should call
+ * cond_type_range_exception (temp);
+ */
+ return temp;
+ }
+
+ if ((TREE_CODE (type) == ARRAY_TYPE ||
+ /* should work for a bitstring too */
+ (TREE_CODE (type) == SET_TYPE && TREE_CODE (TREE_TYPE (type)) == BOOLEAN_TYPE)) &&
+ integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (type))))
+ {
+ tree temp = fold (build (PLUS_EXPR, chill_integer_type_node,
+ integer_one_node,
+ TYPE_MAX_VALUE (TYPE_DOMAIN (type))));
+ return convert (chill_integer_type_node, temp);
+ }
+
+ if (CH_IS_BUFFER_MODE (type) || CH_IS_EVENT_MODE (type))
+ {
+ tree len = max_queue_size (type);
+
+ if (len == NULL_TREE)
+ len = integer_minus_one_node;
+ return len;
+ }
+
+ if (CH_IS_TEXT_MODE (type))
+ {
+ if (TREE_CODE (expr) == TYPE_DECL)
+ {
+ /* text mode name */
+ return text_length (type);
+ }
+ else
+ {
+ /* text location */
+ tree temp = build_component_ref (
+ build_component_ref (expr, get_identifier ("tloc")),
+ var_length_id);
+ return convert (integer_type_node, temp);
+ }
+ }
+
+ error("LENGTH argument must be string, buffer, event mode, text location or mode");
+ return error_mark_node;
+ }
+ return NULL_TREE;
+}
+
+/* Compute the declared minimum/maximum value of the variable,
+ * expression or declared type
+ */
+static tree
+build_chill_lower_or_upper (what, is_upper)
+ tree what;
+ int is_upper; /* o -> LOWER; 1 -> UPPER */
+{
+ if (pass == 2)
+ {
+ tree type;
+ struct ch_class class;
+
+ if (what == NULL_TREE || TREE_CODE (what) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE_CLASS (TREE_CODE (what)) == 't')
+ type = what;
+ else
+ type = TREE_TYPE (what);
+ if (type == NULL_TREE)
+ {
+ if (is_upper)
+ error ("UPPER argument must have a mode, or be a mode");
+ else
+ error ("LOWER argument must have a mode, or be a mode");
+ return error_mark_node;
+ }
+ while (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ if (chill_varying_type_p (type))
+ type = CH_VARYING_ARRAY_TYPE (type);
+
+ if (discrete_type_p (type))
+ {
+ tree val = is_upper ? TYPE_MAX_VALUE (type) : TYPE_MIN_VALUE (type);
+ class.kind = CH_VALUE_CLASS;
+ class.mode = type;
+ return convert_to_class (class, val);
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == SET_TYPE)
+ {
+ if (TYPE_STRING_FLAG (type))
+ {
+ class.kind = CH_DERIVED_CLASS;
+ class.mode = integer_type_node;
+ }
+ else
+ {
+ class.kind = CH_VALUE_CLASS;
+ class.mode = TYPE_DOMAIN (type);
+ }
+ type = TYPE_DOMAIN (type);
+ return convert_to_class (class,
+ is_upper
+ ? TYPE_MAX_VALUE (type)
+ : TYPE_MIN_VALUE (type));
+ }
+ if (is_upper)
+ error("UPPER argument must be string, array, mode or integer");
+ else
+ error("LOWER argument must be string, array, mode or integer");
+ return error_mark_node;
+ }
+ return NULL_TREE;
+}
+
+tree
+build_chill_lower (what)
+ tree what;
+{
+ return build_chill_lower_or_upper (what, 0);
+}
+
+static tree
+build_max_min (expr, max_min)
+ tree expr;
+ int max_min; /* 0: calculate MIN; 1: calculate MAX */
+{
+ if (pass == 2)
+ {
+ tree type, temp, setminval;
+ tree set_base_type;
+ int size_in_bytes;
+
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (expr) == IDENTIFIER_NODE)
+ expr = lookup_name (expr);
+
+ type = TREE_TYPE (expr);
+ set_base_type = TYPE_DOMAIN (type);
+ setminval = TYPE_MIN_VALUE (set_base_type);
+
+ if (TREE_CODE (type) != SET_TYPE)
+ {
+ error("%s argument must be POWERSET mode",
+ max_min ? "MAX" : "MIN");
+ return error_mark_node;
+ }
+
+ /* find max/min of constant powerset at compile time */
+ if (TREE_CODE (expr) == CONSTRUCTOR && TREE_CONSTANT (expr)
+ && (size_in_bytes = int_size_in_bytes (type)) >= 0)
+ {
+ HOST_WIDE_INT min_val = -1, max_val = -1;
+ HOST_WIDE_INT i, i_hi = 0;
+ HOST_WIDE_INT size_in_bits = size_in_bytes * BITS_PER_UNIT;
+ char *buffer = (char*) alloca (size_in_bits);
+ if (buffer == NULL
+ || get_set_constructor_bits (expr, buffer, size_in_bits))
+ abort ();
+ for (i = 0; i < size_in_bits; i++)
+ {
+ if (buffer[i])
+ {
+ if (min_val < 0)
+ min_val = i;
+ max_val = i;
+ }
+ }
+ if (min_val < 0)
+ error ("%s called for empty POWERSET", max_min ? "MAX" : "MIN");
+ i = max_min ? max_val : min_val;
+ temp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (expr)));
+ add_double (i, i_hi,
+ TREE_INT_CST_LOW (temp), TREE_INT_CST_HIGH (temp),
+ &i, &i_hi);
+ temp = build_int_2 (i, i_hi);
+ TREE_TYPE (temp) = set_base_type;
+ return temp;
+ }
+ else
+ {
+ tree parmlist, filename, lineno;
+ char *funcname;
+
+ /* set up to call appropriate runtime function */
+ if (max_min)
+ funcname = "__flsetpowerset";
+ else
+ funcname = "__ffsetpowerset";
+
+ setminval = convert (long_integer_type_node, setminval);
+ filename = force_addr_of (get_chill_filename());
+ lineno = get_chill_linenumber();
+ parmlist = tree_cons (NULL_TREE, force_addr_of (expr),
+ tree_cons (NULL_TREE, powersetlen (expr),
+ tree_cons (NULL_TREE, setminval,
+ tree_cons (NULL_TREE, filename,
+ build_tree_list (NULL_TREE, lineno)))));
+ temp = lookup_name (get_identifier (funcname));
+ temp = build_chill_function_call (temp, parmlist);
+ TREE_TYPE (temp) = set_base_type;
+ return temp;
+ }
+ }
+ return NULL_TREE;
+}
+
+
+/* Compute the current runtime maximum value of the powerset
+ */
+tree
+build_chill_max (expr)
+ tree expr;
+{
+ return build_max_min (expr, 1);
+}
+
+
+/* Compute the current runtime minimum value of the powerset
+ */
+tree
+build_chill_min (expr)
+ tree expr;
+{
+ return build_max_min (expr, 0);
+}
+
+
+/* Build a conversion from the given expression to an INT,
+ * but only when the expression's type is the same size as
+ * an INT.
+ */
+tree
+build_chill_num (expr)
+ tree expr;
+{
+ if (pass == 2)
+ {
+ tree temp;
+ int need_unsigned;
+
+ if (expr == NULL_TREE || TREE_CODE(expr) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (expr) == IDENTIFIER_NODE)
+ expr = lookup_name (expr);
+
+ expr = convert_to_discrete (expr);
+ if (expr == NULL_TREE)
+ {
+ error ("argument to NUM is not discrete");
+ return error_mark_node;
+ }
+
+ /* enumeral types and string slices of length 1 must be kept unsigned */
+ need_unsigned = (TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE)
+ || TREE_UNSIGNED (TREE_TYPE (expr));
+
+ temp = type_for_size (TYPE_PRECISION (TREE_TYPE (expr)),
+ need_unsigned);
+ if (temp == NULL_TREE)
+ {
+ error ("No integer mode which matches expression's mode");
+ return integer_zero_node;
+ }
+ temp = convert (temp, expr);
+
+ if (TREE_CONSTANT (temp))
+ {
+ if (tree_int_cst_lt (temp,
+ TYPE_MIN_VALUE (TREE_TYPE (temp))))
+ error ("NUM's parameter is below its mode range");
+ if (tree_int_cst_lt (TYPE_MAX_VALUE (TREE_TYPE (temp)),
+ temp))
+ error ("NUM's parameter is above its mode range");
+ }
+#if 0
+ else
+ {
+ if (range_checking)
+ cond_overflow_exception (temp,
+ TYPE_MIN_VALUE (TREE_TYPE (temp)),
+ TYPE_MAX_VALUE (TREE_TYPE (temp)));
+ }
+#endif
+
+ /* NUM delivers the INT derived class */
+ CH_DERIVED_FLAG (temp) = 1;
+
+ return temp;
+ }
+ return NULL_TREE;
+}
+
+
+static tree
+build_chill_pred_or_succ (expr, op)
+ tree expr;
+ enum tree_code op; /* PLUS_EXPR for SUCC; MINUS_EXPR for PRED. */
+{
+ struct ch_class class;
+ tree etype, cond;
+ tree limit;
+
+ if (pass == 1)
+ return NULL_TREE;
+
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+
+ /* disallow numbered SETs */
+ if (TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE
+ && CH_ENUM_IS_NUMBERED (TREE_TYPE (expr)))
+ {
+ error ("Cannot take SUCC or PRED of a numbered SET");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
+ {
+ if (TREE_TYPE (TREE_TYPE (expr)) == void_type_node)
+ {
+ error ("SUCC or PRED must not be done on a PTR.");
+ return error_mark_node;
+ }
+ pedwarn ("SUCC or PRED for a reference type is not standard.");
+ return fold (build (op, TREE_TYPE (expr),
+ expr,
+ size_in_bytes (TREE_TYPE (TREE_TYPE (expr)))));
+ }
+
+ expr = convert_to_discrete (expr);
+
+ if (expr == NULL_TREE)
+ {
+ error ("SUCC or PRED argument must be a discrete mode");
+ return error_mark_node;
+ }
+
+ class = chill_expr_class (expr);
+ if (class.mode)
+ class.mode = CH_ROOT_MODE (class.mode);
+ etype = class.mode;
+ expr = convert (etype, expr);
+
+ /* Exception if expression is already at the
+ min (PRED)/max(SUCC) valid value for its type. */
+ cond = fold (build (op == PLUS_EXPR ? GE_EXPR : LE_EXPR,
+ boolean_type_node,
+ expr,
+ convert (etype,
+ op == PLUS_EXPR ? TYPE_MAX_VALUE (etype)
+ : TYPE_MIN_VALUE (etype))));
+ if (TREE_CODE (cond) == INTEGER_CST
+ && tree_int_cst_equal (cond, integer_one_node))
+ {
+ error ("Taking the %s of a value already at its %s value",
+ op == PLUS_EXPR ? "SUCC" : "PRED",
+ op == PLUS_EXPR ? "maximum" : "minimum");
+ return error_mark_node;
+ }
+
+ if (range_checking)
+ expr = check_expression (expr, cond,
+ ridpointers[(int) RID_OVERFLOW]);
+
+ expr = fold (build (op, etype, expr,
+ convert (etype, integer_one_node)));
+ return convert_to_class (class, expr);
+}
+
+/* Compute the value of the CHILL `size' operator just
+ * like the C 'sizeof' operator (code stolen from c-typeck.c)
+ * TYPE may be a location or mode tree. In pass 1, we build
+ * a function-call syntax tree; in pass 2, we evaluate it.
+ */
+tree
+build_chill_sizeof (type)
+ tree type;
+{
+ if (pass == 2)
+ {
+ tree temp;
+ struct ch_class class;
+ enum tree_code code;
+ tree signame = NULL_TREE;
+
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (type) == IDENTIFIER_NODE)
+ type = lookup_name (type);
+
+ code = TREE_CODE (type);
+ if (code == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE_CLASS (TREE_CODE (type)) != 't')
+ {
+ if (TREE_CODE (type) == TYPE_DECL && CH_DECL_SIGNAL (type))
+ signame = DECL_NAME (type);
+ type = TREE_TYPE (type);
+ }
+
+ if (code == FUNCTION_TYPE)
+ {
+ if (pedantic || warn_pointer_arith)
+ pedwarn ("size applied to a function mode");
+ return error_mark_node;
+ }
+ if (code == VOID_TYPE)
+ {
+ if (pedantic || warn_pointer_arith)
+ pedwarn ("sizeof applied to a void mode");
+ return error_mark_node;
+ }
+ if (TYPE_SIZE (type) == 0)
+ {
+ error ("sizeof applied to an incomplete mode");
+ return error_mark_node;
+ }
+
+ temp = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
+ size_int (TYPE_PRECISION (char_type_node)));
+ if (signame != NULL_TREE)
+ {
+ /* we have a signal definition. This signal may have no
+ data items specified. The definition however says that
+ there are data, cause we cannot build a structure without
+ fields. In this case return 0. */
+ if (IDENTIFIER_SIGNAL_DATA (signame) == 0)
+ temp = integer_zero_node;
+ }
+
+ /* FIXME: should call
+ * cond_type_range_exception (temp);
+ */
+ class.kind = CH_DERIVED_CLASS;
+ class.mode = integer_type_node;
+ return convert_to_class (class, temp);
+ }
+ return NULL_TREE;
+}
+
+/* Compute the declared maximum value of the variable,
+ * expression or declared type
+ */
+tree
+build_chill_upper (what)
+ tree what;
+{
+ return build_chill_lower_or_upper (what, 1);
+}
+
+/*
+ * Here at the site of a function/procedure call.. We need to build
+ * temps for the INOUT and OUT parameters, and copy the actual parameters
+ * into the temps. After the call, we 'copy back' the values from the
+ * temps to the actual parameter variables. This somewhat verbose pol-
+ * icy meets the requirement that the actual parameters are undisturbed
+ * if the function/procedure causes an exception. They are updated only
+ * upon a normal return from the function.
+ *
+ * Note: the expr_list, which collects all of the above assignments, etc,
+ * is built in REVERSE execution order. The list is corrected by nreverse
+ * inside the build_chill_compound_expr call.
+ */
+tree
+build_chill_function_call (function, expr)
+ tree function, expr;
+{
+ register tree typetail, valtail, typelist;
+ register tree temp, actual_args = NULL_TREE;
+ tree name = NULL_TREE;
+ tree function_call;
+ tree fntype;
+ int parmno = 1; /* parameter number for error message */
+ int callee_raise_exception = 0;
+
+ /* list of assignments to run after the actual call,
+ copying from the temps back to the user's variables. */
+ tree copy_back = NULL_TREE;
+
+ /* list of expressions to run before the call, copying from
+ the user's variable to the temps that are passed to the function */
+ tree expr_list = NULL_TREE;
+
+ if (function == NULL_TREE || TREE_CODE (function) == ERROR_MARK)
+ return error_mark_node;
+
+ if (expr != NULL_TREE && TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+
+ if (pass < 2)
+ return error_mark_node;
+
+ fntype = TREE_TYPE (function);
+ if (TREE_CODE (function) == FUNCTION_DECL)
+ {
+ callee_raise_exception = TYPE_RAISES_EXCEPTIONS (fntype) != NULL_TREE;
+
+ /* Differs from default_conversion by not setting TREE_ADDRESSABLE
+ (because calling an inline function does not mean the function
+ needs to be separately compiled). */
+ fntype = build_type_variant (fntype,
+ TREE_READONLY (function),
+ TREE_THIS_VOLATILE (function));
+ name = DECL_NAME (function);
+
+ /* check that function is not a PROCESS */
+ if (CH_DECL_PROCESS (function))
+ {
+ error ("cannot call a PROCESS, you START a PROCESS");
+ return error_mark_node;
+ }
+
+ function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
+ }
+ else if (TREE_CODE (fntype) == POINTER_TYPE)
+ {
+ fntype = TREE_TYPE (fntype);
+ callee_raise_exception = TYPE_RAISES_EXCEPTIONS (fntype) != NULL_TREE;
+
+ /* Z.200 6.7 Call Action:
+ "A procedure call causes the EMPTY exception if the
+ procedure primitive value delivers NULL. */
+ if (TREE_CODE (function) != ADDR_EXPR
+ || TREE_CODE (TREE_OPERAND (function, 0)) != FUNCTION_DECL)
+ function = check_non_null (function);
+ }
+
+ typelist = TYPE_ARG_TYPES (fntype);
+ if (callee_raise_exception)
+ {
+ /* remove last two arguments from list for subsequent checking.
+ They will get added automatically after checking */
+ int len = list_length (typelist);
+ int i;
+ tree newtypelist = NULL_TREE;
+ tree wrk = typelist;
+
+ for (i = 0; i < len - 3; i++)
+ {
+ newtypelist = tree_cons (TREE_PURPOSE (wrk), TREE_VALUE (wrk), newtypelist);
+ wrk = TREE_CHAIN (wrk);
+ }
+ /* add the void_type_node */
+ newtypelist = tree_cons (NULL_TREE, void_type_node, newtypelist);
+ typelist = nreverse (newtypelist);
+ }
+
+ /* Scan the given expressions and types, producing individual
+ converted arguments and pushing them on ACTUAL_ARGS in
+ reverse order. */
+ for (valtail = expr, typetail = typelist;
+ valtail != NULL_TREE && typetail != NULL_TREE; parmno++,
+ valtail = TREE_CHAIN (valtail), typetail = TREE_CHAIN (typetail))
+ {
+ register tree actual = TREE_VALUE (valtail);
+ register tree attr = TREE_PURPOSE (typetail)
+ ? TREE_PURPOSE (typetail) : ridpointers[(int) RID_IN];
+ register tree type = TREE_VALUE (typetail);
+ char place[30];
+ sprintf (place, "parameter %d", parmno);
+
+ /* if we have reached void_type_node in typelist we are at the
+ end of formal parameters and then we have too many actual
+ parameters */
+ if (type == void_type_node)
+ break;
+
+ /* check if actual is a TYPE_DECL. FIXME: what else ? */
+ if (TREE_CODE (actual) == TYPE_DECL)
+ {
+ error ("invalid %s", place);
+ actual = error_mark_node;
+ }
+ /* INOUT or OUT param to handle? */
+ else if (attr == ridpointers[(int) RID_OUT]
+ || attr == ridpointers[(int)RID_INOUT])
+ {
+ char temp_name[20];
+ tree parmtmp;
+ tree in_actual = NULL_TREE, out_actual;
+
+ /* actual parameter must be a location so we can
+ build a reference to it */
+ if (!CH_LOCATION_P (actual))
+ {
+ error ("%s parameter %d must be a location",
+ (attr == ridpointers[(int) RID_OUT]) ?
+ "OUT" : "INOUT", parmno);
+ continue;
+ }
+ if (TYPE_READONLY_PROPERTY (TREE_TYPE (actual))
+ || TREE_READONLY (actual))
+ {
+ error ("%s parameter %d is READ-only",
+ (attr == ridpointers[(int) RID_OUT]) ?
+ "OUT" : "INOUT", parmno);
+ continue;
+ }
+
+ sprintf (temp_name, "PARM_%d_%s", parmno,
+ (attr == ridpointers[(int)RID_OUT]) ?
+ "OUT" : "INOUT");
+ parmtmp = decl_temp1 (get_unique_identifier (temp_name),
+ TREE_TYPE (type), 0, NULL_TREE, 0, 0);
+ /* this temp *must not* be optimized into a register */
+ mark_addressable (parmtmp);
+
+ if (attr == ridpointers[(int)RID_INOUT])
+ {
+ tree in_actual = chill_convert_for_assignment (TREE_TYPE (type),
+ actual, place);
+ tree tmp = build_chill_modify_expr (parmtmp, in_actual);
+ expr_list = tree_cons (NULL_TREE, tmp, expr_list);
+ }
+ if (in_actual != error_mark_node)
+ {
+ /* list of copy back assignments to perform, from the temp
+ back to the actual parameter */
+ out_actual = chill_convert_for_assignment (TREE_TYPE (actual),
+ parmtmp, place);
+ copy_back = tree_cons (NULL_TREE,
+ build_chill_modify_expr (actual,
+ out_actual),
+ copy_back);
+ }
+ /* we can do this because build_chill_function_type
+ turned these parameters into REFERENCE_TYPEs. */
+ actual = build1 (ADDR_EXPR, type, parmtmp);
+ }
+ else if (attr == ridpointers[(int) RID_LOC])
+ {
+ int is_location = chill_location (actual);
+ if (is_location)
+ {
+ if (is_location == 1)
+ {
+ error ("LOC actual parameter %d is a non-referable location",
+ parmno);
+ actual = error_mark_node;
+ }
+ else if (! CH_READ_COMPATIBLE (type, TREE_TYPE (actual)))
+ {
+ error ("mode mismatch in parameter %d", parmno);
+ actual = error_mark_node;
+ }
+ else
+ actual = convert (type, actual);
+ }
+ else
+ {
+ actual = chill_convert_for_assignment (TREE_TYPE (type),
+ actual, place);
+ sprintf (place, "parameter_%d", parmno);
+ actual = decl_temp1 (get_identifier (place),
+ TREE_TYPE (type), 0, actual, 0, 0);
+ actual = convert (type, actual);
+ }
+ mark_addressable (actual);
+ }
+ else
+ actual = chill_convert_for_assignment (type, actual, place);
+
+ actual_args = tree_cons (NULL_TREE, actual, actual_args);
+ }
+
+ if (valtail != 0 && TREE_VALUE (valtail) != void_type_node)
+ {
+ char *errstr = "too many arguments to procedure";
+ if (name)
+ error ("%s `%s'", errstr, IDENTIFIER_POINTER (name));
+ else
+ error (errstr);
+ return error_mark_node;
+ }
+ else if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
+ {
+ char *errstr = "too few arguments to procedure";
+ if (name)
+ error ("%s `%s'", errstr, IDENTIFIER_POINTER (name));
+ else
+ error (errstr);
+ return error_mark_node;
+ }
+
+ if (callee_raise_exception)
+ {
+ /* add linenumber and filename of the caller as arguments */
+ actual_args = tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()),
+ actual_args);
+ actual_args = tree_cons (NULL_TREE, get_chill_linenumber (), actual_args);
+ }
+
+ function_call = build (CALL_EXPR, TREE_TYPE (fntype),
+ function, nreverse (actual_args), NULL_TREE);
+ TREE_SIDE_EFFECTS (function_call) = 1;
+
+ if (copy_back == NULL_TREE && expr_list == NULL_TREE)
+ return function_call; /* no copying to do, either way */
+ else
+ {
+ tree result_type = TREE_TYPE (fntype);
+ tree result_tmp = NULL_TREE;
+
+ /* no result wanted from procedure call */
+ if (result_type == NULL_TREE || result_type == void_type_node)
+ expr_list = tree_cons (NULL_TREE, function_call, expr_list);
+ else
+ {
+ /* create a temp for the function's result. this is so that we can
+ evaluate this temp as the last expression in the list, which will
+ make the function's return value the value of the whole list of
+ expressions (by the C rules for compound expressions) */
+ result_tmp = decl_temp1 (get_unique_identifier ("FUNC_RESULT"),
+ result_type, 0, NULL_TREE, 0, 0);
+ expr_list = tree_cons (NULL_TREE,
+ build_chill_modify_expr (result_tmp, function_call),
+ expr_list);
+ }
+
+ expr_list = chainon (copy_back, expr_list);
+
+ /* last, but not least, the function's result */
+ if (result_tmp != NULL_TREE)
+ expr_list = tree_cons (NULL_TREE, result_tmp, expr_list);
+ temp = build_chill_compound_expr (nreverse (expr_list));
+ return temp;
+ }
+}
+
+/* We saw something that looks like a function call,
+ but if it's pass 1, we're not sure. */
+
+tree
+build_generalized_call (func, args)
+ tree func, args;
+{
+ tree type = TREE_TYPE (func);
+
+ if (pass == 1)
+ return build (CALL_EXPR, NULL_TREE, func, args, NULL_TREE);
+
+ /* Handle string repetition */
+ if (TREE_CODE (func) == INTEGER_CST)
+ {
+ if (args == NULL_TREE || TREE_CHAIN (args) != NULL_TREE)
+ {
+ error ("syntax error (integer used as function)");
+ return error_mark_node;
+ }
+ if (TREE_CODE (args) == TREE_LIST)
+ args = TREE_VALUE (args);
+ return build_chill_repetition_op (func, args);
+ }
+
+ if (args != NULL_TREE)
+ {
+ if (TREE_CODE (args) == RANGE_EXPR)
+ {
+ tree lo = TREE_OPERAND (args, 0), hi = TREE_OPERAND (args, 1);
+ if (TREE_CODE_CLASS (TREE_CODE (func)) == 't')
+ return build_chill_range_type (func, lo, hi);
+ else
+ return build_chill_slice_with_range (func, lo, hi);
+ }
+ else if (TREE_CODE (args) != TREE_LIST)
+ {
+ error ("syntax error - missing operator, comma, or '('?");
+ return error_mark_node;
+ }
+ }
+
+ if (TREE_CODE (func) == TYPE_DECL)
+ {
+ if (CH_DECL_SIGNAL (func))
+ return build_signal_descriptor (func, args);
+ func = TREE_TYPE (func);
+ }
+
+ if (TREE_CODE_CLASS (TREE_CODE (func)) == 't'
+ && args != NULL_TREE && TREE_CHAIN (args) == NULL_TREE)
+ return build_chill_cast (func, TREE_VALUE (args));
+
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ || (TREE_CODE (type) == POINTER_TYPE
+ && TREE_TYPE (type) != NULL_TREE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE))
+ {
+ /* Check for a built-in Chill function. */
+ if (TREE_CODE (func) == FUNCTION_DECL
+ && DECL_BUILT_IN (func)
+ && DECL_FUNCTION_CODE (func) > END_BUILTINS)
+ {
+ tree fnname = DECL_NAME (func);
+ switch ((enum chill_built_in_function)DECL_FUNCTION_CODE (func))
+ {
+ case BUILT_IN_CH_ABS:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_abs (TREE_VALUE (args));
+ case BUILT_IN_ABSTIME:
+ if (check_arglist_length (args, 0, 6, fnname) < 0)
+ return error_mark_node;
+ return build_chill_abstime (args);
+ case BUILT_IN_ADDR:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+#if 0
+ return build_chill_addr_expr (TREE_VALUE (args), (char *)0);
+#else
+ return build_chill_arrow_expr (TREE_VALUE (args), 0);
+#endif
+ case BUILT_IN_ALLOCATE_GLOBAL_MEMORY:
+ if (check_arglist_length (args, 2, 2, fnname) < 0)
+ return error_mark_node;
+ return build_allocate_global_memory_call
+ (TREE_VALUE (args),
+ TREE_VALUE (TREE_CHAIN (args)));
+ case BUILT_IN_ALLOCATE:
+ if (check_arglist_length (args, 1, 2, fnname) < 0)
+ return error_mark_node;
+ return build_chill_allocate (TREE_VALUE (args),
+ TREE_CHAIN (args) == NULL_TREE ? NULL_TREE : TREE_VALUE (TREE_CHAIN (args)));
+ case BUILT_IN_ALLOCATE_MEMORY:
+ if (check_arglist_length (args, 2, 2, fnname) < 0)
+ return error_mark_node;
+ return build_allocate_memory_call
+ (TREE_VALUE (args),
+ TREE_VALUE (TREE_CHAIN (args)));
+ case BUILT_IN_ASSOCIATE:
+ if (check_arglist_length (args, 2, 3, fnname) < 0)
+ return error_mark_node;
+ return build_chill_associate
+ (TREE_VALUE (args),
+ TREE_VALUE (TREE_CHAIN (args)),
+ TREE_CHAIN (TREE_CHAIN (args)));
+ case BUILT_IN_ARCCOS:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__acos");
+ case BUILT_IN_ARCSIN:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__asin");
+ case BUILT_IN_ARCTAN:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__atan");
+ case BUILT_IN_CARD:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_card (TREE_VALUE (args));
+ case BUILT_IN_CONNECT:
+ if (check_arglist_length (args, 3, 5, fnname) < 0)
+ return error_mark_node;
+ return build_chill_connect
+ (TREE_VALUE (args),
+ TREE_VALUE (TREE_CHAIN (args)),
+ TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))),
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (args))));
+ case BUILT_IN_COPY_NUMBER:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_copy_number (TREE_VALUE (args));
+ case BUILT_IN_CH_COS:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__cos");
+ case BUILT_IN_CREATE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_create (TREE_VALUE (args));
+ case BUILT_IN_DAYS:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_duration (TREE_VALUE (args), DAYS_MULTIPLIER,
+ fnname, DAYS_MAX);
+ case BUILT_IN_CH_DELETE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_delete (TREE_VALUE (args));
+ case BUILT_IN_DESCR:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_descr (TREE_VALUE (args));
+ case BUILT_IN_DISCONNECT:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_disconnect (TREE_VALUE (args));
+ case BUILT_IN_DISSOCIATE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_dissociate (TREE_VALUE (args));
+ case BUILT_IN_EOLN:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_eoln (TREE_VALUE (args));
+ case BUILT_IN_EXISTING:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_existing (TREE_VALUE (args));
+ case BUILT_IN_EXP:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__exp");
+ case BUILT_IN_GEN_CODE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_gen_code (TREE_VALUE (args));
+ case BUILT_IN_GEN_INST:
+ if (check_arglist_length (args, 2, 2, fnname) < 0)
+ return error_mark_node;
+ return build_gen_inst (TREE_VALUE (args),
+ TREE_VALUE (TREE_CHAIN (args)));
+ case BUILT_IN_GEN_PTYPE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_gen_ptype (TREE_VALUE (args));
+ case BUILT_IN_GETASSOCIATION:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_getassociation (TREE_VALUE (args));
+ case BUILT_IN_GETSTACK:
+ if (check_arglist_length (args, 1, 2, fnname) < 0)
+ return error_mark_node;
+ return build_chill_getstack (TREE_VALUE (args),
+ TREE_CHAIN (args) == NULL_TREE ? NULL_TREE : TREE_VALUE (TREE_CHAIN (args)));
+ case BUILT_IN_GETTEXTACCESS:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_gettextaccess (TREE_VALUE (args));
+ case BUILT_IN_GETTEXTINDEX:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_gettextindex (TREE_VALUE (args));
+ case BUILT_IN_GETTEXTRECORD:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_gettextrecord (TREE_VALUE (args));
+ case BUILT_IN_GETUSAGE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_getusage (TREE_VALUE (args));
+ case BUILT_IN_HOURS:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_duration (TREE_VALUE (args), HOURS_MULTIPLIER,
+ fnname, HOURS_MAX);
+ case BUILT_IN_INDEXABLE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_indexable (TREE_VALUE (args));
+ case BUILT_IN_INTTIME:
+ if (check_arglist_length (args, 2, 7, fnname) < 0)
+ return error_mark_node;
+ return build_chill_inttime (TREE_VALUE (args),
+ TREE_CHAIN (args));
+ case BUILT_IN_ISASSOCIATED:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_isassociated (TREE_VALUE (args));
+ case BUILT_IN_LENGTH:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_length (TREE_VALUE (args));
+ case BUILT_IN_LN:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__log");
+ case BUILT_IN_LOG:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__log10");
+ case BUILT_IN_LOWER:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_lower (TREE_VALUE (args));
+ case BUILT_IN_MAX:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_max (TREE_VALUE (args));
+ case BUILT_IN_MILLISECS:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_duration (TREE_VALUE (args), MILLISECS_MULTIPLIER,
+ fnname, MILLISECS_MAX);
+ case BUILT_IN_MIN:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_min (TREE_VALUE (args));
+ case BUILT_IN_MINUTES:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_duration (TREE_VALUE (args), MINUTES_MULTIPLIER,
+ fnname, MINUTES_MAX);
+ case BUILT_IN_MODIFY:
+ if (check_arglist_length (args, 1, -1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_modify (TREE_VALUE (args), TREE_CHAIN (args));
+ case BUILT_IN_NUM:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_num (TREE_VALUE (args));
+ case BUILT_IN_OUTOFFILE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_outoffile (TREE_VALUE (args));
+ case BUILT_IN_PRED:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_pred_or_succ (TREE_VALUE (args), MINUS_EXPR);
+ case BUILT_IN_PROC_TYPE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_proc_type (TREE_VALUE (args));
+ case BUILT_IN_QUEUE_LENGTH:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_queue_length (TREE_VALUE (args));
+ case BUILT_IN_READABLE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_readable (TREE_VALUE (args));
+ case BUILT_IN_READRECORD:
+ if (check_arglist_length (args, 1, 3, fnname) < 0)
+ return error_mark_node;
+ return build_chill_readrecord (TREE_VALUE (args), TREE_CHAIN (args));
+ case BUILT_IN_READTEXT:
+ if (check_arglist_length (args, 2, -1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_readtext (TREE_VALUE (args),
+ TREE_CHAIN (args));
+ case BUILT_IN_RETURN_MEMORY:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_return_memory (TREE_VALUE (args));
+ case BUILT_IN_SECS:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_duration (TREE_VALUE (args), SECS_MULTIPLIER,
+ fnname, SECS_MAX);
+ case BUILT_IN_SEQUENCIBLE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_sequencible (TREE_VALUE (args));
+ case BUILT_IN_SETTEXTACCESS:
+ if (check_arglist_length (args, 2, 2, fnname) < 0)
+ return error_mark_node;
+ return build_chill_settextaccess (TREE_VALUE (args),
+ TREE_VALUE (TREE_CHAIN (args)));
+ case BUILT_IN_SETTEXTINDEX:
+ if (check_arglist_length (args, 2, 2, fnname) < 0)
+ return error_mark_node;
+ return build_chill_settextindex (TREE_VALUE (args),
+ TREE_VALUE (TREE_CHAIN (args)));
+ case BUILT_IN_SETTEXTRECORD:
+ if (check_arglist_length (args, 2, 2, fnname) < 0)
+ return error_mark_node;
+ return build_chill_settextrecord (TREE_VALUE (args),
+ TREE_VALUE (TREE_CHAIN (args)));
+ case BUILT_IN_CH_SIN:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__sin");
+ case BUILT_IN_SIZE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_sizeof (TREE_VALUE (args));
+ case BUILT_IN_SQRT:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__sqrt");
+ case BUILT_IN_SUCC:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_pred_or_succ (TREE_VALUE (args), PLUS_EXPR);
+ case BUILT_IN_TAN:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_floatcall (TREE_VALUE (args),
+ IDENTIFIER_POINTER (fnname),
+ "__tan");
+ case BUILT_IN_TERMINATE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_terminate (TREE_VALUE (args));
+ case BUILT_IN_UPPER:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_upper (TREE_VALUE (args));
+ case BUILT_IN_VARIABLE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_variable (TREE_VALUE (args));
+ case BUILT_IN_WRITEABLE:
+ if (check_arglist_length (args, 1, 1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_writeable (TREE_VALUE (args));
+ case BUILT_IN_WRITERECORD:
+ if (check_arglist_length (args, 2, 3, fnname) < 0)
+ return error_mark_node;
+ return build_chill_writerecord (TREE_VALUE (args), TREE_CHAIN (args));
+ case BUILT_IN_WRITETEXT:
+ if (check_arglist_length (args, 2, -1, fnname) < 0)
+ return error_mark_node;
+ return build_chill_writetext (TREE_VALUE (args),
+ TREE_CHAIN (args));
+
+ case BUILT_IN_EXPIRED:
+ case BUILT_IN_WAIT:
+ sorry ("unimplemented builtin function `%s'",
+ IDENTIFIER_POINTER (fnname));
+ break;
+ default:
+ error ("internal error - bad builtin function `%s'",
+ IDENTIFIER_POINTER (fnname));
+ }
+ }
+ return build_chill_function_call (func, args);
+ }
+
+ if (chill_varying_type_p (TREE_TYPE (func)))
+ type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (type)));
+
+ if (CH_STRING_TYPE_P (type))
+ {
+ if (args == NULL_TREE)
+ {
+ error ("empty expression in string index");
+ return error_mark_node;
+ }
+ if (TREE_CHAIN (args) != NULL)
+ {
+ error ("only one expression allowed in string index");
+ return error_mark_node;
+ }
+ if (flag_old_strings)
+ return build_chill_slice_with_length (func,
+ TREE_VALUE (args),
+ integer_one_node);
+ else if (CH_BOOLS_TYPE_P (type))
+ return build_chill_bitref (func, args);
+ else
+ return build_chill_array_ref (func, args);
+ }
+
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ return build_chill_array_ref (func, args);
+
+ if (TREE_CODE (func) != ERROR_MARK)
+ error ("invalid: primval ( untyped_exprlist )");
+ return error_mark_node;
+}
+
+/* Given a set stored as one bit per char (in BUFFER[0 .. BIT_SIZE-1]),
+ return a CONTRUCTOR, of type TYPE (a SET_TYPE). */
+tree
+expand_packed_set (buffer, bit_size, type)
+ char *buffer;
+ int bit_size;
+ tree type;
+{
+ /* The ordinal number corresponding to the first stored bit. */
+ HOST_WIDE_INT first_bit_no =
+ TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (type)));
+ tree list = NULL_TREE;
+ int i;
+
+ for (i = 0; i < bit_size; i++)
+ if (buffer[i])
+ {
+ int next_0;
+ for (next_0 = i + 1;
+ next_0 < bit_size && buffer[next_0]; next_0++)
+ ;
+ if (next_0 == i + 1)
+ list = tree_cons (NULL_TREE,
+ build_int_2 (i + first_bit_no, 0), list);
+ else
+ {
+ list = tree_cons (build_int_2 (i + first_bit_no, 0),
+ build_int_2 (next_0 - 1 + first_bit_no, 0), list);
+ /* advance i past the range of 1-bits */
+ i = next_0;
+ }
+ }
+ list = build (CONSTRUCTOR, type, NULL_TREE, nreverse (list));
+ TREE_CONSTANT (list) = 1;
+ return list;
+}
+
+/*
+ * fold a set represented as a CONSTRUCTOR list.
+ * An empty set has a NULL_TREE in its TREE_OPERAND (set, 1) slot.
+ */
+static tree
+fold_set_expr (code, op0, op1)
+ enum chill_tree_code code;
+ tree op0, op1;
+{
+ tree temp;
+ char *buffer0, *buffer1, *bufferr;
+ int i, size0, size1, first_unused_bit;
+
+ if (! TREE_CONSTANT (op0) || TREE_CODE (op0) != CONSTRUCTOR)
+ return NULL_TREE;
+
+ if (op1
+ && (! TREE_CONSTANT (op1) || TREE_CODE (op1) != CONSTRUCTOR))
+ return NULL_TREE;
+
+ size0 = int_size_in_bytes (TREE_TYPE (op0)) * BITS_PER_UNIT;
+ if (size0 < 0)
+ {
+ error ("operand is variable-size bitstring/power-set");
+ return error_mark_node;
+ }
+ buffer0 = (char*) alloca (size0);
+
+ temp = get_set_constructor_bits (op0, buffer0, size0);
+ if (temp)
+ return NULL_TREE;
+
+ if (op0 && op1)
+ {
+ size1 = int_size_in_bytes (TREE_TYPE (op1)) * BITS_PER_UNIT;
+ if (size1 < 0)
+ {
+ error ("operand is variable-size bitstring/power-set");
+ return error_mark_node;
+ }
+ if (size0 != size1)
+ return NULL_TREE;
+ buffer1 = (char*) alloca (size1);
+ temp = get_set_constructor_bits (op1, buffer1, size1);
+ if (temp)
+ return NULL_TREE;
+ }
+
+ bufferr = (char*) alloca (size0); /* result buffer */
+
+ switch ((int)code)
+ {
+ case SET_NOT_EXPR:
+ case BIT_NOT_EXPR:
+ for (i = 0; i < size0; i++)
+ bufferr[i] = 1 & ~buffer0[i];
+ goto build_result;
+ case SET_AND_EXPR:
+ case BIT_AND_EXPR:
+ for (i = 0; i < size0; i++)
+ bufferr[i] = buffer0[i] & buffer1[i];
+ goto build_result;
+ case SET_IOR_EXPR:
+ case BIT_IOR_EXPR:
+ for (i = 0; i < size0; i++)
+ bufferr[i] = buffer0[i] | buffer1[i];
+ goto build_result;
+ case SET_XOR_EXPR:
+ case BIT_XOR_EXPR:
+ for (i = 0; i < size0; i++)
+ bufferr[i] = (buffer0[i] ^ buffer1[i]) & 1;
+ goto build_result;
+ case SET_DIFF_EXPR:
+ case MINUS_EXPR:
+ for (i = 0; i < size0; i++)
+ bufferr[i] = buffer0[i] & ~buffer1[i];
+ goto build_result;
+ build_result:
+ /* mask out unused bits. Same as runtime library does. */
+ first_unused_bit = TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (op0))))
+ - TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (op0)))) + 1;
+ for (i = first_unused_bit; i < size0 ; i++)
+ bufferr[i] = 0;
+ return expand_packed_set (bufferr, size0, TREE_TYPE (op0));
+ case EQ_EXPR:
+ for (i = 0; i < size0; i++)
+ if (buffer0[i] != buffer1[i])
+ return boolean_false_node;
+ return boolean_true_node;
+
+ case NE_EXPR:
+ for (i = 0; i < size0; i++)
+ if (buffer0[i] != buffer1[i])
+ return boolean_true_node;
+ return boolean_false_node;
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+/*
+ * build a set or bit-array expression. Type-checking is
+ * done elsewhere.
+ */
+static tree
+build_compare_set_expr (code, op0, op1)
+ enum chill_tree_code code;
+ tree op0, op1;
+{
+ tree result_type = NULL_TREE;
+ char *fnname;
+ tree x;
+
+ /* These conversions are needed if -fold-strings. */
+ if (TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE)
+ {
+ if (CH_BOOLS_ONE_P (TREE_TYPE (op1)))
+ return build_compare_discrete_expr (code,
+ op0,
+ convert (boolean_type_node, op1));
+ else
+ op0 = convert (bitstring_one_type_node, op0);
+ }
+ if (TREE_CODE (TREE_TYPE (op1)) == BOOLEAN_TYPE)
+ {
+ if (CH_BOOLS_ONE_P (TREE_TYPE (op0)))
+ return build_compare_discrete_expr (code,
+ convert (boolean_type_node, op0),
+ op1);
+ else
+ op1 = convert (bitstring_one_type_node, op1);
+ }
+
+ switch ((int)code)
+ {
+ case EQ_EXPR:
+ {
+ tree temp = fold_set_expr (EQ_EXPR, op0, op1);
+ if (temp)
+ return temp;
+ fnname = "__eqpowerset";
+ goto compare_powerset;
+ }
+ break;
+
+ case GE_EXPR:
+ /* switch operands and fall thru */
+ x = op0;
+ op0 = op1;
+ op1 = x;
+
+ case LE_EXPR:
+ fnname = "__lepowerset";
+ goto compare_powerset;
+
+ case GT_EXPR:
+ /* switch operands and fall thru */
+ x = op0;
+ op0 = op1;
+ op1 = x;
+
+ case LT_EXPR:
+ fnname = "__ltpowerset";
+ goto compare_powerset;
+
+ case NE_EXPR:
+ return invert_truthvalue (build_compare_set_expr (EQ_EXPR, op0, op1));
+
+ compare_powerset:
+ {
+ tree tsize = powersetlen (op0);
+
+ if (TREE_CODE (TREE_TYPE (op0)) != SET_TYPE)
+ tsize = fold (build (MULT_EXPR, sizetype, tsize,
+ size_int (BITS_PER_UNIT)));
+
+ return build_chill_function_call (lookup_name (get_identifier (fnname)),
+ tree_cons (NULL_TREE, force_addr_of (op0),
+ tree_cons (NULL_TREE, force_addr_of (op1),
+ tree_cons (NULL_TREE, tsize, NULL_TREE))));
+ }
+ break;
+
+ default:
+ if ((int) code >= (int)LAST_AND_UNUSED_TREE_CODE)
+ {
+ error ("tree code `%s' unhandled in build_compare_set_expr",
+ tree_code_name[(int)code]);
+ return error_mark_node;
+ }
+ break;
+ }
+
+ return build ((enum tree_code)code, result_type,
+ op0, op1);
+}
+
+/* Convert a varying string (or array) to dynamic non-varying string:
+ EXP becomes EXP.var_data(0 UP EXP.var_length). */
+
+tree
+varying_to_slice (exp)
+ tree exp;
+{
+ if (!chill_varying_type_p (TREE_TYPE (exp)))
+ return exp;
+ else
+ { tree size, data, data_domain, doamin, min;
+ tree novelty = CH_NOVELTY (TREE_TYPE (exp));
+ exp = save_if_needed (exp);
+ size = build_component_ref (exp, var_length_id);
+ data = build_component_ref (exp, var_data_id);
+ TREE_TYPE (data) = copy_novelty (novelty, TREE_TYPE (data));
+ data_domain = TYPE_DOMAIN (TREE_TYPE (data));
+ if (data_domain != NULL_TREE
+ && TYPE_MIN_VALUE (data_domain) != NULL_TREE)
+ min = TYPE_MIN_VALUE (data_domain);
+ else
+ min = integer_zero_node;
+ return build_chill_slice (data, min, size);
+ }
+}
+
+/* Convert a scalar argument to a string or array type. This is a subroutine
+ of `build_concat_expr'. */
+
+static tree
+scalar_to_string (exp)
+ tree exp;
+{
+ tree type = TREE_TYPE (exp);
+
+ if (SCALAR_P (type))
+ {
+ int was_const = TREE_CONSTANT (exp);
+ if (TREE_TYPE (exp) == char_type_node)
+ exp = convert (string_one_type_node, exp);
+ else if (TREE_TYPE (exp) == boolean_type_node)
+ exp = convert (bitstring_one_type_node, exp);
+ else
+ exp = convert (build_array_type_for_scalar (type), exp);
+ TREE_CONSTANT (exp) = was_const;
+ return exp;
+ }
+ return varying_to_slice (exp);
+}
+
+/* FIXME: Generalize this to general arrays (not just strings),
+ at least for the compiler-generated case of padding fixed-length arrays. */
+
+static tree
+build_concat_expr (op0, op1)
+ tree op0, op1;
+{
+ tree orig_op0 = op0, orig_op1 = op1;
+ tree type0, type1, size0, size1, res;
+
+ op0 = scalar_to_string (op0);
+ type0 = TREE_TYPE (op0);
+ op1 = scalar_to_string (op1);
+ type1 = TREE_TYPE (op1);
+ size1 = size_in_bytes (type1);
+
+ /* try to fold constant string literals */
+ if (TREE_CODE (op0) == STRING_CST
+ && (TREE_CODE (op1) == STRING_CST
+ || TREE_CODE (op1) == UNDEFINED_EXPR)
+ && TREE_CODE (size1) == INTEGER_CST)
+ {
+ int len0 = TREE_STRING_LENGTH (op0);
+ int len1 = TREE_INT_CST_LOW (size1);
+ char *result = xmalloc (len0 + len1 + 1);
+ memcpy (result, TREE_STRING_POINTER (op0), len0);
+ if (TREE_CODE (op1) == UNDEFINED_EXPR)
+ memset (&result[len0], '\0', len1);
+ else
+ memcpy (&result[len0], TREE_STRING_POINTER (op1), len1);
+ return build_chill_string (len0 + len1, result);
+ }
+ else if (TREE_CODE (type0) == TREE_CODE (type1))
+ {
+ tree result_size;
+ struct ch_class result_class;
+ struct ch_class class0;
+ struct ch_class class1;
+
+ class0 = chill_expr_class (orig_op0);
+ class1 = chill_expr_class (orig_op1);
+
+ if (TREE_CODE (type0) == SET_TYPE)
+ {
+ result_size = size_binop (PLUS_EXPR,
+ discrete_count (TYPE_DOMAIN (type0)),
+ discrete_count (TYPE_DOMAIN (type1)));
+ result_class.mode = build_bitstring_type (result_size);
+ }
+ else
+ {
+ tree max0 = TYPE_MAX_VALUE (type0);
+ tree max1 = TYPE_MAX_VALUE (type1);
+
+ /* new array's dynamic size (in bytes). */
+ size0 = size_in_bytes (type0);
+ /* size1 was computed above. */
+
+ result_size = size_binop (PLUS_EXPR, size0, size1);
+ /* new array's type. */
+ result_class.mode = build_string_type (char_type_node, result_size);
+
+ if (max0 || max1)
+ {
+ max0 = max0 == 0 ? size0 : convert (sizetype, max0);
+ max1 = max1 == 0 ? size1 : convert (sizetype, max1);
+ TYPE_MAX_VALUE (result_class.mode)
+ = size_binop (PLUS_EXPR, max0, max1);
+ }
+ }
+
+ if (class0.kind == CH_VALUE_CLASS || class1.kind == CH_VALUE_CLASS)
+ {
+ tree novelty0 = CH_NOVELTY (TREE_TYPE (orig_op0));
+ result_class.kind = CH_VALUE_CLASS;
+ if (class0.kind == CH_VALUE_CLASS && novelty0 != NULL_TREE)
+ SET_CH_NOVELTY_NONNIL (result_class.mode, novelty0);
+ else if (class1.kind == CH_VALUE_CLASS)
+ SET_CH_NOVELTY (result_class.mode,
+ CH_NOVELTY (TREE_TYPE (orig_op1)));
+ }
+ else
+ result_class.kind = CH_DERIVED_CLASS;
+
+ if (TREE_CODE (result_class.mode) == SET_TYPE
+ && TREE_CONSTANT (op0) && TREE_CONSTANT (op1)
+ && TREE_CODE (op0) == CONSTRUCTOR && TREE_CODE (op1) == CONSTRUCTOR)
+ {
+ HOST_WIDE_INT size0, size1; char *buffer;
+ size0 = TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type0))) + 1;
+ size1 = TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type1))) + 1;
+ buffer = (char*) alloca (size0 + size1);
+ if (size0 < 0 || size1 < 0
+ || get_set_constructor_bits (op0, buffer, size0)
+ || get_set_constructor_bits (op1, buffer + size0, size1))
+ abort ();
+ res = expand_packed_set (buffer, size0 + size1, result_class.mode);
+ }
+ else
+ res = build (CONCAT_EXPR, result_class.mode, op0, op1);
+ return convert_to_class (result_class, res);
+ }
+ else
+ {
+ error ("incompatible modes in concat expression");
+ return error_mark_node;
+ }
+}
+
+/*
+ * handle varying and fixed array compare operations
+ */
+static tree
+build_compare_string_expr (code, op0, op1)
+ enum chill_tree_code code;
+ tree op0, op1;
+{
+ if (op0 == NULL_TREE || TREE_CODE (op0) == ERROR_MARK)
+ return error_mark_node;
+ if (op1 == NULL_TREE || TREE_CODE (op1) == ERROR_MARK)
+ return error_mark_node;
+
+ if (tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (op0)),
+ TYPE_SIZE (TREE_TYPE (op1)))
+ && ! chill_varying_type_p (TREE_TYPE (op0))
+ && ! chill_varying_type_p (TREE_TYPE (op1)))
+ {
+ tree size = size_in_bytes (TREE_TYPE (op0));
+ tree temp = lookup_name (get_identifier ("memcmp"));
+ temp = build_chill_function_call (temp,
+ tree_cons (NULL_TREE, force_addr_of (op0),
+ tree_cons (NULL_TREE, force_addr_of (op1),
+ tree_cons (NULL_TREE, size, NULL_TREE))));
+ return build_compare_discrete_expr (code, temp, integer_zero_node);
+ }
+
+ switch ((int)code)
+ {
+ case EQ_EXPR:
+ code = STRING_EQ_EXPR;
+ break;
+ case GE_EXPR:
+ return invert_truthvalue (build_compare_string_expr (LT_EXPR, op0, op1));
+ case LE_EXPR:
+ return invert_truthvalue (build_compare_string_expr (LT_EXPR, op1, op0));
+ case GT_EXPR:
+ return build_compare_string_expr (LT_EXPR, op1, op0);
+ case LT_EXPR:
+ code = STRING_LT_EXPR;
+ break;
+ case NE_EXPR:
+ return invert_truthvalue (build_compare_string_expr (EQ_EXPR, op0, op1));
+ default:
+ error ("Invalid operation on array of chars");
+ return error_mark_node;
+ }
+
+ return build (code, boolean_type_node, op0, op1);
+}
+
+tree
+compare_records (exp0, exp1)
+ tree exp0, exp1;
+{
+ tree type = TREE_TYPE (exp0);
+ tree field;
+ int have_variants = 0;
+
+ tree result = boolean_true_node;
+ extern int maximum_field_alignment;
+
+ if (TREE_CODE (type) != RECORD_TYPE)
+ abort ();
+
+ exp0 = save_if_needed (exp0);
+ exp1 = save_if_needed (exp1);
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (DECL_NAME (field) == NULL_TREE)
+ {
+ have_variants = 1;
+ break;
+ }
+ }
+
+ /* in case of -fpack we always do a memcmp */
+ if (maximum_field_alignment != 0)
+ {
+ tree memcmp_func = lookup_name (get_identifier ("memcmp"));
+ tree arg1 = force_addr_of (exp0);
+ tree arg2 = force_addr_of (exp1);
+ tree arg3 = size_in_bytes (type);
+ tree fcall = build_chill_function_call (memcmp_func,
+ tree_cons (NULL_TREE, arg1,
+ tree_cons (NULL_TREE, arg2,
+ tree_cons (NULL_TREE, arg3, NULL_TREE))));
+
+ if (have_variants)
+ warning ("comparison of variant structures is unsafe");
+ result = build_chill_binary_op (EQ_EXPR, fcall, integer_zero_node);
+ return result;
+ }
+
+ if (have_variants)
+ {
+ sorry ("compare with variant records");
+ return error_mark_node;
+ }
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ tree exp0fld = build_component_ref (exp0, DECL_NAME (field));
+ tree exp1fld = build_component_ref (exp1, DECL_NAME (field));
+ tree eq_flds = build_chill_binary_op (EQ_EXPR, exp0fld, exp1fld);
+ result = build_chill_binary_op (TRUTH_AND_EXPR, result, eq_flds);
+ }
+ return result;
+}
+
+int
+compare_int_csts (op, val1, val2)
+ enum tree_code op;
+ tree val1, val2;
+{
+ int result;
+ tree tmp;
+ tree type1 = TREE_TYPE (val1);
+ tree type2 = TREE_TYPE (val2);
+ switch (op)
+ {
+ case GT_EXPR:
+ case GE_EXPR:
+ tmp = val1; val1 = val2; val2 = tmp;
+ tmp = type1; type1 = type2; type2 = tmp;
+ op = (op == GT_EXPR) ? LT_EXPR : LE_EXPR;
+ /* ... fall through ... */
+ case LT_EXPR:
+ case LE_EXPR:
+ if (!TREE_UNSIGNED (type1))
+ {
+ if (!TREE_UNSIGNED (type2))
+ result = INT_CST_LT (val1, val2);
+ else if (TREE_INT_CST_HIGH (val1) < 0)
+ result = 1;
+ else
+ result = INT_CST_LT_UNSIGNED (val1, val2);
+ }
+ else
+ {
+ if (!TREE_UNSIGNED (type2) && TREE_INT_CST_HIGH (val2) < 0)
+ result = 0;
+ else
+ result = INT_CST_LT_UNSIGNED (val1, val2);
+ }
+ if (op == LT_EXPR || result == 1)
+ break;
+ /* else fall through ... */
+ case NE_EXPR:
+ case EQ_EXPR:
+ if (TREE_INT_CST_LOW (val1) == TREE_INT_CST_LOW (val2)
+ && TREE_INT_CST_HIGH (val1) == TREE_INT_CST_HIGH (val2)
+ /* They're bitwise equal.
+ Check for one being negative and the other unsigned. */
+ && (TREE_INT_CST_HIGH (val2) >= 0
+ || TREE_UNSIGNED (TREE_TYPE (val1))
+ == TREE_UNSIGNED (TREE_TYPE (val2))))
+ result = 1;
+ else
+ result = 0;
+ if (op == NE_EXPR)
+ result = !result;
+ break;
+ }
+ return result;
+}
+
+/* Build an expression to compare discrete values VAL1 and VAL2.
+ This does not check that they are discrete, nor that they are
+ compatible; if you need such checks use build_compare_expr. */
+
+tree
+build_compare_discrete_expr (op, val1, val2)
+ enum chill_tree_code op;
+ tree val1, val2;
+{
+ tree type1 = TREE_TYPE (val1);
+ tree type2 = TREE_TYPE (val2);
+ tree tmp;
+
+ if (TREE_CODE (val1) == INTEGER_CST && TREE_CODE (val2) == INTEGER_CST)
+ {
+ if (compare_int_csts (op, val1, val2))
+ return boolean_true_node;
+ else
+ return boolean_false_node;
+ }
+
+ if (TREE_UNSIGNED (type1) != TREE_UNSIGNED (type2))
+ {
+ switch (op)
+ {
+ case GT_EXPR:
+ case GE_EXPR:
+ tmp = val1; val1 = val2; val2 = tmp;
+ tmp = type1; type1 = type2; type2 = tmp;
+ op = (op == GT_EXPR) ? LT_EXPR : LE_EXPR;
+ /* ... fall through ... */
+ case LT_EXPR:
+ case LE_EXPR:
+ if (TREE_UNSIGNED (type2))
+ {
+ tmp = build_int_2_wide (0, 0);
+ TREE_TYPE (tmp) = type1;
+ val1 = save_expr (val1);
+ tmp = fold (build (LT_EXPR, boolean_type_node, val1, tmp));
+ if (TYPE_PRECISION (type2) < TYPE_PRECISION (type1))
+ {
+ type2 = unsigned_type (type1);
+ val2 = convert_to_integer (type2, val2);
+ }
+ val1 = convert_to_integer (type2, val1);
+ return fold (build (TRUTH_OR_EXPR, boolean_type_node,
+ tmp,
+ fold (build (op, boolean_type_node,
+ val1, val2))));
+ }
+ unsigned_vs_signed: /* val1 is unsigned, val2 is signed */
+ tmp = build_int_2_wide (0, 0);
+ TREE_TYPE (tmp) = type2;
+ val2 = save_expr (val2);
+ tmp = fold (build (GE_EXPR, boolean_type_node, val2, tmp));
+ if (TYPE_PRECISION (type1) < TYPE_PRECISION (type2))
+ {
+ type1 = unsigned_type (type2);
+ val1 = convert_to_integer (type1, val1);
+ }
+ val2 = convert_to_integer (type1, val2);
+ return fold (build (TRUTH_AND_EXPR, boolean_type_node, tmp,
+ fold (build (op, boolean_type_node,
+ val1, val2))));
+ case EQ_EXPR:
+ if (TREE_UNSIGNED (val2))
+ {
+ tmp = val1; val1 = val2; val2 = tmp;
+ tmp = type1; type1 = type2; type2 = tmp;
+ }
+ goto unsigned_vs_signed;
+ case NE_EXPR:
+ tmp = build_compare_expr (EQ_EXPR, val1, val2);
+ return build_chill_unary_op (TRUTH_NOT_EXPR, tmp);
+ }
+ }
+ if (TYPE_PRECISION (type1) > TYPE_PRECISION (type2))
+ val2 = convert (type1, val2);
+ else if (TYPE_PRECISION (type1) < TYPE_PRECISION (type2))
+ val1 = convert (type2, val1);
+ return fold (build (op, boolean_type_node, val1, val2));
+}
+
+tree
+build_compare_expr (op, val1, val2)
+ enum chill_tree_code op;
+ tree val1, val2;
+{
+ tree tmp;
+ tree type1, type2;
+ val1 = check_have_mode (val1, "relational expression");
+ val2 = check_have_mode (val2, "relational expression");
+ if (val1 == NULL_TREE || TREE_CODE (val1) == ERROR_MARK)
+ return error_mark_node;
+ if (val2 == NULL_TREE || TREE_CODE (val2) == ERROR_MARK)
+ return error_mark_node;
+
+ if (pass == 1)
+ return build (op, NULL_TREE, val1, val2);
+
+ if (!CH_COMPATIBLE_CLASSES (val1, val2))
+ {
+ error ("incompatible operands to %s", boolean_code_name [op]);
+ return error_mark_node;
+ }
+
+ tmp = CH_ROOT_MODE (TREE_TYPE (val1));
+ if (tmp != TREE_TYPE (val1))
+ val1 = convert (tmp, val1);
+ tmp = CH_ROOT_MODE (TREE_TYPE (val2));
+ if (tmp != TREE_TYPE (val2))
+ val2 = convert (tmp, val2);
+
+ type1 = TREE_TYPE (val1);
+ type2 = TREE_TYPE (val2);
+
+ if (TREE_CODE (type1) == SET_TYPE)
+ tmp = build_compare_set_expr (op, val1, val2);
+
+ else if (discrete_type_p (type1))
+ tmp = build_compare_discrete_expr (op, val1, val2);
+
+ else if (chill_varying_type_p (type1) || chill_varying_type_p (type2)
+ || (TREE_CODE (type1) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) == CHAR_TYPE)
+ || (TREE_CODE (type2) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (type2)) == CHAR_TYPE) )
+ tmp = build_compare_string_expr (op, val1, val2);
+
+ else if ((TREE_CODE (type1) == RECORD_TYPE
+ || TREE_CODE (type2) == RECORD_TYPE)
+ && (op == EQ_EXPR || op == NE_EXPR))
+ {
+ /* This is for handling INSTANCEs being compared against NULL. */
+ if (val1 == null_pointer_node)
+ val1 = convert (type2, val1);
+ if (val2 == null_pointer_node)
+ val2 = convert (type1, val2);
+
+ tmp = compare_records (val1, val2);
+ if (op == NE_EXPR)
+ tmp = build_chill_unary_op (TRUTH_NOT_EXPR, tmp);
+ }
+
+ else if (TREE_CODE (type1) == REAL_TYPE || TREE_CODE (type2) == REAL_TYPE
+ || (op == EQ_EXPR || op == NE_EXPR))
+ {
+ tmp = build (op, boolean_type_node, val1, val2);
+ CH_DERIVED_FLAG (tmp) = 1; /* Optimization to avoid copy_node. */
+ tmp = fold (tmp);
+ }
+
+ else
+ {
+ error ("relational operator not allowed for this mode");
+ return error_mark_node;
+ }
+
+ if (!CH_DERIVED_FLAG (tmp))
+ {
+ tmp = copy_node (tmp);
+ CH_DERIVED_FLAG (tmp) = 1;
+ }
+ return tmp;
+}
+
+tree
+finish_chill_binary_op (node)
+ tree node;
+{
+ tree op0 = check_have_mode (TREE_OPERAND (node, 0), "binary expression");
+ tree op1 = check_have_mode (TREE_OPERAND (node, 1), "binary expression");
+ tree type0 = TREE_TYPE (op0);
+ tree type1 = TREE_TYPE (op1);
+ enum tree_code code0;
+ enum tree_code code1;
+ tree folded;
+
+ if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
+ return error_mark_node;
+
+ if (UNSATISFIED (op0) || UNSATISFIED (op1))
+ {
+ UNSATISFIED_FLAG (node) = 1;
+ return node;
+ }
+#if 0
+ /* assure that both operands have a type */
+ if (! type0 && type1)
+ {
+ op0 = convert (type1, op0);
+ type0 = TREE_TYPE (op0);
+ }
+ if (! type1 && type0)
+ {
+ op1 = convert (type0, op1);
+ type1 = TREE_TYPE (op1);
+ }
+#endif
+ UNSATISFIED_FLAG (node) = 0;
+#if 0
+
+ { int op0f = TREE_CODE (op0) == FUNCTION_DECL;
+ int op1f = TREE_CODE (op1) == FUNCTION_DECL;
+ if (op0f)
+ op0 = convert (build_pointer_type (TREE_TYPE (op0)), op0);
+ if (op1f)
+ op1 = convert (build_pointer_type (TREE_TYPE (op1)), op1);
+ if ((op0f || op1f)
+ && code != EQ_EXPR && code != NE_EXPR)
+ error ("Cannot use %s operator on PROC mode variable",
+ tree_code_name[(int)code]);
+ }
+
+ if (invalid_left_operand (type0, code))
+ {
+ error ("invalid left operand of %s", tree_code_name[(int)code]);
+ return error_mark_node;
+ }
+ if (invalid_right_operand (code, type1))
+ {
+ error ("invalid right operand of %s", tree_code_name[(int)code]);
+ return error_mark_node;
+ }
+#endif
+
+ switch (TREE_CODE (node))
+ {
+ case CONCAT_EXPR:
+ return build_concat_expr (op0, op1);
+
+ case REPLICATE_EXPR:
+ op0 = fold (op0);
+ if (!TREE_CONSTANT (op0) || !TREE_CONSTANT (op1))
+ {
+ error ("repetition expression must be constant");
+ return error_mark_node;
+ }
+ else
+ return build_chill_repetition_op (op0, op1);
+
+ case FLOOR_MOD_EXPR:
+ case TRUNC_MOD_EXPR:
+ if (TREE_CODE (type0) != INTEGER_TYPE)
+ {
+ error ("left argument to MOD/REM operator must be integral");
+ return error_mark_node;
+ }
+ if (TREE_CODE (type1) != INTEGER_TYPE)
+ {
+ error ("right argument to MOD/REM operator must be integral");
+ return error_mark_node;
+ }
+ break;
+
+ case MINUS_EXPR:
+ if (TREE_CODE (type1) == SET_TYPE)
+ {
+ tree temp = fold_set_expr (MINUS_EXPR, op0, op1);
+
+ if (temp)
+ return temp;
+ if (TYPE_MODE (type1) == BLKmode)
+ TREE_SET_CODE (node, SET_DIFF_EXPR);
+ else
+ {
+ op1 = build_chill_unary_op (BIT_NOT_EXPR, op1);
+ TREE_OPERAND (node, 1) = op1;
+ TREE_SET_CODE (node, BIT_AND_EXPR);
+ }
+ }
+ break;
+
+ case TRUNC_DIV_EXPR:
+ if (TREE_CODE (type0) == REAL_TYPE || TREE_CODE (type1) == REAL_TYPE)
+ TREE_SET_CODE (node, RDIV_EXPR);
+ break;
+
+ case BIT_AND_EXPR:
+ if (TYPE_MODE (type1) == BLKmode)
+ TREE_SET_CODE (node, SET_AND_EXPR);
+ goto fold_set_binop;
+ case BIT_IOR_EXPR:
+ if (TYPE_MODE (type1) == BLKmode)
+ TREE_SET_CODE (node, SET_IOR_EXPR);
+ goto fold_set_binop;
+ case BIT_XOR_EXPR:
+ if (TYPE_MODE (type1) == BLKmode)
+ TREE_SET_CODE (node, SET_XOR_EXPR);
+ goto fold_set_binop;
+ case SET_AND_EXPR:
+ case SET_IOR_EXPR:
+ case SET_XOR_EXPR:
+ case SET_DIFF_EXPR:
+ fold_set_binop:
+ if (TREE_CODE (type0) == SET_TYPE)
+ {
+ tree temp = fold_set_expr (TREE_CODE (node), op0, op1);
+
+ if (temp)
+ return temp;
+ }
+ break;
+
+ case SET_IN_EXPR:
+ if (TREE_CODE (type1) != SET_TYPE || CH_BOOLS_TYPE_P (type1))
+ {
+ error ("right operand of IN is not a powerset");
+ return error_mark_node;
+ }
+ if (!CH_COMPATIBLE (op0, TYPE_DOMAIN (type1)))
+ {
+ error ("left operand of IN incompatible with right operand");
+ return error_mark_node;
+ }
+ type0 = CH_ROOT_MODE (type0);
+ if (type0 != TREE_TYPE (op0))
+ TREE_OPERAND (node, 0) = op0 = convert (type0, op0);
+ TREE_TYPE (node) = boolean_type_node;
+ CH_DERIVED_FLAG (node) = 1;
+ node = fold (node);
+ if (!CH_DERIVED_FLAG (node))
+ {
+ node = copy_node (node);
+ CH_DERIVED_FLAG (node) = 1;
+ }
+ return node;
+ case NE_EXPR:
+ case EQ_EXPR:
+ case GE_EXPR:
+ case GT_EXPR:
+ case LE_EXPR:
+ case LT_EXPR:
+ return build_compare_expr (TREE_CODE (node), op0, op1);
+ default:
+ ;
+ }
+
+ if (!CH_COMPATIBLE_CLASSES (op0, op1))
+ {
+ error ("incompatible operands to %s", tree_code_name[(int) TREE_CODE (node)]);
+ return error_mark_node;
+ }
+
+
+ finish:
+ if (TREE_TYPE (node) == NULL_TREE)
+ {
+ struct ch_class class;
+ class = CH_ROOT_RESULTING_CLASS (op0, op1);
+ TREE_OPERAND (node, 0) = op0 = convert_to_class (class, op0);
+ type0 = TREE_TYPE (op0);
+ TREE_OPERAND (node, 1) = op1 = convert_to_class (class, op1);
+ type1 = TREE_TYPE (op1);
+ TREE_TYPE (node) = class.mode;
+ folded = convert_to_class (class, fold (node));
+ }
+ else
+ folded = fold (node);
+#if 0
+ if (folded == node)
+ TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
+#endif
+ if (TREE_CODE (node) == TRUNC_DIV_EXPR)
+ if (TREE_CONSTANT (op1))
+ {
+ if (tree_int_cst_equal (op1, integer_zero_node))
+ {
+ error ("division by zero");
+ return integer_zero_node;
+ }
+ }
+ else if (range_checking)
+ {
+#if 0
+ tree test = build (EQ_EXPR, boolean_type_node, op1, integer_zero_node);
+ /* Should this be overflow? */
+ folded = check_expression (folded, test,
+ ridpointers[(int) RID_RANGEFAIL]);
+#endif
+ }
+ return folded;
+}
+
+/*
+ * This implements the '->' operator, which, like the '&' in C,
+ * returns a pointer to an object, which has the type of
+ * pointer-to-that-object.
+ *
+ * FORCE is 0 when we're evaluating a user-level syntactic construct,
+ * and 1 when we're calling from inside the compiler.
+ */
+tree
+build_chill_arrow_expr (ref, force)
+ tree ref;
+ int force;
+{
+ tree addr_type;
+ tree result;
+
+ if (pass == 1)
+ {
+ error ("-> operator not allow in constant expression");
+ return error_mark_node;
+ }
+
+ if (ref == NULL_TREE || TREE_CODE (ref) == ERROR_MARK)
+ return ref;
+
+ while (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
+ ref = convert (TREE_TYPE (TREE_TYPE (ref)), ref);
+
+ if (!force && ! CH_LOCATION_P (ref))
+ {
+ if (TREE_CODE (ref) == STRING_CST)
+ pedwarn ("taking the address of a string literal is non-standard");
+ else if (TREE_CODE (TREE_TYPE (ref)) == FUNCTION_TYPE)
+ pedwarn ("taking the address of a function is non-standard");
+ else
+ {
+ error ("ADDR requires a LOCATION argument");
+ return error_mark_node;
+ }
+ /* FIXME: Should we be sure that ref isn't a
+ function if we're being pedantic? */
+ }
+
+ addr_type = build_pointer_type (TREE_TYPE (ref));
+
+#if 0
+ /* This transformation makes chill_expr_class return CH_VALUE_CLASS
+ when it should return CH_REFERENCE_CLASS. That could be fixed,
+ but we probably don't want this transformation anyway. */
+ if (TREE_CODE (ref) == NOP_EXPR) /* RETYPE_EXPR */
+ {
+ tree addr;
+ while (TREE_CODE (ref) == NOP_EXPR) /* RETYPE_EXPR */
+ ref = TREE_OPERAND (ref, 0);
+ mark_addressable (ref);
+ addr = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (ref)), ref);
+ return build1 (NOP_EXPR, /* RETYPE_EXPR */
+ addr_type,
+ addr);
+ }
+ else
+#endif
+ {
+ if (! mark_addressable (ref))
+ {
+ error ("-> expression is not addressable");
+ return error_mark_node;
+ }
+ result = build1 (ADDR_EXPR, addr_type, ref);
+ if (staticp (ref)
+ && ! (TREE_CODE (ref) == FUNCTION_DECL
+ && DECL_CONTEXT (ref) != 0))
+ TREE_CONSTANT (result) = 1;
+ return result;
+ }
+}
+
+/*
+ * This implements the ADDR builtin function, which returns a
+ * free reference, analogous to the C 'void *'.
+ */
+tree
+build_chill_addr_expr (ref, errormsg)
+ tree ref;
+ char *errormsg;
+{
+ if (ref == error_mark_node)
+ return ref;
+
+ if (! CH_LOCATION_P (ref)
+ && TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE)
+ {
+ error ("ADDR parameter must be a LOCATION", errormsg);
+ return error_mark_node;
+ }
+ ref = build_chill_arrow_expr (ref, 1);
+
+ if (ref != NULL_TREE && TREE_CODE (ref) != ERROR_MARK)
+ TREE_TYPE (ref) = ptr_type_node;
+ else if (errormsg == NULL)
+ {
+ error ("possible internal error in build_chill_arrow_expr");
+ return error_mark_node;
+ }
+ else
+ {
+ error ("%s is not addressable", errormsg);
+ return error_mark_node;
+ }
+ return ref;
+}
+
+tree
+build_chill_binary_op (code, op0, op1)
+ enum chill_tree_code code;
+ tree op0, op1;
+{
+ register tree result;
+
+ if (op0 == NULL_TREE || TREE_CODE (op0) == ERROR_MARK)
+ return error_mark_node;
+ if (op1 == NULL_TREE || TREE_CODE (op1) == ERROR_MARK)
+ return error_mark_node;
+
+ result = build (code, NULL_TREE, op0, op1);
+
+ if (pass != 1)
+ result = finish_chill_binary_op (result);
+ return result;
+}
+
+/*
+ * process a string repetition phrase '(' COUNT ')' STRING
+ */
+tree
+string_char_rep (count, string)
+ int count;
+ tree string;
+{
+ int slen, charindx, repcnt;
+ char ch;
+ char *temp;
+ char *inp;
+ char *outp;
+ tree type;
+
+ if (string == NULL_TREE || TREE_CODE (string) == ERROR_MARK)
+ return error_mark_node;
+
+ type = TREE_TYPE (string);
+ slen = int_size_in_bytes (type);
+ temp = xmalloc (slen * count);
+ inp = &ch;
+ outp = temp;
+ if (TREE_CODE (string) == STRING_CST)
+ inp = TREE_STRING_POINTER (string);
+ else /* single character */
+ ch = (char)TREE_INT_CST_LOW (string);
+
+ /* copy the string/char COUNT times into the output buffer */
+ for (outp = temp, repcnt = 0; repcnt < count; repcnt++)
+ for (charindx = 0; charindx < slen; charindx++)
+ *outp++ = inp[charindx];
+ return build_chill_string (slen * count, temp);
+}
+
+/* Build a bit-string constant containing with the given LENGTH
+ containing all ones (if VALUE is true), or all zeros (if VALUE is false). */
+
+tree
+build_boring_bitstring (length, value)
+ long length;
+ int value;
+{
+ tree result;
+ tree list; /* Value of CONSTRUCTOR_ELTS in the result. */
+ if (value && length > 0)
+ list = tree_cons (integer_zero_node, size_int (length - 1), NULL_TREE);
+ else
+ list = NULL_TREE;
+
+ result = build (CONSTRUCTOR,
+ build_bitstring_type (size_int (length)),
+ NULL_TREE,
+ list);
+ TREE_CONSTANT (result) = 1;
+ CH_DERIVED_FLAG (result) = 1;
+ return result;
+}
+
+/*
+ * handle a string repetition, with the syntax:
+ * ( COUNT ) 'STRING'
+ * COUNT is required to be constant, positive and folded.
+ */
+tree
+build_chill_repetition_op (count_op, string)
+ tree count_op;
+ tree string;
+{
+ int count;
+ tree type = TREE_TYPE (string);
+
+ if (TREE_CODE (count_op) != INTEGER_CST)
+ {
+ error ("repetition count is not an integer constant");
+ return error_mark_node;
+ }
+
+ count = TREE_INT_CST_LOW (count_op);
+
+ if (count < 0)
+ {
+ error ("repetition count < 0");
+ return error_mark_node;
+ }
+ if (! TREE_CONSTANT (string))
+ {
+ error ("repetition value not constant");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (string) == STRING_CST)
+ return string_char_rep (count, string);
+
+ switch ((int)TREE_CODE (type))
+ {
+ case BOOLEAN_TYPE:
+ if (TREE_CODE (string) == INTEGER_CST)
+ return build_boring_bitstring (count, TREE_INT_CST_LOW (string));
+ error ("bitstring repetition of non-constant boolean");
+ return error_mark_node;
+
+ case CHAR_TYPE:
+ return string_char_rep (count, string);
+
+ case SET_TYPE:
+ { int i, tree_const = 1;
+ tree new_list = NULL_TREE;
+ tree vallist;
+ tree result;
+ tree domain = TYPE_DOMAIN (type);
+ tree orig_length;
+ HOST_WIDE_INT orig_len;
+
+ if (!CH_BOOLS_TYPE_P (type)) /* cannot replicate a powerset */
+ break;
+
+ orig_length = discrete_count (domain);
+
+ if (TREE_CODE (string) != CONSTRUCTOR || !TREE_CONSTANT (string)
+ || TREE_CODE (orig_length) != INTEGER_CST)
+ {
+ error ("string repetition operand is non-constant bitstring");
+ return error_mark_node;
+ }
+
+
+ orig_len = TREE_INT_CST_LOW (orig_length);
+
+ /* if the set is empty, this is NULL */
+ vallist = TREE_OPERAND (string, 1);
+
+ if (vallist == NULL_TREE) /* No bits are set. */
+ return build_boring_bitstring (count * orig_len, 0);
+ else if (TREE_CHAIN (vallist) == NULL_TREE
+ && (TREE_PURPOSE (vallist) == NULL_TREE
+ ? (orig_len == 1
+ && tree_int_cst_equal (TYPE_MIN_VALUE (domain),
+ TREE_VALUE (vallist)))
+ : (tree_int_cst_equal (TYPE_MIN_VALUE (domain),
+ TREE_PURPOSE (vallist))
+ && tree_int_cst_equal (TYPE_MAX_VALUE (domain),
+ TREE_VALUE (vallist)))))
+ return build_boring_bitstring (count * orig_len, 1);
+
+ for (i = 0; i < count; i++)
+ {
+ tree origin = build_int_2 (i * orig_len, 0);
+ tree temp;
+
+ /* scan down the given value list, building
+ new bit-positions */
+ for (temp = vallist; temp; temp = TREE_CHAIN (temp))
+ {
+ tree new_value
+ = fold (size_binop (PLUS_EXPR, origin, TREE_VALUE (temp)));
+ tree new_purpose = NULL_TREE;
+ if (! TREE_CONSTANT (TREE_VALUE (temp)))
+ tree_const = 0;
+ if (TREE_PURPOSE (temp))
+ {
+ new_purpose = fold (size_binop (PLUS_EXPR,
+ origin,
+ TREE_PURPOSE (temp)));
+ if (! TREE_CONSTANT (TREE_PURPOSE (temp)))
+ tree_const = 0;
+ }
+
+ new_list = tree_cons (new_purpose,
+ new_value, new_list);
+ }
+ }
+ result = build (CONSTRUCTOR,
+ build_bitstring_type (size_int (count * orig_len)),
+ NULL_TREE, nreverse (new_list));
+ TREE_CONSTANT (result) = tree_const;
+ CH_DERIVED_FLAG (result) = CH_DERIVED_FLAG (string);
+ return result;
+ }
+
+ default:
+ error ("non-char, non-bit string repetition");
+ return error_mark_node;
+ }
+ return error_mark_node;
+}
+
+tree
+finish_chill_unary_op (node)
+ tree node;
+{
+ enum chill_tree_code code = TREE_CODE (node);
+ tree op0 = check_have_mode (TREE_OPERAND (node, 0), "unary expression");
+ tree type0 = TREE_TYPE (op0);
+ struct ch_class class;
+
+ if (TREE_CODE (op0) == ERROR_MARK)
+ return error_mark_node;
+ /* The expression codes of the data types of the arguments tell us
+ whether the arguments are integers, floating, pointers, etc. */
+
+ if (TREE_CODE (type0) == REFERENCE_TYPE)
+ {
+ op0 = convert (TREE_TYPE (type0), op0);
+ type0 = TREE_TYPE (op0);
+ }
+
+ if (invalid_right_operand (code, type0))
+ {
+ error ("invalid operand of %s",
+ tree_code_name[(int)code]);
+ return error_mark_node;
+ }
+ switch ((int)TREE_CODE (type0))
+ {
+ case ARRAY_TYPE:
+ if (TREE_CODE ( TREE_TYPE (type0)) == BOOLEAN_TYPE)
+ code = SET_NOT_EXPR;
+ else
+ {
+ error ("right operand of %s is not array of boolean",
+ tree_code_name[(int)code]);
+ return error_mark_node;
+ }
+ break;
+ case BOOLEAN_TYPE:
+ switch ((int)code)
+ {
+ case BIT_NOT_EXPR:
+ case TRUTH_NOT_EXPR:
+ return invert_truthvalue (truthvalue_conversion (op0));
+
+ default:
+ error ("%s operator applied to boolean variable",
+ tree_code_name[(int)code]);
+ return error_mark_node;
+ }
+ break;
+
+ case SET_TYPE:
+ switch ((int)code)
+ {
+ case BIT_NOT_EXPR:
+ case NEGATE_EXPR:
+ {
+ tree temp = fold_set_expr (BIT_NOT_EXPR, op0, NULL_TREE);
+
+ if (temp)
+ return temp;
+
+ code = SET_NOT_EXPR;
+ }
+ break;
+
+ default:
+ error ("invalid right operand of %s", tree_code_name[(int)code]);
+ return error_mark_node;
+ }
+
+ }
+
+ class = chill_expr_class (op0);
+ if (class.mode)
+ class.mode = CH_ROOT_MODE (class.mode);
+ TREE_SET_CODE (node, code);
+ TREE_OPERAND (node, 0) = op0 = convert_to_class (class, op0);
+ TREE_TYPE (node) = TREE_TYPE (op0);
+
+ node = convert_to_class (class, fold (node));
+
+ /* FIXME: should call
+ * cond_type_range_exception (op0);
+ */
+ return node;
+}
+
+/* op is TRUTH_NOT_EXPR, BIT_NOT_EXPR, or NEGATE_EXPR */
+
+tree
+build_chill_unary_op (code, op0)
+ enum chill_tree_code code;
+ tree op0;
+{
+ register tree result = NULL_TREE;
+ struct ch_class class;
+ tree type0 = TREE_TYPE (op0);
+
+ if (op0 == NULL_TREE || TREE_CODE (op0) == ERROR_MARK)
+ return error_mark_node;
+
+ result = build1 (code, NULL_TREE, op0);
+
+ if (pass != 1)
+ result = finish_chill_unary_op (result);
+ return result;
+}
+
+tree
+truthvalue_conversion (expr)
+ tree expr;
+{
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+
+#if 0 /* what about a LE_EXPR (integer_type, integer_type ) */
+ if (TREE_CODE (TREE_TYPE (expr)) != BOOLEAN_TYPE)
+ error ("non-boolean mode in conditional expression");
+#endif
+
+ switch ((int)TREE_CODE (expr))
+ {
+ /* It is simpler and generates better code to have only TRUTH_*_EXPR
+ or comparison expressions as truth values at this level. */
+#if 0
+ case COMPONENT_REF:
+ /* A one-bit unsigned bit-field is already acceptable. */
+ if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1)))
+ && TREE_UNSIGNED (TREE_OPERAND (expr, 1)))
+ return expr;
+ break;
+#endif
+
+ case EQ_EXPR:
+ /* It is simpler and generates better code to have only TRUTH_*_EXPR
+ or comparison expressions as truth values at this level. */
+ case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case ERROR_MARK:
+ return expr;
+
+ case INTEGER_CST:
+ return integer_zerop (expr) ? boolean_false_node : boolean_true_node;
+
+ case REAL_CST:
+ return real_zerop (expr) ? boolean_false_node : boolean_true_node;
+
+ case ADDR_EXPR:
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
+ return build (COMPOUND_EXPR, boolean_type_node,
+ TREE_OPERAND (expr, 0), boolean_true_node);
+ else
+ return boolean_true_node;
+
+ case NEGATE_EXPR:
+ case ABS_EXPR:
+ case FLOAT_EXPR:
+ case FFS_EXPR:
+ /* These don't change whether an object is non-zero or zero. */
+ return truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ /* These don't change whether an object is zero or non-zero, but
+ we can't ignore them if their second arg has side-effects. */
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
+ return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 1),
+ truthvalue_conversion (TREE_OPERAND (expr, 0)));
+ else
+ return truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+ case COND_EXPR:
+ /* Distribute the conversion into the arms of a COND_EXPR. */
+ return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0),
+ truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ truthvalue_conversion (TREE_OPERAND (expr, 2))));
+
+ case CONVERT_EXPR:
+ /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
+ since that affects how `default_conversion' will behave. */
+ if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
+ break;
+ /* fall through... */
+ case NOP_EXPR:
+ /* If this is widening the argument, we can ignore it. */
+ if (TYPE_PRECISION (TREE_TYPE (expr))
+ >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
+ return truthvalue_conversion (TREE_OPERAND (expr, 0));
+ break;
+
+ case BIT_XOR_EXPR:
+ case MINUS_EXPR:
+ /* These can be changed into a comparison of the two objects. */
+ if (TREE_TYPE (TREE_OPERAND (expr, 0))
+ == TREE_TYPE (TREE_OPERAND (expr, 1)))
+ return build_chill_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
+ TREE_OPERAND (expr, 1));
+ return build_chill_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
+ fold (build1 (NOP_EXPR,
+ TREE_TYPE (TREE_OPERAND (expr, 0)),
+ TREE_OPERAND (expr, 1))));
+ }
+
+ return build_chill_binary_op (NE_EXPR, expr, boolean_false_node);
+}
+
+
+/*
+ * return a folded tree for the powerset's length in bits. If a
+ * non-set is passed, we assume it's an array or boolean bytes.
+ */
+tree
+powersetlen (powerset)
+ tree powerset;
+{
+ tree domain, temp;
+
+ if (powerset == NULL_TREE || TREE_CODE (powerset) == ERROR_MARK)
+ return error_mark_node;
+
+ return discrete_count (TYPE_DOMAIN (TREE_TYPE (powerset)));
+}
diff --git a/gcc/ch/lang-specs.h b/gcc/ch/lang-specs.h
new file mode 100644
index 0000000..be02c11
--- /dev/null
+++ b/gcc/ch/lang-specs.h
@@ -0,0 +1,42 @@
+/* Definitions for specs for GNU CHILL.
+ Copyright (C) 1995 Free Software Foundation, Inc..
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This is the contribution to the `default_compilers' array in gcc.c for
+ CHILL. */
+
+ {".ch", "@chill" },
+ {".chi", "@chill" },
+ {"@chill",
+ "cpp -lang-chill %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ %{C:%{!E:%eGNU CHILL does not support -C without using -E}}\
+ -undef -D__GNUCHILL__=%v1 -D__GNUC_MINOR__=%v2\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:-D__OPTIMIZE__} %{traditional} %{ftraditional:-traditional}\
+ %{traditional-cpp:-traditional} %{!undef:%{!ansi:%p} %P} %{trigraphs}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
+ %i %{!E:%g.i}%{E:%W{o*}} \n",
+ "%{!E:cc1chill %g.i %1 \
+ %{!Q:-quiet} -dumpbase %b.ch %{d*} %{m*} %{a}\
+ %{g*} %{O*} %{W*} %{w} %{pedantic*} %{itu} \
+ %{v:-version} %{pg:-p} %{p} %{f*} %{I*} \
+ %{aux-info*} %X \
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %a %Y \
+ %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
+ %{!pipe:%g.s} %A\n }}"},
diff --git a/gcc/ch/lang.c b/gcc/ch/lang.c
new file mode 100644
index 0000000..b52bca6
--- /dev/null
+++ b/gcc/ch/lang.c
@@ -0,0 +1,306 @@
+/* Language-specific hook definitions for CHILL front end.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "config.h"
+#include "tree.h"
+#include "ch-tree.h"
+#include "lex.h"
+#include <stdio.h>
+#include "input.h"
+
+/* Type node for boolean types. */
+
+tree boolean_type_node;
+
+/* True if STRING(INDEX) yields a CHARS(1) (or BOOLS(1)) rather than
+ a CHAR (or BOOL). Also, makes CHARS(1) similar for CHAR,
+ and BOOLS(1) similar to BOOL. This is for compatibility
+ for the 1984 version of Z.200.*/
+int flag_old_strings = 0;
+
+/* This is set non-zero to force user input tokens to lower case.
+ This is non-standard. See Z.200, page 8. */
+int ignore_case = 1;
+
+/* True if reserved and predefined words ('special' words in the Z.200
+ terminology) are in uppercase. Obviously, this had better not be
+ true if we're ignoring input case. */
+int special_UC = 0;
+
+/* The actual name of the input file, regardless of any #line directives */
+char* chill_real_input_filename;
+extern FILE* finput;
+
+extern int maximum_field_alignment;
+
+extern void error PROTO((char *, ...));
+extern void error_with_decl PROTO((tree, char *, ...));
+extern void fatal PROTO((char *, ...));
+extern int floor_log2_wide PROTO((unsigned HOST_WIDE_INT));
+extern void pedwarn_with_decl PROTO((tree, char *, ...));
+extern void sorry PROTO((char *, ...));
+extern int type_hash_list PROTO((tree));
+
+/* return 1 if the expression tree given has all
+ constant nodes as its leaves; return 0 otherwise. */
+int
+deep_const_expr (exp)
+ tree exp;
+{
+ enum chill_tree_code code;
+ int length;
+ int i;
+
+ if (exp == NULL_TREE)
+ return 0;
+
+ code = TREE_CODE (exp);
+ length = tree_code_length[(int) code];
+
+ /* constant leaf? return TRUE */
+ if (TREE_CODE_CLASS (code) == 'c')
+ return 1;
+
+ /* recursively check next level down */
+ for (i = 0; i < length; i++)
+ if (! deep_const_expr (TREE_OPERAND (exp, i)))
+ return 0;
+ return 1;
+}
+
+
+tree
+const_expr (exp)
+ tree exp;
+{
+ if (TREE_CODE (exp) == INTEGER_CST)
+ return exp;
+ if (TREE_CODE (exp) == CONST_DECL)
+ return const_expr (DECL_INITIAL (exp));
+ if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd'
+ && DECL_INITIAL (exp) != NULL_TREE
+ && TREE_READONLY (exp))
+ return DECL_INITIAL (exp);
+ if (deep_const_expr (exp))
+ return exp;
+ if (TREE_CODE (exp) != ERROR_MARK)
+ error ("non-constant expression");
+ return error_mark_node;
+}
+
+/* Each of the functions defined here
+ is an alternative to a function in objc-actions.c. */
+
+/* Used by c-lex.c, but only for objc. */
+tree
+lookup_interface (arg)
+ tree arg;
+{
+ return 0;
+}
+
+int
+maybe_objc_comptypes (lhs, rhs)
+ tree lhs, rhs;
+{
+ return -1;
+}
+
+tree
+maybe_building_objc_message_expr ()
+{
+ return 0;
+}
+
+int
+recognize_objc_keyword ()
+{
+ return 0;
+}
+
+void
+lang_init_options ()
+{
+}
+
+/* used by print-tree.c */
+
+void
+lang_print_xnode (file, node, indent)
+ FILE *file;
+ tree node;
+ int indent;
+{
+}
+
+void
+GNU_xref_begin ()
+{
+ fatal ("GCC does not yet support XREF");
+}
+
+void
+GNU_xref_end ()
+{
+ fatal ("GCC does not yet support XREF");
+}
+
+/*
+ * process chill-specific compiler command-line options
+ */
+int
+lang_decode_option (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *p = argv[0];
+ static explicit_ignore_case = 0;
+ if (!strcmp(p, "-lang-chill"))
+ ; /* do nothing */
+ else if (!strcmp (p, "-fruntime-checking"))
+ {
+ range_checking = 1;
+ empty_checking = 1;
+ }
+ else if (!strcmp (p, "-fno-runtime-checking"))
+ {
+ range_checking = 0;
+ empty_checking = 0;
+ runtime_checking_flag = 0;
+ }
+ else if (!strcmp (p, "-flocal-loop-counter"))
+ flag_local_loop_counter = 1;
+ else if (!strcmp (p, "-fno-local-loop-counter"))
+ flag_local_loop_counter = 0;
+ else if (!strcmp (p, "-fold-strings"))
+ flag_old_strings = 1;
+ else if (!strcmp (p, "-fno-old-strings"))
+ flag_old_strings = 0;
+ else if (!strcmp (p, "-fignore-case"))
+ {
+ explicit_ignore_case = 1;
+ if (special_UC)
+ {
+ error ("Ignoring case upon input and");
+ error ("making special words uppercase wouldn't work.");
+ }
+ else
+ ignore_case = 1;
+ }
+ else if (!strcmp (p, "-fno-ignore-case"))
+ ignore_case = 0;
+ else if (!strcmp (p, "-fspecial_UC"))
+ {
+ if (explicit_ignore_case)
+ {
+ error ("Making special words uppercase and");
+ error (" ignoring case upon input wouldn't work.");
+ }
+ else
+ special_UC = 1, ignore_case = 0;
+ }
+ else if (!strcmp (p, "-fspecial_LC"))
+ special_UC = 0;
+ else if (!strcmp (p, "-fpack"))
+ maximum_field_alignment = BITS_PER_UNIT;
+ else if (!strcmp (p, "-fno-pack"))
+ maximum_field_alignment = 0;
+ else if (!strcmp (p, "-fchill-grant-only"))
+ grant_only_flag = 1;
+ else if (!strcmp (p, "-fgrant-only"))
+ grant_only_flag = 1;
+ /* user has specified a seize-file path */
+ else if (p[0] == '-' && p[1] == 'I')
+ register_seize_path (&p[2]);
+ if (!strcmp(p, "-itu")) /* Force Z.200 semantics */
+ {
+ pedantic = 1; /* FIXME: new flag name? */
+ flag_local_loop_counter = 1;
+ }
+ else
+ return c_decode_option (argc, argv);
+
+ return 1;
+}
+
+void
+chill_print_error_function (file)
+ char *file;
+{
+ static tree last_error_function = NULL_TREE;
+ static struct module *last_error_module = NULL;
+
+ if (last_error_function == current_function_decl
+ && last_error_module == current_module)
+ return;
+
+ last_error_function = current_function_decl;
+ last_error_module = current_module;
+
+ if (file)
+ fprintf (stderr, "%s: ", file);
+
+ if (current_function_decl == global_function_decl
+ || current_function_decl == NULL_TREE)
+ {
+ if (current_module == NULL)
+ fprintf (stderr, "At top level:\n");
+ else
+ fprintf (stderr, "In module %s:\n",
+ IDENTIFIER_POINTER (current_module->name));
+ }
+ else
+ {
+ char *kind = "function";
+ char *name = (*decl_printable_name) (current_function_decl, 2);
+ fprintf (stderr, "In %s `%s':\n", kind, name);
+ }
+}
+
+/* Print an error message for invalid use of an incomplete type.
+ VALUE is the expression that was used (or 0 if that isn't known)
+ and TYPE is the type that was invalid. */
+
+void
+incomplete_type_error (value, type)
+ tree value;
+ tree type;
+{
+ error ("internal error - use of undefined type");
+}
+
+void
+lang_init ()
+{
+ extern void (*print_error_function) PROTO((char*));
+
+ chill_real_input_filename = input_filename;
+
+ /* the beginning of the file is a new line; check for # */
+ /* With luck, we discover the real source file's name from that
+ and put it in input_filename. */
+
+ ungetc (check_newline (), finput);
+
+ /* set default grant file */
+ set_default_grant_file ();
+
+ print_error_function = chill_print_error_function;
+}
diff --git a/gcc/ch/parse.c b/gcc/ch/parse.c
new file mode 100644
index 0000000..32f72e5
--- /dev/null
+++ b/gcc/ch/parse.c
@@ -0,0 +1,4237 @@
+/* Parser for GNU CHILL (CCITT High-Level Language) -*- C -*-
+ Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This is a two-pass parser. In pass 1, we collect declarations,
+ * ignoring actions and most expressions. We store only the
+ * declarations and close, open and re-lex the input file to save
+ * main memory. We anticipate that the compiler will be processing
+ * *very* large single programs which are mechanically generated,
+ * and so we want to store a minimum of information between passes.
+ *
+ * yylex detects the end of the main input file and returns the
+ * END_PASS_1 token. We then re-initialize each CHILL compiler
+ * module's global variables and re-process the input file. The
+ * grant file is output. If the user has requested it, GNU CHILL
+ * exits at this time - its only purpose was to generate the grant
+ * file. Optionally, the compiler may exit if errors were detected
+ * in pass 1.
+ *
+ * As each symbol scope is entered, we install its declarations into
+ * the symbol table. Undeclared types and variables are announced
+ * now.
+ *
+ * Then code is generated.
+ */
+
+#include <stdio.h>
+#include "config.h"
+#include "tree.h"
+#include "ch-tree.h"
+#include "lex.h"
+#include "actions.h"
+#include "tasking.h"
+#include "parse.h"
+
+/* Since parsers are distinct for each language, put the
+ language string definition here. (fnf) */
+char *language_string = "GNU CHILL";
+
+/* Common code to be done before expanding any action. */
+#define INIT_ACTION { \
+ if (! ignoring) emit_line_note (input_filename, lineno); }
+
+/* Pop a scope for an ON handler. */
+#define POP_USED_ON_CONTEXT pop_handler(1)
+
+/* Pop a scope for an ON handler that wasn't there. */
+#define POP_UNUSED_ON_CONTEXT pop_handler(0)
+
+#define PUSH_ACTION push_action()
+
+/* Cause the `yydebug' variable to be defined. */
+#define YYDEBUG 1
+
+extern void assemble_external PROTO((tree));
+extern void chill_check_no_handlers PROTO((void));
+extern void chill_finish_on PROTO((void));
+extern void chill_handle_case_default PROTO((void));
+extern void chill_handle_on_labels PROTO((tree));
+extern tree chill_initializer_constant_valid_p PROTO((tree, tree));
+extern void chill_start_default_handler PROTO((void));
+extern void chill_start_on PROTO((void));
+extern struct rtx_def* emit_line_note PROTO((char *, int));
+extern struct rtx_def* gen_label_rtx PROTO((void));
+extern void emit_jump PROTO((struct rtx_def *));
+extern void emit_label PROTO((struct rtx_def *));
+extern void error PROTO((char *, ...));
+extern int expand_exit_labelled PROTO((tree));
+extern void lookup_and_expand_goto PROTO((tree));
+extern void lookup_and_handle_exit PROTO((tree));
+
+extern void push_granted PROTO((tree, tree));
+extern void sorry PROTO((char *, ...));
+extern void warning PROTO((char *, ...));
+
+extern int lineno;
+extern char *input_filename;
+extern tree generic_signal_type_node;
+extern tree signal_code;
+extern int all_static_flag;
+extern int ignore_case;
+
+static int quasi_signal = 0; /* 1 if processing a quasi signal decl */
+
+int parsing_newmode; /* 0 while parsing SYNMODE;
+ 1 while parsing NEWMODE. */
+int expand_exit_needed = 0;
+
+/* Gets incremented if we see errors such that we don't want to run pass 2. */
+
+int serious_errors = 0;
+
+static tree current_fieldlist;
+
+/* We don't care about expressions during pass 1, except while we're
+ parsing the RHS of a SYN definition, or while parsing a mode that
+ we need. NOTE: This also causes mode expressions to be ignored. */
+int ignoring = 1; /* 1 to ignore expressions */
+
+/* True if we have seen an action not in a (user) function. */
+int seen_action = 0;
+int build_constructor = 0;
+
+/* The action_nesting_level of the current procedure body. */
+int proc_action_level = 0;
+
+/* This is the identifier of the label that prefixes the current action,
+ or NULL if there was none. It is cleared at the end of an action,
+ or when starting a nested action list, so get it while you can! */
+static tree label = NULL_TREE; /* for statement labels */
+
+#if 0
+static tree current_block;
+#endif
+
+int in_pseudo_module = 0;
+int pass = 0; /* 0 for init_decl_processing,
+ 1 for pass 1, 2 for pass 2 */
+
+/* re-initialize global variables for pass 2 */
+static void
+ch_parse_init ()
+{
+ expand_exit_needed = 0;
+ label = NULL_TREE; /* for statement labels */
+ current_module = NULL;
+ in_pseudo_module = 0;
+}
+
+static void
+check_end_label (start, end)
+ tree start, end;
+{
+ if (end != NULL_TREE)
+ {
+ if (start == NULL_TREE && pass == 1)
+ error ("there was no start label to match the end label '%s'",
+ IDENTIFIER_POINTER(end));
+ else if (start != end && pass == 1)
+ error ("start label '%s' does not match end label '%s'",
+ IDENTIFIER_POINTER(start),
+ IDENTIFIER_POINTER(end));
+ }
+}
+
+
+/*
+ * given a tree which is an id, a type or a decl,
+ * return the associated type, or issue an error and
+ * return error_mark_node.
+ */
+tree
+get_type_of (id_or_decl)
+ tree id_or_decl;
+{
+ tree type = id_or_decl;
+
+ if (id_or_decl == NULL_TREE
+ || TREE_CODE (id_or_decl) == ERROR_MARK)
+ return error_mark_node;
+
+ if (pass == 1 || ignoring == 1)
+ return id_or_decl;
+
+ if (TREE_CODE (type) == IDENTIFIER_NODE)
+ {
+ type = lookup_name (id_or_decl);
+ if (type == NULL_TREE)
+ {
+ error ("`%s' not declared", IDENTIFIER_POINTER (id_or_decl));
+ type = error_mark_node;
+ }
+ }
+ if (TREE_CODE (type) == TYPE_DECL)
+ type = TREE_TYPE (type);
+ return type; /* was a type all along */
+}
+
+
+static void
+end_function ()
+{
+ if (CH_DECL_PROCESS (current_function_decl))
+ {
+ /* finishing a process */
+ if (! ignoring)
+ {
+ tree result =
+ build_chill_function_call
+ (lookup_name (get_identifier ("__stop_process")),
+ NULL_TREE);
+ expand_expr_stmt (result);
+ emit_line_note (input_filename, lineno);
+ }
+ }
+ else
+ {
+ /* finishing a procedure.. */
+ if (! ignoring)
+ {
+ if (result_never_set
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl)))
+ != VOID_TYPE)
+ warning ("No RETURN or RESULT in procedure");
+ chill_expand_return (NULL_TREE, 1);
+ }
+ }
+ finish_chill_function ();
+ pop_chill_function_context ();
+}
+
+static tree
+build_prefix_clause (id)
+ tree id;
+{
+ if (!id)
+ {
+ if (current_module && current_module->name)
+ { char *module_name = IDENTIFIER_POINTER (current_module->name);
+ if (module_name[0] && module_name[0] != '_')
+ return current_module->name;
+ }
+ error ("PREFIXED clause with no prelix in unlabeled module");
+ }
+ return id;
+}
+
+void
+possibly_define_exit_label (label)
+ tree label;
+{
+ if (label)
+ define_label (input_filename, lineno, munge_exit_label (label));
+}
+
+#define MAX_LOOK_AHEAD 2
+static enum terminal terminal_buffer[MAX_LOOK_AHEAD+1];
+YYSTYPE yylval;
+static YYSTYPE val_buffer[MAX_LOOK_AHEAD+1];
+
+/*enum terminal current_token, lookahead_token;*/
+
+#define TOKEN_NOT_READ dummy_last_terminal
+
+#ifdef __GNUC__
+__inline__
+#endif
+static int
+PEEK_TOKEN()
+{
+ if (terminal_buffer[0] == TOKEN_NOT_READ)
+ {
+ terminal_buffer[0] = yylex();
+ val_buffer[0] = yylval;
+ }
+ return terminal_buffer[0];
+}
+#define PEEK_TREE() val_buffer[0].ttype
+#define PEEK_TOKEN1() peek_token_(1)
+#define PEEK_TOKEN2() peek_token_(2)
+static int
+peek_token_ (i)
+ int i;
+{
+ if (i > MAX_LOOK_AHEAD)
+ fatal ("internal error - too much lookahead");
+ if (terminal_buffer[i] == TOKEN_NOT_READ)
+ {
+ terminal_buffer[i] = yylex();
+ val_buffer[i] = yylval;
+ }
+ return terminal_buffer[i];
+}
+
+static void
+pushback_token (code, node)
+ int code;
+ tree node;
+{
+ int i;
+ if (terminal_buffer[MAX_LOOK_AHEAD] != TOKEN_NOT_READ)
+ fatal ("internal error - cannot pushback token");
+ for (i = MAX_LOOK_AHEAD; i > 0; i--)
+ {
+ terminal_buffer[i] = terminal_buffer[i - 1];
+ val_buffer[i] = val_buffer[i - 1];
+ }
+ terminal_buffer[0] = code;
+ val_buffer[0].ttype = node;
+}
+
+static void
+forward_token_()
+{
+ int i;
+ for (i = 0; i < MAX_LOOK_AHEAD; i++)
+ {
+ terminal_buffer[i] = terminal_buffer[i+1];
+ val_buffer[i] = val_buffer[i+1];
+ }
+ terminal_buffer[MAX_LOOK_AHEAD] = TOKEN_NOT_READ;
+}
+#define FORWARD_TOKEN() forward_token_()
+
+/* Skip the next token.
+ if it isn't TOKEN, the parser is broken. */
+
+void
+require(token)
+ enum terminal token;
+{
+ if (PEEK_TOKEN() != token)
+ {
+ char buf[80];
+ sprintf (buf, "internal parser error - expected token %d", (int)token);
+ fatal(buf);
+ }
+ FORWARD_TOKEN();
+}
+
+int
+check_token (token)
+ enum terminal token;
+{
+ if (PEEK_TOKEN() != token)
+ return 0;
+ FORWARD_TOKEN ();
+ return 1;
+}
+
+/* return 0 if expected token was not found,
+ else return 1.
+*/
+int
+expect(token, message)
+ enum terminal token;
+ char *message;
+{
+ if (PEEK_TOKEN() != token)
+ {
+ if (pass == 1)
+ error(message ? message : "syntax error");
+ return 0;
+ }
+ else
+ FORWARD_TOKEN();
+ return 1;
+}
+
+/* define a SYNONYM __PROCNAME__ (__procname__) which holds
+ the name of the current procedure.
+ This should be quit the same as __FUNCTION__ in C */
+static void
+define__PROCNAME__ ()
+{
+ char *fname;
+ tree string;
+ tree procname;
+
+ if (current_function_decl == NULL_TREE)
+ fname = "toplevel";
+ else
+ fname = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
+
+ string = build_chill_string (strlen (fname), fname);
+ procname = get_identifier (ignore_case ? "__procname__" : "__PROCNAME__");
+ push_syndecl (procname, NULL_TREE, string);
+}
+
+/* Forward declarations. */
+static tree parse_expression ();
+static tree parse_primval ();
+static tree parse_mode PROTO((void));
+static tree parse_opt_mode PROTO((void));
+static tree parse_untyped_expr ();
+static tree parse_opt_untyped_expr ();
+static int parse_definition PROTO((int));
+static void parse_opt_actions ();
+static void parse_body PROTO((void));
+static tree parse_if_expression_body PROTO((void));
+static tree parse_opt_handler PROTO((void));
+
+static tree
+parse_opt_name_string (allow_all)
+ int allow_all; /* 1 if ALL is allowed as a postfix */
+{
+ enum terminal token = PEEK_TOKEN();
+ tree name;
+ if (token != NAME)
+ {
+ if (token == ALL && allow_all)
+ {
+ FORWARD_TOKEN ();
+ return ALL_POSTFIX;
+ }
+ return NULL_TREE;
+ }
+ name = PEEK_TREE();
+ for (;;)
+ {
+ FORWARD_TOKEN ();
+ token = PEEK_TOKEN();
+ if (token != '!')
+ return name;
+ FORWARD_TOKEN();
+ token = PEEK_TOKEN();
+ if (token == ALL && allow_all)
+ return get_identifier3(IDENTIFIER_POINTER (name), "!", "*");
+ if (token != NAME)
+ {
+ if (pass == 1)
+ error ("'%s!' is not followed by an identifier",
+ IDENTIFIER_POINTER (name));
+ return name;
+ }
+ name = get_identifier3(IDENTIFIER_POINTER(name),
+ "!", IDENTIFIER_POINTER(PEEK_TREE()));
+ }
+}
+
+static tree
+parse_simple_name_string ()
+{
+ enum terminal token = PEEK_TOKEN();
+ tree name;
+ if (token != NAME)
+ {
+ error ("expected a name here");
+ return error_mark_node;
+ }
+ name = PEEK_TREE ();
+ FORWARD_TOKEN ();
+ return name;
+}
+
+static tree
+parse_name_string ()
+{
+ tree name = parse_opt_name_string (0);
+ if (name)
+ return name;
+ if (pass == 1)
+ error ("expected a name string here");
+ return error_mark_node;
+}
+
+static tree
+parse_defining_occurrence ()
+{
+ if (PEEK_TOKEN () == NAME)
+ {
+ tree id = PEEK_TREE();
+ FORWARD_TOKEN ();
+ return id;
+ }
+ return NULL;
+}
+
+/* Matches: <name_string>
+ Returns if pass 1: the identifier.
+ Returns if pass 2: a decl or value for identifier. */
+
+static tree
+parse_name ()
+{
+ tree name = parse_name_string ();
+ if (pass == 1 || ignoring)
+ return name;
+ else
+ {
+ tree decl = lookup_name (name);
+ if (decl == NULL_TREE)
+ {
+ error ("`%s' undeclared", IDENTIFIER_POINTER (name));
+ return error_mark_node;
+ }
+ else if (TREE_CODE (TREE_TYPE (decl)) == ERROR_MARK)
+ return error_mark_node;
+ else if (TREE_CODE (decl) == CONST_DECL)
+ return DECL_INITIAL (decl);
+ else if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE)
+ return convert_from_reference (decl);
+ else
+ return decl;
+ }
+}
+
+static tree
+parse_optlabel()
+{
+ tree label = parse_defining_occurrence();
+ if (label != NULL)
+ expect(COLON, "expected a ':' here");
+ return label;
+}
+
+static void
+parse_semi_colon ()
+{
+ enum terminal token = PEEK_TOKEN ();
+ if (token == SC)
+ FORWARD_TOKEN ();
+ else if (pass == 1)
+ (token == END ? pedwarn : error) ("expected ';' here");
+ label = NULL_TREE;
+}
+
+static void
+parse_opt_end_label_semi_colon (start_label)
+ tree start_label;
+{
+ if (PEEK_TOKEN() == NAME)
+ {
+ tree end_label = parse_name_string ();
+ check_end_label (start_label, end_label);
+ }
+ parse_semi_colon ();
+}
+
+extern tree set_module_name ();
+
+static void
+parse_modulion (label)
+ tree label;
+{
+ tree module_name;
+
+ label = set_module_name (label);
+ module_name = push_module (label, 0);
+ FORWARD_TOKEN();
+
+ push_action ();
+ parse_body();
+ expect(END, "expected END here");
+ parse_opt_handler ();
+ parse_opt_end_label_semi_colon (label);
+ find_granted_decls ();
+ pop_module ();
+}
+
+static void
+parse_spec_module (label)
+ tree label;
+{
+ tree module_name = push_module (set_module_name (label), 1);
+ int save_ignoring = ignoring;
+ ignoring = pass == 2;
+ FORWARD_TOKEN(); /* SKIP SPEC */
+ expect (MODULE, "expected 'MODULE' here");
+
+ while (parse_definition (1)) { }
+ if (parse_action ())
+ error ("action not allowed in SPEC MODULE");
+ expect(END, "expected END here");
+ parse_opt_end_label_semi_colon (label);
+ find_granted_decls ();
+ pop_module ();
+ ignoring = save_ignoring;
+}
+
+/* Matches: <name_string> ( "," <name_string> )*
+ Returns either a single IDENTIFIER_NODE,
+ or a chain (TREE_LIST) of IDENTIFIER_NODES.
+ (Since a single identifier is the common case, we avoid wasting space
+ (twice, once for each pass) with extra TREE_LIST nodes in that case.)
+ (Will not return NULL_TREE even if ignoring is true.) */
+
+static tree
+parse_defining_occurrence_list ()
+{
+ tree chain = NULL_TREE;
+ tree name = parse_defining_occurrence ();
+ if (name == NULL_TREE)
+ {
+ error("missing defining occurrence");
+ return NULL_TREE;
+ }
+ if (! check_token (COMMA))
+ return name;
+ chain = build_tree_list (NULL_TREE, name);
+ for (;;)
+ {
+ name = parse_defining_occurrence ();
+ if (name == NULL)
+ {
+ error ("bad defining occurrence following ','");
+ break;
+ }
+ chain = tree_cons (NULL_TREE, name, chain);
+ if (! check_token (COMMA))
+ break;
+ }
+ return nreverse (chain);
+}
+
+static void
+parse_mode_definition (is_newmode)
+ int is_newmode;
+{
+ tree mode, names;
+ int save_ignoring = ignoring;
+ ignoring = pass == 2;
+ names = parse_defining_occurrence_list ();
+ expect (EQL, "missing '=' in mode definition");
+ mode = parse_mode ();
+ if (names == NULL_TREE || TREE_CODE (names) == TREE_LIST)
+ {
+ for ( ; names != NULL_TREE; names = TREE_CHAIN (names))
+ push_modedef (names, mode, is_newmode);
+ }
+ else
+ push_modedef (names, mode, is_newmode);
+ ignoring = save_ignoring;
+}
+
+void
+parse_mode_definition_statement (is_newmode)
+ int is_newmode;
+{
+ tree names;
+ FORWARD_TOKEN (); /* skip SYNMODE or NEWMODE */
+ parse_mode_definition (is_newmode);
+ while (PEEK_TOKEN () == COMMA)
+ {
+ FORWARD_TOKEN ();
+ parse_mode_definition (is_newmode);
+ }
+ parse_semi_colon ();
+}
+
+static void
+parse_synonym_definition ()
+{ tree expr = NULL_TREE;
+ tree names = parse_defining_occurrence_list ();
+ tree mode = parse_opt_mode ();
+ if (! expect (EQL, "missing '=' in synonym definition"))
+ mode = error_mark_node;
+ else
+ {
+ if (mode)
+ expr = parse_untyped_expr ();
+ else
+ expr = parse_expression ();
+ }
+ if (names == NULL_TREE || TREE_CODE (names) == TREE_LIST)
+ {
+ for ( ; names != NULL_TREE; names = TREE_CHAIN (names))
+ push_syndecl (names, mode, expr);
+ }
+ else
+ push_syndecl (names, mode, expr);
+}
+
+static void
+parse_synonym_definition_statement()
+{
+ int save_ignoring= ignoring;
+ ignoring = pass == 2;
+ require (SYN);
+ parse_synonym_definition ();
+ while (PEEK_TOKEN () == COMMA)
+ {
+ FORWARD_TOKEN ();
+ parse_synonym_definition ();
+ }
+ ignoring = save_ignoring;
+ parse_semi_colon ();
+}
+
+/* Attempts to match: "(" <exception list> ")" ":".
+ Return NULL_TREE on failure, and non-NULL on success.
+ On success, if pass 1, return a TREE_LIST of IDENTIFIER_NODEs. */
+
+static tree
+parse_on_exception_list ()
+{
+ tree name;
+ tree list = NULL_TREE;
+ int tok1 = PEEK_TOKEN ();
+ int tok2 = PEEK_TOKEN1 ();
+
+ /* This requires a lot of look-ahead, because we cannot
+ easily a priori distinguish an exception-list from an expression. */
+ if (tok1 != LPRN || tok2 != NAME)
+ {
+ if (tok1 == NAME && tok2 == COLON && pass == 1)
+ error ("missing '(' in exception list");
+ return 0;
+ }
+ require (LPRN);
+ name = parse_name_string ();
+ if (PEEK_TOKEN () == RPRN && PEEK_TOKEN1 () == COLON)
+ {
+ /* Matched: '(' <name_string> ')' ':' */
+ FORWARD_TOKEN (); FORWARD_TOKEN ();
+ return pass == 1 ? build_tree_list (NULL_TREE, name) : name;
+ }
+ if (PEEK_TOKEN() == COMMA)
+ {
+ if (pass == 1)
+ list = build_tree_list (NULL_TREE, name);
+ while (check_token (COMMA))
+ {
+ tree old_names = list;
+ name = parse_name_string ();
+ if (pass == 1)
+ {
+ for ( ; old_names != NULL_TREE; old_names = TREE_CHAIN (old_names))
+ {
+ if (TREE_VALUE (old_names) == name)
+ {
+ error ("ON exception names must be unique");
+ goto continue_parsing;
+ }
+ }
+ list = tree_cons (NULL_TREE, name, list);
+ continue_parsing:
+ ;
+ }
+ }
+ if (! check_token (RPRN) || ! check_token(COLON))
+ error ("syntax error in exception list");
+ return pass == 1 ? nreverse (list) : name;
+ }
+ /* Matched: '(' name_string
+ but it doesn't match the syntax of an exception list.
+ It could be the beginning of an expression, so back up. */
+ pushback_token (NAME, name);
+ pushback_token (LPRN, 0);
+ return NULL_TREE;
+}
+
+static void
+parse_on_alternatives ()
+{
+ for (;;)
+ {
+ tree except_list = parse_on_exception_list ();
+ if (except_list != NULL)
+ chill_handle_on_labels (except_list);
+ else if (parse_action ())
+ expand_exit_needed = 1;
+ else
+ break;
+ }
+}
+
+static tree
+parse_opt_handler ()
+{
+ if (! check_token (ON))
+ {
+ POP_UNUSED_ON_CONTEXT;
+ return NULL_TREE;
+ }
+ if (check_token (END))
+ {
+ pedwarn ("empty ON-condition");
+ POP_UNUSED_ON_CONTEXT;
+ return NULL_TREE;
+ }
+ if (! ignoring)
+ {
+ chill_start_on ();
+ expand_exit_needed = 0;
+ }
+ if (PEEK_TOKEN () != ELSE)
+ {
+ parse_on_alternatives ();
+ if (! ignoring && expand_exit_needed)
+ expand_exit_something ();
+ }
+ if (check_token (ELSE))
+ {
+ chill_start_default_handler ();
+ label = NULL_TREE;
+ parse_opt_actions ();
+ if (! ignoring)
+ {
+ emit_line_note (input_filename, lineno);
+ expand_exit_something ();
+ }
+ }
+ expect (END, "missing 'END' after");
+ if (! ignoring)
+ chill_finish_on ();
+ POP_USED_ON_CONTEXT;
+ return integer_zero_node;
+}
+
+static void
+parse_loc_declaration (in_spec_module)
+ int in_spec_module;
+{
+ tree names = parse_defining_occurrence_list ();
+ int save_ignoring = ignoring;
+ int is_static, lifetime_bound;
+ tree mode, init_value = NULL_TREE;
+ int loc_decl = 0;
+
+ ignoring = pass == 2;
+ mode = parse_mode ();
+ ignoring = save_ignoring;
+ is_static = check_token (STATIC);
+ if (check_token (BASED))
+ {
+ expect(LPRN, "BASED must be followed by (NAME)");
+ do_based_decls (names, mode, parse_name_string ());
+ expect(RPRN, "BASED must be followed by (NAME)");
+ return;
+ }
+ if (check_token (LOC))
+ {
+ /* loc-identity declaration */
+ if (pass == 1)
+ mode = build_chill_reference_type (mode);
+ loc_decl = 1;
+ }
+ lifetime_bound = check_token (INIT);
+ if (lifetime_bound && loc_decl)
+ {
+ if (pass == 1)
+ error ("INIT not allowed at loc-identity declaration");
+ lifetime_bound = 0;
+ }
+ if (PEEK_TOKEN () == ASGN || PEEK_TOKEN() == EQL)
+ {
+ save_ignoring = ignoring;
+ ignoring = pass == 1;
+ if (PEEK_TOKEN() == EQL)
+ {
+ if (pass == 1)
+ error ("'=' used where ':=' is required");
+ }
+ FORWARD_TOKEN();
+ if (! lifetime_bound)
+ push_handler ();
+ init_value = parse_untyped_expr ();
+ if (in_spec_module)
+ {
+ error ("initialization is not allowed in spec module");
+ init_value = NULL_TREE;
+ }
+ if (! lifetime_bound)
+ parse_opt_handler ();
+ ignoring = save_ignoring;
+ }
+ if (init_value == NULL_TREE && loc_decl && pass == 1)
+ error ("loc-identity declaration without initialisation");
+ do_decls (names, mode,
+ is_static || global_bindings_p ()
+ /* the variable becomes STATIC if all_static_flag is set and
+ current functions doesn't have the RECURSIVE attribute */
+ || (all_static_flag && !CH_DECL_RECURSIVE (current_function_decl)),
+ lifetime_bound, init_value, in_spec_module);
+
+ /* Free any temporaries we made while initializing the decl. */
+ free_temp_slots ();
+}
+
+static void
+parse_declaration_statement (in_spec_module)
+ int in_spec_module;
+{
+ int save_ignoring = ignoring;
+ ignoring = pass == 2;
+ require (DCL);
+ parse_loc_declaration (in_spec_module);
+ while (PEEK_TOKEN () == COMMA)
+ {
+ FORWARD_TOKEN ();
+ parse_loc_declaration (in_spec_module);
+ }
+ ignoring = save_ignoring;
+ parse_semi_colon ();
+}
+
+tree
+parse_optforbid ()
+{
+ if (check_token (FORBID) == 0)
+ return NULL_TREE;
+ if (check_token (ALL))
+ return ignoring ? NULL_TREE : build_int_2 (-1, -1);
+#if 0
+ if (check_token (LPRN))
+ {
+ tree list = parse_forbidlist ();
+ expect (RPRN, "missing ')' after FORBID list");
+ return list;
+ }
+#endif
+ error ("bad syntax following FORBID");
+ return NULL_TREE;
+}
+
+/* Matches: <grant postfix> or <seize postfix>
+ Returns: A (singleton) TREE_LIST. */
+
+tree
+parse_postfix (grant_or_seize)
+ enum terminal grant_or_seize;
+{
+ tree name = parse_opt_name_string (1);
+ tree forbid = NULL_TREE;
+ if (name == NULL_TREE)
+ {
+ error ("expected a postfix name here");
+ name = error_mark_node;
+ }
+ if (grant_or_seize == GRANT)
+ forbid = parse_optforbid ();
+ return build_tree_list (forbid, name);
+}
+
+tree
+parse_postfix_list (grant_or_seize)
+ enum terminal grant_or_seize;
+{
+ tree list = parse_postfix (grant_or_seize);
+ while (check_token (COMMA))
+ list = chainon (list, parse_postfix (grant_or_seize));
+ return list;
+}
+
+void
+parse_rename_clauses (grant_or_seize)
+ enum terminal grant_or_seize;
+{
+ for (;;)
+ {
+ tree rename_old_prefix, rename_new_prefix, postfix;
+ require (LPRN);
+ rename_old_prefix = parse_opt_name_string (0);
+ expect (ARROW, "missing '->' in rename clause");
+ rename_new_prefix = parse_opt_name_string (0);
+ expect (RPRN, "missing ')' in rename clause");
+ expect ('!', "missing '!' in rename clause");
+ postfix = parse_postfix (grant_or_seize);
+
+ if (grant_or_seize == GRANT)
+ chill_grant (rename_old_prefix, rename_new_prefix,
+ TREE_VALUE (postfix), TREE_PURPOSE (postfix));
+ else
+ chill_seize (rename_old_prefix, rename_new_prefix,
+ TREE_VALUE (postfix));
+
+ if (PEEK_TOKEN () != COMMA)
+ break;
+ FORWARD_TOKEN ();
+ if (PEEK_TOKEN () != LPRN)
+ {
+ error ("expected another rename clause");
+ break;
+ }
+ }
+}
+
+static tree
+parse_opt_prefix_clause ()
+{
+ if (check_token (PREFIXED) == 0)
+ return NULL_TREE;
+ return build_prefix_clause (parse_opt_name_string (0));
+}
+
+void
+parse_grant_statement ()
+{
+ require (GRANT);
+ if (PEEK_TOKEN () == LPRN)
+ parse_rename_clauses (GRANT);
+ else
+ {
+ tree window = parse_postfix_list (GRANT);
+ tree new_prefix = parse_opt_prefix_clause ();
+ tree t;
+ for (t = window; t; t = TREE_CHAIN (t))
+ chill_grant (NULL_TREE, new_prefix, TREE_VALUE (t), TREE_PURPOSE (t));
+ }
+}
+
+void
+parse_seize_statement ()
+{
+ require (SEIZE);
+ if (PEEK_TOKEN () == LPRN)
+ parse_rename_clauses (SEIZE);
+ else
+ {
+ tree seize_window = parse_postfix_list (SEIZE);
+ tree old_prefix = parse_opt_prefix_clause ();
+ tree t;
+ for (t = seize_window; t; t = TREE_CHAIN (t))
+ chill_seize (old_prefix, NULL_TREE, TREE_VALUE (t));
+ }
+}
+
+/* In pass 1, this returns a TREE_LIST, one node for each parameter.
+ In pass 2, we get a list of PARM_DECLs chained together.
+ In either case, the list is in reverse order. */
+
+static tree
+parse_param_name_list ()
+{
+ tree list = NULL_TREE;
+ do
+ {
+ tree new_link;
+ tree name = parse_defining_occurrence ();
+ if (name == NULL_TREE)
+ {
+ error ("syntax error in parameter name list");
+ return list;
+ }
+ if (pass == 1)
+ new_link = build_tree_list (NULL_TREE, name);
+ /* else if (current_module->is_spec_module) ; nothing */
+ else /* pass == 2 */
+ {
+ new_link = make_node (PARM_DECL);
+ DECL_NAME (new_link) = name;
+ DECL_ASSEMBLER_NAME (new_link) = name;
+ }
+
+ TREE_CHAIN (new_link) = list;
+ list = new_link;
+ } while (check_token (COMMA));
+ return list;
+}
+
+static tree
+parse_param_attr ()
+{
+ tree attr;
+ switch (PEEK_TOKEN ())
+ {
+ case PARAMATTR: /* INOUT is returned here */
+ attr = PEEK_TREE ();
+ FORWARD_TOKEN ();
+ return attr;
+ case IN:
+ FORWARD_TOKEN ();
+ return ridpointers[(int) RID_IN];
+ case LOC:
+ FORWARD_TOKEN ();
+ return ridpointers[(int) RID_LOC];
+#if 0
+ case DYNAMIC:
+ FORWARD_TOKEN ();
+ return ridpointers[(int) RID_DYNAMIC];
+#endif
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* We wrap CHILL array parameters in a STRUCT. The original parameter
+ name is unpacked from the struct at get_identifier time */
+
+/* In pass 1, returns list of types; in pass 2: chain of PARM_DECLs. */
+
+static tree
+parse_formpar (in_spec_module)
+ int in_spec_module;
+{
+ tree names = parse_param_name_list ();
+ tree mode = parse_mode ();
+ tree paramattr = parse_param_attr ();
+ return chill_munge_params (nreverse (names), mode, paramattr);
+}
+
+/*
+ * Note: build_process_header depends upon the *exact*
+ * representation of STRUCT fields and of formal parameter
+ * lists. If either is changed, build_process_header will
+ * also need change. Push_extern_process is affected as well.
+ */
+static tree
+parse_formparlist (in_spec_module)
+ int in_spec_module;
+{
+ tree list = NULL_TREE;
+ if (PEEK_TOKEN() == RPRN)
+ return NULL_TREE;
+ for (;;)
+ {
+ list = chainon (list, parse_formpar (in_spec_module));
+ if (! check_token (COMMA))
+ break;
+ }
+ return list;
+}
+
+static tree
+parse_opt_result_spec ()
+{
+ tree mode;
+ int is_nonref, is_loc, is_dynamic;
+ if (!check_token (RETURNS))
+ return void_type_node;
+ expect (LPRN, "expected '(' after RETURNS");
+ mode = parse_mode ();
+ is_nonref = check_token (NONREF);
+ is_loc = check_token (LOC);
+ is_dynamic = check_token (DYNAMIC);
+ if (is_nonref && !is_loc)
+ error ("NONREF specific without LOC in result attribute");
+ if (is_dynamic && !is_loc)
+ error ("DYNAMIC specific without LOC in result attribute");
+ mode = get_type_of (mode);
+ if (is_loc && ! ignoring)
+ mode = build_chill_reference_type (mode);
+ expect (RPRN, "expected ')' after RETURNS");
+ return mode;
+}
+
+static tree
+parse_opt_except ()
+{
+ tree list = NULL_TREE;
+ if (!check_token (EXCEPTIONS))
+ return NULL_TREE;
+ expect (LPRN, "expected '(' after EXCEPTIONS");
+ do
+ {
+ tree except_name = parse_name_string ();
+ tree name;
+ for (name = list; name != NULL_TREE; name = TREE_CHAIN (name))
+ if (TREE_VALUE (name) == except_name && pass == 1)
+ {
+ error ("exception names must be unique");
+ break;
+ }
+ if (name == NULL_TREE && !ignoring)
+ list = tree_cons (NULL_TREE, except_name, list);
+ } while (check_token (COMMA));
+ expect (RPRN, "expected ')' after EXCEPTIONS");
+ return list;
+}
+
+static tree
+parse_opt_recursive ()
+{
+ if (check_token (RECURSIVE))
+ return ridpointers[RID_RECURSIVE];
+ else
+ return NULL_TREE;
+}
+
+static tree
+parse_procedureattr ()
+{
+ tree generality;
+ tree optrecursive;
+ switch (PEEK_TOKEN ())
+ {
+ case GENERAL:
+ FORWARD_TOKEN ();
+ generality = ridpointers[RID_GENERAL];
+ break;
+ case SIMPLE:
+ FORWARD_TOKEN ();
+ generality = ridpointers[RID_SIMPLE];
+ break;
+ case INLINE:
+ FORWARD_TOKEN ();
+ generality = ridpointers[RID_INLINE];
+ break;
+ default:
+ generality = NULL_TREE;
+ }
+ optrecursive = parse_opt_recursive ();
+ if (pass != 1)
+ return NULL_TREE;
+ if (generality)
+ generality = build_tree_list (NULL_TREE, generality);
+ if (optrecursive)
+ generality = tree_cons (NULL_TREE, optrecursive, generality);
+ return generality;
+}
+
+/* Parse the body and last part of a procedure or process definition. */
+
+static void
+parse_proc_body (name, exceptions)
+ tree name;
+ tree exceptions;
+{
+ int save_proc_action_level = proc_action_level;
+ proc_action_level = action_nesting_level;
+ if (exceptions != NULL_TREE)
+ /* set up a handler for reraising exceptions */
+ push_handler ();
+ push_action ();
+ define__PROCNAME__ ();
+ parse_body ();
+ proc_action_level = save_proc_action_level;
+ expect (END, "'END' was expected here");
+ parse_opt_handler ();
+ if (exceptions != NULL_TREE)
+ chill_reraise_exceptions (exceptions);
+ parse_opt_end_label_semi_colon (name);
+ end_function ();
+}
+
+static void
+parse_procedure_definition (in_spec_module)
+ int in_spec_module;
+{
+ int save_ignoring = ignoring;
+ tree name = parse_defining_occurrence ();
+ tree params, result, exceptlist, attributes;
+ int save_chill_at_module_level = chill_at_module_level;
+ chill_at_module_level = 0;
+ if (!in_spec_module)
+ ignoring = pass == 2;
+ require (COLON); require (PROC);
+ expect (LPRN, "missing '(' after PROC");
+ params = parse_formparlist (in_spec_module);
+ expect (RPRN, "missing ')' in PROC");
+ result = parse_opt_result_spec ();
+ exceptlist = parse_opt_except ();
+ attributes = parse_procedureattr ();
+ ignoring = save_ignoring;
+ if (in_spec_module)
+ {
+ expect (END, "missing 'END'");
+ parse_opt_end_label_semi_colon (name);
+ push_extern_function (name, result, params, exceptlist, 0);
+ return;
+ }
+ push_chill_function_context ();
+ start_chill_function (name, result, params, exceptlist, attributes);
+ current_module->procedure_seen = 1;
+ parse_proc_body (name, TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
+ chill_at_module_level = save_chill_at_module_level;
+}
+
+static tree
+parse_processpar ()
+{
+ tree names = parse_defining_occurrence_list ();
+ tree mode = parse_mode ();
+ tree paramattr = parse_param_attr ();
+ tree parms = NULL_TREE;
+ if (names && TREE_CODE (names) == IDENTIFIER_NODE)
+ names = build_tree_list (NULL_TREE, names);
+ return tree_cons (tree_cons (paramattr, mode, NULL_TREE), names, NULL_TREE);
+}
+
+static tree
+parse_processparlist ()
+{
+ tree list = NULL_TREE;
+ if (PEEK_TOKEN() == RPRN)
+ return NULL_TREE;
+ for (;;)
+ {
+ list = chainon (list, parse_processpar ());
+ if (! check_token (COMMA))
+ break;
+ }
+ return list;
+}
+
+static void
+parse_process_definition (in_spec_module)
+ int in_spec_module;
+{
+ int save_ignoring = ignoring;
+ tree name = parse_defining_occurrence ();
+ tree params;
+ tree tmp;
+ if (!in_spec_module)
+ ignoring = 0;
+ require (COLON); require (PROCESS);
+ expect (LPRN, "missing '(' after PROCESS");
+ params = parse_processparlist (in_spec_module);
+ expect (RPRN, "missing ')' in PROCESS");
+ ignoring = save_ignoring;
+ if (in_spec_module)
+ {
+ expect (END, "missing 'END'");
+ parse_opt_end_label_semi_colon (name);
+ push_extern_process (name, params, NULL_TREE, 0);
+ return;
+ }
+ tmp = build_process_header (name, params);
+ parse_proc_body (name, NULL_TREE);
+ build_process_wrapper (name, tmp);
+}
+
+static void
+parse_signal_definition ()
+{
+ tree signame = parse_defining_occurrence ();
+ tree modes = NULL_TREE;
+ tree dest = NULL_TREE;
+
+ if (check_token (EQL))
+ {
+ expect (LPRN, "missing '(' after 'SIGNAL <name> ='");
+ for (;;)
+ {
+ tree mode = parse_mode ();
+ modes = tree_cons (NULL_TREE, mode, modes);
+ if (! check_token (COMMA))
+ break;
+ }
+ expect (RPRN, "missing ')'");
+ modes = nreverse (modes);
+ }
+
+ if (check_token (TO))
+ {
+ tree decl;
+ int save_ignoring = ignoring;
+ ignoring = 0;
+ decl = parse_name ();
+ ignoring = save_ignoring;
+ if (pass > 1)
+ {
+ if (decl == NULL_TREE
+ || TREE_CODE (decl) == ERROR_MARK
+ || TREE_CODE (decl) != FUNCTION_DECL
+ || !CH_DECL_PROCESS (decl))
+ error ("must specify a PROCESS name");
+ else
+ dest = decl;
+ }
+ }
+
+ if (! global_bindings_p ())
+ error ("SIGNAL must be in global reach");
+ else
+ {
+ tree struc = build_signal_struct_type (signame, modes, dest);
+ tree decl =
+ generate_tasking_code_variable (signame,
+ &signal_code,
+ current_module->is_spec_module);
+ /* remember the code variable in the struct type */
+ DECL_TASKING_CODE_DECL (struc) = (struct lang_decl *)decl;
+ CH_DECL_SIGNAL (struc) = 1;
+ add_taskstuff_to_list (decl, "_TT_Signal",
+ current_module->is_spec_module ?
+ NULL_TREE : signal_code, struc, NULL_TREE);
+ }
+
+}
+
+static void
+parse_signal_definition_statement ()
+{
+ int save_ignoring = ignoring;
+ ignoring = pass == 2;
+ require (SIGNAL);
+ for (;;)
+ {
+ parse_signal_definition ();
+ if (! check_token (COMMA))
+ break;
+ if (PEEK_TOKEN () == SC)
+ {
+ error ("syntax error while parsing signal definition statement");
+ break;
+ }
+ }
+ parse_semi_colon ();
+ ignoring = save_ignoring;
+}
+
+static int
+parse_definition (in_spec_module)
+ int in_spec_module;
+{
+ switch (PEEK_TOKEN ())
+ {
+ case NAME:
+ if (PEEK_TOKEN1() == COLON)
+ if (PEEK_TOKEN2() == PROC)
+ {
+ parse_procedure_definition (in_spec_module);
+ return 1;
+ }
+ else if (PEEK_TOKEN2() == PROCESS)
+ {
+ parse_process_definition (in_spec_module);
+ return 1;
+ }
+ return 0;
+ case DCL:
+ parse_declaration_statement(in_spec_module);
+ break;
+ case GRANT:
+ parse_grant_statement ();
+ break;
+ case NEWMODE:
+ parse_mode_definition_statement(1);
+ break;
+ case SC:
+ label = NULL_TREE;
+ FORWARD_TOKEN();
+ return 1;
+ case SEIZE:
+ parse_seize_statement ();
+ break;
+ case SIGNAL:
+ parse_signal_definition_statement ();
+ break;
+ case SYN:
+ parse_synonym_definition_statement();
+ break;
+ case SYNMODE:
+ parse_mode_definition_statement(0);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void
+parse_then_clause ()
+{
+ expect (THEN, "expected 'THEN' after 'IF'");
+ if (! ignoring)
+ emit_line_note (input_filename, lineno);
+ parse_opt_actions ();
+}
+
+static void
+parse_opt_else_clause ()
+{
+ while (check_token (ELSIF))
+ {
+ tree cond = parse_expression ();
+ if (! ignoring)
+ expand_start_elseif (truthvalue_conversion (cond));
+ parse_then_clause ();
+ }
+ if (check_token (ELSE))
+ {
+ if (! ignoring)
+ { emit_line_note (input_filename, lineno);
+ expand_start_else ();
+ }
+ parse_opt_actions ();
+ }
+}
+
+static tree parse_expr_list ()
+{
+ tree expr = parse_expression ();
+ tree list = ignoring ? NULL_TREE : build_tree_list (NULL_TREE, expr);
+ while (check_token (COMMA))
+ {
+ expr = parse_expression ();
+ if (! ignoring)
+ list = tree_cons (NULL_TREE, expr, list);
+ }
+ return list;
+}
+
+static tree
+parse_range_list_clause ()
+{
+ tree name = parse_opt_name_string (0);
+ if (name == NULL_TREE)
+ return NULL_TREE;
+ while (check_token (COMMA))
+ {
+ name = parse_name_string (0);
+ }
+ if (check_token (SC))
+ {
+ sorry ("case range list");
+ return error_mark_node;
+ }
+ pushback_token (NAME, name);
+ return NULL_TREE;
+}
+
+static void
+pushback_paren_expr (expr)
+ tree expr;
+{
+ if (pass == 1 && !ignoring)
+ expr = build1 (PAREN_EXPR, NULL_TREE, expr);
+ pushback_token (EXPR, expr);
+}
+
+/* Matches: <case label> */
+
+static tree
+parse_case_label ()
+{
+ tree expr;
+ if (check_token (ELSE))
+ return case_else_node;
+ /* Does this also handle the case of a mode name? FIXME */
+ expr = parse_expression ();
+ if (check_token (COLON))
+ {
+ tree max_expr = parse_expression ();
+ if (! ignoring)
+ expr = build (RANGE_EXPR, NULL_TREE, expr, max_expr);
+ }
+ return expr;
+}
+
+/* Parses: <case_label_list>
+ Fails if not followed by COMMA or COLON.
+ If it fails, it backs up if needed, and returns NULL_TREE.
+ IN_TUPLE is true if we are parsing a tuple element,
+ and 0 if we are parsing a case label specification. */
+
+static tree
+parse_case_label_list (selector, in_tuple)
+ tree selector;
+ int in_tuple;
+{
+ tree expr, list;
+ if (! check_token (LPRN))
+ return NULL_TREE;
+ if (check_token (MUL))
+ {
+ expect (RPRN, "missing ')' after '*' case label list");
+ if (ignoring)
+ return integer_zero_node;
+ expr = build (RANGE_EXPR, NULL_TREE, NULL_TREE, NULL_TREE);
+ expr = build_tree_list (NULL_TREE, expr);
+ return expr;
+ }
+ expr = parse_case_label ();
+ if (check_token (RPRN))
+ {
+ if ((in_tuple || PEEK_TOKEN () != COMMA) && PEEK_TOKEN () != COLON)
+ {
+ /* Ooops! It looks like it was the start of an action or
+ unlabelled tuple element, and not a case label, so back up. */
+ if (expr != NULL_TREE && TREE_CODE (expr) == RANGE_EXPR)
+ {
+ error ("misplaced colon in case label");
+ expr = error_mark_node;
+ }
+ pushback_paren_expr (expr);
+ return NULL_TREE;
+ }
+ list = build_tree_list (NULL_TREE, expr);
+ if (expr == case_else_node && selector != NULL_TREE)
+ ELSE_LABEL_SPECIFIED (selector) = 1;
+ return list;
+ }
+ list = build_tree_list (NULL_TREE, expr);
+ if (expr == case_else_node && selector != NULL_TREE)
+ ELSE_LABEL_SPECIFIED (selector) = 1;
+
+ while (check_token (COMMA))
+ {
+ expr = parse_case_label ();
+ list = tree_cons (NULL_TREE, expr, list);
+ if (expr == case_else_node && selector != NULL_TREE)
+ ELSE_LABEL_SPECIFIED (selector) = 1;
+ }
+ expect (RPRN, "missing ')' at end of case label list");
+ return nreverse (list);
+}
+
+/* Parses: <case_label_specification>
+ Must be followed by a COLON.
+ If it fails, it backs up if needed, and returns NULL_TREE. */
+
+static tree
+parse_case_label_specification (selectors)
+ tree selectors;
+{
+ tree list_list = NULL_TREE;
+ tree list;
+ list = parse_case_label_list (selectors, 0);
+ if (list == NULL_TREE)
+ return NULL_TREE;
+ list_list = build_tree_list (NULL_TREE, list);
+ while (check_token (COMMA))
+ {
+ if (selectors != NULL_TREE)
+ selectors = TREE_CHAIN (selectors);
+ list = parse_case_label_list (selectors, 0);
+ if (list == NULL_TREE)
+ {
+ error ("unrecognized case label list after ','");
+ return list_list;
+ }
+ list_list = tree_cons (NULL_TREE, list, list_list);
+ }
+ return nreverse (list_list);
+}
+
+static void
+parse_single_dimension_case_action (selector)
+ tree selector;
+{
+ int no_completeness_check = 0;
+
+/* The case label/action toggle. It is 0 initially, and when an action
+ was last seen. It is 1 integer_zero_node when a label was last seen. */
+ int caseaction_flag = 0;
+
+ if (! ignoring)
+ {
+ expand_exit_needed = 0;
+ selector = check_case_selector (selector);
+ expand_start_case (1, selector, TREE_TYPE (selector), "CASE statement");
+ push_momentary ();
+ }
+
+ for (;;)
+ {
+ tree label_spec = parse_case_label_specification (selector);
+ if (label_spec != NULL_TREE)
+ {
+ expect (COLON, "missing ':' in case alternative");
+ if (! ignoring)
+ {
+ no_completeness_check |= chill_handle_single_dimension_case_label (
+ selector, label_spec, &expand_exit_needed, &caseaction_flag);
+ }
+ }
+ else if (parse_action ())
+ {
+ expand_exit_needed = 1;
+ caseaction_flag = 0;
+ }
+ else
+ break;
+ }
+
+ if (! ignoring)
+ {
+ if (expand_exit_needed || caseaction_flag == 1)
+ expand_exit_something ();
+ }
+ if (check_token (ELSE))
+ {
+ if (! ignoring)
+ chill_handle_case_default ();
+ parse_opt_actions ();
+ if (! ignoring)
+ {
+ emit_line_note (input_filename, lineno);
+ expand_exit_something ();
+ }
+ }
+ else if (! ignoring && TREE_CODE (selector) != ERROR_MARK &&
+ ! no_completeness_check)
+ check_missing_cases (TREE_TYPE (selector));
+
+ expect (ESAC, "missing 'ESAC' after 'CASE'");
+ if (! ignoring)
+ {
+ expand_end_case (selector);
+ pop_momentary ();
+ }
+}
+
+static void
+parse_multi_dimension_case_action (selector)
+ tree selector;
+{
+ struct rtx_def *begin_test_label, *end_case_label, *new_label;
+ tree action_labels = NULL_TREE;
+ tree tests = NULL_TREE;
+ tree new_test;
+ int save_lineno = lineno;
+ char *save_filename = input_filename;
+
+ /* We can't compute the range of an (ELSE) label until all of the CASE
+ label specifications have been seen, however, the code for the actions
+ between them is generated on the fly. We can still generate everything in
+ one pass is we use the following form:
+
+ Compile a CASE of the form
+
+ case S1,...,Sn of
+ (X11),...,(X1n): A1;
+ ...
+ (Xm1),...,(Xmn): Am;
+ else Ae;
+ esac;
+
+ into:
+
+ goto L0;
+ L1: A1; goto L99;
+ ...
+ Lm: Am; goto L99;
+ Le: Ae; goto L99;
+ L0:
+ T1 := s1; ...; Tn := Sn;
+ if (T1 = X11 and ... and Tn = X1n) GOTO L1;
+ ...
+ if (T1 = Xm1 and ... and Tn = Xmn) GOTO Lm;
+ GOTO Le;
+ L99;
+ */
+
+ if (! ignoring)
+ {
+ selector = check_case_selector_list (selector);
+ begin_test_label = gen_label_rtx ();
+ end_case_label = gen_label_rtx ();
+ emit_jump (begin_test_label);
+ }
+
+ for (;;)
+ {
+ tree label_spec = parse_case_label_specification (selector);
+ if (label_spec != NULL_TREE)
+ {
+ expect (COLON, "missing ':' in case alternative");
+ if (! ignoring)
+ {
+ tests = tree_cons (label_spec, NULL_TREE, tests);
+
+ if (action_labels != NULL_TREE)
+ emit_jump (end_case_label);
+
+ new_label = gen_label_rtx ();
+ emit_label (new_label);
+ emit_line_note (input_filename, lineno);
+ action_labels = tree_cons (NULL_TREE, NULL_TREE, action_labels);
+ TREE_CST_RTL (action_labels) = new_label;
+ }
+ }
+ else if (! parse_action ())
+ {
+ if (action_labels != NULL_TREE)
+ emit_jump (end_case_label);
+ break;
+ }
+ }
+
+ if (check_token (ELSE))
+ {
+ if (! ignoring)
+ {
+ new_label = gen_label_rtx ();
+ emit_label (new_label);
+ emit_line_note (input_filename, lineno);
+ action_labels = tree_cons (NULL_TREE, NULL_TREE, action_labels);
+ TREE_CST_RTL (action_labels) = new_label;
+ }
+ parse_opt_actions ();
+ if (! ignoring)
+ emit_jump (end_case_label);
+ }
+
+ expect (ESAC, "missing 'ESAC' after 'CASE'");
+
+ if (! ignoring)
+ {
+ emit_label (begin_test_label);
+ emit_line_note (save_filename, save_lineno);
+ if (tests != NULL_TREE)
+ {
+ tree cond;
+ tests = nreverse (tests);
+ action_labels = nreverse (action_labels);
+ compute_else_ranges (selector, tests);
+
+ cond = build_multi_case_selector_expression (selector, TREE_PURPOSE (tests));
+ expand_start_cond (truthvalue_conversion (cond), label ? 1 : 0);
+ emit_jump (TREE_CST_RTL (action_labels));
+
+ for (tests = TREE_CHAIN (tests), action_labels = TREE_CHAIN (action_labels);
+ tests != NULL_TREE && action_labels != NULL_TREE;
+ tests = TREE_CHAIN (tests), action_labels = TREE_CHAIN (action_labels))
+ {
+ cond =
+ build_multi_case_selector_expression (selector, TREE_PURPOSE (tests));
+ expand_start_elseif (truthvalue_conversion (cond));
+ emit_jump (TREE_CST_RTL (action_labels));
+ }
+ if (action_labels != NULL_TREE)
+ {
+ expand_start_else ();
+ emit_jump (TREE_CST_RTL (action_labels));
+ }
+ expand_end_cond ();
+ }
+ emit_label (end_case_label);
+ }
+}
+
+static void
+parse_case_action (label)
+ tree label;
+{
+ tree selector;
+ int multi_dimension_case = 0;
+
+/* The case label/action toggle. It is 0 initially, and when an action
+ was last seen. It is 1 integer_zero_node when a label was last seen. */
+ int caseaction_flag = 0;
+
+ require (CASE);
+ selector = parse_expr_list ();
+ selector = nreverse (selector);
+ expect (OF, "missing 'OF' after 'CASE'");
+ parse_range_list_clause ();
+
+ PUSH_ACTION;
+ if (label)
+ pushlevel (1);
+
+ if (! ignoring)
+ {
+ expand_exit_needed = 0;
+ if (TREE_CODE (selector) == TREE_LIST)
+ {
+ if (TREE_CHAIN (selector) != NULL_TREE)
+ multi_dimension_case = 1;
+ else
+ selector = TREE_VALUE (selector);
+ }
+ }
+
+ /* We want to use the regular CASE support for the single dimension case. The
+ multi dimension case requires different handling. Note that when "ignoring"
+ is true we parse using the single dimension code. This is OK since it will
+ still parse correctly. */
+ if (multi_dimension_case)
+ parse_multi_dimension_case_action (selector);
+ else
+ parse_single_dimension_case_action (selector);
+
+ if (label)
+ {
+ possibly_define_exit_label (label);
+ poplevel (0, 0, 0);
+ }
+}
+
+/* Matches: [ <asm_operand> { "," <asm_operand> }* ],
+ where <asm_operand> = STRING '(' <expression> ')'
+ These are the operands other than the first string and colon
+ in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */
+
+static tree
+parse_asm_operands ()
+{
+ tree list = NULL_TREE;
+ if (PEEK_TOKEN () != STRING)
+ return NULL_TREE;
+ for (;;)
+ {
+ tree string, expr;
+ if (PEEK_TOKEN () != STRING)
+ {
+ error ("bad ASM operand");
+ return list;
+ }
+ string = PEEK_TREE();
+ FORWARD_TOKEN ();
+ expect (LPRN, "missing '(' in ASM operand");
+ expr = parse_expression ();
+ expect (RPRN, "missing ')' in ASM operand");
+ list = tree_cons (string, expr, list);
+ if (! check_token (COMMA))
+ break;
+ }
+ return nreverse (list);
+}
+
+/* Matches: STRING { ',' STRING }* */
+
+static tree
+parse_asm_clobbers ()
+{
+ tree list = NULL_TREE;
+ for (;;)
+ {
+ tree string, expr;
+ if (PEEK_TOKEN () != STRING)
+ {
+ error ("bad ASM operand");
+ return list;
+ }
+ string = PEEK_TREE();
+ FORWARD_TOKEN ();
+ list = tree_cons (NULL_TREE, string, list);
+ if (! check_token (COMMA))
+ break;
+ }
+ return list;
+}
+
+void
+ch_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
+ tree string, outputs, inputs, clobbers;
+ int vol;
+ char *filename;
+ int line;
+{
+ int noutputs = list_length (outputs);
+ register int i;
+ /* o[I] is the place that output number I should be written. */
+ register tree *o = (tree *) alloca (noutputs * sizeof (tree));
+ register tree tail;
+
+ if (TREE_CODE (string) == ADDR_EXPR)
+ string = TREE_OPERAND (string, 0);
+ if (TREE_CODE (string) != STRING_CST)
+ {
+ error ("asm template is not a string constant");
+ return;
+ }
+
+ /* Record the contents of OUTPUTS before it is modified. */
+ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+ o[i] = TREE_VALUE (tail);
+
+#if 0
+ /* Perform default conversions on array and function inputs. */
+ /* Don't do this for other types--
+ it would screw up operands expected to be in memory. */
+ for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++)
+ if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE)
+ TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
+#endif
+
+ /* Generate the ASM_OPERANDS insn;
+ store into the TREE_VALUEs of OUTPUTS some trees for
+ where the values were actually stored. */
+ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line);
+
+ /* Copy all the intermediate outputs into the specified outputs. */
+ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+ {
+ if (o[i] != TREE_VALUE (tail))
+ {
+ expand_expr (build_chill_modify_expr (o[i], TREE_VALUE (tail)),
+ 0, VOIDmode, 0);
+ free_temp_slots ();
+ }
+ /* Detect modification of read-only values.
+ (Otherwise done by build_modify_expr.) */
+ else
+ {
+ tree type = TREE_TYPE (o[i]);
+ if (TYPE_READONLY (type)
+ || ((TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ && TYPE_FIELDS_READONLY (type)))
+ warning ("readonly location modified by 'asm'");
+ }
+ }
+
+ /* Those MODIFY_EXPRs could do autoincrements. */
+ emit_queue ();
+}
+
+static void
+parse_asm_action ()
+{
+ tree insn;
+ require (ASM_KEYWORD);
+ expect (LPRN, "missing '('");
+ PUSH_ACTION;
+ if (!ignoring)
+ emit_line_note (input_filename, lineno);
+ insn = parse_expression ();
+ if (check_token (COLON))
+ {
+ tree output_operand, input_operand, clobbered_regs;
+ output_operand = parse_asm_operands ();
+ if (check_token (COLON))
+ input_operand = parse_asm_operands ();
+ else
+ input_operand = NULL_TREE;
+ if (check_token (COLON))
+ clobbered_regs = parse_asm_clobbers ();
+ else
+ clobbered_regs = NULL_TREE;
+ expect (RPRN, "missing ')'");
+ if (!ignoring)
+ ch_expand_asm_operands (insn, output_operand, input_operand,
+ clobbered_regs, FALSE,
+ input_filename, lineno);
+ }
+ else
+ {
+ expect (RPRN, "missing ')'");
+ STRIP_NOPS (insn);
+ if (ignoring) { }
+ else if ((TREE_CODE (insn) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (insn, 0)) == STRING_CST)
+ || TREE_CODE (insn) == STRING_CST)
+ expand_asm (insn);
+ else
+ error ("argument of `asm' is not a constant string");
+ }
+}
+
+static void
+parse_begin_end_block (label)
+ tree label;
+{
+ require (BEGINTOKEN);
+#if 0
+ /* don't make a linenote at BEGIN */
+ INIT_ACTION;
+#endif
+ pushlevel (1);
+ if (! ignoring)
+ {
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (label ? 1 : 0);
+ }
+ push_handler ();
+ parse_body ();
+ expect (END, "missing 'END'");
+ /* Note that the opthandler comes before the poplevel
+ - hence a handler is in the scope of the block. */
+ parse_opt_handler ();
+ possibly_define_exit_label (label);
+ if (! ignoring)
+ {
+ emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ }
+ poplevel (kept_level_p (), 0, 0);
+ if (! ignoring)
+ pop_momentary ();
+ parse_opt_end_label_semi_colon (label);
+}
+
+static void
+parse_if_action (label)
+ tree label;
+{
+ tree cond;
+ require (IF);
+ PUSH_ACTION;
+ cond = parse_expression ();
+ if (label)
+ pushlevel (1);
+ if (! ignoring)
+ {
+ expand_start_cond (truthvalue_conversion (cond),
+ label ? 1 : 0);
+ }
+ parse_then_clause ();
+ parse_opt_else_clause ();
+ expect (FI, "expected 'FI' after 'IF'");
+ if (! ignoring)
+ {
+ emit_line_note (input_filename, lineno);
+ expand_end_cond ();
+ }
+ if (label)
+ {
+ possibly_define_exit_label (label);
+ poplevel (0, 0, 0);
+ }
+}
+
+/* Matches: <iteration> (as in a <for control>). */
+
+static void
+parse_iteration ()
+{
+ tree loop_counter = parse_defining_occurrence ();
+ if (check_token (ASGN))
+ {
+ tree start_value = parse_expression ();
+ tree step_value
+ = check_token (BY) ? parse_expression () : NULL_TREE;
+ int going_down = check_token (DOWN);
+ tree end_value;
+ if (check_token (TO))
+ end_value = parse_expression ();
+ else
+ {
+ error ("expected 'TO' in step enumeration");
+ end_value = error_mark_node;
+ }
+ if (!ignoring)
+ build_loop_iterator (loop_counter, start_value, step_value,
+ end_value, going_down, 0, 0);
+ }
+ else
+ {
+ int going_down = check_token (DOWN);
+ tree expr;
+ if (check_token (IN))
+ expr = parse_expression ();
+ else
+ {
+ error ("expected 'IN' in FOR control here");
+ expr = error_mark_node;
+ }
+ if (!ignoring)
+ {
+ tree low_bound, high_bound;
+ if (expr && TREE_CODE (expr) == TYPE_DECL)
+ {
+ expr = TREE_TYPE (expr);
+ /* FIXME: expr must be an array or powerset */
+ low_bound = convert (expr, TYPE_MIN_VALUE (expr));
+ high_bound = convert (expr, TYPE_MAX_VALUE (expr));
+ }
+ else
+ {
+ low_bound = expr;
+ high_bound = NULL_TREE;
+ }
+ build_loop_iterator (loop_counter, low_bound,
+ NULL_TREE, high_bound,
+ going_down, 1, 0);
+ }
+ }
+}
+
+/* Matches: '(' <event list> ')' ':'.
+ Or; returns NULL_EXPR. */
+
+static tree
+parse_delay_case_event_list ()
+{
+ tree event_list = NULL_TREE;
+ tree event;
+ if (! check_token (LPRN))
+ return NULL_TREE;
+ event = parse_expression ();
+ if (PEEK_TOKEN () == ')' && PEEK_TOKEN1 () != ':')
+ {
+ /* Oops. */
+ require (RPRN);
+ pushback_paren_expr (event);
+ return NULL_TREE;
+ }
+ for (;;)
+ {
+ if (! ignoring)
+ event_list = tree_cons (NULL_TREE, event, event_list);
+ if (! check_token (COMMA))
+ break;
+ event = parse_expression ();
+ }
+ expect (RPRN, "missing ')'");
+ expect (COLON, "missing ':'");
+ return ignoring ? error_mark_node : event_list;
+}
+
+static void
+parse_delay_case_action (label)
+ tree label;
+{
+ tree label_cnt, set_location, priority;
+ tree combined_event_list = NULL_TREE;
+ require (DELAY);
+ require (CASE);
+ PUSH_ACTION;
+ pushlevel (1);
+ expand_exit_needed = 0;
+ if (check_token (SET))
+ {
+ set_location = parse_expression ();
+ parse_semi_colon ();
+ }
+ else
+ set_location = NULL_TREE;
+ if (check_token (PRIORITY))
+ {
+ priority = parse_expression ();
+ parse_semi_colon ();
+ }
+ else
+ priority = NULL_TREE;
+ if (! ignoring)
+ label_cnt = build_delay_case_start (set_location, priority);
+ for (;;)
+ {
+ tree event_list = parse_delay_case_event_list ();
+ if (event_list)
+ {
+ if (! ignoring )
+ {
+ int if_or_elseif = combined_event_list == NULL_TREE;
+ build_delay_case_label (event_list, if_or_elseif);
+ combined_event_list = chainon (combined_event_list, event_list);
+ }
+ }
+ else if (parse_action ())
+ {
+ if (! ignoring)
+ {
+ expand_exit_needed = 1;
+ if (combined_event_list == NULL_TREE)
+ error ("missing DELAY CASE alternative");
+ }
+ }
+ else
+ break;
+ }
+ expect (ESAC, "missing 'ESAC' in DELAY CASE'");
+ if (! ignoring)
+ build_delay_case_end (label_cnt, combined_event_list);
+ possibly_define_exit_label (label);
+ poplevel (0, 0, 0);
+}
+
+static void
+parse_do_action (label)
+ tree label;
+{
+ tree condition;
+ int token;
+ require (DO);
+ if (check_token (WITH))
+ {
+ tree list = NULL_TREE;
+ for (;;)
+ {
+ tree name = parse_primval ();
+ if (! ignoring && TREE_CODE (name) != ERROR_MARK)
+ {
+ if (TREE_CODE (TREE_TYPE (name)) == REFERENCE_TYPE)
+ name = convert (TREE_TYPE (TREE_TYPE (name)), name);
+ else
+ {
+ int is_loc = chill_location (name);
+ if (is_loc == 1) /* This is probably not possible */
+ warning ("non-referable location in DO WITH");
+
+ if (is_loc > 1)
+ name = build_chill_arrow_expr (name, 1);
+ name = decl_temp1 (get_identifier ("__with_element"),
+ TREE_TYPE (name),
+ 0, name, 0, 0);
+ if (is_loc > 1)
+ name = build_chill_indirect_ref (name, NULL_TREE, 0);
+
+ }
+ if (TREE_CODE (TREE_TYPE (name)) != RECORD_TYPE)
+ error ("WITH element must be of STRUCT mode");
+ else
+ list = tree_cons (NULL_TREE, name, list);
+ }
+ if (! check_token (COMMA))
+ break;
+ }
+ pushlevel (1);
+ push_action ();
+ for (list = nreverse (list); list != NULL_TREE; list = TREE_CHAIN (list))
+ shadow_record_fields (TREE_VALUE (list));
+
+ parse_semi_colon ();
+ parse_opt_actions ();
+ expect (OD, "missing 'OD' in 'DO WITH'");
+ if (! ignoring)
+ emit_line_note (input_filename, lineno);
+ possibly_define_exit_label (label);
+ parse_opt_handler ();
+ parse_opt_end_label_semi_colon (label);
+ poplevel (0, 0, 0);
+ return;
+ }
+ token = PEEK_TOKEN();
+ if (token != FOR && token != WHILE)
+ {
+ push_handler ();
+ parse_opt_actions ();
+ expect (OD, "Missing 'OD' after 'DO'");
+ parse_opt_handler ();
+ parse_opt_end_label_semi_colon (label);
+ return;
+ }
+ if (! ignoring)
+ emit_line_note (input_filename, lineno);
+ push_loop_block ();
+ if (check_token (FOR))
+ {
+ if (check_token (EVER))
+ {
+ if (!ignoring)
+ build_loop_iterator (NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE,
+ 0, 0, 1);
+ }
+ else
+ {
+ parse_iteration ();
+ while (check_token (COMMA))
+ parse_iteration ();
+ }
+ }
+ else if (!ignoring)
+ build_loop_iterator (NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE,
+ 0, 0, 1);
+
+ begin_loop_scope ();
+ if (! ignoring)
+ build_loop_start (label);
+ condition = check_token (WHILE) ? parse_expression () : NULL_TREE;
+ if (! ignoring)
+ top_loop_end_check (condition);
+ parse_semi_colon ();
+ parse_opt_actions ();
+ if (! ignoring)
+ build_loop_end ();
+ expect (OD, "Missing 'OD' after 'DO'");
+ /* Note that the handler is inside the reach of the DO. */
+ parse_opt_handler ();
+ end_loop_scope (label);
+ pop_loop_block ();
+ parse_opt_end_label_semi_colon (label);
+}
+
+/* Matches: '(' <signal name> [ 'IN' <defining occurrence list> ']' ')' ':'
+ or: '(' <buffer location> IN (defining occurrence> ')' ':'
+ or: returns NULL_TREE. */
+
+static tree
+parse_receive_spec ()
+{
+ tree val;
+ tree name_list = NULL_TREE;
+ if (!check_token (LPRN))
+ return NULL_TREE;
+ val = parse_primval ();
+ if (check_token (IN))
+ {
+#if 0
+ if (flag_local_loop_counter)
+ name_list = parse_defining_occurrence_list ();
+ else
+#endif
+ {
+ for (;;)
+ {
+ tree loc = parse_primval ();
+ if (! ignoring)
+ name_list = tree_cons (NULL_TREE, loc, name_list);
+ if (! check_token (COMMA))
+ break;
+ }
+ }
+ }
+ if (! check_token (RPRN))
+ {
+ error ("missing ')' in signal/buffer receive alternative");
+ return NULL_TREE;
+ }
+ if (check_token (COLON))
+ {
+ if (ignoring || val == NULL_TREE || TREE_CODE (val) == ERROR_MARK)
+ return error_mark_node;
+ else
+ return build_receive_case_label (val, name_list);
+ }
+
+ /* We saw: '(' <primitive value> ')' not followed by ':'.
+ Presumably the start of an action. Backup and fail. */
+ if (name_list != NULL_TREE)
+ error ("misplaced 'IN' in signal/buffer receive alternative");
+ pushback_paren_expr (val);
+ return NULL_TREE;
+}
+
+/* To understand the code generation for this, see ch-tasking.c,
+ and the 2-page comments preceding the
+ build_chill_receive_case_start () definition. */
+
+static void
+parse_receive_case_action (label)
+ tree label;
+{
+ tree instance_location;
+ tree have_else_actions;
+ int spec_seen = 0;
+ tree alt_list = NULL_TREE;
+ require (RECEIVE);
+ require (CASE);
+ push_action ();
+ pushlevel (1);
+ if (! ignoring)
+ {
+ expand_exit_needed = 0;
+ }
+
+ if (check_token (SET))
+ {
+ instance_location = parse_expression ();
+ parse_semi_colon ();
+ }
+ else
+ instance_location = NULL_TREE;
+ if (! ignoring)
+ instance_location = build_receive_case_start (instance_location);
+
+ for (;;)
+ {
+ tree receive_spec = parse_receive_spec ();
+ if (receive_spec)
+ {
+ if (! ignoring)
+ alt_list = tree_cons (NULL_TREE, receive_spec, alt_list);
+ spec_seen++;
+ }
+ else if (parse_action ())
+ {
+ if (! spec_seen && pass == 1)
+ error ("missing RECEIVE alternative");
+ if (! ignoring)
+ expand_exit_needed = 1;
+ spec_seen = 1;
+ }
+ else
+ break;
+ }
+ if (check_token (ELSE))
+ {
+ if (! ignoring)
+ {
+ emit_line_note (input_filename, lineno);
+ if (build_receive_case_if_generated ())
+ expand_start_else ();
+ }
+ parse_opt_actions ();
+ have_else_actions = integer_one_node;
+ }
+ else
+ have_else_actions = integer_zero_node;
+ expect (ESAC, "missing 'ESAC' matching 'RECEIVE CASE'");
+ if (! ignoring)
+ {
+ build_receive_case_end (instance_location, nreverse (alt_list),
+ have_else_actions);
+ }
+ possibly_define_exit_label (label);
+ poplevel (0, 0, 0);
+}
+
+static void
+parse_send_action ()
+{
+ tree signal = NULL_TREE;
+ tree buffer = NULL_TREE;
+ tree value_list;
+ tree with_expr, to_expr, priority;
+ require (SEND);
+ /* The tricky part is distinguishing between a SEND buffer action,
+ and a SEND signal action. */
+ if (pass != 2 || PEEK_TOKEN () != NAME)
+ {
+ /* If this is pass 2, it's a SEND buffer action.
+ If it's pass 1, we don't care. */
+ buffer = parse_primval ();
+ }
+ else
+ {
+ /* We have to specifically check for signalname followed by
+ a '(', since we allow a signalname to be used (syntactically)
+ as a "function". */
+ tree name = parse_name ();
+ if (TREE_CODE (name) == TYPE_DECL && CH_DECL_SIGNAL (name))
+ signal = name; /* It's a SEND signal action! */
+ else
+ {
+ /* It's not a legal SEND signal action.
+ Back up and try as a SEND buffer action. */
+ pushback_token (EXPR, name);
+ buffer = parse_primval ();
+ }
+ }
+ if (check_token (LPRN))
+ {
+ value_list = NULL_TREE;
+ for (;;)
+ {
+ tree expr = parse_untyped_expr ();
+ if (! ignoring)
+ value_list = tree_cons (NULL_TREE, expr, value_list);
+ if (! check_token (COMMA))
+ break;
+ }
+ value_list = nreverse (value_list);
+ expect (RPRN, "missing ')'");
+ }
+ else
+ value_list = NULL_TREE;
+ if (check_token (WITH))
+ with_expr = parse_expression ();
+ else
+ with_expr = NULL_TREE;
+ if (check_token (TO))
+ to_expr = parse_expression ();
+ else
+ to_expr = NULL_TREE;
+ if (check_token (PRIORITY))
+ priority = parse_expression ();
+ else
+ priority = NULL_TREE;
+ PUSH_ACTION;
+ if (ignoring)
+ return;
+
+ if (signal)
+ { /* It's a <send signal action>! */
+ tree sigdesc = build_signal_descriptor (signal, value_list);
+ if (sigdesc != NULL_TREE && TREE_CODE (sigdesc) != ERROR_MARK)
+ {
+ tree sendto = to_expr ? to_expr : IDENTIFIER_SIGNAL_DEST (signal);
+ expand_send_signal (sigdesc, with_expr,
+ sendto, priority, DECL_NAME (signal));
+ }
+ }
+ else
+ {
+ /* all checks are done in expand_send_buffer */
+ expand_send_buffer (buffer, value_list, priority, with_expr, to_expr);
+ }
+}
+
+static void
+parse_start_action ()
+{
+ tree name, copy_number, param_list, startset;
+ require (START);
+ name = parse_name_string ();
+ expect (LPRN, "missing '(' in START action");
+ PUSH_ACTION;
+ /* copy number is a required parameter */
+ copy_number = parse_expression ();
+ if (!ignoring
+ && (copy_number == NULL_TREE
+ || TREE_CODE (copy_number) == ERROR_MARK
+ || TREE_CODE (TREE_TYPE (copy_number)) != INTEGER_TYPE))
+ {
+ error ("PROCESS copy number must be integer");
+ copy_number = integer_zero_node;
+ }
+ if (check_token (COMMA))
+ param_list = parse_expr_list (); /* user parameters */
+ else
+ param_list = NULL_TREE;
+ expect (RPRN, "missing ')'");
+ startset = check_token (SET) ? parse_primval () : NULL;
+ build_start_process (name, copy_number, param_list, startset);
+}
+
+static void
+parse_opt_actions ()
+{
+ while (parse_action ()) ;
+}
+
+int
+parse_action ()
+{
+ tree label = NULL_TREE;
+ tree expr, rhs, loclist;
+ enum tree_code op;
+
+ if (current_function_decl == global_function_decl
+ && PEEK_TOKEN () != SC
+ && PEEK_TOKEN () != END)
+ seen_action = 1, build_constructor = 1;
+
+ if (PEEK_TOKEN () == NAME && PEEK_TOKEN1 () == COLON)
+ {
+ label = parse_defining_occurrence ();
+ require (COLON);
+ INIT_ACTION;
+ define_label (input_filename, lineno, label);
+ }
+
+ switch (PEEK_TOKEN ())
+ {
+ case AFTER:
+ {
+ int delay;
+ require (AFTER);
+ expr = parse_primval ();
+ delay = check_token (DELAY);
+ expect (IN, "missing 'IN'");
+ push_action ();
+ pushlevel (1);
+ build_after_start (expr, delay);
+ parse_opt_actions ();
+ expect (TIMEOUT, "missing 'TIMEOUT'");
+ build_after_timeout_start ();
+ parse_opt_actions ();
+ expect (END, "missing 'END'");
+ build_after_end ();
+ possibly_define_exit_label (label);
+ poplevel (0, 0, 0);
+ }
+ goto bracketed_action;
+ case ASM_KEYWORD:
+ parse_asm_action ();
+ goto no_handler_action;
+ case ASSERT:
+ require (ASSERT);
+ PUSH_ACTION;
+ expr = parse_expression ();
+ if (! ignoring)
+ { tree assertfail = ridpointers[(int) RID_ASSERTFAIL];
+ expr = build (TRUTH_ORIF_EXPR, void_type_node, expr,
+ build_cause_exception (assertfail, 0));
+ expand_expr_stmt (fold (expr));
+ }
+ goto handler_action;
+ case AT:
+ require (AT);
+ PUSH_ACTION;
+ expr = parse_primval ();
+ expect (IN, "missing 'IN'");
+ pushlevel (1);
+ if (! ignoring)
+ build_at_action (expr);
+ parse_opt_actions ();
+ expect (TIMEOUT, "missing 'TIMEOUT'");
+ if (! ignoring)
+ expand_start_else ();
+ parse_opt_actions ();
+ expect (END, "missing 'END'");
+ if (! ignoring)
+ expand_end_cond ();
+ possibly_define_exit_label (label);
+ poplevel (0, 0, 0);
+ goto bracketed_action;
+ case BEGINTOKEN:
+ parse_begin_end_block (label);
+ return 1;
+ case CASE:
+ parse_case_action (label);
+ goto bracketed_action;
+ case CAUSE:
+ require (CAUSE);
+ expr = parse_name_string ();
+ PUSH_ACTION;
+ if (! ignoring && TREE_CODE (expr) != ERROR_MARK)
+ expand_cause_exception (expr);
+ goto no_handler_action;
+ case CONTINUE:
+ require (CONTINUE);
+ expr = parse_expression ();
+ PUSH_ACTION;
+ if (! ignoring)
+ expand_continue_event (expr);
+ goto handler_action;
+ case CYCLE:
+ require (CYCLE);
+ PUSH_ACTION;
+ expr = parse_primval ();
+ expect (IN, "missing 'IN' after 'CYCLE'");
+ pushlevel (1);
+ /* We a tree list where TREE_VALUE is the label
+ and TREE_PURPOSE is the variable denotes the timeout id. */
+ expr = build_cycle_start (expr);
+ parse_opt_actions ();
+ expect (END, "missing 'END'");
+ if (! ignoring)
+ build_cycle_end (expr);
+ possibly_define_exit_label (label);
+ poplevel (0, 0, 0);
+ goto bracketed_action;
+ case DELAY:
+ if (PEEK_TOKEN1 () == CASE)
+ {
+ parse_delay_case_action (label);
+ goto bracketed_action;
+ }
+ require (DELAY);
+ PUSH_ACTION;
+ expr = parse_primval ();
+ rhs = check_token (PRIORITY) ? parse_expression () : NULL_TREE;
+ if (! ignoring)
+ build_delay_action (expr, rhs);
+ goto handler_action;
+ case DO:
+ parse_do_action (label);
+ return 1;
+ case EXIT:
+ require (EXIT);
+ expr = parse_name_string ();
+ PUSH_ACTION;
+ lookup_and_handle_exit (expr);
+ goto no_handler_action;
+ case GOTO:
+ require (GOTO);
+ expr = parse_name_string ();
+ PUSH_ACTION;
+ lookup_and_expand_goto (expr);
+ goto no_handler_action;
+ case IF:
+ parse_if_action (label);
+ goto bracketed_action;
+ case RECEIVE:
+ if (PEEK_TOKEN1 () != CASE)
+ return 0;
+ parse_receive_case_action (label);
+ goto bracketed_action;
+ case RESULT:
+ require (RESULT);
+ PUSH_ACTION;
+ expr = parse_untyped_expr ();
+ if (! ignoring)
+ chill_expand_result (expr, 1);
+ goto handler_action;
+ case RETURN:
+ require (RETURN);
+ PUSH_ACTION;
+ expr = parse_opt_untyped_expr ();
+ if (! ignoring)
+ {
+ /* Do this as RESULT expr and RETURN to get exceptions */
+ chill_expand_result (expr, 0);
+ expand_goto_except_cleanup (proc_action_level);
+ chill_expand_return (NULL_TREE, 0);
+ }
+ if (expr)
+ goto handler_action;
+ else
+ goto no_handler_action;
+ case SC:
+ require (SC);
+ return 1;
+ case SEND:
+ parse_send_action ();
+ goto handler_action;
+ case START:
+ parse_start_action ();
+ goto handler_action;
+ case STOP:
+ require (STOP);
+ PUSH_ACTION;
+ if (! ignoring)
+ { tree func = lookup_name (get_identifier ("__stop_process"));
+ tree result = build_chill_function_call (func, NULL_TREE);
+ expand_expr_stmt (result);
+ }
+ goto no_handler_action;
+ case CALL:
+ require (CALL);
+ /* Fall through to here ... */
+ case EXPR:
+ case LPRN:
+ case NAME:
+ /* This handles calls and assignments. */
+ PUSH_ACTION;
+ expr = parse_primval ();
+ switch (PEEK_TOKEN ())
+ {
+ case END:
+ parse_semi_colon (); /* Emits error message. */
+ case ON:
+ case SC:
+ if (!ignoring && TREE_CODE (expr) != ERROR_MARK)
+ {
+ if (TREE_CODE (expr) != CALL_EXPR
+ && TREE_TYPE (expr) != void_type_node
+ && ! TREE_SIDE_EFFECTS (expr))
+ {
+ if (TREE_CODE (expr) == FUNCTION_DECL)
+ error ("missing parenthesis for procedure call");
+ else
+ error ("expression is not an action");
+ expr = error_mark_node;
+ }
+ else
+ expand_expr_stmt (expr);
+ }
+ goto handler_action;
+ default:
+ loclist
+ = ignoring ? NULL_TREE : build_tree_list (NULL_TREE, expr);
+ while (PEEK_TOKEN () == COMMA)
+ {
+ FORWARD_TOKEN ();
+ expr = parse_primval ();
+ if (!ignoring && TREE_CODE (expr) != ERROR_MARK)
+ loclist = tree_cons (NULL_TREE, expr, loclist);
+ }
+ }
+ switch (PEEK_TOKEN ())
+ {
+ case OR: op = BIT_IOR_EXPR; break;
+ case XOR: op = BIT_XOR_EXPR; break;
+ case ORIF: op = TRUTH_ORIF_EXPR; break;
+ case AND: op = BIT_AND_EXPR; break;
+ case ANDIF: op = TRUTH_ANDIF_EXPR; break;
+ case PLUS: op = PLUS_EXPR; break;
+ case SUB: op = MINUS_EXPR; break;
+ case CONCAT: op = CONCAT_EXPR; break;
+ case MUL: op = MULT_EXPR; break;
+ case DIV: op = TRUNC_DIV_EXPR; break;
+ case MOD: op = FLOOR_MOD_EXPR; break;
+ case REM: op = TRUNC_MOD_EXPR; break;
+
+ default:
+ error ("syntax error in action");
+ case SC: case ON:
+ case ASGN: op = NOP_EXPR; break;
+ ;
+ }
+
+ /* Looks like it was an assignment action. */
+ FORWARD_TOKEN ();
+ if (op != NOP_EXPR)
+ expect (ASGN, "expected ':=' here");
+ rhs = parse_untyped_expr ();
+ if (!ignoring)
+ expand_assignment_action (loclist, op, rhs);
+ goto handler_action;
+
+ default:
+ return 0;
+ }
+
+ bracketed_action:
+ /* We've parsed a bracketed action. */
+ parse_opt_handler ();
+ parse_opt_end_label_semi_colon (label);
+ return 1;
+
+ no_handler_action:
+ if (parse_opt_handler () != NULL_TREE && pass == 1)
+ error ("no handler is permitted on this action.");
+ parse_semi_colon ();
+ return 1;
+
+ handler_action:
+ parse_opt_handler ();
+ parse_semi_colon ();
+ return 1;
+}
+
+static void
+parse_body ()
+{
+ again:
+ while (parse_definition (0)) ;
+
+ while (parse_action ()) ;
+
+ if (parse_definition (0))
+ {
+ if (pass == 1)
+ pedwarn ("definition follows action");
+ goto again;
+ }
+}
+
+static tree
+parse_opt_untyped_expr ()
+{
+ switch (PEEK_TOKEN ())
+ {
+ case ON:
+ case END:
+ case SC:
+ case COMMA:
+ case COLON:
+ case RPRN:
+ return NULL_TREE;
+ default:
+ return parse_untyped_expr ();
+ }
+}
+
+static tree
+parse_call (function)
+ tree function;
+{
+ tree arg1, arg2, arg_list = NULL_TREE;
+ enum terminal tok;
+ require (LPRN);
+ arg1 = parse_opt_untyped_expr ();
+ if (arg1 != NULL_TREE)
+ {
+ tok = PEEK_TOKEN ();
+ if (tok == UP || tok == COLON)
+ {
+ FORWARD_TOKEN ();
+#if 0
+ /* check that arg1 isn't untyped (or mode);*/
+#endif
+ arg2 = parse_expression ();
+ expect (RPRN, "expected ')' to terminate slice");
+ if (ignoring)
+ return integer_zero_node;
+ else if (tok == UP)
+ return build_chill_slice_with_length (function, arg1, arg2);
+ else
+ return build_chill_slice_with_range (function, arg1, arg2);
+ }
+ if (!ignoring)
+ arg_list = build_tree_list (NULL_TREE, arg1);
+ while (check_token (COMMA))
+ {
+ arg2 = parse_untyped_expr ();
+ if (!ignoring)
+ arg_list = tree_cons (NULL_TREE, arg2, arg_list);
+ }
+ }
+
+ expect (RPRN, "expected ')' here");
+ return ignoring ? function
+ : build_generalized_call (function, nreverse (arg_list));
+}
+
+/* Matches: <field name list>
+ Returns: A list of IDENTIFIER_NODEs (or NULL_TREE if ignoring),
+ in reverse order. */
+
+static tree
+parse_tuple_fieldname_list ()
+{
+ tree list = NULL_TREE;
+ do
+ {
+ tree name;
+ if (!check_token (DOT))
+ {
+ error ("bad tuple field name list");
+ return NULL_TREE;
+ }
+ name = parse_simple_name_string ();
+ list = ignoring ? NULL_TREE : tree_cons (NULL_TREE, name, list);
+ } while (check_token (COMMA));
+ return list;
+}
+
+/* Returns one or nore TREE_LIST nodes, in reverse order. */
+
+static tree
+parse_tuple_element ()
+{
+ /* The tupleelement chain is built in reverse order,
+ and put in forward order when the list is used. */
+ tree value, list, label;
+ if (PEEK_TOKEN () == DOT)
+ {
+ /* Parse a labelled structure tuple. */
+ tree list = parse_tuple_fieldname_list (), field;
+ expect (COLON, "missing ':' in tuple");
+ value = parse_untyped_expr ();
+ if (ignoring)
+ return NULL_TREE;
+ /* FIXME: Should use save_expr(value), but that
+ confuses nested calls to digest_init! */
+ /* Re-use the list of field names as a list of name-value pairs. */
+ for (field = list; field != NULL_TREE; field = TREE_CHAIN (field))
+ { tree field_name = TREE_VALUE (field);
+ TREE_PURPOSE (field) = field_name;
+ TREE_VALUE (field) = value;
+ TUPLE_NAMED_FIELD (field) = 1;
+ }
+ return list;
+ }
+
+ label = parse_case_label_list (NULL_TREE, 1);
+ if (label)
+ {
+ expect (COLON, "missing ':' in tuple");
+ value = parse_untyped_expr ();
+ if (ignoring || label == NULL_TREE)
+ return NULL_TREE;
+ if (TREE_CODE (label) != TREE_LIST)
+ {
+ error ("invalid syntax for label in tuple");
+ return NULL_TREE;
+ }
+ else
+ {
+ /* FIXME: Should use save_expr(value), but that
+ confuses nested calls to digest_init! */
+ tree link = label;
+ for (; link != NULL_TREE; link = TREE_CHAIN (link))
+ { tree index = TREE_VALUE (link);
+ if (pass == 1 && TREE_CODE (index) != TREE_LIST)
+ index = build1 (PAREN_EXPR, NULL_TREE, index);
+ TREE_VALUE (link) = value;
+ TREE_PURPOSE (link) = index;
+ }
+ return nreverse (label);
+ }
+ }
+
+ value = parse_untyped_expr ();
+ if (check_token (COLON))
+ {
+ /* A powerset range [or possibly a labeled Array?] */
+ tree value2 = parse_untyped_expr ();
+ return ignoring ? NULL_TREE : build_tree_list (value, value2);
+ }
+ return ignoring ? NULL_TREE : build_tree_list (NULL_TREE, value);
+}
+
+/* Matches: a COMMA-separated list of tuple elements.
+ Returns a list (of TREE_LIST nodes). */
+static tree
+parse_opt_element_list ()
+{
+ tree list = NULL_TREE;
+ if (PEEK_TOKEN () == RPC)
+ return NULL_TREE;
+ for (;;)
+ {
+ tree element = parse_tuple_element ();
+ list = chainon (element, list); /* Built in reverse order */
+ if (PEEK_TOKEN () == RPC)
+ break;
+ if (!check_token (COMMA))
+ {
+ error ("bad syntax in tuple");
+ return NULL_TREE;
+ }
+ }
+ return nreverse (list);
+}
+
+/* Parses: '[' elements ']'
+ If modename is non-NULL it prefixed the tuple. */
+
+static tree
+parse_tuple (modename)
+ tree modename;
+{
+ tree list;
+ require (LPC);
+ list = parse_opt_element_list ();
+ expect (RPC, "missing ']' after tuple");
+ if (ignoring)
+ return integer_zero_node;
+ list = build_nt (CONSTRUCTOR, NULL_TREE, list);
+ if (modename == NULL_TREE)
+ return list;
+ else if (pass == 1)
+ TREE_TYPE (list) = modename;
+ else if (TREE_CODE (modename) != TYPE_DECL)
+ {
+ error ("non-mode name before tuple");
+ return error_mark_node;
+ }
+ else
+ list = chill_expand_tuple (TREE_TYPE (modename), list);
+ return list;
+}
+
+static tree
+parse_primval ()
+{
+ tree val;
+ switch (PEEK_TOKEN ())
+ {
+ case NUMBER:
+ case FLOATING:
+ case STRING:
+ case SINGLECHAR:
+ case BITSTRING:
+ case CONST:
+ case EXPR:
+ val = PEEK_TREE();
+ FORWARD_TOKEN ();
+ break;
+ case THIS:
+ val = build_chill_function_call (PEEK_TREE (), NULL_TREE);
+ FORWARD_TOKEN ();
+ break;
+ case LPRN:
+ FORWARD_TOKEN ();
+ val = parse_expression ();
+ expect (RPRN, "missing right parenthesis");
+ if (pass == 1 && ! ignoring)
+ val = build1 (PAREN_EXPR, NULL_TREE, val);
+ break;
+ case LPC:
+ val = parse_tuple (NULL_TREE);
+ break;
+ case NAME:
+ val = parse_name ();
+ if (PEEK_TOKEN() == LPC)
+ val = parse_tuple (val); /* Matched: <mode_name> <tuple> */
+ break;
+ default:
+ if (!ignoring)
+ error ("invalid expression/location syntax");
+ val = error_mark_node;
+ }
+ for (;;)
+ {
+ tree name, args;
+ switch (PEEK_TOKEN ())
+ {
+ case DOT:
+ FORWARD_TOKEN ();
+ name = parse_simple_name_string ();
+ val = ignoring ? val : build_chill_component_ref (val, name);
+ continue;
+ case ARROW:
+ FORWARD_TOKEN ();
+ name = parse_opt_name_string (0);
+ val = ignoring ? val : build_chill_indirect_ref (val, name, 1);
+ continue;
+ case LPRN:
+ /* The SEND buffer action syntax is ambiguous, at least when
+ parsed left-to-right. In the example 'SEND foo(v) ...' the
+ phrase 'foo(v)' could be a buffer location procedure call
+ (which then must be followed by the value to send).
+ On the other hand, if 'foo' is a buffer, stop parsing
+ after 'foo', and let parse_send_action pick up '(v) as
+ the value ot send.
+
+ We handle the ambiguity for SEND signal action differently,
+ since we allow (as an extension) a signal to be used as
+ a "function" (see build_generalized_call). */
+ if (TREE_TYPE (val) != NULL_TREE
+ && CH_IS_BUFFER_MODE (TREE_TYPE (val)))
+ return val;
+ val = parse_call (val);
+ continue;
+ case STRING:
+ case BITSTRING:
+ case SINGLECHAR:
+ case NAME:
+ /* Handle string repetition. (See comment in parse_operand5.) */
+ args = parse_primval ();
+ val = ignoring ? val : build_generalized_call (val, args);
+ continue;
+ }
+ break;
+ }
+ return val;
+}
+
+static tree
+parse_operand6 ()
+{
+ if (check_token (RECEIVE))
+ {
+ tree location = parse_primval ();
+ sorry ("RECEIVE expression");
+ return integer_one_node;
+ }
+ else if (check_token (ARROW))
+ {
+ tree location = parse_primval ();
+ return ignoring ? location : build_chill_arrow_expr (location, 0);
+ }
+ else
+ return parse_primval();
+}
+
+static tree
+parse_operand5()
+{
+ enum tree_code op;
+ /* We are supposed to be looking for a <string repetition operator>,
+ but in general we can't distinguish that from a parenthesized
+ expression. This is especially difficult if we allow the
+ string operand to be a constant expression (as requested by
+ some users), and not just a string literal.
+ Consider: LPRN expr RPRN LPRN expr RPRN
+ Is that a function call or string repetition?
+ Instead, we handle string repetition in parse_primval,
+ and build_generalized_call. */
+ tree rarg;
+ switch (PEEK_TOKEN())
+ {
+ case NOT: op = BIT_NOT_EXPR; break;
+ case SUB: op = NEGATE_EXPR; break;
+ default:
+ op = NOP_EXPR;
+ }
+ if (op != NOP_EXPR)
+ FORWARD_TOKEN();
+ rarg = parse_operand6();
+ return (op == NOP_EXPR || ignoring) ? rarg
+ : build_chill_unary_op (op, rarg);
+}
+
+static tree
+parse_operand4 ()
+{
+ tree larg = parse_operand5(), rarg;
+ enum tree_code op;
+ for (;;)
+ {
+ switch (PEEK_TOKEN())
+ {
+ case MUL: op = MULT_EXPR; break;
+ case DIV: op = TRUNC_DIV_EXPR; break;
+ case MOD: op = FLOOR_MOD_EXPR; break;
+ case REM: op = TRUNC_MOD_EXPR; break;
+ default:
+ return larg;
+ }
+ FORWARD_TOKEN();
+ rarg = parse_operand5();
+ if (!ignoring)
+ larg = build_chill_binary_op (op, larg, rarg);
+ }
+}
+
+static tree
+parse_operand3 ()
+{
+ tree larg = parse_operand4 (), rarg;
+ enum tree_code op;
+ for (;;)
+ {
+ switch (PEEK_TOKEN())
+ {
+ case PLUS: op = PLUS_EXPR; break;
+ case SUB: op = MINUS_EXPR; break;
+ case CONCAT: op = CONCAT_EXPR; break;
+ default:
+ return larg;
+ }
+ FORWARD_TOKEN();
+ rarg = parse_operand4();
+ if (!ignoring)
+ larg = build_chill_binary_op (op, larg, rarg);
+ }
+}
+
+static tree
+parse_operand2 ()
+{
+ tree larg = parse_operand3 (), rarg;
+ enum tree_code op;
+ for (;;)
+ {
+ if (check_token (IN))
+ {
+ rarg = parse_operand3();
+ if (! ignoring)
+ larg = build_chill_binary_op (SET_IN_EXPR, larg, rarg);
+ }
+ else
+ {
+ switch (PEEK_TOKEN())
+ {
+ case GT: op = GT_EXPR; break;
+ case GTE: op = GE_EXPR; break;
+ case LT: op = LT_EXPR; break;
+ case LTE: op = LE_EXPR; break;
+ case EQL: op = EQ_EXPR; break;
+ case NE: op = NE_EXPR; break;
+ default:
+ return larg;
+ }
+ FORWARD_TOKEN();
+ rarg = parse_operand3();
+ if (!ignoring)
+ larg = build_compare_expr (op, larg, rarg);
+ }
+ }
+}
+
+static tree
+parse_operand1 ()
+{
+ tree larg = parse_operand2 (), rarg;
+ enum tree_code op;
+ for (;;)
+ {
+ switch (PEEK_TOKEN())
+ {
+ case AND: op = BIT_AND_EXPR; break;
+ case ANDIF: op = TRUTH_ANDIF_EXPR; break;
+ default:
+ return larg;
+ }
+ FORWARD_TOKEN();
+ rarg = parse_operand2();
+ if (!ignoring)
+ larg = build_chill_binary_op (op, larg, rarg);
+ }
+}
+
+static tree
+parse_operand0 ()
+{
+ tree larg = parse_operand1(), rarg;
+ enum tree_code op;
+ for (;;)
+ {
+ switch (PEEK_TOKEN())
+ {
+ case OR: op = BIT_IOR_EXPR; break;
+ case XOR: op = BIT_XOR_EXPR; break;
+ case ORIF: op = TRUTH_ORIF_EXPR; break;
+ default:
+ return larg;
+ }
+ FORWARD_TOKEN();
+ rarg = parse_operand1();
+ if (!ignoring)
+ larg = build_chill_binary_op (op, larg, rarg);
+ }
+}
+
+static tree
+parse_expression ()
+{
+ return parse_operand0 ();
+}
+
+static tree
+parse_case_expression ()
+{
+ tree selector_list;
+ tree else_expr;
+ tree case_expr;
+ tree case_alt_list = NULL_TREE;
+
+ require (CASE);
+ selector_list = parse_expr_list ();
+ selector_list = nreverse (selector_list);
+
+ expect (OF, "missing 'OF'");
+ while (PEEK_TOKEN () == LPRN)
+ {
+ tree label_spec = parse_case_label_specification (selector_list);
+ tree sub_expr;
+ expect (COLON, "missing ':' in value case alternative");
+ sub_expr = parse_expression ();
+ expect (SC, "missing ';'");
+ if (! ignoring)
+ case_alt_list = tree_cons (label_spec, sub_expr, case_alt_list);
+ }
+ if (check_token (ELSE))
+ {
+ else_expr = parse_expression ();
+ if (check_token (SC) && pass == 1)
+ warning("there should not be a ';' here");
+ }
+ else
+ else_expr = NULL_TREE;
+ expect (ESAC, "missing 'ESAC' in 'CASE' expression");
+
+ if (ignoring)
+ return integer_zero_node;
+
+ /* If this is a multi dimension case, then transform it into an COND_EXPR
+ here. This must be done before store_expr is called since it has some
+ special handling for COND_EXPR expressions. */
+ if (TREE_CHAIN (selector_list) != NULL_TREE)
+ {
+ case_alt_list = nreverse (case_alt_list);
+ compute_else_ranges (selector_list, case_alt_list);
+ case_expr =
+ build_chill_multi_dimension_case_expr (selector_list, case_alt_list, else_expr);
+ }
+ else
+ case_expr = build_chill_case_expr (selector_list, case_alt_list, else_expr);
+
+ return case_expr;
+}
+
+static tree
+parse_then_alternative ()
+{
+ expect (THEN, "missing 'THEN' in 'IF' expression");
+ return parse_expression ();
+}
+
+static tree
+parse_else_alternative ()
+{
+ if (check_token (ELSIF))
+ return parse_if_expression_body ();
+ else if (check_token (ELSE))
+ return parse_expression ();
+ error ("missing ELSE/ELSIF in IF expression");
+ return error_mark_node;
+}
+
+/* Matches: <boolean expression> <then alternative> <else alternative> */
+
+static tree
+parse_if_expression_body ()
+{
+ tree bool_expr, then_expr, else_expr;
+ bool_expr = parse_expression ();
+ then_expr = parse_then_alternative ();
+ else_expr = parse_else_alternative ();
+ if (ignoring)
+ return integer_zero_node;
+ else
+ return build_nt (COND_EXPR, bool_expr, then_expr, else_expr);
+}
+
+static tree
+parse_if_expression ()
+{
+ tree expr;
+ require (IF);
+ expr = parse_if_expression_body ();
+ expect (FI, "missing 'FI' at end of conditional expression");
+ return expr;
+}
+
+/* An <untyped_expr> is a superset of <expr>. It also includes
+ <conditional expressions> and untyped <tuples>, whose types
+ are not given by their constituents. Hence, these are only
+ allowed in certain contexts that expect a certain type.
+ You should call convert() to fix up the <untyped_expr>. */
+
+static tree
+parse_untyped_expr ()
+{
+ tree val;
+ switch (PEEK_TOKEN())
+ {
+ case IF:
+ return parse_if_expression ();
+ case CASE:
+ return parse_case_expression ();
+ case LPRN:
+ switch (PEEK_TOKEN1())
+ {
+ case IF:
+ case CASE:
+ if (pass == 1)
+ pedwarn ("conditional expression not allowed inside parentheses");
+ goto skip_lprn;
+ case LPC:
+ if (pass == 1)
+ pedwarn ("mode-less tuple not allowed inside parentheses");
+ skip_lprn:
+ FORWARD_TOKEN ();
+ val = parse_untyped_expr ();
+ expect (RPRN, "missing ')'");
+ return val;
+ default: ;
+ /* fall through */
+ }
+ default:
+ return parse_operand0 ();
+ }
+}
+
+/* Matches: <index mode> */
+
+static tree
+parse_index_mode ()
+{
+ /* This is another one that is nasty to parse!
+ Let's feel our way ahead ... */
+ tree lower, upper;
+ if (PEEK_TOKEN () == NAME)
+ {
+ tree name = parse_name ();
+ switch (PEEK_TOKEN ())
+ {
+ case COMMA:
+ case RPRN:
+ case SC: /* An error */
+ /* This can only (legally) be a discrete mode name. */
+ return name;
+ case LPRN:
+ /* This could be named discrete range,
+ a cast, or some other expression (maybe). */
+ require (LPRN);
+ lower = parse_expression ();
+ if (check_token (COLON))
+ {
+ upper = parse_expression ();
+ expect (RPRN, "missing ')'");
+ /* Matched: <mode_name> '(' <expr> ':' <expr> ')' */
+ if (ignoring)
+ return NULL_TREE;
+ else
+ return build_chill_range_type (name, lower, upper);
+ }
+ /* Looks like a cast or procedure call or something.
+ Backup, and try again. */
+ pushback_token (EXPR, lower);
+ pushback_token (LPRN, NULL_TREE);
+ lower = parse_call (name);
+ goto parse_literal_range_colon;
+ default:
+ /* This has to be the start of an expression. */
+ pushback_token (EXPR, name);
+ goto parse_literal_range;
+ }
+ }
+ /* It's not a name. But it could still be a discrete mode. */
+ lower = parse_opt_mode ();
+ if (lower)
+ return lower;
+ parse_literal_range:
+ /* Nope, it's a discrete literal range. */
+ lower = parse_expression ();
+ parse_literal_range_colon:
+ expect (COLON, "expected ':' here");
+
+ upper = parse_expression ();
+ return ignoring ? NULL_TREE
+ : build_chill_range_type (NULL_TREE, lower, upper);
+}
+
+static tree
+parse_set_mode ()
+{
+ int set_name_cnt = 0; /* count of named set elements */
+ int set_is_numbered = 0; /* TRUE if set elements have explicit values */
+ int set_is_not_numbered = 0;
+ tree list = NULL_TREE;
+ tree mode = ignoring ? void_type_node : start_enum (NULL_TREE);
+ require (SET);
+ expect (LPRN, "missing left parenthesis after SET");
+ for (;;)
+ {
+ tree name, value = NULL_TREE;
+ if (check_token (MUL))
+ name = NULL_TREE;
+ else
+ {
+ name = parse_defining_occurrence ();
+ if (check_token (EQL))
+ {
+ value = parse_expression ();
+ set_is_numbered = 1;
+ }
+ else
+ set_is_not_numbered = 1;
+ set_name_cnt++;
+ }
+ name = build_enumerator (name, value);
+ if (pass == 1)
+ list = chainon (name, list);
+ if (! check_token (COMMA))
+ break;
+ }
+ expect (RPRN, "missing right parenthesis after SET");
+ if (!ignoring)
+ {
+ if (set_is_numbered && set_is_not_numbered)
+ /* Z.200 doesn't allow mixed numbered and unnumbered set elements,
+ but we can do it. Print a warning */
+ pedwarn ("mixed numbered and unnumbered set elements is not standard");
+ mode = finish_enum (mode, list);
+ if (set_name_cnt == 0)
+ error ("SET mode must define at least one named value");
+ CH_ENUM_IS_NUMBERED(mode) = set_is_numbered ? 1 : 0;
+ }
+ return mode;
+}
+
+/* parse layout POS:
+ returns a tree with following layout
+
+ treelist
+ pupose=treelist value=NULL_TREE (to indicate POS)
+ pupose=word value=treelist | NULL_TREE
+ pupose=startbit value=treelist | NULL_TREE
+ purpose= value=
+ integer_zero | integer_one length | endbit
+*/
+static tree
+parse_pos ()
+{
+ tree word;
+ tree startbit = NULL_TREE, endbit = NULL_TREE;
+ tree what = NULL_TREE;
+
+ require (LPRN);
+ word = parse_untyped_expr ();
+ if (check_token (COMMA))
+ {
+ startbit = parse_untyped_expr ();
+ if (check_token (COMMA))
+ {
+ what = integer_zero_node;
+ endbit = parse_untyped_expr ();
+ }
+ else if (check_token (COLON))
+ {
+ what = integer_one_node;
+ endbit = parse_untyped_expr ();
+ }
+ }
+ require (RPRN);
+
+ /* build the tree as described above */
+ if (what != NULL_TREE)
+ what = tree_cons (what, endbit, NULL_TREE);
+ if (startbit != NULL_TREE)
+ startbit = tree_cons (startbit, what, NULL_TREE);
+ endbit = tree_cons (word, startbit, NULL_TREE);
+ return tree_cons (endbit, NULL_TREE, NULL_TREE);
+}
+
+/* parse layout STEP
+ returns a tree with the following layout
+
+ treelist
+ pupose=NULL_TREE value=treelist (to indicate STEP)
+ pupose=POS(see baove) value=stepsize | NULL_TREE
+*/
+static tree
+parse_step ()
+{
+ tree pos;
+ tree stepsize = NULL_TREE;
+
+ require (LPRN);
+ require (POS);
+ pos = parse_pos ();
+ if (check_token (COMMA))
+ stepsize = parse_untyped_expr ();
+ require (RPRN);
+ TREE_VALUE (pos) = stepsize;
+ return tree_cons (NULL_TREE, pos, NULL_TREE);
+}
+
+/* returns layout for fields or array elements.
+ NULL_TREE no layout specified
+ integer_one_node PACK specified
+ integer_zero_node NOPACK specified
+ tree_list PURPOSE POS
+ tree_list VALUE STEP
+*/
+static tree
+parse_opt_layout (in)
+ int in; /* 0 ... parse structure, 1 ... parse array */
+{
+ tree val = NULL_TREE;
+
+ if (check_token (PACK))
+ {
+ return integer_one_node;
+ }
+ else if (check_token (NOPACK))
+ {
+ return integer_zero_node;
+ }
+ else if (check_token (POS))
+ {
+ val = parse_pos ();
+ if (in == 1 && pass == 1)
+ {
+ error ("POS not allowed for ARRAY");
+ val = NULL_TREE;
+ }
+ return val;
+ }
+ else if (check_token (STEP))
+ {
+ val = parse_step ();
+ if (in == 0 && pass == 1)
+ {
+ error ("STEP not allowed in field definition");
+ val = NULL_TREE;
+ }
+ return val;
+ }
+ else
+ return NULL_TREE;
+}
+
+static tree
+parse_field_name_list ()
+{
+ tree chain = NULL_TREE;
+ tree name = parse_defining_occurrence ();
+ if (name == NULL_TREE)
+ {
+ error("missing field name");
+ return NULL_TREE;
+ }
+ chain = build_tree_list (NULL_TREE, name);
+ while (check_token (COMMA))
+ {
+ name = parse_defining_occurrence ();
+ if (name == NULL)
+ {
+ error ("bad field name following ','");
+ break;
+ }
+ if (! ignoring)
+ chain = tree_cons (NULL_TREE, name, chain);
+ }
+ return chain;
+}
+
+/* Matches: <fixed field> or <variant field>, i.e.:
+ <field name defining occurrence list> <mode> [ <field layout> ].
+ Returns: A chain of FIELD_DECLs.
+ NULL_TREE is returned if ignoring is true or an error is seen. */
+
+static tree
+parse_fixed_field ()
+{
+ tree field_names = parse_field_name_list ();
+ tree mode = parse_mode ();
+ tree layout = parse_opt_layout (0);
+ return ignoring ? NULL_TREE
+ : grok_chill_fixedfields (field_names, mode, layout);
+}
+
+
+/* Matches: [ <variant field> { "," <variant field> }* ]
+ Returns: A chain of FIELD_DECLs.
+ NULL_TREE is returned if ignoring is true or an error is seen. */
+
+static tree
+parse_variant_field_list ()
+{
+ tree fields = NULL_TREE;
+ if (PEEK_TOKEN () != NAME)
+ return NULL_TREE;
+ for (;;)
+ {
+ fields = chainon (fields, parse_fixed_field ());
+ if (PEEK_TOKEN () != COMMA || PEEK_TOKEN1 () != NAME)
+ break;
+ require (COMMA);
+ }
+ return fields;
+}
+
+/* Matches: <variant alternative>
+ Returns a TREE_LIST node, whose TREE_PURPOSE (if non-NULL) is the label,
+ and whose TREE_VALUE is the list of FIELD_DECLs. */
+
+static tree
+parse_variant_alternative ()
+{
+ tree labels, x;
+ tree variant_fields = NULL_TREE;
+ if (PEEK_TOKEN () == LPRN)
+ labels = parse_case_label_specification (NULL_TREE);
+ else
+ labels = NULL_TREE;
+ if (! check_token (COLON))
+ {
+ error ("expected ':' in structure variant alternative");
+ return NULL_TREE;
+ }
+
+ /* We now read a list a variant fields, until we come to the end
+ of the variant alternative. But since both variant fields
+ *and* variant alternatives are separated by COMMAs,
+ we will have to look ahead to distinguish the start of a variant
+ field from the start of a new variant alternative.
+ We use the fact that a variant alternative must start with
+ either a LPRN or a COLON, while a variant field must start with a NAME.
+ This look-ahead is handled by parse_simple_fields. */
+ return build_tree_list (labels, parse_variant_field_list ());
+}
+
+/* Parse <field> (which is <fixed field> or <alternative field>).
+ Returns: A chain of FIELD_DECLs (or NULL_TREE on error or if ignoring). */
+
+static tree
+parse_field ()
+{
+ if (check_token (CASE))
+ {
+ tree tag_list = NULL_TREE, variants, opt_variant_else;
+ if (PEEK_TOKEN () == NAME)
+ {
+ tag_list = nreverse (parse_field_name_list ());
+ if (pass == 1)
+ tag_list = lookup_tag_fields (tag_list, current_fieldlist);
+ }
+ expect (OF, "missing 'OF' in alternative structure field");
+
+ variants = parse_variant_alternative ();
+ while (check_token (COMMA))
+ variants = chainon (parse_variant_alternative (), variants);
+ variants = nreverse (variants);
+
+ if (check_token (ELSE))
+ opt_variant_else = parse_variant_field_list ();
+ else
+ opt_variant_else = NULL_TREE;
+ expect (ESAC, "missing 'ESAC' following alternative structure field");
+ if (ignoring)
+ return NULL_TREE;
+ return grok_chill_variantdefs (tag_list, variants, opt_variant_else);
+ }
+ else if (PEEK_TOKEN () == NAME)
+ return parse_fixed_field ();
+ else
+ {
+ if (pass == 1)
+ error ("missing field");
+ return NULL_TREE;
+ }
+}
+
+static tree
+parse_structure_mode ()
+{
+ tree save_fieldlist = current_fieldlist;
+ tree fields;
+ require (STRUCT);
+ expect (LPRN, "expected '(' after STRUCT");
+ current_fieldlist = fields = parse_field ();
+ while (check_token (COMMA))
+ fields = chainon (fields, parse_field ());
+ expect (RPRN, "expected ')' after STRUCT");
+ current_fieldlist = save_fieldlist;
+ return ignoring ? void_type_node : build_chill_struct_type (fields);
+}
+
+static tree
+parse_opt_queue_size ()
+{
+ if (check_token (LPRN))
+ {
+ tree size = parse_expression ();
+ expect (RPRN, "missing ')'");
+ return size;
+ }
+ else
+ return NULL_TREE;
+}
+
+static tree
+parse_procedure_mode ()
+{
+ tree param_types = NULL_TREE, result_spec, except_list, recursive;
+ require (PROC);
+ expect (LPRN, "missing '(' after PROC");
+ if (! check_token (RPRN))
+ {
+ for (;;)
+ {
+ tree pmode = parse_mode ();
+ tree paramattr = parse_param_attr ();
+ if (! ignoring)
+ {
+ pmode = get_type_of (pmode);
+ param_types = tree_cons (paramattr, pmode, param_types);
+ }
+ if (! check_token (COMMA))
+ break;
+ }
+ expect (RPRN, "missing ')' after PROC");
+ }
+ result_spec = parse_opt_result_spec ();
+ except_list = parse_opt_except ();
+ recursive = parse_opt_recursive ();
+ if (ignoring)
+ return void_type_node;
+ return build_chill_pointer_type (build_chill_function_type
+ (result_spec, nreverse (param_types),
+ except_list, recursive));
+}
+
+/* Matches: <mode>
+ A NAME will be assumed to be a <mode name>, and thus a <mode>.
+ Returns NULL_TREE if no mode is seen.
+ (If ignoring is true, the return value may be an arbitrary tree node,
+ but will be non-NULL if something that could be a mode is seen.) */
+
+static tree
+parse_opt_mode ()
+{
+ switch (PEEK_TOKEN ())
+ {
+ case ACCESS:
+ {
+ tree index_mode, record_mode;
+ int dynamic = 0;
+ require (ACCESS);
+ if (check_token (LPRN))
+ {
+ index_mode = parse_index_mode ();
+ expect (RPRN, "mssing ')'");
+ }
+ else
+ index_mode = NULL_TREE;
+ record_mode = parse_opt_mode ();
+ if (record_mode)
+ dynamic = check_token (DYNAMIC);
+ return ignoring ? void_type_node
+ : build_access_mode (index_mode, record_mode, dynamic);
+ }
+ case ARRAY:
+ {
+ tree index_list = NULL_TREE, base_mode;
+ int varying;
+ int num_index_modes = 0;
+ int i;
+ tree layouts = NULL_TREE;
+ FORWARD_TOKEN ();
+ expect (LPRN, "missing '(' after ARRAY");
+ for (;;)
+ {
+ tree index = parse_index_mode ();
+ num_index_modes++;
+ if (!ignoring)
+ index_list = tree_cons (NULL_TREE, index, index_list);
+ if (! check_token (COMMA))
+ break;
+ }
+ expect (RPRN, "missing ')' after ARRAY");
+ varying = check_token (VARYING);
+ base_mode = parse_mode ();
+ /* Allow a layout specification for each index mode */
+ for (i = 0; i < num_index_modes; ++i)
+ {
+ tree new_layout = parse_opt_layout (1);
+ if (new_layout == NULL_TREE)
+ break;
+ if (!ignoring)
+ layouts = tree_cons (NULL_TREE, new_layout, layouts);
+ }
+ if (ignoring)
+ return base_mode;
+ return build_chill_array_type (get_type_of (base_mode),
+ index_list, varying, layouts);
+ }
+ case ASSOCIATION:
+ require (ASSOCIATION);
+ return association_type_node;
+ case BIN:
+ { tree length;
+ FORWARD_TOKEN();
+ expect (LPRN, "missing left parenthesis after BIN");
+ length = parse_expression ();
+ expect (RPRN, "missing right parenthesis after BIN");
+ return ignoring ? void_type_node : build_chill_bin_type (length);
+ }
+ case BOOLS:
+ {
+ tree length;
+ FORWARD_TOKEN ();
+ expect (LPRN, "missing '(' after BOOLS");
+ length = parse_expression ();
+ expect (RPRN, "missing ')' after BOOLS");
+ if (check_token (VARYING))
+ error ("VARYING bit-strings not implemented");
+ return ignoring ? void_type_node : build_bitstring_type (length);
+ }
+ case BUFFER:
+ {
+ tree qsize, element_mode;
+ require (BUFFER);
+ qsize = parse_opt_queue_size ();
+ element_mode = parse_mode ();
+ return ignoring ? element_mode
+ : build_buffer_type (element_mode, qsize);
+ }
+ case CHARS:
+ {
+ tree length;
+ int varying;
+ tree type;
+ FORWARD_TOKEN ();
+ expect (LPRN, "missing '(' after CHARS");
+ length = parse_expression ();
+ expect (RPRN, "missing ')' after CHARS");
+ varying = check_token (VARYING);
+ if (ignoring)
+ return void_type_node;
+ type = build_string_type (char_type_node, length);
+ if (varying)
+ type = build_varying_struct (type);
+ return type;
+ }
+ case EVENT:
+ {
+ tree qsize;
+ require (EVENT);
+ qsize = parse_opt_queue_size ();
+ return ignoring ? void_type_node : build_event_type (qsize);
+ }
+ case NAME:
+ {
+ tree mode = get_type_of (parse_name ());
+ if (check_token (LPRN))
+ {
+ tree min_value = parse_expression ();
+ if (check_token (COLON))
+ {
+ tree max_value = parse_expression ();
+ expect (RPRN, "syntax error - expected ')'");
+ /* Matched: <mode_name> '(' <expr> ':' <expr> ')' */
+ if (ignoring)
+ return mode;
+ else
+ return build_chill_range_type (mode, min_value, max_value);
+ }
+ if (check_token (RPRN))
+ {
+ int varying = check_token (VARYING);
+ if (! ignoring)
+ {
+ if (mode == char_type_node || varying)
+ {
+ if (mode != char_type_node
+ && mode != ridpointers[(int) RID_CHAR])
+ error ("strings must be composed of chars");
+ mode = build_string_type (char_type_node, min_value);
+ if (varying)
+ mode = build_varying_struct (mode);
+ }
+ else
+ {
+ /* Parameterized mode,
+ or old-fashioned CHAR(N) string declaration.. */
+ tree pmode = make_node (LANG_TYPE);
+ TREE_TYPE (pmode) = mode;
+ TYPE_DOMAIN (pmode) = min_value;
+ mode = pmode;
+ }
+ }
+ }
+ }
+ return mode;
+ }
+ case POWERSET:
+ { tree mode;
+ FORWARD_TOKEN ();
+ mode = parse_mode ();
+ if (ignoring || TREE_CODE (mode) == ERROR_MARK)
+ return mode;
+ return build_powerset_type (get_type_of (mode));
+ }
+ case PROC:
+ return parse_procedure_mode ();
+ case RANGE:
+ { tree low, high;
+ FORWARD_TOKEN();
+ expect (LPRN, "missing left parenthesis after RANGE");
+ low = parse_expression ();
+ expect (COLON, "missing colon");
+ high = parse_expression ();
+ expect (RPRN, "missing right parenthesis after RANGE");
+ return ignoring ? void_type_node
+ : build_chill_range_type (NULL_TREE, low, high);
+ }
+ case READ:
+ FORWARD_TOKEN ();
+ {
+ tree mode2 = get_type_of (parse_mode ());
+ if (ignoring || TREE_CODE (mode2) == ERROR_MARK)
+ return mode2;
+ if (mode2
+ && TREE_CODE_CLASS (TREE_CODE (mode2)) == 'd'
+ && CH_IS_BUFFER_MODE (mode2))
+ {
+ error ("BUFFER modes may not be readonly");
+ return mode2;
+ }
+ if (mode2
+ && TREE_CODE_CLASS (TREE_CODE (mode2)) == 'd'
+ && CH_IS_EVENT_MODE (mode2))
+ {
+ error ("EVENT modes may not be readonly");
+ return mode2;
+ }
+ return build_readonly_type (mode2);
+
+ }
+ case REF:
+ { tree mode;
+ FORWARD_TOKEN ();
+ mode = parse_mode ();
+ if (ignoring)
+ return mode;
+ mode = get_type_of (mode);
+ return (TREE_CODE (mode) == ERROR_MARK) ? mode
+ : build_chill_pointer_type (mode);
+ }
+ case SET:
+ return parse_set_mode ();
+ case SIGNAL:
+ if (pedantic)
+ error ("SIGNAL is not a valid mode");
+ return generic_signal_type_node;
+ case STRUCT:
+ return parse_structure_mode ();
+ case TEXT:
+ {
+ tree length, index_mode;
+ int dynamic;
+ require (TEXT);
+ expect (LPRN, "missing '('");
+ length = parse_expression ();
+ expect (RPRN, "missing ')'");
+ /* FIXME: This should actually look for an optional index_mode,
+ but that is tricky to do. */
+ index_mode = parse_opt_mode ();
+ dynamic = check_token (DYNAMIC);
+ return ignoring ? void_type_node
+ : build_text_mode (length, index_mode, dynamic);
+ }
+ case USAGE:
+ require (USAGE);
+ return usage_type_node;
+ case WHERE:
+ require (WHERE);
+ return where_type_node;
+ default:
+ return NULL_TREE;
+ }
+}
+
+static tree
+parse_mode ()
+{
+ tree mode = parse_opt_mode ();
+ if (mode == NULL_TREE)
+ {
+ if (pass == 1)
+ error ("syntax error - missing mode");
+ mode = error_mark_node;
+ }
+ return mode;
+}
+
+static void
+parse_program()
+{
+ /* Initialize global variables for current pass. */
+ int i;
+ expand_exit_needed = 0;
+ label = NULL_TREE; /* for statement labels */
+ current_module = NULL;
+ current_function_decl = NULL_TREE;
+ in_pseudo_module = 0;
+
+ for (i = 0; i <= MAX_LOOK_AHEAD; i++)
+ terminal_buffer[i] = TOKEN_NOT_READ;
+
+#if 0
+ /* skip some junk */
+ while (PEEK_TOKEN() == HEADEREL)
+ FORWARD_TOKEN();
+#endif
+
+ start_outer_function ();
+
+ for (;;)
+ {
+ tree label = parse_optlabel ();
+ if (PEEK_TOKEN() == MODULE || PEEK_TOKEN() == REGION)
+ parse_modulion (label);
+ else if (PEEK_TOKEN() == SPEC)
+ parse_spec_module (label);
+ else break;
+ }
+
+ finish_outer_function ();
+}
+
+void
+parse_pass_1_2()
+{
+ parse_program();
+ if (PEEK_TOKEN() != END_PASS_1)
+ {
+ error ("syntax error - expected a module or end of file");
+ serious_errors++;
+ }
+ chill_finish_compile ();
+ if (serious_errors)
+ exit (FATAL_EXIT_CODE);
+ switch_to_pass_2 ();
+ ch_parse_init ();
+ except_init_pass_2 ();
+ ignoring = 0;
+ parse_program();
+ chill_finish_compile ();
+}
+
+int yyparse ()
+{
+ parse_pass_1_2 ();
+ return 0;
+}
+
+/*
+ * We've had an error. Move the compiler's state back to
+ * the global binding level. This prevents the loop in
+ * compile_file in toplev.c from looping forever, since the
+ * CHILL poplevel() has *no* effect on the value returned by
+ * global_bindings_p().
+ */
+void
+to_global_binding_level ()
+{
+ while (! global_bindings_p ())
+ current_function_decl = DECL_CONTEXT (current_function_decl);
+ serious_errors++;
+}
+
+#if 1
+int yydebug;
+/* Sets the value of the 'yydebug' variable to VALUE.
+ This is a function so we don't have to have YYDEBUG defined
+ in order to build the compiler. */
+void
+set_yydebug (value)
+ int value;
+{
+#if YYDEBUG != 0
+ yydebug = value;
+#else
+ warning ("YYDEBUG not defined.");
+#endif
+}
+#endif
diff --git a/gcc/ch/runtime/allmem.c b/gcc/ch/runtime/allmem.c
new file mode 100644
index 0000000..8cf2be5
--- /dev/null
+++ b/gcc/ch/runtime/allmem.c
@@ -0,0 +1,73 @@
+/* Implement runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include <stdlib.h>
+#include "config.h"
+#include "rtltypes.h"
+
+extern void __cause_ex1 (char *exname, char *file, int lineno);
+
+/* define needed exceptions */
+EXCEPTION (protectionfail);
+EXCEPTION (rangefail);
+EXCEPTION (spacefail);
+
+/*
+ * function _allocate_memory
+ *
+ * parameters:
+ * ptr pointer to location where pointer should be written
+ * size number of bytes to allocate
+ * filename source file which issued the call
+ * linenumber line number within that source file
+ *
+ * returns:
+ * void
+ *
+ * exceptions:
+ * spacefail
+ * protectionfail
+ * rangefail
+ *
+ * abstract:
+ * allocate memory from heap
+ *
+*/
+
+void
+_allocate_memory (ptr, size, filename, linenumber)
+ void **ptr;
+ int size;
+ char *filename;
+ int linenumber;
+{
+ void *tmp;
+
+ if (!ptr)
+ __cause_ex1 ("protectionfail", filename, linenumber);
+ if (size < 0)
+ __cause_ex1 ("rangefail", filename, linenumber);
+ tmp = malloc (size);
+ if (!tmp)
+ __cause_ex1 ("spacefail", filename, linenumber);
+ *ptr = tmp;
+}
diff --git a/gcc/ch/runtime/andps.c b/gcc/ch/runtime/andps.c
new file mode 100644
index 0000000..fd7d609
--- /dev/null
+++ b/gcc/ch/runtime/andps.c
@@ -0,0 +1,76 @@
+/* Implement POWERSET runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+#include <stdio.h>
+#include "powerset.h"
+
+/*
+ * function __andpowerset
+ *
+ * parameters:
+ * out return from __andpowerset
+ * left left powerset
+ * right right powerset
+ * bitlength length of powerset in bits
+ *
+ * returns:
+ * void
+ *
+ * exceptions:
+ * none
+ *
+ * abstract:
+ * and's two powersets
+ *
+ */
+
+void
+__andpowerset (out, left, right, bitlength)
+ SET_WORD *out;
+ SET_WORD *left;
+ SET_WORD *right;
+ unsigned long bitlength;
+{
+ if (bitlength <= SET_CHAR_SIZE)
+ {
+ *((SET_CHAR *)out) = *((SET_CHAR *)left) &
+ *((SET_CHAR *)right);
+ MASK_UNUSED_CHAR_BITS((SET_CHAR *)out, bitlength);
+ }
+ else if (bitlength <= SET_SHORT_SIZE)
+ {
+ *((SET_SHORT *)out) = *((SET_SHORT *)left) &
+ *((SET_SHORT *)right);
+ MASK_UNUSED_SHORT_BITS((SET_SHORT *)out, bitlength);
+ }
+ else
+ {
+ unsigned long len = BITS_TO_WORDS (bitlength);
+ register unsigned long i;
+
+ for (i = 0; i < len; i++)
+ out[i] = left[i] & right[i];
+ MASK_UNUSED_WORD_BITS ((out + len - 1),
+ bitlength % SET_WORD_SIZE);
+ }
+}
diff --git a/gcc/ch/runtime/auxtypes.h b/gcc/ch/runtime/auxtypes.h
new file mode 100644
index 0000000..627da11
--- /dev/null
+++ b/gcc/ch/runtime/auxtypes.h
@@ -0,0 +1,45 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _auxtypes_h_
+#define _auxtypes_h_
+
+
+typedef enum { False, True } Boolean;
+
+#define VARYING_STRING(strlen) \
+ struct { unsigned short len; char body[strlen]; }
+
+typedef struct {
+ unsigned short len;
+ char body[1];
+} VarString;
+
+/* Macros for moving an (U)INT and (U)LONG without alignment worries */
+#define MOV2(tgt,src) \
+ *((char*)(tgt) ) = *((char*)(src) ), \
+ *((char*)(tgt)+1) = *((char*)(src)+1)
+#define MOV4(tgt,src) \
+ *((char*)(tgt) ) = *((char*)(src) ), \
+ *((char*)(tgt)+1) = *((char*)(src)+1), \
+ *((char*)(tgt)+2) = *((char*)(src)+2), \
+ *((char*)(tgt)+3) = *((char*)(src)+3)
+
+#endif
diff --git a/gcc/ch/runtime/basicio.c b/gcc/ch/runtime/basicio.c
new file mode 100644
index 0000000..b13b0b8
--- /dev/null
+++ b/gcc/ch/runtime/basicio.c
@@ -0,0 +1,467 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+ This file is part of GNU CC.
+
+ GNU CC 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 2, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "fileio.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+static
+void
+GetSetAttributes( Association_Mode* the_assoc )
+{
+ struct stat statbuf;
+ int retco;
+
+ if( (retco = stat( the_assoc->pathname, &statbuf )) )
+ return;
+
+ if( S_ISREG(statbuf.st_mode) )
+ {
+ SET_FLAG( the_assoc, IO_EXISTING );
+ if( !TEST_FLAG( the_assoc, IO_VARIABLE ) )
+ SET_FLAG( the_assoc, IO_INDEXABLE );
+ }
+ else
+ if( S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode) )
+ {
+ SET_FLAG( the_assoc, IO_EXISTING );
+ CLR_FLAG( the_assoc, IO_INDEXABLE );
+ }
+ SET_FLAG( the_assoc, IO_SEQUENCIBLE );
+
+ /* FIXME: File size and computation of number of records for outoffile ? */
+
+ if( !access( the_assoc->pathname, R_OK ) )
+ SET_FLAG( the_assoc, IO_READABLE );
+ if( !access( the_assoc->pathname, W_OK ) )
+ SET_FLAG( the_assoc, IO_WRITEABLE );
+}
+
+static
+void
+makeName( Association_Mode* the_assoc, char* the_path, int the_path_len,
+ char* file, int line)
+{
+ int namlen;
+ if( ! the_assoc->pathname &&
+ ! (the_assoc->pathname = (char*)malloc( PATH_MAX )) )
+ CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
+
+ if( the_path[0] != DIRSEP )
+ {
+ if( !getcwd( the_assoc->pathname, PATH_MAX ) )
+ {
+ the_assoc->syserrno = errno;
+ CHILLEXCEPTION( file, line, ASSOCIATEFAIL, GETCWD_FAILS );
+ }
+ namlen = strlen( the_assoc->pathname );
+ the_assoc->pathname[namlen++] = DIRSEP;
+ }
+ else
+ namlen = 0;
+
+ strncpy( the_assoc->pathname + namlen, the_path, the_path_len );
+ the_assoc->pathname[namlen+the_path_len] = '\0';
+}
+
+/*
+ * ASSOCIATE
+ */
+/* Caution: returns an Association mode location (!) */
+Association_Mode*
+__associate( Association_Mode* the_assoc,
+ char* the_path,
+ int the_path_len,
+ char* the_mode,
+ int the_mode_len,
+ char* file,
+ int line )
+{
+ if( !the_assoc )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
+
+ if( TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
+ CHILLEXCEPTION( file, line, ASSOCIATEFAIL, IS_ASSOCIATED );
+
+ /* clear all flags */
+ the_assoc->flags = 0;
+
+ if( ! the_path_len )
+ CHILLEXCEPTION( file, line, ASSOCIATEFAIL, NO_PATH_NAME );
+
+ makeName( the_assoc, the_path, the_path_len, file, line );
+ GetSetAttributes( the_assoc );
+
+ CLR_FLAG( the_assoc, IO_VARIABLE );
+ if ( the_mode )
+ {
+ if( !strncmp( the_mode, "VARIABLE", 8 ) )
+ {
+ SET_FLAG( the_assoc, IO_VARIABLE );
+ CLR_FLAG( the_assoc, IO_INDEXABLE );
+ }
+ else
+ if( strlen( the_mode ) )
+ CHILLEXCEPTION( file, line, ASSOCIATEFAIL, INVALID_ASSOCIATION_MODE );
+ }
+
+ SET_FLAG( the_assoc, IO_ISASSOCIATED );
+ return the_assoc;
+}
+
+/*
+ * DISSOCIATE
+ */
+void
+__dissociate( Association_Mode* the_assoc, char* file, int line )
+{
+ if( !the_assoc )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
+
+ if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
+ CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
+
+ if( the_assoc->access )
+ __disconnect( the_assoc->access, file, line );
+
+ the_assoc->access = NULL;
+ CLR_FLAG( the_assoc, IO_ISASSOCIATED );
+
+ /* free allocated memory */
+ if (the_assoc->pathname)
+ {
+ free (the_assoc->pathname);
+ the_assoc->pathname = 0;
+ }
+ if (the_assoc->bufptr)
+ {
+ free (the_assoc->bufptr);
+ the_assoc->bufptr = 0;
+ }
+}
+
+/*
+ * CREATE
+ */
+void __create( Association_Mode* the_assoc, char* file, int line )
+{
+ if( !the_assoc )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
+
+ if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
+ CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
+
+ if( TEST_FLAG( the_assoc, IO_EXISTING ) )
+ CHILLEXCEPTION( file, line, CREATEFAIL, FILE_EXISTING );
+
+ if( (the_assoc->handle = open( the_assoc->pathname, O_CREAT+O_TRUNC+O_WRONLY, 0666 ))
+ == -1 )
+ CHILLEXCEPTION( file, line, CREATEFAIL, CREATE_FAILS );
+
+ the_assoc->usage = ReadWrite;
+ GetSetAttributes( the_assoc );
+
+ close( the_assoc->handle );
+}
+
+/*
+ * MODIFY
+ */
+void
+__modify( Association_Mode* the_assoc,
+ char* the_path,
+ int the_path_len,
+ char* the_mode,
+ int the_mode_len,
+ char* file,
+ int line )
+{
+ if( !the_assoc )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
+
+ if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
+ CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
+
+ if( the_path_len )
+ {
+ char* oldname;
+
+ if( ! (oldname = (char*)malloc( PATH_MAX )) )
+ CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
+ strcpy( oldname, the_assoc->pathname );
+
+ makeName( the_assoc, the_path, the_path_len, file, line );
+
+ if( rename( oldname, the_assoc->pathname ) )
+ {
+ free( oldname );
+ CHILLEXCEPTION( file, line, MODIFYFAIL, RENAME_FAILS );
+ }
+ free( oldname );
+ }
+ else
+ {
+ /* FIXME: other options? */
+ }
+}
+
+static
+/*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
+int DirMode[] = { O_RDONLY, O_RDWR, O_RDWR };
+
+static
+/*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
+int SeqMode[] = { O_RDONLY, O_RDWR, O_RDWR };
+
+/*
+ * CONNECT
+ */
+void
+__connect( void* the_transfer,
+ Association_Mode* the_assoc,
+ Usage_Mode the_usage,
+ Where_Mode the_where,
+ Boolean with_index,
+ signed long the_index,
+ char* file,
+ int line )
+{
+ Access_Mode* the_access;
+ off_t filepos;
+ off_t savepos;
+ char dummy;
+ unsigned long nbytes;
+ int oflag;
+
+ if( !the_transfer )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
+ if( !the_assoc )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
+
+ if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
+ {
+ if( ! ((Text_Mode*)the_transfer)->access_sub )
+ CHILLEXCEPTION( file, line, EMPTY, NO_ACCESS_SUBLOCATION );
+ the_access = ((Text_Mode*)the_transfer)->access_sub;
+ SET_FLAG( the_access, IO_TEXTIO );
+ }
+ else
+ {
+ the_access = (Access_Mode*)the_transfer;
+ CLR_FLAG( the_access, IO_TEXTIO );
+ }
+
+ /* FIXME: This should be an (implementation-dependent) static check
+ if( with_index && the_access->rectype > Fixed )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, IMPL_RESTRICTION );
+ */
+
+ if( ! TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
+ CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
+
+ if( ! TEST_FLAG( the_assoc, IO_EXISTING ) )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_EXISTING );
+
+ if( ! TEST_FLAG( the_assoc, IO_READABLE ) &&
+ ( the_usage = ReadOnly || the_usage == ReadWrite ) )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_READABLE );
+
+ if( ! TEST_FLAG( the_assoc, IO_WRITEABLE ) &&
+ ( the_usage = WriteOnly || the_usage == ReadWrite ) )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_WRITEABLE );
+
+ if( ! TEST_FLAG( the_assoc, IO_INDEXABLE )
+ && TEST_FLAG( the_access, IO_INDEXED ) )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXABLE );
+
+ if( ! TEST_FLAG( the_assoc, IO_SEQUENCIBLE )
+ && ! TEST_FLAG( the_access, IO_INDEXED ) )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_SEQUENCIBLE );
+
+ if( the_where == Same && the_assoc->access == NULL )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, NO_CURRENT_POS );
+
+ /* This dynamic condition is not checked for text connections. */
+ if( ! TEST_FLAG( the_access, IO_TEXTIO ) )
+ if( ! TEST_FLAG( the_assoc, IO_VARIABLE )
+ && the_access->rectype > Fixed
+ && ( the_usage == WriteOnly || the_usage == ReadWrite ) )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_VARIABLE );
+
+ if( TEST_FLAG( the_assoc, IO_VARIABLE )
+ && the_access->rectype == Fixed
+ && ( the_usage == ReadOnly || the_usage == ReadWrite ) )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_FIXED );
+
+ if( ! TEST_FLAG( the_access, IO_INDEXED ) && the_usage == ReadWrite )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXED );
+
+ /* Access location may be connected to a different association. */
+ if( the_access->association && the_access->association != the_assoc )
+ __disconnect( the_access, file, line );
+
+ /* Is the association location already connected? */
+ if( the_assoc->access )
+ {
+ /* save position just in case we need it for the_where == Same */
+ if( (savepos = lseek( the_assoc->handle, 0L, SEEK_CUR )) == -1L )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
+
+ /* text: read correction, flush buffer */
+ if( the_assoc->bufptr ){
+ savepos -= the_assoc->bufptr->len - the_assoc->bufptr->cur;
+ the_assoc->bufptr->len = the_assoc->bufptr->cur = 0;
+ }
+
+ /* implicit disconnect */
+ __disconnect( the_assoc->access, file, line );
+ }
+
+ the_assoc->usage = the_usage;
+ CLR_FLAG( the_access, IO_OUTOFFILE );
+
+ if( TEST_FLAG( the_access, IO_INDEXED ) )
+ {
+ if( (the_assoc->handle = open( the_assoc->pathname, DirMode[the_usage] )) == -1 )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
+
+ /* Set base index. */
+ switch( the_where )
+ {
+ case First:
+ filepos = 0;
+ break;
+ case Same:
+ filepos = savepos;
+ break;
+ case Last:
+ if( lseek( the_assoc->handle, 0L, SEEK_END ) == -1L )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
+ filepos = lseek( the_assoc->handle, 0L, SEEK_CUR );
+ break;
+ }
+
+ /* Set current index */
+ if( with_index )
+ {
+ if( the_index < the_access->lowindex
+ || the_access->highindex < the_index )
+ CHILLEXCEPTION( file, line, RANGEFAIL, BAD_INDEX );
+ filepos += (the_index - the_access->lowindex) * the_access->reclength;
+ }
+ if( lseek( the_assoc->handle, filepos, SEEK_SET ) == -1L )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
+ the_access->base = filepos;
+ }
+ else
+ {
+ /* for association to text for reading: allocate buffer */
+ if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ) &&
+ the_usage == ReadOnly &&
+ !the_assoc->bufptr )
+ {
+ if( ! (the_assoc->bufptr = (readbuf_t*)malloc( sizeof(readbuf_t) )) )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, BUFFER_ALLOC );
+ memset (the_assoc->bufptr, 0, sizeof (readbuf_t));
+ }
+ if( (the_assoc->handle = open( the_assoc->pathname, SeqMode[the_usage] )) == -1 )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
+
+ /* Set base index. */
+ switch( the_where )
+ {
+ case First:
+ filepos = 0;
+ break;
+ case Same:
+ filepos = savepos;
+ break;
+ case Last:
+ if( lseek( the_assoc->handle, 0L, SEEK_END ) == -1L )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
+ filepos = lseek( the_assoc->handle, 0L, SEEK_CUR );
+ break;
+ }
+
+ /* file truncation for sequential, Write Only */
+ /***************************** FIXME: cannot truncate at Same
+ if( the_usage == WriteOnly )
+ {
+ if( fseek( the_assoc->file_ptr, filepos, SEEK_SET ) == -1L )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, FSEEK_FAILS );
+ fclose( the_assoc->file_ptr );
+ if( !(the_assoc->file_ptr = fopen( the_assoc->pathname, "ab" )) )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
+ }
+ else
+ ***************************/
+ if( (filepos = lseek( the_assoc->handle, filepos, SEEK_SET )) == -1L )
+ CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
+ }
+
+ the_access->association = the_assoc;
+ the_assoc->access = the_access;
+ /* for text: set carriage control default */
+ if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ) ){
+ the_assoc->ctl_pre = '\0';
+ the_assoc->ctl_post = '\n';
+ }
+}
+
+void
+__disconnect( void* the_transfer, char* file, int line )
+{
+ Access_Mode* the_access;
+
+ if( !the_transfer )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
+
+ if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
+ {
+ the_access = ((Text_Mode*)the_transfer)->access_sub;
+ CLR_FLAG( the_access, IO_TEXTIO );
+ }
+ else
+ the_access = (Access_Mode*)the_transfer;
+
+ if( !the_access->association )
+ CHILLEXCEPTION( file, line, NOTCONNECTED, IS_NOT_CONNECTED );
+
+ close( the_access->association->handle );
+ /* FIXME: check result */
+
+ if( the_access->store_loc )
+ free( the_access->store_loc );
+ the_access->store_loc = NULL;
+ the_access->association->access = NULL;
+ the_access->association = NULL;
+}
diff --git a/gcc/ch/runtime/bitstring.h b/gcc/ch/runtime/bitstring.h
new file mode 100644
index 0000000..0a8ce62
--- /dev/null
+++ b/gcc/ch/runtime/bitstring.h
@@ -0,0 +1,29 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _bitstring_h_
+#define _bitstring_h_
+
+int __inpowerset( int i, char* string, int strlen, int dummy );
+void __setbitpowerset (char *powerset, unsigned long bitlength,
+ long minval, long bitno, char newval,
+ char *filename, int lineno);
+
+#endif
diff --git a/gcc/ch/runtime/cause.c b/gcc/ch/runtime/cause.c
new file mode 100644
index 0000000..d4d0794
--- /dev/null
+++ b/gcc/ch/runtime/cause.c
@@ -0,0 +1,48 @@
+/* Implement runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+
+/*
+ * function cause_exception
+ *
+ * parameters:
+ * exname exception name
+ * file file name
+ * lineno line number
+ * user_arg user specified argument
+ *
+ * returns:
+ * void
+ *
+ * abstract:
+ * dummy for ChillLib but may be overwritten by the user
+ *
+ */
+void
+cause_exception (exname, file, lineno, user_arg)
+ char *exname;
+ char *file;
+ int lineno;
+ int user_arg;
+{
+}
diff --git a/gcc/ch/runtime/concatps.c b/gcc/ch/runtime/concatps.c
new file mode 100644
index 0000000..4dacda6
--- /dev/null
+++ b/gcc/ch/runtime/concatps.c
@@ -0,0 +1,93 @@
+/* Implement powerset-related runtime actions for CHILL.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+ Author: Bill Cox
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "powerset.h"
+
+extern void cause_exception (char *exname, char *file, int lineno);
+
+/*
+ * function __concatps
+ *
+ * parameters:
+ * OUT - pointer to output PS
+ * LEFT - pointer to left PS
+ * LEFTLEN - length of left PS in bits
+ * RIGHT - pointer to right PS
+ * RIGHTLEN - length of right PS in bits
+ *
+ * returns:
+ * void
+ *
+ * exceptions:
+ * none
+ *
+ * abstract:
+ * concatenates two powersets into the output powerset.
+ *
+ */
+
+extern void
+__pscpy (SET_WORD *dps,
+ unsigned long dbl,
+ unsigned long doffset,
+ SET_WORD *sps,
+ unsigned long sbl,
+ unsigned long start,
+ unsigned long length);
+
+void
+__concatps (out, left, leftlen, right, rightlen)
+ SET_WORD *out;
+ SET_WORD *left;
+ unsigned long leftlen;
+ SET_WORD *right;
+ unsigned long rightlen;
+{
+ /* allocated sizes for each set involved */
+ unsigned long outall, leftall, rightall;
+
+ if (!out)
+ {
+ /* FIXME: cause an exception */
+ }
+ else if (leftlen == 0 || !left)
+ {
+ if (rightlen == 0 || !right)
+ return; /* no work to do */
+ __pscpy (out, rightlen, (unsigned long)0,
+ right, rightlen, (unsigned long)0, rightlen);
+ }
+ else if (rightlen == 0 || !right)
+ {
+ if (leftlen == 0 || !left)
+ return; /* no work to do */
+ __pscpy (out, leftlen, (unsigned long)0,
+ left, leftlen, (unsigned long)0, leftlen);
+ }
+ /* copy the left powerset into bits 0..leftlen - 1 */
+ __pscpy (out, leftlen + rightlen, (unsigned long)0,
+ left, leftlen, (unsigned long)0, leftlen);
+
+ /* copy the right powerset into bits leftlen..leftlen+rightlen-1 */
+ __pscpy (out, leftlen + rightlen, leftlen,
+ right, rightlen, (unsigned long)0, rightlen);
+}
diff --git a/gcc/ch/runtime/copyps.c b/gcc/ch/runtime/copyps.c
new file mode 100644
index 0000000..226f429
--- /dev/null
+++ b/gcc/ch/runtime/copyps.c
@@ -0,0 +1,111 @@
+/* Implement POWERSET runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+#include <stdio.h>
+#include "powerset.h"
+
+/*
+ * function __powerset_copy
+ * This is more general than __psslice, since it
+ * can be told where in the destination powerset (DOFFSET
+ * parameter) to start storing the slice.
+ *
+ * parameters:
+ * dps dest powerset
+ * dbl destination bit length
+ * doffset offset bit number (zero origin)
+ * sps sourcepowerset
+ * sbl source powerset length in bits
+ * start starting bit number
+ * end ending bit number
+ *
+ * exceptions:
+ * none
+ *
+ * abstract:
+ * Extract into a powerset a slice of another powerset.
+ *
+ */
+void
+__pscpy (dps, dbl, doffset, sps, sbl, start, length)
+ SET_WORD *dps;
+ unsigned long dbl;
+ unsigned long doffset;
+ const SET_WORD*sps;
+ unsigned long sbl;
+ unsigned long start;
+ unsigned long length;
+{
+ unsigned long end = start + length - 1;
+ unsigned long src, dst;
+
+ /* assert end >= start;
+ assert end - start + 1 <= dbl;
+ assert "the sets don't overlap in memory" */
+
+ /* assert doffset >= 0 and < dbl */
+
+ for (src = start, dst = doffset; src <= end; src++, dst++)
+ {
+ char tmp;
+
+ if (sbl <= SET_CHAR_SIZE) /* fetch a bit */
+ tmp = GET_BIT_IN_CHAR (*((SET_CHAR *)sps), src);
+ else if (sbl <= SET_SHORT_SIZE)
+ tmp = GET_BIT_IN_SHORT (*((SET_SHORT *)sps), src);
+ else
+ tmp = GET_BIT_IN_WORD (sps[src / SET_WORD_SIZE], src % SET_WORD_SIZE);
+
+ if (tmp & 1)
+ {
+ if (dbl <= SET_CHAR_SIZE) /* store a 1-bit */
+ SET_BIT_IN_CHAR (*((SET_CHAR *)dps), dst);
+ else if (dbl <= SET_SHORT_SIZE)
+ SET_BIT_IN_SHORT (*((SET_SHORT *)dps), dst);
+ else
+ SET_BIT_IN_WORD (dps[dst / SET_WORD_SIZE], dst % SET_WORD_SIZE);
+ }
+ else
+ {
+ if (dbl <= SET_CHAR_SIZE) /* store a 0-bit */
+ CLEAR_BIT_IN_CHAR (*((SET_CHAR *)dps), dst);
+ else if (dbl <= SET_SHORT_SIZE)
+ CLEAR_BIT_IN_SHORT (*((SET_SHORT *)dps), dst);
+ else
+ CLEAR_BIT_IN_WORD (dps[dst / SET_WORD_SIZE], dst % SET_WORD_SIZE);
+ }
+ }
+ if (dbl <= SET_CHAR_SIZE) /* clear unused bits in output bitstring */
+ {
+ MASK_UNUSED_CHAR_BITS ((SET_CHAR *)dps, dbl);
+ }
+ else if (dbl <= SET_SHORT_SIZE)
+ {
+ MASK_UNUSED_SHORT_BITS ((SET_SHORT *)dps, dbl);
+ }
+ else
+ {
+ MASK_UNUSED_WORD_BITS ((SET_WORD *)(dps + (dbl/SET_WORD_SIZE)),
+ dbl % SET_WORD_SIZE);
+ }
+}
diff --git a/gcc/ch/runtime/eqps.c b/gcc/ch/runtime/eqps.c
new file mode 100644
index 0000000..4ac002d
--- /dev/null
+++ b/gcc/ch/runtime/eqps.c
@@ -0,0 +1,88 @@
+/* Implement POWERSET runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+#include <stdio.h>
+#include "powerset.h"
+
+/*
+ * function __eqpowerset
+ *
+ * parameters:
+ * left left powerset
+ * right right powerset
+ * bitlength length of powerset in bits
+ *
+ * returns:
+ * 1 if powersets are equal, bit for bit
+ *
+ * exceptions:
+ * none
+ *
+ * abstract:
+ * compares two powersets for equality
+ *
+ */
+int
+__eqpowerset (left, right, bitlength)
+ SET_WORD *left;
+ SET_WORD *right;
+ unsigned long bitlength;
+{
+#ifndef USE_CHARS
+ if (bitlength <= SET_CHAR_SIZE)
+ {
+ SET_CHAR c = *(SET_CHAR *)left ^ *(SET_CHAR *)right;
+ MASK_UNUSED_CHAR_BITS (&c, bitlength);
+ return (c == 0) ? 1 : 0;
+ }
+ else if (bitlength <= SET_SHORT_SIZE)
+ {
+ SET_SHORT c = *(SET_SHORT *)left ^ *(SET_SHORT *)right;
+ MASK_UNUSED_SHORT_BITS (&c, bitlength);
+ return (c == 0) ? 1 : 0;
+ }
+ else if (bitlength <= SET_WORD_SIZE)
+ {
+ SET_WORD c = *(SET_WORD *)left ^ *(SET_WORD *)right;
+ MASK_UNUSED_WORD_BITS (&c, bitlength % SET_WORD_SIZE);
+ return (c == 0) ? 1 : 0;
+ }
+ else
+#endif
+ {
+ SET_WORD c;
+ register unsigned long i;
+ unsigned long len = bitlength / SET_WORD_SIZE;
+
+ for (i = 0; i < len; i++) /* a word-oriented memcmp */
+ if (left[i] != right[i])
+ return 0;
+ /* do the last (possibly partial) word */
+ bitlength %= SET_WORD_SIZE;
+ if (bitlength == 0)
+ return 1;
+ c = left[i] ^ right[i];
+ MASK_UNUSED_WORD_BITS (&c, bitlength);
+ return (c == 0) ? 1 : 0;
+ }
+}
diff --git a/gcc/ch/runtime/fileio.h b/gcc/ch/runtime/fileio.h
new file mode 100644
index 0000000..fb15b8f
--- /dev/null
+++ b/gcc/ch/runtime/fileio.h
@@ -0,0 +1,153 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _fileio_h_
+#define _fileio_h_
+
+#include <stdio.h>
+
+#include "auxtypes.h"
+#include "ioerror.h"
+#include "iomodes.h"
+
+#define DIRSEP '/'
+
+#define TEST_FLAG(Xloc,Flag) (((Xloc)->flags) & (Flag))
+#define SET_FLAG(Xloc,Flag) (Xloc)->flags |= (Flag)
+#define CLR_FLAG(Xloc,Flag) (Xloc)->flags = ((Xloc)->flags & ~(Flag))
+
+Boolean
+__isassociated( Association_Mode* the_assoc, char* file, int line );
+
+Boolean
+__existing( Association_Mode* the_assoc, char* file, int line );
+
+Boolean
+__readable( Association_Mode* the_assoc, char* file, int line );
+
+Boolean
+__writeable( Association_Mode* the_assoc, char* file, int line );
+
+Boolean
+__indexable( Association_Mode* the_assoc, char* file, int line );
+
+Boolean
+__sequencible( Association_Mode* the_assoc, char* file, int line );
+
+Boolean
+__variable( Association_Mode* the_assoc, char* file, int line );
+
+typedef signed long int Index_t;
+
+Association_Mode*
+__associate( Association_Mode* the_assoc,
+ char* the_path,
+ int the_path_len,
+ char* the_mode,
+ int the_mode_len,
+ char* file,
+ int line );
+
+void
+__dissociate( Association_Mode* the_assoc, char* file, int line );
+
+void
+__create( Association_Mode* the_assoc, char* file, int line );
+
+void
+__delete( Association_Mode* the_assoc, char* file, int line );
+
+void
+__modify( Association_Mode* the_assoc,
+ char* the_path,
+ int the_path_len,
+ char* the_mode,
+ int the_mode_len,
+ char* file,
+ int line );
+
+void
+__connect( void* the_transfer,
+ Association_Mode* the_assoc,
+ Usage_Mode the_usage,
+ Where_Mode the_where,
+ Boolean with_index,
+ signed long the_index,
+ char* file,
+ int line );
+
+void
+__disconnect( void* the_transfer, char* file, int line );
+
+Association_Mode*
+__getassociation( void* the_transfer, char* file, int line );
+
+Usage_Mode
+__getusage( void* the_transfer, char* file, int line );
+
+Boolean
+__outoffile( void* the_transfer, char* file, int line );
+
+void*
+__readrecord( Access_Mode* the_access,
+ signed long the_index,
+ char* the_buf_addr,
+ char* file,
+ int line );
+
+void
+__writerecord( Access_Mode* the_access,
+ signed long the_index,
+ char* the_val_addr,
+ unsigned long the_val_len,
+ char* file,
+ int line );
+
+VarString*
+__gettextrecord( Text_Mode* the_text, char* file, int line );
+
+unsigned long
+__gettextindex( Text_Mode* the_text, char* file, int line );
+
+Access_Mode*
+__gettextaccess( Text_Mode* the_text, char* file, int line );
+
+Boolean
+__eoln( Text_Mode* the_text, char* file, int line );
+
+void
+__settextrecord( Text_Mode* the_text,
+ VarString* the_text_rec,
+ char* file,
+ int line );
+
+void
+__settextindex( Text_Mode* the_text,
+ signed long the_text_index,
+ char* file,
+ int line );
+
+void
+__settextaccess( Text_Mode* the_text,
+ Access_Mode* the_access,
+ char* file,
+ int line );
+
+#endif
diff --git a/gcc/ch/runtime/flsetps.c b/gcc/ch/runtime/flsetps.c
new file mode 100644
index 0000000..1a79076
--- /dev/null
+++ b/gcc/ch/runtime/flsetps.c
@@ -0,0 +1,107 @@
+/* Implement POWERSET runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+#include <stdio.h>
+#include "powerset.h"
+
+extern void __cause_ex1 (char *exname, char *file, int lineno);
+
+/*
+ * function __flsetpowerset
+ *
+ * parameters:
+ * ps powerset
+ * bitlength length of powerset
+ * minval set low bound
+ * filename caller's file name
+ * lineno caller's line number
+ *
+ * returns:
+ * int largest enumeration value
+ * exceptions:
+ * "empty" if set is empty
+ *
+ * abstract:
+ * Find last bit set in a powerset and return the corresponding value.
+ *
+ */
+long
+__flsetpowerset (ps, bitlength, minval, filename, lineno)
+ SET_WORD *ps;
+ unsigned long bitlength;
+ long minval;
+ char *filename;
+ int lineno;
+{
+ unsigned long bitno;
+
+ if (bitlength <= SET_CHAR_SIZE)
+ {
+ SET_CHAR cset = *((SET_CHAR *)ps);
+ if (cset != 0)
+ {
+ /* found a bit set .. calculate which */
+ for (bitno = SET_CHAR_SIZE; bitno >= 1; bitno--)
+ if (GET_BIT_IN_CHAR (cset, bitno - 1))
+ break;
+ /* return its index */
+ return bitno + minval - 1;
+ }
+ }
+ else if (bitlength <= SET_SHORT_SIZE)
+ {
+ SET_SHORT sset = *((SET_SHORT *)ps);
+ if (sset != 0)
+ {
+ /* found a bit set .. calculate which */
+ for (bitno = SET_SHORT_SIZE; bitno >= 1; bitno--)
+ if (GET_BIT_IN_SHORT (sset, bitno - 1))
+ break;
+ /* return its index */
+ return bitno + minval - 1;
+ }
+ }
+ else /* set composed of array of one or more WORDs */
+ {
+ SET_WORD *endp = ps;
+ SET_WORD *p = ps + BITS_TO_WORDS(bitlength) - 1;
+ unsigned long cnt;
+
+ /* FIXME: bitorder problems? */
+ for (cnt = ((bitlength - 1) / SET_WORD_SIZE) * SET_WORD_SIZE;
+ p >= endp; p--, cnt -= SET_WORD_SIZE)
+ {
+ SET_WORD c = *p;
+ if (c)
+ {
+ /* found a bit set .. calculate which */
+ for (bitno = SET_WORD_SIZE; bitno >= 1; bitno--)
+ if (GET_BIT_IN_WORD (c, bitno - 1))
+ break;
+ return cnt + bitno + minval - 1;
+ }
+ }
+ }
+ /* no bits found - raise exception */
+ __cause_ex1 ("empty", filename, lineno);
+}
diff --git a/gcc/ch/runtime/format.h b/gcc/ch/runtime/format.h
new file mode 100644
index 0000000..8b554f4
--- /dev/null
+++ b/gcc/ch/runtime/format.h
@@ -0,0 +1,71 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _format_h_
+#define _format_h_
+
+#include "iomodes.h"
+#include "fileio.h"
+
+extern Text_Mode __stdin_text;
+extern Text_Mode __stdout_text;
+extern Text_Mode __stderr_text;
+
+void
+__readtext_f( Text_Mode* TextLoc,
+ signed long Index,
+ char* fmtptr,
+ int fmtlen,
+ __tmp_IO_list* ioptr,
+ int iolen,
+ char* file,
+ int line );
+
+void
+__readtext_s( void* string_ptr,
+ int string_len,
+ char* fmtptr,
+ int fmtlen,
+ __tmp_IO_list* ioptr,
+ int iolen,
+ char* file,
+ int line );
+
+void
+__writetext_f( Text_Mode* Text_Loc,
+ signed long Index,
+ char* fmtptr,
+ int fmtlen,
+ __tmp_IO_list* ioptr,
+ int iolen,
+ char* file,
+ int line );
+
+void
+__writetext_s( void* string_ptr,
+ int string_len,
+ char* fmtptr,
+ int fmtlen,
+ __tmp_IO_list* ioptr,
+ int iolen,
+ char* file,
+ int line );
+
+#endif _format_h_
diff --git a/gcc/ch/runtime/getassoc.c b/gcc/ch/runtime/getassoc.c
new file mode 100644
index 0000000..1bc92aa
--- /dev/null
+++ b/gcc/ch/runtime/getassoc.c
@@ -0,0 +1,37 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fileio.h"
+
+Association_Mode*
+__getassociation( void* the_transfer, char* file, int line )
+{
+ Access_Mode* the_access;
+
+ if( !the_transfer )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
+
+ if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
+ the_access = ((Text_Mode*)the_transfer)->access_sub;
+ else
+ the_access = (Access_Mode*)the_transfer;
+
+ return the_access->association;
+}
diff --git a/gcc/ch/runtime/gettextaccess.c b/gcc/ch/runtime/gettextaccess.c
new file mode 100644
index 0000000..28f976d
--- /dev/null
+++ b/gcc/ch/runtime/gettextaccess.c
@@ -0,0 +1,31 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fileio.h"
+
+Access_Mode*
+__gettextaccess( Text_Mode* the_text, char* file, int line )
+{
+ if( !the_text )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_TEXT );
+
+ return the_text->access_sub;
+}
+
diff --git a/gcc/ch/runtime/getusage.c b/gcc/ch/runtime/getusage.c
new file mode 100644
index 0000000..2fcaf77
--- /dev/null
+++ b/gcc/ch/runtime/getusage.c
@@ -0,0 +1,40 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fileio.h"
+
+Usage_Mode
+__getusage( void* the_transfer, char* file, int line )
+{
+ Access_Mode* the_access;
+
+ if( !the_transfer )
+ CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
+
+ if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
+ the_access = ((Text_Mode*)the_transfer)->access_sub;
+ else
+ the_access = (Access_Mode*)the_transfer;
+
+ if( !the_access->association )
+ CHILLEXCEPTION( file, line, NOTCONNECTED, IS_NOT_CONNECTED );
+ return the_access->association->usage;
+}
+
diff --git a/gcc/ch/runtime/inps.c b/gcc/ch/runtime/inps.c
new file mode 100644
index 0000000..d01d76a
--- /dev/null
+++ b/gcc/ch/runtime/inps.c
@@ -0,0 +1,65 @@
+/* Implement POWERSET runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+#include <stdio.h>
+#include "powerset.h"
+
+/*
+ * function __inpowerset
+ *
+ * parameters:
+ * bitno bit number within set
+ * powerset the powerset
+ * bitlength length of powerset in bits
+ * minval number of lowest bit stored
+ *
+ * returns:
+ * int 1 .. found
+ * 0 .. not found
+ *
+ * exceptions:
+ * rangefail
+ *
+ * abstract:
+ * checks if a given value is included in a powerset
+ *
+ */
+int
+__inpowerset (bitno, powerset, bitlength, minval)
+ unsigned long bitno;
+ SET_WORD *powerset;
+ unsigned long bitlength;
+ long minval;
+{
+ if (bitno < minval || (bitno - minval) >= bitlength)
+ return 0;
+
+ bitno -= minval;
+ if (bitlength <= SET_CHAR_SIZE)
+ return GET_BIT_IN_CHAR (*((SET_CHAR *)powerset), bitno);
+ else if (bitlength <= SET_SHORT_SIZE)
+ return GET_BIT_IN_SHORT (*((SET_SHORT *)powerset), bitno);
+ else
+ return GET_BIT_IN_WORD (powerset[bitno / SET_WORD_SIZE],
+ bitno % SET_WORD_SIZE);
+}
diff --git a/gcc/ch/runtime/ioerror.c b/gcc/ch/runtime/ioerror.c
new file mode 100644
index 0000000..8c9fad4
--- /dev/null
+++ b/gcc/ch/runtime/ioerror.c
@@ -0,0 +1,45 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <setjmp.h>
+
+/* define names of IO-exceptions */
+
+char * __IO_exception_names[] =
+{
+ "UNUSED",
+ "notassociated",
+ "associatefail",
+ "createfail",
+ "deletefail",
+ "modifyfail",
+ "connectfail",
+ "notconnected",
+ "empty",
+ "rangefail",
+ "spacefail",
+ "readfail",
+ "writefail",
+ "textfail",
+};
+
+jmp_buf __io_exception;
+
+jmp_buf __rw_exception;
diff --git a/gcc/ch/runtime/ioerror.h b/gcc/ch/runtime/ioerror.h
new file mode 100644
index 0000000..e2ddfe5
--- /dev/null
+++ b/gcc/ch/runtime/ioerror.h
@@ -0,0 +1,161 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _ioerror_h_
+#define _ioerror_h_
+
+#include <setjmp.h>
+
+/* Note: numbers must be in the same order as
+ strings in ioerror.c */
+typedef enum
+{ NOTASSOCIATED = 1,
+ ASSOCIATEFAIL,
+ CREATEFAIL,
+ DELETEFAIL,
+ MODIFYFAIL,
+ CONNECTFAIL,
+ NOTCONNECTED,
+ EMPTY,
+ RANGEFAIL,
+ SPACEFAIL,
+ READFAIL,
+ WRITEFAIL,
+ TEXTFAIL
+} io_exceptions_t;
+
+#ifndef FIRST_IO_ERROR_NUMBER
+#define FIRST_IO_ERROR_NUMBER 0
+#endif
+
+typedef enum {
+ FIRST_AND_UNUSED = FIRST_IO_ERROR_NUMBER,
+ INTERNAL_ERROR,
+ INVALID_IO_LIST,
+ REPFAC_OVERFLOW,
+ CLAUSE_WIDTH_OVERFLOW,
+ UNMATCHED_CLOSING_PAREN,
+ UNMATCHED_OPENING_PAREN,
+ BAD_FORMAT_SPEC_CHAR,
+ NO_PAD_CHAR,
+ IO_CONTROL_NOT_VALID,
+ DUPLICATE_QUALIFIER,
+ NO_FRACTION_WIDTH,
+ NO_EXPONENT_WIDTH,
+ FRACTION_WIDTH_OVERFLOW,
+ EXPONENT_WIDTH_OVERFLOW,
+ NO_FRACTION,
+ NO_EXPONENT,
+ NEGATIVE_FIELD_WIDTH,
+ TEXT_LOC_OVERFLOW,
+ IOLIST_EXHAUSTED,
+ CONVCODE_MODE_MISFIT,
+ SET_CONVERSION_ERROR,
+ BOOL_CONVERSION_ERROR,
+ NON_INT_FIELD_WIDTH,
+ EXCESS_IOLIST_ELEMENTS,
+ NOT_ENOUGH_CHARS,
+ NO_CHARS_FOR_INT,
+ NO_CHARS_FOR_FLOAT,
+ NO_EXPONENT_VAL,
+ INT_VAL_OVERFLOW,
+ REAL_OVERFLOW,
+ NO_DIGITS_FOR_INT,
+ NO_DIGITS_FOR_FLOAT,
+ NO_CHARS_FOR_SET,
+ NO_CHARS_FOR_CHAR,
+ NO_CHARS_FOR_BOOLS,
+ NO_CHARS_FOR_CHARS,
+ NO_CHARS_FOR_TEXT,
+ NO_CHARS_FOR_EDIT,
+ NO_SPACE_TO_SKIP,
+ FORMAT_TEXT_MISMATCH,
+ INTEGER_RANGE_ERROR,
+ SET_RANGE_ERROR,
+ CHAR_RANGE_ERROR,
+ INVALID_CHAR,
+/* end of formatting errors */
+ NULL_ASSOCIATION,
+ NULL_ACCESS,
+ NULL_TEXT,
+ IS_NOT_ASSOCIATED,
+ IS_ASSOCIATED,
+ GETCWD_FAILS,
+ INVALID_ASSOCIATION_MODE,
+ FILE_EXISTING,
+ CREATE_FAILS,
+ DELETE_FAILS,
+ RENAME_FAILS,
+ IMPL_RESTRICTION,
+ NOT_EXISTING,
+ NOT_READABLE,
+ NOT_WRITEABLE,
+ NOT_INDEXABLE,
+ NOT_SEQUENCIBLE,
+ NO_CURRENT_POS,
+ NOT_VARIABLE,
+ NOT_FIXED,
+ NOT_INDEXED,
+ LENGTH_CHANGE,
+ LSEEK_FAILS,
+ BUFFER_ALLOC,
+ OPEN_FAILS,
+ NO_ACCESS_SUBLOCATION,
+ BAD_INDEX,
+ IS_NOT_CONNECTED,
+ NO_PATH_NAME,
+ PATHNAME_ALLOC,
+ BAD_USAGE,
+ OUT_OF_FILE,
+ NULL_STORE_LOC,
+ STORE_LOC_ALLOC,
+ OS_IO_ERROR,
+ RECORD_TOO_LONG,
+ RECORD_TOO_SHORT,
+ BAD_TEXTINDEX,
+ NULL_TEXTREC
+} io_info_word_t;
+
+
+extern
+char* io_info_text [];
+
+extern
+char* exc_text [];
+
+extern
+jmp_buf __io_exception;
+
+extern
+jmp_buf __rw_exception;
+
+void __cause_exception (char *ex, char* f, int line, int info);
+extern char * __IO_exception_names[];
+
+#define IOEXCEPTION(EXC,INFO) \
+ longjmp( __io_exception, (EXC<<16) + INFO )
+
+#define RWEXCEPTION(EXC,INFO) \
+ longjmp( __rw_exception, (EXC<<16) + INFO )
+
+#define CHILLEXCEPTION(FILE,LINE,EXC,INFO) \
+ __cause_exception (__IO_exception_names[EXC], FILE, LINE, INFO);
+
+#endif
diff --git a/gcc/ch/runtime/iomodes.h b/gcc/ch/runtime/iomodes.h
new file mode 100644
index 0000000..8e254e2
--- /dev/null
+++ b/gcc/ch/runtime/iomodes.h
@@ -0,0 +1,251 @@
+/* Implement Input/Output runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _iomodes_h_
+#define _iomodes_h_
+
+#include "auxtypes.h"
+
+typedef enum { ReadOnly, WriteOnly, ReadWrite
+} Usage_Mode;
+
+typedef enum { First, Same, Last
+} Where_Mode;
+
+typedef enum { None, Fixed, VaryingChars
+} Record_t;
+
+/* association flags */
+#define IO_ISASSOCIATED 0x00000001
+#define IO_EXISTING 0x00000002
+#define IO_READABLE 0x00000004
+#define IO_WRITEABLE 0x00000008
+#define IO_INDEXABLE 0x00000010
+#define IO_SEQUENCIBLE 0x00000020
+#define IO_VARIABLE 0x00000040
+#define IO_FIRSTLINE 0x00000100
+#define IO_FORCE_PAGE 0x00000200
+
+struct Access_Mode;
+
+#define READBUFLEN 512
+typedef struct
+{
+ unsigned long len;
+ unsigned long cur;
+ char buf[READBUFLEN];
+} readbuf_t;
+
+typedef struct Association_Mode {
+ unsigned long flags; /* INIT = 0 */
+ char* pathname;
+ struct Access_Mode* access;
+ int handle;
+ readbuf_t* bufptr;
+ long syserrno;
+ char usage;
+ char ctl_pre;
+ char ctl_post;
+} Association_Mode;
+
+/*
+ rectype indexed max. reclength act. reclength
+ ---------------------------------------------------
+ None T/F 0
+ Fixed T/F SIZE(recmode) = SIZE(recmode)
+ Varying F SIZE(recmode) >= length
+*/
+
+/* access/text flags */
+#define IO_TEXTLOCATION 0x80000000
+#define IO_INDEXED 0x00000001
+#define IO_TEXTIO 0x00000002
+#define IO_OUTOFFILE 0x00010000
+
+typedef struct Access_Mode {
+ unsigned long flags; /* INIT */
+ unsigned long reclength; /* INIT */
+ signed long lowindex; /* INIT */
+ signed long highindex; /* INIT */
+ Association_Mode* association;
+ unsigned long base;
+ char* store_loc;
+ Record_t rectype; /* INIT */
+} Access_Mode;
+
+typedef struct Text_Mode {
+ unsigned long flags; /* INIT */
+ VarString* text_record; /* INIT */
+ Access_Mode* access_sub; /* INIT */
+ unsigned long actual_index;
+} Text_Mode;
+
+typedef enum
+{
+ __IO_UNUSED,
+
+ __IO_ByteVal,
+ __IO_UByteVal,
+ __IO_IntVal,
+ __IO_UIntVal,
+ __IO_LongVal,
+ __IO_ULongVal,
+
+ __IO_ByteLoc,
+ __IO_UByteLoc,
+ __IO_IntLoc,
+ __IO_UIntLoc,
+ __IO_LongLoc,
+ __IO_ULongLoc,
+
+ __IO_ByteRangeLoc,
+ __IO_UByteRangeLoc,
+ __IO_IntRangeLoc,
+ __IO_UIntRangeLoc,
+ __IO_LongRangeLoc,
+ __IO_ULongRangeLoc,
+
+ __IO_BoolVal,
+ __IO_BoolLoc,
+ __IO_BoolRangeLoc,
+
+ __IO_SetVal,
+ __IO_SetLoc,
+ __IO_SetRangeLoc,
+
+ __IO_CharVal,
+ __IO_CharLoc,
+ __IO_CharRangeLoc,
+
+ __IO_CharStrLoc,
+
+ __IO_CharVaryingLoc,
+
+ __IO_BitStrLoc,
+
+ __IO_RealVal,
+ __IO_RealLoc,
+ __IO_LongRealVal,
+ __IO_LongRealLoc
+} __tmp_IO_enum;
+
+typedef struct
+{
+ long value;
+ char* name;
+} __tmp_IO_enum_table_type;
+
+typedef struct
+{
+ long value;
+ __tmp_IO_enum_table_type* name_table;
+} __tmp_WIO_set;
+
+typedef struct
+{
+ char* ptr;
+ long lower;
+ long upper;
+} __tmp_IO_charrange;
+
+typedef union
+{
+ signed long slong;
+ unsigned long ulong;
+} __tmp_IO_long;
+
+typedef struct
+{
+ void* ptr;
+ __tmp_IO_long lower;
+ __tmp_IO_long upper;
+} __tmp_IO_intrange;
+
+typedef struct
+{
+ void* ptr;
+ unsigned long lower;
+ unsigned long upper;
+} __tmp_RIO_boolrange;
+
+typedef struct
+{
+ void* ptr;
+ long length;
+ __tmp_IO_enum_table_type* name_table;
+} __tmp_RIO_set;
+
+typedef struct
+{
+ void* ptr;
+ long length;
+ __tmp_IO_enum_table_type* name_table;
+ unsigned long lower;
+ unsigned long upper;
+} __tmp_RIO_setrange;
+
+typedef struct
+{
+ char* string;
+ long string_length;
+} __tmp_IO_charstring;
+
+typedef union
+{
+ char __valbyte;
+ unsigned char __valubyte;
+ short __valint;
+ unsigned short __valuint;
+ long __vallong;
+ unsigned long __valulong;
+ void* __locint;
+ __tmp_IO_intrange __locintrange;
+
+ unsigned char __valbool;
+ unsigned char* __locbool;
+ __tmp_RIO_boolrange __locboolrange;
+
+ __tmp_WIO_set __valset;
+ __tmp_RIO_set __locset;
+ __tmp_RIO_setrange __locsetrange;
+
+ unsigned char __valchar;
+ unsigned char* __locchar;
+ __tmp_IO_charrange __loccharrange;
+
+ __tmp_IO_charstring __loccharstring;
+
+ float __valreal;
+ float* __locreal;
+ double __vallongreal;
+ double* __loclongreal;
+} __tmp_IO_union;
+
+/*
+ * CAUTION: The longest variant of __tmp_IO_union is 5 words long.
+ * Together with __descr this caters for double alignment where required.
+ */
+typedef struct
+{
+ __tmp_IO_union __t;
+ __tmp_IO_enum __descr;
+} __tmp_IO_list;
+
+#endif
diff --git a/gcc/ch/runtime/ltps.c b/gcc/ch/runtime/ltps.c
new file mode 100644
index 0000000..747be42
--- /dev/null
+++ b/gcc/ch/runtime/ltps.c
@@ -0,0 +1,86 @@
+/* Implement POWERSET runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+#include <stdio.h>
+#include "powerset.h"
+
+/*
+ * function __ltpowerset
+ *
+ * parameters:
+ * left powerset
+ * right powerset
+ * bitlength length of powerset
+ *
+ * returns:
+ * int 1 .. left is proper subset of right
+ * (excludes case where left == right)
+ * 0 .. not
+ *
+ * abstract:
+ * check if one powerset is included in another
+ *
+ */
+int
+__ltpowerset (left, right, bitlength)
+ SET_WORD *left;
+ SET_WORD *right;
+ unsigned long bitlength;
+{
+ if (bitlength <= SET_CHAR_SIZE)
+ {
+ if ((*((SET_CHAR *)left) & *((SET_CHAR *)right))
+ != *((SET_CHAR *)left))
+ return 0;
+ if (*((SET_CHAR *)left) != *((SET_CHAR *)right))
+ return 1;
+ return 0;
+ }
+ else if (bitlength <= SET_SHORT_SIZE)
+ {
+ if ((*((SET_SHORT *)left) & *((SET_SHORT *)right))
+ != *((SET_SHORT *)left))
+ return 0;
+ if (*((SET_SHORT *)left) != *((SET_SHORT *)right))
+ return 1;
+ return 0;
+ }
+ else
+ {
+ SET_WORD *endp = left + BITS_TO_WORDS(bitlength);
+ int all_equal = 1; /* assume all bits are equal */
+
+ while (left < endp)
+ {
+ if ((*right & *left) != *left)
+ return 0;
+ if (*left != *right)
+ all_equal = 0;
+ left++;
+ right++;
+ }
+ if (left == endp && all_equal) /* exclude TRUE return for == case */
+ return 0;
+ return 1;
+ }
+}
diff --git a/gcc/ch/runtime/ltstr.c b/gcc/ch/runtime/ltstr.c
new file mode 100644
index 0000000..683a947
--- /dev/null
+++ b/gcc/ch/runtime/ltstr.c
@@ -0,0 +1,55 @@
+/* Implement string-related runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Bill Cox
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/*
+ * function __ltstring
+ *
+ * parameters:
+ * S1 - pointer to left string
+ * LEN1 - length of left string
+ * S2 - pointer to right string
+ * LEN2 - length of right string
+ *
+ * returns:
+ * 1 if left string is a proper subset of the right string, 0 otherwise
+ *
+ * exceptions:
+ * none
+ *
+ * abstract:
+ * compares two character strings for subset relationship
+ *
+ */
+
+int __ltstring (s1, len1, s2, len2)
+ char *s1;
+ int len1;
+ char *s2;
+ int len2;
+{
+ int i;
+
+ i = memcmp (s1, s2, MIN (len1, len2));
+ if (i)
+ return (i < 0);
+ return (len1 < len2);
+}
diff --git a/gcc/ch/runtime/rts.h b/gcc/ch/runtime/rts.h
new file mode 100644
index 0000000..27019e7
--- /dev/null
+++ b/gcc/ch/runtime/rts.h
@@ -0,0 +1,52 @@
+/* GNU CHILL compiler regression test file
+ Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU CC.
+
+ GNU CC 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 2, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __rts_h_
+#define __rts_h_
+
+typedef enum
+{
+ UNUSED,
+ Process,
+ Signal,
+ Buffer,
+ Event,
+ Synonym,
+ Exception,
+ LAST_AND_UNUSED,
+} TaskingEnum;
+
+typedef void (*EntryPoint) ();
+
+typedef struct
+{
+ char *name;
+ short *value;
+ int value_defined;
+ EntryPoint entry;
+ unsigned char /*TaskingEnum*/ type;
+} TaskingStruct;
+
+typedef struct
+{
+ short ptype;
+ short pcopy;
+} INSTANCE;
+
+#endif /* __rts_h_ */
diff --git a/gcc/ch/runtime/sliceps.c b/gcc/ch/runtime/sliceps.c
new file mode 100644
index 0000000..939a0b8
--- /dev/null
+++ b/gcc/ch/runtime/sliceps.c
@@ -0,0 +1,65 @@
+/* Implement POWERSET runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser, et al
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+#include <stdio.h>
+#include "powerset.h"
+
+/*
+ * function __powerset_slice
+ *
+ * parameters:
+ * dps dest powerset
+ * dbl destination bit length
+ * sps sourcepowerset
+ * sbl source powerset length in bits
+ * start starting bit number
+ * end ending bit number
+ *
+ * exceptions:
+ * none
+ *
+ * abstract:
+ * Extract into a powerset a slice of another powerset.
+ *
+ */
+extern void
+__pscpy (SET_WORD *dps,
+ unsigned long dbl,
+ unsigned long doffset,
+ SET_WORD *sps,
+ unsigned long sbl,
+ unsigned long start,
+ unsigned long length);
+
+void
+__psslice (dps, dbl, sps, sbl, start, length)
+ SET_WORD *dps;
+ unsigned long dbl;
+ SET_WORD *sps;
+ unsigned long sbl;
+ unsigned long start;
+ unsigned long length;
+{
+ /* simply supply a zero destination offset and copy the slice */
+ __pscpy (dps, dbl, (unsigned long)0, sps, sbl, start, length);
+}
diff --git a/gcc/ch/runtime/unhex.c b/gcc/ch/runtime/unhex.c
new file mode 100644
index 0000000..3bd23dc
--- /dev/null
+++ b/gcc/ch/runtime/unhex.c
@@ -0,0 +1,57 @@
+/* Implement runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+/*
+ * function unhandled_exception
+ *
+ * parameter:
+ * exname name of exception
+ * file filename
+ * lineno line number
+ * user_arg user specified argument
+ *
+ * returns:
+ * never
+ *
+ * abstract:
+ * print an error message about unhandled exception and call abort
+ *
+ */
+
+void
+unhandled_exception (exname, file, lineno, user_arg)
+ char *exname;
+ char *file;
+ int lineno;
+ int user_arg;
+{
+ sleep (1); /* give previous output a chance to finish */
+ fprintf (stderr, "ChillLib: unhandled exception `%s' in file %s at line %d\n",
+ exname, file, lineno);
+ fflush (stderr);
+ abort ();
+} /* unhandled_exception */
diff --git a/gcc/ch/runtime/unhex1.c b/gcc/ch/runtime/unhex1.c
new file mode 100644
index 0000000..375f6a5
--- /dev/null
+++ b/gcc/ch/runtime/unhex1.c
@@ -0,0 +1,58 @@
+/* Implement runtime actions for CHILL.
+ Copyright (C) 1992,1993 Free Software Foundation, Inc.
+ Author: Wilfried Moser
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define __CHILL_LIB__
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+extern void cause_exception (char *ex, char *file, int lineno, int arg);
+extern void unhandled_exception (char *ex, char *file, int lineno, int arg);
+
+/*
+ * function __unhandled_ex
+ *
+ * parameter:
+ * exname name of exception
+ * file filename
+ * lineno line number
+ *
+ * returns:
+ * never
+ *
+ * abstract:
+ * This function gets called by compiler generated code when an unhandled
+ * exception occures.
+ * First cause_exception gets called (which may be user defined) and
+ * then the standard unhandled exception routine gets called.
+ *
+ */
+
+void
+__unhandled_ex (exname, file, lineno)
+ char *exname;
+ char *file;
+ int lineno;
+{
+ cause_exception (exname, file, lineno, 0);
+ unhandled_exception (exname, file, lineno, 0);
+} /* unhandled_exception */
diff --git a/gcc/ch/satisfy.c b/gcc/ch/satisfy.c
new file mode 100644
index 0000000..a9f3c87
--- /dev/null
+++ b/gcc/ch/satisfy.c
@@ -0,0 +1,628 @@
+/* Name-satisfaction for GNU Chill compiler.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "config.h"
+#include "tree.h"
+#include "flags.h"
+#include "ch-tree.h"
+#include "lex.h"
+
+#define SATISFY(ARG) ((ARG) = satisfy(ARG, chain))
+
+extern void error PROTO((char *, ...));
+extern void error_with_decl PROTO((tree, char *, ...));
+extern void expand_decl PROTO((tree));
+extern void layout_enum PROTO((tree));
+
+struct decl_chain
+{
+ struct decl_chain *prev;
+ /* DECL can be a decl, or a POINTER_TYPE or a REFERENCE_TYPE. */
+ tree decl;
+};
+
+/* forward declaration */
+tree satisfy PROTO((tree, struct decl_chain *));
+
+static struct decl_chain dummy_chain;
+#define LOOKUP_ONLY (chain==&dummy_chain)
+
+/* Recursive helper routine to logically reverse the chain. */
+static void
+cycle_error_print (chain, decl)
+ struct decl_chain *chain;
+ tree decl;
+{
+ if (chain->decl != decl)
+ {
+ cycle_error_print (chain->prev, decl);
+ if (TREE_CODE_CLASS (TREE_CODE (chain->decl)) == 'd')
+ error_with_decl (chain->decl, " `%s', which depends on ...");
+ }
+}
+
+tree
+safe_satisfy_decl (decl, prev_chain)
+ tree decl;
+ struct decl_chain *prev_chain;
+{
+ struct decl_chain new_link;
+ struct decl_chain *link;
+ struct decl_chain *chain = prev_chain;
+ char *save_filename = input_filename;
+ int save_lineno = lineno;
+ tree result = decl;
+
+ if (decl == NULL_TREE)
+ return decl;
+
+ if (!LOOKUP_ONLY)
+ {
+ int pointer_type_breaks_cycle = 0;
+ /* Look for a cycle.
+ We could do this test more efficiently by setting a flag. FIXME */
+ for (link = prev_chain; link != NULL; link = link->prev)
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (link->decl)) != 'd')
+ pointer_type_breaks_cycle = 1;
+ if (link->decl == decl)
+ {
+ if (!pointer_type_breaks_cycle)
+ {
+ error_with_decl (decl, "Cycle: `%s' depends on ...");
+ cycle_error_print (prev_chain, decl);
+ error_with_decl (decl, " `%s'");
+ return error_mark_node;
+ }
+ /* There is a cycle, but it includes a pointer type,
+ so we're OK. However, we still have to continue
+ the satisfy (for example in case this is a TYPE_DECL
+ that points to a LANG_DECL). The cycle-check for
+ POINTER_TYPE/REFERENCE_TYPE should stop the recursion. */
+ break;
+ }
+ }
+
+ new_link.decl = decl;
+ new_link.prev = prev_chain;
+ chain = &new_link;
+ }
+
+ input_filename = DECL_SOURCE_FILE (decl);
+ lineno = DECL_SOURCE_LINE (decl);
+
+ switch ((enum chill_tree_code)TREE_CODE (decl))
+ {
+ case ALIAS_DECL:
+ if (!LOOKUP_ONLY && !DECL_POSTFIX_ALL(decl))
+ result = safe_satisfy_decl (DECL_ABSTRACT_ORIGIN (decl), chain);
+ break;
+ case BASED_DECL:
+ SATISFY (TREE_TYPE (decl));
+ SATISFY (DECL_ABSTRACT_ORIGIN (decl));
+ break;
+ case CONST_DECL:
+ SATISFY (TREE_TYPE (decl));
+ SATISFY (DECL_INITIAL (decl));
+ if (!LOOKUP_ONLY)
+ {
+ if (DECL_SIZE (decl) == 0)
+ {
+ tree init_expr = DECL_INITIAL (decl);
+ tree init_type;
+ tree specified_mode = TREE_TYPE (decl);
+
+ if (init_expr == NULL_TREE
+ || TREE_CODE (init_expr) == ERROR_MARK)
+ goto bad_const;
+ init_type = TREE_TYPE (init_expr);
+ if (specified_mode == NULL_TREE)
+ {
+ if (init_type == NULL_TREE)
+ {
+ check_have_mode (init_expr, "SYN without mode");
+ goto bad_const;
+ }
+ TREE_TYPE (decl) = init_type;
+ CH_DERIVED_FLAG (decl) = CH_DERIVED_FLAG (init_expr);
+ }
+ else if (CH_IS_ASSOCIATION_MODE (specified_mode) ||
+ CH_IS_ACCESS_MODE (specified_mode) || CH_IS_TEXT_MODE (specified_mode) ||
+ CH_IS_BUFFER_MODE (specified_mode) || CH_IS_EVENT_MODE (specified_mode))
+ {
+ error ("SYN of this mode not allowed");
+ goto bad_const;
+ }
+ else if (!CH_COMPATIBLE (init_expr, specified_mode))
+ {
+ error ("mode of SYN incompatible with value");
+ goto bad_const;
+ }
+ else if (discrete_type_p (specified_mode)
+ && TREE_CODE (init_expr) == INTEGER_CST
+ && (compare_int_csts (LT_EXPR, init_expr,
+ TYPE_MIN_VALUE (specified_mode))
+ || compare_int_csts (GT_EXPR, init_expr,
+ TYPE_MAX_VALUE(specified_mode))
+ ))
+ {
+ error ("SYN value outside range of its mode");
+ /* set an always-valid initial value to prevent
+ other errors. */
+ DECL_INITIAL (decl) = TYPE_MIN_VALUE (specified_mode);
+ }
+ else if (CH_STRING_TYPE_P (specified_mode)
+ && (init_type && CH_STRING_TYPE_P (init_type))
+ && integer_zerop (string_assignment_condition (specified_mode, init_expr)))
+ {
+ error ("INIT string too large for mode");
+ DECL_INITIAL (decl) = error_mark_node;
+ }
+ else
+ {
+ struct ch_class class;
+ class.mode = TREE_TYPE (decl);
+ class.kind = CH_VALUE_CLASS;
+ DECL_INITIAL (decl)
+ = convert_to_class (class, DECL_INITIAL (decl));
+ }
+ /* DECL_SIZE is set to prevent re-doing this stuff. */
+ DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (decl));
+ if (! TREE_CONSTANT (DECL_INITIAL (decl))
+ && TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK)
+ {
+ error_with_decl (decl,
+ "value of %s is not a valid constant");
+ DECL_INITIAL (decl) = error_mark_node;
+ }
+ }
+ result = DECL_INITIAL (decl);
+ }
+ break;
+ bad_const:
+ DECL_INITIAL (decl) = error_mark_node;
+ TREE_TYPE (decl) = error_mark_node;
+ return error_mark_node;
+ case FUNCTION_DECL:
+ SATISFY (TREE_TYPE (decl));
+ if (CH_DECL_PROCESS (decl))
+ safe_satisfy_decl (DECL_TASKING_CODE_DECL (decl),
+ prev_chain);
+ break;
+ case PARM_DECL:
+ SATISFY (TREE_TYPE (decl));
+ break;
+ /* RESULT_DECL doesn't need to be satisfied;
+ it's only built internally in pass 2 */
+ case TYPE_DECL:
+ SATISFY (TREE_TYPE (decl));
+ if (CH_DECL_SIGNAL (decl))
+ safe_satisfy_decl (DECL_TASKING_CODE_DECL (decl),
+ prev_chain);
+ if (!LOOKUP_ONLY)
+ {
+ if (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE)
+ TYPE_NAME (TREE_TYPE (decl)) = decl;
+ layout_decl (decl, 0);
+ if (CH_DECL_SIGNAL (decl) && CH_TYPE_NONVALUE_P (TREE_TYPE (decl)))
+ error ("mode with non-value property in signal definition");
+ result = TREE_TYPE (decl);
+ }
+ break;
+ case VAR_DECL:
+ SATISFY (TREE_TYPE (decl));
+ if (!LOOKUP_ONLY)
+ {
+ layout_decl (decl, 0);
+ if (TREE_READONLY (TREE_TYPE (decl)))
+ TREE_READONLY (decl) = 1;
+ }
+ break;
+ default:
+ ;
+ }
+
+ /* Now set the DECL_RTL, if needed. */
+ if (!LOOKUP_ONLY && DECL_RTL (decl) == 0
+ && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == CONST_DECL))
+ {
+ if (TREE_CODE (decl) == FUNCTION_DECL && decl_function_context (decl))
+ make_function_rtl (decl);
+ else if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+ expand_decl (decl);
+ else
+ { char * asm_name;
+ if (current_module == 0 || TREE_PUBLIC (decl)
+ || current_function_decl)
+ asm_name = NULL;
+ else
+ {
+ asm_name = (char*)
+ alloca (IDENTIFIER_LENGTH (current_module->prefix_name)
+ + IDENTIFIER_LENGTH (DECL_NAME (decl)) + 3);
+ sprintf (asm_name, "%s__%s",
+ IDENTIFIER_POINTER (current_module->prefix_name),
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ }
+ make_decl_rtl (decl, asm_name, TREE_PUBLIC (decl));
+ }
+ }
+
+ input_filename = save_filename;
+ lineno = save_lineno;
+
+ return result;
+}
+
+tree
+satisfy_decl (decl, lookup_only)
+ tree decl;
+ int lookup_only;
+{
+ return safe_satisfy_decl (decl, lookup_only ? &dummy_chain : NULL);
+}
+
+static void
+satisfy_list (exp, chain)
+ register tree exp;
+ struct decl_chain *chain;
+{
+ for (; exp != NULL_TREE; exp = TREE_CHAIN (exp))
+ {
+ SATISFY (TREE_VALUE (exp));
+ SATISFY (TREE_PURPOSE (exp));
+ }
+}
+
+static void
+satisfy_list_values (exp, chain)
+ register tree exp;
+ struct decl_chain *chain;
+{
+ for (; exp != NULL_TREE; exp = TREE_CHAIN (exp))
+ {
+ SATISFY (TREE_VALUE (exp));
+ }
+}
+
+tree
+satisfy (exp, chain)
+ tree exp;
+ struct decl_chain *chain;
+{
+ int arg_length;
+ int i;
+ tree decl;
+
+ if (exp == NULL_TREE)
+ return NULL_TREE;
+
+#if 0
+ if (!UNSATISFIED (exp))
+ return exp;
+#endif
+
+ switch (TREE_CODE_CLASS (TREE_CODE (exp)))
+ {
+ case 'd':
+ if (!LOOKUP_ONLY)
+ return safe_satisfy_decl (exp, chain);
+ break;
+ case 'r':
+ case 's':
+ case '<':
+ case 'e':
+ switch ((enum chill_tree_code)TREE_CODE (exp))
+ {
+ case REPLICATE_EXPR:
+ goto binary_op;
+ case TRUTH_NOT_EXPR:
+ goto unary_op;
+ case COMPONENT_REF:
+ SATISFY (TREE_OPERAND (exp, 0));
+ if (!LOOKUP_ONLY && TREE_TYPE (exp) == NULL_TREE)
+ return resolve_component_ref (exp);
+ return exp;
+ case CALL_EXPR:
+ SATISFY (TREE_OPERAND (exp, 0));
+ SATISFY (TREE_OPERAND (exp, 1));
+ if (!LOOKUP_ONLY && TREE_TYPE (exp) == NULL_TREE)
+ return build_generalized_call (TREE_OPERAND (exp, 0),
+ TREE_OPERAND (exp, 1));
+ return exp;
+ case CONSTRUCTOR:
+ { tree link = TREE_OPERAND (exp, 1);
+ int expand_needed = TREE_TYPE (exp)
+ && TREE_CODE_CLASS (TREE_CODE (TREE_TYPE (exp))) != 't';
+ for (; link != NULL_TREE; link = TREE_CHAIN (link))
+ {
+ SATISFY (TREE_VALUE (link));
+ if (!TUPLE_NAMED_FIELD (link))
+ SATISFY (TREE_PURPOSE (link));
+ }
+ SATISFY (TREE_TYPE (exp));
+ if (expand_needed && !LOOKUP_ONLY)
+ {
+ tree type = TREE_TYPE (exp);
+ TREE_TYPE (exp) = NULL_TREE; /* To force expansion. */
+ return chill_expand_tuple (type, exp);
+ }
+ return exp;
+ }
+ default:
+ ;
+ }
+ arg_length = tree_code_length[TREE_CODE (exp)];
+ for (i = 0; i < arg_length; i++)
+ SATISFY (TREE_OPERAND (exp, i));
+ return exp;
+ case '1':
+ unary_op:
+ SATISFY (TREE_OPERAND (exp, 0));
+ if ((enum chill_tree_code)TREE_CODE (exp) == PAREN_EXPR)
+ return TREE_OPERAND (exp, 0);
+ if (!LOOKUP_ONLY)
+ return finish_chill_unary_op (exp);
+ break;
+ case '2':
+ binary_op:
+ SATISFY (TREE_OPERAND (exp, 0));
+ SATISFY (TREE_OPERAND (exp, 1));
+ if (!LOOKUP_ONLY && TREE_CODE (exp) != RANGE_EXPR)
+ return finish_chill_binary_op (exp);
+ break;
+ case 'x':
+ switch ((enum chill_tree_code)TREE_CODE (exp))
+ {
+ case IDENTIFIER_NODE:
+ decl = lookup_name (exp);
+ if (decl == NULL)
+ {
+ if (LOOKUP_ONLY)
+ return exp;
+ error ("undeclared identifier `%s'", IDENTIFIER_POINTER (exp));
+ return error_mark_node;
+ }
+ if (LOOKUP_ONLY)
+ return decl;
+ return safe_satisfy_decl (decl, chain);
+ case TREE_LIST:
+ satisfy_list (exp, chain);
+ break;
+ default:
+ ;
+ }
+ break;
+ case 't':
+ /* If TYPE_SIZE is non-NULL, exp and its subfields has already been
+ satified and laid out. The exception is pointer and reference types,
+ which we layout before we lay out their TREE_TYPE. */
+ if (TYPE_SIZE (exp) && TREE_CODE (exp) != POINTER_TYPE
+ && TREE_CODE (exp) != REFERENCE_TYPE)
+ return exp;
+ if (TYPE_MAIN_VARIANT (exp) != exp)
+ SATISFY (TYPE_MAIN_VARIANT (exp));
+ switch ((enum chill_tree_code)TREE_CODE (exp))
+ {
+ case LANG_TYPE:
+ {
+ tree d = TYPE_DOMAIN (exp);
+ tree t = satisfy (TREE_TYPE (exp), chain);
+ SATISFY (d);
+ /* It is possible that one of the above satisfy calls recursively
+ caused exp to be satisfied, in which case we're done. */
+ if (TREE_CODE (exp) != LANG_TYPE)
+ return exp;
+ TREE_TYPE (exp) = t;
+ TYPE_DOMAIN (exp) = d;
+ if (!LOOKUP_ONLY)
+ exp = smash_dummy_type (exp);
+ }
+ break;
+ case ARRAY_TYPE:
+ SATISFY (TREE_TYPE (exp));
+ SATISFY (TYPE_DOMAIN (exp));
+ SATISFY (TYPE_ATTRIBUTES (exp));
+ if (!LOOKUP_ONLY)
+ CH_TYPE_NONVALUE_P (exp) = CH_TYPE_NONVALUE_P (TREE_TYPE (exp));
+ if (!TYPE_SIZE (exp) && !LOOKUP_ONLY)
+ exp = layout_chill_array_type (exp);
+ break;
+ case FUNCTION_TYPE:
+ SATISFY (TREE_TYPE (exp));
+ if (TREE_CODE_CLASS (TREE_CODE (TREE_TYPE (exp))) != 't'
+ && !LOOKUP_ONLY && TREE_CODE (TREE_TYPE (exp)) != ERROR_MARK)
+ {
+ error ("RETURNS spec with invalid mode");
+ TREE_TYPE (exp) = error_mark_node;
+ }
+ satisfy_list_values (TYPE_ARG_TYPES (exp), chain);
+ if (!TYPE_SIZE (exp) && !LOOKUP_ONLY)
+ layout_type (exp);
+ break;
+ case ENUMERAL_TYPE:
+ if (TYPE_SIZE (exp) == NULL_TREE && !LOOKUP_ONLY)
+ { tree pair;
+ /* FIXME: Should this use satisfy_decl? */
+ for (pair = TYPE_VALUES (exp); pair; pair = TREE_CHAIN (pair))
+ SATISFY (DECL_INITIAL (TREE_VALUE (pair)));
+ layout_enum (exp);
+ }
+ break;
+ case INTEGER_TYPE:
+ SATISFY (TYPE_MIN_VALUE (exp));
+ SATISFY (TYPE_MAX_VALUE (exp));
+ if (TREE_TYPE (exp) != NULL_TREE)
+ { /* A range type */
+ if (TREE_TYPE (exp) != ridpointers[(int) RID_RANGE]
+ && TREE_TYPE (exp) != ridpointers[(int) RID_BIN]
+ && TREE_TYPE (exp) != string_index_type_dummy)
+ SATISFY (TREE_TYPE (exp));
+ if (!TYPE_SIZE (exp) && !LOOKUP_ONLY)
+ exp = layout_chill_range_type (exp, 1);
+ }
+ break;
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ if (LOOKUP_ONLY)
+ SATISFY (TREE_TYPE (exp));
+ else
+ {
+ struct decl_chain *link;
+ int already_seen = 0;
+ for (link = chain; ; link = link->prev)
+ {
+ if (link == NULL)
+ {
+ struct decl_chain new_link;
+ new_link.decl = exp;
+ new_link.prev = chain;
+ TREE_TYPE (exp) = satisfy (TREE_TYPE (exp), &new_link);
+ break;
+ }
+ else if (link->decl == exp)
+ {
+ already_seen = 1;
+ break;
+ }
+ }
+ if (!TYPE_SIZE (exp))
+ {
+ layout_type (exp);
+ if (TREE_CODE (exp) == REFERENCE_TYPE)
+ CH_NOVELTY (exp) = CH_NOVELTY (TREE_TYPE (exp));
+ if (! already_seen)
+ {
+ tree valtype = TREE_TYPE (exp);
+ if (TREE_CODE_CLASS (TREE_CODE (valtype)) != 't')
+ {
+ if (TREE_CODE (valtype) != ERROR_MARK)
+ error ("operand to REF is not a mode");
+ TREE_TYPE (exp) = error_mark_node;
+ return error_mark_node;
+ }
+ else if (TREE_CODE (exp) == POINTER_TYPE
+ && TYPE_POINTER_TO (valtype) == NULL)
+ TYPE_POINTER_TO (valtype) = exp;
+ }
+ }
+ }
+ break;
+ case RECORD_TYPE:
+ {
+ /* FIXME: detected errors in here will be printed as
+ often as this sequence runs. Find another way or
+ place to print the errors. */
+ /* if we have an ACCESS or TEXT mode we have to set
+ maximum_field_alignment to 0 to fit with runtime
+ system, even when we compile with -fpack. */
+ extern int maximum_field_alignment;
+ int save_maximum_field_alignment = maximum_field_alignment;
+
+ if (CH_IS_ACCESS_MODE (exp) || CH_IS_TEXT_MODE (exp))
+ maximum_field_alignment = 0;
+
+ for (decl = TYPE_FIELDS (exp); decl; decl = TREE_CHAIN (decl))
+ {
+ SATISFY (TREE_TYPE (decl));
+ if (!LOOKUP_ONLY)
+ {
+ /* if we have a UNION_TYPE here (variant structure), check for
+ non-value mode in it. This is not allowed (Z.200/pg. 33) */
+ if (TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE &&
+ CH_TYPE_NONVALUE_P (TREE_TYPE (decl)))
+ {
+ error ("field with non-value mode in variant structure not allowed");
+ TREE_TYPE (decl) = error_mark_node;
+ }
+ /* RECORD_TYPE gets the non-value property if one of the
+ fields has the non-value property */
+ CH_TYPE_NONVALUE_P (exp) |= CH_TYPE_NONVALUE_P (TREE_TYPE (decl));
+ }
+ if (TREE_CODE (decl) == CONST_DECL)
+ {
+ SATISFY (DECL_INITIAL (decl));
+ if (!LOOKUP_ONLY)
+ {
+ if (CH_IS_BUFFER_MODE (exp) || CH_IS_EVENT_MODE (exp))
+ DECL_INITIAL (decl)
+ = check_queue_size (exp, DECL_INITIAL (decl));
+ else if (CH_IS_TEXT_MODE (exp) &&
+ DECL_NAME (decl) == get_identifier ("__textlength"))
+ DECL_INITIAL (decl)
+ = check_text_length (exp, DECL_INITIAL (decl));
+ }
+ }
+ else if (TREE_CODE (decl) == FIELD_DECL)
+ {
+ SATISFY (DECL_INITIAL (decl));
+ }
+ }
+ satisfy_list (TYPE_TAG_VALUES (exp), chain);
+ if (!TYPE_SIZE (exp) && !LOOKUP_ONLY)
+ exp = layout_chill_struct_type (exp);
+ maximum_field_alignment = save_maximum_field_alignment;
+
+ /* perform some checks on nonvalue modes, they are record_mode's */
+ if (!LOOKUP_ONLY)
+ {
+ if (CH_IS_BUFFER_MODE (exp))
+ {
+ tree elemmode = buffer_element_mode (exp);
+ if (elemmode != NULL_TREE && CH_TYPE_NONVALUE_P (elemmode))
+ {
+ error ("buffer element mode must not have non-value property");
+ invalidate_buffer_element_mode (exp);
+ }
+ }
+ else if (CH_IS_ACCESS_MODE (exp))
+ {
+ tree recordmode = access_recordmode (exp);
+ if (recordmode != NULL_TREE && CH_TYPE_NONVALUE_P (recordmode))
+ {
+ error ("recordmode must not have the non-value property");
+ invalidate_access_recordmode (exp);
+ }
+ }
+ }
+ }
+ break;
+ case SET_TYPE:
+ SATISFY (TYPE_DOMAIN (exp));
+ if (!TYPE_SIZE (exp) && !LOOKUP_ONLY)
+ exp = layout_powerset_type (exp);
+ break;
+ case UNION_TYPE:
+ for (decl = TYPE_FIELDS (exp); decl; decl = TREE_CHAIN (decl))
+ {
+ SATISFY (TREE_TYPE (decl));
+ if (!LOOKUP_ONLY)
+ CH_TYPE_NONVALUE_P (exp) |= CH_TYPE_NONVALUE_P (TREE_TYPE (decl));
+ }
+ if (!TYPE_SIZE (exp) && !LOOKUP_ONLY)
+ exp = layout_chill_variants (exp);
+ break;
+ default:
+ ;
+ }
+ }
+ return exp;
+}
diff --git a/gcc/ch/tasking.c b/gcc/ch/tasking.c
new file mode 100644
index 0000000..95c81c6
--- /dev/null
+++ b/gcc/ch/tasking.c
@@ -0,0 +1,3423 @@
+/* Implement tasking-related actions for CHILL.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include "config.h"
+#include "tree.h"
+#include "rtl.h"
+#include "ch-tree.h"
+#include "flags.h"
+#include "input.h"
+#include "obstack.h"
+#include "assert.h"
+#include "tasking.h"
+#include "lex.h"
+
+/* external functions */
+extern void emit_jump PROTO((rtx));
+extern void error PROTO((char *, ...));
+extern void error_with_decl PVPROTO ((tree, char *, ...));
+extern void push_obstacks PROTO((struct obstack *, struct obstack *));
+extern void warning PROTO((char *, ...));
+
+/* from ch-lex.l, from compiler directives */
+extern tree process_type;
+extern tree send_signal_prio;
+extern tree send_buffer_prio;
+
+tree tasking_message_type;
+tree instance_type_node;
+tree generic_signal_type_node;
+
+/* the type a tasking code variable has */
+tree chill_taskingcode_type_node;
+
+/* forward declarations */
+void validate_process_parameters PROTO((tree));
+tree make_process_struct PROTO((tree, tree));
+
+/* list of this module's process, buffer, etc. decls.
+ This is a list of TREE_VECs, chain by their TREE_CHAINs. */
+tree tasking_list = NULL_TREE;
+/* The parts of a tasking_list element. */
+#define TASK_INFO_PDECL(NODE) TREE_VEC_ELT(NODE,0)
+#define TASK_INFO_ENTRY(NODE) TREE_VEC_ELT(NODE,1)
+#define TASK_INFO_CODE_DECL(NODE) TREE_VEC_ELT(NODE,2)
+#define TASK_INFO_STUFF_NUM(NODE) TREE_VEC_ELT(NODE,3)
+#define TASK_INFO_STUFF_TYPE(NODE) TREE_VEC_ELT(NODE,4)
+
+/* name template for process argument type */
+static char * struct_name = "__tmp_%s_arg_type";
+
+/* name template for process arguments for debugging type */
+static char * struct_debug_name = "__tmp_%s_debug_type";
+
+/* name template for process argument variable */
+static char * data_name = "__tmp_%s_arg_variable";
+
+/* name template for process wrapper */
+static char * wrapper_name = "__tmp_%s_wrapper";
+
+extern int ignoring;
+static tree void_ftype_void;
+static tree pointer_to_instance;
+static tree infinite_buffer_event_length_node;
+
+tree
+get_struct_type_name (name)
+ tree name;
+{
+ char *idp = IDENTIFIER_POINTER (name); /* process name */
+ char *tmpname = xmalloc (strlen (idp) + strlen (struct_name) + 1);
+
+ sprintf (tmpname, struct_name, idp);
+ return get_identifier (tmpname);
+}
+
+tree
+get_struct_debug_type_name (name)
+ tree name;
+{
+ char *idp = IDENTIFIER_POINTER (name); /* process name */
+ char *tmpname = xmalloc (strlen (idp) + strlen (struct_debug_name) + 1);
+
+ sprintf (tmpname, struct_debug_name, idp);
+ return get_identifier (tmpname);
+}
+
+
+tree
+get_tasking_code_name (name)
+ tree name;
+{
+ char *skelname = "__tmp_%s_code";
+ char *name_str = IDENTIFIER_POINTER (name);
+ char *tmpname = (char *)alloca (IDENTIFIER_LENGTH (name) +
+ strlen (skelname) + 1);
+
+ sprintf (tmpname, skelname, name_str);
+ return get_identifier (tmpname);
+}
+
+
+static tree
+get_struct_variable_name (name)
+ tree name;
+{
+ char *idp = IDENTIFIER_POINTER (name); /* process name */
+ char *tmpname = xmalloc (strlen (idp) + strlen (data_name) + 1);
+
+ sprintf (tmpname, data_name, idp);
+ return get_identifier (tmpname);
+}
+
+static tree
+get_process_wrapper_name (name)
+ tree name;
+{
+ char *idp = IDENTIFIER_POINTER (name);
+ char *tmpname = xmalloc (strlen (idp) + strlen (wrapper_name) + 1);
+
+ sprintf (tmpname, wrapper_name, idp);
+ return get_identifier (tmpname);
+}
+
+/*
+ * If this is a quasi declaration - parsed within a SPEC MODULE,
+ * QUASI_FLAG is TRUE, to indicate that the variable should not
+ * be initialized. The other module will do that.
+ */
+tree
+generate_tasking_code_variable (name, tasking_code_ptr, quasi_flag)
+ tree name, *tasking_code_ptr;
+ int quasi_flag;
+{
+
+ tree decl;
+ tree tasking_code_name = get_tasking_code_name (name);
+
+ if (pass == 2 && ! quasi_flag && *tasking_code_ptr != NULL_TREE)
+ {
+ /* check for value should be assigned is out of range */
+ if (TREE_INT_CST_LOW (*tasking_code_ptr) >
+ TREE_INT_CST_LOW (TYPE_MAX_VALUE (chill_taskingcode_type_node)))
+ error ("Tasking code %d out of range for `%s'.",
+ TREE_INT_CST_LOW (*tasking_code_ptr),
+ IDENTIFIER_POINTER (name));
+ }
+
+ decl = do_decl (tasking_code_name,
+ chill_taskingcode_type_node, 1, 1,
+ quasi_flag ? NULL_TREE : *tasking_code_ptr,
+ 0);
+
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ if (pass == 2 && ! quasi_flag && *tasking_code_ptr != NULL_TREE)
+ *tasking_code_ptr = fold (build (PLUS_EXPR, chill_taskingcode_type_node,
+ integer_one_node,
+ *tasking_code_ptr));
+ return decl;
+}
+
+
+/*
+ * If this is a quasi declaration - parsed within a SPEC MODULE,
+ * QUASI_FLAG is TRUE, to indicate that the variable should not
+ * be initialized. The other module will do that. This is just
+ * for BUFFERs and EVENTs.
+ */
+tree
+decl_tasking_code_variable (name, tasking_code_ptr, quasi_flag)
+ tree name, *tasking_code_ptr;
+ int quasi_flag;
+{
+ extern struct obstack permanent_obstack;
+ tree tasking_code_name = get_tasking_code_name (name);
+ tree decl;
+
+ /* guarantee that RTL for the code_variable resides in
+ the permanent obstack. The BUFFER or EVENT may be
+ declared in a PROC, not at global scope... */
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ push_obstacks_nochange ();
+
+ if (pass == 2 && ! quasi_flag && *tasking_code_ptr != NULL_TREE)
+ {
+ /* check for value should be assigned is out of range */
+ if (TREE_INT_CST_LOW (*tasking_code_ptr) >
+ TREE_INT_CST_LOW (TYPE_MAX_VALUE (chill_taskingcode_type_node)))
+ error ("Tasking code %d out of range for `%s'.",
+ TREE_INT_CST_LOW (*tasking_code_ptr),
+ IDENTIFIER_POINTER (name));
+ }
+
+ decl = decl_temp1 (tasking_code_name,
+ chill_taskingcode_type_node, 1,
+ quasi_flag ? NULL_TREE : *tasking_code_ptr,
+ 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ /* Return to the ambient context. */
+ pop_obstacks ();
+
+ if (pass == 2 && ! quasi_flag && *tasking_code_ptr != NULL_TREE)
+ *tasking_code_ptr = fold (build (PLUS_EXPR, chill_taskingcode_type_node,
+ integer_one_node,
+ *tasking_code_ptr));
+ return decl;
+}
+
+/*
+ * Transmute a process parameter list into an argument structure
+ * TYPE_DECL for the start_process call to reference. Create a
+ * proc_type variable for later. Returns the new struct type.
+ */
+tree
+make_process_struct (name, processparlist)
+ tree name, processparlist;
+{
+ tree temp;
+ tree a_parm;
+ tree field_decls = NULL_TREE;
+
+ if (name == NULL_TREE || TREE_CODE (name) == ERROR_MARK)
+ return error_mark_node;
+
+ if (processparlist == NULL_TREE)
+ return tree_cons (NULL_TREE, NULL_TREE, void_list_node);
+
+ if (TREE_CODE (processparlist) == ERROR_MARK)
+ return error_mark_node;
+
+ /* build list of field decls for build_chill_struct_type */
+ for (a_parm = processparlist; a_parm != NULL_TREE;
+ a_parm = TREE_CHAIN (a_parm))
+ {
+ tree parnamelist = TREE_VALUE (a_parm);
+ tree purpose = TREE_PURPOSE (a_parm);
+ tree mode = TREE_VALUE (purpose);
+ tree parm_attr = TREE_PURPOSE (purpose);
+ tree field;
+
+ /* build a FIELD_DECL node */
+ if (parm_attr != NULL_TREE)
+ {
+ if (parm_attr == ridpointers[(int)RID_LOC])
+ mode = build_chill_reference_type (mode);
+ else if (parm_attr == ridpointers[(int)RID_IN])
+ ;
+ else if (pass == 1)
+ {
+ for (field = parnamelist; field != NULL_TREE;
+ field = TREE_CHAIN (field))
+ error ("invalid attribute for argument `%s' (only IN or LOC allowed).",
+ IDENTIFIER_POINTER (TREE_VALUE (field)));
+ }
+ }
+
+ field = grok_chill_fixedfields (parnamelist, mode, NULL_TREE);
+
+ /* chain the fields in reverse */
+ if (field_decls == NULL_TREE)
+ field_decls = field;
+ else
+ chainon (field_decls, field);
+ }
+
+ temp = build_chill_struct_type (field_decls);
+ return temp;
+}
+
+/* Build a function for a PROCESS and define some
+ types for the process arguments.
+ After the PROCESS a wrapper function will be
+ generated which gets the PROCESS arguments via a pointer
+ to a structure having the same layout as the arguments.
+ This wrapper function then will call the PROCESS.
+ The advantage in doing it this way is, that PROCESS
+ arguments may be displayed by gdb without any change
+ to gdb.
+*/
+tree
+build_process_header (plabel, paramlist)
+ tree plabel, paramlist;
+{
+ tree struct_ptr_type = NULL_TREE;
+ tree new_param_list = NULL_TREE;
+ tree struct_decl = NULL_TREE;
+ tree process_struct = NULL_TREE;
+ tree struct_debug_type = NULL_TREE;
+ tree code_decl;
+
+ if (! global_bindings_p ())
+ {
+ error ("PROCESS may only be declared at module level");
+ return error_mark_node;
+ }
+
+ if (paramlist)
+ {
+ /* must make the structure OUTSIDE the parameter scope */
+ if (pass == 1)
+ {
+ process_struct = make_process_struct (plabel, paramlist);
+ struct_ptr_type = build_chill_pointer_type (process_struct);
+ }
+ else
+ {
+ process_struct = NULL_TREE;
+ struct_ptr_type = NULL_TREE;
+ }
+
+ struct_decl = push_modedef (get_struct_type_name (plabel),
+ struct_ptr_type, -1);
+ DECL_SOURCE_LINE (struct_decl) = 0;
+ struct_debug_type = push_modedef (get_struct_debug_type_name (plabel),
+ process_struct, -1);
+ DECL_SOURCE_LINE (struct_debug_type) = 0;
+
+ if (pass == 2)
+ {
+ /* build a list of PARM_DECL's */
+ tree wrk = paramlist;
+ tree tmp, list = NULL_TREE;
+
+ while (wrk != NULL_TREE)
+ {
+ tree wrk1 = TREE_VALUE (wrk);
+
+ while (wrk1 != NULL_TREE)
+ {
+ tmp = make_node (PARM_DECL);
+ DECL_ASSEMBLER_NAME (tmp) = DECL_NAME (tmp) = TREE_VALUE (wrk1);
+ if (list == NULL_TREE)
+ new_param_list = list = tmp;
+ else
+ {
+ TREE_CHAIN (list) = tmp;
+ list = tmp;
+ }
+ wrk1 = TREE_CHAIN (wrk1);
+ }
+ wrk = TREE_CHAIN (wrk);
+ }
+ }
+ else
+ {
+ /* build a list of modes */
+ tree wrk = paramlist;
+
+ while (wrk != NULL_TREE)
+ {
+ tree wrk1 = TREE_VALUE (wrk);
+
+ while (wrk1 != NULL_TREE)
+ {
+ new_param_list = tree_cons (TREE_PURPOSE (TREE_PURPOSE (wrk)),
+ TREE_VALUE (TREE_PURPOSE (wrk)),
+ new_param_list);
+ wrk1 = TREE_CHAIN (wrk1);
+ }
+ wrk = TREE_CHAIN (wrk);
+ }
+ new_param_list = nreverse (new_param_list);
+ }
+ }
+
+ /* declare the code variable outside the process */
+ code_decl = generate_tasking_code_variable (plabel,
+ &process_type, 0);
+
+ /* start the parameter scope */
+ push_chill_function_context ();
+
+ if (! start_chill_function (plabel, void_type_node,
+ new_param_list, NULL_TREE, NULL_TREE))
+ return error_mark_node;
+
+ current_module->procedure_seen = 1;
+ CH_DECL_PROCESS (current_function_decl) = 1;
+ /* remember the code variable in the function decl */
+ DECL_TASKING_CODE_DECL (current_function_decl) =
+ (struct lang_decl *)code_decl;
+ if (paramlist == NULL_TREE)
+ /* do it here, cause we don't have a wrapper */
+ add_taskstuff_to_list (code_decl, "_TT_Process", process_type,
+ current_function_decl, NULL_TREE);
+
+ return perm_tree_cons (code_decl, struct_decl, NULL_TREE);
+}
+
+/* Generate a function which gets a pointer
+ to an argument block and call the corresponding
+ PROCESS
+*/
+void
+build_process_wrapper (plabel, processdata)
+ tree plabel;
+ tree processdata;
+{
+ tree args = NULL_TREE;
+ tree wrapper = NULL_TREE;
+ tree parammode = TREE_VALUE (processdata);
+ tree code_decl = TREE_PURPOSE (processdata);
+ tree func = lookup_name (plabel);
+
+ /* check the mode. If it is an ERROR_MARK there was an error
+ in build_process_header, if it is a NULL_TREE the process
+ don't have parameters, so we must not generate a wrapper */
+ if (parammode == NULL_TREE ||
+ TREE_CODE (parammode) == ERROR_MARK)
+ return;
+
+ /* get the function name */
+ wrapper = get_process_wrapper_name (plabel);
+
+ /* build the argument */
+ if (pass == 2)
+ {
+ /* build a PARM_DECL */
+ args = make_node (PARM_DECL);
+ DECL_ASSEMBLER_NAME (args) = DECL_NAME (args) = get_identifier ("x");
+ }
+ else
+ {
+ /* build a tree list with the mode */
+ args = tree_cons (NULL_TREE,
+ TREE_TYPE (parammode),
+ NULL_TREE);
+ }
+
+ /* start the function */
+ push_chill_function_context ();
+
+ if (! start_chill_function (wrapper, void_type_node,
+ args, NULL_TREE, NULL_TREE))
+ return;
+
+ /* to avoid granting */
+ DECL_SOURCE_LINE (current_function_decl) = 0;
+
+ if (! ignoring)
+ {
+ /* make the call to the PROCESS */
+ tree wrk;
+ tree x = lookup_name (get_identifier ("x"));
+ /* no need to check this pointer to be NULL */
+ tree indref = build_chill_indirect_ref (x, NULL_TREE, 0);
+
+ args = NULL_TREE;
+ wrk = TYPE_FIELDS (TREE_TYPE (TREE_TYPE (x)));
+ while (wrk != NULL_TREE)
+ {
+ args = tree_cons (NULL_TREE,
+ build_component_ref (indref, DECL_NAME (wrk)),
+ args);
+ wrk = TREE_CHAIN (wrk);
+ }
+ CH_DECL_PROCESS (func) = 0;
+ expand_expr_stmt (
+ build_chill_function_call (func, nreverse (args)));
+ CH_DECL_PROCESS (func) = 1;
+ }
+
+ add_taskstuff_to_list (code_decl, "_TT_Process", process_type,
+ func, current_function_decl);
+
+ /* finish the function */
+ finish_chill_function ();
+ pop_chill_function_context ();
+}
+
+/* Generate errors for INOUT, OUT parameters.
+
+ "Only if LOC is specified may the mode have the non-value
+ property"
+ */
+
+void
+validate_process_parameters (parms)
+ tree parms;
+{
+}
+
+/*
+ * build the tree for a start process action. Loop through the
+ * actual parameters, making a constructor list, which we use to
+ * initialize the argument structure. NAME is the process' name.
+ * COPYNUM is its copy number, whatever that is. EXPRLIST is the
+ * list of actual parameters passed by the start call. They must
+ * match. EXPRLIST must still be in reverse order; we'll reverse it here.
+ *
+ * Note: the OPTSET name is not now used - it's here for
+ * possible future support for the optional 'SET instance-var'
+ * clause.
+ */
+void
+build_start_process (process_name, copynum,
+ exprlist, optset)
+ tree process_name, copynum, exprlist, optset;
+{
+ tree process_decl, struct_type_node;
+ tree result;
+ tree valtail, typetail;
+ tree tuple, actuallist = NULL_TREE;
+ tree typelist;
+ int parmno = 2;
+ tree args;
+ tree filename, linenumber;
+
+ if (exprlist != NULL_TREE && TREE_CODE (exprlist) == ERROR_MARK)
+ process_decl = NULL_TREE;
+ else if (! ignoring)
+ {
+ process_decl = lookup_name (process_name);
+ if (process_decl == NULL_TREE)
+ error ("process name %s never declared",
+ IDENTIFIER_POINTER (process_name));
+ else if (TREE_CODE (process_decl) != FUNCTION_DECL
+ || ! CH_DECL_PROCESS (process_decl))
+ {
+ error ("You may only START a process, not a proc");
+ process_decl = NULL_TREE;
+ }
+ else if (DECL_EXTERNAL (process_decl))
+ {
+ args = TYPE_ARG_TYPES (TREE_TYPE (process_decl));
+ if (TREE_VALUE (args) != void_type_node)
+ struct_type_node = TREE_TYPE (TREE_VALUE (args));
+ else
+ struct_type_node = NULL_TREE;
+ }
+ else
+ {
+ tree debug_type = lookup_name (
+ get_struct_debug_type_name (DECL_NAME (process_decl)));
+
+ if (debug_type == NULL_TREE)
+ /* no debug type, no arguments */
+ struct_type_node = NULL_TREE;
+ else
+ struct_type_node = TREE_TYPE (debug_type);
+ }
+ }
+
+ /* begin a new name scope */
+ pushlevel (1);
+ clear_last_expr ();
+ push_momentary ();
+ if (pass == 2)
+ expand_start_bindings (0);
+
+ if (! ignoring && process_decl != NULL_TREE)
+ {
+ if (optset == NULL_TREE) ;
+ else if (!CH_REFERABLE (optset))
+ {
+ error ("SET expression not a location.");
+ optset = NULL_TREE;
+ }
+ else if (!CH_IS_INSTANCE_MODE (TREE_TYPE (optset)))
+ {
+ error ("SET location must be INSTANCE mode");
+ optset = NULL_TREE;
+ }
+ if (optset)
+ optset = force_addr_of (optset);
+ else
+ optset = convert (ptr_type_node, integer_zero_node);
+
+ if (struct_type_node != NULL_TREE)
+ {
+ typelist = TYPE_FIELDS (struct_type_node);
+
+ for (valtail = nreverse (exprlist), typetail = typelist;
+ valtail != NULL_TREE && typetail != NULL_TREE; parmno++,
+ valtail = TREE_CHAIN (valtail), typetail = TREE_CHAIN (typetail))
+ {
+ register tree actual = valtail ? TREE_VALUE (valtail) : 0;
+ register tree type = typetail ? TREE_TYPE (typetail) : 0;
+ char place[30];
+ sprintf (place, "signal field %d", parmno);
+ actual = chill_convert_for_assignment (type, actual, place);
+ actuallist = tree_cons (NULL_TREE, actual,
+ actuallist);
+ }
+
+ tuple = build_nt (CONSTRUCTOR, NULL_TREE,
+ nreverse (actuallist));
+ }
+ else
+ {
+ valtail = NULL_TREE;
+ typetail = NULL_TREE;
+ }
+
+ if (valtail != 0 && TREE_VALUE (valtail) != void_type_node)
+ {
+ char *errstr = "too many arguments to process";
+ if (process_name)
+ error ("%s `%s'", errstr, IDENTIFIER_POINTER (process_name));
+ else
+ error (errstr);
+ }
+ else if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
+ {
+ char *errstr = "too few arguments to process";
+ if (process_name)
+ error ("%s `%s'", errstr, IDENTIFIER_POINTER (process_name));
+ else
+ error (errstr);
+ }
+ else
+ {
+ tree process_decl = lookup_name (process_name);
+ tree process_type = (tree)DECL_TASKING_CODE_DECL (process_decl);
+ tree struct_size, struct_pointer;
+
+ if (struct_type_node != NULL_TREE)
+ {
+ result =
+ decl_temp1 (get_unique_identifier ("START_ARG"),
+ struct_type_node, 0, tuple, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (result) = 0;
+
+ mark_addressable (result);
+ struct_pointer
+ = build1 (ADDR_EXPR,
+ build_chill_pointer_type (struct_type_node),
+ result);
+ struct_size = size_in_bytes (struct_type_node);
+ }
+ else
+ {
+ struct_size = integer_zero_node;
+ struct_pointer = null_pointer_node;
+ }
+
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (get_identifier ("__start_process")),
+ tree_cons (NULL_TREE, process_type,
+ tree_cons (NULL_TREE, convert (integer_type_node, copynum),
+ tree_cons (NULL_TREE, struct_size,
+ tree_cons (NULL_TREE, struct_pointer,
+ tree_cons (NULL_TREE, optset,
+ tree_cons (NULL_TREE, filename,
+ build_tree_list (NULL_TREE, linenumber)))))))));
+ }
+ }
+ /* end of scope */
+
+ if (pass == 2)
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ poplevel (kept_level_p (), 0, 0);
+ pop_momentary ();
+}
+
+/*
+ * A CHILL SET which represents all of the possible tasking
+ * elements.
+ */
+static tree
+build_tasking_enum ()
+{
+ tree result, decl1;
+ tree enum1;
+ tree list = NULL_TREE;
+ tree value = integer_zero_node;
+
+ enum1 = start_enum (NULL_TREE);
+ result = build_enumerator (get_identifier ("_TT_UNUSED"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Process"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Signal"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Buffer"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Event"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Synonym"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Exception"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = finish_enum (enum1, list);
+
+ decl1 = build_decl (TYPE_DECL,
+ get_identifier ("__tmp_TaskingEnum"),
+ result);
+ pushdecl (decl1);
+ satisfy_decl (decl1, 0);
+ return decl1;
+}
+
+tree
+build_tasking_struct ()
+{
+ tree listbase, decl1, decl2, result;
+ tree enum_type = TREE_TYPE (build_tasking_enum ());
+ /* We temporarily reset the maximum_field_alignment to zero so the
+ compiler's init data structures can be compatible with the
+ run-time system, even when we're compiling with -fpack. */
+ extern int maximum_field_alignment;
+ int save_maximum_field_alignment = maximum_field_alignment;
+ maximum_field_alignment = 0;
+
+ decl1 = build_decl (FIELD_DECL, get_identifier ("TaskName"),
+ build_chill_pointer_type (char_type_node));
+ DECL_INITIAL (decl1) = NULL_TREE;
+ listbase = decl1;
+
+ decl2 = build_decl (FIELD_DECL, get_identifier ("TaskValue"),
+ build_chill_pointer_type (chill_taskingcode_type_node));
+ TREE_CHAIN (decl1) = decl2;
+ DECL_INITIAL (decl2) = NULL_TREE;
+ decl1 = decl2;
+
+ decl2 = build_decl (FIELD_DECL, get_identifier ("TaskValueDefined"),
+ integer_type_node);
+ TREE_CHAIN (decl1) = decl2;
+ DECL_INITIAL (decl2) = NULL_TREE;
+ decl1 = decl2;
+
+ decl2 = build_decl (FIELD_DECL, get_identifier ("TaskEntry"),
+ build_chill_pointer_type (void_ftype_void));
+ TREE_CHAIN (decl1) = decl2;
+ DECL_INITIAL (decl2) = NULL_TREE;
+ decl1 = decl2;
+
+ decl2 = build_decl (FIELD_DECL, get_identifier ("TaskType"),
+ enum_type);
+ TREE_CHAIN (decl1) = decl2;
+ DECL_INITIAL (decl2) = NULL_TREE;
+ decl1 = decl2;
+
+ TREE_CHAIN (decl2) = NULL_TREE;
+ result = build_chill_struct_type (listbase);
+ satisfy_decl (result, 0);
+ maximum_field_alignment = save_maximum_field_alignment;
+ return result;
+}
+
+/*
+ * build data structures describing each task/signal, etc.
+ * in current module.
+ */
+void
+tasking_setup ()
+{
+ tree tasknode;
+ tree struct_type;
+
+ if (pass == 1)
+ return;
+
+ struct_type = TREE_TYPE (lookup_name (
+ get_identifier ("__tmp_TaskingStruct")));
+
+ for (tasknode = tasking_list; tasknode != NULL_TREE;
+ tasknode = TREE_CHAIN (tasknode))
+ {
+ /* This is the tasking_code_variable's decl */
+ tree stuffnumber = TASK_INFO_STUFF_NUM (tasknode);
+ tree code_decl = TASK_INFO_CODE_DECL (tasknode);
+ tree proc_decl = TASK_INFO_PDECL (tasknode);
+ tree entry = TASK_INFO_ENTRY (tasknode);
+ tree name = DECL_NAME (proc_decl);
+ char *init_struct = (char *) alloca (IDENTIFIER_LENGTH(name) + 20);
+ /* take care of zero termination */
+ tree task_name;
+ /* these are the fields of the struct, in declaration order */
+ tree init_flag = (stuffnumber == NULL_TREE) ?
+ integer_zero_node : integer_one_node;
+ tree type = DECL_INITIAL (TASK_INFO_STUFF_TYPE (tasknode));
+ tree int_addr;
+ tree entry_point;
+ tree name_ptr;
+ tree decl;
+ tree struct_id;
+ tree initializer;
+
+ if (TREE_CODE (proc_decl) == FUNCTION_DECL
+ && CH_DECL_PROCESS (proc_decl)
+ && ! DECL_EXTERNAL (proc_decl))
+ {
+ if (entry == NULL_TREE)
+ entry = proc_decl;
+ mark_addressable (entry);
+ entry_point = build1 (ADDR_EXPR,
+ build_chill_pointer_type (void_ftype_void),
+ entry);
+ }
+ else
+ entry_point = build1 (NOP_EXPR,
+ build_chill_pointer_type (void_ftype_void),
+ null_pointer_node);
+
+ /* take care of zero termination */
+ task_name =
+ build_chill_string (IDENTIFIER_LENGTH (name) + 1,
+ IDENTIFIER_POINTER (name));
+
+ mark_addressable (code_decl);
+ int_addr = build1 (ADDR_EXPR,
+ build_chill_pointer_type (chill_integer_type_node),
+ code_decl);
+
+ mark_addressable (task_name);
+ name_ptr = build1 (ADDR_EXPR,
+ build_chill_pointer_type (char_type_node),
+ task_name);
+
+ sprintf (init_struct, "__tmp_%s_struct",
+ IDENTIFIER_POINTER (name));
+
+ struct_id = get_identifier (init_struct);
+ initializer = build (CONSTRUCTOR, struct_type, NULL_TREE,
+ tree_cons (NULL_TREE, name_ptr,
+ tree_cons (NULL_TREE, int_addr,
+ tree_cons (NULL_TREE, init_flag,
+ tree_cons (NULL_TREE, entry_point,
+ tree_cons (NULL_TREE, type, NULL_TREE))))));
+ TREE_CONSTANT (initializer) = 1;
+ decl = decl_temp1 (struct_id, struct_type, 1, initializer, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ /* pass the decl to tasking_registry() in the symbol table */
+ IDENTIFIER_LOCAL_VALUE (struct_id) = decl;
+ }
+}
+
+
+/*
+ * Generate code to register the tasking-related stuff
+ * with the runtime. Only in pass 2.
+ */
+void
+tasking_registry ()
+{
+ tree tasknode, fn_decl;
+
+ if (pass == 1)
+ return;
+
+ fn_decl = lookup_name (get_identifier ("__register_tasking"));
+
+ for (tasknode = tasking_list; tasknode != NULL_TREE;
+ tasknode = TREE_CHAIN (tasknode))
+ {
+ tree proc_decl = TASK_INFO_PDECL (tasknode);
+ tree name = DECL_NAME (proc_decl);
+ tree arg_decl;
+ char *init_struct = (char *) alloca (IDENTIFIER_LENGTH (name) + 20);
+
+ sprintf (init_struct, "__tmp_%s_struct",
+ IDENTIFIER_POINTER (name));
+ arg_decl = lookup_name (get_identifier (init_struct));
+
+ expand_expr_stmt (
+ build_chill_function_call (fn_decl,
+ build_tree_list (NULL_TREE, force_addr_of (arg_decl))));
+ }
+}
+
+/*
+ * Put a tasking entity (a PROCESS, or SIGNAL) onto
+ * the list for tasking_setup (). CODE_DECL is the integer code
+ * variable's DECL, which describes the shadow integer which
+ * accompanies each tasking entity. STUFFTYPE is a string
+ * representing the sort of tasking entity we have here (i.e.
+ * process, signal, etc.). STUFFNUMBER is an enumeration
+ * value saying the same thing. PROC_DECL is the declaration of
+ * the entity. It's a FUNCTION_DECL if the entity is a PROCESS, it's
+ * a TYPE_DECL if the entity is a SIGNAL.
+ */
+void
+add_taskstuff_to_list (code_decl, stufftype, stuffnumber,
+ proc_decl, entry)
+ tree code_decl;
+ char *stufftype;
+ tree stuffnumber, proc_decl, entry;
+{
+ if (pass == 1)
+ /* tell chill_finish_compile that there's
+ task-level code to be processed. */
+ tasking_list = integer_one_node;
+
+ /* do only in pass 2 so we know in chill_finish_compile whether
+ to generate a constructor function, and to avoid double the
+ correct number of entries. */
+ else /* pass == 2 */
+ {
+ tree task_node = make_tree_vec (5);
+ TASK_INFO_PDECL (task_node) = proc_decl;
+ TASK_INFO_ENTRY (task_node) = entry;
+ TASK_INFO_CODE_DECL (task_node) = code_decl;
+ TASK_INFO_STUFF_NUM (task_node) = stuffnumber;
+ TASK_INFO_STUFF_TYPE (task_node)
+ = lookup_name (get_identifier (stufftype));
+ TREE_CHAIN (task_node) = tasking_list;
+ tasking_list = task_node;
+ }
+}
+
+/*
+ * These next routines are called out of build_generalized_call
+ */
+tree
+build_copy_number (instance_expr)
+ tree instance_expr;
+{
+ tree result;
+
+ if (instance_expr == NULL_TREE
+ || TREE_CODE (instance_expr) == ERROR_MARK)
+ return error_mark_node;
+ if (! CH_IS_INSTANCE_MODE (TREE_TYPE (instance_expr)))
+ {
+ error ("COPY_NUMBER argument must be INSTANCE expression");
+ return error_mark_node;
+ }
+ result = build_component_ref (instance_expr,
+ get_identifier (INS_COPY));
+ CH_DERIVED_FLAG (result) = 1;
+ return result;
+}
+
+
+tree
+build_gen_code (decl)
+ tree decl;
+{
+ tree result;
+
+ if (decl == NULL_TREE || TREE_CODE (decl) == ERROR_MARK)
+ return error_mark_node;
+
+ if ((TREE_CODE (decl) == FUNCTION_DECL && CH_DECL_PROCESS (decl))
+ || (TREE_CODE (decl) == TYPE_DECL && CH_DECL_SIGNAL (decl)))
+ result = (tree)(DECL_TASKING_CODE_DECL (decl));
+ else
+ {
+ error ("GEN_CODE argument must be a process or signal name.");
+ return error_mark_node;
+ }
+ CH_DERIVED_FLAG (result) = 1;
+ return (result);
+}
+
+
+tree
+build_gen_inst (process, copyn)
+ tree process, copyn;
+{
+ tree ptype;
+ tree result;
+
+ if (copyn == NULL_TREE || TREE_CODE (copyn) == ERROR_MARK)
+ return error_mark_node;
+ if (process == NULL_TREE || TREE_CODE (process) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (TREE_TYPE (copyn)) != INTEGER_TYPE)
+ {
+ error ("GEN_INST parameter 2 must be an integer mode");
+ copyn = integer_zero_node;
+ }
+
+ copyn = check_range (copyn, copyn,
+ TYPE_MIN_VALUE (chill_taskingcode_type_node),
+ TYPE_MAX_VALUE (chill_taskingcode_type_node));
+
+ if (TREE_CODE (process) == FUNCTION_DECL
+ && CH_DECL_PROCESS (process))
+ ptype = (tree)DECL_TASKING_CODE_DECL (process);
+ else if (TREE_TYPE (process) != NULL_TREE
+ && TREE_CODE (TREE_TYPE (process)) == INTEGER_TYPE)
+ {
+ process = check_range (process, process,
+ TYPE_MIN_VALUE (chill_taskingcode_type_node),
+ TYPE_MAX_VALUE (chill_taskingcode_type_node));
+ ptype = convert (chill_taskingcode_type_node, process);
+ }
+ else
+ {
+ error ("GEN_INST parameter 1 must be a PROCESS or an integer expression");
+ return (error_mark_node);
+ }
+
+ result = convert (instance_type_node,
+ build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE, ptype,
+ tree_cons (NULL_TREE,
+ convert (chill_taskingcode_type_node, copyn), NULL_TREE))));
+ CH_DERIVED_FLAG (result) = 1;
+ return result;
+}
+
+
+tree
+build_gen_ptype (process_decl)
+ tree process_decl;
+{
+ tree result;
+
+ if (process_decl == NULL_TREE || TREE_CODE (process_decl) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (process_decl) != FUNCTION_DECL
+ || ! CH_DECL_PROCESS (process_decl))
+ {
+ error_with_decl (process_decl, "%s is not a declared process");
+ return error_mark_node;
+ }
+
+ result = (tree)DECL_TASKING_CODE_DECL (process_decl);
+ CH_DERIVED_FLAG (result) = 1;
+ return result;
+}
+
+
+tree
+build_proc_type (instance_expr)
+ tree instance_expr;
+{
+ tree result;
+
+ if (instance_expr == NULL_TREE || TREE_CODE (instance_expr) == ERROR_MARK)
+ return error_mark_node;
+
+ if (! CH_IS_INSTANCE_MODE (TREE_TYPE (instance_expr)))
+ {
+ error ("PROC_TYPE argument must be INSTANCE expression");
+ return error_mark_node;
+ }
+ result = build_component_ref (instance_expr,
+ get_identifier (INS_PTYPE));
+ CH_DERIVED_FLAG (result) = 1;
+ return result;
+}
+
+tree
+build_queue_length (buf_ev)
+ tree buf_ev;
+{
+ if (buf_ev == NULL_TREE || TREE_CODE (buf_ev) == ERROR_MARK)
+ return error_mark_node;
+ if (TREE_TYPE (buf_ev) == NULL_TREE ||
+ TREE_CODE (TREE_TYPE (buf_ev)) == ERROR_MARK)
+ return error_mark_node;
+
+ if (CH_IS_BUFFER_MODE (TREE_TYPE (buf_ev)) ||
+ CH_IS_EVENT_MODE (TREE_TYPE (buf_ev)))
+ {
+ char *field_name;
+ tree arg1, arg2;
+
+ if (CH_IS_EVENT_MODE (TREE_TYPE (buf_ev)))
+ {
+ field_name = "__event_data";
+ arg2 = integer_one_node;
+ }
+ else
+ {
+ field_name = "__buffer_data";
+ arg2 = integer_zero_node;
+ }
+ arg1 = build_component_ref (buf_ev, get_identifier (field_name));
+ return build_chill_function_call (
+ lookup_name (get_identifier ("__queue_length")),
+ tree_cons (NULL_TREE, arg1,
+ tree_cons (NULL_TREE, arg2, NULL_TREE)));
+ }
+
+ error ("QUEUE_LENGTH argument must be a BUFFER/EVENT location.");
+ return error_mark_node;
+}
+
+tree
+build_signal_struct_type (signame, sigmodelist, optsigdest)
+ tree signame, sigmodelist, optsigdest;
+{
+ tree decl, temp;
+
+ if (pass == 1)
+ {
+ int fldcnt = 0;
+ tree mode, field_decls = NULL_TREE;
+
+ for (mode = sigmodelist; mode != NULL_TREE; mode = TREE_CHAIN (mode))
+ {
+ tree field;
+ char fldname[20];
+
+ if (TREE_VALUE (mode) == NULL_TREE)
+ continue;
+ sprintf (fldname, "fld%03d", fldcnt++);
+ field = build_decl (FIELD_DECL,
+ get_identifier (fldname),
+ TREE_VALUE (mode));
+ if (field_decls == NULL_TREE)
+ field_decls = field;
+ else
+ chainon (field_decls, field);
+ }
+ if (field_decls == NULL_TREE)
+ field_decls = build_decl (FIELD_DECL,
+ get_identifier ("__tmp_empty"),
+ boolean_type_node);
+ temp = build_chill_struct_type (field_decls);
+
+ /* save the destination process name of the signal */
+ IDENTIFIER_SIGNAL_DEST (signame) = optsigdest;
+ IDENTIFIER_SIGNAL_DATA (signame) = fldcnt;
+ }
+ else
+ {
+ /* optsigset is only valid in pass 2, so we have to save it now */
+ IDENTIFIER_SIGNAL_DEST (signame) = optsigdest;
+ temp = NULL_TREE; /* Actually, don't care. */
+ }
+
+ decl = push_modedef (signame, temp, -1);
+ if (decl != NULL_TREE)
+ CH_DECL_SIGNAL (decl) = 1;
+ return decl;
+}
+
+/*
+ * An instance type is a unique process identifier in the CHILL
+ * tasking arena. It consists of a process type and a copy number.
+ */
+void
+build_instance_type ()
+{
+ tree decl1, decl2, tdecl;
+
+ decl1 = build_decl (FIELD_DECL, get_identifier (INS_PTYPE),
+ chill_taskingcode_type_node);
+
+ TREE_CHAIN (decl1) = decl2 =
+ build_decl (FIELD_DECL, get_identifier (INS_COPY),
+ chill_taskingcode_type_node);
+ TREE_CHAIN (decl2) = NULL_TREE;
+
+ instance_type_node = build_chill_struct_type (decl1);
+ tdecl = build_decl (TYPE_DECL, ridpointers[(int) RID_INSTANCE],
+ instance_type_node);
+ TYPE_NAME (instance_type_node) = tdecl;
+ CH_NOVELTY (instance_type_node) = tdecl;
+ DECL_SOURCE_LINE (tdecl) = 0;
+ pushdecl (tdecl);
+
+ pointer_to_instance = build_chill_pointer_type (instance_type_node);
+}
+
+#if 0
+ *
+ * The tasking message descriptor looks like this C structure:
+ *
+ * typedef struct
+ * {
+ * short *sc; /* ptr to code integer */
+ * int data_len; /* length of signal/buffer data msg */
+ * void *data; /* ptr to signal/buffer data */
+ * } SignalDescr;
+ *
+ *
+#endif
+
+void
+build_tasking_message_type ()
+{
+ tree type_name;
+ tree temp;
+ /* We temporarily reset maximum_field_alignment to deal with
+ the runtime system. */
+ extern int maximum_field_alignment;
+ int save_maximum_field_alignment = maximum_field_alignment;
+ tree field1, field2, field3;
+
+ maximum_field_alignment = 0;
+ field1 = build_decl (FIELD_DECL,
+ get_identifier ("_SD_code_ptr"),
+ build_pointer_type (chill_integer_type_node));
+ field2 = build_decl (FIELD_DECL,
+ get_identifier ("_SD_data_len"),
+ integer_type_node);
+ field3 = build_decl (FIELD_DECL,
+ get_identifier ("_SD_data_ptr"),
+ ptr_type_node);
+ TREE_CHAIN (field1) = field2;
+ TREE_CHAIN (field2) = field3;
+ temp = build_chill_struct_type (field1);
+
+ type_name = get_identifier ("__tmp_SD_struct");
+ tasking_message_type = build_decl (TYPE_DECL, type_name, temp);
+
+ /* This won't get seen in pass 2, so lay it out now. */
+ layout_chill_struct_type (temp);
+ pushdecl (tasking_message_type);
+ maximum_field_alignment = save_maximum_field_alignment;
+}
+
+tree
+build_signal_descriptor (sigdef, exprlist)
+ tree sigdef, exprlist;
+{
+ tree fieldlist, typetail, valtail;
+ tree actuallist = NULL_TREE;
+ tree signame = DECL_NAME (sigdef);
+ tree dataptr, datalen;
+ int parmno = 1;
+
+ if (sigdef == NULL_TREE
+ || TREE_CODE (sigdef) == ERROR_MARK)
+ return error_mark_node;
+
+ if (exprlist != NULL_TREE
+ && TREE_CODE (exprlist) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (sigdef) != TYPE_DECL
+ || ! CH_DECL_SIGNAL (sigdef))
+ {
+ error ("SEND requires a SIGNAL; %s is not a SIGNAL name",
+ signame);
+ return error_mark_node;
+ }
+ if (CH_TYPE_NONVALUE_P (TREE_TYPE (sigdef)))
+ return error_mark_node;
+
+ fieldlist = TYPE_FIELDS (TREE_TYPE (sigdef));
+ if (IDENTIFIER_SIGNAL_DATA (signame) == 0)
+ fieldlist = TREE_CHAIN (fieldlist);
+
+ for (valtail = exprlist, typetail = fieldlist;
+ valtail != NULL_TREE && typetail != NULL_TREE;
+ parmno++, valtail = TREE_CHAIN (valtail),
+ typetail = TREE_CHAIN (typetail))
+ {
+ register tree actual = valtail ? TREE_VALUE (valtail) : 0;
+ register tree type = typetail ? TREE_TYPE (typetail) : 0;
+ char place[30];
+ sprintf (place, "signal field %d", parmno);
+ actual = chill_convert_for_assignment (type, actual, place);
+ actuallist = tree_cons (NULL_TREE, actual, actuallist);
+ }
+ if (valtail != 0 && TREE_VALUE (valtail) != void_type_node)
+ {
+ error ("too many values for SIGNAL `%s'",
+ IDENTIFIER_POINTER (signame));
+ return error_mark_node;
+ }
+ else if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
+ {
+ error ("too few values for SIGNAL `%s'",
+ IDENTIFIER_POINTER (signame));
+ return error_mark_node;
+ }
+
+ {
+ /* build signal data structure */
+ tree sigdataname = get_unique_identifier (
+ IDENTIFIER_POINTER (signame));
+ if (exprlist == NULL_TREE)
+ {
+ dataptr = null_pointer_node;
+ datalen = integer_zero_node;
+ }
+ else
+ {
+ tree tuple = build_nt (CONSTRUCTOR,
+ NULL_TREE, nreverse (actuallist));
+ tree decl = decl_temp1 (sigdataname, TREE_TYPE (sigdef),
+ 0, tuple, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ dataptr = force_addr_of (decl);
+ datalen = size_in_bytes (TREE_TYPE (decl));
+ }
+
+ /* build descriptor pointing to signal data */
+ {
+ tree decl, tuple;
+ tree tasking_message_var = get_unique_identifier (
+ IDENTIFIER_POINTER (signame));
+
+ tree tasking_code =
+ (tree)DECL_TASKING_CODE_DECL (lookup_name (signame));
+
+ mark_addressable (tasking_code);
+ tuple = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR,
+ build_chill_pointer_type (chill_integer_type_node),
+ tasking_code),
+ tree_cons (NULL_TREE, datalen,
+ tree_cons (NULL_TREE, dataptr, NULL_TREE))));
+
+ decl = decl_temp1 (tasking_message_var,
+ TREE_TYPE (tasking_message_type), 0,
+ tuple, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ tuple = force_addr_of (decl);
+ return tuple;
+ }
+ }
+}
+
+void
+expand_send_signal (sigmsgbuffer, optroutinginfo, optsendto,
+ optpriority, signame)
+ tree sigmsgbuffer;
+ tree optroutinginfo;
+ tree optsendto;
+ tree optpriority;
+ tree signame;
+{
+ tree routing_size, routing_addr;
+ tree filename, linenumber;
+ tree sigdest = IDENTIFIER_SIGNAL_DEST (signame);
+
+ /* check the presence of priority */
+ if (optpriority == NULL_TREE)
+ {
+ if (send_signal_prio == NULL_TREE)
+ {
+ /* issue a warning in case of -Wall */
+ if (extra_warnings)
+ {
+ warning ("Signal sent without priority");
+ warning (" and no default priority was set.");
+ warning (" PRIORITY defaulted to 0");
+ }
+ optpriority = integer_zero_node;
+ }
+ else
+ optpriority = send_signal_prio;
+ }
+
+ /* check the presence of a destination.
+ optdest either may be an instance location
+ or a process declaration */
+ if (optsendto == NULL_TREE)
+ {
+ if (sigdest == NULL_TREE)
+ {
+ error ("SEND without a destination instance");
+ error (" and no destination process specified");
+ error (" for the signal");
+ optsendto = convert (instance_type_node,
+ null_pointer_node);
+ }
+ else
+ {
+ /* build an instance [sigdest; -1] */
+ tree process_name = DECL_NAME (sigdest);
+ tree copy_number = fold (build (MINUS_EXPR, integer_type_node,
+ integer_zero_node,
+ integer_one_node));
+ tree tasking_code = (tree)DECL_TASKING_CODE_DECL (
+ lookup_name (process_name));
+
+ optsendto = build (CONSTRUCTOR, instance_type_node, NULL_TREE,
+ tree_cons (NULL_TREE, tasking_code,
+ tree_cons (NULL_TREE, copy_number, NULL_TREE)));
+ /* as our system doesn't allow that and Z.200 specifies it,
+ we issue a warning */
+ warning ("SEND to ANY copy of process `%s'.", IDENTIFIER_POINTER (process_name));
+ }
+ }
+ else if (! CH_IS_INSTANCE_MODE (TREE_TYPE (optsendto)))
+ {
+ error ("SEND TO must be an INSTANCE mode");
+ optsendto = convert (instance_type_node, null_pointer_node);
+ }
+ else
+ optsendto = check_non_null (convert (instance_type_node, optsendto));
+
+ /* check the routing stuff */
+ if (optroutinginfo != NULL_TREE)
+ {
+ tree routing_name;
+ tree decl;
+
+ if (TREE_TYPE (optroutinginfo) == NULL_TREE)
+ {
+ error ("SEND WITH must have a mode");
+ optroutinginfo = integer_zero_node;
+ }
+ routing_name = get_unique_identifier ("RI");
+ decl = decl_temp1 (routing_name,
+ TREE_TYPE (optroutinginfo), 0,
+ optroutinginfo, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ routing_addr = force_addr_of (decl);
+ routing_size = size_in_bytes (TREE_TYPE (decl));
+ }
+ else
+ {
+ routing_size = integer_zero_node;
+ routing_addr = null_pointer_node;
+ }
+ /* get filename and linenumber */
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ /* Now (at last!) we can call the runtime */
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (get_identifier ("__send_signal")),
+ tree_cons (NULL_TREE, sigmsgbuffer,
+ tree_cons (NULL_TREE, optsendto,
+ tree_cons (NULL_TREE, optpriority,
+ tree_cons (NULL_TREE, routing_size,
+ tree_cons (NULL_TREE, routing_addr,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE)))))))));
+}
+
+#if 0
+ * The following code builds a RECEIVE CASE action, which actually
+ * has 2 different functionalities:
+ *
+ * 1) RECEIVE signal CASE action
+ * which looks like this:
+ *
+ * SIGNAL advance;
+ * SIGNAL terminate = (CHAR);
+ * SIGNAL sig1 = (CHAR);
+ *
+ * DCL user, system INSTANCE;
+ * DCL count INT, char_code CHAR;
+ * DCL instance_loc INSTANCE;
+ *
+ * workloop:
+ * RECEIVE CASE SET instance_loc;
+ * (advance):
+ * count + := 1;
+ * (terminate IN char_code):
+ * SEND sig1(char_code) TO system;
+ * EXIT workloop;
+ * ELSE
+ * STOP;
+ * ESAC;
+ *
+ * Because we don''t know until we get to the ESAC how
+ * many signals need processing, we generate the following
+ * C-equivalent code:
+ *
+ * /* define the codes for the signals */
+ * static short __tmp_advance_code;
+ * static short __tmp_terminate_code;
+ * static short __tmp_sig1_code;
+ *
+ * /* define the types of the signals */
+ * typedef struct
+ * {
+ * char fld0;
+ * } __tmp_terminate_struct;
+ *
+ * typedef struct
+ * {
+ * char fld0;
+ * } __tmp_sig1_struct;
+ *
+ * static INSTANCE user, system, instance_loc;
+ * static short count;
+ * static char char_code;
+ *
+ * { /* start a new symbol context */
+ * int number_of_sigs;
+ * short *sig_code [];
+ * void *sigdatabuf;
+ * int sigdatalen;
+ * short sigcode;
+ *
+ * goto __rcsetup;
+ *
+ * __rcdoit: ;
+ * int timedout = __wait_signal (&sigcode
+ * number_of_sigs,
+ * sig_code,
+ * sigdatabuf,
+ * sigdatalen,
+ * &instance_loc);
+ * if (sigcode == __tmp_advance_code)
+ * {
+ * /* code for advance alternative's action_statement_list */
+ * count++;
+ * }
+ * else if (sigcode == __tmp_terminate_code)
+ * {
+ * /* copy signal's data to where they belong,
+ * with range-check, if enabled */
+ * char_code = ((__tmp_terminate_struct *)sigdatabuf)->fld0;
+ *
+ * /* code for terminate alternative's action_statement_list */
+ * __send_signal (sig1 ..... );
+ * goto __workloop_end;
+ * }
+ * else
+ * {
+ * /* code here for the ELSE action_statement_list */
+ * __stop_process ();
+ * }
+ * goto __rc_done;
+ *
+ * __rcsetup:
+ * union { __tmp_terminate_struct terminate;
+ * __tmp_sig1_struct } databuf;
+ * short *sig_code_ptr [2] = { &__tmp_advance_code,
+ * &__tmp_terminate_code };
+ * sigdatabuf = &databuf;
+ * sigdatalen = sizeof (databuf);
+ * sig_code = &sig_code_ptr[0];
+ * number_of_sigs = 2;
+ * goto __rcdoit;
+ *
+ * __rc_done: ;
+ * } /* end the new symbol context */
+ * __workloop_end: ;
+ *
+ *
+ * 2) RECEIVE buffer CASE action:
+ * which looks like this:
+ *
+ * NEWMODE m_s = STRUCT (mini INT, maxi INT);
+ * DCL b1 BUFFER INT;
+ * DCL b2 BUFFER (30) s;
+ *
+ * DCL i INT, s m_s, ins INSTANCE;
+ * DCL count INT;
+ *
+ * workloop:
+ * RECEIVE CASE SET ins;
+ * (b1 IN i):
+ * count +:= i;
+ * (b2 in s):
+ * IF count < s.mini OR count > s.maxi THEN
+ * EXIT workloop;
+ * FI;
+ * ELSE
+ * STOP;
+ * ESAC;
+ *
+ * Because we don''t know until we get to the ESAC how
+ * many buffers need processing, we generate the following
+ * C-equivalent code:
+ *
+ * typedef struct
+ * {
+ * short mini;
+ * short maxi;
+ * } m_s;
+ *
+ * static void *b1;
+ * static void *b2;
+ * static short i;
+ * static m_s s;
+ * static INSTANCE ins;
+ * static short count;
+ *
+ * workloop:
+ * { /* start a new symbol context */
+ * int number_of_sigs;
+ * void *sig_code [];
+ * void *sigdatabuf;
+ * int sigdatalen;
+ * void *buflocation;
+ * int timedout;
+ *
+ * goto __rcsetup;
+ *
+ * __rcdoit:
+ * timedout = __wait_buffer (&buflocation,
+ * number_of_sigs,
+ * sig_code,
+ * sigdatabuf,
+ * sigdatalen,
+ * &ins, ...);
+ * if (buflocation == &b1)
+ * {
+ * i = ((short *)sigdatabuf)->fld0;
+ * count += i;
+ * }
+ * else if (buflocation == &b2)
+ * {
+ * s = ((m_s)*sigdatabuf)->fld1;
+ * if (count < s.mini || count > s.maxi)
+ * goto __workloop_end;
+ * }
+ * else
+ * __stop_process ();
+ * goto __rc_done;
+ *
+ * __rcsetup:
+ * typedef struct
+ * {
+ * void *p;
+ * unsigned maxqueuesize;
+ * } Buffer_Descr;
+ * union { short b1,
+ * m_s b2 } databuf;
+ * Buffer_Descr bufptr [2] =
+ * {
+ * { &b1, -1 },
+ * { &b2, 30 },
+ * };
+ * void * bufarray[2] = { &bufptr[0],
+ * &bufptr[1] };
+ * sigdatabuf = &databuf;
+ * sigdatalen = sizeof (databuf);
+ * sig_code = &bufarray[0];
+ * number_of_sigs = 2;
+ * goto __rcdoit;
+ *
+ * __rc_done;
+ * } /* end of symbol context */
+ * __workloop_end:
+ *
+#endif
+
+struct rc_state_type
+{
+ struct rc_state_type *enclosing;
+ rtx rcdoit;
+ rtx rcsetup;
+ tree n_sigs;
+ tree sig_code;
+ tree databufp;
+ tree datalen;
+ tree else_clause;
+ tree received_signal;
+ tree received_buffer;
+ tree to_loc;
+ int sigseen;
+ int bufseen;
+ tree actuallist;
+ int call_generated;
+ int if_generated;
+ int bufcnt;
+};
+
+struct rc_state_type *current_rc_state = NULL;
+
+/*
+ * this function tells if there is an if to terminate
+ * or not
+ */
+int
+build_receive_case_if_generated()
+{
+ if (!current_rc_state)
+ {
+ error ("internal error: RECEIVE CASE stack invalid.");
+ abort ();
+ }
+ return current_rc_state->if_generated;
+}
+
+/* build_receive_case_start returns an INTEGER_CST node
+ containing the case-label number to be used by
+ build_receive_case_end to generate correct labels */
+tree
+build_receive_case_start (optset)
+ tree optset;
+{
+ /* counter to generate unique receive_case labels */
+ static int rc_lbl_count = 0;
+ tree current_label_value =
+ build_int_2 ((HOST_WIDE_INT)rc_lbl_count, 0);
+ tree sigcodename, filename, linenumber;
+
+ struct rc_state_type *rc_state
+ = (struct rc_state_type*) xmalloc (sizeof (struct rc_state_type));
+ rc_state->rcdoit = gen_label_rtx ();
+ rc_state->rcsetup = gen_label_rtx ();
+ rc_state->enclosing = current_rc_state;
+ current_rc_state = rc_state;
+ rc_state->sigseen = 0;
+ rc_state->bufseen = 0;
+ rc_state->call_generated = 0;
+ rc_state->if_generated = 0;
+ rc_state->bufcnt = 0;
+
+ rc_lbl_count++;
+ if (optset == NULL_TREE || TREE_CODE (optset) == ERROR_MARK)
+ optset = null_pointer_node;
+ else
+ {
+ if (CH_IS_INSTANCE_MODE (TREE_TYPE (optset)) && CH_LOCATION_P (optset))
+ optset = force_addr_of (optset);
+ else
+ {
+ error ("SET requires INSTANCE location");
+ optset = null_pointer_node;
+ }
+ }
+
+ rc_state->to_loc = build_timeout_preface ();
+
+ rc_state->n_sigs =
+ decl_temp1 (get_identifier ("number_of_sigs"),
+ integer_type_node, 0, integer_zero_node, 0, 0);
+
+ rc_state->sig_code =
+ decl_temp1 (get_identifier ("sig_codep"),
+ ptr_type_node, 0, null_pointer_node, 0, 0);
+
+ rc_state->databufp =
+ decl_temp1 (get_identifier ("databufp"),
+ ptr_type_node, 0, null_pointer_node, 0, 0);
+
+ rc_state->datalen =
+ decl_temp1 (get_identifier ("datalen"),
+ integer_type_node, 0, integer_zero_node, 0, 0);
+
+ rc_state->else_clause =
+ decl_temp1 (get_identifier ("else_clause"),
+ integer_type_node, 0, integer_zero_node, 0, 0);
+
+ /* wait_signal will store the signal number in here */
+ sigcodename = get_identifier ("received_signal");
+ rc_state->received_signal =
+ decl_temp1 (sigcodename, chill_integer_type_node, 0,
+ NULL_TREE, 0, 0);
+
+ /* wait_buffer will store the buffer address in here */
+ sigcodename = get_unique_identifier ("received_buffer");
+ rc_state->received_buffer =
+ decl_temp1 (sigcodename, ptr_type_node, 0,
+ NULL_TREE, 0, 0);
+
+ /* now jump to the end of RECEIVE CASE actions, to
+ set up variables for them. */
+ emit_jump (rc_state->rcsetup);
+
+ /* define the __rcdoit label. We come here after
+ initialization of all variables, to execute the
+ actions. */
+ emit_label (rc_state->rcdoit);
+
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ /* Argument list for calling the runtime routine. We'll call it
+ the first time we call build_receive_case_label, when we know
+ whether to call wait_signal or wait_buffer. NOTE: at this time
+ the first argument will be set. */
+ rc_state->actuallist =
+ tree_cons (NULL_TREE, NULL_TREE,
+ tree_cons (NULL_TREE, rc_state->n_sigs,
+ tree_cons (NULL_TREE, rc_state->sig_code,
+ tree_cons (NULL_TREE, rc_state->databufp,
+ tree_cons (NULL_TREE, rc_state->datalen,
+ tree_cons (NULL_TREE, optset,
+ tree_cons (NULL_TREE, rc_state->else_clause,
+ tree_cons (NULL_TREE, rc_state->to_loc,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE))))))))));
+ return current_label_value;
+}
+
+static tree
+build_receive_signal_case_label (sigdecl, loclist)
+ tree sigdecl, loclist;
+{
+ struct rc_state_type *rc_state = current_rc_state;
+ tree signame = DECL_NAME (sigdecl);
+ tree expr;
+
+ if (rc_state->bufseen != 0)
+ {
+ error ("SIGNAL in RECEIVE CASE alternative follows");
+ error (" a BUFFER name on line %d", rc_state->bufseen);
+ return error_mark_node;
+ }
+ rc_state->sigseen = lineno;
+ rc_state->bufseen = 0;
+
+ if (!IDENTIFIER_SIGNAL_DATA (signame) && loclist != NULL_TREE)
+ {
+ error ("SIGNAL `%s' has no data fields", IDENTIFIER_POINTER (signame));
+ return error_mark_node;
+ }
+ if (IDENTIFIER_SIGNAL_DATA (signame) && loclist == NULL_TREE)
+ {
+ error ("SIGNAL `%s' requires data fields", IDENTIFIER_POINTER (signame));
+ return error_mark_node;
+ }
+
+ if (!rc_state->call_generated)
+ {
+ tree wait_call;
+
+ TREE_VALUE (rc_state->actuallist) = force_addr_of (rc_state->received_signal);
+ wait_call = build_chill_function_call (lookup_name
+ (get_identifier ("__wait_signal_timed")),
+ rc_state->actuallist);
+#if 0
+ chill_expand_assignment (rc_state->received_signal,
+ NOP_EXPR, wait_call);
+#endif
+ build_timesupervised_call (wait_call, rc_state->to_loc);
+
+ rc_state->call_generated = 1;
+ }
+
+ /* build the conditional expression */
+ expr = build (EQ_EXPR, boolean_type_node,
+ rc_state->received_signal,
+ (tree)DECL_TASKING_CODE_DECL (sigdecl));
+
+ if (!rc_state->if_generated)
+ {
+ expand_start_cond (expr, 0);
+ rc_state->if_generated = 1;
+ }
+ else
+ expand_start_elseif (expr);
+
+ if (IDENTIFIER_SIGNAL_DATA (signame))
+ {
+ /* copy data from signal buffer to user's variables */
+ tree typelist = TYPE_FIELDS (TREE_TYPE (sigdecl));
+ tree valtail, typetail;
+ int parmno = 1;
+ tree pointer_type = build_chill_pointer_type (TREE_TYPE (sigdecl));
+ tree pointer = convert (pointer_type, rc_state->databufp);
+
+ for (valtail = nreverse (loclist), typetail = typelist;
+ valtail != NULL_TREE && typetail != NULL_TREE;
+ parmno++, valtail = TREE_CHAIN (valtail),
+ typetail = TREE_CHAIN (typetail))
+ {
+ register tree actual = valtail ? TREE_VALUE (valtail) : 0;
+ register tree type = typetail ? TREE_TYPE (typetail) : 0;
+ register tree assgn;
+ char place[30];
+ sprintf (place, "signal field %d", parmno);
+
+ assgn = build_component_ref (build1 (INDIRECT_REF,
+ TREE_TYPE (sigdecl),
+ pointer),
+ DECL_NAME (typetail));
+ if (!CH_TYPE_NONVALUE_P (type))
+ /* don't assign to non-value type. Error printed at signal definition */
+ chill_expand_assignment (actual, NOP_EXPR, assgn);
+ }
+
+ if (valtail == NULL_TREE && typetail != NULL_TREE)
+ error ("too few data fields provided for `%s'",
+ IDENTIFIER_POINTER (signame));
+ if (valtail != NULL_TREE && typetail == NULL_TREE)
+ error ("too many data fields provided for `%s'",
+ IDENTIFIER_POINTER (signame));
+ }
+
+ /* last action here */
+ emit_line_note (input_filename, lineno);
+
+ return build_tree_list (loclist, signame);
+}
+
+static tree
+build_receive_buffer_case_label (buffer, loclist)
+ tree buffer, loclist;
+{
+ struct rc_state_type *rc_state = current_rc_state;
+ tree buftype = buffer_element_mode (TREE_TYPE (buffer));
+ tree expr, var;
+ tree pointer_type, pointer, assgn;
+ int had_errors = 0;
+ tree x, y, z, bufaddr;
+
+ if (rc_state->sigseen != 0)
+ {
+ error ("BUFFER in RECEIVE CASE alternative follows");
+ error (" a SIGNAL name on line %d", rc_state->sigseen);
+ return error_mark_node;
+ }
+ rc_state->bufseen = lineno;
+ rc_state->sigseen = 0;
+
+ if (! CH_REFERABLE (buffer))
+ {
+ error ("BUFFER in RECEIVE CASE alternative must be a location.");
+ return error_mark_node;
+ }
+
+ if (TREE_CHAIN (loclist) != NULL_TREE)
+ {
+ error ("buffer receive alternative requires only 1 defining occurence.");
+ return error_mark_node;
+ }
+
+ if (!rc_state->call_generated)
+ {
+ tree wait_call;
+
+ /* here we change the mode of rc_state->sig_code to
+ REF ARRAY (0:65535) REF __tmp_DESCR_type.
+ This is neccesary, cause we cannot evaluate the buffer twice
+ (once here where we compare against the address of the buffer
+ and second in build_receive_buffer_case_end, where we use the
+ address build the descriptor, which gets passed to __wait_buffer).
+ So we change the comparison from
+ if (rc_state->received_buffer == &buffer)
+ to
+ if (rc_state->received_buffer ==
+ rc_state->sig_codep->[rc_state->bufcnt]->datap).
+
+ This will evaluate the buffer location only once
+ (in build_receive_buffer_case_end) and therefore doesn't confuse
+ our machinery. */
+
+ tree reftmpdescr = build_chill_pointer_type (
+ TREE_TYPE (lookup_name (
+ get_identifier ("__tmp_DESCR_type"))));
+ tree idxtype = build_chill_range_type (NULL_TREE,
+ integer_zero_node,
+ build_int_2 (65535, 0)); /* should be enough, probably use ULONG */
+ tree arrtype = build_chill_array_type (reftmpdescr,
+ tree_cons (NULL_TREE, idxtype, NULL_TREE),
+ 0, NULL_TREE);
+ tree refarrtype = build_chill_pointer_type (arrtype);
+
+ TREE_VALUE (rc_state->actuallist) = force_addr_of (rc_state->received_buffer);
+ wait_call = build_chill_function_call (
+ lookup_name (get_identifier ("__wait_buffer")),
+ rc_state->actuallist);
+#if 0
+ chill_expand_assignment (rc_state->received_buffer,
+ NOP_EXPR, wait_call);
+#endif
+ build_timesupervised_call (wait_call, rc_state->to_loc);
+
+ /* do this after the call, otherwise there will be a mode mismatch */
+ TREE_TYPE (rc_state->sig_code) = refarrtype;
+
+ /* now we are ready to generate the call */
+ rc_state->call_generated = 1;
+ }
+
+ x = build_chill_indirect_ref (rc_state->sig_code, NULL_TREE, 0);
+ y = build_chill_array_ref (x,
+ tree_cons (NULL_TREE, build_int_2 (rc_state->bufcnt, 0), NULL_TREE));
+ z = build_chill_indirect_ref (y, NULL_TREE, 0);
+ bufaddr = build_chill_component_ref (z, get_identifier ("datap"));
+
+ /* build the conditional expression */
+ expr = build (EQ_EXPR, boolean_type_node,
+ rc_state->received_buffer,
+ bufaddr);
+
+ /* next buffer in list */
+ rc_state->bufcnt++;
+
+ if (!rc_state->if_generated)
+ {
+ expand_start_cond (expr, 0);
+ rc_state->if_generated = 1;
+ }
+ else
+ expand_start_elseif (expr);
+
+ /* copy buffer's data to destination */
+ var = TREE_VALUE (loclist);
+
+ if (buftype != NULL_TREE && TREE_CODE (buftype) == ERROR_MARK)
+ had_errors = 1;
+ else if (! CH_COMPATIBLE (var, buftype))
+ {
+ error ("incompatible modes in receive buffer alternative.");
+ had_errors = 1;
+ }
+
+ if (! CH_LOCATION_P (var))
+ {
+ error ("defining occurence in receive buffer alternative must be a location.");
+ had_errors = 1;
+ }
+
+ if (! had_errors)
+ {
+ pointer_type = build_chill_pointer_type (TREE_TYPE (var));
+ pointer = convert (pointer_type,
+ rc_state->databufp);
+ /* no need to check this pointer being NULL */
+ assgn = build_chill_indirect_ref (pointer, NULL_TREE, 0);
+
+ chill_expand_assignment (var, NOP_EXPR, assgn);
+ }
+
+ /* last action here */
+ emit_line_note (input_filename, lineno);
+
+ return build_tree_list (loclist, buffer);
+}
+/*
+ * SIGNAME is the signal name or buffer location,
+ * LOCLIST is a list of possible locations to store data in
+ */
+tree
+build_receive_case_label (signame, loclist)
+ tree signame, loclist;
+{
+ /* now see what we have got and do some checks */
+ if (TREE_CODE (signame) == TYPE_DECL && CH_DECL_SIGNAL (signame))
+ return build_receive_signal_case_label (signame, loclist);
+
+ if (TREE_TYPE (signame) != NULL_TREE
+ && CH_IS_BUFFER_MODE (TREE_TYPE (signame)))
+ {
+ if (loclist == NULL_TREE)
+ {
+ error ("buffer receive alternative without `IN location'.");
+ return error_mark_node;
+ }
+ return build_receive_buffer_case_label (signame, loclist);
+ }
+
+ error ("RECEIVE CASE alternative must specify a SIGNAL name or BUFFER location.");
+ return error_mark_node;
+}
+
+/*
+ * LABEL_CNT is the case-label counter passed from build_receive_case_start.
+ * ELSE_CLAUSE defines if the RECEIVE CASE action had an ELSE(1) or not(0).
+ * BUF_LIST is a tree-list of tree-lists, where TREE_VALUE defines the
+ * BUFFER location and TREE_PURPOSE defines the defining occurence.
+ */
+static void
+build_receive_buffer_case_end (label_cnt, buf_list, else_clause)
+ tree label_cnt, buf_list, else_clause;
+{
+ struct rc_state_type *rc_state = current_rc_state;
+ tree alist;
+ tree field_decls = NULL_TREE; /* list of all buffer types, for the union */
+ int buffer_cnt = 0;
+ tree descr_type = lookup_name (get_identifier ("__tmp_DESCR_type"));
+ tree tuple = NULL_TREE; /* constructors for array of ptrs */
+ tree union_type_node = NULL_TREE;
+
+ /* walk thru all the buffers */
+ for (alist = buf_list; alist != NULL_TREE;
+ buffer_cnt++, alist = TREE_CHAIN (alist))
+ {
+ tree value = TREE_VALUE (alist);
+ tree buffer = TREE_VALUE (value); /* this is the buffer */
+ tree data = TREE_VALUE (TREE_PURPOSE (value)); /* the location to receive in */
+ tree buffer_descr;
+ tree buffer_descr_init;
+ tree buffer_length;
+ tree buffer_ptr;
+ tree field;
+ char fldname[20];
+
+ /* build descriptor for buffer */
+ buffer_length = max_queue_size (TREE_TYPE (buffer));
+ if (buffer_length == NULL_TREE)
+ buffer_length = infinite_buffer_event_length_node;
+ buffer_descr_init = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE, force_addr_of (buffer),
+ tree_cons (NULL_TREE, buffer_length, NULL_TREE)));
+ buffer_descr = decl_temp1 (get_unique_identifier ("RCbuffer"),
+ TREE_TYPE (descr_type), 0,
+ buffer_descr_init, 0, 0);
+ tuple = tree_cons (NULL_TREE,
+ force_addr_of (buffer_descr),
+ tuple);
+
+ /* make a field for the union */
+ sprintf (fldname, "fld%03d", buffer_cnt);
+ field = grok_chill_fixedfields (
+ tree_cons (NULL_TREE, get_identifier (fldname), NULL_TREE),
+ TREE_TYPE (data), NULL_TREE);
+ if (field_decls == NULL_TREE)
+ field_decls = field;
+ else
+ chainon (field_decls, field);
+ }
+
+ /* generate the union */
+ if (field_decls != NULL_TREE)
+ {
+ tree data_id = get_identifier ("databuffer");
+ tree data_decl;
+
+ union_type_node = finish_struct (
+ start_struct (UNION_TYPE, NULL_TREE),
+ field_decls);
+ data_decl = decl_temp1 (data_id, union_type_node, 0, NULL_TREE, 0, 0);
+
+ chill_expand_assignment (rc_state->databufp, NOP_EXPR,
+ force_addr_of (data_decl));
+
+ chill_expand_assignment (rc_state->datalen, NOP_EXPR,
+ size_in_bytes (TREE_TYPE (data_decl)));
+ }
+
+ /* tell runtime system if we had an else or not */
+ chill_expand_assignment (rc_state->else_clause, NOP_EXPR, else_clause);
+
+ /* generate the array of pointers to all buffers */
+ {
+ tree array_id = get_identifier ("buf_ptr_array");
+ tree array_type_node =
+ build_chill_array_type (ptr_type_node,
+ tree_cons (NULL_TREE,
+ build_chill_range_type (NULL_TREE,
+ integer_one_node,
+ build_int_2 (buffer_cnt, 0)),
+ NULL_TREE),
+ 0, NULL_TREE);
+ tree constr = build_nt (CONSTRUCTOR, NULL_TREE, nreverse (tuple));
+ tree array_decl = decl_temp1 (array_id, array_type_node, 0,
+ constr, 0, 0);
+
+ chill_expand_assignment (build_chill_cast (ptr_type_node, rc_state->sig_code),
+ NOP_EXPR,
+ force_addr_of (array_decl));
+ chill_expand_assignment (rc_state->n_sigs, NOP_EXPR,
+ build_int_2 (buffer_cnt, 0));
+ }
+}
+
+/*
+ * SIG_LIST is a tree list. The TREE_VALUEs are VAR_DECLs of
+ * __tmp_%s_code variables, and the TREE_PURPOSEs are the
+ * TYPE_DECLs of the __tmp_%s_struct types. LABEL_CNT is the
+ * case-label counter passed from build_receive_case_start.
+ */
+static void
+build_receive_signal_case_end (label_cnt, sig_list, else_clause)
+ tree label_cnt, sig_list, else_clause;
+{
+ struct rc_state_type *rc_state = current_rc_state;
+ tree alist, temp1;
+ tree union_type_node = NULL_TREE;
+ tree field_decls = NULL_TREE; /* list of signal
+ structure, for the union */
+ tree tuple = NULL_TREE; /* constructor for array of ptrs */
+ int signal_cnt = 0;
+ int fldcnt = 0;
+
+ /* for each list of locations, validate it against the
+ corresponding signal's list of fields. */
+ {
+ for (alist = sig_list; alist != NULL_TREE;
+ signal_cnt++, alist = TREE_CHAIN (alist))
+ {
+ tree value = TREE_VALUE (alist);
+ tree signame = TREE_VALUE (value); /* signal's ID node */
+ tree sigdecl = lookup_name (signame);
+ tree sigtype = TREE_TYPE (sigdecl);
+ tree field;
+ char fldname[20];
+
+ if (IDENTIFIER_SIGNAL_DATA (signame))
+ {
+ sprintf (fldname, "fld%03d", fldcnt++);
+ field = grok_chill_fixedfields (
+ tree_cons (NULL_TREE,
+ get_identifier (fldname),
+ NULL_TREE),
+ sigtype, NULL_TREE);
+ if (field_decls == NULL_TREE)
+ field_decls = field;
+ else
+ chainon (field_decls, field);
+
+ }
+
+ temp1 = (tree)DECL_TASKING_CODE_DECL (sigdecl);
+ mark_addressable (temp1);
+ tuple = tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR,
+ build_chill_pointer_type (chill_integer_type_node),
+ temp1),
+ tuple);
+ }
+ }
+
+ /* generate the union of all of the signal data types */
+ if (field_decls != NULL_TREE)
+ {
+ tree data_id = get_identifier ("databuffer");
+ tree data_decl;
+ union_type_node = finish_struct (start_struct (UNION_TYPE,
+ NULL_TREE),
+ field_decls);
+ data_decl =
+ decl_temp1 (data_id, union_type_node, 0, NULL_TREE, 0, 0);
+
+ chill_expand_assignment (rc_state->databufp, NOP_EXPR,
+ force_addr_of (data_decl));
+
+ chill_expand_assignment (rc_state->datalen, NOP_EXPR,
+ size_in_bytes (TREE_TYPE (data_decl)));
+ }
+
+ /* tell runtime system if we had an else or not */
+ chill_expand_assignment (rc_state->else_clause, NOP_EXPR, else_clause);
+
+ /* generate the array of all signal codes */
+ {
+ tree array_id = get_identifier ("sig_code_array");
+ tree array_type_node
+ = build_chill_array_type (
+ build_chill_pointer_type (chill_integer_type_node),
+ tree_cons (NULL_TREE,
+ build_chill_range_type (NULL_TREE,
+ integer_one_node,
+ build_int_2 (signal_cnt, 0)),
+ NULL_TREE),
+ 0, NULL_TREE);
+ tree constr = build_nt (CONSTRUCTOR, NULL_TREE,
+ nreverse (tuple));
+ tree array_decl =
+ decl_temp1 (array_id, array_type_node, 0, constr, 0, 0);
+
+ chill_expand_assignment (rc_state->sig_code, NOP_EXPR,
+ force_addr_of (array_decl));
+
+ /* give number of signals to runtime system */
+ chill_expand_assignment (rc_state->n_sigs, NOP_EXPR,
+ build_int_2 (signal_cnt, 0));
+ }
+}
+
+/* General function for the end of a RECEIVE CASE action */
+
+void
+build_receive_case_end (label_cnt, alist, else_clause)
+ tree label_cnt, alist, else_clause;
+{
+ rtx rcdone = gen_label_rtx ();
+ struct rc_state_type *rc_state = current_rc_state;
+ tree tmp;
+ int had_errors = 0;
+
+ /* finish the if's, if generated */
+ if (rc_state->if_generated)
+ expand_end_cond ();
+
+ /* check alist for errors */
+ for (tmp = alist; tmp != NULL_TREE; tmp = TREE_CHAIN (tmp))
+ {
+ if (TREE_CODE (TREE_VALUE (tmp)) == ERROR_MARK)
+ had_errors++;
+ }
+
+ /* jump to the end of RECEIVE CASE processing */
+ emit_jump (rcdone);
+
+ /* define the __rcsetup label. We come here to initialize
+ all variables */
+ emit_label (rc_state->rcsetup);
+
+ if (alist == NULL_TREE && !had_errors)
+ {
+ error ("RECEIVE CASE without alternatives");
+ goto gen_rcdoit;
+ }
+
+ if (TREE_CODE (alist) == ERROR_MARK || had_errors)
+ goto gen_rcdoit;
+
+ /* now call the actual end function */
+ if (rc_state->bufseen)
+ build_receive_buffer_case_end (label_cnt, alist, else_clause);
+ else
+ build_receive_signal_case_end (label_cnt, alist, else_clause);
+
+ /* now jump to the beginning of RECEIVE CASE processing */
+gen_rcdoit: ;
+ emit_jump (rc_state->rcdoit);
+
+ /* define the __rcdone label. We come here when the whole
+ receive case is done. */
+ emit_label (rcdone);
+
+ current_rc_state = rc_state->enclosing;
+ free(rc_state);
+}
+
+/* build a CONTINUE action */
+
+void expand_continue_event (evloc)
+ tree evloc;
+{
+ tree filename, linenumber, evaddr;
+
+ /* do some checks */
+ if (evloc == NULL_TREE || TREE_CODE (evloc) == ERROR_MARK)
+ return;
+
+ if (! CH_REFERABLE (evloc) || ! CH_IS_EVENT_MODE (TREE_TYPE (evloc)))
+ {
+ error ("CONTINUE requires an event location.");
+ return;
+ }
+
+ evaddr = force_addr_of (evloc);
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (get_identifier ("__continue")),
+ tree_cons (NULL_TREE, evaddr,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE)))));
+}
+
+#if 0
+ * The following code builds a DELAY CASE statement,
+ * which looks like this in CHILL:
+ *
+ * DCL ev1, ev2 EVENT, ins INSTANCE;
+ * DCL ev3 EVENT (10);
+ * DCL count1 INT := 0, count2 INT := 0;
+ *
+ * DELAY CASE SET ins;
+ * (ev1): count1 +:= 1;
+ * (ev2, ev3): count2 +:= 1;
+ * ESAC;
+ *
+ * Because we don''t know until we get to the ESAC how
+ * many events need processing, we generate the following
+ * C-equivalent code:
+ *
+ *
+ * { /* start a new symbol context */
+ * typedef struct
+ * {
+ * void *p;
+ * unsigned long len;
+ * } Descr;
+ * int number_of_events;
+ * Descr *event_codes;
+ *
+ * goto __dlsetup;
+ *
+ * __dldoit:
+ * void *whatevent = __delay_event (number_of_events,
+ * event_codes,
+ * priority,
+ * &instance_loc,
+ * filename,
+ * linenumber);
+ * if (whatevent == &ev1)
+ * {
+ * /* code for ev1 alternative's action_statement_list */
+ * count1 += 1;
+ * }
+ * else if (whatevent == &ev2 || whatevent == &ev3)
+ * {
+ * /* code for ev2 and ev3 alternative's action_statement_list */
+ * count2 += 1;
+ * }
+ * goto __dl_done;
+ *
+ * __dlsetup:
+ * Descr event_code_ptr [3] = {
+ * { &ev1, -1 },
+ * { &ev2, -1 },
+ * { &ev3, 10 } };
+ * event_codes = &event_code_ptr[0];
+ * number_of_events = 3;
+ * goto __dldoit;
+ *
+ * __dl_done:
+ * ;
+ * } /* end the new symbol context */
+ *
+#endif
+
+struct dl_state_type
+{
+ struct dl_state_type *enclosing;
+ rtx dldoit;
+ rtx dlsetup;
+ tree n_events;
+ tree event_codes;
+ tree received_event;
+};
+
+struct dl_state_type *current_dl_state = NULL;
+
+/* build_receive_case_start returns an INTEGER_CST node
+ containing the case-label number to be used by
+ build_receive_case_end to generate correct labels */
+tree
+build_delay_case_start (optset, optpriority)
+ tree optset, optpriority;
+{
+ /* counter to generate unique delay case labels */
+ static int dl_lbl_count = 0;
+ tree current_label_value =
+ build_int_2 ((HOST_WIDE_INT)dl_lbl_count, 0);
+ tree wait_call;
+ tree actuallist = NULL_TREE;
+ tree filename, linenumber;
+ tree to_loc;
+
+ struct dl_state_type *dl_state
+ = (struct dl_state_type*) xmalloc (sizeof (struct dl_state_type));
+ dl_state->enclosing = current_dl_state;
+ current_dl_state = dl_state;
+ dl_state->dldoit = gen_label_rtx ();
+ dl_state->dlsetup = gen_label_rtx ();
+
+ dl_lbl_count++;
+
+ /* check the optional SET location */
+ if (optset == NULL_TREE
+ || TREE_CODE (optset) == ERROR_MARK)
+ optset = null_pointer_node;
+ else if (CH_IS_INSTANCE_MODE (TREE_TYPE (optset)) && CH_LOCATION_P (optset))
+ optset = force_addr_of (optset);
+ else
+ {
+ error ("SET requires INSTANCE location");
+ optset = null_pointer_node;
+ }
+
+ /* check the presence of the PRIORITY expression */
+ if (optpriority == NULL_TREE)
+ optpriority = integer_zero_node;
+ else if (TREE_CODE (optpriority) == ERROR_MARK)
+ optpriority = integer_zero_node;
+ else if (TREE_CODE (TREE_TYPE (optpriority)) != INTEGER_TYPE)
+ {
+ error ("PRIORITY must be of integer type.");
+ optpriority = integer_zero_node;
+ }
+
+ /* check for time supervised */
+ to_loc = build_timeout_preface ();
+
+ dl_state->n_events =
+ decl_temp1 (get_identifier ("number_of_events"),
+ integer_type_node, 0, integer_zero_node, 0, 0);
+
+ dl_state->event_codes =
+ decl_temp1 (get_identifier ("event_codes"),
+ ptr_type_node, 0, null_pointer_node, 0, 0);
+
+ /* wait_event will store the signal number in here */
+ dl_state->received_event =
+ decl_temp1 (get_identifier ("received_event"),
+ ptr_type_node, 0, NULL_TREE, 0, 0);
+
+ /* now jump to the end of RECEIVE CASE actions, to
+ set up variables for them. */
+ emit_jump (dl_state->dlsetup);
+
+ /* define the __rcdoit label. We come here after
+ initialization of all variables, to execute the
+ actions. */
+ emit_label (dl_state->dldoit);
+
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ /* here we go, call the runtime routine */
+ actuallist = tree_cons (NULL_TREE, force_addr_of (dl_state->received_event),
+ tree_cons (NULL_TREE, dl_state->n_events,
+ tree_cons (NULL_TREE, dl_state->event_codes,
+ tree_cons (NULL_TREE, optpriority,
+ tree_cons (NULL_TREE, to_loc,
+ tree_cons (NULL_TREE, optset,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE))))))));
+
+ wait_call = build_chill_function_call (
+ lookup_name (get_identifier ("__delay_event")),
+ actuallist);
+
+#if 0
+ chill_expand_assignment (dl_state->received_event, NOP_EXPR, wait_call);
+#endif
+ build_timesupervised_call (wait_call, to_loc);
+ return current_label_value;
+}
+
+/*
+ EVENTLIST is the list of this alternative's events
+ and IF_OR_ELSEIF indicates what action (1 for if and
+ 0 for else if) should be generated.
+*/
+void
+build_delay_case_label (eventlist, if_or_elseif)
+ tree eventlist;
+ int if_or_elseif;
+{
+ tree eventp, expr = NULL_TREE;
+
+ if (eventlist == NULL_TREE || TREE_CODE (eventlist) == ERROR_MARK)
+ return;
+
+ for (eventp = eventlist; eventp != NULL_TREE;
+ eventp = TREE_CHAIN (eventp))
+ {
+ tree event = TREE_VALUE (eventp);
+ tree temp1;
+
+ if (event == NULL_TREE || TREE_CODE (event) == ERROR_MARK)
+ temp1 = null_pointer_node;
+ else if (! CH_IS_EVENT_MODE (TREE_TYPE (event)) || ! CH_REFERABLE (event))
+ {
+ error ("delay alternative must be an EVENT location.");
+ temp1 = null_pointer_node;
+ }
+ else
+ temp1 = force_addr_of (event);
+
+ /* build the conditional expression */
+ if (expr == NULL_TREE)
+ expr = build (EQ_EXPR, boolean_type_node,
+ current_dl_state->received_event, temp1);
+ else
+ expr =
+ build (TRUTH_ORIF_EXPR, boolean_type_node, expr,
+ build (EQ_EXPR, boolean_type_node,
+ current_dl_state->received_event, temp1));
+ }
+ if (if_or_elseif)
+ expand_start_cond (expr, 0);
+ else
+ expand_start_elseif (expr);
+
+ /* last action here */
+ emit_line_note (input_filename, lineno);
+}
+
+/*
+ * EVENT_LIST is a tree list. The TREE_VALUEs are VAR_DECLs of
+ * EVENT variables. LABEL_CNT is the case-label counter
+ * passed from build_delay_case_start.
+ */
+void
+build_delay_case_end (label_cnt, event_list)
+ tree label_cnt, event_list;
+{
+ struct dl_state_type *dl_state = current_dl_state;
+ rtx dldone = gen_label_rtx ();
+ tree tuple = NULL_TREE; /* constructor for array of descrs */
+ tree acode;
+ int event_cnt = 0;
+
+ /* if we have an empty event_list, there was no alternatives and we
+ havn't started an if therefor don't run expand_end_cond */
+ if (event_list != NULL_TREE)
+ /* finish the if's */
+ expand_end_cond ();
+
+ /* jump to the end of RECEIVE CASE processing */
+ emit_jump (dldone);
+
+ /* define the __dlsetup label. We come here to initialize
+ all variables */
+ emit_label (dl_state->dlsetup);
+
+ if (event_list == NULL_TREE)
+ {
+ error ("DELAY CASE without alternatives");
+ goto gen_dldoit;
+ }
+
+ if (event_list == NULL_TREE
+ || TREE_CODE (event_list) == ERROR_MARK)
+ goto gen_dldoit;
+
+ /* make a list of pointers (in reverse order)
+ to the event code variables */
+ for (acode = event_list; acode != NULL_TREE;
+ acode = TREE_CHAIN (acode))
+ {
+ tree event = TREE_VALUE (acode);
+ tree event_length;
+ tree descr_init;
+
+ if (event == NULL_TREE || TREE_CODE (event) == ERROR_MARK)
+ {
+ descr_init =
+ tree_cons (NULL_TREE, null_pointer_node,
+ tree_cons (NULL_TREE, integer_zero_node, NULL_TREE));
+ }
+ else
+ {
+ event_length = max_queue_size (TREE_TYPE (event));
+ if (event_length == NULL_TREE)
+ event_length = infinite_buffer_event_length_node;
+ descr_init =
+ tree_cons (NULL_TREE, force_addr_of (event),
+ tree_cons (NULL_TREE, event_length, NULL_TREE));
+ }
+ tuple = tree_cons (NULL_TREE,
+ build_nt (CONSTRUCTOR, NULL_TREE, descr_init),
+ tuple);
+ event_cnt++;
+ }
+
+ /* generate the array of all event code pointers */
+ {
+ tree descr_type = TREE_TYPE (lookup_name (get_identifier ("__tmp_DESCR_type")));
+ tree array_id = get_identifier ("event_code_array");
+ tree array_type_node
+ = build_chill_array_type (descr_type,
+ tree_cons (NULL_TREE,
+ build_chill_range_type (NULL_TREE,
+ integer_one_node,
+ build_int_2 (event_cnt, 0)),
+ NULL_TREE),
+ 0, NULL_TREE);
+ tree constr = build_nt (CONSTRUCTOR, NULL_TREE,
+ nreverse (tuple));
+ tree array_decl =
+ decl_temp1 (array_id, array_type_node, 0, constr, 0, 0);
+
+ chill_expand_assignment (dl_state->event_codes, NOP_EXPR,
+ force_addr_of (array_decl));
+
+ /* give number of signals to runtime system */
+ chill_expand_assignment (dl_state->n_events, NOP_EXPR,
+ build_int_2 (event_cnt, 0));
+ }
+
+ /* now jump to the beginning of DELAY CASE processing */
+gen_dldoit:
+ emit_jump (dl_state->dldoit);
+
+ /* define the __dldone label. We come here when the whole
+ DELAY CASE is done. */
+ emit_label (dldone);
+
+ current_dl_state = dl_state->enclosing;
+ free(dl_state);
+}
+
+#if 0
+ * The following code builds a simple delay statement,
+ * which looks like this in CHILL:
+ *
+ * DCL ev1 EVENT(5), ins INSTANCE;
+ *
+ * DELAY ev1 PRIORITY 7;
+ *
+ * This statement unconditionally delays the current
+ * PROCESS, until some other process CONTINUEs it.
+ *
+ * Here is the generated C code:
+ *
+ * typedef struct
+ * {
+ * void *p;
+ * unsigned long len;
+ * } Descr;
+ *
+ * static short __tmp_ev1_code;
+ *
+ * { /* start a new symbol context */
+ *
+ * Descr __delay_array[1] = { { ev1, 5 } };
+ *
+ * __delay_event (1, &__delay_array, 7, NULL,
+ * filename, linenumber);
+ *
+ * } /* end of symbol scope */
+ */
+#endif
+void
+build_delay_action (event, optpriority)
+ tree event, optpriority;
+{
+ int had_errors = 0;
+ tree to_loc = NULL_TREE;
+ /* we discard the return value of __delay_event, cause in
+ a normal DELAY action no selections have to be made */
+ tree ev_got = null_pointer_node;
+
+ /* check the event */
+ if (event == NULL_TREE || TREE_CODE (event) == ERROR_MARK)
+ had_errors = 1;
+ else if (! CH_IS_EVENT_MODE (TREE_TYPE (event)) || ! CH_REFERABLE (event))
+ {
+ error ("DELAY action requires an event location.");
+ had_errors = 1;
+ }
+
+ /* check the presence of priority */
+ if (optpriority != NULL_TREE)
+ {
+ if (TREE_CODE (optpriority) == ERROR_MARK)
+ return;
+ if (TREE_CODE (TREE_TYPE (optpriority)) != INTEGER_TYPE)
+ {
+ error ("PRIORITY in DELAY action must be of integer type.");
+ return;
+ }
+ }
+ else
+ {
+ /* issue a warning in case of -Wall */
+ if (extra_warnings)
+ {
+ warning ("DELAY action without priority.");
+ warning (" PRIORITY defaulted to 0.");
+ }
+ optpriority = integer_zero_node;
+ }
+ if (had_errors)
+ return;
+
+ {
+ tree descr_type;
+ tree array_type_node;
+ tree array_decl;
+ tree descr_init;
+ tree array_init;
+ tree event_length = max_queue_size (TREE_TYPE (event));
+ tree event_codes;
+ tree filename = force_addr_of (get_chill_filename ());
+ tree linenumber = get_chill_linenumber ();
+ tree actuallist;
+
+ to_loc = build_timeout_preface ();
+
+ descr_type = TREE_TYPE (lookup_name (get_identifier ("__tmp_DESCR_type")));
+
+ array_type_node =
+ build_chill_array_type (descr_type,
+ tree_cons (NULL_TREE,
+ build_chill_range_type (NULL_TREE, integer_one_node,
+ integer_one_node),
+ NULL_TREE),
+ 0, NULL_TREE);
+ if (event_length == NULL_TREE)
+ event_length = infinite_buffer_event_length_node;
+
+ descr_init =
+ tree_cons (NULL_TREE, force_addr_of (event),
+ tree_cons (NULL_TREE, event_length, NULL_TREE));
+ array_init =
+ tree_cons (NULL_TREE,
+ build_nt (CONSTRUCTOR, NULL_TREE, descr_init),
+ NULL_TREE);
+ array_decl =
+ decl_temp1 (get_unique_identifier ("event_codes_array"),
+ array_type_node, 0,
+ build_nt (CONSTRUCTOR, NULL_TREE, array_init),
+ 0, 0);
+
+ event_codes =
+ decl_temp1 (get_unique_identifier ("event_ptr"),
+ ptr_type_node, 0,
+ force_addr_of (array_decl),
+ 0, 0);
+
+ actuallist =
+ tree_cons (NULL_TREE, ev_got,
+ tree_cons (NULL_TREE, integer_one_node,
+ tree_cons (NULL_TREE, event_codes,
+ tree_cons (NULL_TREE, optpriority,
+ tree_cons (NULL_TREE, to_loc,
+ tree_cons (NULL_TREE, null_pointer_node,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE))))))));
+
+
+ build_timesupervised_call (
+ build_chill_function_call (
+ lookup_name (get_identifier ("__delay_event")),
+ actuallist), to_loc);
+ }
+}
+
+void
+expand_send_buffer (buffer, value, optpriority, optwith, optto)
+ tree buffer, value, optpriority, optwith, optto;
+{
+ tree filename, linenumber;
+ tree buffer_mode_decl = NULL_TREE;
+ tree buffer_ptr, value_ptr;
+ int had_errors = 0;
+ tree timeout_value, fcall;
+
+ /* check buffer location */
+ if (buffer == NULL_TREE || TREE_CODE (buffer) == ERROR_MARK)
+ {
+ buffer = NULL_TREE;
+ had_errors = 1;
+ }
+ if (buffer != NULL_TREE)
+ {
+ if (! CH_IS_BUFFER_MODE (TREE_TYPE (buffer)) || ! CH_REFERABLE (buffer))
+ {
+ error ("send buffer action requires a BUFFER location.");
+ had_errors = 1;
+ }
+ else
+ buffer_mode_decl = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (buffer)));
+ }
+
+ /* check value and type */
+ if (value == NULL_TREE || TREE_CODE (value) == ERROR_MARK)
+ {
+ had_errors = 1;
+ value = NULL_TREE;
+ }
+ if (value != NULL_TREE)
+ {
+ if (TREE_CHAIN (value) != NULL_TREE)
+ {
+ error ("there must be only 1 value for send buffer action.");
+ had_errors = 1;
+ }
+ else
+ {
+ value = TREE_VALUE (value);
+ if (value == NULL_TREE || TREE_CODE (value) == ERROR_MARK)
+ {
+ had_errors = 1;
+ value = NULL_TREE;
+ }
+ if (value != NULL_TREE && buffer_mode_decl != NULL_TREE)
+ {
+ if (TREE_TYPE (buffer_mode_decl) != NULL_TREE &&
+ TREE_CODE (TREE_TYPE (buffer_mode_decl)) == ERROR_MARK)
+ had_errors = 1;
+ else if (CH_COMPATIBLE (value, TREE_TYPE (buffer_mode_decl)))
+ {
+ value = convert (TREE_TYPE (buffer_mode_decl), value);
+ if (value == NULL_TREE || TREE_CODE (value) == ERROR_MARK)
+ {
+ error ("convert failed for send buffer action.");
+ had_errors = 1;
+ }
+ }
+ else
+ {
+ error ("incompatible modes in send buffer action.");
+ had_errors = 1;
+ }
+ }
+ }
+ }
+
+ /* check the presence of priority */
+ if (optpriority == NULL_TREE)
+ {
+ if (send_buffer_prio == NULL_TREE)
+ {
+ /* issue a warning in case of -Wall */
+ if (extra_warnings)
+ {
+ warning ("Buffer sent without priority");
+ warning (" and no default priority was set.");
+ warning (" PRIORITY defaulted to 0.");
+ }
+ optpriority = integer_zero_node;
+ }
+ else
+ optpriority = send_buffer_prio;
+ }
+ else if (TREE_CODE (optpriority) == ERROR_MARK)
+ had_errors = 1;
+ else if (TREE_CODE (TREE_TYPE (optpriority)) != INTEGER_TYPE)
+ {
+ error ("PRIORITY must be of integer type.");
+ had_errors = 1;
+ }
+
+ if (optwith != NULL_TREE)
+ {
+ error ("WITH not allowed for send buffer action.");
+ had_errors = 1;
+ }
+ if (optto != NULL_TREE)
+ {
+ error ("TO not allowed for send buffer action.");
+ had_errors = 1;
+ }
+ if (had_errors)
+ return;
+
+ {
+ tree descr_type;
+ tree buffer_descr, buffer_init, buffer_length;
+ tree val;
+
+ /* process timeout */
+ timeout_value = build_timeout_preface ();
+
+ descr_type = lookup_name (get_identifier ("__tmp_DESCR_type"));
+
+ /* build descr for buffer */
+ buffer_length = max_queue_size (TREE_TYPE (buffer));
+ if (buffer_length == NULL_TREE)
+ buffer_length = infinite_buffer_event_length_node;
+ buffer_init = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE, force_addr_of (buffer),
+ tree_cons (NULL_TREE, buffer_length, NULL_TREE)));
+ buffer_descr = decl_temp1 (get_unique_identifier ("buffer_descr"),
+ TREE_TYPE (descr_type), 0, buffer_init,
+ 0, 0);
+ buffer_ptr = decl_temp1 (get_unique_identifier ("buffer_ptr"),
+ ptr_type_node, 0,
+ force_addr_of (buffer_descr),
+ 0, 0);
+
+ /* build descr for value */
+ if (! CH_REFERABLE (value))
+ val = decl_temp1 (get_identifier ("buffer_value"),
+ TREE_TYPE (value), 0,
+ value, 0, 0);
+ else
+ val = value;
+
+ value_ptr = build_chill_descr (val);
+
+ }
+
+ /* get filename and linenumber */
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ /* Now, we can call the runtime */
+ fcall = build_chill_function_call (
+ lookup_name (get_identifier ("__send_buffer")),
+ tree_cons (NULL_TREE, buffer_ptr,
+ tree_cons (NULL_TREE, value_ptr,
+ tree_cons (NULL_TREE, optpriority,
+ tree_cons (NULL_TREE, timeout_value,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE)))))));
+ build_timesupervised_call (fcall, timeout_value);
+}
+# if 0
+
+void
+process_buffer_decls (namelist, mode, optstatic)
+ tree namelist, mode;
+ int optstatic;
+{
+ tree names;
+ int quasi_flag = current_module->is_spec_module;
+
+ if (pass < 2)
+ return;
+
+ for (names = namelist; names != NULL_TREE; names = TREE_CHAIN (names))
+ {
+ tree name = TREE_VALUE (names);
+ tree bufdecl = lookup_name (name);
+ tree code_decl =
+ decl_tasking_code_variable (name, &buffer_code, quasi_flag);
+
+ /* remember the code variable in the buffer decl */
+ DECL_TASKING_CODE_DECL (bufdecl) = (struct lang_decl *)code_decl;
+
+ add_taskstuff_to_list (code_decl, "_TT_Buffer",
+ quasi_flag ? NULL_TREE : buffer_code,
+ bufdecl);
+ }
+}
+#endif
+
+/*
+ * if no queue size was specified, QUEUESIZE is integer_zero_node.
+ */
+tree
+build_buffer_type (element_type, queuesize)
+ tree element_type, queuesize;
+{
+ tree type, field;
+ if (element_type == NULL_TREE || TREE_CODE (element_type) == ERROR_MARK)
+ return error_mark_node;
+ if (queuesize != NULL_TREE && TREE_CODE (queuesize) == ERROR_MARK)
+ return error_mark_node;
+
+ type = make_node (RECORD_TYPE);
+ field = build_decl (FIELD_DECL, get_identifier("__buffer_data"),
+ ptr_type_node);
+ TYPE_FIELDS (type) = field;
+ TREE_CHAIN (field)
+ = build_lang_decl (TYPE_DECL, get_identifier ("__element_mode"),
+ element_type);
+ field = TREE_CHAIN (field);
+ if (queuesize)
+ {
+ tree size_field = build_decl (CONST_DECL, get_identifier("__queue_max"),
+ integer_type_node);
+ DECL_INITIAL (size_field) = queuesize;
+ TREE_CHAIN (field) = size_field;
+ }
+ CH_IS_BUFFER_MODE (type) = 1;
+ CH_TYPE_NONVALUE_P (type) = 1;
+ if (pass == 2)
+ type = layout_chill_struct_type (type);
+ return type;
+}
+
+#if 0
+tree
+build_buffer_descriptor (bufname, expr, optpriority)
+ tree bufname, expr, optpriority;
+{
+ tree bufdecl;
+
+ if (bufname == NULL_TREE
+ || TREE_CODE (bufname) == ERROR_MARK)
+ return error_mark_node;
+
+ if (expr != NULL_TREE
+ && TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+#if 0
+/* FIXME: is this what we really want to test? */
+ bufdecl = lookup_name (bufname);
+ if (TREE_CODE (bufdecl) != TYPE_DECL
+ || ! CH_IS_BUFFER_MODE (TREE_TYPE (bufdecl)))
+ {
+ error ("SEND requires a BUFFER; `%s' is not a BUFFER name",
+ bufname);
+ return error_mark_node;
+ }
+#endif
+ {
+ /* build buffer/signal data structure */
+ tree bufdataname = get_unique_identifier (IDENTIFIER_POINTER (bufname));
+ tree dataptr;
+
+ if (expr == NULL_TREE)
+ dataptr = null_pointer_node;
+ else
+ {
+ tree decl =
+ decl_temp1 (bufdataname, TREE_TYPE (bufdecl), 0,
+ expr, 0, 0);
+ /* prevent granting of this variable */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ dataptr = force_addr_of (decl);
+ }
+
+ /* build descriptor pointing to buffer data */
+ {
+ tree tasking_message_var = get_unique_identifier (IDENTIFIER_POINTER (bufname));
+ tree data_len = (expr == NULL_TREE) ? integer_zero_node :
+ size_in_bytes (TREE_TYPE (bufdecl));
+ tree tasking_code = (tree)DECL_TASKING_CODE_DECL (bufdecl);
+ tree tuple = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR,
+ build_chill_pointer_type (chill_integer_type_node),
+ tasking_code),
+ tree_cons (NULL_TREE, data_len,
+ tree_cons (NULL_TREE, dataptr, NULL_TREE))));
+
+ tree decl = decl_temp1 (tasking_message_var,
+ TREE_TYPE (tasking_message_type), 0,
+ tuple, 0, 0);
+ mark_addressable (tasking_code);
+ /* prevent granting of this variable */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ tuple = force_addr_of (decl);
+ return tuple;
+ }
+ }
+}
+#endif
+
+#if 0
+void
+process_event_decls (namelist, mode, optstatic)
+ tree namelist, mode;
+ int optstatic;
+{
+ tree names;
+ int quasi_flag = current_module->is_spec_module;
+
+ if (pass < 2)
+ return;
+
+ for (names = namelist; names != NULL_TREE; names = TREE_CHAIN (names))
+ {
+ tree name = TREE_VALUE (names);
+ tree eventdecl = lookup_name (name);
+ tree code_decl =
+ decl_tasking_code_variable (name, &event_code, quasi_flag);
+
+ /* remember the code variable in the event decl */
+ DECL_TASKING_CODE_DECL (eventdecl) = (struct lang_decl *)code_decl;
+
+ add_taskstuff_to_list (code_decl, "_TT_Event",
+ quasi_flag ? NULL_TREE : event_code,
+ eventdecl);
+ }
+}
+#endif
+
+/* Return the buffer or event length of a buffer or event mode.
+ (NULL_TREE means unlimited.) */
+
+tree
+max_queue_size (mode)
+ tree mode;
+{
+ tree field = TYPE_FIELDS (mode);
+ for ( ; field != NULL_TREE ; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == CONST_DECL)
+ return DECL_INITIAL (field);
+ }
+ return NULL_TREE;
+}
+
+/* Return the buffer element mode of a buffer mode. */
+
+tree
+buffer_element_mode (bufmode)
+ tree bufmode;
+{
+ tree field = TYPE_FIELDS (bufmode);
+ for ( ; field != NULL_TREE; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == TYPE_DECL)
+ return TREE_TYPE (field);
+ }
+ return NULL_TREE;
+}
+
+/* invalidate buffer element mode in case we detect, that the
+ elelment mode has the non-value property */
+
+void
+invalidate_buffer_element_mode (bufmode)
+ tree bufmode;
+{
+ tree field = TYPE_FIELDS (bufmode);
+ for ( ; field != NULL_TREE; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == TYPE_DECL)
+ {
+ TREE_TYPE (field) = error_mark_node;
+ return;
+ }
+ }
+}
+
+/* For an EVENT or BUFFER mode TYPE, with a give maximum queue size QSIZE,
+ perform various error checks. Return a new queue size. */
+
+tree
+check_queue_size (type, qsize)
+ tree type, qsize;
+{
+ if (qsize == NULL_TREE || TREE_CODE (qsize) == ERROR_MARK)
+ return qsize;
+ if (TREE_TYPE (qsize) == NULL_TREE
+ || !CH_SIMILAR (TREE_TYPE (qsize), integer_type_node))
+ {
+ error ("non-integral max queue size for EVENT/BUFFER mode");
+ return integer_one_node;
+ }
+ if (TREE_CODE (qsize) != INTEGER_CST)
+ {
+ error ("non-constant max queue size for EVENT/BUFFER mode");
+ return integer_one_node;
+ }
+ if (compare_int_csts (pedantic ? LE_EXPR : LT_EXPR,
+ qsize,
+ integer_zero_node))
+ {
+ error ("max queue_size for EVENT/BUFFER is not positive");
+ return integer_one_node;
+ }
+ return qsize;
+}
+
+/*
+ * An EVENT type is modelled as a boolean type, which should
+ * allocate the minimum amount of space.
+ */
+tree
+build_event_type (queuesize)
+ tree queuesize;
+{
+ tree type = make_node (RECORD_TYPE);
+ tree field = build_decl (FIELD_DECL, get_identifier("__event_data"),
+ ptr_type_node);
+ TYPE_FIELDS (type) = field;
+ if (queuesize)
+ {
+ tree size_field = build_decl (CONST_DECL, get_identifier("__queue_max"),
+ integer_type_node);
+ DECL_INITIAL (size_field) = queuesize;
+ TREE_CHAIN (field) = size_field;
+ }
+ CH_IS_EVENT_MODE (type) = 1;
+ CH_TYPE_NONVALUE_P (type) = 1;
+ if (pass == 2)
+ type = layout_chill_struct_type (type);
+ return type;
+}
+
+/*
+ * Initialize the various types of tasking data.
+ */
+void
+tasking_init ()
+{
+ extern int ignore_case;
+ extern int special_UC;
+ extern tree chill_predefined_function_type;
+ tree temp, ins_ftype_void;
+ tree endlink = void_list_node;
+ tree int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int;
+ tree void_ftype_ptr;
+ tree void_ftype_ptr_ins_int_int_ptr_ptr_int;
+ tree int_ftype_ptr_ptr_int_ptr_ptr_int;
+ tree void_ftype_int_int_int_ptr_ptr_ptr_int;
+ tree int_ftype_ptr_int_ptr_int_ptr_ptr_ptr_int;
+ tree int_ftype_ptr_int;
+
+ /* type of tasking code variables */
+ chill_taskingcode_type_node = short_unsigned_type_node;
+
+ void_ftype_void =
+ build_function_type (void_type_node,
+ tree_cons (NULL_TREE, void_type_node, NULL_TREE));
+
+ build_instance_type ();
+ ins_ftype_void
+ = build_function_type (instance_type_node,
+ tree_cons (NULL_TREE, void_type_node,
+ build_tree_list (NULL_TREE, void_type_node)));
+
+ builtin_function ("__whoami", ins_ftype_void,
+ NOT_BUILT_IN, NULL_PTR);
+
+ build_tasking_message_type ();
+
+ temp = build_decl (TYPE_DECL,
+ get_identifier ("__tmp_TaskingStruct"),
+ build_tasking_struct ());
+ pushdecl (temp);
+ DECL_SOURCE_LINE (temp) = 0;
+
+ /* any SIGNAL will be compatible with this one */
+ generic_signal_type_node = copy_node (boolean_type_node);
+
+ builtin_function ((ignore_case || ! special_UC) ? "copy_number" : "COPY_NUMBER",
+ chill_predefined_function_type,
+ BUILT_IN_COPY_NUMBER, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "gen_code" : "GEN_CODE",
+ chill_predefined_function_type,
+ BUILT_IN_GEN_CODE, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "gen_inst" : "GEN_INST",
+ chill_predefined_function_type,
+ BUILT_IN_GEN_INST, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "gen_ptype" : "GEN_PTYPE",
+ chill_predefined_function_type,
+ BUILT_IN_GEN_PTYPE, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "proc_type" : "PROC_TYPE",
+ chill_predefined_function_type,
+ BUILT_IN_PROC_TYPE, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "queue_length" : "QUEUE_LENGTH",
+ chill_predefined_function_type,
+ BUILT_IN_QUEUE_LENGTH, NULL_PTR);
+
+ int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))))))));
+ void_ftype_ptr
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node, endlink));
+
+ int_ftype_ptr_int_ptr_int_ptr_ptr_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))))));
+
+ void_ftype_ptr_ins_int_int_ptr_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, instance_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))))));
+ int_ftype_ptr_ptr_int_ptr_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))));
+
+ void_ftype_int_int_int_ptr_ptr_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))))));
+
+ int_ftype_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)));
+
+ builtin_function ("__delay_event", int_ftype_ptr_int_ptr_int_ptr_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__queue_length", int_ftype_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__register_tasking", void_ftype_ptr,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__send_signal", void_ftype_ptr_ins_int_int_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__send_buffer", int_ftype_ptr_ptr_int_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__start_process", void_ftype_int_int_int_ptr_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__stop_process", void_ftype_void, NOT_BUILT_IN,
+ NULL_PTR);
+ builtin_function ("__wait_buffer", int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__wait_signal_timed", int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+
+ infinite_buffer_event_length_node = build_int_2 (-1, 0);
+ TREE_TYPE (infinite_buffer_event_length_node) = long_integer_type_node;
+ TREE_UNSIGNED (infinite_buffer_event_length_node) = 1;
+}
diff --git a/gcc/ch/timing.c b/gcc/ch/timing.c
new file mode 100644
index 0000000..f96b715
--- /dev/null
+++ b/gcc/ch/timing.c
@@ -0,0 +1,494 @@
+/* Implement timing-related actions for CHILL.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include "config.h"
+#include "tree.h"
+#include "rtl.h"
+#include "ch-tree.h"
+#include "flags.h"
+#include "input.h"
+#include "obstack.h"
+#include "lex.h"
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+/* set non-zero if input text is forced to lowercase */
+extern int ignore_case;
+
+/* set non-zero if special words are to be entered in uppercase */
+extern int special_UC;
+
+/* timing modes */
+tree abs_timing_type_node;
+tree duration_timing_type_node;
+
+/* rts time type */
+static tree rtstime_type_node = NULL_TREE;
+
+/* the stack for AFTER primval [ DELAY ] IN
+ and has following layout
+
+ TREE_VALUE (TREE_VALUE (after_stack)) = current time or NULL_TREE (if DELAY specified)
+ TREE_PURPOSE (TREE_VALUE (after_stack)) = the duration location
+ TREE_VALUE (TREE_PURPOSE (after_stack)) = label at TIMEOUT
+ TREE_PURPOSE (TREE_PURPOSE (after_stack)) = label at the end of AFTER action
+*/
+tree after_stack = NULL_TREE;
+
+/* in pass 1 we need a seperate list for the labels */
+static tree after_stack_pass_1 = NULL_TREE;
+static tree after_help;
+
+void
+timing_init ()
+{
+ tree ptr_ftype_durt_ptr_int;
+ tree int_ftype_abst_ptr_int;
+ tree void_ftype_ptr;
+ tree long_ftype_int_int_int_int_int_int_int_ptr_int;
+ tree void_ftype_abstime_ptr;
+ tree int_ftype_ptr_durt_ptr;
+ tree void_ftype_durt_ptr;
+ tree void_ftype_ptr_durt_ptr_int;
+ tree temp;
+ tree endlink;
+ tree ulong_type;
+
+ ulong_type = TREE_TYPE (lookup_name (
+ get_identifier ((ignore_case || ! special_UC ) ?
+ "ulong" : "ULONG")));
+
+ /* build modes for TIME and DURATION */
+ duration_timing_type_node = make_unsigned_type (LONG_TYPE_SIZE);
+ temp = pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_DURATION],
+ duration_timing_type_node));
+ SET_CH_NOVELTY_NONNIL (duration_timing_type_node, temp);
+ abs_timing_type_node = make_unsigned_type (LONG_TYPE_SIZE);
+ temp = pushdecl (build_decl (TYPE_DECL, ridpointers[(int)RID_TIME],
+ abs_timing_type_node));
+ SET_CH_NOVELTY_NONNIL (abs_timing_type_node, temp);
+
+ /* the mode of time the runtimesystem returns */
+ if (rtstime_type_node == NULL_TREE)
+ {
+ tree decl1, decl2, result;
+
+ decl1 = build_decl (FIELD_DECL,
+ get_identifier ("secs"),
+ ulong_type);
+ DECL_INITIAL (decl1) = NULL_TREE;
+ decl2 = build_decl (FIELD_DECL,
+ get_identifier ("nsecs"),
+ ulong_type);
+ DECL_INITIAL (decl2) = NULL_TREE;
+ TREE_CHAIN (decl2) = NULL_TREE;
+ TREE_CHAIN (decl1) = decl2;
+
+ result = build_chill_struct_type (decl1);
+ pushdecl (temp = build_decl (TYPE_DECL,
+ get_identifier ("__tmp_rtstime"), result));
+ DECL_SOURCE_LINE (temp) = 0;
+ satisfy_decl (temp, 0);
+ rtstime_type_node = TREE_TYPE (temp);
+ }
+
+ endlink = void_list_node;
+
+ ptr_ftype_durt_ptr_int
+ = build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, duration_timing_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+
+ int_ftype_abst_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, abs_timing_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))));
+
+ void_ftype_ptr
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ endlink));
+
+ long_ftype_int_int_int_int_int_int_int_ptr_int
+ = build_function_type (abs_timing_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))))))));
+
+ void_ftype_abstime_ptr
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, abs_timing_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ endlink)));
+
+ int_ftype_ptr_durt_ptr
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, duration_timing_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ endlink))));
+
+ void_ftype_durt_ptr
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, duration_timing_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ endlink)));
+
+ void_ftype_ptr_durt_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, duration_timing_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))));
+
+ builtin_function ("_abstime", long_ftype_int_int_int_int_int_int_int_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__check_cycle", void_ftype_ptr_durt_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__convert_duration_rtstime", void_ftype_durt_ptr,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__define_timeout", ptr_ftype_durt_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("_inttime", void_ftype_abstime_ptr,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__remaintime", int_ftype_ptr_durt_ptr,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__rtstime", void_ftype_ptr,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__wait_until", int_ftype_abst_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+}
+
+#if 0
+ *
+ * build AT action
+ *
+ * AT primval IN
+ * ok-actionlist
+ * TIMEOUT
+ * to-actionlist
+ * END;
+ *
+ * gets translated to
+ *
+ * if (__wait_until (primval) == 0)
+ * ok-actionlist
+ * else
+ * to-action-list
+ *
+#endif
+
+void
+build_at_action (t)
+ tree t;
+{
+ tree abstime, expr, filename, fcall;
+
+ if (t == NULL_TREE || TREE_CODE (t) == ERROR_MARK)
+ abstime = convert (abs_timing_type_node, build_int_2 (0, 0));
+ else
+ abstime = t;
+
+ if (TREE_TYPE (abstime) != abs_timing_type_node)
+ {
+ error ("absolute time value must be of mode TIME.");
+ abstime = convert (abs_timing_type_node, build_int_2 (0, 0));
+ }
+ filename = force_addr_of (get_chill_filename ());
+ fcall = build_chill_function_call (
+ lookup_name (get_identifier ("__wait_until")),
+ tree_cons (NULL_TREE, abstime,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))));
+ expr = build (EQ_EXPR, integer_type_node, fcall, integer_zero_node);
+ expand_start_cond (expr, 0);
+ emit_line_note (input_filename, lineno);
+}
+
+#if 0
+ *
+ * build CYCLE action
+ *
+ * CYCLE primval IN
+ * actionlist
+ * END;
+ *
+ * gets translated to
+ *
+ * {
+ * RtsTime now;
+ * label:
+ * __rtstime (&now);
+ * actionlist
+ * __check_cycle (&now, primval, filename, lineno);
+ * goto label;
+ * }
+ *
+#endif
+
+tree
+build_cycle_start (t)
+ tree t;
+{
+ tree purpose = build_tree_list (NULL_TREE, NULL_TREE);
+ tree toid = build_tree_list (purpose, NULL_TREE);
+
+ /* define the label. Note: define_label needs to be called in
+ pass 1 and pass 2. */
+ TREE_VALUE (toid) = define_label (input_filename, lineno,
+ get_unique_identifier ("CYCLE_label"));
+ if (! ignoring)
+ {
+ tree duration_value, now_location;
+
+ if (t == NULL_TREE || TREE_CODE (t) == ERROR_MARK)
+ duration_value = convert (duration_timing_type_node, build_int_2 (0,0));
+ else
+ duration_value = t;
+
+ if (TREE_TYPE (duration_value) != duration_timing_type_node)
+ {
+ error ("duration primitive value must be of mode DURATION.");
+ duration_value = convert (duration_timing_type_node, build_int_2 (0,0));
+ }
+ TREE_PURPOSE (TREE_PURPOSE (toid)) = duration_value;
+ /* define the variable */
+ now_location = decl_temp1 (get_unique_identifier ("CYCLE_var"),
+ rtstime_type_node, 0,
+ NULL_TREE, 0, 0);
+ TREE_VALUE (TREE_PURPOSE (toid)) = force_addr_of (now_location);
+
+ /* build the call to __rtstime */
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (get_identifier ("__rtstime")),
+ build_tree_list (NULL_TREE, TREE_VALUE (TREE_PURPOSE (toid)))));
+ }
+
+ return toid;
+}
+
+void
+build_cycle_end (toid)
+ tree toid;
+{
+ tree filename, linenumber;
+
+ /* here we call __check_cycle and then jump to beginning of this
+ action */
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+ expand_expr_stmt (
+ build_chill_function_call (
+ lookup_name (get_identifier ("__check_cycle")),
+ tree_cons (NULL_TREE, TREE_VALUE (TREE_PURPOSE (toid)),
+ tree_cons (NULL_TREE, TREE_PURPOSE (TREE_PURPOSE (toid)),
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE))))));
+ expand_goto (TREE_VALUE (toid));
+}
+
+#if 0
+ *
+ * build AFTER ACTION
+ *
+ * AFTER primval [ DELAY ] IN
+ * action-list
+ * TIMEOUT
+ * to-action-list
+ * END
+ *
+ * gets translated to
+ *
+ * {
+ * struct chill_time __now;
+ * duration dur = primval;
+ * if (! delay_spceified)
+ * __rts_time (&__now);
+ * .
+ * .
+ * goto end-label;
+ * to-label:
+ * .
+ * .
+ * end-label:
+ * }
+ *
+#endif
+
+void
+build_after_start (duration, delay_flag)
+ tree duration;
+ int delay_flag;
+{
+ tree value, purpose;
+
+ if (! ignoring)
+ {
+ value = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
+ purpose = after_stack_pass_1;
+ after_stack_pass_1 = TREE_CHAIN (after_stack_pass_1);
+ after_stack = tree_cons (purpose, value, after_stack);
+
+ if (TREE_TYPE (duration) != duration_timing_type_node)
+ {
+ error ("duration primitive value must be of mode DURATION.");
+ duration = convert (duration_timing_type_node, build_int_2 (0,0));
+ }
+ TREE_PURPOSE (value) = decl_temp1 (get_identifier ("AFTER_duration"),
+ duration_timing_type_node, 0,
+ duration, 0, 0);
+
+ if (! delay_flag)
+ {
+ /* in this case we have to get the current time */
+ TREE_VALUE (value) = decl_temp1 (get_unique_identifier ("AFTER_now"),
+ rtstime_type_node, 0,
+ NULL_TREE, 0, 0);
+ /* build the function call to initialize the variable */
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (get_identifier ("__rtstime")),
+ build_tree_list (NULL_TREE, force_addr_of (TREE_VALUE (value)))));
+ }
+ }
+ else
+ {
+ /* in pass 1 we just save the labels */
+ after_help = tree_cons (NULL_TREE, NULL_TREE, after_help);
+ after_stack_pass_1 = chainon (after_stack_pass_1, after_help);
+ }
+}
+
+void
+build_after_timeout_start ()
+{
+ tree label_name, goto_where;
+
+ if (! ignoring)
+ {
+ /* jump to the end of AFTER action */
+ lookup_and_expand_goto (TREE_PURPOSE (TREE_PURPOSE (after_stack)));
+ label_name = TREE_VALUE (TREE_PURPOSE (after_stack));
+ /* mark we are in TIMEOUT part of AFTER action */
+ TREE_VALUE (TREE_PURPOSE (after_stack)) = NULL_TREE;
+ }
+ else
+ {
+ label_name = get_unique_identifier ("AFTER_tolabel");
+ TREE_VALUE (after_help) = label_name;
+ }
+ define_label (input_filename, lineno, label_name);
+}
+
+void
+build_after_end ()
+{
+ tree label_name;
+
+ /* define the end label */
+ if (! ignoring)
+ {
+ label_name = TREE_PURPOSE (TREE_PURPOSE (after_stack));
+ after_stack = TREE_CHAIN (after_stack);
+ }
+ else
+ {
+ label_name = get_unique_identifier ("AFTER_endlabel");
+ TREE_PURPOSE (after_help) = label_name;
+ after_help = TREE_CHAIN (after_help);
+ }
+ define_label (input_filename, lineno, label_name);
+}
+
+tree
+build_timeout_preface ()
+{
+ tree timeout_value = null_pointer_node;
+
+ if (after_stack != NULL_TREE &&
+ TREE_VALUE (TREE_PURPOSE (after_stack)) != NULL_TREE)
+ {
+ tree to_loc;
+
+ to_loc = decl_temp1 (get_unique_identifier ("TOloc"),
+ rtstime_type_node, 0, NULL_TREE, 0, 0);
+ timeout_value = force_addr_of (to_loc);
+
+ if (TREE_VALUE (TREE_VALUE (after_stack)) == NULL_TREE)
+ {
+ /* DELAY specified -- just call __convert_duration_rtstime for
+ given duration value */
+ expand_expr_stmt (
+ build_chill_function_call (
+ lookup_name (get_identifier ("__convert_duration_rtstime")),
+ tree_cons (NULL_TREE, TREE_PURPOSE (TREE_VALUE (after_stack)),
+ tree_cons (NULL_TREE, timeout_value, NULL_TREE))));
+ }
+ else
+ {
+ /* delay not specified -- call __remaintime which returns the
+ remaining time of duration in rtstime format and check the
+ result */
+ tree fcall =
+ build_chill_function_call (
+ lookup_name (get_identifier ("__remaintime")),
+ tree_cons (NULL_TREE, force_addr_of (TREE_VALUE (TREE_VALUE (after_stack))),
+ tree_cons (NULL_TREE, TREE_PURPOSE (TREE_VALUE (after_stack)),
+ tree_cons (NULL_TREE, timeout_value, NULL_TREE))));
+ tree expr = build (NE_EXPR, integer_type_node,
+ fcall, integer_zero_node);
+ expand_start_cond (expr, 0);
+ lookup_and_expand_goto (TREE_VALUE (TREE_PURPOSE (after_stack)));
+ expand_end_cond ();
+ }
+ }
+ return timeout_value;
+}
+
+void
+build_timesupervised_call (fcall, to_loc)
+ tree fcall;
+ tree to_loc;
+{
+ if (to_loc == null_pointer_node)
+ expand_expr_stmt (fcall);
+ else
+ {
+ tree expr = build (NE_EXPR, integer_type_node, fcall, integer_zero_node);
+ expand_start_cond (expr, 0);
+ lookup_and_expand_goto (TREE_VALUE (TREE_PURPOSE (after_stack)));
+ expand_end_cond ();
+ }
+}
diff --git a/gcc/ch/typeck.c b/gcc/ch/typeck.c
new file mode 100644
index 0000000..5f97494
--- /dev/null
+++ b/gcc/ch/typeck.c
@@ -0,0 +1,3905 @@
+/* Build expressions with type checking for CHILL compiler.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of the CHILL front end.
+ It contains routines to build C expressions given their operands,
+ including computing the modes of the result, C-specific error checks,
+ and some optimization.
+
+ There are also routines to build RETURN_STMT nodes and CASE_STMT nodes,
+ and to process initializations in declarations (since they work
+ like a strange sort of assignment). */
+
+#include "config.h"
+#include <stdio.h>
+#include "tree.h"
+#include "ch-tree.h"
+#include "flags.h"
+#include "rtl.h"
+#include "expr.h"
+#include "lex.h"
+
+extern tree build_chill_compound_expr PROTO((tree));
+extern tree build_component_ref PROTO((tree, tree));
+extern void c_expand_return PROTO((tree));
+extern int ch_singleton_set PROTO((tree));
+extern void error PROTO((char *, ...));
+extern void error_with_decl PROTO((tree, char *, ...));
+extern int mark_addressable PROTO((tree));
+extern void pedwarn PROTO((char *, ...));
+extern void pedwarn_with_decl PROTO((tree, char *, ...));
+extern tree require_complete_type PROTO((tree));
+extern void sorry PROTO((char *, ...));
+extern void warning PROTO((char *, ...));
+extern int get_type_precision PROTO((tree, tree));
+
+extern tree intQI_type_node;
+extern tree intHI_type_node;
+extern tree intSI_type_node;
+extern tree intDI_type_node;
+extern tree intTI_type_node;
+
+extern tree unsigned_intQI_type_node;
+extern tree unsigned_intHI_type_node;
+extern tree unsigned_intSI_type_node;
+extern tree unsigned_intDI_type_node;
+extern tree unsigned_intTI_type_node;
+
+/* forward declarations */
+tree chill_expand_tuple PROTO((tree, tree));
+static int chill_l_equivalent PROTO((tree, tree, struct mode_chain*));
+extern tree extract_constant_from_buffer();
+
+/*
+ * This function checks an array access.
+ * It calls error (ERROR_MESSAGE) if the condition (index <= domain max value
+ * index >= domain min value)
+ * is not met at compile time,
+ * If a runtime test is required and permitted,
+ * check_expression is used to do so.
+ * the global RANGE_CHECKING flags controls the
+ * generation of runtime checking code.
+ */
+tree
+valid_array_index_p (array, idx, error_message, is_varying_lhs)
+ tree array, idx;
+ char *error_message;
+ int is_varying_lhs;
+{
+ tree cond, low_limit, high_cond, atype, domain;
+ tree orig_index = idx;
+ enum chill_tree_code condition;
+
+ if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK
+ || idx == NULL_TREE || TREE_CODE (idx) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (idx) == TYPE_DECL
+ || TREE_CODE_CLASS (TREE_CODE (idx)) == 't')
+ {
+ error ("array or string index is a mode (instead of a value)");
+ return error_mark_node;
+ }
+
+ atype = TREE_TYPE (array);
+
+ if (chill_varying_type_p (atype))
+ {
+ domain = TYPE_DOMAIN (CH_VARYING_ARRAY_TYPE (atype));
+ high_cond = build_component_ref (array, var_length_id);
+ if (chill_varying_string_type_p (atype))
+ {
+ if (is_varying_lhs)
+ condition = GT_EXPR;
+ else
+ condition = GE_EXPR;
+ }
+ else
+ condition = GT_EXPR;
+ }
+ else
+ {
+ domain = TYPE_DOMAIN (atype);
+ high_cond = TYPE_MAX_VALUE (domain);
+ condition = GT_EXPR;
+ }
+
+ if (CH_STRING_TYPE_P (atype))
+ {
+ if (! CH_SIMILAR (TREE_TYPE (orig_index), integer_type_node))
+ {
+ error ("index is not an integer expression");
+ return error_mark_node;
+ }
+ }
+ else
+ {
+ if (! CH_COMPATIBLE (orig_index, domain))
+ {
+ error ("index not compatible with index mode");
+ return error_mark_node;
+ }
+ }
+
+ /* Convert BOOLS(1) to BOOL and CHARS(1) to CHAR. */
+ if (flag_old_strings)
+ {
+ idx = convert_to_discrete (idx);
+ if (idx == NULL) /* should never happen */
+ error ("index is not discrete");
+ }
+
+ /* we know we'll refer to this value twice */
+ if (range_checking)
+ idx = save_expr (idx);
+
+ low_limit = TYPE_MIN_VALUE (domain);
+ high_cond = build_compare_discrete_expr (condition, idx, high_cond);
+
+ /* an invalid index expression meets this condition */
+ cond = fold (build (TRUTH_ORIF_EXPR, boolean_type_node,
+ build_compare_discrete_expr (LT_EXPR, idx, low_limit),
+ high_cond));
+
+ /* strip a redundant NOP_EXPR */
+ if (TREE_CODE (cond) == NOP_EXPR
+ && TREE_TYPE (cond) == boolean_type_node
+ && TREE_CODE (TREE_OPERAND (cond, 0)) == INTEGER_CST)
+ cond = TREE_OPERAND (cond, 0);
+
+ idx = convert (CH_STRING_TYPE_P (atype) ? integer_type_node : domain,
+ idx);
+
+ if (TREE_CODE (cond) == INTEGER_CST)
+ {
+ if (tree_int_cst_equal (cond, boolean_false_node))
+ return idx; /* condition met at compile time */
+ error (error_message); /* condition failed at compile time */
+ return error_mark_node;
+ }
+ else if (range_checking)
+ {
+ /* FIXME: often, several of these conditions will
+ be generated for the same source file and line number.
+ A great optimization would be to share the
+ cause_exception function call among them rather
+ than generating a cause_exception call for each. */
+ return check_expression (idx, cond,
+ ridpointers[(int) RID_RANGEFAIL]);
+ }
+ else
+ return idx; /* don't know at compile time */
+}
+
+/*
+ * Extract a slice from an array, which could look like a
+ * SET_TYPE if it's a bitstring. The array could also be VARYING
+ * if the element type is CHAR. The min_value and length values
+ * must have already been checked with valid_array_index_p. No
+ * checking is done here.
+ */
+tree
+build_chill_slice (array, min_value, length)
+ tree array, min_value, length;
+{
+ tree result;
+ tree array_type = TREE_TYPE (array);
+
+ if (!CH_REFERABLE (array) && TREE_CODE (array) != SAVE_EXPR
+ && (TREE_CODE (array) != COMPONENT_REF
+ || TREE_CODE (TREE_OPERAND (array, 0)) != SAVE_EXPR))
+ {
+ if (!TREE_CONSTANT (array))
+ warning ("possible internal error - slice argument is neither referable nor constant");
+ else
+ {
+ /* Force to storage.
+ NOTE: This could mean multiple identical copies of
+ the same constant. FIXME. */
+ tree mydecl = decl_temp1 (get_unique_identifier("SLICEE"),
+ array_type, 1, array, 0, 0);
+ TREE_READONLY (mydecl) = 1;
+ /* mark_addressable (mydecl); FIXME: necessary? */
+ array = mydecl;
+ }
+ }
+
+ /*
+ The code-generation which uses a slice tree needs not only to
+ know the dynamic upper and lower limits of that slice, but the
+ original static allocation, to use to build temps where one or both
+ of the dynamic limits must be calculated at runtime.. We pass the
+ dynamic size by building a new array_type whose limits are the
+ min_value and min_value + length values passed to us.
+
+ The static allocation info is passed by using the parent array's
+ limits to compute a temp_size, which is passed in the lang_specific
+ field of the slice_type.
+ */
+
+ if (TREE_CODE (array_type) == ARRAY_TYPE)
+ {
+ tree domain_type = TYPE_DOMAIN (array_type);
+ tree index_domain
+ = TREE_CODE (length) != INTEGER_CST || integer_zerop (length)
+ ? sizetype
+ : domain_type;
+ tree domain_min = convert (index_domain, TYPE_MIN_VALUE (domain_type));
+ tree domain_max = fold (build (PLUS_EXPR, index_domain,
+ domain_min,
+ convert (index_domain,
+ size_binop (MINUS_EXPR,
+ length,
+ integer_one_node))));
+ tree index_type = build_chill_range_type (domain_type,
+ domain_min,
+ domain_max);
+
+ tree element_type = TREE_TYPE (array_type);
+ tree slice_type = build_simple_array_type (element_type, index_type, NULL_TREE);
+ tree slice_pointer_type;
+ int is_static;
+ tree max_size;
+
+ if (CH_CHARS_TYPE_P (array_type))
+ MARK_AS_STRING_TYPE (slice_type);
+ else
+ TYPE_PACKED (slice_type) = TYPE_PACKED (array_type);
+
+ SET_CH_NOVELTY (slice_type, CH_NOVELTY (array_type));
+
+ if (TREE_CONSTANT (array) && TREE_CODE (min_value) == INTEGER_CST
+ && TREE_CODE (length) == INTEGER_CST)
+ {
+ int type_size = int_size_in_bytes (array_type);
+ unsigned char *buffer = (unsigned char*) alloca (type_size);
+ int delta = int_size_in_bytes (element_type)
+ * (TREE_INT_CST_LOW (min_value) - TREE_INT_CST_LOW (domain_min));
+ bzero (buffer, type_size);
+ if (expand_constant_to_buffer (array, buffer, type_size))
+ {
+ result = extract_constant_from_buffer (slice_type,
+ buffer + delta,
+ type_size - delta);
+ if (result)
+ return result;
+ }
+ }
+
+ /* Kludge used by case CONCAT_EXPR in chill_expand_expr.
+ Set TYPE_ARRAY_MAX_SIZE to a constant upper bound on the
+ bytes needed. */
+ max_size = size_in_bytes (slice_type);
+ if (TREE_CODE (max_size) != INTEGER_CST)
+ {
+ max_size = TYPE_ARRAY_MAX_SIZE (array_type);
+ if (max_size == NULL_TREE)
+ max_size = size_in_bytes (array_type);
+ }
+ TYPE_ARRAY_MAX_SIZE (slice_type) = max_size;
+
+ mark_addressable (array);
+ /* Contruct a SLICE_EXPR to represent a slice of a packed array of bits. */
+ if (TYPE_PACKED (array_type))
+ {
+ if (pass == 2 && TREE_CODE (length) != INTEGER_CST)
+ {
+ sorry ("bit array slice with non-constant length");
+ return error_mark_node;
+ }
+ if (domain_min && ! integer_zerop (domain_min))
+ min_value = size_binop (MINUS_EXPR, min_value,
+ convert (sizetype, domain_min));
+ result = build (SLICE_EXPR, slice_type, array, min_value, length);
+ TREE_READONLY (result)
+ = TREE_READONLY (array) | TYPE_READONLY (TREE_TYPE (array_type));
+ return result;
+ }
+
+ slice_pointer_type = build_chill_pointer_type (slice_type);
+ if (TREE_CODE (min_value) == INTEGER_CST
+ && domain_min && TREE_CODE (domain_min) == INTEGER_CST
+ && compare_int_csts (EQ_EXPR, min_value, domain_min))
+ result = fold (build1 (ADDR_EXPR, slice_pointer_type, array));
+ else
+ {
+ min_value = convert (sizetype, min_value);
+ if (domain_min && ! integer_zerop (domain_min))
+ min_value = size_binop (MINUS_EXPR, min_value,
+ convert (sizetype, domain_min));
+ min_value = size_binop (MULT_EXPR, min_value,
+ size_in_bytes (element_type));
+ result = fold (build (PLUS_EXPR, slice_pointer_type,
+ build1 (ADDR_EXPR, slice_pointer_type,
+ array),
+ convert (slice_pointer_type, min_value)));
+ }
+ /* Return the final array value. */
+ result = fold (build1 (INDIRECT_REF, slice_type, result));
+ TREE_READONLY (result)
+ = TREE_READONLY (array) | TYPE_READONLY (element_type);
+ return result;
+ }
+ else if (TREE_CODE (array_type) == SET_TYPE) /* actually a bitstring */
+ {
+ if (pass == 2 && TREE_CODE (length) != INTEGER_CST)
+ {
+ sorry ("bitstring slice with non-constant length");
+ return error_mark_node;
+ }
+ result = build (SLICE_EXPR, build_bitstring_type (length),
+ array, min_value, length);
+ TREE_READONLY (result)
+ = TREE_READONLY (array) | TYPE_READONLY (TREE_TYPE (array_type));
+ return result;
+ }
+ else if (chill_varying_type_p (array_type))
+ return build_chill_slice (varying_to_slice (array), min_value, length);
+ else
+ {
+ error ("slice operation on non-array, non-bitstring value not supported");
+ return error_mark_node;
+ }
+}
+
+static tree
+build_empty_string (type)
+ tree type;
+{
+ int orig_pass = pass;
+ tree range, result;
+
+ range = build_chill_range_type (type, integer_zero_node,
+ integer_minus_one_node);
+ result = build_chill_array_type (type,
+ tree_cons (NULL_TREE, range, NULL_TREE), 0, NULL_TREE);
+ pass = 2;
+ range = build_chill_range_type (type, integer_zero_node,
+ integer_minus_one_node);
+ result = build_chill_array_type (type,
+ tree_cons (NULL_TREE, range, NULL_TREE), 0, NULL_TREE);
+ pass = orig_pass;
+
+ return decl_temp1 (get_unique_identifier ("EMPTY_STRING"),
+ result, 0, NULL_TREE, 0, 0);
+}
+
+/* We build the runtime range-checking as a separate list
+ * rather than making a compound_expr with min_value
+ * (for example), to control when that comparison gets
+ * generated. We cannot allow it in a TYPE_MAX_VALUE or
+ * TYPE_MIN_VALUE expression, for instance, because that code
+ * will get generated when the slice is laid out, which would
+ * put it outside the scope of an exception handler for the
+ * statement we're generating. I.e. we would be generating
+ * cause_exception calls which might execute before the
+ * necessary ch_link_handler call.
+ */
+tree
+build_chill_slice_with_range (array, min_value, max_value)
+ tree array, min_value, max_value;
+{
+ if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK
+ || min_value == NULL_TREE || TREE_CODE(min_value) == ERROR_MARK
+ || max_value == NULL_TREE || TREE_CODE(max_value) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_TYPE (array) == NULL_TREE
+ || (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (array)) != SET_TYPE
+ && !chill_varying_type_p (TREE_TYPE (array))))
+ {
+ error ("can only take slice of array or string");
+ return error_mark_node;
+ }
+
+ array = save_if_needed (array);
+
+ /* FIXME: test here for max_value >= min_value, except
+ for max_value == -1, min_value == 0 (empty string) */
+ min_value = valid_array_index_p (array, min_value,
+ "slice lower limit out-of-range", 0);
+ if (TREE_CODE (min_value) == ERROR_MARK)
+ return min_value;
+
+ /* FIXME: suppress this test if max_value is the LENGTH of a
+ varying array, which has presumably already been checked. */
+ max_value = valid_array_index_p (array, max_value,
+ "slice upper limit out-of-range", 0);
+ if (TREE_CODE (max_value) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (min_value) == INTEGER_CST
+ && TREE_CODE (max_value) == INTEGER_CST
+ && tree_int_cst_lt (max_value, min_value))
+ return build_empty_string (TREE_TYPE (TREE_TYPE (array)));
+
+ return build_chill_slice (array, min_value,
+ save_expr (size_binop (PLUS_EXPR,
+ size_binop (MINUS_EXPR, max_value, min_value),
+ integer_one_node)));
+}
+
+
+tree
+build_chill_slice_with_length (array, min_value, length)
+ tree array, min_value, length;
+{
+ tree max_index;
+ tree cond, high_cond, atype;
+
+ if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK
+ || min_value == NULL_TREE || TREE_CODE(min_value) == ERROR_MARK
+ || length == NULL_TREE || TREE_CODE(length) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_TYPE (array) == NULL_TREE
+ || (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (array)) != SET_TYPE
+ && !chill_varying_type_p (TREE_TYPE (array))))
+ {
+ error ("can only take slice of array or string");
+ return error_mark_node;
+ }
+
+ if (TREE_CONSTANT (length)
+ && tree_int_cst_lt (length, integer_zero_node))
+ return build_empty_string (TREE_TYPE (TREE_TYPE (array)));
+
+ array = save_if_needed (array);
+ min_value = save_expr (min_value);
+ length = save_expr (length);
+
+ if (! CH_SIMILAR (TREE_TYPE (length), integer_type_node))
+ {
+ error ("slice length is not an integer");
+ length = integer_one_node;
+ }
+
+ max_index = size_binop (MINUS_EXPR,
+ size_binop (PLUS_EXPR, length, min_value),
+ integer_one_node);
+ max_index = convert_to_class (chill_expr_class (min_value), max_index);
+
+ min_value = valid_array_index_p (array, min_value,
+ "slice start index out-of-range", 0);
+ if (TREE_CODE (min_value) == ERROR_MARK)
+ return error_mark_node;
+
+ atype = TREE_TYPE (array);
+
+ if (chill_varying_type_p (atype))
+ high_cond = build_component_ref (array, var_length_id);
+ else
+ high_cond = TYPE_MAX_VALUE (TYPE_DOMAIN (atype));
+
+ /* an invalid index expression meets this condition */
+ cond = fold (build (TRUTH_ORIF_EXPR, boolean_type_node,
+ build_compare_discrete_expr (LT_EXPR,
+ length, integer_zero_node),
+ build_compare_discrete_expr (GT_EXPR,
+ max_index, high_cond)));
+
+ if (TREE_CODE (cond) == INTEGER_CST)
+ {
+ if (! tree_int_cst_equal (cond, boolean_false_node))
+ {
+ error ("slice length out-of-range");
+ return error_mark_node;
+ }
+
+ }
+ else if (range_checking)
+ {
+ min_value = check_expression (min_value, cond,
+ ridpointers[(int) RID_RANGEFAIL]);
+ }
+
+ return build_chill_slice (array, min_value, length);
+}
+
+tree
+build_chill_array_ref (array, indexlist)
+ tree array, indexlist;
+{
+ tree idx;
+
+ if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK)
+ return error_mark_node;
+ if (indexlist == NULL_TREE || TREE_CODE (indexlist) == ERROR_MARK)
+ return error_mark_node;
+
+ idx = TREE_VALUE (indexlist); /* handle first index */
+
+ idx = valid_array_index_p (array, idx,
+ "array index out-of-range", 0);
+ if (TREE_CODE (idx) == ERROR_MARK)
+ return error_mark_node;
+
+ array = build_chill_array_ref_1 (array, idx);
+
+ if (array && TREE_CODE (array) != ERROR_MARK
+ && TREE_CHAIN (indexlist))
+ {
+ /* Z.200 (1988) section 4.2.8 says that:
+ <array> '(' <expression {',' <expression> }* ')'
+ is derived syntax (i.e. syntactic sugar) for:
+ <array> '(' <expression ')' { '(' <expression> ')' }*
+ The intent is clear if <array> has mode: ARRAY (...) ARRAY (...) XXX.
+ But what if <array> has mode: ARRAY (...) CHARS (N)
+ or: ARRAY (...) BOOLS (N).
+ Z.200 doesn't explicitly prohibit it, but the intent is unclear.
+ We'll allow it, since it seems reasonable and useful.
+ However, we won't allow it if <array> is:
+ ARRAY (...) PROC (...).
+ (The latter would make sense if we allowed general
+ Currying, which Chill doesn't.) */
+ if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
+ || chill_varying_type_p (TREE_TYPE (array))
+ || CH_BOOLS_TYPE_P (TREE_TYPE (array)))
+ array = build_generalized_call (array, TREE_CHAIN (indexlist));
+ else
+ error ("too many index expressions");
+ }
+ return array;
+}
+
+/*
+ * Don't error check the index in here. It's supposed to be
+ * checked by the caller.
+ */
+tree
+build_chill_array_ref_1 (array, idx)
+ tree array, idx;
+{
+ tree type;
+ tree domain;
+ tree rval;
+
+ if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK
+ || idx == NULL_TREE || TREE_CODE (idx) == ERROR_MARK)
+ return error_mark_node;
+
+ if (chill_varying_type_p (TREE_TYPE (array)))
+ array = varying_to_slice (array);
+
+ domain = TYPE_DOMAIN (TREE_TYPE (array));
+
+#if 0
+ if (! integer_zerop (TYPE_MIN_VALUE (domain)))
+ {
+ /* The C part of the compiler doesn't understand how to do
+ arithmetic with dissimilar enum types. So we check compatability
+ here, and perform the math in INTEGER_TYPE. */
+ if (TREE_CODE (TREE_TYPE (idx)) == ENUMERAL_TYPE
+ && chill_comptypes (TREE_TYPE (idx), domain, 0))
+ idx = convert (TREE_TYPE (TYPE_MIN_VALUE (domain)), idx);
+ idx = build_binary_op (MINUS_EXPR, idx, TYPE_MIN_VALUE (domain), 0);
+ }
+#endif
+
+ if (CH_STRING_TYPE_P (TREE_TYPE (array)))
+ {
+ /* Could be bitstring or char string. */
+ if (TREE_TYPE (TREE_TYPE (array)) == boolean_type_node)
+ {
+ rval = build (SET_IN_EXPR, boolean_type_node, idx, array);
+ TREE_READONLY (rval) = TREE_READONLY (array);
+ return rval;
+ }
+ }
+
+ if (!discrete_type_p (TREE_TYPE (idx)))
+ {
+ error ("array index is not discrete");
+ return error_mark_node;
+ }
+
+ /* An array that is indexed by a non-constant
+ cannot be stored in a register; we must be able to do
+ address arithmetic on its address.
+ Likewise an array of elements of variable size. */
+ if (TREE_CODE (idx) != INTEGER_CST
+ || (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST))
+ {
+ if (mark_addressable (array) == 0)
+ return error_mark_node;
+ }
+
+ type = TREE_TYPE (TREE_TYPE (array));
+
+ /* Do constant folding */
+ if (TREE_CODE (idx) == INTEGER_CST && TREE_CONSTANT (array))
+ {
+ struct ch_class class;
+ class.kind = CH_VALUE_CLASS;
+ class.mode = type;
+
+ if (TREE_CODE (array) == CONSTRUCTOR)
+ {
+ tree list = CONSTRUCTOR_ELTS (array);
+ for ( ; list != NULL_TREE; list = TREE_CHAIN (list))
+ {
+ if (tree_int_cst_equal (TREE_PURPOSE (list), idx))
+ return convert_to_class (class, TREE_VALUE (list));
+ }
+ }
+ else if (TREE_CODE (array) == STRING_CST
+ && CH_CHARS_TYPE_P (TREE_TYPE (array)))
+ {
+ HOST_WIDE_INT i = TREE_INT_CST_LOW (idx);
+ if (i >= 0 && i < TREE_STRING_LENGTH (array))
+ {
+ char ch = TREE_STRING_POINTER (array) [i];
+ return convert_to_class (class,
+ build_int_2 ((unsigned char)ch, 0));
+ }
+ }
+ }
+
+ if (TYPE_PACKED (TREE_TYPE (array)))
+ rval = build (PACKED_ARRAY_REF, type, array, idx);
+ else
+ rval = build (ARRAY_REF, type, array, idx);
+
+ /* Array ref is const/volatile if the array elements are
+ or if the array is. */
+ TREE_READONLY (rval) = TREE_READONLY (array) | TYPE_READONLY (type);
+ TREE_SIDE_EFFECTS (rval)
+ |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))
+ | TREE_SIDE_EFFECTS (array));
+ TREE_THIS_VOLATILE (rval)
+ |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))
+ /* This was added by rms on 16 Nov 91.
+ It fixes vol struct foo *a; a->elts[1]
+ in an inline function.
+ Hope it doesn't break something else. */
+ | TREE_THIS_VOLATILE (array));
+ return fold (rval);
+}
+
+tree
+build_chill_bitref (bitstring, indexlist)
+ tree bitstring, indexlist;
+{
+ if (TREE_CODE (bitstring) == ERROR_MARK)
+ return bitstring;
+ if (TREE_CODE (indexlist) == ERROR_MARK)
+ return indexlist;
+
+ if (TREE_CHAIN (indexlist) != NULL_TREE)
+ {
+ error ("invalid compound index for bitstring mode");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (indexlist) == TREE_LIST)
+ {
+ tree result = build (SET_IN_EXPR, boolean_type_node,
+ TREE_VALUE (indexlist), bitstring);
+ TREE_READONLY (result) = TREE_READONLY (bitstring);
+ return result;
+ }
+ else abort ();
+}
+
+
+int
+discrete_type_p (type)
+ tree type;
+{
+ return INTEGRAL_TYPE_P (type);
+}
+
+/* Checks that EXP has discrete type, or can be converted to discrete.
+ Otherwise, returns NULL_TREE.
+ Normally returns the (possibly-converted) EXP. */
+
+tree
+convert_to_discrete (exp)
+ tree exp;
+{
+ if (! discrete_type_p (TREE_TYPE (exp)))
+ {
+ if (flag_old_strings)
+ {
+ if (CH_CHARS_ONE_P (TREE_TYPE (exp)))
+ return convert (char_type_node, exp);
+ if (CH_BOOLS_ONE_P (TREE_TYPE (exp)))
+ return convert (boolean_type_node, exp);
+ }
+ return NULL_TREE;
+ }
+ return exp;
+}
+
+/* Write into BUFFER the target-machine representation of VALUE.
+ Returns 1 on success, or 0 on failure. (Either the VALUE was
+ not constant, or we don't know how to do the conversion.) */
+
+int
+expand_constant_to_buffer (value, buffer, buf_size)
+ tree value;
+ unsigned char *buffer;
+ int buf_size;
+{
+ tree type = TREE_TYPE (value);
+ int size = int_size_in_bytes (type);
+ int i;
+ if (size < 0 || size > buf_size)
+ return 0;
+ switch (TREE_CODE (value))
+ {
+ case INTEGER_CST:
+ {
+ HOST_WIDE_INT lo = TREE_INT_CST_LOW (value);
+ HOST_WIDE_INT hi = TREE_INT_CST_HIGH (value);
+ for (i = 0; i < size; i++)
+ {
+ /* Doesn't work if host and target BITS_PER_UNIT differ. */
+ unsigned char byte = lo & ((1 << BITS_PER_UNIT) - 1);
+ if (BYTES_BIG_ENDIAN)
+ buffer[size - i - 1] = byte;
+ else
+ buffer[i] = byte;
+ rshift_double (lo, hi, BITS_PER_UNIT, BITS_PER_UNIT * size,
+ &lo, &hi, 0);
+ }
+ }
+ break;
+ case STRING_CST:
+ {
+ size = TREE_STRING_LENGTH (value);
+ if (size > buf_size)
+ return 0;
+ bcopy (TREE_STRING_POINTER (value), buffer, size);
+ break;
+ }
+ case CONSTRUCTOR:
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree element_type = TREE_TYPE (type);
+ int element_size = int_size_in_bytes (element_type);
+ tree list = CONSTRUCTOR_ELTS (value);
+ HOST_WIDE_INT next_index;
+ HOST_WIDE_INT min_index = 0;
+ if (element_size < 0)
+ return 0;
+
+ if (TYPE_DOMAIN (type) != 0)
+ {
+ tree min_val = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
+ if (min_val)
+ if (TREE_CODE (min_val) != INTEGER_CST)
+ return 0;
+ else
+ min_index = TREE_INT_CST_LOW (min_val);
+ }
+
+ next_index = min_index;
+
+ for (; list != NULL_TREE; list = TREE_CHAIN (list))
+ {
+ HOST_WIDE_INT offset;
+ HOST_WIDE_INT last_index;
+ tree purpose = TREE_PURPOSE (list);
+ if (purpose)
+ {
+ if (TREE_CODE (purpose) == INTEGER_CST)
+ last_index = next_index = TREE_INT_CST_LOW (purpose);
+ else if (TREE_CODE (purpose) == RANGE_EXPR)
+ {
+ next_index = TREE_INT_CST_LOW (TREE_OPERAND(purpose, 0));
+ last_index = TREE_INT_CST_LOW (TREE_OPERAND(purpose, 1));
+ }
+ else
+ return 0;
+ }
+ else
+ last_index = next_index;
+ for ( ; next_index <= last_index; next_index++)
+ {
+ offset = (next_index - min_index) * element_size;
+ if (!expand_constant_to_buffer (TREE_VALUE (list),
+ buffer + offset,
+ buf_size - offset))
+ return 0;
+ }
+ }
+ break;
+ }
+ else if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ tree list = CONSTRUCTOR_ELTS (value);
+ for (; list != NULL_TREE; list = TREE_CHAIN (list))
+ {
+ tree field = TREE_PURPOSE (list);
+ HOST_WIDE_INT offset;
+ if (field == NULL_TREE || TREE_CODE (field) != FIELD_DECL)
+ return 0;
+ if (DECL_BIT_FIELD (field))
+ return 0;
+ offset = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
+ / BITS_PER_UNIT;
+ if (!expand_constant_to_buffer (TREE_VALUE (list),
+ buffer + offset,
+ buf_size - offset))
+ return 0;
+ }
+ break;
+ }
+ else if (TREE_CODE (type) == SET_TYPE)
+ {
+ if (get_set_constructor_bytes (value, buffer, buf_size)
+ != NULL_TREE)
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/* Given that BUFFER contains a target-machine representation of
+ a value of type TYPE, return that value as a tree.
+ Returns NULL_TREE on failure. (E.g. the TYPE might be variable size,
+ or perhaps we don't know how to do the conversion.) */
+
+tree
+extract_constant_from_buffer (type, buffer, buf_size)
+ tree type;
+ unsigned char *buffer;
+ int buf_size;
+{
+ tree value;
+ int size = int_size_in_bytes (type);
+ int i;
+ if (size < 0 || size > buf_size)
+ return 0;
+ switch (TREE_CODE (type))
+ {
+ case INTEGER_TYPE:
+ case CHAR_TYPE:
+ case BOOLEAN_TYPE:
+ case ENUMERAL_TYPE:
+ case POINTER_TYPE:
+ {
+ HOST_WIDE_INT lo = 0, hi = 0;
+ /* Accumulate (into (lo,hi) the bytes (from buffer). */
+ for (i = size; --i >= 0; )
+ {
+ unsigned char byte;
+ /* Get next byte (in big-endian order). */
+ if (BYTES_BIG_ENDIAN)
+ byte = buffer[size - i - 1];
+ else
+ byte = buffer[i];
+ lshift_double (lo, hi, BITS_PER_UNIT, TYPE_PRECISION (type),
+ &lo, &hi, 0);
+ add_double (lo, hi, byte, 0, &lo, &hi);
+ }
+ value = build_int_2 (lo, hi);
+ TREE_TYPE (value) = type;
+ return value;
+ }
+ case ARRAY_TYPE:
+ {
+ tree element_type = TREE_TYPE (type);
+ int element_size = int_size_in_bytes (element_type);
+ tree list = NULL_TREE;
+ HOST_WIDE_INT min_index = 0, max_index, cur_index;
+ if (element_size == 1 && CH_CHARS_TYPE_P (type))
+ {
+ value = build_string (size, buffer);
+ CH_DERIVED_FLAG (value) = 1;
+ TREE_TYPE (value) = type;
+ return value;
+ }
+ if (TYPE_DOMAIN (type) == 0)
+ return 0;
+ value = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
+ if (value)
+ if (TREE_CODE (value) != INTEGER_CST)
+ return 0;
+ else
+ min_index = TREE_INT_CST_LOW (value);
+ value = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+ if (value == NULL_TREE || TREE_CODE (value) != INTEGER_CST)
+ return 0;
+ else
+ max_index = TREE_INT_CST_LOW (value);
+ for (cur_index = max_index; cur_index >= min_index; cur_index--)
+ {
+ HOST_WIDE_INT offset = (cur_index - min_index) * element_size;
+ value = extract_constant_from_buffer (element_type,
+ buffer + offset,
+ buf_size - offset);
+ if (value == NULL_TREE)
+ return NULL_TREE;
+ list = tree_cons (build_int_2 (cur_index, 0), value, list);
+ }
+ value = build (CONSTRUCTOR, type, NULL_TREE, list);
+ TREE_CONSTANT (value) = 1;
+ TREE_STATIC (value) = 1;
+ return value;
+ }
+ case RECORD_TYPE:
+ {
+ tree list = NULL_TREE;
+ tree field = TYPE_FIELDS (type);
+ for (; field != NULL_TREE; field = TREE_CHAIN (field))
+ {
+ HOST_WIDE_INT offset
+ = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)) / BITS_PER_UNIT;
+ if (DECL_BIT_FIELD (field))
+ return 0;
+ value = extract_constant_from_buffer (TREE_TYPE (field),
+ buffer + offset,
+ buf_size - offset);
+ if (value == NULL_TREE)
+ return NULL_TREE;
+ list = tree_cons (field, value, list);
+ }
+ value = build (CONSTRUCTOR, type, NULL_TREE, nreverse (list));
+ TREE_CONSTANT (value) = 1;
+ TREE_STATIC (value) = 1;
+ return value;
+ }
+
+ case UNION_TYPE:
+ {
+ tree longest_variant = NULL_TREE;
+ int longest_size = 0;
+ tree field = TYPE_FIELDS (type);
+
+ /* This is a kludge. We assume that converting the data to te
+ longest variant will provide valid data for the "correct"
+ variant. This is usually the case, but is not guaranteed.
+ For example, the longest variant may include holes.
+ Also incorrect interpreting the given value as the longest
+ variant may confuse the compiler if that should happen
+ to yield invalid values. ??? */
+
+ for (; field != NULL_TREE; field = TREE_CHAIN (field))
+ {
+ int size = TREE_INT_CST_LOW (size_in_bytes (TREE_TYPE (field)));
+
+ if (size > longest_size)
+ {
+ longest_size = size;
+ longest_variant = field;
+ }
+ }
+ if (longest_variant == NULL_TREE)
+ return NULL_TREE;
+ return extract_constant_from_buffer (TREE_TYPE (longest_variant), buffer, buf_size);
+ }
+
+ case SET_TYPE:
+ {
+ tree list = NULL_TREE;
+ int i;
+ HOST_WIDE_INT min_index, max_index;
+ if (TYPE_DOMAIN (type) == 0)
+ return 0;
+ value = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
+ if (value == NULL_TREE)
+ min_index = 0;
+ else if (TREE_CODE (value) != INTEGER_CST)
+ return 0;
+ else
+ min_index = TREE_INT_CST_LOW (value);
+ value = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+ if (value == NULL_TREE)
+ max_index = 0;
+ else if (TREE_CODE (value) != INTEGER_CST)
+ return 0;
+ else
+ max_index = TREE_INT_CST_LOW (value);
+ for (i = max_index + 1 - min_index; --i >= 0; )
+ {
+ unsigned char byte = (unsigned char)buffer[i / BITS_PER_UNIT];
+ unsigned bit_pos = (unsigned)i % (unsigned)BITS_PER_UNIT;
+ if (BYTES_BIG_ENDIAN
+ ? (byte & (1 << (BITS_PER_UNIT - 1 - bit_pos)))
+ : (byte & (1 << bit_pos)))
+ list = tree_cons (NULL_TREE,
+ build_int_2 (i + min_index, 0), list);
+ }
+ value = build (CONSTRUCTOR, type, NULL_TREE, list);
+ TREE_CONSTANT (value) = 1;
+ TREE_STATIC (value) = 1;
+ return value;
+ }
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+tree
+build_chill_cast (type, expr)
+ tree type, expr;
+{
+ tree expr_type;
+ int expr_type_size;
+ int type_size;
+ int type_is_discrete;
+ int expr_type_is_discrete;
+
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+
+ /* if expression was untyped because of its context (an
+ if_expr or case_expr in a tuple, perhaps) just apply
+ the type */
+ expr_type = TREE_TYPE (expr);
+ if (expr_type == NULL_TREE
+ || TREE_CODE (expr_type) == ERROR_MARK)
+ return convert (type, expr);
+
+ if (expr_type == type)
+ return expr;
+
+ expr_type_size = int_size_in_bytes (expr_type);
+ type_size = int_size_in_bytes (type);
+
+ if (expr_type_size == -1)
+ {
+ error ("conversions from variable_size value");
+ return error_mark_node;
+ }
+ if (type_size == -1)
+ {
+ error ("conversions to variable_size mode");
+ return error_mark_node;
+ }
+
+ /* FIXME: process REAL ==> INT && INT ==> REAL && REAL ==> REAL. I hope this is correct. */
+ if ((TREE_CODE (expr_type) == INTEGER_TYPE && TREE_CODE (type) == REAL_TYPE) ||
+ (TREE_CODE (expr_type) == REAL_TYPE && TREE_CODE (type) == INTEGER_TYPE) ||
+ (TREE_CODE (expr_type) == REAL_TYPE && TREE_CODE (type) == REAL_TYPE))
+ return convert (type, expr);
+
+ /* FIXME: Don't know if this is correct */
+ /* Don't allow conversions to or from REAL with others then integer */
+ if (TREE_CODE (type) == REAL_TYPE)
+ {
+ error ("cannot convert to float");
+ return error_mark_node;
+ }
+ else if (TREE_CODE (expr_type) == REAL_TYPE)
+ {
+ error ("cannot convert float to this mode");
+ return error_mark_node;
+ }
+
+ if (expr_type_size == type_size && CH_REFERABLE (expr))
+ goto do_location_conversion;
+
+ type_is_discrete
+ = discrete_type_p (type) || TREE_CODE (type) == POINTER_TYPE;
+ expr_type_is_discrete
+ = discrete_type_p (expr_type) || TREE_CODE (expr_type) == POINTER_TYPE;
+ if (expr_type_is_discrete && type_is_discrete)
+ {
+ /* do an overflow check
+ FIXME: is this always neccessary ??? */
+ /* FIXME: don't do range chacking when target type is PTR.
+ PTR doesn't have MIN and MAXVALUE. result is sigsegv. */
+ if (range_checking && type != ptr_type_node)
+ {
+ tree tmp = expr;
+
+ STRIP_NOPS (tmp);
+ if (TREE_CONSTANT (tmp) && TREE_CODE (tmp) != ADDR_EXPR)
+ {
+ if (compare_int_csts (LT_EXPR, tmp, TYPE_MIN_VALUE (type)) ||
+ compare_int_csts (GT_EXPR, tmp, TYPE_MAX_VALUE (type)))
+ {
+ error ("OVERFLOW in expression conversion");
+ return error_mark_node;
+ }
+ }
+ else
+ {
+ int cond1 = tree_int_cst_lt (TYPE_SIZE (type),
+ TYPE_SIZE (expr_type));
+ int cond2 = TREE_UNSIGNED (type) && (! TREE_UNSIGNED (expr_type));
+ int cond3 = (! TREE_UNSIGNED (type))
+ && TREE_UNSIGNED (expr_type)
+ && tree_int_cst_equal (TYPE_SIZE (type),
+ TYPE_SIZE (expr_type));
+ int cond4 = TREE_TYPE (type) && type_is_discrete;
+
+ if (cond1 || cond2 || cond3 || cond4)
+ {
+ tree type_min = TYPE_MIN_VALUE (type);
+ tree type_max = TYPE_MAX_VALUE (type);
+
+ expr = save_if_needed (expr);
+ if (expr && type_min && type_max)
+ {
+ tree check = test_range (expr, type_min, type_max);
+ if (!integer_zerop (check))
+ {
+ if (current_function_decl == NULL_TREE)
+ {
+ if (TREE_CODE (check) == INTEGER_CST)
+ error ("overflow (not inside function)");
+ else
+ warning ("possible overflow (not inside function)");
+ }
+ else
+ {
+ if (TREE_CODE (check) == INTEGER_CST)
+ warning ("expression will always cause OVERFLOW");
+ expr = check_expression (expr, check,
+ ridpointers[(int) RID_OVERFLOW]);
+ }
+ }
+ }
+ }
+ }
+ }
+ return convert (type, expr);
+ }
+
+ if (TREE_CODE (expr) == INTEGER_CST && expr_type_size != type_size)
+ {
+ /* There should probably be a pedwarn here ... */
+ tree itype = type_for_size (type_size * BITS_PER_UNIT, 1);
+ if (itype)
+ {
+ expr = convert (itype, expr);
+ expr_type = TREE_TYPE (expr);
+ expr_type_size= type_size;
+ }
+ }
+
+ /* If expr is a constant of the right size, use it to to
+ initialize a static variable. */
+ if (expr_type_size == type_size && TREE_CONSTANT (expr) && !pedantic)
+ {
+ unsigned char *buffer = (unsigned char*) alloca (type_size);
+ tree value;
+ bzero (buffer, type_size);
+ if (!expand_constant_to_buffer (expr, buffer, type_size))
+ {
+ error ("not implemented: constant conversion from that kind of expression");
+ return error_mark_node;
+ }
+ value = extract_constant_from_buffer (type, buffer, type_size);
+ if (value == NULL_TREE)
+ {
+ error ("not implemented: constant conversion to that kind of mode");
+ return error_mark_node;
+ }
+ return value;
+ }
+
+ if (!CH_REFERABLE (expr) && expr_type_size == type_size)
+ {
+ tree temp = decl_temp1 (get_unique_identifier ("CAST"),
+ TREE_TYPE (expr), 0, 0, 0, 0);
+ tree convert1 = build_chill_modify_expr (temp, expr);
+ pedwarn ("non-standard, non-portable value conversion");
+ return build (COMPOUND_EXPR, type, convert1,
+ build_chill_cast (type, temp));
+ }
+
+ if (CH_REFERABLE (expr) && expr_type_size != type_size)
+ error ("location conversion between differently-sized modes");
+ else
+ error ("unsupported value conversion");
+ return error_mark_node;
+
+ do_location_conversion:
+ /* To avoid confusing other parts of gcc,
+ represent this as the C expression: *(TYPE*)EXPR. */
+ mark_addressable (expr);
+ expr = build1 (INDIRECT_REF, type,
+ build1 (NOP_EXPR, build_pointer_type (type),
+ build1 (ADDR_EXPR, build_pointer_type (expr_type),
+ expr)));
+ TREE_READONLY (expr) == TYPE_READONLY (type);
+ return expr;
+}
+
+/*
+ * given a set_type, build an integer array from it that C will grok.
+ */
+tree
+build_array_from_set (type)
+ tree type;
+{
+ tree bytespint, bit_array_size, int_array_count;
+
+ if (type == NULL_TREE || type == error_mark_node || TREE_CODE (type) != SET_TYPE)
+ return error_mark_node;
+
+ bytespint = build_int_2 (HOST_BITS_PER_INT / HOST_BITS_PER_CHAR, 0);
+ bit_array_size = size_in_bytes (type);
+ int_array_count = fold (size_binop (TRUNC_DIV_EXPR, bit_array_size,
+ bytespint));
+ if (integer_zerop (int_array_count))
+ int_array_count = size_one_node;
+ type = build_array_type (integer_type_node,
+ build_index_type (int_array_count));
+ return type;
+}
+
+
+tree
+build_chill_bin_type (size)
+ tree size;
+{
+#if 0
+ int isize;
+
+ if (TREE_CODE (size) != INTEGER_CST
+ || (isize = TREE_INT_CST_LOW (size), isize <= 0))
+ {
+ error ("operand to bin must be a non-negative integer literal");
+ return error_mark_node;
+ }
+ if (isize <= TYPE_PRECISION (unsigned_char_type_node))
+ return unsigned_char_type_node;
+ if (isize <= TYPE_PRECISION (short_unsigned_type_node))
+ return short_unsigned_type_node;
+ if (isize <= TYPE_PRECISION (unsigned_type_node))
+ return unsigned_type_node;
+ if (isize <= TYPE_PRECISION (long_unsigned_type_node))
+ return long_unsigned_type_node;
+ if (isize <= TYPE_PRECISION (long_long_unsigned_type_node))
+ return long_long_unsigned_type_node;
+ error ("size %d of BIN too big - no such integer mode", isize);
+ return error_mark_node;
+#endif
+ tree bintype;
+
+ if (pass == 1)
+ {
+ bintype = make_node (INTEGER_TYPE);
+ TREE_TYPE (bintype) = ridpointers[(int) RID_BIN];
+ TYPE_MIN_VALUE (bintype) = size;
+ TYPE_MAX_VALUE (bintype) = size;
+ }
+ else
+ {
+ error ("BIN in pass 2");
+ return error_mark_node;
+ }
+ return bintype;
+}
+
+tree
+chill_expand_tuple (type, constructor)
+ tree type, constructor;
+{
+ char *name;
+ tree nonreft = type;
+
+ if (TYPE_NAME (type) != NULL_TREE)
+ {
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ name = IDENTIFIER_POINTER (TYPE_NAME (type));
+ else
+ name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ }
+ else
+ name = "";
+
+ /* get to actual underlying type for digest_init */
+ while (nonreft && TREE_CODE (nonreft) == REFERENCE_TYPE)
+ nonreft = TREE_TYPE (nonreft);
+
+ if (TREE_CODE (nonreft) == ARRAY_TYPE
+ || TREE_CODE (nonreft) == RECORD_TYPE
+ || TREE_CODE (nonreft) == SET_TYPE)
+ return convert (nonreft, constructor);
+ else
+ {
+ error ("mode of tuple is neither ARRAY, STRUCT, nor POWERSET");
+ return error_mark_node;
+ }
+}
+
+/* This function classifies an expr into the Null class,
+ the All class, the M-Value, the M-derived, or the M-reference class.
+ It probably has some inaccuracies. */
+
+struct ch_class
+chill_expr_class (expr)
+ tree expr;
+{
+ struct ch_class class;
+ /* The Null class contains the NULL pointer constant (only). */
+ if (expr == null_pointer_node)
+ {
+ class.kind = CH_NULL_CLASS;
+ class.mode = NULL_TREE;
+ return class;
+ }
+
+ /* The All class contains the <undefined value> "*". */
+ if (TREE_CODE (expr) == UNDEFINED_EXPR)
+ {
+ class.kind = CH_ALL_CLASS;
+ class.mode = NULL_TREE;
+ return class;
+ }
+
+ if (CH_DERIVED_FLAG (expr))
+ {
+ class.kind = CH_DERIVED_CLASS;
+ class.mode = TREE_TYPE (expr);
+ return class;
+ }
+
+ /* The M-Reference contains <references location> (address-of) expressions.
+ Note that something that's been converted to a reference doesn't count. */
+ if (TREE_CODE (expr) == ADDR_EXPR
+ && TREE_CODE (TREE_TYPE (expr)) != REFERENCE_TYPE)
+ {
+ class.kind = CH_REFERENCE_CLASS;
+ class.mode = TREE_TYPE (TREE_TYPE (expr));
+ return class;
+ }
+
+ /* The M-Value class contains expressions with a known, specific mode M. */
+ class.kind = CH_VALUE_CLASS;
+ class.mode = TREE_TYPE (expr);
+ return class;
+}
+
+/* Returns >= 1 iff REF is a location. Return 2 if it is referable. */
+
+int chill_location (ref)
+ tree ref;
+{
+ register enum tree_code code = TREE_CODE (ref);
+
+ switch (code)
+ {
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case ARRAY_REF:
+ case PACKED_ARRAY_REF:
+ case COMPONENT_REF:
+ case NOP_EXPR: /* RETYPE_EXPR */
+ return chill_location (TREE_OPERAND (ref, 0));
+ case COMPOUND_EXPR:
+ return chill_location (TREE_OPERAND (ref, 1));
+
+ case BIT_FIELD_REF:
+ case SLICE_EXPR:
+ /* A bit-string slice is nor referable. */
+ return chill_location (TREE_OPERAND (ref, 0)) == 0 ? 0 : 1;
+
+ case CONSTRUCTOR:
+ case STRING_CST:
+ return 0;
+
+ case INDIRECT_REF:
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case ERROR_MARK:
+ if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
+ return 2;
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+int
+chill_referable (val)
+ tree val;
+{
+ return chill_location (val) > 1;
+}
+
+/* Make a copy of MODE, but with the given NOVELTY. */
+
+tree
+copy_novelty (novelty, mode)
+ tree novelty, mode;
+{
+ if (CH_NOVELTY (mode) != novelty)
+ {
+ mode = copy_node (mode);
+ TYPE_MAIN_VARIANT (mode) = mode;
+ TYPE_NEXT_VARIANT (mode) = 0;
+ TYPE_POINTER_TO (mode) = 0;
+ TYPE_REFERENCE_TO (mode) = 0;
+ SET_CH_NOVELTY (mode, novelty);
+ }
+ return mode;
+}
+
+
+struct mode_chain
+{
+ struct mode_chain *prev;
+ tree mode1, mode2;
+};
+
+/* Tests if MODE1 and MODE2 are SIMILAR.
+ This is more or less as defined in the Blue Book, though
+ see FIXME for parts that are unfinished.
+ CHAIN is used to catch infinite recursion: It is a list of pairs
+ of mode arguments to calls to chill_similar "outer" to this call. */
+
+int
+chill_similar (mode1, mode2, chain)
+ tree mode1, mode2;
+ struct mode_chain *chain;
+{
+ int varying1, varying2;
+ tree t1, t2;
+ struct mode_chain *link, node;
+ if (mode1 == NULL_TREE || mode2 == NULL_TREE)
+ return 0;
+
+ while (TREE_CODE (mode1) == REFERENCE_TYPE)
+ mode1 = TREE_TYPE (mode1);
+ while (TREE_CODE (mode2) == REFERENCE_TYPE)
+ mode2 = TREE_TYPE (mode2);
+
+ /* Range modes are similar to their parent types. */
+ while (TREE_CODE (mode1) == INTEGER_TYPE && TREE_TYPE (mode1) != NULL_TREE)
+ mode1 = TREE_TYPE (mode1);
+ while (TREE_CODE (mode2) == INTEGER_TYPE && TREE_TYPE (mode2) != NULL_TREE)
+ mode2 = TREE_TYPE (mode2);
+
+
+ /* see Z.200 sections 12.1.2.2 and 13.2 - all integer precisions
+ are similar to INT and to each other */
+ if (mode1 == mode2 ||
+ (TREE_CODE (mode1) == INTEGER_TYPE && TREE_CODE (mode2) == INTEGER_TYPE))
+ return 1;
+
+ /* This guards against certain kinds of recursion.
+ For example:
+ SYNMODE a = STRUCT ( next REF a );
+ SYNMODE b = STRUCT ( next REF b );
+ These moes are similar, but will get an infite recursion trying
+ to prove that. So, if we are recursing, assume the moes are similar.
+ If they are not, we'll find some other discrepancy. */
+ for (link = chain; link != NULL; link = link->prev)
+ {
+ if (link->mode1 == mode1 && link->mode2 == mode2)
+ return 1;
+ }
+
+ node.mode1 = mode1;
+ node.mode2 = mode2;
+ node.prev = chain;
+
+ varying1 = chill_varying_type_p (mode1);
+ varying2 = chill_varying_type_p (mode2);
+ /* FIXME: This isn't quite strict enough. */
+ if ((varying1 && varying2)
+ || (varying1 && TREE_CODE (mode2) == ARRAY_TYPE)
+ || (varying2 && TREE_CODE (mode1) == ARRAY_TYPE))
+ return 1;
+
+ if (TREE_CODE(mode1) != TREE_CODE(mode2))
+ {
+ if (flag_old_strings)
+ {
+ /* The recursion is to handle varying strings. */
+ if ((TREE_CODE (mode1) == CHAR_TYPE
+ && CH_SIMILAR (mode2, string_one_type_node))
+ || (TREE_CODE (mode2) == CHAR_TYPE
+ && CH_SIMILAR (mode1, string_one_type_node)))
+ return 1;
+ if ((TREE_CODE (mode1) == BOOLEAN_TYPE
+ && CH_SIMILAR (mode2, bitstring_one_type_node))
+ || (TREE_CODE (mode2) == BOOLEAN_TYPE
+ && CH_SIMILAR (mode1, bitstring_one_type_node)))
+ return 1;
+ }
+ if (TREE_CODE (mode1) == FUNCTION_TYPE
+ && TREE_CODE (mode2) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (mode2)) == FUNCTION_TYPE)
+ mode2 = TREE_TYPE (mode2);
+ else if (TREE_CODE (mode2) == FUNCTION_TYPE
+ && TREE_CODE (mode1) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (mode1)) == FUNCTION_TYPE)
+ mode1 = TREE_TYPE (mode1);
+ else
+ return 0;
+ }
+
+ if (CH_IS_BUFFER_MODE (mode1) && CH_IS_BUFFER_MODE (mode2))
+ {
+ tree len1 = max_queue_size (mode1);
+ tree len2 = max_queue_size (mode2);
+ return tree_int_cst_equal (len1, len2);
+ }
+ else if (CH_IS_EVENT_MODE (mode1) && CH_IS_EVENT_MODE (mode2))
+ {
+ tree len1 = max_queue_size (mode1);
+ tree len2 = max_queue_size (mode2);
+ return tree_int_cst_equal (len1, len2);
+ }
+ else if (CH_IS_ACCESS_MODE (mode1) && CH_IS_ACCESS_MODE (mode2))
+ {
+ tree index1 = access_indexmode (mode1);
+ tree index2 = access_indexmode (mode2);
+ tree record1 = access_recordmode (mode1);
+ tree record2 = access_recordmode (mode2);
+ if (! chill_read_compatible (index1, index2))
+ return 0;
+ return chill_read_compatible (record1, record2);
+ }
+ switch ((enum chill_tree_code)TREE_CODE (mode1))
+ {
+ case INTEGER_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ return 1;
+ case ENUMERAL_TYPE:
+ if (TYPE_VALUES (mode1) == TYPE_VALUES (mode2))
+ return 1;
+ else
+ {
+ /* FIXME: This is more strict than z.200, which seems to
+ allow the elements to be reordered, as long as they
+ have the same values. */
+
+ tree field1 = TYPE_VALUES (mode1);
+ tree field2 = TYPE_VALUES (mode2);
+
+ while (field1 != NULL_TREE && field2 != NULL_TREE)
+ {
+ tree value1, value2;
+ /* Check that the names are equal. */
+ if (TREE_PURPOSE (field1) != TREE_PURPOSE (field2))
+ break;
+
+ value1 = TREE_VALUE (field1);
+ value2 = TREE_VALUE (field2);
+ /* This isn't quite sufficient in general, but will do ... */
+ /* Note that proclaim_decl can cause the SET modes to be
+ compared BEFORE they are satisfied, but otherwise
+ chill_similar is mostly called after satisfaction. */
+ if (TREE_CODE (value1) == CONST_DECL)
+ value1 = DECL_INITIAL (value1);
+ if (TREE_CODE (value2) == CONST_DECL)
+ value2 = DECL_INITIAL (value2);
+ /* Check that the values are equal or both NULL. */
+ if (!(value1 == NULL_TREE && value2 == NULL_TREE)
+ && (value1 == NULL_TREE || value2 == NULL_TREE
+ || ! tree_int_cst_equal (value1, value2)))
+ break;
+ field1 = TREE_CHAIN (field1);
+ field2 = TREE_CHAIN (field2);
+ }
+ return field1 == NULL_TREE && field2 == NULL_TREE;
+ }
+ case SET_TYPE:
+ /* check for bit strings */
+ if (CH_BOOLS_TYPE_P (mode1))
+ return CH_BOOLS_TYPE_P (mode2);
+ if (CH_BOOLS_TYPE_P (mode2))
+ return CH_BOOLS_TYPE_P (mode1);
+ /* both are powerset modes */
+ return CH_EQUIVALENT (TYPE_DOMAIN (mode1), TYPE_DOMAIN (mode2));
+
+ case POINTER_TYPE:
+ /* Are the referenced modes equivalent? */
+ return !integer_zerop (chill_equivalent (TREE_TYPE (mode1),
+ TREE_TYPE (mode2),
+ &node));
+
+ case ARRAY_TYPE:
+ /* char for char strings */
+ if (CH_CHARS_TYPE_P (mode1))
+ return CH_CHARS_TYPE_P (mode2);
+ if (CH_CHARS_TYPE_P (mode2))
+ return CH_CHARS_TYPE_P (mode1);
+ /* array modes */
+ if (CH_V_EQUIVALENT (TYPE_DOMAIN (mode1), TYPE_DOMAIN (mode2))
+ /* Are the elements modes equivalent? */
+ && !integer_zerop (chill_equivalent (TREE_TYPE (mode1),
+ TREE_TYPE (mode2),
+ &node)))
+ {
+ /* FIXME: Check that element layouts are equivalent */
+
+ tree count1 = fold (build (MINUS_EXPR, sizetype,
+ TYPE_MAX_VALUE (TYPE_DOMAIN (mode1)),
+ TYPE_MIN_VALUE (TYPE_DOMAIN (mode1))));
+ tree count2 = fold (build (MINUS_EXPR, sizetype,
+ TYPE_MAX_VALUE (TYPE_DOMAIN (mode2)),
+ TYPE_MIN_VALUE (TYPE_DOMAIN (mode2))));
+ tree cond = build_compare_discrete_expr (EQ_EXPR, count1, count2);
+ if (TREE_CODE (cond) == INTEGER_CST)
+ return !integer_zerop (cond);
+ else
+ {
+#if 0
+ extern int ignoring;
+ if (!ignoring
+ && range_checking
+ && current_function_decl)
+ return cond;
+#endif
+ return 1;
+ }
+ }
+ return 0;
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ for (t1 = TYPE_FIELDS (mode1), t2 = TYPE_FIELDS (mode2);
+ t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+ {
+ if (TREE_CODE (t1) != TREE_CODE (t2))
+ return 0;
+ /* Are the field modes equivalent? */
+ if (integer_zerop (chill_equivalent (TREE_TYPE (t1),
+ TREE_TYPE (t2),
+ &node)))
+ return 0;
+ }
+ return t1 == t2;
+
+ case FUNCTION_TYPE:
+ if (!chill_l_equivalent (TREE_TYPE (mode1), TREE_TYPE (mode2), &node))
+ return 0;
+ for (t1 = TYPE_ARG_TYPES (mode1), t2 = TYPE_ARG_TYPES (mode2);
+ t1 != NULL_TREE && t2 != NULL_TREE;
+ t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+ {
+ tree attr1 = TREE_PURPOSE (t1)
+ ? TREE_PURPOSE (t1) : ridpointers[(int) RID_IN];
+ tree attr2 = TREE_PURPOSE (t2)
+ ? TREE_PURPOSE (t2) : ridpointers[(int) RID_IN];
+ if (attr1 != attr2)
+ return 0;
+ if (!chill_l_equivalent (TREE_VALUE (t1), TREE_VALUE (t2), &node))
+ return 0;
+ }
+ if (t1 != t2) /* Both NULL_TREE */
+ return 0;
+ /* check list of exception names */
+ t1 = TYPE_RAISES_EXCEPTIONS (mode1);
+ t2 = TYPE_RAISES_EXCEPTIONS (mode2);
+ if (t1 == NULL_TREE && t2 != NULL_TREE)
+ return 0;
+ if (t1 != NULL_TREE && t2 == NULL_TREE)
+ return 0;
+ if (list_length (t1) != list_length (t2))
+ return 0;
+ while (t1 != NULL_TREE)
+ {
+ if (value_member (TREE_VALUE (t1), t2) == NULL_TREE)
+ return 0;
+ t1 = TREE_CHAIN (t1);
+ }
+ /* FIXME: Should also check they have the same RECURSIVITY */
+ return 1;
+
+ default:
+ ;
+#if 0
+ /* Need to handle row modes, instance modes,
+ association modes, access modes, text modes,
+ duration modes, absolute time modes, structure modes,
+ parameterized structure modes */
+#endif
+ }
+ return 1;
+}
+
+/* Return a node that is true iff MODE1 and MODE2 are equivalent.
+ This is normally boolean_true_node or boolean_false_node,
+ but can be dynamic for dynamic types.
+ CHAIN is as for chill_similar. */
+
+tree
+chill_equivalent (mode1, mode2, chain)
+ tree mode1, mode2;
+ struct mode_chain *chain;
+{
+ int varying1, varying2;
+ int is_string1, is_string2;
+ tree base_mode1, base_mode2;
+
+ /* Are the modes v-equivalent? */
+#if 0
+ if (!chill_similar (mode1, mode2, chain)
+ || CH_NOVELTY(mode1) != CH_NOVELTY(mode2))
+ return boolean_false_node;
+#endif
+ if (!chill_similar (mode1, mode2, chain))
+ return boolean_false_node;
+ else if (TREE_CODE (mode2) == FUNCTION_TYPE
+ && TREE_CODE (mode1) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (mode1)) == FUNCTION_TYPE)
+ /* don't check novelty in this case to avoid error in case of
+ NEWMODE'd proceduremode gets assigned a function */
+ return boolean_true_node;
+ else if (CH_NOVELTY(mode1) != CH_NOVELTY(mode2))
+ return boolean_false_node;
+
+ varying1 = chill_varying_type_p (mode1);
+ varying2 = chill_varying_type_p (mode2);
+
+ if (varying1 != varying2)
+ return boolean_false_node;
+ base_mode1 = varying1 ? CH_VARYING_ARRAY_TYPE (mode1) : mode1;
+ base_mode2 = varying2 ? CH_VARYING_ARRAY_TYPE (mode2) : mode2;
+ is_string1 = CH_STRING_TYPE_P (base_mode1);
+ is_string2 = CH_STRING_TYPE_P (base_mode2);
+ if (is_string1 || is_string2)
+ {
+ if (is_string1 != is_string2)
+ return boolean_false_node;
+ return fold (build (EQ_EXPR, boolean_type_node,
+ TYPE_SIZE (base_mode1),
+ TYPE_SIZE (base_mode2)));
+ }
+
+ /* && some more stuff FIXME! */
+ if (TREE_CODE(mode1) == INTEGER_TYPE || TREE_CODE(mode2) == INTEGER_TYPE)
+ {
+ if (TREE_CODE(mode1) != INTEGER_TYPE || TREE_CODE(mode2) != INTEGER_TYPE)
+ return boolean_false_node;
+ /* If one is a range, the other has to be a range. */
+ if ((TREE_TYPE (mode1) != NULL_TREE) != (TREE_TYPE (mode2) != NULL_TREE))
+ return boolean_false_node;
+ if (TYPE_PRECISION (mode1) != TYPE_PRECISION (mode2))
+ return boolean_false_node;
+ if (!tree_int_cst_equal (TYPE_MIN_VALUE (mode1), TYPE_MIN_VALUE (mode2)))
+ return boolean_false_node;
+ if (!tree_int_cst_equal (TYPE_MAX_VALUE (mode1), TYPE_MAX_VALUE (mode2)))
+ return boolean_false_node;
+ }
+ return boolean_true_node;
+}
+
+static int
+chill_l_equivalent (mode1, mode2, chain)
+ tree mode1, mode2;
+ struct mode_chain *chain;
+{
+ /* Are the modes equivalent? */
+ if (integer_zerop (chill_equivalent (mode1, mode2, chain)))
+ return 0;
+ if (TYPE_READONLY (mode1) != TYPE_READONLY (mode2))
+ return 0;
+#if 0
+ ... other conditions ...;
+#endif
+ return 1;
+}
+
+/* See Z200 12.1.2.12 */
+
+int
+chill_read_compatible (modeM, modeN)
+ tree modeM, modeN;
+{
+ while (TREE_CODE (modeM) == REFERENCE_TYPE)
+ modeM = TREE_TYPE (modeM);
+ while (TREE_CODE (modeN) == REFERENCE_TYPE)
+ modeN = TREE_TYPE (modeN);
+
+ if (!CH_EQUIVALENT (modeM, modeN))
+ return 0;
+ if (TYPE_READONLY (modeN))
+ {
+ if (!TYPE_READONLY (modeM))
+ return 0;
+ if (CH_IS_BOUND_REFERENCE_MODE (modeM)
+ && CH_IS_BOUND_REFERENCE_MODE (modeN))
+ {
+ return chill_l_equivalent (TREE_TYPE (modeM), TREE_TYPE (modeN), 0);
+ }
+#if 0
+ ...;
+#endif
+ }
+ return 1;
+}
+
+/* Tests if MODE is compatible with the class of EXPR.
+ Cfr. Chill Blue Book 12.1.2.15. */
+
+int
+chill_compatible (expr, mode)
+ tree expr, mode;
+{
+ struct ch_class class;
+
+ if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK)
+ return 0;
+ if (mode == NULL_TREE || TREE_CODE (mode) == ERROR_MARK)
+ return 0;
+
+ while (TREE_CODE (mode) == REFERENCE_TYPE)
+ mode = TREE_TYPE (mode);
+
+ if (TREE_TYPE (expr) == NULL_TREE)
+ if (TREE_CODE (expr) == CONSTRUCTOR)
+ return TREE_CODE (mode) == RECORD_TYPE
+ || ((TREE_CODE (mode) == SET_TYPE || TREE_CODE (mode) == ARRAY_TYPE)
+ && ! TYPE_STRING_FLAG (mode));
+ else
+ return TREE_CODE (expr) == CASE_EXPR || TREE_CODE (expr) == COND_EXPR;
+
+ class = chill_expr_class (expr);
+ switch (class.kind)
+ {
+ case CH_ALL_CLASS:
+ return 1;
+ case CH_NULL_CLASS:
+ return CH_IS_REFERENCE_MODE (mode) || CH_IS_PROCEDURE_MODE (mode)
+ || CH_IS_INSTANCE_MODE (mode);
+ case CH_VALUE_CLASS:
+ if (CH_HAS_REFERENCING_PROPERTY (mode))
+ return CH_RESTRICTABLE_TO(mode, class.mode);
+ else
+ return CH_V_EQUIVALENT(mode, class.mode);
+ case CH_DERIVED_CLASS:
+ return CH_SIMILAR (class.mode, mode);
+ case CH_REFERENCE_CLASS:
+ if (!CH_IS_REFERENCE_MODE (mode))
+ return 0;
+#if 0
+ /* FIXME! */
+ if (class.mode is a row mode)
+ ...;
+ else if (class.mode is not a static mode)
+ return 0; /* is this possible? FIXME */
+#endif
+ return !CH_IS_BOUND_REFERENCE_MODE(mode)
+ || CH_READ_COMPATIBLE (TREE_TYPE (mode), class.mode);
+ }
+ return 0; /* ERROR! */
+}
+
+/* Tests if the class of of EXPR1 and EXPR2 are compatible.
+ Cfr. Chill Blue Book 12.1.2.16. */
+
+int
+chill_compatible_classes (expr1, expr2)
+ tree expr1, expr2;
+{
+ struct ch_class temp;
+ struct ch_class class1, class2;
+ class1 = chill_expr_class (expr1);
+ class2 = chill_expr_class (expr2);
+
+ switch (class1.kind)
+ {
+ case CH_ALL_CLASS:
+ return 1;
+ case CH_NULL_CLASS:
+ switch (class2.kind)
+ {
+ case CH_ALL_CLASS:
+ case CH_NULL_CLASS:
+ case CH_REFERENCE_CLASS:
+ return 1;
+ case CH_VALUE_CLASS:
+ case CH_DERIVED_CLASS:
+ goto rule4;
+ }
+ case CH_REFERENCE_CLASS:
+ switch (class2.kind)
+ {
+ case CH_ALL_CLASS:
+ case CH_NULL_CLASS:
+ return 1;
+ case CH_REFERENCE_CLASS:
+ return CH_EQUIVALENT (class1.mode, class2.mode);
+ case CH_VALUE_CLASS:
+ goto rule6;
+ case CH_DERIVED_CLASS:
+ return 0;
+ }
+ case CH_DERIVED_CLASS:
+ switch (class2.kind)
+ {
+ case CH_ALL_CLASS:
+ return 1;
+ case CH_VALUE_CLASS:
+ case CH_DERIVED_CLASS:
+ return CH_SIMILAR (class1.mode, class2.mode);
+ case CH_NULL_CLASS:
+ class2 = class1;
+ goto rule4;
+ case CH_REFERENCE_CLASS:
+ return 0;
+ }
+ case CH_VALUE_CLASS:
+ switch (class2.kind)
+ {
+ case CH_ALL_CLASS:
+ return 1;
+ case CH_DERIVED_CLASS:
+ return CH_SIMILAR (class1.mode, class2.mode);
+ case CH_VALUE_CLASS:
+ return CH_V_EQUIVALENT (class1.mode, class2.mode);
+ case CH_NULL_CLASS:
+ class2 = class1;
+ goto rule4;
+ case CH_REFERENCE_CLASS:
+ temp = class1; class1 = class2; class2 = temp;
+ goto rule6;
+ }
+ }
+ rule4:
+ /* The Null class is Compatible with the M-derived class or M-value class
+ if and only if M is a reference mdoe, procedure mode or instance mode.*/
+ return CH_IS_REFERENCE_MODE (class2.mode)
+ || CH_IS_PROCEDURE_MODE (class2.mode)
+ || CH_IS_INSTANCE_MODE (class2.mode);
+
+ rule6:
+ /* The M-reference class is compatible with the N-value class if and
+ only if N is a reference mode and ... */
+ if (!CH_IS_REFERENCE_MODE (class2.mode))
+ return 0;
+ if (1) /* If M is a static mode - FIXME */
+ {
+ if (!CH_IS_BOUND_REFERENCE_MODE (class2.mode))
+ return 1;
+ if (CH_EQUIVALENT (TREE_TYPE (class2.mode), class1.mode))
+ return 1;
+ }
+ /* If N is a row mode whose .... FIXME */
+ return 0;
+}
+
+/* Cfr. Blue Book 12.1.1.6, with some "extensions." */
+
+tree
+chill_root_mode (mode)
+ tree mode;
+{
+ /* Reference types are not user-visible types.
+ This seems like a good place to get rid of them. */
+ if (TREE_CODE (mode) == REFERENCE_TYPE)
+ mode = TREE_TYPE (mode);
+
+ while (TREE_CODE (mode) == INTEGER_TYPE && TREE_TYPE (mode) != NULL_TREE)
+ mode = TREE_TYPE (mode); /* a sub-range */
+
+ /* This extension in not in the Blue Book - which only has a
+ single Integer type.
+ We should probably use chill_integer_type_node rather
+ than integer_type_node, but that is likely to bomb.
+ At some point, these will become the same, I hope. FIXME */
+ if (TREE_CODE (mode) == INTEGER_TYPE
+ && TYPE_PRECISION (mode) < TYPE_PRECISION (integer_type_node)
+ && CH_NOVELTY (mode) == NULL_TREE)
+ mode = integer_type_node;
+
+ if (TREE_CODE (mode) == FUNCTION_TYPE)
+ return build_pointer_type (mode);
+
+ return mode;
+}
+
+/* Cfr. Blue Book 12.1.1.7. */
+
+tree
+chill_resulting_mode (mode1, mode2)
+ tree mode1, mode2;
+{
+ mode1 = CH_ROOT_MODE (mode1);
+ mode2 = CH_ROOT_MODE (mode2);
+ if (chill_varying_type_p (mode1))
+ return mode1;
+ if (chill_varying_type_p (mode2))
+ return mode2;
+ return mode1;
+}
+
+/* Cfr. Blue Book (z200, 1988) 12.1.1.7 Resulting class. */
+
+struct ch_class
+chill_resulting_class (class1, class2)
+ struct ch_class class1, class2;
+{
+ struct ch_class class;
+ switch (class1.kind)
+ {
+ case CH_VALUE_CLASS:
+ switch (class2.kind)
+ {
+ case CH_DERIVED_CLASS:
+ case CH_ALL_CLASS:
+ class.kind = CH_VALUE_CLASS;
+ class.mode = CH_ROOT_MODE (class1.mode);
+ return class;
+ case CH_VALUE_CLASS:
+ class.kind = CH_VALUE_CLASS;
+ class.mode
+ = CH_ROOT_MODE (CH_RESULTING_MODE (class1.mode, class2.mode));
+ return class;
+ }
+ case CH_DERIVED_CLASS:
+ switch (class2.kind)
+ {
+ case CH_VALUE_CLASS:
+ class.kind = CH_VALUE_CLASS;
+ class.mode = CH_ROOT_MODE (class2.mode);
+ return class;
+ case CH_DERIVED_CLASS:
+ class.kind = CH_DERIVED_CLASS;
+ class.mode = CH_RESULTING_MODE (class1.mode, class2.mode);
+ return class;
+ case CH_ALL_CLASS:
+ class.kind = CH_DERIVED_CLASS;
+ class.mode = CH_ROOT_MODE (class1.mode);
+ return class;
+ }
+ case CH_ALL_CLASS:
+ switch (class2.kind)
+ {
+ case CH_VALUE_CLASS:
+ class.kind = CH_VALUE_CLASS;
+ class.mode = CH_ROOT_MODE (class2.mode);
+ return class;
+ case CH_ALL_CLASS:
+ class.kind = CH_ALL_CLASS;
+ class.mode = NULL_TREE;
+ return class;
+ case CH_DERIVED_CLASS:
+ class.kind = CH_DERIVED_CLASS;
+ class.mode = CH_ROOT_MODE (class2.mode);
+ return class;
+ }
+ }
+ error ("internal error in chill_root_resulting_mode");
+ class.kind = CH_VALUE_CLASS;
+ class.mode = CH_ROOT_MODE (class1.mode);
+ return class;
+}
+
+
+/*
+ * See Z.200, section 6.3, static conditions. This function
+ * returns bool_false_node if the condition is not met at compile time,
+ * bool_true_node if the condition is detectably met at compile time
+ * an expression if a runtime check would be required or was generated.
+ * It should only be called with string modes and values.
+ */
+tree
+string_assignment_condition (lhs_mode, rhs_value)
+ tree lhs_mode, rhs_value;
+{
+ tree lhs_size, rhs_size, cond;
+ tree rhs_mode = TREE_TYPE (rhs_value);
+ int lhs_varying = chill_varying_type_p (lhs_mode);
+
+ if (lhs_varying)
+ lhs_size = size_in_bytes (CH_VARYING_ARRAY_TYPE (lhs_mode));
+ else if (CH_BOOLS_TYPE_P (lhs_mode))
+ lhs_size = TYPE_MAX_VALUE (TYPE_DOMAIN (lhs_mode));
+ else
+ lhs_size = size_in_bytes (lhs_mode);
+ lhs_size = convert (chill_unsigned_type_node, lhs_size);
+
+ if (rhs_mode && TREE_CODE (rhs_mode) == REFERENCE_TYPE)
+ rhs_mode = TREE_TYPE (rhs_mode);
+ if (rhs_mode == NULL_TREE)
+ {
+ /* actually, count constructor's length */
+ abort ();
+ }
+ else if (chill_varying_type_p (rhs_mode))
+ rhs_size = build_component_ref (rhs_value, var_length_id);
+ else if (CH_BOOLS_TYPE_P (rhs_mode))
+ rhs_size = TYPE_MAX_VALUE (TYPE_DOMAIN (rhs_mode));
+ else
+ rhs_size = size_in_bytes (rhs_mode);
+ rhs_size = convert (chill_unsigned_type_node, rhs_size);
+
+ /* validity condition */
+ cond = fold (build (lhs_varying ? GE_EXPR : EQ_EXPR,
+ boolean_type_node, lhs_size, rhs_size));
+ return cond;
+}
+
+/*
+ * take a basic CHILL type and wrap it in a VARYING structure.
+ * Be sure the length field is initialized. Return the wrapper.
+ */
+tree
+build_varying_struct (type)
+ tree type;
+{
+ tree decl1, decl2, result;
+
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+
+ decl1 = build_decl (FIELD_DECL, var_length_id, chill_integer_type_node);
+ decl2 = build_decl (FIELD_DECL, var_data_id, type);
+ TREE_CHAIN (decl1) = decl2;
+ TREE_CHAIN (decl2) = NULL_TREE;
+ result = build_chill_struct_type (decl1);
+
+ /* mark this so we don't complain about missing initializers.
+ It's fine for a VARYING array to be partially initialized.. */
+ C_TYPE_VARIABLE_SIZE(type) = 1;
+ return result;
+}
+
+
+/*
+ * This is the struct type that forms the runtime initializer
+ * list. There's at least one of these generated per module.
+ * It's attached to the global initializer list by the module's
+ * 'constructor' code. Should only be called in pass 2.
+ */
+tree
+build_init_struct ()
+{
+ tree decl1, decl2, result;
+ /* We temporarily reset the maximum_field_alignment to zero so the
+ compiler's init data structures can be compatible with the
+ run-time system, even when we're compiling with -fpack. */
+ extern int maximum_field_alignment;
+ int save_maximum_field_alignment = maximum_field_alignment;
+ maximum_field_alignment = 0;
+
+ decl1 = build_decl (FIELD_DECL, get_identifier ("__INIT_ENTRY"),
+ build_chill_pointer_type (
+ build_function_type (void_type_node, NULL_TREE)));
+
+ decl2 = build_decl (FIELD_DECL, get_identifier ("__INIT_NEXT"),
+ build_chill_pointer_type (void_type_node));
+
+ TREE_CHAIN (decl1) = decl2;
+ TREE_CHAIN (decl2) = NULL_TREE;
+ result = build_chill_struct_type (decl1);
+ maximum_field_alignment = save_maximum_field_alignment;
+ return result;
+}
+
+
+/*
+ * Return 1 if the given type is a single-bit boolean set,
+ * in which the domain's min and max values
+ * are both zero,
+ * 0 if not. This can become a macro later..
+ */
+int
+ch_singleton_set (type)
+ tree type;
+{
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return 0;
+ if (TREE_CODE (type) != SET_TYPE)
+ return 0;
+ if (TREE_TYPE (type) == NULL_TREE
+ || TREE_CODE (TREE_TYPE (type)) != BOOLEAN_TYPE)
+ return 0;
+ if (TYPE_DOMAIN (type) == NULL_TREE)
+ return 0;
+ if (! tree_int_cst_equal (TYPE_MIN_VALUE (TYPE_DOMAIN (type)),
+ integer_zero_node))
+ return 0;
+ if (! tree_int_cst_equal (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+ integer_zero_node))
+ return 0;
+ return 1;
+}
+
+/* return non-zero if TYPE is a compiler-generated VARYING
+ array of some base type */
+int
+chill_varying_type_p (type)
+ tree type;
+{
+ if (type == NULL_TREE)
+ return 0;
+ if (TREE_CODE (type) != RECORD_TYPE)
+ return 0;
+ if (TYPE_FIELDS (type) == NULL_TREE
+ || TREE_CHAIN (TYPE_FIELDS (type)) == NULL_TREE)
+ return 0;
+ if (DECL_NAME (TYPE_FIELDS (type)) != var_length_id)
+ return 0;
+ if (DECL_NAME (TREE_CHAIN (TYPE_FIELDS (type))) != var_data_id)
+ return 0;
+ if (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (type))) != NULL_TREE)
+ return 0;
+ return 1;
+}
+
+/* return non-zero if TYPE is a compiler-generated VARYING
+ string record */
+int
+chill_varying_string_type_p (type)
+ tree type;
+{
+ tree var_data_type;
+
+ if (!chill_varying_type_p (type))
+ return 0;
+
+ var_data_type = CH_VARYING_ARRAY_TYPE (type);
+ return CH_CHARS_TYPE_P (var_data_type);
+}
+
+/* swiped from c-typeck.c */
+/* Build an assignment expression of lvalue LHS from value RHS. */
+
+tree
+build_chill_modify_expr (lhs, rhs)
+ tree lhs, rhs;
+{
+ register tree result;
+
+
+ tree lhstype = TREE_TYPE (lhs);
+
+ /* Avoid duplicate error messages from operands that had errors. */
+ if (lhs == NULL_TREE || TREE_CODE (lhs) == ERROR_MARK || rhs == NULL_TREE || TREE_CODE (rhs) == ERROR_MARK)
+ return error_mark_node;
+
+ /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
+ /* Do not use STRIP_NOPS here. We do not want an enumerator
+ whose value is 0 to count as a null pointer constant. */
+ if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
+ rhs = TREE_OPERAND (rhs, 0);
+
+#if 0
+ /* Handle a cast used as an "lvalue".
+ We have already performed any binary operator using the value as cast.
+ Now convert the result to the cast type of the lhs,
+ and then true type of the lhs and store it there;
+ then convert result back to the cast type to be the value
+ of the assignment. */
+
+ switch (TREE_CODE (lhs))
+ {
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ case FIX_CEIL_EXPR:
+ {
+ tree inner_lhs = TREE_OPERAND (lhs, 0);
+ tree result;
+ result = build_chill_modify_expr (inner_lhs,
+ convert (TREE_TYPE (inner_lhs),
+ convert (lhstype, rhs)));
+ pedantic_lvalue_warning (CONVERT_EXPR);
+ return convert (TREE_TYPE (lhs), result);
+ }
+ }
+
+ /* Now we have handled acceptable kinds of LHS that are not truly lvalues.
+ Reject anything strange now. */
+
+ if (!lvalue_or_else (lhs, "assignment"))
+ return error_mark_node;
+#endif
+ /* FIXME: need to generate a RANGEFAIL if the RHS won't
+ fit into the LHS. */
+
+ if (TREE_CODE (lhs) != VAR_DECL
+ && ((TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE &&
+ (TREE_TYPE (rhs) && TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE)) ||
+ chill_varying_type_p (TREE_TYPE (lhs)) ||
+ chill_varying_type_p (TREE_TYPE (rhs))))
+ {
+ int lhs_varying = chill_varying_type_p (TREE_TYPE (lhs));
+ int rhs_varying = chill_varying_type_p (TREE_TYPE (rhs));
+
+ /* point at actual RHS data's type */
+ tree rhs_data_type = rhs_varying ?
+ CH_VARYING_ARRAY_TYPE (TREE_TYPE (rhs)) :
+ TREE_TYPE (rhs);
+ {
+ /* point at actual LHS data's type */
+ tree lhs_data_type = lhs_varying ?
+ CH_VARYING_ARRAY_TYPE (TREE_TYPE (lhs)) :
+ TREE_TYPE (lhs);
+
+ int lhs_bytes = int_size_in_bytes (lhs_data_type);
+ int rhs_bytes = int_size_in_bytes (rhs_data_type);
+
+ /* if both sides not varying, and sizes not dynamically
+ computed, sizes must *match* */
+ if (! lhs_varying && ! rhs_varying && lhs_bytes != rhs_bytes
+ && lhs_bytes > 0 && rhs_bytes > 0)
+ {
+ error ("string lengths not equal");
+ return error_mark_node;
+ }
+ /* Must have enough space on LHS for static size of RHS */
+
+ if (lhs_bytes > 0 && rhs_bytes > 0
+ && lhs_bytes < rhs_bytes)
+ {
+ if (rhs_varying)
+ {
+ /* FIXME: generate runtime test for room */
+ ;
+ }
+ else
+ {
+ error ("can't do ARRAY assignment - too large");
+ return error_mark_node;
+ }
+ }
+ }
+
+ /* now we know the RHS will fit in LHS, build trees for the
+ emit_block_move parameters */
+
+ if (lhs_varying)
+ rhs = convert (TREE_TYPE (lhs), rhs);
+ else
+ {
+ if (rhs_varying)
+ rhs = build_component_ref (rhs, var_data_id);
+
+ if (! mark_addressable (rhs))
+ {
+ error ("rhs of array assignment is not addressable");
+ return error_mark_node;
+ }
+
+ lhs = force_addr_of (lhs);
+ rhs = build1 (ADDR_EXPR, const_ptr_type_node, rhs);
+ return
+ build_chill_function_call (lookup_name (get_identifier ("memmove")),
+ tree_cons (NULL_TREE, lhs,
+ tree_cons (NULL_TREE, rhs,
+ tree_cons (NULL_TREE, size_in_bytes (rhs_data_type),
+ NULL_TREE))));
+ }
+ }
+
+ result = build (MODIFY_EXPR, lhstype, lhs, rhs);
+ TREE_SIDE_EFFECTS (result) = 1;
+
+ return result;
+}
+
+/* Constructors for pointer, array and function types.
+ (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
+ constructed by language-dependent code, not here.) */
+
+/* Construct, lay out and return the type of pointers to TO_TYPE.
+ If such a type has already been constructed, reuse it. */
+
+tree
+make_chill_pointer_type (to_type, code)
+ tree to_type;
+ enum tree_code code; /* POINTER_TYPE or REFERENCE_TYPE */
+{
+ extern struct obstack *current_obstack;
+ extern struct obstack *saveable_obstack;
+ extern struct obstack permanent_obstack;
+ tree t;
+ register struct obstack *ambient_obstack = current_obstack;
+ register struct obstack *ambient_saveable_obstack = saveable_obstack;
+
+ /* If TO_TYPE is permanent, make this permanent too. */
+ if (TREE_PERMANENT (to_type))
+ {
+ current_obstack = &permanent_obstack;
+ saveable_obstack = &permanent_obstack;
+ }
+
+ t = make_node (code);
+ TREE_TYPE (t) = to_type;
+
+ current_obstack = ambient_obstack;
+ saveable_obstack = ambient_saveable_obstack;
+ return t;
+}
+
+
+tree
+build_chill_pointer_type (to_type)
+ tree to_type;
+{
+ int is_type_node = TREE_CODE_CLASS (TREE_CODE (to_type)) == 't';
+ register tree t = is_type_node ? TYPE_POINTER_TO (to_type) : NULL_TREE;
+
+ /* First, if we already have a type for pointers to TO_TYPE, use it. */
+
+ if (t)
+ return t;
+
+ /* We need a new one. */
+ t = make_chill_pointer_type (to_type, POINTER_TYPE);
+
+ /* Lay out the type. This function has many callers that are concerned
+ with expression-construction, and this simplifies them all.
+ Also, it guarantees the TYPE_SIZE is permanent if the type is. */
+ if ((is_type_node && (TYPE_SIZE (to_type) != NULL_TREE))
+ || pass == 2)
+ {
+ /* Record this type as the pointer to TO_TYPE. */
+ TYPE_POINTER_TO (to_type) = t;
+ layout_type (t);
+ }
+
+ return t;
+}
+
+tree
+build_chill_reference_type (to_type)
+ tree to_type;
+{
+ int is_type_node = TREE_CODE_CLASS (TREE_CODE (to_type)) == 't';
+ register tree t = is_type_node ? TYPE_REFERENCE_TO (to_type) : NULL_TREE;
+
+ /* First, if we already have a type for references to TO_TYPE, use it. */
+
+ if (t)
+ return t;
+
+ /* We need a new one. */
+ t = make_chill_pointer_type (to_type, REFERENCE_TYPE);
+
+ /* Lay out the type. This function has many callers that are concerned
+ with expression-construction, and this simplifies them all.
+ Also, it guarantees the TYPE_SIZE is permanent if the type is. */
+ if ((is_type_node && (TYPE_SIZE (to_type) != NULL_TREE))
+ || pass == 2)
+ {
+ /* Record this type as the reference to TO_TYPE. */
+ TYPE_REFERENCE_TO (to_type) = t;
+ layout_type (t);
+ CH_NOVELTY (t) = CH_NOVELTY (to_type);
+ }
+
+ return t;
+}
+
+tree
+make_chill_range_type (type, lowval, highval)
+ tree type, lowval, highval;
+{
+ register tree itype = make_node (INTEGER_TYPE);
+ TREE_TYPE (itype) = type;
+ TYPE_MIN_VALUE (itype) = lowval;
+ TYPE_MAX_VALUE (itype) = highval;
+ return itype;
+}
+
+tree
+layout_chill_range_type (rangetype, must_be_const)
+ tree rangetype;
+ int must_be_const;
+{
+ tree type = TREE_TYPE (rangetype);
+ tree lowval = TYPE_MIN_VALUE (rangetype);
+ tree highval = TYPE_MAX_VALUE (rangetype);
+ int bad_limits = 0;
+
+ if (TYPE_SIZE (rangetype) != NULL_TREE)
+ return rangetype;
+
+ /* process BIN */
+ if (type == ridpointers[(int) RID_BIN])
+ {
+ int binsize;
+
+ /* make a range out of it */
+ if (TREE_CODE (highval) != INTEGER_CST)
+ {
+ error ("non-constant expression for BIN");
+ return error_mark_node;
+ }
+ binsize = TREE_INT_CST_LOW (highval);
+ if (binsize < 0)
+ {
+ error ("expression for BIN must not be negative");
+ return error_mark_node;
+ }
+ if (binsize > 32)
+ {
+ error ("cannot process BIN (>32)");
+ return error_mark_node;
+ }
+ type = ridpointers [(int) RID_RANGE];
+ lowval = integer_zero_node;
+ highval = build_int_2 ((1 << binsize) - 1, 0);
+ }
+
+ if (TREE_CODE (lowval) == ERROR_MARK ||
+ TREE_CODE (highval) == ERROR_MARK)
+ return error_mark_node;
+
+ if (!CH_COMPATIBLE_CLASSES (lowval, highval))
+ {
+ error ("bounds of range are not compatible");
+ return error_mark_node;
+ }
+
+ if (type == string_index_type_dummy)
+ {
+ if (TREE_CODE (highval) == INTEGER_CST
+ && compare_int_csts (LT_EXPR, highval, integer_minus_one_node))
+ {
+ error ("negative string length");
+ highval = integer_minus_one_node;
+ }
+ if (compare_int_csts (EQ_EXPR, highval, integer_minus_one_node))
+ type = integer_type_node;
+ else
+ type = sizetype;
+ TREE_TYPE (rangetype) = type;
+ }
+ else if (type == ridpointers[(int) RID_RANGE])
+ {
+ /* This isn't 100% right, since the Blue Book definition
+ uses Resulting Class, rather than Resulting Mode,
+ but it's close enough. */
+ type = CH_ROOT_RESULTING_CLASS (lowval, highval).mode;
+
+ /* The default TYPE is the type of the constants -
+ except if the constants are integers, we choose an
+ integer type that fits. */
+ if (TREE_CODE (type) == INTEGER_TYPE
+ && TREE_CODE (lowval) == INTEGER_CST
+ && TREE_CODE (highval) == INTEGER_CST)
+ {
+ /* The logic of this code has been copied from finish_enum
+ in c-decl.c. FIXME duplication! */
+ int precision = 0;
+ HOST_WIDE_INT maxvalue = TREE_INT_CST_LOW (highval);
+ HOST_WIDE_INT minvalue = TREE_INT_CST_LOW (lowval);
+ if (TREE_INT_CST_HIGH (lowval) >= 0
+ ? tree_int_cst_lt (TYPE_MAX_VALUE (unsigned_type_node), highval)
+ : (tree_int_cst_lt (lowval, TYPE_MIN_VALUE (integer_type_node))
+ || tree_int_cst_lt (TYPE_MAX_VALUE (integer_type_node), highval)))
+ precision = TYPE_PRECISION (long_long_integer_type_node);
+ else
+ {
+ if (maxvalue > 0)
+ precision = floor_log2 (maxvalue) + 1;
+ if (minvalue < 0)
+ {
+ /* Compute number of bits to represent magnitude of a
+ negative value. Add one to MINVALUE since range of
+ negative numbers includes the power of two. */
+ unsigned negprecision = floor_log2 (-minvalue - 1) + 1;
+ if (negprecision > precision)
+ precision = negprecision;
+ precision += 1; /* room for sign bit */
+ }
+
+ if (!precision)
+ precision = 1;
+ }
+ type = type_for_size (precision, minvalue >= 0);
+
+ }
+ TREE_TYPE (rangetype) = type;
+ }
+ else
+ {
+ if (!CH_COMPATIBLE (lowval, type))
+ {
+ error ("range's lower bound and parent mode don't match");
+ return integer_type_node; /* an innocuous fake */
+ }
+ if (!CH_COMPATIBLE (highval, type))
+ {
+ error ("range's upper bound and parent mode don't match");
+ return integer_type_node; /* an innocuous fake */
+ }
+ }
+
+ if (TREE_CODE (type) == ERROR_MARK)
+ return type;
+ else if (TREE_CODE_CLASS (TREE_CODE (type)) != 't')
+ {
+ error ("making range from non-mode");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (lowval) == REAL_CST || TREE_CODE (highval) == REAL_CST)
+ {
+ sorry ("floating point ranges");
+ return integer_type_node; /* another fake */
+ }
+
+ if (TREE_CODE (lowval) != INTEGER_CST || TREE_CODE (highval) != INTEGER_CST)
+ {
+ if (must_be_const)
+ {
+ error ("range mode has non-constant limits");
+ bad_limits = 1;
+ }
+ }
+ else if (tree_int_cst_equal (lowval, integer_zero_node)
+ && tree_int_cst_equal (highval, integer_minus_one_node))
+ ; /* do nothing - this is the index type for an empty string */
+ else if (compare_int_csts (LT_EXPR, highval, TYPE_MIN_VALUE (type)))
+ {
+ error ("range's high bound < mode's low bound");
+ bad_limits = 1;
+ }
+ else if (compare_int_csts (GT_EXPR, highval, TYPE_MAX_VALUE (type)))
+ {
+ error ("range's high bound > mode's high bound");
+ bad_limits = 1;
+ }
+ else if (compare_int_csts (LT_EXPR, highval, lowval))
+ {
+ error ("range mode high bound < range mode low bound");
+ bad_limits = 1;
+ }
+ else if (compare_int_csts (LT_EXPR, lowval, TYPE_MIN_VALUE (type)))
+ {
+ error ("range's low bound < mode's low bound");
+ bad_limits = 1;
+ }
+ else if (compare_int_csts (GT_EXPR, lowval, TYPE_MAX_VALUE (type)))
+ {
+ error ("range's low bound > mode's high bound");
+ bad_limits = 1;
+ }
+
+ if (bad_limits)
+ {
+ lowval = TYPE_MIN_VALUE (type);
+ highval = lowval;
+ }
+
+ highval = convert (type, highval);
+ lowval = convert (type, lowval);
+ TYPE_MIN_VALUE (rangetype) = lowval;
+ TYPE_MAX_VALUE (rangetype) = highval;
+ TYPE_PRECISION (rangetype) = TYPE_PRECISION (type);
+ TYPE_MODE (rangetype) = TYPE_MODE (type);
+ TYPE_SIZE (rangetype) = TYPE_SIZE (type);
+ TYPE_ALIGN (rangetype) = TYPE_ALIGN (type);
+ TREE_UNSIGNED (rangetype) = TREE_UNSIGNED (type);
+ CH_NOVELTY (rangetype) = CH_NOVELTY (type);
+ return rangetype;
+}
+
+/* Build a _TYPE node that has range bounds associated with its values.
+ TYPE is the base type for the range type. */
+tree
+build_chill_range_type (type, lowval, highval)
+ tree type, lowval, highval;
+{
+ tree rangetype;
+
+ if (type == NULL_TREE)
+ type = ridpointers[(int) RID_RANGE];
+ else if (TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+
+ rangetype = make_chill_range_type (type, lowval, highval);
+ if (pass != 1)
+ rangetype = layout_chill_range_type (rangetype, 0);
+
+ return rangetype;
+}
+
+/* Build a CHILL array type, but with minimal checking etc. */
+
+tree
+build_simple_array_type (type, idx, layout)
+ tree type, idx, layout;
+{
+ tree array_type = make_node (ARRAY_TYPE);
+ TREE_TYPE (array_type) = type;
+ TYPE_DOMAIN (array_type) = idx;
+ TYPE_ATTRIBUTES (array_type) = layout;
+ if (pass != 1)
+ array_type = layout_chill_array_type (array_type);
+ return array_type;
+}
+
+static void
+apply_chill_array_layout (array_type)
+ tree array_type;
+{
+ tree layout, temp, what, element_type;
+ int stepsize, word, start_bit, offset, length, natural_length;
+ int stepsize_specified;
+ int start_bit_error = 0;
+ int length_error = 0;
+
+ layout = TYPE_ATTRIBUTES (array_type);
+ if (layout == NULL_TREE)
+ return;
+
+ if (layout == integer_zero_node) /* NOPACK */
+ {
+ TYPE_PACKED (array_type) = 0;
+ return;
+ }
+
+ /* Allow for the packing of 1 bit discrete modes at the bit level. */
+ element_type = TREE_TYPE (array_type);
+ if (discrete_type_p (element_type)
+ && get_type_precision (TYPE_MIN_VALUE (element_type),
+ TYPE_MAX_VALUE (element_type)) == 1)
+ natural_length = 1;
+ else
+ natural_length = TREE_INT_CST_LOW (TYPE_SIZE (element_type));
+
+ if (layout == integer_one_node) /* PACK */
+ {
+ if (natural_length == 1)
+ TYPE_PACKED (array_type) = 1;
+ return;
+ }
+
+ /* The layout is a STEP (...).
+ The current implementation restricts STEP specifications to be of the form
+ STEP(POS(0,0,n),n) where n is the natural size of the element mode. */
+ stepsize_specified = 0;
+ temp = TREE_VALUE (layout);
+ if (TREE_VALUE (temp) != NULL_TREE)
+ {
+ if (TREE_CODE (TREE_VALUE (temp)) != INTEGER_CST)
+ error ("Stepsize in STEP must be an integer constant");
+ else
+ {
+ stepsize = TREE_INT_CST_LOW (TREE_VALUE (temp));
+ if (stepsize <= 0)
+ error ("Stepsize in STEP must be > 0");
+ else
+ stepsize_specified = 1;
+
+ if (stepsize != natural_length)
+ sorry ("Stepsize in STEP must be the natural width of "
+ "the array element mode");
+ }
+ }
+
+ temp = TREE_PURPOSE (temp);
+ if (TREE_CODE (TREE_PURPOSE (temp)) != INTEGER_CST)
+ error ("Starting word in POS must be an integer constant");
+ else
+ {
+ word = TREE_INT_CST_LOW (TREE_PURPOSE (temp));
+ if (word < 0)
+ error ("Starting word in POS must be >= 0");
+ if (word != 0)
+ sorry ("Starting word in POS within STEP must be 0");
+ }
+
+ length = natural_length;
+ temp = TREE_VALUE (temp);
+ if (temp != NULL_TREE)
+ {
+ int wordsize = TYPE_PRECISION (chill_integer_type_node);
+ if (TREE_CODE (TREE_PURPOSE (temp)) != INTEGER_CST)
+ {
+ error ("Starting bit in POS must be an integer constant");
+ start_bit_error = 1;
+ }
+ else
+ {
+ start_bit = TREE_INT_CST_LOW (TREE_PURPOSE (temp));
+ if (start_bit != 0)
+ sorry ("Starting bit in POS within STEP must be 0");
+ if (start_bit < 0)
+ {
+ error ("Starting bit in POS must be >= 0");
+ start_bit = 0;
+ start_bit_error = 1;
+ }
+ else if (start_bit >= wordsize)
+ {
+ error ("Starting bit in POS must be < the width of a word");
+ start_bit = 0;
+ start_bit_error = 1;
+ }
+ }
+
+ temp = TREE_VALUE (temp);
+ if (temp != NULL_TREE)
+ {
+ what = TREE_PURPOSE (temp);
+ if (what == integer_zero_node)
+ {
+ if (TREE_CODE (TREE_VALUE (temp)) != INTEGER_CST)
+ {
+ error ("Length in POS must be an integer constant");
+ length_error = 1;
+ }
+ else
+ {
+ length = TREE_INT_CST_LOW (TREE_VALUE (temp));
+ if (length <= 0)
+ error ("Length in POS must be > 0");
+ }
+ }
+ else
+ {
+ if (TREE_CODE (TREE_VALUE (temp)) != INTEGER_CST)
+ {
+ error ("End bit in POS must be an integer constant");
+ length_error = 1;
+ }
+ else
+ {
+ int end_bit = TREE_INT_CST_LOW (TREE_VALUE (temp));
+ if (end_bit < start_bit)
+ {
+ error ("End bit in POS must be >= the start bit");
+ end_bit = wordsize - 1;
+ length_error = 1;
+ }
+ else if (end_bit >= wordsize)
+ {
+ error ("End bit in POS must be < the width of a word");
+ end_bit = wordsize - 1;
+ length_error = 1;
+ }
+ else if (start_bit_error)
+ length_error = 1;
+ else
+ length = end_bit - start_bit + 1;
+ }
+ }
+ if (! length_error && length != natural_length)
+ {
+ sorry ("The length specified on POS within STEP must be "
+ "the natural length of the array element type");
+ }
+ }
+ }
+
+ if (! length_error && stepsize_specified && stepsize < length)
+ error ("Step size in STEP must be >= the length in POS");
+
+ if (length == 1)
+ TYPE_PACKED (array_type) = 1;
+}
+
+tree
+layout_chill_array_type (array_type)
+ tree array_type;
+{
+ tree itype;
+ tree element_type = TREE_TYPE (array_type);
+
+ if (TREE_CODE (element_type) == ARRAY_TYPE
+ && TYPE_SIZE (element_type) == 0)
+ layout_chill_array_type (element_type);
+
+ itype = TYPE_DOMAIN (array_type);
+
+ if (TREE_CODE (itype) == ERROR_MARK
+ || TREE_CODE (element_type) == ERROR_MARK)
+ return error_mark_node;
+
+ /* do a lower/upper bound check. */
+ if (TREE_CODE (itype) == INTEGER_CST)
+ {
+ error ("array index must be a range, not a single integer");
+ return error_mark_node;
+ }
+ if (TREE_CODE_CLASS (TREE_CODE (itype)) != 't'
+ || !discrete_type_p (itype))
+ {
+ error ("array index is not a discrete mode");
+ return error_mark_node;
+ }
+
+ /* apply the array layout, if specified. */
+ apply_chill_array_layout (array_type);
+ TYPE_ATTRIBUTES (array_type) = NULL_TREE;
+
+ /* Make sure TYPE_POINTER_TO (element_type) is filled in. */
+ build_pointer_type (element_type);
+
+ if (TYPE_SIZE (array_type) == 0)
+ layout_type (array_type);
+
+ if (TYPE_READONLY_PROPERTY (element_type))
+ TYPE_FIELDS_READONLY (array_type) = 1;
+
+ TYPE_ARRAY_MAX_SIZE (array_type) = size_in_bytes (array_type);
+ return array_type;
+}
+
+/* Build a CHILL array type.
+
+ TYPE is the element type of the array.
+ IDXLIST is the list of dimensions of the array.
+ VARYING_P is non-zero if the array is a varying array.
+ LAYOUT is (NULL_TREE, integer_one_node, integer_zero_node, tree_list),
+ meaning (default, pack, nopack, STEP (...) ). */
+tree
+build_chill_array_type (type, idxlist, varying_p, layouts)
+ tree type, idxlist;
+ int varying_p;
+ tree layouts;
+{
+ tree array_type = type;
+
+ if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+ if (idxlist == NULL_TREE || TREE_CODE (idxlist) == ERROR_MARK)
+ return error_mark_node;
+
+ /* We have to walk down the list of index decls, building inner
+ array types as we go. We need to reverse the list of layouts so that the
+ first layout applies to the last index etc. */
+ layouts = nreverse (layouts);
+ for ( ; idxlist; idxlist = TREE_CHAIN (idxlist))
+ {
+ if (layouts != NULL_TREE)
+ {
+ type = build_simple_array_type (
+ type, TREE_VALUE (idxlist), TREE_VALUE (layouts));
+ layouts = TREE_CHAIN (layouts);
+ }
+ else
+ type = build_simple_array_type (type, TREE_VALUE (idxlist), NULL_TREE);
+ }
+ array_type = type;
+ if (varying_p)
+ array_type = build_varying_struct (array_type);
+ return array_type;
+}
+
+/* Function to help qsort sort FIELD_DECLs by name order. */
+
+static int
+field_decl_cmp (x, y)
+ tree *x, *y;
+{
+ return (long)DECL_NAME (*x) - (long)DECL_NAME (*y);
+}
+
+tree
+make_chill_struct_type (fieldlist)
+ tree fieldlist;
+{
+ tree t, x;
+ if (TREE_UNION_ELEM (fieldlist))
+ t = make_node (UNION_TYPE);
+ else
+ t = make_node (RECORD_TYPE);
+ /* Install struct as DECL_CONTEXT of each field decl. */
+ for (x = fieldlist; x; x = TREE_CHAIN (x))
+ {
+ DECL_CONTEXT (x) = t;
+ DECL_FIELD_SIZE (x) = 0;
+ }
+
+ /* Delete all duplicate fields from the fieldlist */
+ for (x = fieldlist; x && TREE_CHAIN (x);)
+ /* Anonymous fields aren't duplicates. */
+ if (DECL_NAME (TREE_CHAIN (x)) == 0)
+ x = TREE_CHAIN (x);
+ else
+ {
+ register tree y = fieldlist;
+
+ while (1)
+ {
+ if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x)))
+ break;
+ if (y == x)
+ break;
+ y = TREE_CHAIN (y);
+ }
+ if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x)))
+ {
+ error_with_decl (TREE_CHAIN (x), "duplicate member `%s'");
+ TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x));
+ }
+ else x = TREE_CHAIN (x);
+ }
+
+ TYPE_FIELDS (t) = fieldlist;
+
+ return t;
+}
+
+/* decl is a FIELD_DECL.
+ DECL_INIT (decl) is (NULL_TREE, integer_one_node, integer_zero_node, tree_list),
+ meaning (default, pack, nopack, POS (...) ).
+ The return value is a boolean: 1 if POS specified, 0 if not */
+static int
+apply_chill_field_layout (decl, next_struct_offset)
+ tree decl;
+ int* next_struct_offset;
+{
+ tree layout, type, temp, what;
+ int word, wordsize, start_bit, offset, length, natural_length;
+ int pos_error = 0;
+ int is_discrete;
+
+ type = TREE_TYPE (decl);
+ is_discrete = discrete_type_p (type);
+ if (is_discrete)
+ natural_length = get_type_precision (TYPE_MIN_VALUE (type), TYPE_MAX_VALUE (type));
+ else
+ natural_length = TREE_INT_CST_LOW (TYPE_SIZE (type));
+
+ layout = DECL_INITIAL (decl);
+ if (layout == integer_zero_node) /* NOPACK */
+ {
+ DECL_PACKED (decl) = 0;
+ *next_struct_offset += natural_length;
+ return 0; /* not POS */
+ }
+
+ if (layout == integer_one_node) /* PACK */
+ {
+ if (is_discrete)
+ DECL_BIT_FIELD (decl) = 1;
+ else
+ {
+ DECL_BIT_FIELD (decl) = 0;
+ DECL_ALIGN (decl) = BITS_PER_UNIT;
+ }
+ DECL_PACKED (decl) = 1;
+ DECL_FIELD_SIZE (decl) = natural_length;
+ *next_struct_offset += natural_length;
+ return 0; /* not POS */
+ }
+
+ /* The layout is a POS (...). The current implementation restricts the use
+ of POS to monotonically increasing fields whose width must be the
+ natural width of the underlying type. */
+ temp = TREE_PURPOSE (layout);
+
+ if (TREE_CODE (TREE_PURPOSE (temp)) != INTEGER_CST)
+ {
+ error ("Starting word in POS must be an integer constant");
+ pos_error = 1;
+ }
+ else
+ {
+ word = TREE_INT_CST_LOW (TREE_PURPOSE (temp));
+ if (word < 0)
+ {
+ error ("Starting word in POS must be >= 0");
+ word = 0;
+ pos_error = 1;
+ }
+ }
+
+ wordsize = TYPE_PRECISION (chill_integer_type_node);
+ offset = word * wordsize;
+ length = natural_length;
+
+ temp = TREE_VALUE (temp);
+ if (temp != NULL_TREE)
+ {
+ if (TREE_CODE (TREE_PURPOSE (temp)) != INTEGER_CST)
+ {
+ error ("Starting bit in POS must be an integer constant");
+ start_bit = *next_struct_offset - offset;
+ pos_error = 1;
+ }
+ else
+ {
+ start_bit = TREE_INT_CST_LOW (TREE_PURPOSE (temp));
+ if (start_bit < 0)
+ {
+ error ("Starting bit in POS must be >= 0");
+ start_bit = *next_struct_offset - offset;
+ pos_error = 1;
+ }
+ else if (start_bit >= wordsize)
+ {
+ error ("Starting bit in POS must be < the width of a word");
+ start_bit = *next_struct_offset - offset;
+ pos_error = 1;
+ }
+ }
+
+ temp = TREE_VALUE (temp);
+ if (temp != NULL_TREE)
+ {
+ what = TREE_PURPOSE (temp);
+ if (what == integer_zero_node)
+ {
+ if (TREE_CODE (TREE_VALUE (temp)) != INTEGER_CST)
+ {
+ error ("Length in POS must be an integer constant");
+ pos_error = 1;
+ }
+ else
+ {
+ length = TREE_INT_CST_LOW (TREE_VALUE (temp));
+ if (length <= 0)
+ {
+ error ("Length in POS must be > 0");
+ length = natural_length;
+ pos_error = 1;
+ }
+ }
+ }
+ else
+ {
+ if (TREE_CODE (TREE_VALUE (temp)) != INTEGER_CST)
+ {
+ error ("End bit in POS must be an integer constant");
+ pos_error = 1;
+ }
+ else
+ {
+ int end_bit = TREE_INT_CST_LOW (TREE_VALUE (temp));
+ if (end_bit < start_bit)
+ {
+ error ("End bit in POS must be >= the start bit");
+ pos_error = 1;
+ }
+ else if (end_bit >= wordsize)
+ {
+ error ("End bit in POS must be < the width of a word");
+ pos_error = 1;
+ }
+ else
+ length = end_bit - start_bit + 1;
+ }
+ }
+ if (length != natural_length && ! pos_error)
+ {
+ sorry ("The length specified on POS must be the natural length "
+ "of the field type");
+ length = natural_length;
+ }
+ }
+
+ offset += start_bit;
+ }
+
+ if (offset != *next_struct_offset && ! pos_error)
+ sorry ("STRUCT fields must be layed out in monotonically increasing order");
+
+ DECL_PACKED (decl) = 1;
+ DECL_BIT_FIELD (decl) = is_discrete;
+ DECL_FIELD_SIZE (decl) = length;
+ *next_struct_offset += natural_length;
+
+ return 1; /* was POS */
+}
+
+tree
+layout_chill_struct_type (t)
+ tree t;
+{
+ tree fieldlist = TYPE_FIELDS (t);
+ tree x;
+ int old_momentary;
+ int was_pos;
+ int pos_seen = 0;
+ int pos_error = 0;
+ int next_struct_offset;
+
+ old_momentary = suspend_momentary ();
+
+ /* Process specified field sizes.
+ Set DECL_FIELD_SIZE to the specified size, or 0 if none specified.
+ The specified size is found in the DECL_INITIAL.
+ Store 0 there, except for ": 0" fields (so we can find them
+ and delete them, below). */
+
+ next_struct_offset = 0;
+ for (x = fieldlist; x; x = TREE_CHAIN (x))
+ {
+ /* An EVENT or BUFFER mode is implemented as a RECORD_TYPE
+ which may contain a CONST_DECL for the maximum queue size. */
+ if (TREE_CODE (x) == CONST_DECL)
+ continue;
+
+ /* If any field is const, the structure type is pseudo-const. */
+ /* A field that is pseudo-const makes the structure likewise. */
+ if (TREE_READONLY (x) || TYPE_READONLY_PROPERTY (TREE_TYPE (x)))
+ TYPE_FIELDS_READONLY (t) = 1;
+
+ /* Any field that is volatile means variables of this type must be
+ treated in some ways as volatile. */
+ if (TREE_THIS_VOLATILE (x))
+ C_TYPE_FIELDS_VOLATILE (t) = 1;
+
+ if (DECL_INITIAL (x) != NULL_TREE)
+ {
+ was_pos = apply_chill_field_layout (x, &next_struct_offset);
+ DECL_INITIAL (x) = NULL_TREE;
+ }
+ else
+ {
+ int min_align = TYPE_ALIGN (TREE_TYPE (x));
+ DECL_ALIGN (x) = MAX (DECL_ALIGN (x), min_align);
+ was_pos = 0;
+ }
+ if ((! was_pos && pos_seen) || (was_pos && ! pos_seen && x != fieldlist))
+ pos_error = 1;
+ pos_seen |= was_pos;
+ }
+
+ if (pos_error)
+ error ("If one field has a POS layout, then all fields must have a POS layout");
+
+ /* Now DECL_INITIAL is null on all fields. */
+
+ layout_type (t);
+
+ /* Now we have the truly final field list.
+ Store it in this type and in the variants. */
+
+ TYPE_FIELDS (t) = fieldlist;
+
+ /* If there are lots of fields, sort so we can look through them fast.
+ We arbitrarily consider 16 or more elts to be "a lot". */
+ {
+ int len = 0;
+
+ for (x = fieldlist; x; x = TREE_CHAIN (x))
+ {
+ if (len > 15)
+ break;
+ len += 1;
+ }
+ if (len > 15)
+ {
+ tree *field_array;
+ char *space;
+
+ len += list_length (x);
+ /* Use the same allocation policy here that make_node uses, to
+ ensure that this lives as long as the rest of the struct decl.
+ All decls in an inline function need to be saved. */
+ if (allocation_temporary_p ())
+ space = savealloc (sizeof (struct lang_type) + len * sizeof (tree));
+ else
+ space = oballoc (sizeof (struct lang_type) + len * sizeof (tree));
+
+ TYPE_LANG_SPECIFIC (t) = (struct lang_type *) space;
+ TYPE_LANG_SPECIFIC (t)->foo.rec.len = len;
+
+ field_array = &TYPE_LANG_SPECIFIC (t)->foo.rec.elts[0];
+ len = 0;
+ for (x = fieldlist; x; x = TREE_CHAIN (x))
+ field_array[len++] = x;
+
+ qsort (field_array, len, sizeof (tree), field_decl_cmp);
+ }
+ }
+
+ for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
+ {
+ TYPE_FIELDS (x) = TYPE_FIELDS (t);
+ TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
+ TYPE_ALIGN (x) = TYPE_ALIGN (t);
+ }
+
+ resume_momentary (old_momentary);
+
+ return t;
+}
+
+/* Given a list of fields, FIELDLIST, return a structure
+ type that contains these fields. The returned type is
+ always a new type. */
+tree
+build_chill_struct_type (fieldlist)
+ tree fieldlist;
+{
+ register tree t;
+
+ if (fieldlist == NULL_TREE || TREE_CODE (fieldlist) == ERROR_MARK)
+ return error_mark_node;
+
+ t = make_chill_struct_type (fieldlist);
+ if (pass != 1)
+ t = layout_chill_struct_type (t);
+
+/* pushtag (NULL_TREE, t); */
+
+ return t;
+}
+
+/* Fix a LANG_TYPE. These are used for three different uses:
+ - representing a 'READ M' (in which case TYPE_READONLY is set);
+ - for a NEWMODE or SYNMODE (CH_NOVELTY is set for a NEWMODE); and
+ - for a parameterised type (TREE_TYPE points to base type,
+ while TYPE_DOMAIN is the parameter or parameter list).
+ Called from satisfy. */
+tree
+smash_dummy_type (type)
+ tree type;
+{
+ /* Save fields that we don't want to copy from ORIGIN. */
+ tree origin = TREE_TYPE (type);
+ tree main = TYPE_MAIN_VARIANT (origin);
+ int save_uid = TYPE_UID (type);
+ struct obstack *save_obstack = TYPE_OBSTACK (type);
+ tree save_name = TYPE_NAME (type);
+ int save_permanent = TREE_PERMANENT (type);
+ int save_readonly = TYPE_READONLY (type);
+ tree save_novelty = CH_NOVELTY (type);
+ tree save_domain = TYPE_DOMAIN (type);
+ struct lang_type *save_lang_specific = TYPE_LANG_SPECIFIC (type);
+
+ if (origin == NULL_TREE)
+ abort ();
+
+ if (save_domain)
+ {
+ if (TREE_CODE (save_domain) == ERROR_MARK)
+ return error_mark_node;
+ if (origin == char_type_node)
+ { /* Old-fashioned CHAR(N) declaration. */
+ origin = build_string_type (origin, save_domain);
+ }
+ else
+ { /* Handle parameterised modes. */
+ int is_varying = chill_varying_type_p (origin);
+ tree new_max = save_domain;
+ tree origin_novelty = CH_NOVELTY (origin);
+ if (is_varying)
+ origin = CH_VARYING_ARRAY_TYPE (origin);
+ if (CH_STRING_TYPE_P (origin))
+ {
+ tree oldindex = TYPE_DOMAIN (origin);
+ new_max = check_range (new_max, new_max, NULL_TREE,
+ size_binop (PLUS_EXPR,
+ TYPE_MAX_VALUE (oldindex),
+ integer_one_node));
+ origin = build_string_type (TREE_TYPE (origin), new_max);
+ }
+ else if (TREE_CODE (origin) == ARRAY_TYPE)
+ {
+ tree oldindex = TYPE_DOMAIN (origin);
+ tree upper = check_range (new_max, new_max, NULL_TREE,
+ TYPE_MAX_VALUE (oldindex));
+ tree newindex
+ = build_chill_range_type (TREE_TYPE (oldindex),
+ TYPE_MIN_VALUE (oldindex), upper);
+ origin = build_simple_array_type (TREE_TYPE (origin), newindex, NULL_TREE);
+ }
+ else if (TREE_CODE (origin) == RECORD_TYPE)
+ {
+ error ("parameterised structures not implemented");
+ return error_mark_node;
+ }
+ else
+ {
+ error ("invalid parameterised type");
+ return error_mark_node;
+ }
+
+ SET_CH_NOVELTY (origin, origin_novelty);
+ if (is_varying)
+ {
+ origin = build_varying_struct (origin);
+ SET_CH_NOVELTY (origin, origin_novelty);
+ }
+ }
+ save_domain = NULL_TREE;
+ }
+
+ if (TREE_CODE (origin) == ERROR_MARK)
+ return error_mark_node;
+
+ *(struct tree_type*)type = *(struct tree_type*)origin;
+ /* The following is so that the debug code for
+ the copy is different from the original type.
+ The two statements usually duplicate each other
+ (because they clear fields of the same union),
+ but the optimizer should catch that. */
+ TYPE_SYMTAB_POINTER (type) = 0;
+ TYPE_SYMTAB_ADDRESS (type) = 0;
+
+ /* Restore fields that we didn't want copied from ORIGIN. */
+ TYPE_UID (type) = save_uid;
+ TYPE_OBSTACK (type) = save_obstack;
+ TREE_PERMANENT (type) = save_permanent;
+ TYPE_NAME (type) = save_name;
+
+ TREE_CHAIN (type) = NULL_TREE;
+ TYPE_VOLATILE (type) = 0;
+ TYPE_POINTER_TO (type) = 0;
+ TYPE_REFERENCE_TO (type) = 0;
+
+ if (save_readonly)
+ { /* TYPE is READ ORIGIN.
+ Add this type to the chain of variants of TYPE. */
+ TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (main);
+ TYPE_NEXT_VARIANT (main) = type;
+ TYPE_READONLY (type) = save_readonly;
+ }
+ else
+ {
+ /* TYPE is the copy of the RHS in a NEWMODE or SYNMODE.
+ We also get here after old-fashioned CHAR(N) declaration (see above). */
+ TYPE_MAIN_VARIANT (type) = type;
+ TYPE_NEXT_VARIANT (type) = NULL_TREE;
+ if (save_name)
+ DECL_ORIGINAL_TYPE (save_name) = origin;
+
+ if (save_novelty != NULL_TREE) /* A NEWMODE declaration. */
+ {
+ CH_NOVELTY (type) = save_novelty;
+
+ /* Z.200: "If the DEFINING mode of the NEWMODE name is a range mode,
+ then the virtual mode &name is introduced as the PARENT mode
+ of the NEWMODE name. The DEFINING mode of &name is the PARENT
+ mode of the range mode, and the NOVELTY of &name is that of
+ the NEWMODE name." */
+
+ if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type))
+ {
+ tree parent;
+ /* PARENT is the virtual mode &name mentioned above. */
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ parent = copy_novelty (save_novelty,TREE_TYPE (type));
+ pop_obstacks ();
+
+ TREE_TYPE (type) = parent;
+ TYPE_MIN_VALUE (type) = convert (parent, TYPE_MIN_VALUE (type));
+ TYPE_MAX_VALUE (type) = convert (parent, TYPE_MAX_VALUE (type));
+ }
+ }
+ }
+ return type;
+}
+
+/* This generates a LANG_TYPE node that represents 'READ TYPE'. */
+
+tree
+build_readonly_type (type)
+ tree type;
+{
+ tree node = make_node (LANG_TYPE);
+ TREE_TYPE (node) = type;
+ TYPE_READONLY (node) = 1;
+ if (pass != 1)
+ node = smash_dummy_type (node);
+ return node;
+}
+
+
+/* Return an unsigned type the same as TYPE in other respects. */
+
+tree
+unsigned_type (type)
+ tree type;
+{
+ tree type1 = TYPE_MAIN_VARIANT (type);
+ if (type1 == signed_char_type_node || type1 == char_type_node)
+ return unsigned_char_type_node;
+ if (type1 == integer_type_node)
+ return unsigned_type_node;
+ if (type1 == short_integer_type_node)
+ return short_unsigned_type_node;
+ if (type1 == long_integer_type_node)
+ return long_unsigned_type_node;
+ if (type1 == long_long_integer_type_node)
+ return long_long_unsigned_type_node;
+
+ return signed_or_unsigned_type (1, type);
+}
+
+/* Return a signed type the same as TYPE in other respects. */
+
+tree
+signed_type (type)
+ tree type;
+{
+ tree type1 = TYPE_MAIN_VARIANT (type);
+ while (TREE_CODE (type1) == INTEGER_TYPE && TREE_TYPE (type1) != NULL_TREE)
+ type1 = TREE_TYPE (type1);
+ if (type1 == unsigned_char_type_node || type1 == char_type_node)
+ return signed_char_type_node;
+ if (type1 == unsigned_type_node)
+ return integer_type_node;
+ if (type1 == short_unsigned_type_node)
+ return short_integer_type_node;
+ if (type1 == long_unsigned_type_node)
+ return long_integer_type_node;
+ if (type1 == long_long_unsigned_type_node)
+ return long_long_integer_type_node;
+ if (TYPE_PRECISION (type1) == 1)
+ return signed_boolean_type_node;
+
+ return signed_or_unsigned_type (0, type);
+}
+
+/* Return a type the same as TYPE except unsigned or
+ signed according to UNSIGNEDP. */
+
+tree
+signed_or_unsigned_type (unsignedp, type)
+ int unsignedp;
+ tree type;
+{
+ if (! INTEGRAL_TYPE_P (type)
+ || TREE_UNSIGNED (type) == unsignedp)
+ return type;
+
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
+ return (unsignedp ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+ return type;
+}
+
+/* Mark EXP saying that we need to be able to take the
+ address of it; it should not be allocated in a register.
+ Value is 1 if successful. */
+
+int
+mark_addressable (exp)
+ tree exp;
+{
+ register tree x = exp;
+ while (1)
+ switch (TREE_CODE (x))
+ {
+ case ADDR_EXPR:
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ x = TREE_OPERAND (x, 0);
+ break;
+
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case COMPOUND_EXPR:
+ x = TREE_OPERAND (x, 1);
+ break;
+
+ case COND_EXPR:
+ return mark_addressable (TREE_OPERAND (x, 1))
+ & mark_addressable (TREE_OPERAND (x, 2));
+
+ case CONSTRUCTOR:
+ TREE_ADDRESSABLE (x) = 1;
+ return 1;
+
+ case INDIRECT_REF:
+ /* We sometimes add a cast *(TYPE*)&FOO to handle type and mode
+ incompatibility problems. Handle this case by marking FOO. */
+ if (TREE_CODE (TREE_OPERAND (x, 0)) == NOP_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (x, 0), 0)) == ADDR_EXPR)
+ {
+ x = TREE_OPERAND (TREE_OPERAND (x, 0), 0);
+ break;
+ }
+ if (TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR)
+ {
+ x = TREE_OPERAND (x, 0);
+ break;
+ }
+ return 1;
+
+ case VAR_DECL:
+ case CONST_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
+ && DECL_NONLOCAL (x))
+ {
+ if (TREE_PUBLIC (x))
+ {
+ error ("global register variable `%s' used in nested function",
+ IDENTIFIER_POINTER (DECL_NAME (x)));
+ return 0;
+ }
+ pedwarn ("register variable `%s' used in nested function",
+ IDENTIFIER_POINTER (DECL_NAME (x)));
+ }
+ else if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x))
+ {
+ if (TREE_PUBLIC (x))
+ {
+ error ("address of global register variable `%s' requested",
+ IDENTIFIER_POINTER (DECL_NAME (x)));
+ return 0;
+ }
+
+ /* If we are making this addressable due to its having
+ volatile components, give a different error message. Also
+ handle the case of an unnamed parameter by not trying
+ to give the name. */
+
+ else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x)))
+ {
+ error ("cannot put object with volatile field into register");
+ return 0;
+ }
+
+ pedwarn ("address of register variable `%s' requested",
+ IDENTIFIER_POINTER (DECL_NAME (x)));
+ }
+ put_var_into_stack (x);
+
+ /* drops through */
+ case FUNCTION_DECL:
+ TREE_ADDRESSABLE (x) = 1;
+#if 0 /* poplevel deals with this now. */
+ if (DECL_CONTEXT (x) == 0)
+ TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
+#endif
+ /* drops through */
+ default:
+ return 1;
+ }
+}
+
+/* Return nonzero if VALUE is a valid constant-valued expression
+ for use in initializing a static variable; one that can be an
+ element of a "constant" initializer.
+
+ Return null_pointer_node if the value is absolute;
+ if it is relocatable, return the variable that determines the relocation.
+ We assume that VALUE has been folded as much as possible;
+ therefore, we do not need to check for such things as
+ arithmetic-combinations of integers. */
+
+tree
+initializer_constant_valid_p (value, endtype)
+ tree value;
+ tree endtype;
+{
+ switch (TREE_CODE (value))
+ {
+ case CONSTRUCTOR:
+ if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
+ && TREE_CONSTANT (value))
+ return
+ initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
+ endtype);
+
+ return TREE_STATIC (value) ? null_pointer_node : 0;
+
+ case INTEGER_CST:
+ case REAL_CST:
+ case STRING_CST:
+ case COMPLEX_CST:
+ return null_pointer_node;
+
+ case ADDR_EXPR:
+ return TREE_OPERAND (value, 0);
+
+ case NON_LVALUE_EXPR:
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ /* Allow conversions between pointer types. */
+ if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE)
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ /* Allow conversions between real types. */
+ if (TREE_CODE (TREE_TYPE (value)) == REAL_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == REAL_TYPE)
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ /* Allow length-preserving conversions between integer types. */
+ if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ /* Allow conversions between other integer types only if
+ explicit value. */
+ if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE)
+ {
+ tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ if (inner == null_pointer_node)
+ return null_pointer_node;
+ return 0;
+ }
+
+ /* Allow (int) &foo provided int is as wide as a pointer. */
+ if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+
+ /* Likewise conversions from int to pointers. */
+ if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+
+ /* Allow conversions to union types if the value inside is okay. */
+ if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ return 0;
+
+ case PLUS_EXPR:
+ if (TREE_CODE (endtype) == INTEGER_TYPE
+ && TYPE_PRECISION (endtype) < POINTER_SIZE)
+ return 0;
+ {
+ tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+ endtype);
+ /* If either term is absolute, use the other terms relocation. */
+ if (valid0 == null_pointer_node)
+ return valid1;
+ if (valid1 == null_pointer_node)
+ return valid0;
+ return 0;
+ }
+
+ case MINUS_EXPR:
+ if (TREE_CODE (endtype) == INTEGER_TYPE
+ && TYPE_PRECISION (endtype) < POINTER_SIZE)
+ return 0;
+ {
+ tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+ endtype);
+ /* Win if second argument is absolute. */
+ if (valid1 == null_pointer_node)
+ return valid0;
+ /* Win if both arguments have the same relocation.
+ Then the value is absolute. */
+ if (valid0 == valid1)
+ return null_pointer_node;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Return an integer type with BITS bits of precision,
+ that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
+
+tree
+type_for_size (bits, unsignedp)
+ unsigned bits;
+ int unsignedp;
+{
+ if (bits == TYPE_PRECISION (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+
+ if (bits == TYPE_PRECISION (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+ if (bits == TYPE_PRECISION (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+ if (bits == TYPE_PRECISION (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+ if (bits == TYPE_PRECISION (long_long_integer_type_node))
+ return (unsignedp ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+
+ if (bits <= TYPE_PRECISION (intQI_type_node))
+ return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+
+ if (bits <= TYPE_PRECISION (intHI_type_node))
+ return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+
+ if (bits <= TYPE_PRECISION (intSI_type_node))
+ return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+
+ if (bits <= TYPE_PRECISION (intDI_type_node))
+ return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+
+ if (bits <= TYPE_PRECISION (intTI_type_node))
+ return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
+
+ return 0;
+}
+
+/* Return a data type that has machine mode MODE.
+ If the mode is an integer,
+ then UNSIGNEDP selects between signed and unsigned types. */
+
+tree
+type_for_mode (mode, unsignedp)
+ enum machine_mode mode;
+ int unsignedp;
+{
+ if (mode == TYPE_MODE (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+
+ if (mode == TYPE_MODE (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+ if (mode == TYPE_MODE (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+ if (mode == TYPE_MODE (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+ if (mode == TYPE_MODE (long_long_integer_type_node))
+ return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node;
+
+ if (mode == TYPE_MODE (intQI_type_node))
+ return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+
+ if (mode == TYPE_MODE (intHI_type_node))
+ return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+
+ if (mode == TYPE_MODE (intSI_type_node))
+ return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+
+ if (mode == TYPE_MODE (intDI_type_node))
+ return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+
+ if (mode == TYPE_MODE (intTI_type_node))
+ return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
+
+ if (mode == TYPE_MODE (float_type_node))
+ return float_type_node;
+
+ if (mode == TYPE_MODE (double_type_node))
+ return double_type_node;
+
+ if (mode == TYPE_MODE (long_double_type_node))
+ return long_double_type_node;
+
+ if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
+ return build_pointer_type (char_type_node);
+
+ if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
+ return build_pointer_type (integer_type_node);
+
+ return 0;
+}