279 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			279 lines
		
	
	
	
		
			6.8 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$ */
 | |
| /*	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>
 | |
| #include	<em.h>
 | |
| #include	"debug.h"
 | |
| #include	"botch_free.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	"level.h"
 | |
| #include	"mes.h"
 | |
| #include	"noRoption.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.
 | |
| 	*/
 | |
| 	register struct stack_level *stl = new_stack_level();
 | |
| 	register struct stack_level *loclev = local_level;
 | |
| 	
 | |
| 	loclev->sl_next = stl;
 | |
| 	stl->sl_previous = loclev;
 | |
| 	stl->sl_level = ++level;
 | |
| 	stl->sl_max_block = loclev->sl_max_block;
 | |
| 	local_level = stl;
 | |
| #ifdef	LINT
 | |
| 	lint_start_local();
 | |
| #endif	LINT
 | |
| }
 | |
| 
 | |
| stack_idf(idf, stl)
 | |
| 	struct idf *idf;
 | |
| 	register struct stack_level *stl;
 | |
| {
 | |
| 	/*	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.
 | |
| 	*/
 | |
| 	register struct stack_level *stl;
 | |
| 
 | |
| 	if (lvl == level)
 | |
| 		return local_level;
 | |
| 	stl = &UniversalLevel;
 | |
| 		
 | |
| 	while (stl->sl_level != lvl)
 | |
| 		stl = stl->sl_next;
 | |
| 	return stl;
 | |
| }
 | |
| 
 | |
| 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
 | |
| 
 | |
| #ifdef	LINT
 | |
| 	lint_end_local(local_level);
 | |
| #endif	LINT
 | |
| 
 | |
| 	/*	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);
 | |
| 			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)	{
 | |
| 		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.
 | |
| 	*/
 | |
| 	register struct stack_entry *se = local_level->sl_entry;
 | |
| 
 | |
| #ifdef	LINT
 | |
| 	lint_end_global(local_level);
 | |
| #endif	LINT
 | |
| 
 | |
| 	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']) {
 | |
| 			char *symbol2str();
 | |
| 
 | |
| 			print("\"%s\", %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",
 | |
| 				symbol2str(def->df_sc),
 | |
| 				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 */
 | |
| #ifndef NOROPTION
 | |
| 			if (options['R'])
 | |
| 				warning("static function %s never defined, %s",
 | |
| 					idf->id_text,
 | |
| 					"changed to extern"
 | |
| 				);
 | |
| #endif
 | |
| 			def->df_sc = EXTERN;
 | |
| 		}
 | |
| 		
 | |
| 		if (
 | |
| 			def->df_alloc == ALLOC_SEEN &&
 | |
| 			!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 */
 | |
| 		}
 | |
| 		se = se->next;
 | |
| 	}
 | |
| 	/*	Note:
 | |
| 		df_alloc must be set to ALLOC_DONE because the idf entry
 | |
| 		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.
 | |
| 			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.
 | |
| 		Although only one of them concerns a variable, we meet the
 | |
| 		s 3 times when scanning the identifier stack.
 | |
| 	*/
 | |
| }
 | |
| 
 | |
| /*	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 File *nfp = 0;
 | |
| 
 | |
| open_name_list()
 | |
| {
 | |
| 	if (nmlist && sys_open(nmlist, OP_WRITE, &nfp) == 0)
 | |
| 		fatal("cannot create namelist %s", nmlist);
 | |
| }
 | |
| 
 | |
| namelist(nm)
 | |
| 	char *nm;
 | |
| {
 | |
| 	if (nmlist)	{
 | |
| 		sys_write(nfp, nm, strlen(nm));
 | |
| 		sys_write(nfp, "\n", 1);
 | |
| 	}
 | |
| }
 |