aboutsummaryrefslogtreecommitdiff
path: root/gcc/f/data.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/f/data.c')
-rw-r--r--gcc/f/data.c1810
1 files changed, 1810 insertions, 0 deletions
diff --git a/gcc/f/data.c b/gcc/f/data.c
new file mode 100644
index 0000000..15bf3b0
--- /dev/null
+++ b/gcc/f/data.c
@@ -0,0 +1,1810 @@
+/* data.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.ai.mit.edu).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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 Fortran 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 Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+
+ Description:
+ Do the tough things for DATA statement (and INTEGER FOO/.../-style
+ initializations), like implied-DO and suchlike.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "data.h"
+#include "bit.h"
+#include "bld.h"
+#include "com.h"
+#include "expr.h"
+#include "global.h"
+#include "malloc.h"
+#include "st.h"
+#include "storag.h"
+#include "top.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+/* I picked this value as one that, when plugged into a couple of small
+ but nearly identical test cases I have called BIG-0.f and BIG-1.f,
+ causes BIG-1.f to take about 10 times as long (elapsed) to compile
+ (in f771 only) as BIG-0.f. These test cases differ in that BIG-0.f
+ doesn't put the one initialized variable in a common area that has
+ a large uninitialized array in it, while BIG-1.f does. The size of
+ the array is this many elements, as long as they all are INTEGER
+ type. Note that, as of 0.5.18, sparse cases are better handled,
+ so BIG-2.f now is used; it provides nonzero initial
+ values for all elements of the same array BIG-0 has. */
+#ifndef FFEDATA_sizeTOO_BIG_INIT_
+#define FFEDATA_sizeTOO_BIG_INIT_ 75*1024
+#endif
+
+/* Internal typedefs. */
+
+typedef struct _ffedata_convert_cache_ *ffedataConvertCache_;
+typedef struct _ffedata_impdo_ *ffedataImpdo_;
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+struct _ffedata_convert_cache_
+ {
+ ffebld converted; /* Results of converting expr to following
+ type. */
+ ffeinfoBasictype basic_type;
+ ffeinfoKindtype kind_type;
+ ffetargetCharacterSize size;
+ ffeinfoRank rank;
+ };
+
+struct _ffedata_impdo_
+ {
+ ffedataImpdo_ outer; /* Enclosing IMPDO construct. */
+ ffebld outer_list; /* Item after my IMPDO on the outer list. */
+ ffebld my_list; /* Beginning of list in my IMPDO. */
+ ffesymbol itervar; /* Iteration variable. */
+ ffetargetIntegerDefault increment;
+ ffetargetIntegerDefault final;
+ };
+
+/* Static objects accessed by functions in this module. */
+
+static ffedataImpdo_ ffedata_stack_ = NULL;
+static ffebld ffedata_list_ = NULL;
+static bool ffedata_reinit_; /* value_ should report REINIT error. */
+static bool ffedata_reported_error_; /* Error has been reported. */
+static ffesymbol ffedata_symbol_ = NULL; /* Symbol being initialized. */
+static ffeinfoBasictype ffedata_basictype_; /* Info on symbol. */
+static ffeinfoKindtype ffedata_kindtype_;
+static ffestorag ffedata_storage_; /* If non-NULL, inits go into this parent. */
+static ffeinfoBasictype ffedata_storage_bt_; /* Info on storage. */
+static ffeinfoKindtype ffedata_storage_kt_;
+static ffetargetOffset ffedata_storage_size_; /* Size of entire storage. */
+static ffetargetAlign ffedata_storage_units_; /* #units per storage unit. */
+static ffetargetOffset ffedata_arraysize_; /* Size of array being
+ inited. */
+static ffetargetOffset ffedata_expected_; /* Number of elements to
+ init. */
+static ffetargetOffset ffedata_number_; /* #elements inited so far. */
+static ffetargetOffset ffedata_offset_; /* Offset of next element. */
+static ffetargetOffset ffedata_symbolsize_; /* Size of entire sym. */
+static ffetargetCharacterSize ffedata_size_; /* Size of an element. */
+static ffetargetCharacterSize ffedata_charexpected_; /* #char to init. */
+static ffetargetCharacterSize ffedata_charnumber_; /* #chars inited. */
+static ffetargetCharacterSize ffedata_charoffset_; /* Offset of next char. */
+static ffedataConvertCache_ ffedata_convert_cache_; /* Fewer conversions. */
+static int ffedata_convert_cache_max_ = 0; /* #entries available. */
+static int ffedata_convert_cache_use_ = 0; /* #entries in use. */
+
+/* Static functions (internal). */
+
+static bool ffedata_advance_ (void);
+static ffebld ffedata_convert_ (ffebld source, ffelexToken source_token,
+ ffelexToken dest_token, ffeinfoBasictype bt, ffeinfoKindtype kt,
+ ffeinfoRank rk, ffetargetCharacterSize sz);
+static ffetargetInteger1 ffedata_eval_integer1_ (ffebld expr);
+static ffetargetOffset ffedata_eval_offset_ (ffebld subscripts,
+ ffebld dims);
+static ffetargetCharacterSize ffedata_eval_substr_begin_ (ffebld expr);
+static ffetargetCharacterSize ffedata_eval_substr_end_ (ffebld expr,
+ ffetargetCharacterSize min, ffetargetCharacterSize max);
+static void ffedata_gather_ (ffestorag mst, ffestorag st);
+static void ffedata_pop_ (void);
+static void ffedata_push_ (void);
+static bool ffedata_value_ (ffebld value, ffelexToken token);
+
+/* Internal macros. */
+
+
+/* ffedata_begin -- Initialize with list of targets
+
+ ffebld list;
+ ffedata_begin(list); // ITEM... list of SYMTERs, ARRAYs, SUBSTRs, ...
+
+ Remember the list. After this call, 0...n calls to ffedata_value must
+ follow, and then a single call to ffedata_end. */
+
+void
+ffedata_begin (ffebld list)
+{
+ assert (ffedata_list_ == NULL);
+ ffedata_list_ = list;
+ ffedata_symbol_ = NULL;
+ ffedata_reported_error_ = FALSE;
+ ffedata_reinit_ = FALSE;
+ ffedata_advance_ ();
+}
+
+/* ffedata_end -- End of initialization sequence
+
+ if (ffedata_end(FALSE))
+ // everything's ok
+
+ Make sure the end of the list is valid here. */
+
+bool
+ffedata_end (bool reported_error, ffelexToken t)
+{
+ reported_error |= ffedata_reported_error_;
+
+ /* If still targets to initialize, too few initializers, so complain. */
+
+ if ((ffedata_symbol_ != NULL) && !reported_error)
+ {
+ reported_error = TRUE;
+ ffebad_start (FFEBAD_DATA_TOOFEW);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ }
+
+ /* Pop off any impdo stacks (present only if ffedata_symbol_ != NULL). */
+
+ while (ffedata_stack_ != NULL)
+ ffedata_pop_ ();
+
+ if (ffedata_list_ != NULL)
+ {
+ assert (reported_error);
+ ffedata_list_ = NULL;
+ }
+
+ return TRUE;
+}
+
+/* ffedata_gather -- Gather previously disparate initializations into one place
+
+ ffestorag st; // A typeCBLOCK or typeLOCAL aggregate.
+ ffedata_gather(st);
+
+ Prior to this call, st has no init or accretion info, but (presumably
+ at least one of) its subordinate storage areas has init or accretion
+ info. After this call, none of the subordinate storage areas has inits,
+ because they've all been moved into the newly created init/accretion
+ info for st. During this call, conflicting inits produce only one
+ error message. */
+
+void
+ffedata_gather (ffestorag st)
+{
+ ffesymbol s;
+ ffebld b;
+
+ /* Prepare info on the storage area we're putting init info into. */
+
+ ffetarget_aggregate_info (&ffedata_storage_bt_, &ffedata_storage_kt_,
+ &ffedata_storage_units_, ffestorag_basictype (st),
+ ffestorag_kindtype (st));
+ ffedata_storage_size_ = ffestorag_size (st) / ffedata_storage_units_;
+ assert (ffestorag_size (st) % ffedata_storage_units_ == 0);
+
+ /* If a CBLOCK, gather all the init info for its explicit members. */
+
+ if ((ffestorag_type (st) == FFESTORAG_typeCBLOCK)
+ && (ffestorag_symbol (st) != NULL))
+ {
+ s = ffestorag_symbol (st);
+ for (b = ffesymbol_commonlist (s); b != NULL; b = ffebld_trail (b))
+ ffedata_gather_ (st,
+ ffesymbol_storage (ffebld_symter (ffebld_head (b))));
+ }
+
+ /* For CBLOCK or LOCAL, gather all the init info for equivalenced members. */
+
+ ffestorag_drive (ffestorag_list_equivs (st), ffedata_gather_, st);
+}
+
+/* ffedata_value -- Provide some number of initial values
+
+ ffebld value;
+ ffelexToken t; // Points to the value.
+ if (ffedata_value(1,value,t))
+ // Everything's ok
+
+ Makes sure the value is ok, then remembers it according to the list
+ provided to ffedata_begin. As many instances of the value may be
+ supplied as desired, as indicated by the first argument. */
+
+bool
+ffedata_value (ffetargetIntegerDefault rpt, ffebld value, ffelexToken token)
+{
+ ffetargetIntegerDefault i;
+
+ /* Maybe ignore zero values, to speed up compiling, even though we lose
+ checking for multiple initializations for now. */
+
+ if (!ffe_is_zeros ()
+ && (value != NULL)
+ && (ffebld_op (value) == FFEBLD_opCONTER)
+ && ffebld_constant_is_zero (ffebld_conter (value)))
+ value = NULL;
+ else if ((value != NULL)
+ && (ffebld_op (value) == FFEBLD_opANY))
+ value = NULL;
+ else
+ {
+ /* Must be a constant. */
+ assert (value != NULL);
+ assert (ffebld_op (value) == FFEBLD_opCONTER);
+ }
+
+ /* Later we can optimize certain cases by seeing that the target array can
+ take some number of values, and provide this number to _value_. */
+
+ if (rpt == 1)
+ ffedata_convert_cache_use_ = -1; /* Don't bother caching. */
+ else
+ ffedata_convert_cache_use_ = 0; /* Maybe use the cache. */
+
+ for (i = 0; i < rpt; ++i)
+ {
+ if ((ffedata_symbol_ != NULL)
+ && !ffesymbol_is_init (ffedata_symbol_))
+ {
+ ffesymbol_signal_change (ffedata_symbol_);
+ ffesymbol_update_init (ffedata_symbol_);
+ if (1 || ffe_is_90 ())
+ ffesymbol_update_save (ffedata_symbol_);
+#if FFEGLOBAL_ENABLED
+ if (ffesymbol_common (ffedata_symbol_) != NULL)
+ ffeglobal_init_common (ffesymbol_common (ffedata_symbol_),
+ token);
+#endif
+ ffesymbol_signal_unreported (ffedata_symbol_);
+ }
+ if (!ffedata_value_ (value, token))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* ffedata_advance_ -- Advance initialization target to next item in list
+
+ if (ffedata_advance_())
+ // everything's ok
+
+ Sets common info to characterize the next item in the list. Handles
+ IMPDO constructs accordingly. Does not handle advances within a single
+ item, as in the common extension "DATA CHARTYPE/33,34,35/", where
+ CHARTYPE is CHARACTER*3, for example. */
+
+static bool
+ffedata_advance_ ()
+{
+ ffebld next;
+
+ /* Come here after handling an IMPDO. */
+
+tail_recurse: /* :::::::::::::::::::: */
+
+ /* Assume we're not going to find a new target for now. */
+
+ ffedata_symbol_ = NULL;
+
+ /* If at the end of the list, we're done. */
+
+ if (ffedata_list_ == NULL)
+ {
+ ffetargetIntegerDefault newval;
+
+ if (ffedata_stack_ == NULL)
+ return TRUE; /* No IMPDO in progress, we is done! */
+
+ /* Iterate the IMPDO. */
+
+ newval = ffesymbol_value (ffedata_stack_->itervar)
+ + ffedata_stack_->increment;
+
+ /* See if we're still in the loop. */
+
+ if (((ffedata_stack_->increment > 0)
+ ? newval > ffedata_stack_->final
+ : newval < ffedata_stack_->final)
+ || (((ffesymbol_value (ffedata_stack_->itervar) < 0)
+ == (ffedata_stack_->increment < 0))
+ && ((ffesymbol_value (ffedata_stack_->itervar) < 0)
+ != (newval < 0)))) /* Overflow/underflow? */
+ { /* Done with the loop. */
+ ffedata_list_ = ffedata_stack_->outer_list; /* Restore list. */
+ ffedata_pop_ (); /* Pop me off the impdo stack. */
+ }
+ else
+ { /* Still in the loop, reset the list and
+ update the iter var. */
+ ffedata_list_ = ffedata_stack_->my_list; /* Reset list. */
+ ffesymbol_set_value (ffedata_stack_->itervar, newval);
+ }
+ goto tail_recurse; /* :::::::::::::::::::: */
+ }
+
+ /* Move to the next item in the list. */
+
+ next = ffebld_head (ffedata_list_);
+ ffedata_list_ = ffebld_trail (ffedata_list_);
+
+ /* Really shouldn't happen. */
+
+ if (next == NULL)
+ return TRUE;
+
+ /* See what kind of target this is. */
+
+ switch (ffebld_op (next))
+ {
+ case FFEBLD_opSYMTER: /* Simple reference to scalar or array. */
+ ffedata_symbol_ = ffebld_symter (next);
+ ffedata_storage_ = (ffesymbol_storage (ffedata_symbol_) == NULL) ? NULL
+ : ffestorag_parent (ffesymbol_storage (ffedata_symbol_));
+ if (ffedata_storage_ != NULL)
+ {
+ ffetarget_aggregate_info (&ffedata_storage_bt_, &ffedata_storage_kt_,
+ &ffedata_storage_units_,
+ ffestorag_basictype (ffedata_storage_),
+ ffestorag_kindtype (ffedata_storage_));
+ ffedata_storage_size_ = ffestorag_size (ffedata_storage_)
+ / ffedata_storage_units_;
+ assert (ffestorag_size (ffedata_storage_) % ffedata_storage_units_ == 0);
+ }
+
+ if ((ffesymbol_init (ffedata_symbol_) != NULL)
+ || (ffesymbol_accretion (ffedata_symbol_) != NULL)
+ || ((ffedata_storage_ != NULL)
+ && (ffestorag_init (ffedata_storage_) != NULL)))
+ {
+#if 0
+ ffebad_start (FFEBAD_DATA_REINIT);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+#else
+ ffedata_reinit_ = TRUE;
+ return TRUE;
+#endif
+ }
+ ffedata_basictype_ = ffesymbol_basictype (ffedata_symbol_);
+ ffedata_kindtype_ = ffesymbol_kindtype (ffedata_symbol_);
+ if (ffesymbol_rank (ffedata_symbol_) == 0)
+ ffedata_arraysize_ = 1;
+ else
+ {
+ ffebld size = ffesymbol_arraysize (ffedata_symbol_);
+
+ assert (size != NULL);
+ assert (ffebld_op (size) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (size))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (size))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_arraysize_ = ffebld_constant_integerdefault (ffebld_conter
+ (size));
+ }
+ ffedata_expected_ = ffedata_arraysize_;
+ ffedata_number_ = 0;
+ ffedata_offset_ = 0;
+ ffedata_size_ = (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? ffesymbol_size (ffedata_symbol_) : 1;
+ ffedata_symbolsize_ = ffedata_size_ * ffedata_arraysize_;
+ ffedata_charexpected_ = ffedata_size_;
+ ffedata_charnumber_ = 0;
+ ffedata_charoffset_ = 0;
+ break;
+
+ case FFEBLD_opARRAYREF: /* Reference to element of array. */
+ ffedata_symbol_ = ffebld_symter (ffebld_left (next));
+ ffedata_storage_ = (ffesymbol_storage (ffedata_symbol_) == NULL) ? NULL
+ : ffestorag_parent (ffesymbol_storage (ffedata_symbol_));
+ if (ffedata_storage_ != NULL)
+ {
+ ffetarget_aggregate_info (&ffedata_storage_bt_, &ffedata_storage_kt_,
+ &ffedata_storage_units_,
+ ffestorag_basictype (ffedata_storage_),
+ ffestorag_kindtype (ffedata_storage_));
+ ffedata_storage_size_ = ffestorag_size (ffedata_storage_)
+ / ffedata_storage_units_;
+ assert (ffestorag_size (ffedata_storage_) % ffedata_storage_units_ == 0);
+ }
+
+ if ((ffesymbol_init (ffedata_symbol_) != NULL)
+ || ((ffedata_storage_ != NULL)
+ && (ffestorag_init (ffedata_storage_) != NULL)))
+ {
+#if 0
+ ffebad_start (FFEBAD_DATA_REINIT);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+#else
+ ffedata_reinit_ = TRUE;
+ return TRUE;
+#endif
+ }
+ ffedata_basictype_ = ffesymbol_basictype (ffedata_symbol_);
+ ffedata_kindtype_ = ffesymbol_kindtype (ffedata_symbol_);
+ if (ffesymbol_rank (ffedata_symbol_) == 0)
+ ffedata_arraysize_ = 1; /* Shouldn't happen in this case... */
+ else
+ {
+ ffebld size = ffesymbol_arraysize (ffedata_symbol_);
+
+ assert (size != NULL);
+ assert (ffebld_op (size) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (size))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (size))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_arraysize_ = ffebld_constant_integerdefault (ffebld_conter
+ (size));
+ }
+ ffedata_expected_ = 1;
+ ffedata_number_ = 0;
+ ffedata_offset_ = ffedata_eval_offset_ (ffebld_right (next),
+ ffesymbol_dims (ffedata_symbol_));
+ ffedata_size_ = (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? ffesymbol_size (ffedata_symbol_) : 1;
+ ffedata_symbolsize_ = ffedata_size_ * ffedata_arraysize_;
+ ffedata_charexpected_ = ffedata_size_;
+ ffedata_charnumber_ = 0;
+ ffedata_charoffset_ = 0;
+ break;
+
+ case FFEBLD_opSUBSTR: /* Substring reference to scalar or array
+ element. */
+ {
+ bool arrayref = ffebld_op (ffebld_left (next)) == FFEBLD_opARRAYREF;
+ ffebld colon = ffebld_right (next);
+
+ assert (colon != NULL);
+
+ ffedata_symbol_ = ffebld_symter (ffebld_left (arrayref
+ ? ffebld_left (next) : next));
+ ffedata_storage_ = (ffesymbol_storage (ffedata_symbol_) == NULL) ? NULL
+ : ffestorag_parent (ffesymbol_storage (ffedata_symbol_));
+ if (ffedata_storage_ != NULL)
+ {
+ ffetarget_aggregate_info (&ffedata_storage_bt_, &ffedata_storage_kt_,
+ &ffedata_storage_units_,
+ ffestorag_basictype (ffedata_storage_),
+ ffestorag_kindtype (ffedata_storage_));
+ ffedata_storage_size_ = ffestorag_size (ffedata_storage_)
+ / ffedata_storage_units_;
+ assert (ffestorag_size (ffedata_storage_) % ffedata_storage_units_ == 0);
+ }
+
+ if ((ffesymbol_init (ffedata_symbol_) != NULL)
+ || ((ffedata_storage_ != NULL)
+ && (ffestorag_init (ffedata_storage_) != NULL)))
+ {
+#if 0
+ ffebad_start (FFEBAD_DATA_REINIT);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+#else
+ ffedata_reinit_ = TRUE;
+ return TRUE;
+#endif
+ }
+ ffedata_basictype_ = ffesymbol_basictype (ffedata_symbol_);
+ ffedata_kindtype_ = ffesymbol_kindtype (ffedata_symbol_);
+ if (ffesymbol_rank (ffedata_symbol_) == 0)
+ ffedata_arraysize_ = 1;
+ else
+ {
+ ffebld size = ffesymbol_arraysize (ffedata_symbol_);
+
+ assert (size != NULL);
+ assert (ffebld_op (size) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (size))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (size))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_arraysize_ = ffebld_constant_integerdefault (ffebld_conter
+ (size));
+ }
+ ffedata_expected_ = arrayref ? 1 : ffedata_arraysize_;
+ ffedata_number_ = 0;
+ ffedata_offset_ = arrayref ? ffedata_eval_offset_ (ffebld_right
+ (ffebld_left (next)), ffesymbol_dims (ffedata_symbol_)) : 0;
+ ffedata_size_ = ffesymbol_size (ffedata_symbol_);
+ ffedata_symbolsize_ = ffedata_size_ * ffedata_arraysize_;
+ ffedata_charnumber_ = 0;
+ ffedata_charoffset_ = ffedata_eval_substr_begin_ (ffebld_head (colon));
+ ffedata_charexpected_ = ffedata_eval_substr_end_ (ffebld_head
+ (ffebld_trail (colon)), ffedata_charoffset_,
+ ffedata_size_) - ffedata_charoffset_ + 1;
+ }
+ break;
+
+ case FFEBLD_opIMPDO: /* Implied-DO construct. */
+ {
+ ffebld itervar;
+ ffebld start;
+ ffebld end;
+ ffebld incr;
+ ffebld item = ffebld_right (next);
+
+ itervar = ffebld_head (item);
+ item = ffebld_trail (item);
+ start = ffebld_head (item);
+ item = ffebld_trail (item);
+ end = ffebld_head (item);
+ item = ffebld_trail (item);
+ incr = ffebld_head (item);
+
+ ffedata_push_ ();
+ ffedata_stack_->outer_list = ffedata_list_;
+ ffedata_stack_->my_list = ffedata_list_ = ffebld_left (next);
+
+ assert (ffeinfo_basictype (ffebld_info (itervar))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (itervar))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_stack_->itervar = ffebld_symter (itervar);
+
+ assert (ffeinfo_basictype (ffebld_info (start))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (start))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffesymbol_set_value (ffedata_stack_->itervar, ffedata_eval_integer1_ (start));
+
+ assert (ffeinfo_basictype (ffebld_info (end))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (end))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_stack_->final = ffedata_eval_integer1_ (end);
+
+ if (incr == NULL)
+ ffedata_stack_->increment = 1;
+ else
+ {
+ assert (ffeinfo_basictype (ffebld_info (incr))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (incr))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_stack_->increment = ffedata_eval_integer1_ (incr);
+ if (ffedata_stack_->increment == 0)
+ {
+ ffebad_start (FFEBAD_DATA_ZERO);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_stack_->itervar));
+ ffebad_finish ();
+ ffedata_pop_ ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+ }
+
+ if ((ffedata_stack_->increment > 0)
+ ? ffesymbol_value (ffedata_stack_->itervar)
+ > ffedata_stack_->final
+ : ffesymbol_value (ffedata_stack_->itervar)
+ < ffedata_stack_->final)
+ {
+ ffedata_reported_error_ = TRUE;
+ ffebad_start (FFEBAD_DATA_EMPTY);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_stack_->itervar));
+ ffebad_finish ();
+ ffedata_pop_ ();
+ return FALSE;
+ }
+ }
+ goto tail_recurse; /* :::::::::::::::::::: */
+
+ case FFEBLD_opANY:
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+
+ default:
+ assert ("bad op" == NULL);
+ break;
+ }
+
+ return TRUE;
+}
+
+/* ffedata_convert_ -- Convert source expression to given type using cache
+
+ ffebld source;
+ ffelexToken source_token;
+ ffelexToken dest_token; // Any appropriate token for "destination".
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetCharactersize sz;
+ source = ffedata_convert_(source,source_token,dest_token,bt,kt,sz);
+
+ Like ffeexpr_convert, but calls it only if necessary (if the converted
+ expression doesn't already exist in the cache) and then puts the result
+ in the cache. */
+
+ffebld
+ffedata_convert_ (ffebld source, ffelexToken source_token,
+ ffelexToken dest_token, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffeinfoRank rk,
+ ffetargetCharacterSize sz)
+{
+ ffebld converted;
+ int i;
+ int max;
+ ffedataConvertCache_ cache;
+
+ for (i = 0; i < ffedata_convert_cache_use_; ++i)
+ if ((bt == ffedata_convert_cache_[i].basic_type)
+ && (kt == ffedata_convert_cache_[i].kind_type)
+ && (sz == ffedata_convert_cache_[i].size)
+ && (rk == ffedata_convert_cache_[i].rank))
+ return ffedata_convert_cache_[i].converted;
+
+ converted = ffeexpr_convert (source, source_token, dest_token, bt, kt, rk,
+ sz, FFEEXPR_contextDATA);
+
+ if (ffedata_convert_cache_use_ >= ffedata_convert_cache_max_)
+ {
+ if (ffedata_convert_cache_max_ == 0)
+ max = 4;
+ else
+ max = ffedata_convert_cache_max_ << 1;
+
+ if (max > ffedata_convert_cache_max_)
+ {
+ cache = (ffedataConvertCache_) malloc_new_ks (malloc_pool_image (),
+ "FFEDATA cache", max * sizeof (*cache));
+ if (ffedata_convert_cache_max_ != 0)
+ {
+ memcpy (cache, ffedata_convert_cache_,
+ ffedata_convert_cache_max_ * sizeof (*cache));
+ malloc_kill_ks (malloc_pool_image (), ffedata_convert_cache_,
+ ffedata_convert_cache_max_ * sizeof (*cache));
+ }
+ ffedata_convert_cache_ = cache;
+ ffedata_convert_cache_max_ = max;
+ }
+ else
+ return converted; /* In case int overflows! */
+ }
+
+ i = ffedata_convert_cache_use_++;
+
+ ffedata_convert_cache_[i].converted = converted;
+ ffedata_convert_cache_[i].basic_type = bt;
+ ffedata_convert_cache_[i].kind_type = kt;
+ ffedata_convert_cache_[i].size = sz;
+ ffedata_convert_cache_[i].rank = rk;
+
+ return converted;
+}
+
+/* ffedata_eval_integer1_ -- Evaluate expression
+
+ ffetargetIntegerDefault result;
+ ffebld expr; // must be kindtypeINTEGER1.
+
+ result = ffedata_eval_integer1_(expr);
+
+ Evalues the expression (which yields a kindtypeINTEGER1 result) and
+ returns the result. */
+
+static ffetargetIntegerDefault
+ffedata_eval_integer1_ (ffebld expr)
+{
+ ffetargetInteger1 result;
+ ffebad error;
+
+ assert (expr != NULL);
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opCONTER:
+ return ffebld_constant_integer1 (ffebld_conter (expr));
+
+ case FFEBLD_opSYMTER:
+ return ffesymbol_value (ffebld_symter (expr));
+
+ case FFEBLD_opUPLUS:
+ return ffedata_eval_integer1_ (ffebld_left (expr));
+
+ case FFEBLD_opUMINUS:
+ error = ffetarget_uminus_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)));
+ break;
+
+ case FFEBLD_opADD:
+ error = ffetarget_add_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opSUBTRACT:
+ error = ffetarget_subtract_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opMULTIPLY:
+ error = ffetarget_multiply_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opDIVIDE:
+ error = ffetarget_divide_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opPOWER:
+ {
+ ffebld r = ffebld_right (expr);
+
+ if ((ffeinfo_basictype (ffebld_info (r)) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (ffebld_info (r)) != FFEINFO_kindtypeINTEGERDEFAULT))
+ error = FFEBAD_DATA_EVAL;
+ else
+ error = ffetarget_power_integerdefault_integerdefault (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (r));
+ }
+ break;
+
+#if 0 /* Only for character basictype. */
+ case FFEBLD_opCONCATENATE:
+ error =;
+ break;
+#endif
+
+ case FFEBLD_opNOT:
+ error = ffetarget_not_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)));
+ break;
+
+#if 0 /* Only for logical basictype. */
+ case FFEBLD_opLT:
+ error =;
+ break;
+
+ case FFEBLD_opLE:
+ error =;
+ break;
+
+ case FFEBLD_opEQ:
+ error =;
+ break;
+
+ case FFEBLD_opNE:
+ error =;
+ break;
+
+ case FFEBLD_opGT:
+ error =;
+ break;
+
+ case FFEBLD_opGE:
+ error =;
+ break;
+#endif
+
+ case FFEBLD_opAND:
+ error = ffetarget_and_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opOR:
+ error = ffetarget_or_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opXOR:
+ error = ffetarget_xor_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opEQV:
+ error = ffetarget_eqv_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opNEQV:
+ error = ffetarget_neqv_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opPAREN:
+ return ffedata_eval_integer1_ (ffebld_left (expr));
+
+#if 0 /* ~~ no idea how to do this */
+ case FFEBLD_opPERCENT_LOC:
+ error =;
+ break;
+#endif
+
+#if 0 /* not allowed by ANSI, but perhaps as an
+ extension someday? */
+ case FFEBLD_opCONVERT:
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+ default:
+ error = FFEBAD_DATA_EVAL;
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+ default:
+ error = FFEBAD_DATA_EVAL;
+ break;
+ }
+ break;
+ }
+ break;
+#endif
+
+#if 0 /* not valid ops */
+ case FFEBLD_opREPEAT:
+ error =;
+ break;
+
+ case FFEBLD_opBOUNDS:
+ error =;
+ break;
+#endif
+
+#if 0 /* not allowed by ANSI, but perhaps as an
+ extension someday? */
+ case FFEBLD_opFUNCREF:
+ error =;
+ break;
+#endif
+
+#if 0 /* not valid ops */
+ case FFEBLD_opSUBRREF:
+ error =;
+ break;
+
+ case FFEBLD_opARRAYREF:
+ error =;
+ break;
+#endif
+
+#if 0 /* not valid for integer1 */
+ case FFEBLD_opSUBSTR:
+ error =;
+ break;
+#endif
+
+ default:
+ error = FFEBAD_DATA_EVAL;
+ break;
+ }
+
+ if (error != FFEBAD)
+ {
+ ffebad_start (error);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_finish ();
+ result = 0;
+ }
+
+ return result;
+}
+
+/* ffedata_eval_offset_ -- Evaluate offset info array
+
+ ffetargetOffset offset; // 0...max-1.
+ ffebld subscripts; // an opITEM list of subscript exprs.
+ ffebld dims; // an opITEM list of opBOUNDS exprs.
+
+ result = ffedata_eval_offset_(expr);
+
+ Evalues the expression (which yields a kindtypeINTEGER1 result) and
+ returns the result. */
+
+static ffetargetOffset
+ffedata_eval_offset_ (ffebld subscripts, ffebld dims)
+{
+ ffetargetIntegerDefault offset = 0;
+ ffetargetIntegerDefault width = 1;
+ ffetargetIntegerDefault value;
+ ffetargetIntegerDefault lowbound;
+ ffetargetIntegerDefault highbound;
+ ffetargetOffset final;
+ ffebld subscript;
+ ffebld dim;
+ ffebld low;
+ ffebld high;
+ int rank = 0;
+ bool ok;
+
+ while (subscripts != NULL)
+ {
+ ++rank;
+ assert (dims != NULL);
+
+ subscript = ffebld_head (subscripts);
+ dim = ffebld_head (dims);
+
+ assert (ffeinfo_basictype (ffebld_info (subscript)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (subscript)) == FFEINFO_kindtypeINTEGER1);
+ value = ffedata_eval_integer1_ (subscript);
+
+ assert (ffebld_op (dim) == FFEBLD_opBOUNDS);
+ low = ffebld_left (dim);
+ high = ffebld_right (dim);
+
+ if (low == NULL)
+ lowbound = 1;
+ else
+ {
+ assert (ffeinfo_basictype (ffebld_info (low)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (low)) == FFEINFO_kindtypeINTEGERDEFAULT);
+ lowbound = ffedata_eval_integer1_ (low);
+ }
+
+ assert (ffeinfo_basictype (ffebld_info (high)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (high)) == FFEINFO_kindtypeINTEGERDEFAULT);
+ highbound = ffedata_eval_integer1_ (high);
+
+ if ((value < lowbound) || (value > highbound))
+ {
+ char rankstr[10];
+
+ sprintf (rankstr, "%d", rank);
+ value = lowbound;
+ ffebad_start (FFEBAD_DATA_SUBSCRIPT);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_string (rankstr);
+ ffebad_finish ();
+ }
+
+ subscripts = ffebld_trail (subscripts);
+ dims = ffebld_trail (dims);
+
+ offset += width * (value - lowbound);
+ if (subscripts != NULL)
+ width *= highbound - lowbound + 1;
+ }
+
+ assert (dims == NULL);
+
+ ok = ffetarget_offset (&final, offset);
+ assert (ok);
+
+ return final;
+}
+
+/* ffedata_eval_substr_begin_ -- Evaluate begin-point of substr reference
+
+ ffetargetCharacterSize beginpoint;
+ ffebld endval; // head(colon).
+
+ beginpoint = ffedata_eval_substr_end_(endval);
+
+ If beginval is NULL, returns 0. Otherwise makes sure beginval is
+ kindtypeINTEGERDEFAULT, makes sure its value is > 0,
+ and returns its value minus one, or issues an error message. */
+
+static ffetargetCharacterSize
+ffedata_eval_substr_begin_ (ffebld expr)
+{
+ ffetargetIntegerDefault val;
+
+ if (expr == NULL)
+ return 0;
+
+ assert (ffeinfo_basictype (ffebld_info (expr)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (expr)) == FFEINFO_kindtypeINTEGERDEFAULT);
+
+ val = ffedata_eval_integer1_ (expr);
+
+ if (val < 1)
+ {
+ val = 1;
+ ffebad_start (FFEBAD_DATA_RANGE);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ }
+
+ return val - 1;
+}
+
+/* ffedata_eval_substr_end_ -- Evaluate end-point of substr reference
+
+ ffetargetCharacterSize endpoint;
+ ffebld endval; // head(trail(colon)).
+ ffetargetCharacterSize min; // beginpoint of substr reference.
+ ffetargetCharacterSize max; // size of entity.
+
+ endpoint = ffedata_eval_substr_end_(endval,dflt);
+
+ If endval is NULL, returns max. Otherwise makes sure endval is
+ kindtypeINTEGERDEFAULT, makes sure its value is > min and <= max,
+ and returns its value minus one, or issues an error message. */
+
+static ffetargetCharacterSize
+ffedata_eval_substr_end_ (ffebld expr, ffetargetCharacterSize min,
+ ffetargetCharacterSize max)
+{
+ ffetargetIntegerDefault val;
+
+ if (expr == NULL)
+ return max - 1;
+
+ assert (ffeinfo_basictype (ffebld_info (expr)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (expr)) == FFEINFO_kindtypeINTEGER1);
+
+ val = ffedata_eval_integer1_ (expr);
+
+ if ((val < (ffetargetIntegerDefault) min)
+ || (val > (ffetargetIntegerDefault) max))
+ {
+ val = 1;
+ ffebad_start (FFEBAD_DATA_RANGE);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ }
+
+ return val - 1;
+}
+
+/* ffedata_gather_ -- Gather initial values for sym into master sym inits
+
+ ffestorag mst; // A typeCBLOCK or typeLOCAL aggregate.
+ ffestorag st; // A typeCOMMON or typeEQUIV member.
+ ffedata_gather_(mst,st);
+
+ If st has any initialization info, transfer that info into mst and
+ clear st's info. */
+
+void
+ffedata_gather_ (ffestorag mst, ffestorag st)
+{
+ ffesymbol s;
+ ffesymbol s_whine; /* Symbol to complain about in diagnostics. */
+ ffebld b;
+ ffetargetOffset offset;
+ ffetargetOffset units_expected;
+ ffebitCount actual;
+ ffebldConstantArray array;
+ ffebld accter;
+ ffetargetCopyfunc fn;
+ void *ptr1;
+ void *ptr2;
+ size_t size;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffeinfoBasictype ign_bt;
+ ffeinfoKindtype ign_kt;
+ ffetargetAlign units;
+ ffebit bits;
+ ffetargetOffset source_offset;
+ bool whine = FALSE;
+
+ if (st == NULL)
+ return; /* Nothing to do. */
+
+ s = ffestorag_symbol (st);
+
+ assert (s != NULL); /* Must have a corresponding symbol (else how
+ inited?). */
+ assert (ffestorag_init (st) == NULL); /* No init info on storage itself. */
+ assert (ffestorag_accretion (st) == NULL);
+
+ if ((((b = ffesymbol_init (s)) == NULL)
+ && ((b = ffesymbol_accretion (s)) == NULL))
+ || (ffebld_op (b) == FFEBLD_opANY)
+ || ((ffebld_op (b) == FFEBLD_opCONVERT)
+ && (ffebld_op (ffebld_left (b)) == FFEBLD_opANY)))
+ return; /* Nothing to do. */
+
+ /* b now holds the init/accretion expr. */
+
+ ffesymbol_set_init (s, NULL);
+ ffesymbol_set_accretion (s, NULL);
+ ffesymbol_set_accretes (s, 0);
+
+ s_whine = ffestorag_symbol (mst);
+ if (s_whine == NULL)
+ s_whine = s;
+
+ /* Make sure we haven't fully accreted during an array init. */
+
+ if (ffestorag_init (mst) != NULL)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffewhere_line_unknown (), ffewhere_column_unknown ());
+ ffebad_string (ffesymbol_text (s_whine));
+ ffebad_finish ();
+ return;
+ }
+
+ bt = ffeinfo_basictype (ffebld_info (b));
+ kt = ffeinfo_kindtype (ffebld_info (b));
+
+ /* Calculate offset for aggregate area. */
+
+ ffedata_charexpected_ = (bt == FFEINFO_basictypeCHARACTER)
+ ? ffebld_size (b) : 1;
+ ffetarget_aggregate_info (&ign_bt, &ign_kt, &units, bt,
+ kt);/* Find out unit size of source datum. */
+ assert (units % ffedata_storage_units_ == 0);
+ units_expected = ffedata_charexpected_ * units / ffedata_storage_units_;
+ offset = (ffestorag_offset (st) - ffestorag_offset (mst))
+ / ffedata_storage_units_;
+
+ /* Does an accretion array exist? If not, create it. */
+
+ if (ffestorag_accretion (mst) == NULL)
+ {
+#if FFEDATA_sizeTOO_BIG_INIT_ != 0
+ if (ffedata_storage_size_ >= FFEDATA_sizeTOO_BIG_INIT_)
+ {
+ char bignum[40];
+
+ sprintf (&bignum[0], "%ld", (long) ffedata_storage_size_);
+ ffebad_start (FFEBAD_TOO_BIG_INIT);
+ ffebad_here (0, ffesymbol_where_line (s_whine),
+ ffesymbol_where_column (s_whine));
+ ffebad_string (ffesymbol_text (s_whine));
+ ffebad_string (bignum);
+ ffebad_finish ();
+ }
+#endif
+ array = ffebld_constantarray_new (ffedata_storage_bt_,
+ ffedata_storage_kt_, ffedata_storage_size_);
+ accter = ffebld_new_accter (array, ffebit_new (ffe_pool_program_unit (),
+ ffedata_storage_size_));
+ ffebld_set_info (accter, ffeinfo_new
+ (ffedata_storage_bt_,
+ ffedata_storage_kt_,
+ 1,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? 1 : FFETARGET_charactersizeNONE));
+ ffestorag_set_accretion (mst, accter);
+ ffestorag_set_accretes (mst, ffedata_storage_size_);
+ }
+ else
+ {
+ accter = ffestorag_accretion (mst);
+ assert (ffedata_storage_size_ == (ffetargetOffset) ffebld_accter_size (accter));
+ array = ffebld_accter (accter);
+ }
+
+ /* Put value in accretion array at desired offset. */
+
+ fn = ffetarget_aggregate_ptr_memcpy (ffedata_storage_bt_, ffedata_storage_kt_,
+ bt, kt);
+
+ switch (ffebld_op (b))
+ {
+ case FFEBLD_opCONTER:
+ ffebld_constantarray_prepare (&ptr1, &ptr2, &size, array, ffedata_storage_bt_,
+ ffedata_storage_kt_, offset,
+ ffebld_constant_ptr_to_union (ffebld_conter (b)),
+ bt, kt);
+ (*fn) (ptr1, ptr2, size); /* Does the appropriate memcpy-like
+ operation. */
+ ffebit_count (ffebld_accter_bits (accter),
+ offset, FALSE, units_expected, &actual); /* How many FALSE? */
+ if (units_expected != (ffetargetOffset) actual)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffewhere_line_unknown (), ffewhere_column_unknown ());
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ }
+ ffestorag_set_accretes (mst,
+ ffestorag_accretes (mst)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset, 1, units_expected);
+
+ /* If done accreting for this storage area, establish as initialized. */
+
+ if (ffestorag_accretes (mst) == 0)
+ {
+ ffestorag_set_init (mst, accter);
+ ffestorag_set_accretion (mst, NULL);
+ ffebit_kill (ffebld_accter_bits (ffestorag_init (mst)));
+ ffebld_set_op (ffestorag_init (mst), FFEBLD_opARRTER);
+ ffebld_set_arrter (ffestorag_init (mst),
+ ffebld_accter (ffestorag_init (mst)));
+ ffebld_arrter_set_size (ffestorag_init (mst),
+ ffedata_storage_size_);
+ ffecom_notify_init_storage (mst);
+ }
+
+ return;
+
+ case FFEBLD_opARRTER:
+ ffebld_constantarray_preparray (&ptr1, &ptr2, &size, array, ffedata_storage_bt_,
+ ffedata_storage_kt_, offset, ffebld_arrter (b),
+ bt, kt);
+ size *= ffebld_arrter_size (b);
+ units_expected *= ffebld_arrter_size (b);
+ (*fn) (ptr1, ptr2, size); /* Does the appropriate memcpy-like
+ operation. */
+ ffebit_count (ffebld_accter_bits (accter),
+ offset, FALSE, units_expected, &actual); /* How many FALSE? */
+ if (units_expected != (ffetargetOffset) actual)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffewhere_line_unknown (), ffewhere_column_unknown ());
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ }
+ ffestorag_set_accretes (mst,
+ ffestorag_accretes (mst)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset, 1, units_expected);
+
+ /* If done accreting for this storage area, establish as initialized. */
+
+ if (ffestorag_accretes (mst) == 0)
+ {
+ ffestorag_set_init (mst, accter);
+ ffestorag_set_accretion (mst, NULL);
+ ffebit_kill (ffebld_accter_bits (ffestorag_init (mst)));
+ ffebld_set_op (ffestorag_init (mst), FFEBLD_opARRTER);
+ ffebld_set_arrter (ffestorag_init (mst),
+ ffebld_accter (ffestorag_init (mst)));
+ ffebld_arrter_set_size (ffestorag_init (mst),
+ ffedata_storage_size_);
+ ffecom_notify_init_storage (mst);
+ }
+
+ return;
+
+ case FFEBLD_opACCTER:
+ ffebld_constantarray_preparray (&ptr1, &ptr2, &size, array, ffedata_storage_bt_,
+ ffedata_storage_kt_, offset, ffebld_accter (b),
+ bt, kt);
+ bits = ffebld_accter_bits (b);
+ source_offset = 0;
+
+ for (;;)
+ {
+ ffetargetOffset unexp;
+ ffetargetOffset siz;
+ ffebitCount length;
+ bool value;
+
+ ffebit_test (bits, source_offset, &value, &length);
+ if (length == 0)
+ break; /* Exit the loop early. */
+ siz = size * length;
+ unexp = units_expected * length;
+ if (value)
+ {
+ (*fn) (ptr1, ptr2, siz); /* Does memcpy-like operation. */
+ ffebit_count (ffebld_accter_bits (accter), /* How many FALSE? */
+ offset, FALSE, unexp, &actual);
+ if (!whine && (unexp != (ffetargetOffset) actual))
+ {
+ whine = TRUE; /* Don't whine more than once for one gather. */
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffewhere_line_unknown (), ffewhere_column_unknown ());
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ }
+ ffestorag_set_accretes (mst,
+ ffestorag_accretes (mst)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset, 1, unexp);
+ }
+ source_offset += length;
+ offset += unexp;
+ ptr1 = ((char *) ptr1) + siz;
+ ptr2 = ((char *) ptr2) + siz;
+ }
+
+ /* If done accreting for this storage area, establish as initialized. */
+
+ if (ffestorag_accretes (mst) == 0)
+ {
+ ffestorag_set_init (mst, accter);
+ ffestorag_set_accretion (mst, NULL);
+ ffebit_kill (ffebld_accter_bits (ffestorag_init (mst)));
+ ffebld_set_op (ffestorag_init (mst), FFEBLD_opARRTER);
+ ffebld_set_arrter (ffestorag_init (mst),
+ ffebld_accter (ffestorag_init (mst)));
+ ffebld_arrter_set_size (ffestorag_init (mst),
+ ffedata_storage_size_);
+ ffecom_notify_init_storage (mst);
+ }
+
+ return;
+
+ default:
+ assert ("bad init op in gather_" == NULL);
+ return;
+ }
+}
+
+/* ffedata_pop_ -- Pop an impdo stack entry
+
+ ffedata_pop_(); */
+
+static void
+ffedata_pop_ ()
+{
+ ffedataImpdo_ victim = ffedata_stack_;
+
+ assert (victim != NULL);
+
+ ffedata_stack_ = ffedata_stack_->outer;
+
+ malloc_kill_ks (ffe_pool_program_unit (), victim, sizeof (*victim));
+}
+
+/* ffedata_push_ -- Push an impdo stack entry
+
+ ffedata_push_(); */
+
+static void
+ffedata_push_ ()
+{
+ ffedataImpdo_ baby;
+
+ baby = malloc_new_ks (ffe_pool_program_unit (), "ffedataImpdo_", sizeof (*baby));
+
+ baby->outer = ffedata_stack_;
+ ffedata_stack_ = baby;
+}
+
+/* ffedata_value_ -- Provide an initial value
+
+ ffebld value;
+ ffelexToken t; // Points to the value.
+ if (ffedata_value(value,t))
+ // Everything's ok
+
+ Makes sure the value is ok, then remembers it according to the list
+ provided to ffedata_begin. */
+
+static bool
+ffedata_value_ (ffebld value, ffelexToken token)
+{
+
+ /* If already reported an error, don't do anything. */
+
+ if (ffedata_reported_error_)
+ return FALSE;
+
+ /* If the value is an error marker, remember we've seen one and do nothing
+ else. */
+
+ if ((value != NULL)
+ && (ffebld_op (value) == FFEBLD_opANY))
+ {
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* If too many values (no more targets), complain. */
+
+ if (ffedata_symbol_ == NULL)
+ {
+ ffebad_start (FFEBAD_DATA_TOOMANY);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* If ffedata_advance_ wanted to register a complaint, do it now
+ that we have the token to point at instead of just the start
+ of the whole statement. */
+
+ if (ffedata_reinit_)
+ {
+ ffebad_start (FFEBAD_DATA_REINIT);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+#if FFEGLOBAL_ENABLED
+ if (ffesymbol_common (ffedata_symbol_) != NULL)
+ ffeglobal_init_common (ffesymbol_common (ffedata_symbol_), token);
+#endif
+
+ /* Convert value to desired type. */
+
+ if (value != NULL)
+ {
+ if (ffedata_convert_cache_use_ == -1)
+ value = ffeexpr_convert
+ (value, token, NULL, ffedata_basictype_,
+ ffedata_kindtype_, 0,
+ (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? ffedata_charexpected_ : FFETARGET_charactersizeNONE,
+ FFEEXPR_contextDATA);
+ else /* Use the cache. */
+ value = ffedata_convert_
+ (value, token, NULL, ffedata_basictype_,
+ ffedata_kindtype_, 0,
+ (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? ffedata_charexpected_ : FFETARGET_charactersizeNONE);
+ }
+
+ /* If we couldn't, bug out. */
+
+ if ((value != NULL) && (ffebld_op (value) == FFEBLD_opANY))
+ {
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* Handle the case where initializes go to a parent's storage area. */
+
+ if (ffedata_storage_ != NULL)
+ {
+ ffetargetOffset offset;
+ ffetargetOffset units_expected;
+ ffebitCount actual;
+ ffebldConstantArray array;
+ ffebld accter;
+ ffetargetCopyfunc fn;
+ void *ptr1;
+ void *ptr2;
+ size_t size;
+ ffeinfoBasictype ign_bt;
+ ffeinfoKindtype ign_kt;
+ ffetargetAlign units;
+
+ /* Make sure we haven't fully accreted during an array init. */
+
+ if (ffestorag_init (ffedata_storage_) != NULL)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* Calculate offset. */
+
+ offset = ffedata_offset_ * ffedata_size_ + ffedata_charoffset_;
+
+ /* Is offset within range? If not, whine, but don't do anything else. */
+
+ if (offset + ffedata_charexpected_ - 1 > ffedata_symbolsize_)
+ {
+ ffebad_start (FFEBAD_DATA_RANGE);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* Now calculate offset for aggregate area. */
+
+ ffetarget_aggregate_info (&ign_bt, &ign_kt, &units, ffedata_basictype_,
+ ffedata_kindtype_); /* Find out unit size of
+ source datum. */
+ assert (units % ffedata_storage_units_ == 0);
+ units_expected = ffedata_charexpected_ * units / ffedata_storage_units_;
+ offset *= units / ffedata_storage_units_;
+ offset += (ffestorag_offset (ffesymbol_storage (ffedata_symbol_))
+ - ffestorag_offset (ffedata_storage_))
+ / ffedata_storage_units_;
+
+ assert (offset + units_expected - 1 <= ffedata_storage_size_);
+
+ /* Does an accretion array exist? If not, create it. */
+
+ if (value != NULL)
+ {
+ if (ffestorag_accretion (ffedata_storage_) == NULL)
+ {
+#if FFEDATA_sizeTOO_BIG_INIT_ != 0
+ if (ffedata_storage_size_ >= FFEDATA_sizeTOO_BIG_INIT_)
+ {
+ char bignum[40];
+
+ sprintf (&bignum[0], "%ld", (long) ffedata_storage_size_);
+ ffebad_start (FFEBAD_TOO_BIG_INIT);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_string (bignum);
+ ffebad_finish ();
+ }
+#endif
+ array = ffebld_constantarray_new
+ (ffedata_storage_bt_, ffedata_storage_kt_,
+ ffedata_storage_size_);
+ accter = ffebld_new_accter (array,
+ ffebit_new (ffe_pool_program_unit (),
+ ffedata_storage_size_));
+ ffebld_set_info (accter, ffeinfo_new
+ (ffedata_storage_bt_,
+ ffedata_storage_kt_,
+ 1,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ (ffedata_basictype_
+ == FFEINFO_basictypeCHARACTER)
+ ? 1 : FFETARGET_charactersizeNONE));
+ ffestorag_set_accretion (ffedata_storage_, accter);
+ ffestorag_set_accretes (ffedata_storage_, ffedata_storage_size_);
+ }
+ else
+ {
+ accter = ffestorag_accretion (ffedata_storage_);
+ assert (ffedata_storage_size_ == (ffetargetOffset) ffebld_accter_size (accter));
+ array = ffebld_accter (accter);
+ }
+
+ /* Put value in accretion array at desired offset. */
+
+ fn = ffetarget_aggregate_ptr_memcpy
+ (ffedata_storage_bt_, ffedata_storage_kt_,
+ ffedata_basictype_, ffedata_kindtype_);
+ ffebld_constantarray_prepare
+ (&ptr1, &ptr2, &size, array, ffedata_storage_bt_,
+ ffedata_storage_kt_, offset,
+ ffebld_constant_ptr_to_union (ffebld_conter (value)),
+ ffedata_basictype_, ffedata_kindtype_);
+ (*fn) (ptr1, ptr2, size); /* Does the appropriate memcpy-like
+ operation. */
+ ffebit_count (ffebld_accter_bits (accter),
+ offset, FALSE, units_expected,
+ &actual); /* How many FALSE? */
+ if (units_expected != (ffetargetOffset) actual)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ }
+ ffestorag_set_accretes (ffedata_storage_,
+ ffestorag_accretes (ffedata_storage_)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset,
+ 1, units_expected);
+
+ /* If done accreting for this storage area, establish as
+ initialized. */
+
+ if (ffestorag_accretes (ffedata_storage_) == 0)
+ {
+ ffestorag_set_init (ffedata_storage_, accter);
+ ffestorag_set_accretion (ffedata_storage_, NULL);
+ ffebit_kill (ffebld_accter_bits
+ (ffestorag_init (ffedata_storage_)));
+ ffebld_set_op (ffestorag_init (ffedata_storage_),
+ FFEBLD_opARRTER);
+ ffebld_set_arrter
+ (ffestorag_init (ffedata_storage_),
+ ffebld_accter (ffestorag_init (ffedata_storage_)));
+ ffebld_arrter_set_size (ffestorag_init (ffedata_storage_),
+ ffedata_storage_size_);
+ ffecom_notify_init_storage (ffedata_storage_);
+ }
+ }
+
+ /* If still accreting, adjust specs accordingly and return. */
+
+ if (++ffedata_number_ < ffedata_expected_)
+ {
+ ++ffedata_offset_;
+ return TRUE;
+ }
+
+ return ffedata_advance_ ();
+ }
+
+ /* Figure out where the value goes -- in an accretion array or directly
+ into the final initial-value slot for the symbol. */
+
+ if ((ffedata_number_ != 0)
+ || (ffedata_arraysize_ > 1)
+ || (ffedata_charnumber_ != 0)
+ || (ffedata_size_ > ffedata_charexpected_))
+ { /* Accrete this value. */
+ ffetargetOffset offset;
+ ffebitCount actual;
+ ffebldConstantArray array;
+ ffebld accter = NULL;
+
+ /* Calculate offset. */
+
+ offset = ffedata_offset_ * ffedata_size_ + ffedata_charoffset_;
+
+ /* Is offset within range? If not, whine, but don't do anything else. */
+
+ if (offset + ffedata_charexpected_ - 1 > ffedata_symbolsize_)
+ {
+ ffebad_start (FFEBAD_DATA_RANGE);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* Does an accretion array exist? If not, create it. */
+
+ if (value != NULL)
+ {
+ if (ffesymbol_accretion (ffedata_symbol_) == NULL)
+ {
+#if FFEDATA_sizeTOO_BIG_INIT_ != 0
+ if (ffedata_symbolsize_ >= FFEDATA_sizeTOO_BIG_INIT_ )
+ {
+ char bignum[40];
+
+ sprintf (&bignum[0], "%ld", (long) ffedata_symbolsize_);
+ ffebad_start (FFEBAD_TOO_BIG_INIT);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_string (bignum);
+ ffebad_finish ();
+ }
+#endif
+ array = ffebld_constantarray_new
+ (ffedata_basictype_, ffedata_kindtype_,
+ ffedata_symbolsize_);
+ accter = ffebld_new_accter (array,
+ ffebit_new (ffe_pool_program_unit (),
+ ffedata_symbolsize_));
+ ffebld_set_info (accter, ffeinfo_new
+ (ffedata_basictype_,
+ ffedata_kindtype_,
+ 1,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ (ffedata_basictype_
+ == FFEINFO_basictypeCHARACTER)
+ ? 1 : FFETARGET_charactersizeNONE));
+ ffesymbol_set_accretion (ffedata_symbol_, accter);
+ ffesymbol_set_accretes (ffedata_symbol_, ffedata_symbolsize_);
+ }
+ else
+ {
+ accter = ffesymbol_accretion (ffedata_symbol_);
+ assert (ffedata_symbolsize_
+ == (ffetargetOffset) ffebld_accter_size (accter));
+ array = ffebld_accter (accter);
+ }
+
+ /* Put value in accretion array at desired offset. */
+
+ ffebld_constantarray_put
+ (array, ffedata_basictype_, ffedata_kindtype_,
+ offset, ffebld_constant_union (ffebld_conter (value)));
+ ffebit_count (ffebld_accter_bits (accter), offset, FALSE,
+ ffedata_charexpected_,
+ &actual); /* How many FALSE? */
+ if (actual != (unsigned long int) ffedata_charexpected_)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ }
+ ffesymbol_set_accretes (ffedata_symbol_,
+ ffesymbol_accretes (ffedata_symbol_)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset,
+ 1, ffedata_charexpected_);
+ ffesymbol_signal_unreported (ffedata_symbol_);
+ }
+
+ /* If still accreting, adjust specs accordingly and return. */
+
+ if (++ffedata_number_ < ffedata_expected_)
+ {
+ ++ffedata_offset_;
+ return TRUE;
+ }
+
+ /* Else, if done accreting for this symbol, establish as initialized. */
+
+ if ((value != NULL)
+ && (ffesymbol_accretes (ffedata_symbol_) == 0))
+ {
+ ffesymbol_set_init (ffedata_symbol_, accter);
+ ffesymbol_set_accretion (ffedata_symbol_, NULL);
+ ffebit_kill (ffebld_accter_bits (ffesymbol_init (ffedata_symbol_)));
+ ffebld_set_op (ffesymbol_init (ffedata_symbol_), FFEBLD_opARRTER);
+ ffebld_set_arrter (ffesymbol_init (ffedata_symbol_),
+ ffebld_accter (ffesymbol_init (ffedata_symbol_)));
+ ffebld_arrter_set_size (ffesymbol_init (ffedata_symbol_),
+ ffedata_symbolsize_);
+ ffecom_notify_init_symbol (ffedata_symbol_);
+ }
+ }
+ else if (value != NULL)
+ {
+ /* Simple, direct, one-shot assignment. */
+ ffesymbol_set_init (ffedata_symbol_, value);
+ ffecom_notify_init_symbol (ffedata_symbol_);
+ }
+
+ /* Call on advance function to get next target in list. */
+
+ return ffedata_advance_ ();
+}