Personal tools
You are here: Home Projects C++ Cfront releases Release 1.0 Source cfront src expand.c
Document Actions

expand.c

by Paul McJones last modified 2007-02-02 09:34

Click here to get the file

Size 11.1 kB - File type text/x-csrc

File contents

/* @(#) expand.c 1.3 1/27/86 17:48:48 */ 
/*ident	"@(#)cfront:src/expand.c	1.3" */
/*****************************************************************

	C++ source for cfront, the C++ compiler front-end
	written in the computer science research center of Bell Labs

	Copyright (c) 1984 AT&T, Inc. All Rights Reserved
	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC.


expand.c:

	expand inline functions

******************************************************************/

#include "cfront.h"

char* temp(char* vn, char* fn, char* cn)
/*
	make the name of the temporary: _X_vn_fn_cn
*/
{	if (vn[0]!='_' || vn[1]!='X') {
		int vnl = strlen(vn);
		int fnl = strlen(fn);
		int cnl = (cn)?strlen(cn):0;
		char* s = new char[vnl+fnl+cnl+6];

		s[0] = '_';
		s[1] = 'X';
		strcpy(s+2,vn);
		s[vnl+2] = '_';
		strcpy(s+vnl+3,fn);
		if (cnl) {
			s[vnl+fnl+3] = '_';
			strcpy(s+vnl+fnl+4,cn);
		}
		return s;
	}
	else
		return vn;

}

Pname dcl_local(Ptable scope, Pname an, Pname fn)
{
	if (scope == 0) {
		error('s',"cannot expand inlineF needing temporary variable in nonF context");
		return an;
	}
	if (an->n_stclass == STATIC) error('s',"static%n in inlineF",an);
	Pname cn = fn->n_table->t_name;
	char* s = temp(an->string,fn->string,(cn)?cn->string:0);
	Pname nx = new name(s);
/*error('d',"%n: %d->dcl_local(%s)",fn,scope,s); */
	nx->tp = an->tp;
	PERM(nx->tp);
	nx->n_used = an->n_used;
	nx->n_assigned_to = an->n_assigned_to;
	nx->n_addr_taken = an->n_addr_taken;
	Pname r = scope->insert(nx,0);
	delete nx;
	return r;
}

