624 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			624 lines
		
	
	
	
		
			15 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$ */
 | 
						|
/* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */
 | 
						|
 | 
						|
#include	"nofloat.h"
 | 
						|
#include	<em.h>
 | 
						|
#include	"debug.h"
 | 
						|
#include	<alloc.h>
 | 
						|
#include	"nobitfield.h"
 | 
						|
#include	"arith.h"
 | 
						|
#include	"align.h"
 | 
						|
#include	"label.h"
 | 
						|
#include	"expr.h"
 | 
						|
#include	"type.h"
 | 
						|
#include	"struct.h"
 | 
						|
#include	"field.h"
 | 
						|
#include	"assert.h"
 | 
						|
#include	"Lpars.h"
 | 
						|
#include	"class.h"
 | 
						|
#include	"sizes.h"
 | 
						|
#include	"idf.h"
 | 
						|
#include	"level.h"
 | 
						|
#include	"def.h"
 | 
						|
 | 
						|
#define con_nullbyte()	C_con_ucon("0", (arith)1)
 | 
						|
 | 
						|
char *symbol2str();
 | 
						|
char *long2str();
 | 
						|
char *strncpy();
 | 
						|
struct expr *do_array(), *do_struct(), *IVAL();
 | 
						|
extern char options[];
 | 
						|
 | 
						|
/*	do_ival() performs the initialisation of a global variable
 | 
						|
	of type tp with the initialisation expression expr by calling IVAL().
 | 
						|
	Guided by type tp, the expression is evaluated.
 | 
						|
*/
 | 
						|
do_ival(tpp, ex)
 | 
						|
	struct type **tpp;
 | 
						|
	struct expr *ex;
 | 
						|
{
 | 
						|
	if (IVAL(tpp, ex) != 0)
 | 
						|
		too_many_initialisers(ex);
 | 
						|
}
 | 
						|
 | 
						|
/*	IVAL() recursively guides the initialisation expression through the
 | 
						|
	different routines for the different types of initialisation:
 | 
						|
	-	array initialisation
 | 
						|
	-	struct initialisation
 | 
						|
	-	fundamental type initialisation
 | 
						|
	Upto now, the initialisation of a union is not allowed!
 | 
						|
	An initialisation expression tree consists of normal expressions
 | 
						|
	which can be joined together by ',' nodes, which operator acts
 | 
						|
	like the lisp function "cons" to build lists.
 | 
						|
	IVAL() returns a pointer to the remaining expression tree.
 | 
						|
*/
 | 
						|
struct expr *
 | 
						|
