403 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			403 lines
		
	
	
	
		
			7.9 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$ */
 | |
| /*	DUMP ROUTINES	*/
 | |
| 
 | |
| #include	"debug.h"
 | |
| 
 | |
| #ifdef	DEBUG
 | |
| #include	"nofloat.h"
 | |
| #include	"nopp.h"
 | |
| #include	"nobitfield.h"
 | |
| #include	"arith.h"
 | |
| #include	"stack.h"
 | |
| #include	"idf.h"
 | |
| #include	"def.h"
 | |
| #include	"type.h"
 | |
| #include	"struct.h"
 | |
| #include	"field.h"
 | |
| #include	"Lpars.h"
 | |
| #include	"label.h"
 | |
| #include	"expr.h"
 | |
| #include	"static.h"
 | |
| 
 | |
| /*	Some routines (symbol2str, token2str, type2str) which should have
 | |
|  *	yielded strings are written to yield a pointer to a transient piece
 | |
|  *	of memory, containing the string, since this is the only reasonable
 | |
|  *	thing to do in C. `Transient' means that the result may soon
 | |
|  *	disappear, which is generally not a problem, since normally it is
 | |
|  *	consumed immediately. Sometimes we need more than one of them, and
 | |
|  *	MAXTRANS is the maximum number we will need simultaneously.
 | |
|  */
 | |
| #define	MAXTRANS	6
 | |
| 
 | |
| extern char options[];
 | |
| 
 | |
| extern char *sprint();
 | |
| 
 | |
| extern struct idf *idf_hashtable[];
 | |
| extern char *symbol2str(), *type2str(), *next_transient();
 | |
| 
 | |
| enum sdef_kind {selector, field};		/* parameter for dumpsdefs */
 | |
| 
 | |
| static int dumplevel;
 | |
| 
 | |
| static
 | |
| newline()	{
 | |
| 	register int dl = dumplevel;
 | |
| 	
 | |
| 	print("\n");
 | |
| 	while (dl >= 2)	{
 | |
| 		print("\t");
 | |
| 		dl -= 2;
 | |
| 	}
 | |
| 	if (dl)
 | |
| 		print("    ");
 | |
| }
 | |
| 
 | |
| dumpidftab(msg, opt)
 | |
| 	char msg[];
 | |
| {
 | |
| 	/*	Dumps the identifier table in readable form (but in
 | |
| 		arbitrary order).
 | |
| 		Unless opt & 1, macros are not dumped.
 | |
| 		Unless opt & 2, reserved identifiers are not dumped.
 | |
| 		Unless opt & 4, universal identifiers are not dumped.
 | |
| 	*/
 | |
| 	int i;
 | |
| 
 | |
| 	print(">>> DUMPIDF, %s (start)", msg);
 | |
| 	dumpstack();
 | |
| 	for (i = 0; i < HASHSIZE; i++)	{
 | |
| 		register struct idf *notch = idf_hashtable[i];
 | |
| 
 | |
| 		while (notch)	{
 | |
| 			dumpidf(notch, opt);
 | |
| 			notch = notch->next;
 | |
| 		}
 | |
| 	}
 | |
| 	newline();
 | |
| 	print(">>> DUMPIDF, %s (end)\n", msg);
 | |
| }
 | |
| 
 | |
| dumpstack()
 | |
| {
 | |
| 	/*	Dumps the identifier stack, starting at the top.
 | |
| 	*/
 | |
| 	register struct stack_level *stl = local_level;
 | |
| 	
 | |
| 	while (stl)	{
 | |
| 		register struct stack_entry *se = stl->sl_entry;
 | |
| 		
 | |
| 		newline();
 | |
| 		print("%3d: ", stl->sl_level);
 | |
| 		while (se)	{
 | |
| 			print("%s ", se->se_idf->id_text);
 | |
| 			se = se->next;
 | |
| 		}
 | |
| 		stl = stl->sl_previous;
 | |
| 	}
 | |
| 	print("\n");
 | |
| }
 | |
| 
 | |
| dumpidf(idf, opt)
 | |
