V10/cmd/cfront/xptcfront/print.c

Compare this file to the similar file:
Show the results in this format:

/*ident	"@(#)ctrans:src/print.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.

print.c:

	print statements and expressions

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

#include "cfront.h"

static int addrof_cm ;
extern void puttok(TOK);

/*
void cprint(Pexpr e)
{
	if (e == 0) return;
//error('d',"%k %n %t",e->base,e->base==NAME?e:0,e->tp);
//	if ((e->base==NAME || e->base==ANAME)
//	&& Pname(e)->n_evaluated==0) {
		Ptype t = e->tp;
		while (t->base == TYPE) t = Pbase(t)->b_name->tp;
		if (t->base == EOBJ) fprintf(out_file,"(int)");
//	}
        
        Eprint(e);
}
*/
#define cprint(e) if (e) Eprint(e)
#define eprint(e) if (e) Eprint(e)

void Eprint(Pexpr e)
{
	switch (e->base) {
	case REF:
		if (Pref(e)->mem && Pref(e)->mem->tp && Pref(e)->mem->tp->base == FCT) {
			//  suppress ``this'' in ``this->f''
			Pref(e)->mem->print();
			break;
		}
	case NAME:
	case MDOT:
	case ID:
	case ZERO:
	case ICON:
	case CCON:
	case FCON:
	case STRING:
	case IVAL:
	case TEXT:
	case CM:
	case G_CM:
	case ELIST:
	case COLON:
	case ILIST:
	case DOT:
	case THIS:
	case CALL:
	case G_CALL:
	case ICALL:
	case ANAME:
		e->print();
	case DUMMY:
		break;
	default:
		putch('(');
		e->print();
		putch(')');
	}
}

