| /* Implementation of Fortran symbol manager |
| Copyright (C) 1995, 1996, 1997, 2003 |
| Free Software Foundation, Inc. |
| Contributed by James Craig Burley. |
| |
| 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. */ |
| |
| /* Would be good to understand why PROGUNIT in this case too. |
| (1995-08-22). */ |
| #define FFESYMBOL_globalCURRENT_ FFESYMBOL_globalPROGUNIT_ |
| |
| /* 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 const char *const ffesymbol_state_name_[] = |
| { |
| "?", |
| "@", |
| "&", |
| "$", |
| }; |
| |
| /* List of attribute names. */ |
| |
| static const char *const 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_ (void) |
| { |
| 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 = 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; |
| s->hook = FFECOM_symbolNULL; |
| 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; |
| s->assigned = FALSE; |
| |
| ffename_set_symbol (n, s); |
| |
| if (!ffesymbol_retractable_) |
| { |
| s->have_old = FALSE; |
| return s; |
| } |
| |
| r = 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. */ |
| |
| const 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) (ffesymbol)) |
| { |
| 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) (ffesymbol)) |
| { |
| ffename_space_drive_symbol (ffesymbol_sfunc_, fn); |
| } |
| |
| /* 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 (void) |
| { |
| 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 (void) |
| { |
| #if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalFILE_ |
| ffesymbol_global_ = ffename_space_new (ffe_pool_file ()); |
| #endif |
| } |
| |
| void |
| ffesymbol_init_2 (void) |
| { |
| } |
| |
| void |
| ffesymbol_init_3 (void) |
| { |
| #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 (void) |
| { |
| 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); |
| } |
| |
| /* 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 (void) |
| { |
| 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 = malloc_new_kp (ffesymbol_retract_pool_, "FFESYMBOL retract", |
| sizeof (*r)); |
| r->next = NULL; |
| r->command = FFESYMBOL_retractcommandRETRACT_; |
| r->live = s; |
| r->symbol = sym = 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. */ |
| |
| const char * |
| ffesymbol_state_string (ffesymbolState state) |
| { |
| if (state >= ARRAY_SIZE (ffesymbol_state_name_)) |
| return "?\?\?"; |
| return ffesymbol_state_name_[state]; |
| } |
| |
| void |
| ffesymbol_terminate_0 (void) |
| { |
| } |
| |
| void |
| ffesymbol_terminate_1 (void) |
| { |
| #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 (void) |
| { |
| #if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_ |
| ffesymbol_kill_manifest_ (); |
| #endif |
| } |
| |
| void |
| ffesymbol_terminate_3 (void) |
| { |
| #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 (void) |
| { |
| 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))); |
| } |
| } |