IVAL(tpp, ex)
 | 
						|
	struct type **tpp;		/* type of global variable	*/
 | 
						|
	register struct expr *ex;	/* initialiser expression	*/
 | 
						|
{
 | 
						|
	register struct type *tp = *tpp;
 | 
						|
	
 | 
						|
	switch (tp->tp_fund) {
 | 
						|
	case ARRAY: /* array initialisation	*/
 | 
						|
		if (valid_type(tp->tp_up, "array element") == 0)
 | 
						|
			return 0;
 | 
						|
		if (ISCOMMA(ex)) /* list of initialisation expressions */
 | 
						|
			return do_array(ex, tpp);
 | 
						|
		if (tp->tp_up->tp_fund == CHAR && ex->ex_class == String)
 | 
						|
			/* initialisation like char s[] = "I am a string" */
 | 
						|
			ch_array(tpp, ex);
 | 
						|
		else /* " int i[24] = 12;"	*/
 | 
						|
			check_and_pad(ex, tpp);
 | 
						|
		break;
 | 
						|
	case STRUCT: /* struct initialisation */
 | 
						|
		if (valid_type(tp, "struct") == 0)
 | 
						|
			return 0;
 | 
						|
		if (ISCOMMA(ex)) /* list of initialisation expressions */
 | 
						|
			return do_struct(ex, tp);
 | 
						|
		check_and_pad(ex, tpp); /* "struct foo f = 12;"	*/
 | 
						|
		break;
 | 
						|
	case UNION:
 | 
						|
		error("union initialisation not allowed");
 | 
						|
		break;
 | 
						|
	case ERRONEOUS:
 | 
						|
		break;
 | 
						|
	default: /* fundamental type	*/
 | 
						|
		if (ISCOMMA(ex)) { /* " int i = {12};"	*/
 | 
						|
			if (IVAL(tpp, ex->OP_LEFT) != 0)
 | 
						|
				too_many_initialisers(ex);
 | 
						|
			/*	return remainings of the list for the
 | 
						|
				other members of the aggregate, if this
 | 
						|
				item belongs to an aggregate.
 | 
						|
			*/
 | 
						|
			return ex->OP_RIGHT;
 | 
						|
		}
 | 
						|
		check_ival(ex, tp); /* "int i = 12;" */
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*	do_array() initialises the members of an array described
 | 
						|
	by type tp with the expressions in expr.
 | 
						|
	Two important cases:
 | 
						|
	-	the number of members is known
 | 
						|
	-	the number of members is not known
 | 
						|
	In the latter case, do_array() digests the whole expression
 | 
						|
	tree it is given.
 | 
						|
	In the former case, do_array() eats as many members from
 | 
						|
	the expression tree as are needed for the array.
 | 
						|
	If there are not sufficient members for the array, the remaining
 | 
						|
	members are padded with zeroes
 | 
						|
*/
 | 
						|
struct expr *
 | 
						|
do_array(ex, tpp)
 | 
						|
	register struct expr *ex;
 | 
						|
	struct type **tpp;
 | 
						|
{
 | 
						|
	register struct type *tp = *tpp;
 | 
						|
	register arith elem_count;
 | 
						|
	
 | 
						|
	ASSERT(tp->tp_fund == ARRAY && ISCOMMA(ex));
 | 
						|
	/*	the following test catches initialisations like
 | 
						|
		char c[] = {"just a string"};
 | 
						|
		or
 | 
						|
		char d[] = {{"just another string"}};
 | 
						|
		The use of the brackets causes this problem.
 | 
						|
		Note: although the implementation of such initialisations
 | 
						|
		is completely foolish, we did it!! (no applause, thank you)
 | 
						|
	*/
 | 
						|
	if (tp->tp_up->tp_fund == CHAR) {
 | 
						|
		register struct expr *f = ex->OP_LEFT, *g = NILEXPR;
 | 
						|
 | 
						|
		while (ISCOMMA(f)) {	/* eat the brackets!!!	*/
 | 
						|
			g = f;
 | 
						|
			f = f->OP_LEFT;
 | 
						|
		}
 | 
						|
		if (f->ex_class == String) { /* hallelujah, it's a string! */
 | 
						|
			ch_array(tpp, f);
 | 
						|
			return g ? g->OP_RIGHT : ex->OP_RIGHT;
 | 
						|
		}
 | 
						|
		/* else: just go on with the next part of this function */
 | 
						|
		if (g != 0)
 | 
						|
			ex = g;
 | 
						|
	}
 | 
						|
	if (tp->tp_size == (arith)-1) {
 | 
						|
		/* declared with unknown size: [] */
 | 
						|
		for (elem_count = 0; ex; elem_count++) {
 | 
						|
			/* eat whole initialisation expression	*/
 | 
						|
			if (ISCOMMA(ex->OP_LEFT)) { /* embraced member */
 | 
						|
				if (IVAL(&(tp->tp_up), ex->OP_LEFT) != 0)
 | 
						|
					too_many_initialisers(ex);
 | 
						|
				ex = ex->OP_RIGHT;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				if (aggregate_type(tp->tp_up))
 | 
						|
					ex = IVAL(&(tp->tp_up), ex);
 | 
						|
				else {
 | 
						|
					check_ival(ex->OP_LEFT, tp->tp_up);
 | 
						|
					ex = ex->OP_RIGHT;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		/* set the proper size	*/
 | 
						|
		*tpp = construct_type(ARRAY, tp->tp_up, elem_count);
 | 
						|
	}
 | 
						|
	else {		/* the number of members is already known	*/
 | 
						|
		arith dim = tp->tp_size / tp->tp_up->tp_size;
 | 
						|
 | 
						|
		for (elem_count = 0; elem_count < dim && ex; elem_count++) {
 | 
						|
			if (ISCOMMA(ex->OP_LEFT)) { /* embraced member */
 | 
						|
				if (IVAL(&(tp->tp_up), ex->OP_LEFT) != 0)
 | 
						|
					too_many_initialisers(ex);
 | 
						|
				ex = ex->OP_RIGHT;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				if (aggregate_type(tp->tp_up))
 | 
						|
					ex = IVAL(&(tp->tp_up), ex);
 | 
						|
				else {
 | 
						|
					check_ival(ex->OP_LEFT, tp->tp_up);
 | 
						|
					ex = ex->OP_RIGHT;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (ex && elem_count == dim)
 | 
						|
			/*	all the members are initialised but there
 | 
						|
				remains a part of the expression tree which
 | 
						|
				is returned
 | 
						|
			*/
 | 
						|
			return ex;
 | 
						|
		if ((ex == 0) && elem_count < dim)
 | 
						|
			/*	the expression tree is completely absorbed
 | 
						|
				but there are still members which must be
 | 
						|
				initialised with zeroes
 | 
						|
			*/
 | 
						|
			do
 | 
						|
				pad(tp->tp_up);
 | 
						|
			while (++elem_count < dim);
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*	do_struct() initialises a struct of type tp with the expression expr.
 | 
						|
	The main loop is just controlled by the definition of the selectors
 | 
						|
	during which alignment is taken care of.
 | 
						|
*/
 | 
						|
struct expr *
 | 
						|
do_struct(ex, tp)
 | 
						|
	register struct expr *ex;
 | 
						|
	register struct type *tp;
 | 
						|
{
 | 
						|
	register struct sdef *sd = tp->tp_sdef;
 | 
						|
	arith bytes_upto_here = (arith)0;
 | 
						|
	arith last_offset = (arith)-1;
 | 
						|
	
 | 
						|
	ASSERT(tp->tp_fund == STRUCT && ISCOMMA(ex));
 | 
						|
	/* as long as there are selectors and there is an initialiser..	*/
 | 
						|
	while (sd && ex) {
 | 
						|
		if (ISCOMMA(ex->OP_LEFT)) {	/* embraced expression	*/
 | 
						|
			if (IVAL(&(sd->sd_type), ex->OP_LEFT) != 0)
 | 
						|
				too_many_initialisers(ex);
 | 
						|
			ex = ex->OP_RIGHT;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			if (aggregate_type(sd->sd_type))
 | 
						|
				/* selector is an aggregate itself	*/
 | 
						|
				ex = IVAL(&(sd->sd_type), ex);
 | 
						|
			else {
 | 
						|
#ifdef NOBITFIELD
 | 
						|
				/* fundamental type, not embraced */
 | 
						|
				check_ival(ex->OP_LEFT, sd->sd_type);
 | 
						|
				ex = ex->OP_RIGHT;
 | 
						|
#else
 | 
						|
				if (is_anon_idf(sd->sd_idf))
 | 
						|
					/*	a hole in the struct due to
 | 
						|
						the use of ";:n;" in a struct
 | 
						|
						definition.
 | 
						|
					*/
 | 
						|
					put_bf(sd->sd_type, (arith)0);
 | 
						|
				else { /* fundamental type, not embraced */
 | 
						|
					check_ival(ex->OP_LEFT, sd->sd_type);
 | 
						|
					ex = ex->OP_RIGHT;
 | 
						|
				}
 | 
						|
#endif NOBITFIELD
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (sd->sd_sdef) /* align upto the next selector boundary */
 | 
						|
			bytes_upto_here += zero_bytes(sd);
 | 
						|
		if (last_offset != sd->sd_offset) {
 | 
						|
			/* don't take the field-width more than once	*/
 | 
						|
			bytes_upto_here +=
 | 
						|
				size_of_type(sd->sd_type, "selector");
 | 
						|
			last_offset = sd->sd_offset;
 | 
						|
		}
 | 
						|
		sd = sd->sd_sdef;
 | 
						|
	}
 | 
						|
	/* perfect fit if (ex && (sd == 0)) holds	*/
 | 
						|
	if ((ex == 0) && (sd != 0)) {
 | 
						|
		/* there are selectors left which must be padded with zeroes */
 | 
						|
		do {
 | 
						|
			pad(sd->sd_type);
 | 
						|
			/* take care of the alignment restrictions	*/
 | 
						|
			if (sd->sd_sdef)
 | 
						|
				bytes_upto_here += zero_bytes(sd);
 | 
						|
			/* no field thrown-outs here	*/
 | 
						|
			bytes_upto_here +=
 | 
						|
				size_of_type(sd->sd_type, "selector");
 | 
						|
		} while (sd = sd->sd_sdef);
 | 
						|
	}
 | 
						|
	/* keep on aligning...	*/
 | 
						|
	while (bytes_upto_here++ < tp->tp_size)
 | 
						|
		con_nullbyte();
 | 
						|
	return ex;
 | 
						|
}
 | 
						|
 | 
						|
/*	check_and_pad() is given a simple initialisation expression
 | 
						|
	where the type can be either a simple or an aggregate type.
 | 
						|
	In the latter case, only the first member is initialised and
 | 
						|
	the rest is zeroed.
 | 
						|
*/
 | 
						|
check_and_pad(ex, tpp)
 | 
						|
	register struct expr *ex;
 | 
						|
	struct type **tpp;
 | 
						|
{
 | 
						|
	/* ex is of a fundamental type	*/
 | 
						|
	register struct type *tp = *tpp;
 | 
						|
 | 
						|
	if (tp->tp_fund == ARRAY) {
 | 
						|
		if (valid_type(tp->tp_up, "array element") == 0)
 | 
						|
			return;
 | 
						|
		check_and_pad(ex, &(tp->tp_up));	/* first member	*/
 | 
						|
		if (tp->tp_size == (arith)-1)
 | 
						|
			/*	no size specified upto here: just
 | 
						|
				set it to the size of one member.
 | 
						|
			*/
 | 
						|
			tp = *tpp = construct_type(ARRAY, tp->tp_up, (arith)1);
 | 
						|
		else {
 | 
						|
			register int dim = tp->tp_size / tp->tp_up->tp_size;
 | 
						|
			/* pad remaining members with zeroes */
 | 
						|
			while (--dim > 0)
 | 
						|
				pad(tp->tp_up);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	if (tp->tp_fund == STRUCT) {
 | 
						|
		register struct sdef *sd = tp->tp_sdef;
 | 
						|
 | 
						|
		if (valid_type(tp, "struct") == 0)
 | 
						|
			return;
 | 
						|
		check_and_pad(ex, &(sd->sd_type));
 | 
						|
		/* next selector is aligned by adding extra zeroes */
 | 
						|
		if (sd->sd_sdef)
 | 
						|
			zero_bytes(sd);
 | 
						|
		while (sd = sd->sd_sdef) { /* pad remaining selectors	*/
 | 
						|
			pad(sd->sd_type);
 | 
						|
			if (sd->sd_sdef)
 | 
						|
				zero_bytes(sd);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else	/* simple type	*/
 | 
						|
		check_ival(ex, tp);
 | 
						|
}
 | 
						|
 | 
						|
/*	pad() fills an element of type tp with zeroes.
 | 
						|
	If the element is an aggregate, pad() is called recursively.
 | 
						|
*/
 | 
						|
pad(tp)
 | 
						|
	register struct type *tp;
 | 
						|
{
 | 
						|
	register arith sz = tp->tp_size;
 | 
						|
 | 
						|
	switch (tp->tp_fund) {
 | 
						|
	case ARRAY:
 | 
						|
		if (valid_type(tp->tp_up, "array element") == 0)
 | 
						|
			return;
 | 
						|
		break;
 | 
						|
	case STRUCT:
 | 
						|
		if (valid_type(tp, "struct") == 0)
 | 
						|
			return;
 | 
						|
		break;
 | 
						|
	case UNION:
 | 
						|
		if (valid_type(tp, "union") == 0)
 | 
						|
			return;
 | 
						|
		if (options['R']) {
 | 
						|
			warning("initialisation of unions not allowed");
 | 
						|
		}
 | 
						|
		break;
 | 
						|
#ifndef NOBITFIELD
 | 
						|
	case FIELD:
 | 
						|
		put_bf(tp, (arith)0);
 | 
						|
		return;
 | 
						|
#endif NOBITFIELD
 | 
						|
	case ERRONEOUS:
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	while (sz >= word_size) {
 | 
						|
		C_con_cst((arith) 0);
 | 
						|
		sz -= word_size;
 | 
						|
	}
 | 
						|
	while (sz) {
 | 
						|
		C_con_icon("0", (arith) 1);
 | 
						|
		sz--;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*	check_ival() checks whether the initialisation of an element
 | 
						|
	of a fundamental type is legal and, if so, performs the initialisation
 | 
						|
	by directly generating the necessary code.
 | 
						|
	No further comment is needed to explain the internal structure
 | 
						|
	of this straightforward function.
 | 
						|
*/
 | 
						|
check_ival(expr, tp)
 | 
						|
	register struct expr *expr;
 | 
						|
	register struct type *tp;
 | 
						|
{
 | 
						|
	/*	The philosophy here is that ch7cast puts an explicit
 | 
						|
		conversion node in front of the expression if the types
 | 
						|
		are not compatible.  In this case, the initialisation
 | 
						|
		expression is no longer a constant.
 | 
						|
	*/
 | 
						|
	struct expr *ex = expr;
 | 
						|
	
 | 
						|
	switch (tp->tp_fund) {
 | 
						|
	case CHAR:
 | 
						|
	case SHORT:
 | 
						|
	case INT:
 | 
						|
	case LONG:
 | 
						|
	case ENUM:
 | 
						|
	case POINTER:
 | 
						|
		ch7cast(&ex, '=', tp);
 | 
						|
		expr = ex;
 | 
						|
#ifdef DEBUG
 | 
						|
		print_expr("init-expr after cast", expr);
 | 
						|
#endif DEBUG
 | 
						|
		if (!is_ld_cst(expr))
 | 
						|
			illegal_init_cst(expr);
 | 
						|
		else
 | 
						|
		if (expr->VL_CLASS == Const)
 | 
						|
			con_int(expr);
 | 
						|
		else
 | 
						|
		if (expr->VL_CLASS == Name) {
 | 
						|
			register struct idf *idf = expr->VL_IDF;
 | 
						|
 | 
						|
			if (idf->id_def->df_level >= L_LOCAL)
 | 
						|
				illegal_init_cst(expr);
 | 
						|
			else	/* e.g., int f(); int p = f; */
 | 
						|
			if (idf->id_def->df_type->tp_fund == FUNCTION)
 | 
						|
				C_con_pnam(idf->id_text);
 | 
						|
			else	/* e.g., int a; int *p = &a; */
 | 
						|
				C_con_dnam(idf->id_text, expr->VL_VALUE);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			ASSERT(expr->VL_CLASS == Label);
 | 
						|
			C_con_dlb(expr->VL_LBL, expr->VL_VALUE);
 | 
						|
		}
 | 
						|
		break;
 | 
						|
#ifndef NOFLOAT
 | 
						|
	case FLOAT:
 | 
						|
	case DOUBLE:
 | 
						|
		ch7cast(&ex, '=', tp);
 | 
						|
		expr = ex;
 | 
						|
#ifdef DEBUG
 | 
						|
		print_expr("init-expr after cast", expr);
 | 
						|
#endif DEBUG
 | 
						|
		if (expr->ex_class == Float)
 | 
						|
			C_con_fcon(expr->FL_VALUE, expr->ex_type->tp_size);
 | 
						|
		else
 | 
						|
		if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) {
 | 
						|
			/* float f = 1; */
 | 
						|
			expr = expr->OP_RIGHT;
 | 
						|
			if (is_cp_cst(expr))
 | 
						|
				C_con_fcon(long2str((long)expr->VL_VALUE, 10),
 | 
						|
					tp->tp_size);
 | 
						|
			else 
 | 
						|
				illegal_init_cst(expr);
 | 
						|
		}
 | 
						|
		else
 | 
						|
			illegal_init_cst(expr);
 | 
						|
		break;
 | 
						|
#endif NOFLOAT
 | 
						|
 | 
						|
#ifndef NOBITFIELD
 | 
						|
	case FIELD:
 | 
						|
		ch7cast(&ex, '=', tp->tp_up);
 | 
						|
		expr = ex;
 | 
						|
#ifdef DEBUG
 | 
						|
		print_expr("init-expr after cast", expr);
 | 
						|
#endif DEBUG
 | 
						|
		if (is_cp_cst(expr))
 | 
						|
			put_bf(tp, expr->VL_VALUE);
 | 
						|
		else
 | 
						|
			illegal_init_cst(expr);
 | 
						|
		break;
 | 
						|
#endif NOBITFIELD
 | 
						|
 | 
						|
	case ERRONEOUS:
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		crash("check_ival");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*	ch_array() initialises an array of characters when given
 | 
						|
	a string constant.
 | 
						|
	Alignment is taken care of.
 | 
						|
*/
 | 
						|
ch_array(tpp, ex)
 | 
						|
	struct type **tpp;	/* type tp = array of characters	*/
 | 
						|
	struct expr *ex;
 | 
						|
{
 | 
						|
	register struct type *tp = *tpp;
 | 
						|
	register arith length = ex->SG_LEN;
 | 
						|
	char *s;
 | 
						|
	arith ntopad;
 | 
						|
 | 
						|
	ASSERT(ex->ex_class == String);
 | 
						|
	if (tp->tp_size == (arith)-1) {
 | 
						|
		/* set the dimension	*/
 | 
						|
		tp = *tpp = construct_type(ARRAY, tp->tp_up, length);
 | 
						|
		ntopad = align(tp->tp_size, word_size) - tp->tp_size;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		arith dim = tp->tp_size / tp->tp_up->tp_size;
 | 
						|
		extern char options[];
 | 
						|
 | 
						|
		if (length > dim) {
 | 
						|
			if (options['R'])
 | 
						|
				too_many_initialisers(ex);
 | 
						|
			else { /* don't take the null byte into account */
 | 
						|
				if (length > dim + 1)
 | 
						|
					expr_warning(ex,
 | 
						|
						"too many initialisers");
 | 
						|
				length = dim;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		ntopad = align(dim, word_size) - length;
 | 
						|
	}
 | 
						|
	/* throw out the characters of the already prepared string	*/
 | 
						|
	s = Malloc((unsigned) (length + ntopad));
 | 
						|
	clear(s, (int) (length + ntopad));
 | 
						|
	strncpy(s, ex->SG_VALUE, (int) length);
 | 
						|
	free(ex->SG_VALUE);
 | 
						|
	str_cst(s, (int) (length + ntopad));
 | 
						|
	free(s);
 | 
						|
}
 | 
						|
 | 
						|
/*	As long as some parts of the pipeline cannot handle very long string
 | 
						|
	constants, string constants are written out in chunks
 | 
						|
*/
 | 
						|
str_cst(str, len)
 | 
						|
	register char *str;
 | 
						|
	register int len;
 | 
						|
{
 | 
						|
	arith chunksize = ((127 + word_size) / word_size) * word_size;
 | 
						|
 | 
						|
	while (len > chunksize) {
 | 
						|
		C_con_scon(str, chunksize);
 | 
						|
		len -= chunksize;
 | 
						|
		str += chunksize;
 | 
						|
	}
 | 
						|
	C_con_scon(str, (arith) len);
 | 
						|
}
 | 
						|
 | 
						|
#ifndef NOBITFIELD
 | 
						|
/*	put_bf() takes care of the initialisation of (bit-)field
 | 
						|
	selectors of a struct: each time such an initialisation takes place,
 | 
						|
	put_bf() is called instead of the normal code generating routines.
 | 
						|
	Put_bf() stores the given integral value into "field" and
 | 
						|
	"throws" the result of "field" out if the current selector
 | 
						|
	is the last of this number of fields stored at the same address.
 | 
						|
*/
 | 
						|
put_bf(tp, val)
 | 
						|
	struct type *tp;
 | 
						|
	arith val;
 | 
						|
{
 | 
						|
	static long field = (arith)0;
 | 
						|
	static arith offset = (arith)-1;
 | 
						|
	register struct field *fd = tp->tp_field;
 | 
						|
	register struct sdef *sd =  fd->fd_sdef;
 | 
						|
	static struct expr exp;
 | 
						|
 | 
						|
	ASSERT(sd);
 | 
						|
	if (offset == (arith)-1) {
 | 
						|
		/* first bitfield in this field	*/
 | 
						|
		offset = sd->sd_offset;
 | 
						|
		exp.ex_type = tp->tp_up;
 | 
						|
		exp.ex_class = Value;
 | 
						|
		exp.VL_CLASS = Const;
 | 
						|
	}
 | 
						|
	if (val != 0)	/* insert the value into "field"	*/
 | 
						|
		field |= (val & fd->fd_mask) << fd->fd_shift;
 | 
						|
	if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) {
 | 
						|
		/* the selector was the last stored at this address	*/
 | 
						|
		exp.VL_VALUE = field;
 | 
						|
		con_int(&exp);
 | 
						|
		field = (arith)0;
 | 
						|
		offset = (arith)-1;
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif NOBITFIELD
 | 
						|
 | 
						|
int
 | 
						|
zero_bytes(sd)
 | 
						|
	register struct sdef *sd;
 | 
						|
{
 | 
						|
	/*	fills the space between a selector of a struct
 | 
						|
		and the next selector of that struct with zero-bytes.
 | 
						|
	*/
 | 
						|
	register int n = sd->sd_sdef->sd_offset - sd->sd_offset -
 | 
						|
		size_of_type(sd->sd_type, "struct member");
 | 
						|
	register int count = n;
 | 
						|
 | 
						|
	while (n-- > 0)
 | 
						|
		con_nullbyte();
 | 
						|
	return count;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
valid_type(tp, str)
 | 
						|
	struct type *tp;
 | 
						|
	char *str;
 | 
						|
{
 | 
						|
	if (tp->tp_size < 0) {
 | 
						|
		error("size of %s unknown", str);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
con_int(ex)
 | 
						|
	register struct expr *ex;
 | 
						|
{
 | 
						|
	register struct type *tp = ex->ex_type;
 | 
						|
 | 
						|
	ASSERT(is_cp_cst(ex));
 | 
						|
	if (tp->tp_unsigned)
 | 
						|
		C_con_ucon(long2str((long)ex->VL_VALUE, -10), tp->tp_size);
 | 
						|
	else
 | 
						|
		C_con_icon(long2str((long)ex->VL_VALUE, 10), tp->tp_size);
 | 
						|
}
 | 
						|
 | 
						|
illegal_init_cst(ex)
 | 
						|
	struct expr *ex;
 | 
						|
{
 | 
						|
	expr_error(ex, "illegal initialisation constant");
 | 
						|
}
 | 
						|
 | 
						|
too_many_initialisers(ex)
 | 
						|
	struct expr *ex;
 | 
						|
{
 | 
						|
	expr_error(ex, "too many initialisers");
 | 
						|
}
 | 
						|
 | 
						|
aggregate_type(tp)
 | 
						|
	register struct type *tp;
 | 
						|
{
 | 
						|
	return tp->tp_fund == ARRAY || tp->tp_fund == STRUCT;
 | 
						|
}
 |