void expr::print()
{
	if (this == 0) error('i',"0->E::print()");
	if (this==e1 || this==e2) error('i',"(%p%k)->E::print(%p %p)",this,base,e1,e2);
// error('d',"(%d %k)->expr::print(%d %d)",this,base,e1,e2);

	switch (base) {
	case MDOT:
	{
// error('d',"mdot %s i1 %d %t",string2,i1,mem->tp);
	int not_allocated = 0;
		switch (i1) {
		case 0:
			putcat('O',string2);
			puttok(DOT);	// use sub-object directly
			mem->print();
			break;
		case 1:
			putcat('P',string2);
			puttok(REF);	// use through pointer
			mem->print();
			break;
		case 2:
			if (mem->tp->is_ptr_or_ref()==0) {
				mem->print();
				puttok(DOT);
				putcat('O',string2);
			}
			else
			{
			putch('(');	// REF turns pointer into object: add &
			putch('&');	// ``this'' is a pointer
			putch('(');
			eprint(mem);//mem->print();
			puttok(REF);	// call sub-object directly
			putcat('O',string2);
			putch(')');
			putch(')');
			}
			break;
		case 5:
			not_allocated = 1;
			// no break;	
		case 3:
		    if (mem->tp->is_ptr_or_ref()==0) {
			putch('(');	// Px is a pointer (T*) turn it back to a T
			putch('*');	// *Px
			putch('(');
			eprint(mem);//mem->print();
			puttok(DOT);	//  call through pointer
			putcat('P',string2);
			putch(')');
			putch(')');
		    }
		    else {
//			eprint(mem);	// <<< mem->print()
			if (not_allocated) {
				putch('(');
				mem->print();
				if ( mem->base == NAME ) 
					puttok(REF);
				else puttok(DOT);
				putcat('O',string4);
				putch(')');
			}
			else eprint(mem);
			if (mem->base == NAME && not_allocated)
				puttok(DOT);
			else puttok(REF);	//  call through pointer
			putcat('P',string2);
		    }
		    break;
		case 9:	// vtbl entry:	(p->_vtbl).f, (p->_vtbl).i, (p->_vtbl).d
			// or memptr: mp.f, mp.i, mp.d
			eprint(mem);
			putch('.');
			putstring(string2);
		} // end switch(i1)
		break;
	} // end MDOT

	case NAME:
	{	Pname n = Pname(this);
                if (n->n_evaluated
        //      && n->tp->base!=EOBJ    // this output enumerators
                && n->n_scope!=ARG) {
                        Ptype t = tp;
			while (t->base == TYPE) t = Pbase(t)->b_name->tp;
                        if (t->base == EOBJ) t = Penum(Pbase(t)->b_name->tp)->e_type;
                        if (t->base!=INT || t->is_unsigned()) {
				putstring("((");
				bit oc = Cast;
				Cast = 1;
                                t->print();
				Cast = oc;
				fprintf(out_file,")%d)",n->n_val);
			}
			else
				fprintf(out_file,"%d",n->n_val);
		}
		else
			n->print();
		break;
	}
	case ANAME:
		if (curr_icall) {	// in expansion: look it up
			Pname n = Pname(this);
			int argno = int(n->n_val);

			for (Pin il=curr_icall; il; il=il->i_next)
				if (n->n_table == il->i_table) goto aok;
			goto bok;
		aok:
			if (n = il->i_args[argno].local) {
				n->print();
			}
			else {
				Pexpr ee = il->i_args[argno].arg;
				Ptype t = il->i_args[argno].tp;
				if (ee==0 || ee==this) error('i',"%p->E::print(A %p)",this,ee);
				if (ee->tp==0
				|| (t!=ee->tp
					&& t->check(ee->tp,0)
					&& t->is_cl_obj()==0
				//	&& eobj==0)
					)
				) {
					putstring("((");
					bit oc = Cast;
					Cast = 1;
					t->print();
					Cast = oc;
					putch(')');
					// eprint(ee);
				//	if (ee->base == CAST) {
				//		eprint(ee->e1);
				//	}
				//	else
						eprint(ee);
					putch(')');
				}
				else
					eprint(ee);
			}
		}
		else {
		bok:	/* in body: print it: */
			Pname(this)->print();
		}
		break;

	case ICALL:
	{	il->i_next = curr_icall;
		curr_icall = il;
//error('d',"icall %n",il->fct_name);
		if (il == 0) error('i',"E::print: iline missing");
		Pexpr a0 = il->i_args[0].arg;
		int val = QUEST;
		if (il->fct_name->n_oper != CTOR) goto dumb;

		/*
			find the value of "this"
	   		if the argument is a "this" NOT assigned to
			by the programmer, it was initialized
		*/
		switch (a0->base) {
		case ZERO:
			val = 0;
			break;
		case ADDROF:
		case G_ADDROF:
			val = 1;
			break;
		case CAST:
			if (a0->e1->base == ANAME || a0->e1->base == NAME) {
				Pname a = (Pname)a0->e1;
				if (a->n_assigned_to == FUDGE111) val = FUDGE111;
			}
		}
		if (val==QUEST) goto dumb;
		/*
			now find the test:  "(this==0) ? _new(sizeof(X)) : 0"

			e1 is a comma expression,
			the test is either the first sub-expression
				or the first sub-expression after the assignments
					initializing temporary variables
		 */
	dumb:
		eprint(e1);
		if (e2) Pstmt(e2)->print();
		curr_icall = il->i_next;
		break;
	}
	case REF:
	case DOT:
		eprint(e1);
		puttok(base);
		if (mem == 0) {
			fprintf(out_file,"MEM0");
			break;
		}
		if (mem->base == NAME)
			Pname(mem)->print();
		else
			mem->print();
		break;

	case MEMPTR:
		error("P toMF not called");
		break;

	case VALUE:
		tp2->print();
		puttok(LP);

//		if (e2) {
//			putstring(" &");
//			e2->print();
//			putstring(", ");
//		}
		if (e1) e1->print();
		puttok(RP);
		break;

	case SIZEOF:
		puttok(SIZEOF);
		if (e1 && e1!=dummy) {
			eprint(e1);
		}
		else if (tp2) {
			putch('(');
			if (tp2->base == CLASS) {
				Pclass cl = Pclass(tp2);
				putstring((cl->csu == UNION)?"union ":"struct ");
				char *str = 0;
    				// nested local class does not encode name
    				if ( cl->lex_level && cl->nested_sig == 0 ) 
    					str = make_local_name( cl );
    				putstring(str?str:(cl->nested_sig?cl->nested_sig:cl->string));
				delete str;
			}
			else
				tp2->print();
			putch(')');
		}
		break;

/*
// always turned into function calls:
        case NEW:
        case GNEW:
// error('d',"print new %d tp2 %t e1 %d e2 %d",base,tp2,e1,e2);
		puttok(NEW);
		tp2->print();
		if (e1) {
			putch('(');
			e1->print();
			putch(')');
		}
		break;

	case DELETE:
        case GDELETE:
//error('d',"print delete");
		puttok(DELETE);
		e1->print();
		break;
*/
	case CAST:
		putch('(');
//error('d',"print cast %t",tp2);
		if (tp2->base != VOID && tp2->memptr() == 0 ) {
                        // when VOID is represented as CHAR not everything
                        // can be cast to VOID
			putch('(');
			bit oc = Cast;
			Cast = 1;
			tp2->print();
			Cast = oc;
			putch(')');	
		}
		eprint(e1);
		putch(')');
		break;

	case ICON:
	case FCON:
	case CCON:
	case ID:
		if (string) putst(string);
		break;

	case STRING:
                // avoid printing very long lines
                ntok += 4;
		fprintf(out_file,"\"%s\"",string);
		break;

	case THIS:
	case ZERO:
		putstring("0 ");
		break;

	case IVAL:
		fprintf(out_file,"%d",i1);
		break;

	case TEXT:
	{
		int oo = vtbl_opt;	// make `simulated static' name
		vtbl_opt = -1;	
		char* s = vtbl_name(string,string2);
		vtbl_opt = oo;
		s[2] = 'p';	// pointer, not tbl itself
                char* t = ptbl_lookup(s);
                fprintf(out_file, " %s",t);
		delete t;

		char *str = 0;
		if ( string ) { 
			str = new char[ strlen(string) + strlen(string2) + 1 ];
			strcpy( str, string );
			strcat( str, string2 );
		}

		if ( ptbl->look( str?str:string2, 0 ) == 0 &&
		     ptbl->look( str?str:string2, HIDDEN ) == 0 ) {
			Pname nn = ptbl->insert(new name(str?str:string2),0);
			nn->string2 = new char[strlen(s)+1];
			strcpy(nn->string2,s);
		}

		delete str;
		delete s;
	}
		// no break;

	case DUMMY:
		break;

	case G_CALL:
	case CALL:
	{	Pname fn = fct_name;
		Pname at;
		int m_ptr = 0;

		if (fn) {
			Pfct f = Pfct(fn->tp);

			if (f->base==OVERLOAD) {	// overloaded after call
				fct_name = fn = Pgen(f)->fct_list->f;
				f = Pfct(fn->tp);
			}

			fn->print();
			at = f->f_args;
		}
		else {
			Pfct f = Pfct(e1->tp);

			if (f) {	// pointer to fct
				Pexpr exex = e1;
				if ( exex->base == DEREF ) {
    					exex = exex->e1;
    					while ( exex->base == CAST )
       						exex = exex->e1;
    					if ( exex->base == MDOT )
       						m_ptr = 1;
				}

				if (f->base == OVERLOAD) { // overloaded after call
					fct_name = fn = Pgen(f)->fct_list->f;
					f = Pfct(fn->tp);
				}

				while (f->base == TYPE) f = Pfct(Pbase(f)->b_name->tp);
				if (f->base == PTR) {
					putstring("(*");
					e1->print();
					putch(')');
					f = Pfct(Pptr(f)->typ);
					while (f->base == TYPE) f = Pfct(Pbase(f)->b_name->tp);
				}
				else
					eprint(e1);

			//	at = (f->f_result) ? f->f_result : f->argtype;
				at = f->f_args;
			}
			else {	// virtual: argtype encoded
				// f_this already linked to f_result and/or argtype
				at = (e1->base==QUEST) ? Pname(e1->e1->tp2) : Pname(e1->tp2);
				eprint(e1);
			}
		}

		puttok(LP);

		if (e2) {
			if (at) {
				Pexpr e = e2;
				while (at) {
					Pexpr ex;
					Ptype t = at->tp;

					if (t == 0) error('i',"T ofA missing for%n",fn);
					if (e == 0) error('i',"%tA missing for%n",t,fn);
					if (e->base == ELIST) {
						ex = e->e1;
						e =  e->e2;
					}
					else
						ex = e;

					if (ex == 0) error('i',"A ofT%t missing",t);
					if (t!=ex->tp
					&& ex->tp
					&& t->check(ex->tp,0)
					&& t->is_cl_obj()==0
					&& eobj==0
					&& m_ptr == 0
					&& (t->is_ptr()==0 || Mptr==0)) {
						putch('(');
						bit oc = Cast;
						Cast = 1;
						t->print();
						Cast = oc;
						putch(')');
#ifdef sun
if (ex->base == DIV) { // defend against perverse SUN cc bug
	putstring("(0+");
	eprint(ex);
	putch(')');
}
else
#endif
						// eprint(ex);
					//	if (ex->base==CAST) {
					//		eprint(ex->e1);
					//	}
					//	else
							eprint(ex);
					}
					else
						ex->print();

					// if m_ptr is set, then don't advance at
					// at does not know about generated `this'
					if ( m_ptr ) {
						m_ptr = 0;
						if (at) puttok(CM);
						continue;
					}

					at = at->n_list;
					if (at) puttok(CM);
				}
				if (e) {
					puttok(CM);
					e->print();
				}		 
			}
			else
				e2->print();
		}
		puttok(RP);
		break;
	}

	case ASSIGN:
		if (e1->base==ANAME && Pname(e1)->n_assigned_to==FUDGE111) {
		// suppress assignment to "this" that has been optimized away
			Pname n = Pname(e1);
			int argno = int(n->n_val);
			for (Pin il=curr_icall; il; il=il->i_next)
				if (il->i_table == n->n_table) goto akk;
			goto bkk;
		akk:
			if (il->i_args[argno].local == 0) {
				e2->print();
				break;
			}
		}
		//no break
	case EQ:
	case NE:
	case GT:
	case GE:
	case LE:
	case LT:
	bkk:
	{	Ptype t1 = e1->tp;
		Ptype t2 = e2->tp;

                if (base!=ASSIGN) {
			cprint(e1);
		}
		else
			eprint(e1);
		puttok(base);

		if (t1 && t1!=t2 && e2->base!=ZERO) {
			// cast, but beware of int!=long etc.
		cmp:
			switch (t1->base) {
			case TYPE:
				t1 = Pbase(t1)->b_name->tp;
				goto cmp;
			default:
                        //        if (e2->base==NAME
                        //        && Pname(e2)->n_evaluated==0
                        //        && e2->tp->base==EOBJ)
                        //                fprintf(out_file,"(int)");
                                break;
                    //    case EOBJ:
                    //           if (base==ASSIGN) goto cst;
                    //          break;
			case PTR:
			case RPTR:
			case VEC:
				if (t2)
					while ( t2->base == TYPE ) 
						t2 = Pbase(t2)->b_name->tp;

				if (e2->tp==0
				|| (Pptr(t1)->typ!=Pptr(t2)->typ && t1->check(t2,0))) {
                   //     cst:
					putch('(');
					bit oc = Cast;
					Cast = 1;
					e1->tp->print();
					Cast = oc;
					putch(')');	
				}
			}
		}

		eprint(e2);
		break;
	}

	case DEREF:
		if (e2) {

			eprint(e1);
			putch('[');
			cprint(e2);
			putch(']');
		}
		else {
                        putch('(');
			putch('*');
			eprint(e1);
                        putch(')');
		}
		break;

	case ILIST:
		puttok(LC);
		if (e1) e1->print();
		if (e2) {	// member pointer initiliazers
			puttok(CM);
			e2->print();
		}
		puttok(RC);
		break;

	case ELIST:
	{	Pexpr e = this;
		for(;;) {
			if (e->base == ELIST) {
				e->e1->print();
				if (e = e->e2) {
					puttok(CM);
				}
				else
					return;
			}
			else {
				e->print();
				return;
			}
		}
	}

	case QUEST:
	{	// look for (&a == 0) etc.
		Neval = 0;
		binary_val = 1;
		long i = cond->eval();
		binary_val = 0;
		if (Neval == 0)
			(i?e1:e2)->print();
		else {
			eprint(cond);
			putch('?');
                	cprint(e1);
			putch(':');
                	cprint(e2);
		}
		break;
	}

	case CM:	// do &(a,b) => (a,&b) for previously checked inlines
	case G_CM:
		puttok(LP);
		switch (e1->base) {
		case ZERO:
		case IVAL:
		case ICON:
		case NAME:
		case MDOT:
		case DOT:
		case REF:
		case FCON:
		// case FVAL:
		case STRING:
			goto le2;	// suppress constant a: &(a,b) => (&b)
		default:
			{	int oo = addrof_cm;	// &(a,b) does not affect a
				addrof_cm = 0;
				eprint(e1);
				addrof_cm = oo;
			}
			puttok(CM);
		le2:
			if (addrof_cm) {
				switch (e2->base) {
				case CAST:
					if (e2->e2)
					switch (e2->e2->base) {
					case CM:
					case G_CM:
					case ICALL:	goto ec;
					}
				case NAME:
				case MDOT:
				case DOT:
				case DEREF:
				case REF:
				case ANAME:
					puttok(ADDROF);
					addrof_cm--;
					eprint(e2);
					addrof_cm++;
					break;
				case ICALL:
		//		case CALL:
				case CM:
				case G_CM:
				ec:
					eprint(e2);
					break;
				case G_CALL:
					/* & ( e, ctor() ) with temporary optimized away */
					if (e2->fct_name
					&& e2->fct_name->n_oper==CTOR) {
						addrof_cm--;
						eprint(e2);
						addrof_cm++;
						break;
					}
				default:
					error('i',"& inlineF call (%k)",e2->base);
				}
			}
			else
			//	e2->print();
				eprint(e2);
			puttok(RP);
		}
		break;

	case UPLUS: // only preserved for ansi_opt==1
	case UMINUS:
	case NOT:
	case COMPL:
        //      puttok(base);
        //      eprint(e2);
        //      break;
                goto op2;
	case ADDROF:
	case G_ADDROF:
		switch (e2->base) {	// & *e1 or &e1[e2]
		case DEREF:
			if (e2->e2 == 0) {	// &*e == e
				e2->e1->print();
				return;
			}
			break;
		case ICALL:
			addrof_cm++;	// assumes inline expanded into ,-expression
			eprint(e2);
			addrof_cm--;
			return;
		case ASSIGN:		// &(a=b)	??? works on many cc s
			eprint(e2);	// make sure it breaks!
			return;
		case NAME: {
			Pname n = Pname(e2);
			if(n->n_evaluated) {
				n->n_evaluated=0;
				puttok(ADDROF);
				eprint(e2);
				n->n_evaluated=1;
				return;
			}
			break;
			}
		}

		// suppress cc warning on &fct
		if (e2->tp==0 || e2->tp->base!=FCT) puttok(ADDROF);

		eprint(e2);
		break;

	case PLUS:
	case MINUS:
	case MUL:
	case DIV:
	case MOD:
	case LS:
	case RS:
	case AND:
	case OR:
	case ER:
	case ANDAND:
	case OROR:
        case DECR:
        case INCR:
                cprint(e1);
        op2:
		puttok(base);
		cprint(e2);
                break;
	case ASOR:
	case ASER:
	case ASAND:
	case ASPLUS:
	case ASMINUS:
	case ASMUL:
	case ASMOD:
	case ASDIV:
	case ASLS:
	case ASRS:
                eprint(e1);
                goto op2;

	default:
		error('i',"%p->E::print%k",this,base);
	//	fprintf(out_file," EEE(%d) ",base);
	}
}

