diff options
Diffstat (limited to 'gcc/f/symbol.c')
-rw-r--r-- | gcc/f/symbol.c | 1469 |
1 files changed, 1469 insertions, 0 deletions
diff --git a/gcc/f/symbol.c b/gcc/f/symbol.c new file mode 100644 index 0000000..7199cdb --- /dev/null +++ b/gcc/f/symbol.c @@ -0,0 +1,1469 @@ +/* Implementation of Fortran symbol manager + 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. */ + +#include "proj.h" +#include "symbol.h" +#include "bad.h" +#include "bld.h" +#include "com.h" +#include "equiv.h" +#include "global.h" +#include "info.h" +#include "intrin.h" +#include "lex.h" +#include "malloc.h" +#include "src.h" +#include "st.h" +#include "storag.h" +#include "target.h" +#include "where.h" + +/* Choice of how to handle global symbols -- either global only within the + program unit being defined or global within the entire source file. + The former is appropriate for systems where an object file can + easily be taken apart program unit by program unit, the latter is the + UNIX/C model where the object file is essentially a monolith. */ + +#define FFESYMBOL_globalPROGUNIT_ 1 +#define FFESYMBOL_globalFILE_ 2 + +/* Choose how to handle global symbols here. */ + +#if FFECOM_targetCURRENT == FFECOM_targetFFE +#define FFESYMBOL_globalCURRENT_ FFESYMBOL_globalPROGUNIT_ +#elif FFECOM_targetCURRENT == FFECOM_targetGCC +/* Would be good to understand why PROGUNIT in this case too. + (1995-08-22). */ +#define FFESYMBOL_globalCURRENT_ FFESYMBOL_globalPROGUNIT_ +#else +#error +#endif + +/* Choose how to handle memory pools based on global symbol stuff. */ + +#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_ +#define FFESYMBOL_SPACE_POOL_ ffe_pool_program_unit() +#elif FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalFILE_ +#define FFESYMBOL_SPACE_POOL_ ffe_pool_file() +#else +#error +#endif + +/* What kind of retraction is needed for a symbol? */ + +enum _ffesymbol_retractcommand_ + { + FFESYMBOL_retractcommandDELETE_, + FFESYMBOL_retractcommandRETRACT_, + FFESYMBOL_retractcommand_ + }; +typedef enum _ffesymbol_retractcommand_ ffesymbolRetractCommand_; + +/* This object keeps track of retraction for a symbol and links to the next + such object. */ + +typedef struct _ffesymbol_retract_ *ffesymbolRetract_; +struct _ffesymbol_retract_ + { + ffesymbolRetract_ next; + ffesymbolRetractCommand_ command; + ffesymbol live; /* Live symbol. */ + ffesymbol symbol; /* Backup copy of symbol. */ + }; + +static ffebad ffesymbol_check_token_ (ffelexToken t, char *c); +static void ffesymbol_kill_manifest_ (void); +static ffesymbol ffesymbol_new_ (ffename n); +static ffesymbol ffesymbol_unhook_ (ffesymbol s); +static void ffesymbol_whine_state_ (ffebad bad, ffelexToken t, char c); + +/* Manifest names for unnamed things (as tokens) so we make them only + once. */ + +static ffelexToken ffesymbol_token_blank_common_ = NULL; +static ffelexToken ffesymbol_token_unnamed_main_ = NULL; +static ffelexToken ffesymbol_token_unnamed_blockdata_ = NULL; + +/* Name spaces currently in force. */ + +static ffenameSpace ffesymbol_global_ = NULL; +static ffenameSpace ffesymbol_local_ = NULL; +static ffenameSpace ffesymbol_sfunc_ = NULL; + +/* Keep track of retraction. */ + +static bool ffesymbol_retractable_ = FALSE; +static mallocPool ffesymbol_retract_pool_; +static ffesymbolRetract_ ffesymbol_retract_first_; +static ffesymbolRetract_ *ffesymbol_retract_list_; + +/* List of state names. */ + +static char *ffesymbol_state_name_[] = +{ + "?", + "@", + "&", + "$", +}; + +/* List of attribute names. */ + +static char *ffesymbol_attr_name_[] = +{ +#define DEFATTR(ATTR,ATTRS,NAME) NAME, +#include "symbol.def" +#undef DEFATTR +}; + + +/* Check whether the token text has any invalid characters. If not, + return FALSE. If so, if error messages inhibited, return TRUE + so caller knows to try again later, else report error and return + FALSE. */ + +static ffebad +ffesymbol_check_token_ (ffelexToken t, char *c) +{ + char *p = ffelex_token_text (t); + ffeTokenLength len = ffelex_token_length (t); + ffebad bad; + ffeTokenLength i = 0; + ffebad skip_me = ((ffe_case_symbol () == FFE_caseINITCAP) + ? FFEBAD_SYMBOL_NOLOWER_INITCAP : FFEBAD + 1); + ffebad stop_me = ((ffe_case_symbol () == FFE_caseINITCAP) + ? FFEBAD : FFEBAD + 1); + if (len == 0) + return FFEBAD; + + bad = ffesrc_bad_char_symbol_init (*p); + if (bad == FFEBAD) + { + for (++i, ++p; i < len; ++i, ++p) + { + bad = ffesrc_bad_char_symbol_noninit (*p); + if (bad == skip_me) + continue; /* Keep looking for good InitCap character. */ + if (bad == stop_me) + break; /* Found good InitCap character. */ + if (bad != FFEBAD) + break; /* Bad character found. */ + } + } + + if (bad != FFEBAD) + if (i >= len) + *c = *(ffelex_token_text (t)); + else + *c = *p; + + return bad; +} + +/* Kill manifest (g77-picked) names. */ + +static void +ffesymbol_kill_manifest_ () +{ + if (ffesymbol_token_blank_common_ != NULL) + ffelex_token_kill (ffesymbol_token_blank_common_); + if (ffesymbol_token_unnamed_main_ != NULL) + ffelex_token_kill (ffesymbol_token_unnamed_main_); + if (ffesymbol_token_unnamed_blockdata_ != NULL) + ffelex_token_kill (ffesymbol_token_unnamed_blockdata_); + + ffesymbol_token_blank_common_ = NULL; + ffesymbol_token_unnamed_main_ = NULL; + ffesymbol_token_unnamed_blockdata_ = NULL; +} + +/* Make new symbol. + + If the "retractable" flag is not set, just return the new symbol. + Else, add symbol to the "retract" list as a delete item, set + the "have_old" flag, and return the new symbol. */ + +static ffesymbol +ffesymbol_new_ (ffename n) +{ + ffesymbol s; + ffesymbolRetract_ r; + + assert (n != NULL); + + s = (ffesymbol) malloc_new_ks (FFESYMBOL_SPACE_POOL_, "FFESYMBOL", + sizeof (*s)); + s->name = n; + s->other_space_name = NULL; +#if FFEGLOBAL_ENABLED + s->global = NULL; +#endif + s->attrs = FFESYMBOL_attrsetNONE; + s->state = FFESYMBOL_stateNONE; + s->info = ffeinfo_new_null (); + s->dims = NULL; + s->extents = NULL; + s->dim_syms = NULL; + s->array_size = NULL; + s->init = NULL; + s->accretion = NULL; + s->accretes = 0; + s->dummy_args = NULL; + s->namelist = NULL; + s->common_list = NULL; + s->sfunc_expr = NULL; + s->list_bottom = NULL; + s->common = NULL; + s->equiv = NULL; + s->storage = NULL; +#ifdef FFECOM_symbolHOOK + s->hook = FFECOM_symbolNULL; +#endif + s->sfa_dummy_parent = NULL; + s->func_result = NULL; + s->value = 0; + s->check_state = FFESYMBOL_checkstateNONE_; + s->check_token = NULL; + s->max_entry_num = 0; + s->num_entries = 0; + s->generic = FFEINTRIN_genNONE; + s->specific = FFEINTRIN_specNONE; + s->implementation = FFEINTRIN_impNONE; + s->is_save = FALSE; + s->is_init = FALSE; + s->do_iter = FALSE; + s->reported = FALSE; + s->explicit_where = FALSE; + s->namelisted = FALSE; + + ffename_set_symbol (n, s); + + if (!ffesymbol_retractable_) + { + s->have_old = FALSE; + return s; + } + + r = (ffesymbolRetract_) malloc_new_kp (ffesymbol_retract_pool_, + "FFESYMBOL retract", sizeof (*r)); + r->next = NULL; + r->command = FFESYMBOL_retractcommandDELETE_; + r->live = s; + r->symbol = NULL; /* No backup copy. */ + + *ffesymbol_retract_list_ = r; + ffesymbol_retract_list_ = &r->next; + + s->have_old = TRUE; + return s; +} + +/* Unhook a symbol from its (soon-to-be-killed) name obj. + + NULLify the names to which this symbol points. Do other cleanup as + needed. */ + +static ffesymbol +ffesymbol_unhook_ (ffesymbol s) +{ + s->other_space_name = s->name = NULL; + if ((ffesymbol_attrs (s) & FFESYMBOL_attrsCBLOCK) + || (ffesymbol_kind (s) == FFEINFO_kindNAMELIST)) + ffebld_end_list (ffesymbol_ptr_to_listbottom (s)); + if (s->check_state == FFESYMBOL_checkstatePENDING_) + ffelex_token_kill (s->check_token); + + return s; +} + +/* Issue diagnostic about bad character in token representing user-defined + symbol name. */ + +static void +ffesymbol_whine_state_ (ffebad bad, ffelexToken t, char c) +{ + char badstr[2]; + + badstr[0] = c; + badstr[1] = '\0'; + + ffebad_start (bad); + ffebad_here (0, ffelex_token_where_line (t), + ffelex_token_where_column (t)); + ffebad_string (badstr); + ffebad_finish (); +} + +/* Returns a string representing the attributes set. */ + +char * +ffesymbol_attrs_string (ffesymbolAttrs attrs) +{ + static char string[FFESYMBOL_attr * 12 + 20]; + char *p; + ffesymbolAttr attr; + + p = &string[0]; + + if (attrs == FFESYMBOL_attrsetNONE) + { + strcpy (p, "NONE"); + return &string[0]; + } + + for (attr = 0; attr < FFESYMBOL_attr; ++attr) + { + if (attrs & ((ffesymbolAttrs) 1 << attr)) + { + attrs &= ~((ffesymbolAttrs) 1 << attr); + strcpy (p, ffesymbol_attr_name_[attr]); + while (*p) + ++p; + *(p++) = '|'; + } + } + if (attrs == FFESYMBOL_attrsetNONE) + *--p = '\0'; + else + sprintf (p, "?0x%" ffesymbolAttrs_f "x?", attrs); + assert (((size_t) (p - &string[0])) < ARRAY_SIZE (string)); + return &string[0]; +} + +/* Check symbol's name for validity, considering that it might actually + be an intrinsic and thus should not be complained about just yet. */ + +void +ffesymbol_check (ffesymbol s, ffelexToken t, bool maybe_intrin) +{ + char c; + ffebad bad; + ffeintrinGen gen; + ffeintrinSpec spec; + ffeintrinImp imp; + + if (!ffesrc_check_symbol () + || ((s->check_state != FFESYMBOL_checkstateNONE_) + && ((s->check_state != FFESYMBOL_checkstateINHIBITED_) + || ffebad_inhibit ()))) + return; + + bad = ffesymbol_check_token_ (t, &c); + + if (bad == FFEBAD) + { + s->check_state = FFESYMBOL_checkstateCHECKED_; + return; + } + + if (maybe_intrin + && ffeintrin_is_intrinsic (ffelex_token_text (t), NULL, FALSE, + &gen, &spec, &imp)) + { + s->check_state = FFESYMBOL_checkstatePENDING_; + s->check_token = ffelex_token_use (t); + return; + } + + if (ffebad_inhibit ()) + { + s->check_state = FFESYMBOL_checkstateINHIBITED_; + return; /* Don't complain now, do it later. */ + } + + s->check_state = FFESYMBOL_checkstateCHECKED_; + + ffesymbol_whine_state_ (bad, t, c); +} + +/* Declare a BLOCKDATA unit. + + Retrieves or creates the ffesymbol for the specified BLOCKDATA (unnamed + if t is NULL). Doesn't actually ensure the named item is a + BLOCKDATA; the caller must handle that. */ + +ffesymbol +ffesymbol_declare_blockdataunit (ffelexToken t, ffewhereLine wl, + ffewhereColumn wc) +{ + ffename n; + ffesymbol s; + bool user = (t != NULL); + + assert (!ffesymbol_retractable_); + + if (t == NULL) + { + if (ffesymbol_token_unnamed_blockdata_ == NULL) + ffesymbol_token_unnamed_blockdata_ + = ffelex_token_new_name (FFETARGET_nameUNNAMED_BLOCK_DATA, wl, wc); + t = ffesymbol_token_unnamed_blockdata_; + } + + n = ffename_lookup (ffesymbol_local_, t); + if (n != NULL) + return ffename_symbol (n); /* This will become an error. */ + + n = ffename_find (ffesymbol_global_, t); + s = ffename_symbol (n); + if (s != NULL) + { + if (user) + ffesymbol_check (s, t, FALSE); + return s; + } + + s = ffesymbol_new_ (n); + if (user) + ffesymbol_check (s, t, FALSE); + + /* A program unit name also is in the local name space. */ + + n = ffename_find (ffesymbol_local_, t); + ffename_set_symbol (n, s); + s->other_space_name = n; + + ffeglobal_new_blockdata (s, t); /* Detect conflicts, when + appropriate. */ + + return s; +} + +/* Declare a common block (named or unnamed). + + Retrieves or creates the ffesymbol for the specified common block (blank + common if t is NULL). Doesn't actually ensure the named item is a + common block; the caller must handle that. */ + +ffesymbol +ffesymbol_declare_cblock (ffelexToken t, ffewhereLine wl, ffewhereColumn wc) +{ + ffename n; + ffesymbol s; + bool blank; + + assert (!ffesymbol_retractable_); + + if (t == NULL) + { + blank = TRUE; + if (ffesymbol_token_blank_common_ == NULL) + ffesymbol_token_blank_common_ + = ffelex_token_new_name (FFETARGET_nameBLANK_COMMON, wl, wc); + t = ffesymbol_token_blank_common_; + } + else + blank = FALSE; + + n = ffename_find (ffesymbol_global_, t); + s = ffename_symbol (n); + if (s != NULL) + { + if (!blank) + ffesymbol_check (s, t, FALSE); + return s; + } + + s = ffesymbol_new_ (n); + if (!blank) + ffesymbol_check (s, t, FALSE); + + ffeglobal_new_common (s, t, blank); /* Detect conflicts. */ + + return s; +} + +/* Declare a FUNCTION program unit (with distinct RESULT() name). + + Retrieves or creates the ffesymbol for the specified function. Doesn't + actually ensure the named item is a function; the caller must handle + that. + + If FUNCTION with RESULT() is specified but the names are the same, + pretend as though RESULT() was not specified, and don't call this + function; use ffesymbol_declare_funcunit() instead. */ + +ffesymbol +ffesymbol_declare_funcnotresunit (ffelexToken t) +{ + ffename n; + ffesymbol s; + + assert (t != NULL); + assert (!ffesymbol_retractable_); + + n = ffename_lookup (ffesymbol_local_, t); + if (n != NULL) + return ffename_symbol (n); /* This will become an error. */ + + n = ffename_find (ffesymbol_global_, t); + s = ffename_symbol (n); + if (s != NULL) + { + ffesymbol_check (s, t, FALSE); + return s; + } + + s = ffesymbol_new_ (n); + ffesymbol_check (s, t, FALSE); + + /* A FUNCTION program unit name also is in the local name space; handle it + here since RESULT() is a different name and is handled separately. */ + + n = ffename_find (ffesymbol_local_, t); + ffename_set_symbol (n, s); + s->other_space_name = n; + + ffeglobal_new_function (s, t);/* Detect conflicts, when appropriate. */ + + return s; +} + +/* Declare a function result. + + Retrieves or creates the ffesymbol for the specified function result, + whether specified via a distinct RESULT() or by default in a FUNCTION or + ENTRY statement. */ + +ffesymbol +ffesymbol_declare_funcresult (ffelexToken t) +{ + ffename n; + ffesymbol s; + + assert (t != NULL); + assert (!ffesymbol_retractable_); + + n = ffename_find (ffesymbol_local_, t); + s = ffename_symbol (n); + if (s != NULL) + return s; + + return ffesymbol_new_ (n); +} + +/* Declare a FUNCTION program unit with no RESULT(). + + Retrieves or creates the ffesymbol for the specified function. Doesn't + actually ensure the named item is a function; the caller must handle + that. + + This is the function to call when the FUNCTION or ENTRY statement has + no separate and distinct name specified via RESULT(). That's because + this function enters the global name of the function in only the global + name space. ffesymbol_declare_funcresult() must still be called to + declare the name for the function result in the local name space. */ + +ffesymbol +ffesymbol_declare_funcunit (ffelexToken t) +{ + ffename n; + ffesymbol s; + + assert (t != NULL); + assert (!ffesymbol_retractable_); + + n = ffename_find (ffesymbol_global_, t); + s = ffename_symbol (n); + if (s != NULL) + { + ffesymbol_check (s, t, FALSE); + return s; + } + + s = ffesymbol_new_ (n); + ffesymbol_check (s, t, FALSE); + + ffeglobal_new_function (s, t);/* Detect conflicts. */ + + return s; +} + +/* Declare a local entity. + + Retrieves or creates the ffesymbol for the specified local entity. + Set maybe_intrin TRUE if this name might turn out to name an + intrinsic (legitimately); otherwise if the name doesn't meet the + requirements for a user-defined symbol name, a diagnostic will be + issued right away rather than waiting until the intrinsicness of the + symbol is determined. */ + +ffesymbol +ffesymbol_declare_local (ffelexToken t, bool maybe_intrin) +{ + ffename n; + ffesymbol s; + + assert (t != NULL); + + /* If we're parsing within a statement function definition, return the + symbol if already known (a dummy argument for the statement function). + Otherwise continue on, which means the symbol is declared within the + containing (local) program unit rather than the statement function + definition. */ + + if ((ffesymbol_sfunc_ != NULL) + && ((n = ffename_lookup (ffesymbol_sfunc_, t)) != NULL)) + return ffename_symbol (n); + + n = ffename_find (ffesymbol_local_, t); + s = ffename_symbol (n); + if (s != NULL) + { + ffesymbol_check (s, t, maybe_intrin); + return s; + } + + s = ffesymbol_new_ (n); + ffesymbol_check (s, t, maybe_intrin); + return s; +} + +/* Declare a main program unit. + + Retrieves or creates the ffesymbol for the specified main program unit + (unnamed main program unit if t is NULL). Doesn't actually ensure the + named item is a program; the caller must handle that. */ + +ffesymbol +ffesymbol_declare_programunit (ffelexToken t, ffewhereLine wl, + ffewhereColumn wc) +{ + ffename n; + ffesymbol s; + bool user = (t != NULL); + + assert (!ffesymbol_retractable_); + + if (t == NULL) + { + if (ffesymbol_token_unnamed_main_ == NULL) + ffesymbol_token_unnamed_main_ + = ffelex_token_new_name (FFETARGET_nameUNNAMED_MAIN, wl, wc); + t = ffesymbol_token_unnamed_main_; + } + + n = ffename_lookup (ffesymbol_local_, t); + if (n != NULL) + return ffename_symbol (n); /* This will become an error. */ + + n = ffename_find (ffesymbol_global_, t); + s = ffename_symbol (n); + if (s != NULL) + { + if (user) + ffesymbol_check (s, t, FALSE); + return s; + } + + s = ffesymbol_new_ (n); + if (user) + ffesymbol_check (s, t, FALSE); + + /* A program unit name also is in the local name space. */ + + n = ffename_find (ffesymbol_local_, t); + ffename_set_symbol (n, s); + s->other_space_name = n; + + ffeglobal_new_program (s, t); /* Detect conflicts. */ + + return s; +} + +/* Declare a statement-function dummy. + + Retrieves or creates the ffesymbol for the specified statement + function dummy. Also ensures that it has a link to the parent (local) + ffesymbol with the same name, creating it if necessary. */ + +ffesymbol +ffesymbol_declare_sfdummy (ffelexToken t) +{ + ffename n; + ffesymbol s; + ffesymbol sp; /* Parent symbol in local area. */ + + assert (t != NULL); + + n = ffename_find (ffesymbol_local_, t); + sp = ffename_symbol (n); + if (sp == NULL) + sp = ffesymbol_new_ (n); + ffesymbol_check (sp, t, FALSE); + + n = ffename_find (ffesymbol_sfunc_, t); + s = ffename_symbol (n); + if (s == NULL) + { + s = ffesymbol_new_ (n); + s->sfa_dummy_parent = sp; + } + else + assert (s->sfa_dummy_parent == sp); + + return s; +} + +/* Declare a subroutine program unit. + + Retrieves or creates the ffesymbol for the specified subroutine + Doesn't actually ensure the named item is a subroutine; the caller must + handle that. */ + +ffesymbol +ffesymbol_declare_subrunit (ffelexToken t) +{ + ffename n; + ffesymbol s; + + assert (!ffesymbol_retractable_); + assert (t != NULL); + + n = ffename_lookup (ffesymbol_local_, t); + if (n != NULL) + return ffename_symbol (n); /* This will become an error. */ + + n = ffename_find (ffesymbol_global_, t); + s = ffename_symbol (n); + if (s != NULL) + { + ffesymbol_check (s, t, FALSE); + return s; + } + + s = ffesymbol_new_ (n); + ffesymbol_check (s, t, FALSE); + + /* A program unit name also is in the local name space. */ + + n = ffename_find (ffesymbol_local_, t); + ffename_set_symbol (n, s); + s->other_space_name = n; + + ffeglobal_new_subroutine (s, t); /* Detect conflicts, when + appropriate. */ + + return s; +} + +/* Call given fn with all local/global symbols. + + ffesymbol (*fn) (ffesymbol s); + ffesymbol_drive (fn); */ + +void +ffesymbol_drive (ffesymbol (*fn) ()) +{ + assert (ffesymbol_sfunc_ == NULL); /* Might be ok, but not for current + uses. */ + ffename_space_drive_symbol (ffesymbol_local_, fn); + ffename_space_drive_symbol (ffesymbol_global_, fn); +} + +/* Call given fn with all sfunc-only symbols. + + ffesymbol (*fn) (ffesymbol s); + ffesymbol_drive_sfnames (fn); */ + +void +ffesymbol_drive_sfnames (ffesymbol (*fn) ()) +{ + ffename_space_drive_symbol (ffesymbol_sfunc_, fn); +} + +/* Dump info on the symbol for debugging purposes. */ + +void +ffesymbol_dump (ffesymbol s) +{ + ffeinfoKind k; + ffeinfoWhere w; + + assert (s != NULL); + + if (ffeinfo_size (s->info) != FFETARGET_charactersizeNONE) + fprintf (dmpout, "%s:%d%s%s*%" ffetargetCharacterSize_f "u", + ffesymbol_text (s), + (int) ffeinfo_rank (s->info), + ffeinfo_basictype_string (ffeinfo_basictype (s->info)), + ffeinfo_kindtype_string (ffeinfo_kindtype (s->info)), + ffeinfo_size (s->info)); + else + fprintf (dmpout, "%s:%d%s%s", + ffesymbol_text (s), + (int) ffeinfo_rank (s->info), + ffeinfo_basictype_string (ffeinfo_basictype (s->info)), + ffeinfo_kindtype_string (ffeinfo_kindtype (s->info))); + if ((k = ffeinfo_kind (s->info)) != FFEINFO_kindNONE) + fprintf (dmpout, "/%s", ffeinfo_kind_string (k)); + if ((w = ffeinfo_where (s->info)) != FFEINFO_whereNONE) + fprintf (dmpout, "@%s", ffeinfo_where_string (w)); + + if ((s->generic != FFEINTRIN_genNONE) + || (s->specific != FFEINTRIN_specNONE) + || (s->implementation != FFEINTRIN_impNONE)) + fprintf (dmpout, "{%s:%s:%s}", + ffeintrin_name_generic (s->generic), + ffeintrin_name_specific (s->specific), + ffeintrin_name_implementation (s->implementation)); +} + +/* Produce generic error message about a symbol. + + For now, just output error message using symbol's name and pointing to + the token. */ + +void +ffesymbol_error (ffesymbol s, ffelexToken t) +{ + if ((t != NULL) + && ffest_ffebad_start (FFEBAD_SYMERR)) + { + ffebad_string (ffesymbol_text (s)); + ffebad_here (0, ffelex_token_where_line (t), + ffelex_token_where_column (t)); + ffebad_here (1, ffesymbol_where_line (s), ffesymbol_where_column (s)); + ffebad_finish (); + } + + if (ffesymbol_attr (s, FFESYMBOL_attrANY)) + return; + + ffesymbol_signal_change (s); /* May need to back up to previous version. */ + if ((ffesymbol_attrs (s) & FFESYMBOL_attrsCBLOCK) + || (ffesymbol_kind (s) == FFEINFO_kindNAMELIST)) + ffebld_end_list (ffesymbol_ptr_to_listbottom (s)); + ffesymbol_set_attr (s, FFESYMBOL_attrANY); + ffesymbol_set_info (s, ffeinfo_new_any ()); + ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD); + if (s->check_state == FFESYMBOL_checkstatePENDING_) + ffelex_token_kill (s->check_token); + s->check_state = FFESYMBOL_checkstateCHECKED_; + s = ffecom_sym_learned (s); + ffesymbol_signal_unreported (s); +} + +void +ffesymbol_init_0 () +{ + ffesymbolAttrs attrs = FFESYMBOL_attrsetNONE; + + assert (FFESYMBOL_state == ARRAY_SIZE (ffesymbol_state_name_)); + assert (FFESYMBOL_attr == ARRAY_SIZE (ffesymbol_attr_name_)); + assert (attrs == FFESYMBOL_attrsetNONE); + attrs = ((ffesymbolAttrs) 1 << FFESYMBOL_attr); + assert (attrs != 0); +} + +void +ffesymbol_init_1 () +{ +#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalFILE_ + ffesymbol_global_ = ffename_space_new (ffe_pool_file ()); +#endif +} + +void +ffesymbol_init_2 () +{ +} + +void +ffesymbol_init_3 () +{ +#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_ + ffesymbol_global_ = ffename_space_new (ffe_pool_program_unit ()); +#endif + ffesymbol_local_ = ffename_space_new (ffe_pool_program_unit ()); +} + +void +ffesymbol_init_4 () +{ + ffesymbol_sfunc_ = ffename_space_new (ffe_pool_program_unit ()); +} + +/* Look up a local entity. + + Retrieves the ffesymbol for the specified local entity, or returns NULL + if no local entity by that name exists. */ + +ffesymbol +ffesymbol_lookup_local (ffelexToken t) +{ + ffename n; + ffesymbol s; + + assert (t != NULL); + + n = ffename_lookup (ffesymbol_local_, t); + if (n == NULL) + return NULL; + + s = ffename_symbol (n); + return s; /* May be NULL here, too. */ +} + +/* Registers the symbol as one that is referenced by the + current program unit. Currently applies only to + symbols known to have global interest (globals and + intrinsics). + + s is the (global/intrinsic) symbol referenced; t is the + referencing token; explicit is TRUE if the reference + is, e.g., INTRINSIC FOO. */ + +void +ffesymbol_reference (ffesymbol s, ffelexToken t, bool explicit) +{ + ffename gn; + ffesymbol gs = NULL; + ffeinfoKind kind; + ffeinfoWhere where; + bool okay; + + if (ffesymbol_retractable_) + return; + + if (t == NULL) + t = ffename_token (s->name); /* Use the first reference in this program unit. */ + + kind = ffesymbol_kind (s); + where = ffesymbol_where (s); + + if (where == FFEINFO_whereINTRINSIC) + { + ffeglobal_ref_intrinsic (s, t, + explicit + || s->explicit_where + || ffeintrin_is_standard (s->generic, s->specific)); + return; + } + + if ((where != FFEINFO_whereGLOBAL) + && ((where != FFEINFO_whereLOCAL) + || ((kind != FFEINFO_kindFUNCTION) + && (kind != FFEINFO_kindSUBROUTINE)))) + return; + + gn = ffename_lookup (ffesymbol_global_, t); + if (gn != NULL) + gs = ffename_symbol (gn); + if ((gs != NULL) && (gs != s)) + { + /* We have just discovered another global symbol with the same name + but a different `nature'. Complain. Note that COMMON /FOO/ can + coexist with local symbol FOO, e.g. local variable, just not with + CALL FOO, hence the separate namespaces. */ + + ffesymbol_error (gs, t); + ffesymbol_error (s, NULL); + return; + } + + switch (kind) + { + case FFEINFO_kindBLOCKDATA: + okay = ffeglobal_ref_blockdata (s, t); + break; + + case FFEINFO_kindSUBROUTINE: + okay = ffeglobal_ref_subroutine (s, t); + break; + + case FFEINFO_kindFUNCTION: + okay = ffeglobal_ref_function (s, t); + break; + + case FFEINFO_kindNONE: + okay = ffeglobal_ref_external (s, t); + break; + + default: + assert ("bad kind in global ref" == NULL); + return; + } + + if (! okay) + ffesymbol_error (s, NULL); +} + +/* Report info on the symbol for debugging purposes. */ + +ffesymbol +ffesymbol_report (ffesymbol s) +{ + ffeinfoKind k; + ffeinfoWhere w; + + assert (s != NULL); + + if (s->reported) + return s; + + s->reported = TRUE; + + if (ffeinfo_size (s->info) != FFETARGET_charactersizeNONE) + fprintf (dmpout, "\"%s\": %s %s %d%s%s*%" ffetargetCharacterSize_f "u", + ffesymbol_text (s), + ffesymbol_state_string (s->state), + ffesymbol_attrs_string (s->attrs), + (int) ffeinfo_rank (s->info), + ffeinfo_basictype_string (ffeinfo_basictype (s->info)), + ffeinfo_kindtype_string (ffeinfo_kindtype (s->info)), + ffeinfo_size (s->info)); + else + fprintf (dmpout, "\"%s\": %s %s %d%s%s", + ffesymbol_text (s), + ffesymbol_state_string (s->state), + ffesymbol_attrs_string (s->attrs), + (int) ffeinfo_rank (s->info), + ffeinfo_basictype_string (ffeinfo_basictype (s->info)), + ffeinfo_kindtype_string (ffeinfo_kindtype (s->info))); + if ((k = ffeinfo_kind (s->info)) != FFEINFO_kindNONE) + fprintf (dmpout, "/%s", ffeinfo_kind_string (k)); + if ((w = ffeinfo_where (s->info)) != FFEINFO_whereNONE) + fprintf (dmpout, "@%s", ffeinfo_where_string (w)); + fputc ('\n', dmpout); + + if (s->dims != NULL) + { + fprintf (dmpout, " dims: "); + ffebld_dump (s->dims); + fputs ("\n", dmpout); + } + + if (s->extents != NULL) + { + fprintf (dmpout, " extents: "); + ffebld_dump (s->extents); + fputs ("\n", dmpout); + } + + if (s->dim_syms != NULL) + { + fprintf (dmpout, " dim syms: "); + ffebld_dump (s->dim_syms); + fputs ("\n", dmpout); + } + + if (s->array_size != NULL) + { + fprintf (dmpout, " array size: "); + ffebld_dump (s->array_size); + fputs ("\n", dmpout); + } + + if (s->init != NULL) + { + fprintf (dmpout, " init-value: "); + if (ffebld_op (s->init) == FFEBLD_opANY) + fputs ("<any>\n", dmpout); + else + { + ffebld_dump (s->init); + fputs ("\n", dmpout); + } + } + + if (s->accretion != NULL) + { + fprintf (dmpout, " accretion (%" ffetargetOffset_f "d left): ", + s->accretes); + ffebld_dump (s->accretion); + fputs ("\n", dmpout); + } + else if (s->accretes != 0) + fprintf (dmpout, " accretes!! = %" ffetargetOffset_f "d left\n", + s->accretes); + + if (s->dummy_args != NULL) + { + fprintf (dmpout, " dummies: "); + ffebld_dump (s->dummy_args); + fputs ("\n", dmpout); + } + + if (s->namelist != NULL) + { + fprintf (dmpout, " namelist: "); + ffebld_dump (s->namelist); + fputs ("\n", dmpout); + } + + if (s->common_list != NULL) + { + fprintf (dmpout, " common-list: "); + ffebld_dump (s->common_list); + fputs ("\n", dmpout); + } + + if (s->sfunc_expr != NULL) + { + fprintf (dmpout, " sfunc expression: "); + ffebld_dump (s->sfunc_expr); + fputs ("\n", dmpout); + } + + if (s->is_save) + { + fprintf (dmpout, " SAVEd\n"); + } + + if (s->is_init) + { + fprintf (dmpout, " initialized\n"); + } + + if (s->do_iter) + { + fprintf (dmpout, " DO-loop iteration variable (currently)\n"); + } + + if (s->explicit_where) + { + fprintf (dmpout, " Explicit INTRINSIC/EXTERNAL\n"); + } + + if (s->namelisted) + { + fprintf (dmpout, " Namelisted\n"); + } + + if (s->common != NULL) + { + fprintf (dmpout, " COMMON area: %s\n", ffesymbol_text (s->common)); + } + + if (s->equiv != NULL) + { + fprintf (dmpout, " EQUIVALENCE information: "); + ffeequiv_dump (s->equiv); + fputs ("\n", dmpout); + } + + if (s->storage != NULL) + { + fprintf (dmpout, " Storage: "); + ffestorag_dump (s->storage); + fputs ("\n", dmpout); + } + + return s; +} + +/* Report info on the symbols. */ + +void +ffesymbol_report_all () +{ + ffename_space_drive_symbol (ffesymbol_sfunc_, ffesymbol_report); + ffename_space_drive_symbol (ffesymbol_local_, ffesymbol_report); + ffename_space_drive_symbol (ffesymbol_global_, ffesymbol_report); +} + +/* Resolve symbol that has become known intrinsic or non-intrinsic. */ + +void +ffesymbol_resolve_intrin (ffesymbol s) +{ + char c; + ffebad bad; + + if (!ffesrc_check_symbol ()) + return; + if (s->check_state != FFESYMBOL_checkstatePENDING_) + return; + if (ffebad_inhibit ()) + return; /* We'll get back to this later. */ + + if (ffesymbol_where (s) != FFEINFO_whereINTRINSIC) + { + bad = ffesymbol_check_token_ (s->check_token, &c); + assert (bad != FFEBAD); /* How did this suddenly become ok? */ + ffesymbol_whine_state_ (bad, s->check_token, c); + } + + s->check_state = FFESYMBOL_checkstateCHECKED_; + ffelex_token_kill (s->check_token); +} + +/* Retract or cancel retract list. */ + +void +ffesymbol_retract (bool retract) +{ + ffesymbolRetract_ r; + ffename name; + ffename other_space_name; + ffesymbol ls; + ffesymbol os; + + assert (ffesymbol_retractable_); + + ffesymbol_retractable_ = FALSE; + + for (r = ffesymbol_retract_first_; r != NULL; r = r->next) + { + ls = r->live; + os = r->symbol; + switch (r->command) + { + case FFESYMBOL_retractcommandDELETE_: + if (retract) + { + ffecom_sym_retract (ls); + name = ls->name; + other_space_name = ls->other_space_name; + ffesymbol_unhook_ (ls); + malloc_kill_ks (FFESYMBOL_SPACE_POOL_, ls, sizeof (*ls)); + if (name != NULL) + ffename_set_symbol (name, NULL); + if (other_space_name != NULL) + ffename_set_symbol (other_space_name, NULL); + } + else + { + ffecom_sym_commit (ls); + ls->have_old = FALSE; + } + break; + + case FFESYMBOL_retractcommandRETRACT_: + if (retract) + { + ffecom_sym_retract (ls); + ffesymbol_unhook_ (ls); + *ls = *os; + malloc_kill_ks (FFESYMBOL_SPACE_POOL_, os, sizeof (*os)); + } + else + { + ffecom_sym_commit (ls); + ffesymbol_unhook_ (os); + malloc_kill_ks (FFESYMBOL_SPACE_POOL_, os, sizeof (*os)); + ls->have_old = FALSE; + } + break; + + default: + assert ("bad command" == NULL); + break; + } + } +} + +/* Return retractable flag. */ + +bool +ffesymbol_retractable () +{ + return ffesymbol_retractable_; +} + +/* Set retractable flag, retract pool. + + Between this call and ffesymbol_retract, any changes made to existing + symbols cause the previous versions of those symbols to be saved, and any + newly created symbols to have their previous nonexistence saved. When + ffesymbol_retract is called, this information either is used to retract + the changes and new symbols, or is discarded. */ + +void +ffesymbol_set_retractable (mallocPool pool) +{ + assert (!ffesymbol_retractable_); + + ffesymbol_retractable_ = TRUE; + ffesymbol_retract_pool_ = pool; + ffesymbol_retract_list_ = &ffesymbol_retract_first_; + ffesymbol_retract_first_ = NULL; +} + +/* Existing symbol about to be changed; save? + + Call this function before changing a symbol if it is possible that + the current actions may need to be undone (i.e. one of several possible + statement forms are being used to analyze the current system). + + If the "retractable" flag is not set, just return. + Else, if the symbol's "have_old" flag is set, just return. + Else, make a copy of the symbol and add it to the "retract" list, set + the "have_old" flag, and return. */ + +void +ffesymbol_signal_change (ffesymbol s) +{ + ffesymbolRetract_ r; + ffesymbol sym; + + if (!ffesymbol_retractable_ || s->have_old) + return; + + r = (ffesymbolRetract_) malloc_new_kp (ffesymbol_retract_pool_, + "FFESYMBOL retract", sizeof (*r)); + r->next = NULL; + r->command = FFESYMBOL_retractcommandRETRACT_; + r->live = s; + r->symbol = sym = (ffesymbol) malloc_new_ks (FFESYMBOL_SPACE_POOL_, + "FFESYMBOL", sizeof (*sym)); + *sym = *s; /* Make an exact copy of the symbol in case + we need it back. */ + sym->info = ffeinfo_use (s->info); + if (s->check_state == FFESYMBOL_checkstatePENDING_) + sym->check_token = ffelex_token_use (s->check_token); + + *ffesymbol_retract_list_ = r; + ffesymbol_retract_list_ = &r->next; + + s->have_old = TRUE; +} + +/* Returns the string based on the state. */ + +char * +ffesymbol_state_string (ffesymbolState state) +{ + if (state >= ARRAY_SIZE (ffesymbol_state_name_)) + return "?\?\?"; + return ffesymbol_state_name_[state]; +} + +void +ffesymbol_terminate_0 () +{ +} + +void +ffesymbol_terminate_1 () +{ +#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalFILE_ + ffename_space_drive_symbol (ffesymbol_global_, ffesymbol_unhook_); + ffename_space_kill (ffesymbol_global_); + ffesymbol_global_ = NULL; + + ffesymbol_kill_manifest_ (); +#endif +} + +void +ffesymbol_terminate_2 () +{ +#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_ + ffesymbol_kill_manifest_ (); +#endif +} + +void +ffesymbol_terminate_3 () +{ +#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_ + ffename_space_drive_symbol (ffesymbol_global_, ffesymbol_unhook_); + ffename_space_kill (ffesymbol_global_); +#endif + ffename_space_drive_symbol (ffesymbol_local_, ffesymbol_unhook_); + ffename_space_kill (ffesymbol_local_); +#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_ + ffesymbol_global_ = NULL; +#endif + ffesymbol_local_ = NULL; +} + +void +ffesymbol_terminate_4 () +{ + ffename_space_drive_symbol (ffesymbol_sfunc_, ffesymbol_unhook_); + ffename_space_kill (ffesymbol_sfunc_); + ffesymbol_sfunc_ = NULL; +} + +/* Update INIT info to TRUE and all equiv/storage too. + + If INIT flag is TRUE, does nothing. Else sets it to TRUE and calls + on the ffeequiv and ffestorag modules to update their INIT flags if + the <s> symbol has those objects, and also updates the common area if + it exists. */ + +void +ffesymbol_update_init (ffesymbol s) +{ + ffebld item; + + if (s->is_init) + return; + + s->is_init = TRUE; + + if ((s->equiv != NULL) + && !ffeequiv_is_init (s->equiv)) + ffeequiv_update_init (s->equiv); + + if ((s->storage != NULL) + && !ffestorag_is_init (s->storage)) + ffestorag_update_init (s->storage); + + if ((s->common != NULL) + && (!ffesymbol_is_init (s->common))) + ffesymbol_update_init (s->common); + + for (item = s->common_list; item != NULL; item = ffebld_trail (item)) + { + if (!ffesymbol_is_init (ffebld_symter (ffebld_head (item)))) + ffesymbol_update_init (ffebld_symter (ffebld_head (item))); + } +} + +/* Update SAVE info to TRUE and all equiv/storage too. + + If SAVE flag is TRUE, does nothing. Else sets it to TRUE and calls + on the ffeequiv and ffestorag modules to update their SAVE flags if + the <s> symbol has those objects, and also updates the common area if + it exists. */ + +void +ffesymbol_update_save (ffesymbol s) +{ + ffebld item; + + if (s->is_save) + return; + + s->is_save = TRUE; + + if ((s->equiv != NULL) + && !ffeequiv_is_save (s->equiv)) + ffeequiv_update_save (s->equiv); + + if ((s->storage != NULL) + && !ffestorag_is_save (s->storage)) + ffestorag_update_save (s->storage); + + if ((s->common != NULL) + && (!ffesymbol_is_save (s->common))) + ffesymbol_update_save (s->common); + + for (item = s->common_list; item != NULL; item = ffebld_trail (item)) + { + if (!ffesymbol_is_save (ffebld_symter (ffebld_head (item)))) + ffesymbol_update_save (ffebld_symter (ffebld_head (item))); + } +} |