Pstmt stmt.expand()
/*
	copy the statements with the formal arguments replaced by ANAMES 

	called once only per inline function
	expand_tbl!=0 if the function should be transformed into an expression
	and expand_tbl is the table for local variables
*/
{
	if (this == 0) error('i',"0->stmt.expand() for%n",expand_fn);
/*error('d',"stmt %d:%k s=%d e=%d l=%d",this,base,s,e,s_list);*/

	if (memtbl) {	/* check for static variables */
		register Ptable t = memtbl;
		register int i;
		for (register Pname n = t->get_mem(i=1); n; n=t->get_mem(++i)) 
			if (n->n_stclass == STATIC) {
				error('s',"static%n in inlineF",n);
				n->n_stclass = AUTO;
			}
	}

	if (expand_tbl) {	/* make expression */
		Pexpr ee;
		static ret_seen = 0;

		if (memtbl && base!=BLOCK) { /* temporaries */
			int i;
			Pname n;
			Ptable tbl = memtbl;
			for (n = tbl->get_mem(i=1); n; n=tbl->get_mem(++i)) {
/*error('d',"%n: %n",expand_fn,n);*/
				Pname nn = dcl_local(scope,n,expand_fn);
				nn->base = NAME;
				n->string = nn->string;
			}
		}

		switch (base) {
		default:
			error('s',"%kS in inline%n",base,expand_fn);
			return (Pstmt)dummy;

		case BLOCK:
			if (s_list) {
				ee = (Pexpr) s_list->expand();
				if (s) {
					ee = new expr(CM, (Pexpr)s->expand(), ee);	
					PERM(ee);
				}
				return (Pstmt) ee;
			}

			if (s) return s->expand();

			return (Pstmt) zero;

		case PAIR:
			ee = s2 ? (Pexpr)s2->expand() : 0;
			ee = new expr(CM, s?(Pexpr)s->expand():0, ee);
			if (s_list) ee = new expr(CM, ee, (Pexpr)s_list->expand());
			PERM(ee);
			return (Pstmt) ee;

		case RETURN:
			ret_seen = 1;
			s_list = 0;
			return (Pstmt) e->expand();

		case SM:
			ee = (e==0 || e->base==DUMMY) ? zero : e->expand();
			if (s_list) {
				ee = new expr(CM, ee, (Pexpr)s_list->expand());
				PERM(ee);
			}
			return (Pstmt)ee;

		case IF:
		{	ret_seen = 0;
			Pexpr qq = new expr(QUEST,(Pexpr)s->expand(),0);
			qq->cond = e->expand();
			qq->e2 = else_stmt ? (Pexpr)else_stmt->expand() : zero;
			if (ret_seen && s_list) error('s',"S after \"return\" inIF");
			ret_seen = 0;
			if (s_list) qq = new expr(CM,qq,(Pexpr)s_list->expand());
			PERM(qq);
			return (Pstmt)qq;
		}
		}
	}

	switch (base) {
	default:
		if (e) e = e->expand();
		break;
	case PAIR:
		if (s2) s2 = s2->expand();
		break;
	case BLOCK:
		break;
	case FOR:
		if (for_init) for_init = for_init->expand();
		if (e2) e2 = e2->expand();
		break;
	case LABEL:
	case GOTO:
	case RETURN:
	case BREAK:
	case CONTINUE:
		error('s',"%kS in inline%n",base,expand_fn);
	}

	if (s) s = s->expand();
	if (s_list) s_list = s_list->expand();
	PERM(this);
	return this;
}

Pexpr expr.expand()
{
	if (this == 0) error('i',"expr.expand(0)");
/*fprintf(stderr,"%s(): expr %d: b=%d e1=%d e2=%d\n",expand_fn->string,this,base,e1,e2); fflush(stderr);*/
	switch (base) {
	case NAME:
		if (expand_tbl && ((Pname)this)->n_scope==FCT) {
			Pname n = (Pname)this;
			char* s = n->string;
			if (s[0]=='_' && s[1]=='X') break;
			Pname cn = expand_fn->n_table->t_name;
			n->string = temp(s,expand_fn->string,(cn)?cn->string:0);
		}
	case DUMMY:
	case ICON:
	case FCON:
	case CCON:
	case IVAL:
	case FVAL:
	case LVAL:
	case STRING:
	case ZERO:
	case SIZEOF:
	case TEXT:
	case ANAME:
		break;
	case ICALL:
		if (expand_tbl && e1==0) {
			Pname fn = il->fct_name;
			Pfct f = (Pfct)fn->tp;
			if (f->returns==void_type && fn->n_oper!=CTOR)
				error('s',"non-value-returning inline%n called in value-returning inline%n",fn,expand_fn);
			else
				error("inline%n called before defined",fn);
		}
		break;
	case QUEST:
		cond = cond->expand();
	default:
		if (e2) e2 = e2->expand();
	case REF:
	case DOT:
		if (e1) e1 = e1->expand();
		break;
	case CAST:
		PERM(tp2);
		e1 = e1->expand();
		break;
	}

	PERM(this);
	return this;
}