Pexpr aval(Pname a)
{
	int argno = int(a->n_val);
	Pin il;
	for (il=curr_icall; il; il=il->i_next)
		if (il->i_table == a->n_table) goto aok;
	return 0;
aok:
	Pexpr aa = il->i_args[argno].arg;
ll:
	switch (aa->base) {
	case CAST:	aa = aa->e1; goto ll;
	case ANAME:	return aval(Pname(aa));
	default:	return aa;
	}
}

#define putcond()	putch('('); e->print(); putch(')')

static loc csloc = { 0, 0 }; // loc of last stmt with line!=0

void stmt::print()
{
//error('d',"S::print %d:%k s %d s_list %d",this,base,s,s_list);
	if (where.line == 0) {
	    if (csloc.line) csloc.putline();
	} else {
	    csloc = where;
	    if (where.line!=last_line.line)
		if (last_ll = where.line)
			where.putline();
		else
			last_line.putline();
	}

	if (memtbl && base!=BLOCK) { /* also print declarations of temporaries */
		puttok(LC);
		Ptable tbl = memtbl;
		memtbl = 0;
		int i;
		int bl = 1;
		for (Pname n=tbl->get_mem(i=1); n; n=tbl->get_mem(++i)){
			if (n->tp == any_type) continue;
			/* avoid double declarartion of temporaries from inlines */
			char* s = n->string;
			if (s[0]!='_' || s[1]!='_' || s[2]!='X') {
				n->dcl_print(0);
				bl = 0;
			}
			Pname cn;
			if (bl
			&& (cn=n->tp->is_cl_obj())
			&& Pclass(cn->tp)->has_dtor()) bl = 0;
		}
		if ( last_ll==0 && (last_ll = where.line) )
			where.putline();
		if (bl) {
			Pstmt sl = s_list;
			s_list = 0;
			print();
			memtbl = tbl;
			puttok(RC);
			if (sl) {
				s_list = sl;
				sl->print();
			}
		}
		else {
			print();
			memtbl = tbl;
			puttok(RC);
		}
		return;
	}

	switch (base) {
	default:
		error('i',"S::print(base=%k)",base);

	case ASM:
		fprintf(out_file,"asm(\"%s\");\n",(char*)e);
		break;

	case DCL:
		d->dcl_print(SM);
		break;

	case BREAK:
	case CONTINUE:
		puttok(base);
		puttok(SM);
		break;

	case DEFAULT:
		puttok(base);
		//puttok(COLON);
		putch(':');
		s->print();
		break;

	case SM:
		if (e) {
			e->print();
			if (e->base==ICALL && e->e2) break;	/* a block: no SM */
		}
		puttok(SM);
		break;

	case WHILE:
		puttok(WHILE);
		putcond();
		if (s->s_list) {
			puttok(LC);
			s->print();
			puttok(RC);
		}
		else
			s->print();
		break;

	case DO:
		puttok(DO);
		s->print();
		puttok(WHILE);
		putcond();
		puttok(SM);
		break;

	case SWITCH:
		puttok(SWITCH);
		putcond();
		s->print();
		break;

	case RETURN:
		{
		puttok(RETURN);
		if (e) {
//error('d',"print return rt %t etp %t",ret_tp,e->tp);
			if (ret_tp && ret_tp!=e->tp) {
				Ptype tt = ret_tp;
			gook:
				switch (tt->base) {
				case TYPE:
					tt = Pbase(tt)->b_name->tp;
					goto gook;
				case COBJ:
					break;	// cannot cast to struct
				case RPTR:
				case PTR:
					if (Pptr(tt)->typ==Pptr(e->tp)->typ) break;
					if (Pptr(tt)->memof) break;
				default:
					if (e->tp==0 || ret_tp->check(e->tp,0)) {
						int oc = Cast;
						putch('(');
						Cast = 1;
						ret_tp->print();
						Cast = oc;
						putch(')');
					}
				}
			}
			eprint(e);
		}
		puttok(SM);
		}
		while (s_list && s_list->base==SM) s_list = s_list->s_list; // FUDGE!!
		break;

	case CASE:
		puttok(CASE);
		eprint(e);
		putch(':');
		s->print();
		break;

	case GOTO:
		puttok(GOTO);
		d->print();
		puttok(SM);
		break;

	case LABEL:
		d->print();
		putch(':');
		s->print();
		break;

	case IF:
	{	int val = QUEST;
		if (e->base == ANAME) {
			Pname a = Pname(e);
			Pexpr arg = aval(a);
//error('d',"arg %d%k %d (%d)",arg,arg?arg->base:0,arg?arg->base:0,arg?arg->e1:0);
			if (arg)
				switch (arg->base) {
				case ZERO:	val = 0; break;
				case ADDROF:
				case G_ADDROF:	val = 1; break;
				case IVAL:	val = arg->i1!=0;
			}
		}
//error('d',"val %d",val);
		switch (val) {
		case 1:
			s->print();
			break;
		case 0:
			if (else_stmt)
				else_stmt->print();
			else
				puttok(SM);	/* null statement */
			break;
		default:
			puttok(IF);
			putcond();
			if (s->s_list) {
				puttok(LC);
				s->print();
				puttok(RC);
			}
			else
				s->print();
			if (else_stmt) {
				if (else_stmt->where.line == 0) {
				    if (csloc.line) csloc.putline();
				} else {
				    csloc = else_stmt->where;
				    if (else_stmt->where.line!=last_line.line)
					if (last_ll = else_stmt->where.line)
						else_stmt->where.putline();
					else
						last_line.putline();
				}
				puttok(ELSE);
				if (else_stmt->s_list) {
					puttok(LC);
					else_stmt->print();
					puttok(RC);
				}
				else
					else_stmt->print();
			}
		}
		break;
	}

	case FOR:
	{
	//	int fi = for_init && ((for_init->base!=SM || for_init->memtbl || for_init->s_list);
		int fi = 0;	// is the initializer statement an expression?
		if (for_init) {
			fi = 1;
			if (for_init->memtbl==0 && for_init->s_list==0)
				if (for_init->base==SM)
					if (for_init->e->base!=ICALL || for_init->e->e1)
						fi = 0;
		}
//error('d',"for(; %d%k; %d%k)",e,e->base,e2,e2->base);
		if (fi) {
			puttok(LC);
			for_init->print();
		}
		putstring("for(");
		if (fi==0 && for_init) for_init->e->print();
		putch(';');	// to avoid newline: not puttok(SM)
		if (e) e->print();
		putch(';');
		if (e2) e2->print();
		puttok(RP);
		s->print();
		if (fi) puttok(RC);
		break;
	}

	case PAIR:
		if (s&&s2) {
			puttok(LC);
			s->print();
			s2->print();
			puttok(RC);
		}
		else {
			if (s) s->print();
			if (s2) s2->print();
		}
		break;

	case BLOCK:
		puttok(LC);
//error('d',"block %d d %d memtbl %d own_tbl %d",this,d,memtbl,own_tbl);
		if (d) d->dcl_print(SM);
		if (memtbl && own_tbl) {
			Pname n;
			int i;
			for (n=memtbl->get_mem(i=1); n; n=memtbl->get_mem(++i)) {
				if (n->tp && n->n_union==0 && n->tp!=any_type)
					switch (n->n_scope) {
					case ARGT:
					case ARG:
						break;
					default:
// error('d', "n: %s %k n_key: %k", n->string, n->base, n->n_key);
						if ( n->base == TNAME && n->n_key == NESTED ) 
							continue; // printed from nested class
						n->dcl_print(0);
					}
			}
			if (last_ll==0 && s && (last_ll=s->where.line))
				s->where.putline();
		}
		if (s) s->print();
		if (where2.line == 0) {
		    if (csloc.line) csloc.putline();
		} else {
		    csloc = where2;
		    if (where2.line!=last_line.line)
			if (last_ll = where2.line)
				where2.putline();
			else
				last_line.putline();
		}
		putstring("}\n");
		if (last_ll && where.line) last_line.line++;
	}

	if (s_list) s_list->print();
}

