ack/lang/m2/comp/def.c
1986-04-06 17:42:56 +00:00

280 lines
6.4 KiB
C

/* D E F I N I T I O N M E C H A N I S M */
static char *RcsId = "$Header$";
#include <alloc.h>
#include <em_arith.h>
#include <em_label.h>
#include <assert.h>
#include "Lpars.h"
#include "def.h"
#include "type.h"
#include "idf.h"
#include "main.h"
#include "scope.h"
#include "LLlex.h"
#include "node.h"
#include "debug.h"
struct def *h_def; /* Pointer to free list of def structures */
static struct def illegal_def =
{0, 0, 0, -20 /* Illegal scope */, D_ERROR};
struct def *ill_df = &illegal_def;
struct def *
define(id, scope, kind)
register struct idf *id;
struct scope *scope;
{
/* Declare an identifier in a scope, but first check if it
already has been defined. If so, error message.
*/
register struct def *df;
register struct scope *sc;
DO_DEBUG(debug(4,"Defining identifier %s in scope %d", id->id_text, scope->sc_scope));
df = lookup(id, scope->sc_scope);
if ( /* Already in this scope */
df
|| /* A closed scope, and id defined in the pervasive scope */
( CurrentScope == scope
&&
scopeclosed(CurrentScope)
&&
(df = lookup(id, 0)))
) {
switch(df->df_kind) {
case D_PROCHEAD:
if (kind == D_PROCEDURE) {
df->df_kind = D_PROCEDURE;
return df;
}
break;
case D_HIDDEN:
if (kind == D_TYPE && !DefinitionModule) {
df->df_kind = D_HTYPE;
return df;
}
break;
case D_ERROR:
case D_ISEXPORTED:
df->df_kind = kind;
return df;
}
if (kind != D_ERROR) {
error("identifier \"%s\" already declared", id->id_text);
}
return df;
}
df = new_def();
df->df_idf = id;
df->df_scope = scope->sc_scope;
df->df_kind = kind;
df->next = id->id_def;
id->id_def = df;
/* enter the definition in the list of definitions in this scope */
df->df_nextinscope = scope->sc_def;
scope->sc_def = df;
return df;
}
struct def *
lookup(id, scope)
register struct idf *id;
{
/* Look up a definition of an identifier in scope "scope".
Make the "def" list self-organizing.
Return a pointer to its "def" structure if it exists,
otherwise return 0.
*/
register struct def *df, *df1;
df1 = 0;
df = id->id_def;
DO_DEBUG(debug(4,"Looking for identifier %s in scope %d", id->id_text, scope));
while (df) {
if (df->df_scope == scope) {
if (df->df_kind == D_IMPORT) {
df = df->imp_def;
assert(df != 0);
return df;
}
if (df1) {
df1->next = df->next;
df->next = id->id_def;
id->id_def = df;
}
return df;
}
df1 = df;
df = df->next;
}
return 0;
}
Export(ids, qualified)
register struct node *ids;
{
/* From the current scope, the list of identifiers "ids" is
exported. Note this fact. If the export is not qualified, make
all the "ids" visible in the enclosing scope by defining them
in this scope as "imported".
*/
register struct def *df;
while (ids) {
df = define(ids->nd_IDF, CurrentScope, D_ISEXPORTED);
if (qualified) {
df->df_flags |= D_QEXPORTED;
}
else {
df->df_flags |= D_EXPORTED;
df = define(ids->nd_IDF, enclosing(CurrentScope),
D_IMPORT);
}
ids = ids->next;
}
}
Import(ids, idn, local)
register struct node *ids;
struct node *idn;
{
/* "ids" is a list of imported identifiers.
If "idn" is a null-pointer, the identifiers are imported from
the enclosing scope. Otherwise they are imported from the module
indicated by "idn", which must be visible in the enclosing
scope. An exception must be made for imports of the
Compilation Unit.
This case is indicated by the value 0 of the flag "local".
In this case, if "idn" is a null pointer, the "ids" identifiers
are all module identifiers. Their Definition Modules must be
read. Otherwise "idn" is a module identifier whose Definition
Module must be read. "ids" then represents a list of
identifiers defined in this module.
*/
register struct def *df;
register struct idf *id = 0;
int scope;
int kind;
int imp_kind;
#define FROM_MODULE 0
#define FROM_ENCLOSING 1
struct def *lookfor(), *GetDefinitionModule();
if (idn) id = idn->nd_IDF;
kind = D_IMPORT;
scope = enclosing(CurrentScope)->sc_scope;
if (!id) imp_kind = FROM_ENCLOSING;
else {
imp_kind = FROM_MODULE;
if (local) df = lookfor(id, enclosing(CurrentScope), 1);
else df = GetDefinitionModule(id);
if (df->df_kind != D_MODULE) {
/* enter all "ids" with type D_ERROR */
kind = D_ERROR;
if (df->df_kind != D_ERROR) {
node_error(idn, "identifier \"%s\" does not represent a module", id->id_text);
}
}
else scope = df->mod_scope;
}
while (ids) {
if (imp_kind == FROM_MODULE) {
if (!(df = lookup(ids->nd_IDF, scope))) {
node_error(ids, "identifier \"%s\" not declared in qualifying module",
ids->nd_IDF->id_text);
df = ill_df;
}
else
if (!(df->df_flags&(D_EXPORTED|D_QEXPORTED))) {
node_error(ids,"identifier \"%s\" not exported from qualifying module",
ids->nd_IDF->id_text);
}
}
else {
if (local) {
df = lookfor(ids->nd_IDF,
enclosing(CurrentScope), 0);
} else df = GetDefinitionModule(ids->nd_IDF);
if (df->df_kind == D_ERROR) {
node_error(ids, "identifier \"%s\" not visible in enclosing scope",
ids->nd_IDF->id_text);
}
}
define(ids->nd_IDF, CurrentScope, kind)->imp_def = df;
if (df->df_kind == D_TYPE &&
df->df_type->tp_fund == ENUMERATION) {
/* Also import all enumeration literals */
exprt_literals(df->df_type->enm_enums,
CurrentScope);
}
ids = ids->next;
}
}
exprt_literals(df, toscope)
register struct def *df;
register struct scope *toscope;
{
/* A list of enumeration literals is exported. This is implemented
as an import from the scope "toscope".
*/
while (df) {
define(df->df_idf, toscope, D_IMPORT)->imp_def = df;
df = df->enm_next;
}
}
RemImports(pdf)
struct def **pdf;
{
/* Remove all imports from a definition module. This is
neccesary because the implementation module might import
them again.
*/
register struct def *df = *pdf, *df1 = 0;
while (df) {
if (df->df_kind == D_IMPORT) {
RemFromId(df);
if (df1) {
df1->df_nextinscope = df->df_nextinscope;
free_def(df);
df = df1->df_nextinscope;
}
else {
*pdf = df->df_nextinscope;
free_def(df);
df = *pdf;
}
}
else {
df1 = df;
df = df->df_nextinscope;
}
}
}
RemFromId(df)
struct def *df;
{
/* Remove definition "df" from the definition list
*/
register struct idf *id = df->df_idf;
register struct def *df1;
if (id->id_def == df) id->id_def = df->next;
else {
df1 = id->id_def;
while (df1->next != df) {
assert(df1->next != 0);
df1 = df1->next;
}
df1->next = df->next;
}
}