bit expr.not_simple()
/*
	is a temporary variable needed to hold the value of this expression
	as an argument for an inline expansion?
	return 1; if side effect
	return 2; if modifies expression
*/
{
	int s;
/*error('d',"not_simple%k",base);*/
	switch (base) {
	default:
		return 2;
	case ZERO:
	case IVAL:
	case FVAL:
	case ICON:
	case CCON:
	case FCON:
	case STRING:
	case NAME:	/* unsafe (alias) */
		return 0;
	case SIZEOF:
		return e1==dummy?0:e1->not_simple();
	case G_ADDROF:
	case ADDROF:
		return e2->not_simple();
	case CAST:
	case DOT:
	case REF:
		return e1->not_simple();
	case UMINUS:
	case NOT:
	case COMPL:
		return e2->not_simple();
	case DEREF:
		s = e1->not_simple();
		if (1<s) return 2;
		if (e2==0) return s;
		return s |= e2->not_simple();
	case MUL:
	case DIV:
	case MOD:
	case PLUS:
	case MINUS:
	case LS:
	case RS:
	case AND:
	case OR:
	case ER:
	case LT:
	case LE:
	case GT:
	case GE:
	case EQ:
	case NE:
	case ANDAND:
	case OROR:
	case CM:
		s = e1->not_simple();
		if (1<s) return 2;
		return s |= e2->not_simple();
	case QUEST:
		s = cond->not_simple();
		if (1<s) return 2;
		s |= e1->not_simple();
		if (1<s) return 2;
		return s |= e2->not_simple();
	case ANAME:
		if (curr_icall) {
			Pname n = (Pname)this;
			int argno = n->n_val;
			Pin il;
			for (il=curr_icall; il; il=il->i_next)
				if (n->n_table == il->i_table) goto aok;
			goto bok;
		aok:
			return (il->local[argno]) ? 0 : il->arg[argno]->not_simple();
		}
	bok:	error('i',"expand aname%n",this);
	case VALUE:
	case NEW:
	case CALL:
	case G_CALL:
	case ICALL:
	case ASSIGN:
	case INCR:
	case DECR:
	case ASPLUS:
	case ASMINUS:
	case ASMUL:
	case ASDIV:
	case ASMOD:
	case ASAND:
	case ASOR:
	case ASER:
	case ASLS:
	case ASRS:
		return 2;
	}
}


