*** empty log message ***
This commit is contained in:
280
lang/cem/cemcom/stack.c
Normal file
280
lang/cem/cemcom/stack.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/* DERIVED FROM $Header$ */
|
||||
/* S T A C K / U N S T A C K R O U T I N E S */
|
||||
|
||||
#include "debug.h"
|
||||
#include "use_tmp.h"
|
||||
#include "botch_free.h"
|
||||
|
||||
#include "system.h"
|
||||
#include "alloc.h"
|
||||
#include "Lpars.h"
|
||||
#include "arith.h"
|
||||
#include "stack.h"
|
||||
#include "type.h"
|
||||
#include "idf.h"
|
||||
#include "def.h"
|
||||
#include "struct.h"
|
||||
#include "storage.h"
|
||||
#include "level.h"
|
||||
#include "mes.h"
|
||||
#include "em.h"
|
||||
|
||||
/* #include <em_reg.h> */
|
||||
|
||||
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.
|
||||
*/
|
||||
struct stack_level *stl = new_stack_level();
|
||||
|
||||
clear((char *)stl, sizeof(struct stack_level));
|
||||
local_level->sl_next = stl;
|
||||
stl->sl_previous = local_level;
|
||||
stl->sl_level = ++level;
|
||||
stl->sl_local_offset = stl->sl_max_block = local_level->sl_local_offset;
|
||||
local_level = stl;
|
||||
}
|
||||
|
||||
stack_idf(idf, stl)
|
||||
struct idf *idf;
|
||||
struct stack_level *stl;
|
||||
{
|
||||
/* The identifier idf is inserted in the stack on level stl.
|
||||
*/
|
||||
register struct stack_entry *se = new_stack_entry();
|
||||
|
||||
clear((char *)se, sizeof(struct 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.
|
||||
*/
|
||||
if (lvl == level)
|
||||
return local_level;
|
||||
else {
|
||||
register struct stack_level *stl = &UniversalLevel;
|
||||
|
||||
while (stl->sl_level != lvl)
|
||||
stl = stl->sl_next;
|
||||
return stl;
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
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
|
||||
/* 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 (level == L_LOCAL || level == L_FORMAL1) {
|
||||
if ( def->df_register != REG_NONE &&
|
||||
def->df_sc != STATIC &&
|
||||
options['n'] == 0
|
||||
) {
|
||||
int reg;
|
||||
|
||||
switch (def->df_type->tp_fund) {
|
||||
|
||||
case POINTER:
|
||||
reg = reg_pointer;
|
||||
break;
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
reg = reg_float;
|
||||
break;
|
||||
default:
|
||||
reg = reg_any;
|
||||
break;
|
||||
}
|
||||
C_ms_reg(def->df_address,
|
||||
def->df_type->tp_size,
|
||||
reg, def->df_register
|
||||
);
|
||||
}
|
||||
}
|
||||
idf->id_def = def->next;
|
||||
free_def(def);
|
||||
update_ahead(idf);
|
||||
}
|
||||
while ((sdef = idf->id_sdef) && sdef->sd_level >= level) {
|
||||
/* unlink it from the sdef list under the idf block */
|
||||
idf->id_sdef = sdef->next;
|
||||
free_sdef(sdef);
|
||||
}
|
||||
while ((tag = idf->id_struct) && tag->tg_level >= level) {
|
||||
/* 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 && lastlvl->sl_max_block < local_level->sl_max_block)
|
||||
local_level->sl_max_block = lastlvl->sl_max_block;
|
||||
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.
|
||||
*/
|
||||
struct stack_entry *se = local_level->sl_entry;
|
||||
|
||||
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']) {
|
||||
printf("\"%s\", %s, %s, %s\n",
|
||||
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",
|
||||
def->df_initialized ? "init" : "no init",
|
||||
def->df_used ? "used" : "not used");
|
||||
}
|
||||
#endif DEBUG
|
||||
/* find final storage class */
|
||||
if (def->df_sc == GLOBAL || def->df_sc == IMPLICIT) {
|
||||
/* even now we still don't know */
|
||||
def->df_sc = EXTERN;
|
||||
}
|
||||
|
||||
if ( def->df_sc == STATIC
|
||||
&& def->df_type->tp_fund == FUNCTION
|
||||
&& !def->df_initialized
|
||||
) {
|
||||
/* orphaned static function */
|
||||
if (options['R'])
|
||||
warning("static function %s never defined, %s",
|
||||
idf->id_text,
|
||||
"changed to extern"
|
||||
);
|
||||
def->df_sc = EXTERN;
|
||||
}
|
||||
|
||||
if ( def->df_alloc == ALLOC_SEEN &&
|
||||
!def->df_initialized
|
||||
) {
|
||||
/* space must be allocated */
|
||||
bss(idf);
|
||||
namelist(idf->id_text); /* may be common */
|
||||
def->df_alloc = ALLOC_DONE;
|
||||
/* df_alloc must be set to ALLOC_DONE because
|
||||
the idf entry may occur several times in
|
||||
the list.
|
||||
The reason is that the same name may be used
|
||||
for different purposes on the same level, e.g
|
||||
struct s {int s;} s;
|
||||
is a legal definition and contains 3 defining
|
||||
occurrences of s. Each definition has been
|
||||
entered into the idfstack. Although only
|
||||
one of them concerns a variable, we meet the
|
||||
s 3 times when scanning the idfstack.
|
||||
*/
|
||||
}
|
||||
se = se->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
static int nfd;
|
||||
|
||||
open_name_list()
|
||||
{
|
||||
if (nmlist) {
|
||||
if ((nfd = sys_creat(nmlist, 0644)) < 0) {
|
||||
fatal("cannot create namelist %s", nmlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namelist(nm)
|
||||
char *nm;
|
||||
{
|
||||
if (nmlist) {
|
||||
sys_write(nfd, nm, strlen(nm));
|
||||
sys_write(nfd, "\n", 1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user