ack/lang/cem/cemcom/stack.c

282 lines
6.8 KiB
C
Raw Normal View History

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
1986-03-10 13:07:55 +00:00
/* S T A C K / U N S T A C K R O U T I N E S */
#include "lint.h"
#include "nofloat.h"
#include <system.h>
#ifndef LINT
#include <em.h>
#else
#include "l_em.h"
#endif LINT
1986-03-10 13:07:55 +00:00
#include "debug.h"
#include "botch_free.h"
#include <alloc.h>
1986-03-10 13:07:55 +00:00
#include "Lpars.h"
#include "arith.h"
#include "stack.h"
#include "type.h"
#include "idf.h"
#include "def.h"
#include "struct.h"
#include "level.h"
#include "mes.h"
1987-03-25 23:14:43 +00:00
#include "noRoption.h"
1986-03-10 13:07:55 +00:00
extern char options[];
static struct stack_level UniversalLevel;
struct stack_level *local_level = &UniversalLevel;
/* The main reason for having this secondary stacking
mechanism besides the linked lists pointed to by the idf's
is efficiency.
To remove the idf's of a given level, one could scan the
hash table and chase down the idf chains; with a hash
table size of 100 this is feasible, but with a size of say
100000 this becomes painful. Therefore all idf's are also
kept in a stack of sets, one set for each level.
*/
int level; /* Always equal to local_level->sl_level. */
stack_level() {
/* A new level is added on top of the identifier stack.
*/
register struct stack_level *stl = new_stack_level();
register struct stack_level *loclev = local_level;
1986-03-10 13:07:55 +00:00
loclev->sl_next = stl;
stl->sl_previous = loclev;
1986-03-10 13:07:55 +00:00
stl->sl_level = ++level;
stl->sl_max_block = loclev->sl_max_block;
1986-03-10 13:07:55 +00:00
local_level = stl;
#ifdef LINT
lint_start_local();
#endif LINT
1986-03-10 13:07:55 +00:00
}
stack_idf(idf, stl)
struct idf *idf;
register struct stack_level *stl;
1986-03-10 13:07:55 +00:00
{
/* The identifier idf is inserted in the stack on level stl.
*/
register struct stack_entry *se = new_stack_entry();
/* link it into the stack level */
se->next = stl->sl_entry;
se->se_idf = idf;
stl->sl_entry = se;
}
struct stack_level *
stack_level_of(lvl)
{
/* The stack_level corresponding to level lvl is returned.
The stack should probably be an array, to be extended with
realloc where needed.
*/
1987-03-25 23:14:43 +00:00
register struct stack_level *stl;
1986-03-10 13:07:55 +00:00
if (lvl == level)
return local_level;
1987-03-25 23:14:43 +00:00
stl = &UniversalLevel;
1986-03-10 13:07:55 +00:00
1987-03-25 23:14:43 +00:00
while (stl->sl_level != lvl)
stl = stl->sl_next;
return stl;
1986-03-10 13:07:55 +00:00
}
unstack_level()
{
/* The top level of the identifier stack is removed.
*/
struct stack_level *lastlvl;
#ifdef DEBUG
if (options['t'])
dumpidftab("before unstackidfs", 0);
#endif DEBUG
1988-09-16 23:19:50 +00:00
#ifdef LINT
1989-03-06 15:17:39 +00:00
lint_end_local(local_level);
#endif LINT
1986-03-10 13:07:55 +00:00
/* The implementation below is more careful than strictly
necessary. Optimists may optimize it afterwards.
*/
while (local_level->sl_entry) {
register struct stack_entry *se = local_level->sl_entry;
register struct idf *idf = se->se_idf;
register struct def *def;
register struct sdef *sdef;
register struct tag *tag;
/* unlink it from the local stack level */
local_level->sl_entry = se->next;
free_stack_entry(se);
while ((def = idf->id_def) && def->df_level >= level) {
/* unlink it from the def list under the idf block */
if (def->df_sc == LABEL)
unstack_label(idf);
else if (def->df_sc == REGISTER || def->df_sc == AUTO)
FreeLocal(def->df_address);
1986-03-10 13:07:55 +00:00
idf->id_def = def->next;
free_def(def);
update_ahead(idf);
}
1986-03-17 17:47:04 +00:00
while ( (sdef = idf->id_sdef)
&& sdef->sd_level >= level
) {
1986-03-10 13:07:55 +00:00
/* unlink it from the sdef list under the idf block */
idf->id_sdef = sdef->next;
free_sdef(sdef);
}
1986-03-17 17:47:04 +00:00
while ( (tag = idf->id_struct)
&& tag->tg_level >= level
) {
1986-03-10 13:07:55 +00:00
/* unlink it from the struct list under the idf block */
idf->id_struct = tag->next;
free_tag(tag);
}
while ((tag = idf->id_enum) && tag->tg_level >= level) {
/* unlink it from the enum list under the idf block */
idf->id_enum = tag->next;
free_tag(tag);
}
}
/* Unlink the local stack level from the stack.
*/
lastlvl = local_level;
local_level = local_level->sl_previous;
if (level >= L_LOCAL) {
1986-03-17 17:47:04 +00:00
local_level->sl_max_block = lastlvl->sl_max_block;
}
1986-03-10 13:07:55 +00:00
free_stack_level(lastlvl);
local_level->sl_next = (struct stack_level *) 0;
level = local_level->sl_level;
#ifdef DEBUG
if (options['t'])
dumpidftab("after unstackidfs", 0);
#endif DEBUG
}
unstack_world()
{
/* The global level of identifiers is scanned, and final
decisions are taken about such issues as
extern/static/global and un/initialized.
Effects on the code generator: initialised variables
have already been encoded while the uninitialised ones
are not and have to be encoded at this moment.
*/
1986-04-28 09:56:33 +00:00
register struct stack_entry *se = local_level->sl_entry;
1986-03-10 13:07:55 +00:00
#ifdef LINT
1989-03-06 15:17:39 +00:00
lint_end_global(local_level);
#endif LINT
1986-03-10 13:07:55 +00:00
open_name_list();
while (se) {
register struct idf *idf = se->se_idf;
register struct def *def = idf->id_def;
if (!def) {
/* global selectors, etc. */
se = se->next;
continue;
}
#ifdef DEBUG
if (options['a']) {
1986-04-17 14:42:54 +00:00
char *symbol2str();
print("\"%s\", %s, %s, %s, %s\n",
1986-03-10 13:07:55 +00:00
idf->id_text,
(def->df_alloc == 0) ? "no alloc" :
(def->df_alloc == ALLOC_SEEN) ? "alloc seen" :
(def->df_alloc == ALLOC_DONE) ? "alloc done" :
"illegal alloc info",
1986-04-17 14:42:54 +00:00
symbol2str(def->df_sc),
1986-03-10 13:07:55 +00:00
def->df_initialized ? "init" : "no init",
def->df_used ? "used" : "not used");
}
#endif DEBUG
1986-04-28 09:56:33 +00:00
/*
/_* find final storage class *_/
if (def->df_sc == GLOBAL || def->df_sc == IMPLICIT)
/_* even now we still don't know *_/
1986-03-10 13:07:55 +00:00
def->df_sc = EXTERN;
1986-04-28 09:56:33 +00:00
*/
1986-03-10 13:07:55 +00:00
if ( def->df_sc == STATIC
&& def->df_type->tp_fund == FUNCTION
&& !def->df_initialized
) {
/* orphaned static function */
1987-03-25 23:14:43 +00:00
#ifndef NOROPTION
1986-03-10 13:07:55 +00:00
if (options['R'])
warning("static function %s never defined, %s",
idf->id_text,
"changed to extern"
);
1987-03-25 23:14:43 +00:00
#endif
1986-03-10 13:07:55 +00:00
def->df_sc = EXTERN;
}
1986-04-28 09:56:33 +00:00
if (
def->df_alloc == ALLOC_SEEN &&
1986-03-10 13:07:55 +00:00
!def->df_initialized
) {
/* space must be allocated */
bss(idf);
if (def->df_sc != STATIC)
namelist(idf->id_text); /* may be common */
def->df_alloc = ALLOC_DONE; /* see Note below */
1986-03-10 13:07:55 +00:00
}
se = se->next;
}
/* Note:
df_alloc must be set to ALLOC_DONE because the idf entry
1986-04-28 09:56:33 +00:00
may occur several times in the list.
The reason for this is that the same name may be used
for different purposes on the same level, e.g.
1986-04-28 09:56:33 +00:00
struct s {int s;} s;
is a legal definition and contains 3 defining occurrences
of s.
Each definition has been entered into the identifier stack.
1986-04-28 09:56:33 +00:00
Although only one of them concerns a variable, we meet the
s 3 times when scanning the identifier stack.
1986-04-28 09:56:33 +00:00
*/
1986-03-10 13:07:55 +00:00
}
/* A list of potential common names is kept, to be fed to
an understanding loader. The list is written to a file
the name of which is nmlist. If nmlist == NULL, no name
list is generated.
*/
extern char *nmlist; /* BAH! -- main.c */
1986-03-25 10:39:23 +00:00
static File *nfp = 0;
1986-03-10 13:07:55 +00:00
open_name_list()
{
1986-03-25 10:39:23 +00:00
if (nmlist && sys_open(nmlist, OP_WRITE, &nfp) == 0)
fatal("cannot create namelist %s", nmlist);
1986-03-10 13:07:55 +00:00
}
namelist(nm)
char *nm;
{
if (nmlist) {
1986-03-25 10:39:23 +00:00
sys_write(nfp, nm, strlen(nm));
sys_write(nfp, "\n", 1);
1986-03-10 13:07:55 +00:00
}
}