Pexpr fct.expand(Pname fn, Ptable scope, Pexpr ll)
/*
	expand call to (previously defined) inline function in "scope"
	with the argument list "ll"
	(1) declare variables in "scope"
	(2) initialize argument variables
	(3) link to body
*/
{
//error('d',"expand%n inline=%d body %d defined %d f_expr %d last_exp=%d curr_expr=%d",fn,f_inline,body,defined ,f_expr,last_expanded,curr_expr);
	if ((body==0 && f_expr==0)			// before defined
	||  ((defined&SIMPLIFIED)==0)			// before simplified
	||  (Pfct(fn->tp)->body->memtbl==scope)		// while defining
	||  (f_inline==2)				// recursive call
	||  (last_expanded && last_expanded==curr_expr)	// twice in an expression
	) {
		fn->take_addr();			/* so don't expand */
		if (fn->n_addr_taken == 1) {
			Pname nn = new name;		/* but declare it */
			*nn = *fn;
			nn->n_list = dcl_list;
			nn->n_sto = STATIC;
			dcl_list = nn;
		}
		return 0;
	}

	f_inline = 2;

	Pin il = new iline;
	Pexpr ic = new texpr(ICALL,0,0);
	il->fct_name = fn;
	ic->il = il;
	ic->tp = returns;
	Pname n;
	Pname at = (f_this) ? f_this : argtype;
	if (at) il->i_table = at->n_table;
	int i = 0;
	int not_simple = 0;	/* is a temporary argument needed? */

	for (n=at; n; n=n->n_list, i++) {
		/*	check formal/actual argument pairs
			and generate temporaries as necessary
		*/
		if (ll == 0) error('i',"simpl.call:AX for %n",fn);
		Pexpr ee;

		if (ll->base == ELIST) {
			ee = ll->e1;
			ll = ll->e2;
		}
		else {
			ee = ll;
			ll = 0;
		}

		int s;	/* could be avoided when expanding into a block */

//error('d',"n=%n addr %d ass %d used %d ee %k => %d",n,n->n_addr_taken,n->n_assigned_to,n->n_used,ee->base,ee->not_simple());
		if (n->n_assigned_to == FUDGE111) {	/* constructor's this */
			if (ee!=zero && ee->not_simple()==0) {		/* automatic or static
							   then we can use the
							   actual variable
							*/
				il->local[i] = 0;
				goto zxc;
			}
		}

		if (n->n_addr_taken
		|| n->n_assigned_to) {
			Pname nn = dcl_local(scope,n,fn);
			nn->base = NAME;
			il->local[i] = nn;
			++not_simple;
		}
		else if (n->n_used
			&& (s=ee->not_simple())
			&& (1<s || 1<n->n_used) ) {	/* not safe */
			Pname nn = dcl_local(scope,n,fn);
			nn->base = NAME;
			il->local[i] = nn;
			++not_simple;
		}
		else
			il->local[i] = 0;
	zxc:
		il->arg[i] = ee;
		il->tp[i] = n->tp;
	}
	
	Ptable tbl = body->memtbl;
	if (f_expr) {	/* generate comma expression */
		char loc_var = 0;
		/* look for local variables needing declaration: */
//error('d',"fn%n tbl %d",fn,tbl);
		for (n=tbl->get_mem(i=1); n; n=tbl->get_mem(++i) ) {
//error('d',"?%s: b=%d u%d =%d &=%d",n->string,n->base,n->n_used,n->n_assigned_to,n->n_addr_taken);
			if (n->base==NAME
			&& (n->n_used||n->n_assigned_to||n->n_addr_taken)) {
				Pname nn = dcl_local(scope,n,fn);
				nn->base = NAME;
				n->string = nn->string;
				loc_var++;
			}
		}
/*error('d',"not_simple=%d loc_var=%d last_expanded=%d curr_expr=%d",not_simple,loc_var,last_expanded,curr_expr);*/
		if (not_simple || loc_var) last_expanded = curr_expr;

		Pexpr ex;
		if (not_simple) {
			Pexpr etail = ex = new expr(CM,0,0);
			for (i=0; i<MIA; i++) {
				Pname n = il->local[i];
				if (n==0) continue;
				Pexpr e = il->arg[i];
				etail->e1 = new expr(ASSIGN,n,e);
/*error('d',"%n = %k",n,e->base);*/
				if (--not_simple)
					etail = etail->e2 = new expr(CM,0,0);
				else
					break;
			}
			etail->e2 = f_expr;
		}
		else {
			ex = f_expr;
		}
		ic->e1 = ex;
	}
	else {	/* generate block: */
		for (n=tbl->get_mem(i=1); n; n=tbl->get_mem(++i) ) {
			// mangle local names
//error('d',"?%s: b=%d u%d =%d &=%d",n->string,n->base,n->n_used,n->n_assigned_to,n->n_addr_taken);
			if (n->base==NAME
			&& (n->n_used||n->n_assigned_to||n->n_addr_taken)) {
				Pname cn = fn->n_table->t_name;
				n->string = temp(n->string,fn->string,(cn)?cn->string:0);
			}
		}
		Pstmt ss;
		if (not_simple) {
			last_expanded = curr_expr;
			Pstmt st = new estmt(SM,curloc,0,0);
			Pstmt stail = st;
			for (i=0; i<MIA; i++) {
				Pname n = il->local[i];
				if (n == 0) continue;
				Pexpr e = il->arg[i];
				stail->e = new expr(ASSIGN,n,e);
				if (--not_simple)
					stail = stail->s_list = new estmt(SM,curloc,0,0);
				else
					break;
			}
			stail->s_list = body;
			ss = new block(curloc,0,st);
		}
		else {
			ss = body;
		}
		ic->e2 = (Pexpr)ss;
	}

	f_inline = 1;
	return ic;
}
« October 2024 »
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: