1254 lines
31 KiB
C
1254 lines
31 KiB
C
/* 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)));
|
||
}
|
||
}
|