704 lines
16 KiB
C
704 lines
16 KiB
C
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
/* $Header$ */
|
|
/* IDENTIFIER FIDDLING & SYMBOL TABLE HANDLING */
|
|
|
|
#include <em_reg.h>
|
|
#include "nofloat.h"
|
|
#include "debug.h"
|
|
#include "idfsize.h"
|
|
#include "botch_free.h"
|
|
#include "nopp.h"
|
|
#include <alloc.h>
|
|
#include "arith.h"
|
|
#include "align.h"
|
|
#include "LLlex.h"
|
|
#include "level.h"
|
|
#include "stack.h"
|
|
#include "idf.h"
|
|
#include "label.h"
|
|
#include "def.h"
|
|
#include "type.h"
|
|
#include "struct.h"
|
|
#include "declar.h"
|
|
#include "decspecs.h"
|
|
#include "sizes.h"
|
|
#include "Lpars.h"
|
|
#include "assert.h"
|
|
#include "specials.h" /* registration of special identifiers */
|
|
#include "noRoption.h"
|
|
|
|
int idfsize = IDFSIZE;
|
|
extern char options[];
|
|
extern arith NewLocal();
|
|
|
|
char sp_occurred[SP_TOTAL]; /* indicate occurrence of special id */
|
|
|
|
struct idf *idf_hashtable[HASHSIZE];
|
|
/* All identifiers can in principle be reached through
|
|
idf_hashtable; idf_hashtable[hc] is the start of a chain of
|
|
idf's whose tags all hash to hc. Each idf is the start of
|
|
a chain of def's for that idf, sorted according to level,
|
|
with the most recent one on top.
|
|
Any identifier occurring on a level is entered into this
|
|
list, regardless of the nature of its declaration
|
|
(variable, selector, structure tag, etc.).
|
|
*/
|
|
|
|
struct idf *
|
|
idf_hashed(tg, size, hc)
|
|
char *tg;
|
|
int size; /* includes the '\0' character */
|
|
int hc;
|
|
{
|
|
/* The tag tg with length size and known hash value hc is
|
|
looked up in the identifier table; if not found, it is
|
|
entered. A pointer to it is returned.
|
|
The identifier has already been truncated to idfsize
|
|
characters.
|
|
*/
|
|
register struct idf **hook = &idf_hashtable[hc], *notch;
|
|
|
|
while ((notch = *hook)) {
|
|
register cmp = strcmp(tg, notch->id_text);
|
|
|
|
if (cmp < 0)
|
|
break;
|
|
else
|
|
if (cmp == 0) {
|
|
/* suppose that special identifiers, as
|
|
"setjmp", are already inserted
|
|
*/
|
|
sp_occurred[notch->id_special] = 1;
|
|
return notch;
|
|
}
|
|
else
|
|
hook = ¬ch->next;
|
|
}
|
|
/* a new struct idf must be inserted at the hook */
|
|
notch = new_idf();
|
|
notch->next = *hook;
|
|
*hook = notch; /* hooked in */
|
|
notch->id_text = Salloc(tg, (unsigned) size);
|
|
#ifndef NOPP
|
|
notch->id_resmac = 0;
|
|
#endif NOPP
|
|
return notch;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
hash_stat()
|
|
{
|
|
if (options['h']) {
|
|
register int i;
|
|
|
|
print("Hash table tally:\n");
|
|
for (i = 0; i < HASHSIZE; i++) {
|
|
register struct idf *notch = idf_hashtable[i];
|
|
int cnt = 0;
|
|
|
|
while (notch) {
|
|
cnt++;
|
|
notch = notch->next;
|
|
}
|
|
print("%d %d\n", i, cnt);
|
|
}
|
|
print("End hash table tally\n");
|
|
}
|
|
}
|
|
#endif DEBUG
|
|
|
|
struct idf *
|
|
str2idf(tg)
|
|
char tg[];
|
|
{
|
|
/* str2idf() returns an entry in the symbol table for the
|
|
identifier tg. If necessary, an entry is created.
|
|
It is used where the text of the identifier is available
|
|
but its hash value is not; otherwise idf_hashed() is to
|
|
be used.
|
|
*/
|
|
register char *cp = tg;
|
|
register int hash;
|
|
register int pos = -1;
|
|
register int ch;
|
|
char ntg[IDFSIZE + 1];
|
|
register char *ncp = ntg;
|
|
|
|
hash = STARTHASH();
|
|
while (++pos < idfsize && (ch = *cp++)) {
|
|
*ncp++ = ch;
|
|
hash = ENHASH(hash, ch, pos);
|
|
}
|
|
hash = STOPHASH(hash);
|
|
*ncp++ = '\0';
|
|
return idf_hashed(ntg, ncp - ntg, hash);
|
|
}
|
|
|
|
struct idf *
|
|
gen_idf()
|
|
{
|
|
/* A new idf is created out of nowhere, to serve as an
|
|
anonymous name.
|
|
*/
|
|
static int name_cnt;
|
|
char buff[100];
|
|
char *sprint();
|
|
|
|
sprint(buff, "#%d in %s, line %u",
|
|
++name_cnt, dot.tk_file, dot.tk_line);
|
|
return str2idf(buff);
|
|
}
|
|
|
|
int
|
|
is_anon_idf(idf)
|
|
struct idf *idf;
|
|
{
|
|
return idf->id_text[0] == '#';
|
|
}
|
|
|
|
declare_idf(ds, dc, lvl)
|
|
struct decspecs *ds;
|
|
struct declarator *dc;
|
|
{
|
|
/* The identifier inside dc is declared on the level lvl, with
|
|
properties deduced from the decspecs ds and the declarator
|
|
dc.
|
|
The level is given explicitly to be able to insert, e.g.,
|
|
labels on the outermost level inside the function.
|
|
This routine implements the rich semantics of C
|
|
declarations.
|
|
*/
|
|
register struct idf *idf = dc->dc_idf;
|
|
register int sc = ds->ds_sc;
|
|
/* This local copy is essential:
|
|
char b(), c;
|
|
makes b GLOBAL and c AUTO.
|
|
*/
|
|
register struct def *def = idf->id_def; /* may be NULL */
|
|
register struct type *type;
|
|
struct stack_level *stl = stack_level_of(lvl);
|
|
char formal_array = 0;
|
|
|
|
/* determine the present type */
|
|
if (ds->ds_type == 0) {
|
|
/* at the L_FORMAL1 level there is no type specified yet
|
|
*/
|
|
ASSERT(lvl == L_FORMAL1);
|
|
type = int_type; /* may change at L_FORMAL2 */
|
|
}
|
|
else {
|
|
/* combine the decspecs and the declarator into one type */
|
|
type = declare_type(ds->ds_type, dc);
|
|
if (type->tp_size <= (arith)0 &&
|
|
actual_declaration(sc, type)) {
|
|
if (type->tp_size == (arith) -1) {
|
|
/* the type is not yet known,
|
|
but it has to be:
|
|
*/
|
|
extern char *symbol2str();
|
|
error("unknown %s-type",
|
|
symbol2str(type->tp_fund));
|
|
}
|
|
else if (type->tp_fund != LABEL) {
|
|
/* CJ */
|
|
warning("%s has size 0", idf->id_text);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* some additional work for formal definitions */
|
|
if (lvl == L_FORMAL2) {
|
|
switch (type->tp_fund) {
|
|
case FUNCTION:
|
|
warning("%s is a function; cannot be formal",
|
|
idf->id_text);
|
|
type = construct_type(POINTER, type, (arith)0);
|
|
break;
|
|
case ARRAY: /* RM 10.1 */
|
|
type = construct_type(POINTER, type->tp_up, (arith)0);
|
|
formal_array = 1;
|
|
break;
|
|
#ifndef NOFLOAT
|
|
case FLOAT: /* RM 10.1 */
|
|
type = double_type;
|
|
break;
|
|
#endif NOFLOAT
|
|
case CHAR:
|
|
case SHORT:
|
|
/* The RM is not clear about this: we must
|
|
convert the parameter from int (they have
|
|
been pushed as ints) to the specified type.
|
|
The conversion to type int or uint is not
|
|
allowed.
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
/* The tests on types, postponed from do_decspecs(), can now
|
|
be performed.
|
|
*/
|
|
/* update the storage class */
|
|
if (type && type->tp_fund == FUNCTION) {
|
|
if (sc == 0 || (ds->ds_sc_given && sc == AUTO)) /* RM 8.1 */
|
|
sc = GLOBAL;
|
|
else
|
|
if (sc == REGISTER) {
|
|
error("function has illegal storage class");
|
|
ds->ds_sc = sc = GLOBAL;
|
|
}
|
|
}
|
|
else /* non-FUNCTION */
|
|
if (sc == 0)
|
|
sc = lvl == L_GLOBAL ? GLOBAL
|
|
: lvl == L_FORMAL1 || lvl == L_FORMAL2 ? FORMAL
|
|
: AUTO;
|
|
#ifndef NOROPTION
|
|
if (options['R']) { /* some special K & R tests */
|
|
/* is it also an enum? */
|
|
if (idf->id_enum && idf->id_enum->tg_level == level)
|
|
warning("%s is also an enum tag", idf->id_text);
|
|
/* is it a universal typedef? */
|
|
if (def && def->df_level == L_UNIVERSAL)
|
|
warning("redeclaring reserved word %s", idf->id_text);
|
|
}
|
|
#endif
|
|
if (def &&
|
|
( def->df_level == lvl ||
|
|
( lvl != L_GLOBAL && def->df_level > lvl )
|
|
)
|
|
) {
|
|
/* There is already a declaration for idf on this
|
|
level, or even more inside.
|
|
The rules differ for different levels.
|
|
*/
|
|
switch (lvl) {
|
|
case L_GLOBAL:
|
|
global_redecl(idf, sc, type);
|
|
break;
|
|
case L_FORMAL1: /* formal declaration */
|
|
error("formal %s redeclared", idf->id_text);
|
|
break;
|
|
case L_FORMAL2: /* formal definition */
|
|
default: /* local */
|
|
error("%s redeclared", idf->id_text);
|
|
break;
|
|
}
|
|
}
|
|
else /* the idf is unknown on this level */
|
|
if (lvl == L_FORMAL2 && sc != ENUM && good_formal(def, idf)) {
|
|
/* formal declaration, update only */
|
|
def->df_type = type;
|
|
def->df_formal_array = formal_array;
|
|
def->df_sc = sc;
|
|
def->df_level = L_FORMAL2; /* CJ */
|
|
}
|
|
else
|
|
if ( lvl >= L_LOCAL &&
|
|
(type->tp_fund == FUNCTION || sc == EXTERN)
|
|
) {
|
|
/* extern declaration inside function is treated the
|
|
same way as global extern declaration
|
|
*/
|
|
#ifndef NOROPTION
|
|
if ( options['R'] &&
|
|
(sc == STATIC && type->tp_fund == FUNCTION)
|
|
)
|
|
if (!is_anon_idf(idf))
|
|
warning("non-global static function %s",
|
|
idf->id_text);
|
|
#endif
|
|
declare_idf(ds, dc, L_GLOBAL);
|
|
}
|
|
else { /* fill in the def block */
|
|
register struct def *newdef = new_def();
|
|
|
|
newdef->next = def;
|
|
newdef->df_level = lvl;
|
|
newdef->df_type = type;
|
|
newdef->df_sc = sc;
|
|
/* link it into the name list in the proper place */
|
|
idf->id_def = newdef;
|
|
update_ahead(idf);
|
|
stack_idf(idf, stl);
|
|
/* We now calculate the address.
|
|
Globals have names and don't get addresses, they
|
|
get numbers instead (through data_label()).
|
|
Formals are handled by declare_formals().
|
|
So here we hand out local addresses only.
|
|
*/
|
|
if (lvl >= L_LOCAL) {
|
|
ASSERT(sc);
|
|
switch (sc) {
|
|
case REGISTER:
|
|
case AUTO:
|
|
if (type->tp_size == (arith)-1) {
|
|
error("size of local %s unknown",
|
|
idf->id_text);
|
|
/** type = idf->id_def->df_type = int_type; **/
|
|
}
|
|
newdef->df_address =
|
|
NewLocal(type->tp_size,
|
|
type->tp_align,
|
|
regtype(type),
|
|
(sc == REGISTER) ? REG_BONUS
|
|
: REG_DEFAULT
|
|
);
|
|
break;
|
|
case STATIC:
|
|
newdef->df_address = (arith) data_label();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
actual_declaration(sc, tp)
|
|
int sc;
|
|
struct type *tp;
|
|
{
|
|
/* An actual_declaration needs space, right here and now.
|
|
*/
|
|
register int fund = tp->tp_fund;
|
|
|
|
if (sc == ENUM || sc == TYPEDEF) /* virtual declarations */
|
|
return 0;
|
|
if (fund == FUNCTION || fund == ARRAY)
|
|
/* allocation solved in other ways */
|
|
return 0;
|
|
/* to be allocated */
|
|
return 1;
|
|
}
|
|
|
|
global_redecl(idf, new_sc, tp)
|
|
register struct idf *idf;
|
|
register struct type *tp;
|
|
{
|
|
/* A global identifier may be declared several times,
|
|
provided the declarations do not conflict; they might
|
|
conflict in type (or supplement each other in the case of
|
|
an array) or they might conflict or supplement each other
|
|
in storage class.
|
|
*/
|
|
register struct def *def = idf->id_def;
|
|
|
|
if (tp != def->df_type) {
|
|
register struct type *otp = def->df_type;
|
|
if ( tp->tp_fund != ARRAY || otp->tp_fund != ARRAY ||
|
|
tp->tp_up != otp->tp_up
|
|
) {
|
|
error("redeclaration of %s with different type",
|
|
idf->id_text);
|
|
return;
|
|
}
|
|
/* Multiple array declaration; this may be interesting */
|
|
if (tp->tp_size < 0) { /* new decl has [] */
|
|
/* nothing new */
|
|
}
|
|
else
|
|
if (otp->tp_size < 0) { /* old decl has [] */
|
|
def->df_type = tp;
|
|
}
|
|
else
|
|
if (tp->tp_size != otp->tp_size)
|
|
error("inconsistent size in redeclaration of array %s",
|
|
idf->id_text);
|
|
}
|
|
/* Now we may be able to update the storage class.
|
|
Clean out this mess as soon as we know all the possibilities
|
|
for new_sc.
|
|
For now we have:
|
|
EXTERN: we have seen the word "extern"
|
|
GLOBAL: the item was declared on the outer
|
|
level, without either "extern" or
|
|
"static".
|
|
STATIC: we have seen the word "static"
|
|
IMPLICIT: function declaration inferred from
|
|
call
|
|
*/
|
|
if (new_sc == IMPLICIT)
|
|
return; /* no new information */
|
|
switch (def->df_sc) { /* the old storage class */
|
|
case EXTERN:
|
|
switch (new_sc) { /* the new storage class */
|
|
case EXTERN:
|
|
case GLOBAL:
|
|
break;
|
|
case STATIC:
|
|
if (def->df_initialized) {
|
|
error("cannot redeclare %s to static",
|
|
idf->id_text);
|
|
}
|
|
else {
|
|
warning("%s redeclared to static",
|
|
idf->id_text);
|
|
}
|
|
def->df_sc = new_sc;
|
|
break;
|
|
default:
|
|
crash("bad storage class");
|
|
break;
|
|
}
|
|
break;
|
|
case GLOBAL:
|
|
switch (new_sc) { /* the new storage class */
|
|
case EXTERN:
|
|
def->df_sc = EXTERN;
|
|
break;
|
|
case GLOBAL:
|
|
break;
|
|
case STATIC:
|
|
if (def->df_initialized)
|
|
error("cannot redeclare %s to static",
|
|
idf->id_text);
|
|
else {
|
|
#ifndef NOROPTION
|
|
if (options['R'])
|
|
warning("%s redeclared to static",
|
|
idf->id_text);
|
|
#endif
|
|
def->df_sc = STATIC;
|
|
}
|
|
break;
|
|
default:
|
|
crash("bad storage class");
|
|
break;
|
|
}
|
|
break;
|
|
case STATIC:
|
|
switch (new_sc) { /* the new storage class */
|
|
case EXTERN:
|
|
if (def->df_initialized)
|
|
error("cannot redeclare %s to extern",
|
|
idf->id_text);
|
|
else {
|
|
warning("%s redeclared to extern",
|
|
idf->id_text);
|
|
def->df_sc = EXTERN;
|
|
}
|
|
break;
|
|
case GLOBAL:
|
|
case STATIC:
|
|
if (def->df_type->tp_fund != FUNCTION)
|
|
warning("%s was already static",
|
|
idf->id_text);
|
|
break;
|
|
default:
|
|
crash("bad storage class");
|
|
break;
|
|
}
|
|
break;
|
|
case IMPLICIT:
|
|
switch (new_sc) { /* the new storage class */
|
|
case EXTERN:
|
|
case GLOBAL:
|
|
def->df_sc = new_sc;
|
|
break;
|
|
case STATIC:
|
|
#ifndef NOROPTION
|
|
if (options['R'])
|
|
warning("%s was implicitly declared as extern",
|
|
idf->id_text);
|
|
#endif
|
|
def->df_sc = new_sc;
|
|
break;
|
|
default:
|
|
crash("bad storage class");
|
|
break;
|
|
}
|
|
break;
|
|
case ENUM:
|
|
case TYPEDEF:
|
|
error("illegal redeclaration of %s", idf->id_text);
|
|
break;
|
|
default:
|
|
crash("bad storage class");
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
good_formal(def, idf)
|
|
register struct def *def;
|
|
register struct idf *idf;
|
|
{
|
|
/* Succeeds if def is a proper L_FORMAL1 definition and
|
|
gives an error message otherwise.
|
|
*/
|
|
if (!def || def->df_level != L_FORMAL1) { /* not in parameter list */
|
|
if (!is_anon_idf(idf))
|
|
error("%s not in parameter list", idf->id_text);
|
|
return 0;
|
|
}
|
|
ASSERT(def->df_sc == FORMAL); /* CJ */
|
|
return 1;
|
|
}
|
|
|
|
declare_params(dc)
|
|
register struct declarator *dc;
|
|
{
|
|
/* Declares the formal parameters if they exist.
|
|
*/
|
|
register struct formal *fm = dc->dc_formal;
|
|
|
|
while (fm) {
|
|
declare_parameter(fm->fm_idf);
|
|
fm = fm->next;
|
|
}
|
|
free_formals(dc->dc_formal);
|
|
dc->dc_formal = 0;
|
|
}
|
|
|
|
init_idf(idf)
|
|
register struct idf *idf;
|
|
{
|
|
/* The topmost definition of idf is set to initialized.
|
|
*/
|
|
register struct def *def = idf->id_def; /* the topmost */
|
|
|
|
if (def->df_initialized)
|
|
error("multiple initialization of %s", idf->id_text);
|
|
if (def->df_sc == TYPEDEF) {
|
|
warning("typedef cannot be initialized");
|
|
def->df_sc = EXTERN; /* ??? *//* What else ? */
|
|
}
|
|
def->df_initialized = 1;
|
|
}
|
|
|
|
declare_parameter(idf)
|
|
struct idf *idf;
|
|
{
|
|
/* idf is declared as a formal.
|
|
*/
|
|
add_def(idf, FORMAL, int_type, level);
|
|
}
|
|
|
|
declare_enum(tp, idf, l)
|
|
struct type *tp;
|
|
struct idf *idf;
|
|
arith l;
|
|
{
|
|
/* idf is declared as an enum constant with value l.
|
|
*/
|
|
add_def(idf, ENUM, tp, level);
|
|
idf->id_def->df_address = l;
|
|
}
|
|
|
|
declare_formals(fp)
|
|
arith *fp;
|
|
{
|
|
/* Declares those formals as int that haven't been declared
|
|
by the user.
|
|
An address is assigned to each formal parameter.
|
|
The total size of the formals is returned in *fp;
|
|
*/
|
|
register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
|
|
arith f_offset = (arith)0;
|
|
|
|
#ifdef DEBUG
|
|
if (options['t'])
|
|
dumpidftab("start declare_formals", 0);
|
|
#endif DEBUG
|
|
while (se) {
|
|
register struct def *def = se->se_idf->id_def;
|
|
|
|
def->df_address = f_offset;
|
|
/* the alignment convention for parameters is: align on
|
|
word boundaries, i.e. take care that the following
|
|
parameter starts on a new word boundary.
|
|
*/
|
|
f_offset = align(f_offset + def->df_type->tp_size, (int) word_size);
|
|
formal_cvt(def); /* cvt int to char or short, if necessary */
|
|
se = se->next;
|
|
def->df_level = L_FORMAL2; /* CJ */
|
|
RegisterAccount(def->df_address, def->df_type->tp_size,
|
|
regtype(def->df_type),
|
|
(def->df_sc == REGISTER ? REG_BONUS
|
|
: REG_DEFAULT)
|
|
);
|
|
}
|
|
*fp = f_offset;
|
|
}
|
|
|
|
int
|
|
regtype(tp)
|
|
struct type *tp;
|
|
{
|
|
switch(tp->tp_fund) {
|
|
case INT:
|
|
return reg_any;
|
|
#ifndef NOFLOAT
|
|
case FLOAT:
|
|
case DOUBLE:
|
|
return reg_float;
|
|
#endif NOFLOAT
|
|
case POINTER:
|
|
return reg_pointer;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
add_def(idf, sc, tp, lvl)
|
|
struct idf *idf;
|
|
struct type *tp;
|
|
int lvl;
|
|
int sc;
|
|
{
|
|
/* The identifier idf is declared on level lvl with storage
|
|
class sc and type tp, through a faked C declaration.
|
|
This is probably the wrong way to structure the problem,
|
|
but it will have to do for the time being.
|
|
*/
|
|
struct decspecs Ds; struct declarator Dc;
|
|
|
|
Ds = null_decspecs;
|
|
Ds.ds_type = tp;
|
|
Ds.ds_sc = sc;
|
|
Dc = null_declarator;
|
|
Dc.dc_idf = idf;
|
|
declare_idf(&Ds, &Dc, lvl);
|
|
}
|
|
|
|
update_ahead(idf)
|
|
register struct idf *idf;
|
|
{
|
|
/* The tk_symb of the token ahead is updated in the light of new
|
|
information about the identifier idf.
|
|
*/
|
|
register int tk_symb = AHEAD;
|
|
|
|
if ( (tk_symb == IDENTIFIER || tk_symb == TYPE_IDENTIFIER) &&
|
|
ahead.tk_idf == idf
|
|
)
|
|
AHEAD = idf->id_def && idf->id_def->df_sc == TYPEDEF ?
|
|
TYPE_IDENTIFIER : IDENTIFIER;
|
|
}
|
|
|
|
free_formals(fm)
|
|
register struct formal *fm;
|
|
{
|
|
while (fm) {
|
|
struct formal *tmp = fm->next;
|
|
|
|
free_formal(fm);
|
|
fm = tmp;
|
|
}
|
|
}
|
|
|
|
char hmask[IDFSIZE];
|
|
|
|
init_hmask()
|
|
{
|
|
/* A simple congruence random number generator, as
|
|
described in Knuth, vol 2.
|
|
*/
|
|
register int h, rnd = HASH_X;
|
|
|
|
for (h = 0; h < IDFSIZE; h++) {
|
|
hmask[h] = rnd;
|
|
rnd = (HASH_A * rnd + HASH_C) & HASHMASK;
|
|
}
|
|
}
|