/*
void table::dcl_print(TOK s, TOK pub)

//	print the declarations of the entries in the order they were inserted
//	ignore labels (tp==0)

{
	register Pname* np;
	register int i;

	if (this == 0) return;

	np = entries;
	for (i=1; i<free_slot; i++) {
		register Pname n = np[i];
		switch (s) {
		case 0:
			n->dcl_print(0);
			break;
		case EQ:
			if (n->tp && n->n_scope == pub) n->dcl_print(0);
			break;
		case NE:
			if (n->tp && n->n_scope != pub) n->dcl_print(0);
			break;
		}
	}
}
*/

struct ptbl_rec {
      char* pname;
      char* vname;
      ptbl_rec* next;
};

static char* ptbl_name;
static ptbl_rec* ptbl_rec_lookup_head = 0;
static ptbl_rec* ptbl_rec_pair_head = 0;

void ptbl_init(int flag)
{
      if (!flag) {
	      char *p = st_name( "__ptbl_vec__" );	
              ptbl_name = new char[strlen(p)+1];
              strcpy(ptbl_name, p);                         
              delete p;
              fprintf(out_file, "extern struct __mptr* %s[];\n", ptbl_name);
		if (last_ll) last_line.line++;
      }
      else {
              ptbl_rec *r, *p = ptbl_rec_lookup_head;
	      if ( p == 0 ) return; // don't generate an empty object
              fprintf(out_file, "struct __mptr* %s[] = {\n", ptbl_name);
		if (last_ll) last_line.line++;
              int i = 0;
              while (p != 0) {
                      r = ptbl_rec_pair_head;
                      while (r && strcmp(r->pname, p->pname))
                              r = r->next;
                      fprintf(out_file, "%s,\n", r->vname);
			if (last_ll) last_line.line++;
                      p = p->next;
              }
              // fprintf(out_file, "0\n};\n");
              fprintf(out_file, "\n};\n");
		if (last_ll) last_line.line += 2;
      }
}

char* ptbl_lookup(char *name)
{
      ptbl_rec *r, *s, *p = ptbl_rec_lookup_head;
      int i = 0;

      while (p && strcmp(name, p->pname)) {
              r = p;
              p = p->next;
              i++;
      }

      if (p == 0) {
              s = new ptbl_rec;
              s->pname = new char[strlen(name) + 1];
              s->vname = 0;
              s->next = 0;
              strcpy(s->pname, name);
              if (ptbl_rec_lookup_head == 0) 
                      ptbl_rec_lookup_head = s;
              else r->next = s;
      }

      char *pp = new char[ strlen(ptbl_name) + 10 ];  	
      sprintf(pp, "%s[%d]", ptbl_name, i);
      return(pp);
}

void ptbl_add_pair(char* ptbl, char* vtbl)
{
// error('d', "ptbl_add_pair: ptbl: %s, vtbl: %s", ptbl, vtbl );
      ptbl_rec *p = new ptbl_rec;

      p->pname = new char[strlen(ptbl) + 1];
      strcpy(p->pname, ptbl);
      p->vname = new char[strlen(vtbl) + 1];

      strcpy(p->vname, vtbl);
      p->next = ptbl_rec_pair_head;

      ptbl_rec_pair_head = p;
}