| 	register struct idf *idf;
 | |
| {
 | |
| 	/*	All information about the identifier idf is divulged in a
 | |
| 		hopefully readable format.
 | |
| 	*/
 | |
| 	int started = 0;
 | |
| 	
 | |
| 	if (!idf)
 | |
| 		return;
 | |
| #ifndef NOPP
 | |
| 	if ((opt&1) && idf->id_macro)	{
 | |
| 		if (!started++)	{
 | |
| 			newline();
 | |
| 			print("%s:", idf->id_text);
 | |
| 		}
 | |
| 		print(" macro");
 | |
| 	}
 | |
| #endif NOPP
 | |
| 	if ((opt&2) && idf->id_reserved)	{
 | |
| 		if (!started++)	{
 | |
| 			newline();
 | |
| 			print("%s:", idf->id_text);
 | |
| 		}
 | |
| 		print(" reserved: %d;", idf->id_reserved);
 | |
| 	}
 | |
| 	if (idf->id_def && ((opt&4) || idf->id_def->df_level))	{
 | |
| 		if (!started++)	{
 | |
| 			newline();
 | |
| 			print("%s:", idf->id_text);
 | |
| 		}
 | |
| 		dumpdefs(idf->id_def, opt);
 | |
| 	}
 | |
| 	if (idf->id_sdef)	{
 | |
| 		if (!started++)	{
 | |
| 			newline();
 | |
| 			print("%s:", idf->id_text);
 | |
| 		}
 | |
| 		dumpsdefs(idf->id_sdef, selector);
 | |
| 	}
 | |
| 	if (idf->id_struct)	{
 | |
| 		if (!started++)	{
 | |
| 			newline();
 | |
| 			print("%s:", idf->id_text);
 | |
| 		}
 | |
| 		dumptags(idf->id_struct);
 | |
| 	}
 | |
| 	if (idf->id_enum)	{
 | |
| 		if (!started++)	{
 | |
| 			newline();
 | |
| 			print("%s:", idf->id_text);
 | |
| 		}
 | |
| 		dumptags(idf->id_enum);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| dumpdefs(def, opt)
 | |
| 	register struct def *def;
 | |
| {
 | |
| 	dumplevel++;
 | |
| 	while (def && ((opt&4) || def->df_level))	{
 | |
| 		newline();
 | |
| 		print("L%d: %s %s%s%s%s %lo;",
 | |
| 			def->df_level,
 | |
| 			symbol2str(def->df_sc),
 | |
| 			def->df_initialized ? "init'd " : "",
 | |
| 			def->df_used ? "used " : "",
 | |
| 			type2str(def->df_type),
 | |
| 			def->df_sc == ENUM ? ", =" : " at",
 | |
| 			def->df_address
 | |
| 		);
 | |
| 		def = def->next;
 | |
| 	}
 | |
| 	dumplevel--;
 | |
| }
 | |
| 
 | |
| dumptags(tag)
 | |
| 	register struct tag *tag;
 | |
| {
 | |
| 	dumplevel++;
 | |
| 	while (tag)	{
 | |
| 		register struct type *tp = tag->tg_type;
 | |
| 		register int fund = tp->tp_fund;
 | |
| 
 | |
| 		newline();
 | |
| 		print("L%d: %s %s",
 | |
| 			tag->tg_level,
 | |
| 			fund == STRUCT ? "struct" :
 | |
| 			fund == UNION ? "union" :
 | |
| 			fund == ENUM ? "enum" : "<UNKNOWN>",
 | |
| 			tp->tp_idf->id_text
 | |
| 		);
 | |
| 		if (is_struct_or_union(fund))	{
 | |
| 			print(" {");
 | |
| 			dumpsdefs(tp->tp_sdef, field);
 | |
| 			newline();
 | |
| 			print("}");
 | |
| 		}
 | |
| 		print(";");
 | |
| 		tag = tag->next;
 | |
| 	}
 | |
| 	dumplevel--;
 | |
| }
 | |
| 
 | |
| dumpsdefs(sdef, sdk)
 | |
| 	register struct sdef *sdef;
 | |
| 	enum sdef_kind sdk;
 | |
| {
 | |
| 	/*	Since sdef's are members of two chains, there are actually
 | |
| 		two dumpsdefs's, one following the chain of all selectors
 | |
| 		belonging to the same idf, starting at idf->id_sdef;
 | |
| 		and the other following the chain of all selectors belonging
 | |
| 		to the same struct, starting at stp->tp_sdef.
 | |
| 	*/
 | |
| 
 | |
| 	dumplevel++;
 | |
| 	while (sdef)	{
 | |
| 		newline();
 | |
| 		print("L%d: ", sdef->sd_level);
 | |
| #ifndef NOBITFIELD
 | |
| 		if (sdk == selector)
 | |
| #endif NOBITFIELD
 | |
| 			print("selector %s at offset %lu in %s;",
 | |
| 				type2str(sdef->sd_type),
 | |
| 				sdef->sd_offset, type2str(sdef->sd_stype)
 | |
| 			);
 | |
| #ifndef NOBITFIELD
 | |
| 		else	print("field %s at offset %lu;",
 | |
| 				type2str(sdef->sd_type), sdef->sd_offset
 | |
| 			);
 | |
| #endif NOBITFIELD
 | |
| 		sdef = (sdk == selector ? sdef->next : sdef->sd_sdef);
 | |
| 	}
 | |
| 	dumplevel--;
 | |
| }
 | |
| 
 | |
| char *
 | |
| type2str(tp)
 | |
| 	register struct type *tp;
 | |
| {
 | |
| 	/*	Yields a pointer to a one-line description of the type tp.
 | |
| 	*/
 | |
| 	char *buf = next_transient();
 | |
| 	int ops = 1;
 | |
| 
 | |
| 	buf[0] = '\0';
 | |
| 	if (!tp)	{
 | |
| 		sprint(buf, "<NILTYPE>");
 | |
| 		return buf;
 | |
| 	}
 | |
| 	sprint(buf, "(@%lx, #%ld, &%d) ",
 | |
| 			tp, (long)tp->tp_size, tp->tp_align);
 | |
| 	while (ops)	{
 | |
| 		switch (tp->tp_fund)	{
 | |
| 		case POINTER:
 | |
| 			sprint(buf, "%spointer to ", buf);
 | |
| 			break;
 | |
| 		case ARRAY:
 | |
| 			sprint(buf, "%sarray [%ld] of ", buf, tp->tp_size);
 | |
| 			break;
 | |
| 		case FUNCTION:
 | |
| 			sprint(buf, "%sfunction yielding ", buf);
 | |
| 			break;
 | |
| 		default:
 | |
| 			sprint(buf, "%s%s%s", buf,
 | |
| 					tp->tp_unsigned ? "unsigned " : "",
 | |
| 					symbol2str(tp->tp_fund)
 | |
| 			);
 | |
| 			if (tp->tp_idf)
 | |
| 				sprint(buf, "%s %s", buf,
 | |
| 					tp->tp_idf->id_text);
 | |
| #ifndef NOBITFIELD
 | |
| 			if (tp->tp_field)	{
 | |
| 				struct field *fd = tp->tp_field;
 | |
| 				
 | |
| 				sprint(buf, "%s [s=%ld,w=%ld] of ", buf,
 | |
| 					fd->fd_shift, fd->fd_width);
 | |
| 			}
 | |
| 			else
 | |
| #endif NOBITFIELD
 | |
| 			ops = 0;
 | |
| 			break;
 | |
| 		}
 | |
| 		tp = tp->tp_up;
 | |
| 	}
 | |
| 	return buf;
 | |
| }
 | |
| 
 | |
| GSTATIC char trans_buf[MAXTRANS][300];
 | |
| 
 | |
| char *		/* the ultimate transient buffer supplier */
 | |
| next_transient()
 | |
| {
 | |
| 	static int bnum;
 | |
| 
 | |
| 	if (++bnum == MAXTRANS)
 | |
| 		bnum = 0;
 | |
| 	return trans_buf[bnum];
 | |
| }
 | |
| 
 | |
| print_expr(msg, expr)
 | |
| 	char msg[];
 | |
| 	struct expr *expr;
 | |
| {
 | |
| 	/*	Provisional routine to print an expression preceded by a
 | |
| 		message msg.
 | |
| 	*/
 | |
| 	if (options['x'])	{
 | |
| 		print("\n%s: ", msg);
 | |
| 		print("(L=line, T=type, r/lV=r/lvalue, F=flags, D=depth)\n");
 | |
| 		p1_expr(0, expr);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| p1_expr(lvl, expr)
 | |
| 	register struct expr *expr;
 | |
| {
 | |
| 	extern char *type2str(), *symbol2str();
 | |
| 
 | |
| 	p1_indent(lvl);
 | |
| 	if (!expr)	{
 | |
| 		print("NILEXPR\n");
 | |
| 		return;
 | |
| 	}
 | |
| 	print("expr: L=%u, T=%s, %cV, F=%03o, D=%d, %s: ",
 | |
| 		expr->ex_line,
 | |
| 		type2str(expr->ex_type),
 | |
| 		expr->ex_lvalue ? 'l' : 'r',
 | |
| 		expr->ex_flags & 0xFF,
 | |
| 		expr->ex_depth,
 | |
| 		expr->ex_class == Value ? "Value" :
 | |
| 		expr->ex_class == String ? "String" :
 | |
| #ifndef NOFLOAT
 | |
| 		expr->ex_class == Float ? "Float" :
 | |
| #endif NOFLOAT
 | |
| 		expr->ex_class == Oper ? "Oper" :
 | |
| 		expr->ex_class == Type ? "Type" : "UNKNOWN CLASS"
 | |
| 	);
 | |
| 	switch (expr->ex_class)	{
 | |
| 		struct oper *o;
 | |
| 	case Value:
 | |
| 		switch (expr->VL_CLASS) {
 | |
| 		case Const:
 | |
| 			print("(Const) ");
 | |
| 			break;
 | |
| 		case Name:
 | |
| 			print("(Name) %s + ", expr->VL_IDF->id_text);
 | |
| 			break;
 | |
| 		case Label:
 | |
| 			print("(Label) .%lu + ", expr->VL_LBL);
 | |
| 			break;
 | |
| 		default:
 | |
| 			print("(Unknown) ");
 | |
| 			break;
 | |
| 		}
 | |
| 		print(expr->ex_type->tp_unsigned ? "%lu\n" : "%ld\n",
 | |
| 			expr->VL_VALUE);
 | |
| 		break;
 | |
| 	case String:
 | |
| 	{
 | |
| 		char *bts2str();
 | |
| 
 | |
| 		print(
 | |
| 			"%s\n",
 | |
| 			bts2str(expr->SG_VALUE, expr->SG_LEN, next_transient())
 | |
| 		);
 | |
| 		break;
 | |
| 	}
 | |
| #ifndef NOFLOAT
 | |
| 	case Float:
 | |
| 		print("%s\n", expr->FL_VALUE);
 | |
| 		break;
 | |
| #endif NOFLOAT
 | |
| 	case Oper:
 | |
| 		o = &expr->ex_object.ex_oper;
 | |
| 		print("\n");
 | |
| 		p1_expr(lvl+1, o->op_left);
 | |
| 		p1_indent(lvl);
 | |
| 		print("%s <%s>\n", symbol2str(o->op_oper),
 | |
| 			type2str(o->op_type)
 | |
| 		);
 | |
| 		p1_expr(lvl+1, o->op_right);
 | |
| 		break;
 | |
| 	case Type:
 | |
| 		print("\n");
 | |
| 		break;
 | |
| 	default:
 | |
| 		print("UNKNOWN CLASS\n");
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| p1_indent(lvl)
 | |
| 	register int lvl;
 | |
| {
 | |
| 	while (lvl--)
 | |
| 		print("  ");
 | |
| }
 | |
| #endif	DEBUG
 |