File:  [Research Unix] / researchv10no / cmd / cfront / xptcfront / cfront.cpio
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:35 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

0707071010112043441004440001630000160000010075200466055374000001000000013411alloc.c/*ident	"@(#)ctrans:src/alloc.c	1.4" */
/**************************************************************************

        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.

alloc.c:

*****************************************************************************/
#include "cfront.h"
#include "size.h"
#include "sysent.h"

const int NBITE = (CHUNK-8)/sizeof(name)-1;
const int EBITE = (CHUNK-8)/sizeof(expr)-1;
const int SBITE = (CHUNK-8)/sizeof(stmt)-1;
const int TBITE = (CHUNK-8)/sizeof(table)-1;
const int VBITE = (CHUNK-8)/sizeof(vec)-1;
const int FBITE = (CHUNK-8)/sizeof(fct)-1;
const int PBITE = (CHUNK-8)/sizeof(ptr)-1;

#define  mzero(p,l)  memset(p,0,l)

void* chunk(int i)	// get memory that is not to be freed
{
	register char* cp = malloc(i*CHUNK-8);
	if (cp == 0) {			// no space
		free((char*)gtbl);	// get space for error message
		error('i',"free store exhausted");
	}
	return cp;
}

#ifdef __HAVE_SIZE_T
#include <new.h>
#define NEW_SIZE size_t
#else
#define NEW_SIZE long
#endif

void* operator new(NEW_SIZE sz)	// get memory that might be freed
{
	char* p = calloc((unsigned)sz,1);

//fprintf(stderr,"alloc(%d)->%d\n",sz,p);

	if (p == 0) {			// no space
		free((char*)gtbl);	// get space for error message
		error('i',"free store exhausted");
	}
	return p;
}

void operator delete (void* p)
{
	if (p == 0) return;

//fprintf(stderr,"free(%d) %d\n",p,((int*)p)[-1]-(int)p-1+sizeof(int*));

	free((char*)p);
}

// class new and delete operators

void*
expr::operator new(size_t sz)
{
	register Pexpr p;

        if ( (p=expr_free) == 0 ) {
                register Pexpr q = (Pexpr) chunk(1);
                for (p=expr_free=&q[EBITE-1]; q<p; p--) {
                        p->e1 = p-1;
                        DB(p->node::allocated=0);
		}
		(p+1)->e1 = 0;
		DB(p->node::allocated=0);
	}
	else
		expr_free = p->e1;

	mzero(p,sz);
	return p;
}

void
expr::operator delete(void* vp, size_t)
{
	Pexpr p = (Pexpr)vp;

	DB( if(!p->node::allocated) error('i',"deleting unallocated expr:%k! -- id==%d",p->base,p->node::id);
	    p->node::allocated = 0;
	);
	p->e1 = expr_free;
	expr_free = p;
	vp = 0;
}

void*
stmt::operator new(size_t sz)
{
	register Pstmt p;
	if ( (p=stmt_free) == 0 ) {
		register Pstmt q = (Pstmt) chunk(1);
		for (p=stmt_free=&q[SBITE-1]; q<p; p--) {
			p->s_list = p-1;
			DB(p->node::allocated=0);
		}
		(p+1)->s_list = 0;
		DB(p->node::allocated=0);
	}
	else
		stmt_free = p->s_list;

	mzero(p,sz);
	return p;
}

void
stmt::operator delete(void* vp,size_t)
{
	Pstmt p = (Pstmt)vp;
	DB( if(!p->node::allocated) error('i',"deleting unallocated stmt:%k! -- id==%d",p->base,p->node::id);
	    p->node::allocated = 0;
	);
	p->s_list = stmt_free;
	stmt_free = p;
	vp = 0;
}

void*
name::operator new(size_t sz)
{
	register Pname p;

	if ( (p=name_free) == 0 ) {
		register Pname q = (Pname) chunk(1);
		for (p=name_free=&q[NBITE-1]; q<p; p--) {
			p->n_tbl_list = p-1;
			DB(p->node::allocated=0);
		}
		(p+1)->n_tbl_list = 0;
		DB(p->node::allocated=0);
	}
	else
		name_free = p->n_tbl_list;

	mzero(p,sz);
	return p;
}

void
name::operator delete(void* vp,size_t)
{
	Pname p = (Pname)vp;
	DB( if(!p->node::allocated) error('i',"deleting unallocated name %s! -- id==%d",p->string?p->string:"???",p->node::id);
	    p->node::allocated = 0;
	);
	p->n_tbl_list = name_free;
	name_free = p;
	vp = 0;
}

void*
table::operator new(size_t sz)
{
	register Ptable p;

	if ( (p=table_free) == 0 ) {
		register Ptable q = (Ptable) chunk(1);
		for (p=table_free=&q[TBITE-1]; q<p; p--) {
			p->next = p-1;
			DB(p->node::allocated=0);
		}
		(p+1)->next = 0;
		DB(p->node::allocated=0);
	}
	else
		table_free = p->next;

	mzero(p, sz);
	return p;
}

void
table::operator delete(void* vp,size_t)
{
	Ptable p = (Ptable)vp;
	DB( if(!p->node::allocated) error('i',"deleting unallocated table %d! -- id==%d",p->base,p->node::id);
	    p->node::allocated = 0;
	);
	p->next = table_free;
	table_free = p;
	vp = 0;
}

void*
vec::operator new(size_t sz)
{
	register Pvec p;

	if ( (p=vec_free) == 0 ) {
		register Pvec q = (Pvec) chunk(1);
		for (p=vec_free=&q[VBITE-1]; q<p; p--) {
			p->tlist = p-1;
			DB(p->node::allocated=0);
		}
		(p+1)->tlist = 0;
		DB(p->node::allocated=0);
	}
	else
		vec_free = (Pvec) p->tlist;

	mzero(p, sz);
	return p;
}

void
vec::operator delete(void* vp,size_t)
{
	Pvec p = (Pvec)vp;
	DB( if(!p->node::allocated) error('i',"deleting unallocated vec %d! -- id==%d",p->base,p->node::id);
	    p->node::allocated = 0;
	);
	p->tlist = vec_free;
	vec_free = p;
	vp = 0;
}

void*
fct::operator new(size_t sz)
{
	register Pfct p;

	if ( (p=fct_free) == 0 ) {
		register Pfct q = (Pfct) chunk(1);
		for (p=fct_free=&q[FBITE-1]; q<p; p--) {
			p->tlist = p-1;
			DB(p->node::allocated=0);
		}
		(p+1)->tlist = 0;
		DB(p->node::allocated=0);
	}
	else
		fct_free = (Pfct) p->tlist;

	mzero(p, sz);
	return p;
}

void
fct::operator delete(void* vp,size_t)
{
	Pfct p = (Pfct)vp;
	DB( if(!p->node::allocated) error('i',"deleting unallocated fct %d! -- id==%d",p->base,p->node::id);
	    p->node::allocated = 0;
	);
	p->tlist = fct_free;
	fct_free = p;
	vp = 0;
}

void*
ptr::operator new(size_t sz)
{
	register Pptr p;

//error('d',"ptr new");
	if ( (p=ptr_free) == 0 ) {
		register Pptr q = (Pptr) chunk(1);
		for (p=ptr_free=&q[PBITE-1]; q<p; p--) {
			p->tlist = p-1;
			DB(p->node::allocated=0);
		}
		(p+1)->tlist = 0;
		DB(p->node::allocated=0);
	}
	else 
		ptr_free = (Pptr) p->tlist;

	mzero(p, sz);
	return p;
}

void
ptr::operator delete(void* vp,size_t)
{
	Pptr p = (Pptr)vp;
	DB( if(!p->node::allocated) error('i',"deleting unallocated ptr %d! -- id==%d",p->base,p->node::id);
	    p->node::allocated = 0;
	);
	p->tlist = ptr_free;
	ptr_free = p;
	vp = 0;
}
0707071010112043451004440001630000160000010070500466055374500001100000070343cfront.h/*ident	"@(#)ctrans:src/cfront.h	1.12" */
/***********************************************************************

	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.

	When reading cfront code please remember that C++ was not available
	when it was originally written. Out of necessity cfront is written
	in a style that takes advantage of only few of C++'s features.

	WARNING: This program relies on non-initialized class members being ZERO.
	This will be true as long as they are allocated using the "new" operator
	from alloc.c

cfront.h:

	Here is all the class definitions for cfront, and most of the externs

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

#ifndef _CFRONT_H
#define _CFRONT_H

#include "token.h"
#include "typedef.h"

#ifndef GRAM
extern char* prog_name;		// compiler name and version
extern int inline_restr;	// inline expansion restrictions 
#endif

extern TOK	tlex();
extern Pname	syn();

extern void	ext(int);

extern char* 	make_name(TOK);
extern void 	make_dummy();
extern Pname	dummy_fct;
extern Pname    really_dominate(Pname, Pname, bit);
extern int      exact1(Pname, Ptype);

extern int friend_check(Pclass start,Pclass stop, Pfct f);

struct loc		// a source file location
{
	short	file;	// index into file_name[], or zero
	short	line;
#ifndef GRAM
	void	put(FILE*);
	void	putline();
#endif
};

extern Loc curloc;
extern int curr_file;
extern char* src_file_name;
extern loc noloc; // dummy null location
extern bit binary_val;
extern bit stmtno;

struct ea {	// fudge portable printf-like formatting for error()
	union {
		void* p;
		long i;
	};

	ea(const void* pp) { p = pp; }
	ea(long ii)   { i = ii; }
	ea() {}
};

extern ea* ea0;

overload error;
int error(const char*);
int error(const char*, const ea&, const ea& = *ea0, const ea& = *ea0, const ea& = *ea0);
int error(int, const char*);
int error(int, const char*, const ea&, const ea& = *ea0, const ea& = *ea0, const ea& = *ea0);
int error(loc*, const char*, const ea& = *ea0, const ea& = *ea0, const ea& = *ea0, const ea& = *ea0);
int error(int, loc*, const char*, const ea& = *ea0, const ea& = *ea0, const ea& = *ea0, const ea& = *ea0);
extern char emode;

extern int error_count;
extern int vtbl_opt;
extern int debug_opt;
extern int warning_opt;
extern int ansi_opt;
extern int strict_opt;
extern FILE* out_file;
extern FILE* in_file;
extern char scan_started;

extern int bl_level;
extern Ptable ktbl;		// keywords and typedef names
extern Ptable gtbl;		// global names
extern Ptable ptbl;		
extern Ptable lcl_tbl;
extern char* oper_name(TOK);
extern Pname def_name;
extern Pname pdef_name;
extern Pclass ccl;
extern Pbase defa_type;
extern Pbase moe_type;
extern Pbase mptr_type;

#ifndef GRAM
extern Pstmt Cstmt;		// current statement, or 0
extern Pname Cdcl;		// name currently being declared, or 0

extern Pbase any_type;
extern int largest_int;
#endif

extern Pbase int_type;
extern Pbase char_type;
extern Pbase short_type;
extern Pbase long_type;
extern Pbase uint_type;
extern Pbase float_type;
extern Pbase double_type;
extern Pbase ldouble_type;
extern Pbase void_type;

#ifndef GRAM
extern Pbase uchar_type;
extern Pbase ushort_type;
extern Pbase ulong_type;
extern Ptype Pchar_type;
extern Ptype Pint_type;
extern Ptype Pvptr_type;
extern Ptype Pfctvec_type;
extern Ptype Pvoid_type;
extern Pbase zero_type;
extern Ptype size_t_type;

extern int byte_offset;
extern int bit_offset;
extern int max_align;
extern int const_save;
extern int const_ptr;
extern int cm_const_save;
extern bit const_problem;
#endif

extern Pexpr dummy;	/* the empty expression */
extern Pexpr zero;
extern Pexpr one;
extern Pname sta_name;	/* qualifier for unary :: */

#define DEL(p) if (p && (p->permanent==0)) p->del()
#define PERM(p) p->permanent=1
#define UNPERM(p) p->permanent=0

struct node {
	TOK	base;
	bit	permanent;
        bit     baseclass; // base classes have NAME in their base ...
#ifdef DBG
	bit	displayed;	// avoid infinite recursion in display functions
	bit	allocated;	// set when not on free list
	long	id;
#endif
};
#ifdef DBG
extern long node_id;
extern int Adebug;
#define DBID() { node::id = ++::node_id; node::allocated=1; displayed=0; \
	if(Adebug>=1)fprintf(stderr,"\n*** allocated %d base %d\n",id,base); }
#else
#define DBID() /**/
#endif

struct table : node {
/*	a table is a node only to give it a "base" for debugging */
	bit	init_stat;	/* ==0 if block(s) of table not simplified,
				   ==1 if simplified but had no initializers,
				   ==2 if simplified and had initializers.
				*/
	short	size;
	short	hashsize;
	short	free_slot;	/* next free slot in entries */
	Pname*	entries;
	short*	hashtbl;
	Pstmt	real_block;	/* the last block the user wrote,
				   not one of the ones cfront created
				*/
	Ptable	next;		/* table for enclosing scope */
	Pname	t_name;		/* name of the table */

	static Ptable table_free;
	void* operator new(size_t);
	void operator delete(void*,size_t);

	table(short, Ptable, Pname);
	~table();

	Pname	look(char*, TOK);
	Pname	insert(Pname, TOK);
#ifndef GRAM
	void	grow(int);
	void	set_name(Pname n)	{ t_name = n; };
	Pname	get_mem(int);
	int	max()			{ return free_slot-1; };
	void	dcl_print(TOK,TOK);
#endif
	void	del();
};

#ifndef GRAM
extern bit Nold;
extern bit vec_const, fct_const;
#endif

extern void restore();
extern void set_scope(Pname);
extern Plist modified_tn;

// local class
extern Plist local_tn;
extern Plist local_blk;
extern Plist local_class;
extern void local_hide( Pname ); 
extern char *make_local_name(Pclass, int=0);

// nested type
extern Plist nested_tn;
extern Plist nested_type;
extern Pname curr_scope; 
extern Pname curr_fct; 
extern void nested_hide(Pname); 
extern int is_empty(Pclass,bit=0);

extern Pbase start_cl(TOK, Pname, Pbcl);
extern void end_cl();
extern Pbase end_enum(Pname, nlist*);

/************ types : basic types, aggregates, declarators ************/

#ifndef GRAM
extern bit new_type;
extern Pname cl_obj_vec;
extern Pname eobj;
#endif


#define DEFINED 01	/* definition fed through ?::dcl() */
#define SIMPLIFIED 02	/* in ?::simpl() */
#define DEF_SEEN 04	/* definition seen, but not processed */
#define REF_SEEN 010	/* reference seen (classdef) */
			/*   used for class members in norm.c */
#define IN_ERROR 010

struct type : node {
	bit	defined;	/* flags DEF_SEEN, DEFINED, SIMPLIFIED, IN_ERROR
					not used systematically yet
				*/
	bit	lex_level;
	Pclass  in_class; 	// nested type
	Pname	in_fct;		// local type
	char    *lcl;
	char	*nested_sig;
	char	*signature(char*);
	Ptype	tlist;
	bit	check(Ptype, TOK);
#ifndef GRAM
	void	print();
	void	dcl_print(Pname);
	void	base_print();

	Pname	is_cl_obj();	/* sets cl_obj_vec */
	Pptr	is_ref();
	Pptr	is_ptr();
	Pptr	is_ptr_or_ref();
	bit	is_unsigned();
	void	dcl(Ptable);
	int	tsizeof(int = 0);
	bit	tconst();
	TOK	set_const(bit);
	int	align();
	TOK	kind(TOK,TOK);
	TOK	integral(TOK oo)	{ return kind(oo,'I'); };
	TOK	numeric(TOK oo)		{ return kind(oo,'N'); };
	TOK	num_ptr(TOK oo)		{ return kind(oo,'P'); };
	bit	vec_type();
	Ptype	deref();
	inline Pptr	addrof();
	Pfct	memptr();
#endif
	void	del();
};

struct enumdef : type {	/* ENUM */
	bit	e_body;
	short	no_of_enumerators;
	unsigned char strlen;	// strlen(string)
	char*	string;		// name of enum
	Pname	mem;
	Pbase	e_type;		// type representing the enum
		enumdef(Pname n)	{ base=ENUM; mem=n; };
#ifndef GRAM
	void	print();
	void	dcl_print(Pname);
	void	dcl(Pname, Ptable);
	void	simpl();
#endif
};

struct velem {
	Pname	n;
	int	offset;
};

struct virt : node {
	Pvirt	next;
	int     n_init;
	velem*	virt_init;	// vector of vtbl initializers (zero-terminated)
	Pclass	vclass;		// for class vclass
	char*	string;
	bit	is_vbase;	// vtable for virtual base
	bit	printed;
 	virt(Pclass cl, velem* v, char* s, bit flag, int ni) {base = XVIRT; vclass=cl; virt_init=v; string=s; is_vbase=flag; next=0; n_init = ni;}
};

enum { C_VPTR=1, C_XREF=2, C_ASS=4, C_VBASE=8 };

// An enumeration of the types of classes for Objectstore
enum class_type_enum { vanilla_class,   // A regular class
                       template_class,
                       instantiated_template_class,
                       uninstantiated_template_class,
                       relationship_class,
                       defining_class 
};
class type_extension;

struct classdef : type {	/* CLASS */
        class_type_enum  class_base; // An extension of "base" to further define
                                // the real subtype of the class
	bit	c_body;		/* print definition only once */
	TOK	csu;		/* CLASS, STRUCT, UNION, or ANON */
	bit	obj_align;
	bit	c_xref;
		// 1 set:	has vptr(s) 
		// 2 set:	X(X&) exists
		// 4 set:	operator=(X&) exists
		// 8 set:	has vbaseptr(s)
		
	bit	virt_count;	// number of virtual functions
				// starting at max base class virt_count in
	bit	virt_merge;	// set when no virtual functions, but
				// need to merge virtual base classes
	bit	c_abstract;	// abstract class: don't instantiate
	bit	has_vvtab;	// set if class has vtable from virtual base
	unsigned char strlen;	// strlen(string)
	Pbcl	baselist;	// list of base classes
	char*	string;		/* name of class */
	Pname	mem_list;
	Ptable	memtbl;
	int	obj_size;
	int	real_size;	/* obj_size - alignment waste */
	Plist	friend_list;
	Pname	pubdef;
	Plist	tn_list;	// list of member names hiding type names
	Plist	nest_list;	// list of nested types
	Ptype	this_type;
	Pvirt	virt_list;	// vtbl initializers
	Pname	c_ctor;		// constuctor:
				// possibly overloaded, possibly inherited
	Pname	c_dtor;		// destructor
	Pname	c_itor;		/* constructor X(X&) */
	Pname	conv;		/* operator T() chain */
	struct toknode *c_funqf, *c_funqr; // token Q for parsing function defs after class def

	classdef(TOK);
	~classdef();
	TOK	is_simple()	{ return (csu==CLASS)?0:csu; };
#ifndef GRAM
	void	print();
	void	dcl_print(Pname);
	void	simpl();

	void	print_members();
	void	dcl(Pname, Ptable);

//	bit	has_friend(Pname);
	bit	has_friend(Pclass);
	bit	has_friend(Pfct);

	bit	has_base(Pclass cl);
	bit	baseof(Pname);
	bit	baseof(Pclass);
	Pclass	is_base(char*);

	Pname	has_oper(TOK);
	Pname	has_ctor()	{ return c_ctor; }
	Pname	has_dtor()	{ return c_dtor; }
	Pname	has_itor()	{ return c_itor; }
	Pname	has_ictor();
	Pname	make_itor(int);
	Pexpr	find_name(char*, Pclass, int=0);
	int	do_virtuals(Pvirt, char*, int, bit);
	int	all_virt(Pclass, char*, int, bit);
	void	add_vtbl(velem*, char*, bit, int);
	void	print_all_vtbls(Pclass);
	void	print_vtbl(Pvirt);
	void	really_print(Pvirt);
	int	check_dup(Pclass, TOK);
	int	has_allocated_base(Pclass);
	char 	*has_allocated_base(char*);
	int	get_offset(char*);
	Pbcl	get_base(char*);
	Pexpr	get_vptr_exp(char*);
	Pexpr	find_in_base(char*, Pclass);
        void    modify_inst_names(char *s); // Adjust ctor names for instantiation
        bit     parametrized_class();
        bit 	same_class(Pclass p);
#endif
};

#ifndef GRAM

class clist {
	Pclass cl;
	clist* next;
public:
	clist(Pclass c, clist* n) { cl=c; next=n; }
	int onlist(Pclass);
	void clear();
};
	
extern clist * vcllist;

struct vl {
	struct vl* next;
	Pvirt vt;
	classdef* cl;

	vl(classdef* c, Pvirt v, struct vl* n)
		{ cl = c; vt = v; next = n; }
};

extern vl* vlist;

extern int nin;
extern int Nvis;
extern int Noffset;
extern TOK Nvirt;
extern Pexpr Nptr;
extern Pbcl Nvbc_alloc;
extern char *Nalloc_base;
extern Pexpr rptr(Ptype,Pexpr,int);
extern Pexpr vbase_args(Pfct, Pname);
extern Pexpr cdvec(Pname,Pexpr,Pclass,Pname,int,Pexpr,Pexpr=0);

extern Pexpr find(char*, Pclass, int);
extern Pexpr find_name(Pname, Pclass, Ptable, int, Pname);
extern Pname find_virtual(Pclass,Pname);
extern Pname vfct(Pclass, char*);
extern int Vcheckerror;
extern int ignore_const;	

extern int mex;
extern Pclass mec;
extern Pclass tcl;
#endif

struct basetype : type
	/*	ZTYPE CHAR SHORT INT LONG FLOAT DOUBLE
		FIELD EOBJ COBJ TYPE ANY
	*/
	/*	used for gathering all the attributes
		for a list of declarators

		ZTYPE is the (generic) type of ZERO
		ANY is the generic type of an undeclared name
	*/
{
	bit	b_unsigned;
	bit	b_signed;
	bit	b_volatile;
	bit	b_const;
	bit	b_typedef;
	bit	b_inline;
	bit	b_virtual;
	bit	b_short;
	bit	b_long;
	bit	b_bits;		/* number of bits in field */
	bit	b_offset;	// bit offset of field
	TOK	b_sto;		/* AUTO STATIC EXTERN REGISTER 0 */
	Pname	b_name;		/* name of non-basic type */
	Ptable	b_table;	/* memtbl for b_name, or 0 */
	Pname	b_xname;	/* extra name */
	union {
	Ptype	b_fieldtype;
	char*	b_linkage;
	};

	basetype(TOK, Pname);

	Pbase	type_adj(TOK);
	Pbase	base_adj(Pbase);
	Pbase	name_adj(Pname);
	Pname   aggr();
	Pbase	check(Pname);
#ifndef GRAM
	void	dcl_print();
 	Pbase	arit_conv(Pbase);
        bit     parametrized_class();
#endif
	int     discriminator(int); // union discriminator fcn 
};

enum Linkage { linkage_default, linkage_C, linkage_Cplusplus };
extern Linkage linkage;
void set_linkage(char*);

struct fct : type		// FCT
{
	TOK	nargs;
	TOK	nargs_known;	// 0 if unknown, 1 if known, or ELLIPSIS
	bit  	last_stmt;
	bit	f_vdef;		// 1 if this is the first virtual definition
				// of this function
	bit	f_inline;	// 1 if inline, 2 if being expanded, else 0
	bit	f_const;	// one if member function that may be called for
				// a const object, else 0
	bit	f_static;	// 1 if static member function, else 0
	short	f_virtual;	// index in virtual table, or 0 meaning non-virtual
	short	f_imeasure;	// some measure of the size of an inline function
	Ptype	returns;
	Pname	argtype;
	Ptype	s_returns;
	Pname	f_this;
	Pclass	memof;		// member of class memof
	Pblock	body;
	Pname	f_init;		// base and member initializers
	Pexpr	f_expr;		// body expanded into an expression
	Pexpr	last_expanded;
	Pname	f_result;	// extra second argument of type X&
	Pname	f_args;		// argument list including args added by cfront
	Linkage	f_linkage;
	char*	f_signature;	// character encoding of function type
	Plist local_class;	// list of local classes
	static Pfct fct_free;
	void*	operator new(size_t);
	void	operator delete(void*,size_t);

	fct(Ptype, Pname, TOK);
	void	argdcl(Pname,Pname);
#ifndef GRAM
	Ptype	normalize(Ptype);
	void	dcl_print();
	void	dcl(Pname);
	Pexpr	base_init(Pclass, Pexpr, Ptable, int);
	Pexpr	mem_init(Pname, Pexpr, Ptable);
	void	init_bases(Pclass, Pexpr);
	bit	declared() { return nargs_known; };
	void	simpl();
	int	ctor_simpl(Pclass, Pexpr);
	Pstmt	dtor_simpl(Pclass, Pexpr);
	Pexpr	expand(Pname,Ptable,Pexpr);
	void	sign();
#endif
	int     discriminator(int); // union discriminator fcn 
};

struct name_list : node {
	Pname	f;
	Plist	l;
        name_list(Pname ff, Plist ll) { base = XNLIST; f=ff; l=ll; };
};

#ifndef GRAM
struct gen : type {		// OVERLOAD
	Plist	fct_list;

	gen() { base = OVERLOAD; }
	Pname	add(Pname);
	Pname  	find(Pfct, bit);
	Pname	match(Pname, Pfct, bit);
};
#endif

struct pvtyp : type {
	Ptype typ;
};

struct vec : pvtyp		// VEC
				// typ [ dim ]
{
	Pexpr	dim;
	int	size;	

	static Pvec vec_free;
	void*	operator new(size_t);
	void	operator delete(void*,size_t);

	vec(Ptype t, Pexpr e) { base=VEC; typ=t; dim=e; DBID(); }
#ifndef GRAM
	Ptype	normalize(Ptype);
#endif
};

struct ptr : pvtyp		// PTR, RPTR i.e. reference
{
	Pclass	memof;		// pointer to member of memof: memof::*
	bit	rdo;		// "*const"

	static Pptr ptr_free;
	void*	operator new(size_t);
	void	operator delete(void*,size_t);

	ptr(TOK b, Ptype t) { base=b; typ=t; DBID(); }
#ifndef GRAM
	Ptype	normalize(Ptype);
#endif
};

#ifndef GRAM
inline Pptr type::addrof() { return new ptr(PTR,this); }

extern bit vrp_equiv;
#endif


/****************************** constants ********************************/

		/* STRING ZERO ICON FCON CCON ID */
		/* IVAL FVAL LVAL */

/***************************** expressions ********************************/

#ifndef GRAM
extern Pexpr next_elem();
extern void new_list(Pexpr);
extern void list_check(Pname, Ptype, Pexpr, Ptable=0);
extern Pexpr ref_init(Pptr,Pexpr,Ptable);
extern Pexpr class_init(Pexpr,Ptype,Pexpr,Ptable);
extern Pexpr check_cond(Pexpr, TOK, Ptable);
extern Pexpr ptof(Pfct,Pexpr,Ptable);
extern void dosimpl(Pexpr, Pname);
extern int ref_initializer;
extern int ntok;

extern void ptbl_init(int);
extern void ptbl_add_pair(char*,char*);
extern char *ptbl_lookup(char*);
extern char *st_name(char*);
#endif

struct expr : node	/* PLUS, MINUS, etc. */
	/* IMPORTANT:	all expressions are of sizeof(expr) */
	/*	DEREF		=>	*e1 (e2==0) OR e1[e2]
		UMINUS		=>	-e2
		INCR (e1==0)	=>	++e2
		INCR (e2==0)	=>	e1++
		CM		=>	e1 , e2
		ILIST		=>	LC e1 RC   (an initializer list)
		a Pexpr may denote a name
	*/
{
	union {
		Ptype	tp;
		char 	*string4;
	};
	union {
		Pexpr	e1;
		long	i1;
		char*	string;
	};
	union {
		Pexpr	e2;
		int	i2;
		char*	string2;
		Pexpr	n_initializer;
		Ptype	tpdef;  // local and nested typedef info
	};
	union {			/* used by the derived classes */
		Ptype	tp2;    
		Pname	fct_name;
		Pexpr	cond;
		Pexpr	mem;
		Ptype	as_type;
		Ptable	n_table;
		Pin	il;
		Pname	query_this; 
	};

	static Pexpr expr_free;
	void* operator new(size_t);
	void operator delete(void*,size_t);
	expr(TOK, Pexpr, Pexpr);
	void	del();
#ifndef GRAM
	void	print();
        Pexpr   typ0(Ptable);
	Pexpr	typ(Ptable);
	long	eval();
	unsigned long ueval(long,long);
	int	lval(TOK);
	Ptype	call_fct(Ptable);
	Pexpr	address();
	Pexpr	contents();
	void	simpl();
	Pexpr	expand();
	bit	not_simple();
	Pexpr	try_to_overload(Ptable);
	Pexpr	docast(Ptable);
	Pexpr	dovalue(Ptable);
	Pexpr	donew(Ptable);
	void	simpl_new();
	void	simpl_delete();
#endif
	int     discriminator(int); // union discriminator fcn 
};

struct texpr : expr {		// CAST NEW VALUE (also ICALL)
	texpr(TOK bb, Ptype tt, Pexpr ee) : expr (bb,ee,0) { tp2=tt; }
};

struct cast : expr {		// CAST
	cast(Ptype tt, Pexpr ee) : expr (CAST,ee,0) { tp=tp2=tt; }
};

struct ival : expr {		// IVAL
	ival(long ii) : expr (IVAL,0,0) { i1 = ii;}
};

struct call : expr {		// CALL
	call(Pexpr aa, Pexpr bb) : expr (CALL,aa,bb) { }
#ifndef GRAM
	void	simpl();
	Pexpr	expand(Ptable);
#endif
};

struct qexpr : expr {		// QUEST	cond ? e1 : e2
	qexpr(Pexpr ee, Pexpr ee1, Pexpr ee2) : expr (QUEST,ee1,ee2) { cond=ee; }
};

struct ref : expr {		// REF DOT	e1->mem OR e1.mem
	ref(TOK ba, Pexpr a, Pexpr b) : expr (ba,a,0) { mem=b; }
};

struct mdot : expr {		// MDOT		a.b
	mdot(char* a, Pexpr b) : expr (MDOT,0,0) { string2=a; mem=b; }
};

struct text_expr : expr	{	// TEXT (vtbl_name)
	text_expr(char* a, char* b) : expr (TEXT,0,0)
	{ string=a; string2=b; }
};
char* vtbl_name(char*,char*);
/************************* names (are expressions) ****************************/

struct basecl : node {	// NAME		=> base class
			// VIRTUAL	=> virtual base class
	TOK	ppp;		// private / public / protected
	bit	allocated;	// allocated virtual base
        bit     promoted;       // non-explicit, promoted virtual base
	Pclass	bclass;
	Pexpr	init;		// base class initializers for ctors
	int	ptr_offset;	// pointer's relative position in derived class
	int	obj_offset;	// object's relative position in derived class
	Pname*	virt_init;	// vector of vtbl table initializers
	basecl*	next;

        basecl(Pclass cl, basecl* n) { baseclass=1; bclass=cl; next=n; promoted=0; init=0;}
};

enum template_formal_types { 
	template_type_formal =1 , template_expr_formal,
        template_stmt_tree_formal, template_expr_tree_formal,
        template_actual_arg_dummy // used during the parse
};
extern TOK ppbase;

struct name : expr {	// NAME TNAME and the keywords in the ktbl
	TOK	n_oper;		// name of operator or 0
	TOK	n_sto;		// EXTERN STATIC AUTO REGISTER ENUM 0
	TOK	n_stclass;	// STATIC AUTO REGISTER 0
	TOK	n_scope;	// EXTERN STATIC FCT ARG PUBLIC 0 
	TOK	n_key;	/* for names in table: class */
	bit	n_evaluated;	// 0 or n_val holds the value
	bit	n_xref;		// argument of type X(X&)
	unsigned char	lex_level;
	TOK	n_protect;	// PROTECTED (<=>n_scope==0) or 0
	bit	n_dcl_printed;	// 1: declaration printed
				// 2: definition printed
				// 0: declaration not printed

        // if this is set it implies that n_template_arg == template_type_formal
	char    n_template_arg; // One of template_formal_types for template arguments
        bit     n_template_formal_must_be_class ;
        bit     n_redefined ;   // set only for PT function names where an explict
                                // definition was provided.
        char    *n_anon;	// nested anonymous unions
	short	n_union;	// 0, or union index
	short	n_addr_taken;
	short	n_used;
	short	n_assigned_to;
	Loc	where;
	int	n_offset;	// byte offset in frame or struct
	Pname	n_list;
	Pname	n_tbl_list;
	char    *n_gen_fct_name; // used to be punned with n_tbl_list.
        char    *n_template_arg_string ; // the mangled string name
	union {
	/* 
	 * n_qualifier: name of containing class
	 * n_realscope: for labels (always entered in function table) 
         *		the table for the actual scope in which label occurred.
	 * syn_class: lex table only
	 */
		Pname	n_qualifier;	
                Ptable  n_realscope;    
		int     syn_class; 
        };

	/* n_val: the value of n_initializer; also the argument 
	 * number for inline arguments (when base == ANAME) */
	long	n_val;		
	static Pname name_free;
	void* operator new(size_t);
	void operator delete(void*,size_t);
	name(char* =0);


	Pname	normalize(Pbase, Pblock, bit);
	Pname	tdef();
	Pname	tname(TOK);
	void	hide();
	void	unhide()	{ n_key=0; n_list=0; };
#ifndef GRAM
	Pname	dcl(Ptable,TOK);
	int	no_of_names();
	void	use()		{ n_used++; };
	void	assign();
	void	take_addr();
	void	check_oper(Pname);
	void	simpl();
	void	print();
	void	dcl_print(TOK);
	void	field_align();
	Pname	dofct(Ptable,TOK);
#endif
	void	del();
	int     discriminator(int); // union discriminator fcn 
};

extern int friend_in_class;
extern int in_class_dcl;

// from parser
extern int in_class_decl;
extern int parsing_class_members;
extern int in_mem_fct;
extern int in_arg_list;
extern Ptype in_typedef;
extern int	defer_check;	 // redefinition typedef check delay
extern int	declTag;	 // !1: inline, virtual mod permitted
extern Pname in_tag;
extern Pname statStat;
extern int DECL_TYPE;

/******************** statements *********************************/

struct stmt : node {	/* BREAK CONTINUE DEFAULT */
/*	IMPORTANT: all statement nodes have sizeof(stmt) */
	Pstmt	s;
	Pstmt	s_list;
	Loc	where;
	union {
		Pname	d; // goto/block -- destination
		Pexpr	e2; // for iteration
		Pstmt	has_default; // switch statement default
		int	case_value; 
		Ptype	ret_tp; // pair
	};
	union {
		Pexpr	e;
		bit	own_tbl;
		Pstmt	s2;
	};
	Ptable	memtbl;
	union {
		Pstmt	for_init;
		Pstmt	else_stmt;
		Pstmt	case_list;
		Loc	where2; // location of } at end of block
	};

	static Pstmt stmt_free;
	void* operator new(size_t);
	void operator delete(void*,size_t);
	stmt(TOK, loc, Pstmt);
	void	del();
#ifndef GRAM
	void	print();
	void	dcl();
        void    dcl1(Pstmt&);
	void	reached();
	Pstmt	simpl();
	Pstmt	expand();
	Pstmt	copy();
#endif
	int     discriminator(int); // union discriminator fcn 
};

#ifndef GRAM
extern char* Neval;
extern Ptable scope;
extern Ptable expand_tbl;
extern Pname expand_fn;
#endif

struct estmt : stmt	/* SM WHILE DO SWITCH RETURN CASE */
	/*	SM (e!=0)	=>	e;
		in particular assignments and function calls
		SM (e==0)	=>	;	(the null statement)
		CASE		=>	case e : s ;
		SM_PARAM        => e is the template_statement_tree_formal name
	*/
{
	estmt(TOK t, loc ll, Pexpr ee, Pstmt ss) : stmt (t,ll,ss) { e=ee; }
};

struct ifstmt : stmt	/* IF */
	// else_stme==0 =>	if (e) s
	// else_stmt!=0 =>	if (e) s else else_stmt
{
	ifstmt(loc ll, Pexpr ee, Pstmt ss1, Pstmt ss2)
		: stmt (IF,ll,ss1) { e=ee; else_stmt=ss2; };
};

struct lstmt : stmt	/* LABEL GOTO */
	/*
		d : s
		goto d
	*/
{
	lstmt(TOK bb, loc ll, Pname nn, Pstmt ss) : stmt (bb,ll,ss) { d=nn; }
};

struct forstmt : stmt {	// FOR
	forstmt(loc ll, Pstmt fss, Pexpr ee1, Pexpr ee2, Pstmt ss)
		: stmt (FOR,ll,ss) { for_init=fss; e=ee1; e2=ee2; }
};

struct block : stmt {	// BLOCK	{ d s }
	block(loc ll, Pname nn, Pstmt ss, loc rr = noloc ) : stmt (BLOCK,ll,ss)
		{ d=nn; where2=rr; }
#ifndef GRAM
	void	dcl(Ptable);
	Pstmt	simpl();
#endif
};

#ifndef GRAM
struct pair : public stmt {	// PAIR
	pair(loc ll, Pstmt a, Pstmt b) : stmt (PAIR,ll,a) { s2 = b; }
};
#endif

struct nlist {
	Pname	head;
	Pname	tail;
		nlist(Pname);
	void	add(Pname n)	{ tail->n_list = n; tail = n; };
	void	add_list(Pname);
};

extern Pname name_unlist(nlist*);

struct slist {
	Pstmt	head;
	Pstmt	tail;
		slist(Pstmt s)	{ /*Nl++;*/ head = tail = s; };
	void	add(Pstmt s)	{ tail->s_list = s; tail = s; };
};

extern Pstmt stmt_unlist(slist*);

struct elist {
	Pexpr	head;
	Pexpr	tail;
		elist(Pexpr e)	{ /*Nl++;*/ head = tail = e; };
	void	add(Pexpr e)	{ tail->e2 = e; tail = e; };
};

extern Pexpr expr_unlist(elist*);

#ifndef GRAM 
extern class dcl_context * cc;

struct dcl_context {
	Pname	c_this;	/* current fct's "this" */
	Ptype	tot;	/* type of "this" or 0 */
	Pname	not;	/* name of "this"'s class or 0 */
	Pclass	cot;	/* the definition of "this"'s class */
	Ptable	ftbl;	/* current fct's symbol table */
	Pname	nof;	/* current fct's name */

	void	stack()		{ cc++; *cc = *(cc-1); };
	void	unstack()	{ cc--; };
};

#define MAXCONT	20
extern dcl_context ccvec[MAXCONT];
#endif 

extern void yyerror(char*);


#ifndef GRAM
extern char* line_format;

extern Plist stat_mem_list;
extern Plist isf_list;
extern Pstmt st_ilist;
extern Pstmt st_dlist;
extern Ptable sti_tbl;
extern Ptable std_tbl;
extern int need_sti( Pexpr e, Ptable tbl = 0, bit is_static_ok = 0 ); 
Pexpr try_to_coerce(Ptype, Pexpr, char*, Ptable);
extern bit can_coerce(Ptype, Ptype);
extern Ptype np_promote(TOK, TOK, TOK, Ptype, Ptype, TOK);
extern bit enum_promote;
extern int suppress_error;
extern void delete_local();

extern int over_call(Pname, Pexpr);
extern Pname overFound;
extern Pname Nover;
extern Pname Ncoerce;
extern Nover_coerce;
struct ia : node {
	Pname	local;	// local variable for argument
	Pexpr	arg;	// actual arguments for call
	Ptype	tp;	// type of formal argument
        ia() { base = XIA; };
};

struct iline : node {
	Pname	fct_name;	/* fct called */
	Pin	i_next;
	Ptable	i_table;
	int	i_slots;	// no of arg slots pointer to by i_args
	ia*	i_args;
        iline() { base = XILINE; };
};

extern Pexpr curr_expr;
extern Pin curr_icall;
#define FUDGE111 11111
#define VTOK 22222
#define ITOR 77

extern Pstmt curr_loop;
extern Pblock curr_block;
extern Pstmt curr_switch;
extern loc last_line;  // last #line + number of '\n's output since
extern int last_ll;    // 0 or line of current stmt/dcl being printed
extern FILE* out_file; // output file descriptor
extern bit Cast;
extern loc no_where;

extern no_of_undcl;
extern no_of_badcall;
extern Pname undcl, badcall;

extern long str_to_long(const char*);
extern int c_strlen(const char* s);
#endif

#ifndef GRAM
extern Pname vec_new_fct;
extern Pname new_fct;
extern Pname del_fct;
extern Pname vec_del_fct;

extern int Nstd; // standard coercion used (derived* =>base* or int=>long or ...)

extern int stcount;	// number of names generated using make_name()

Pexpr replace_temp(Pexpr,Pexpr);
void make_res(Pfct);

extern int Pchecked;
Pexpr ptr_init(Pptr,Pexpr,Ptable);
Pexpr call_ctor(Ptable, Pexpr p, Pexpr ctor, Pexpr args, int d = REF, Pexpr vb_args = 0);
Pexpr call_dtor(Pexpr p, Pexpr dtor, Pexpr arg = 0, int d = DOT, Pexpr vb_args = 0);
void check_visibility(Pname, Pname, Pclass, Ptable, Pname);

int make_assignment(Pname);

extern Pname make_tmp(char, Ptype, Ptable);
Pexpr init_tmp(Pname, Pexpr, Ptable);

extern int is_unique_base(Pclass, char*, int, int = 0);
extern Pexpr rptr(Ptype, Pexpr, int);

extern int read_align(char*);
extern void new_init();

extern void Eprint(Pexpr);
extern Pexpr cast_cptr(Pclass ccl, Pexpr ee, Ptable tbl, int real_cast);
extern Pexpr mptr_assign(Pexpr,Pexpr);
extern Pclass Mptr;

#endif

extern bit fake_sizeof;	// suppress error message for ``int v[];''

extern TOK lalex();


#ifdef DBG
extern void display_expr( Pexpr, char* = 0, int = 0 );
extern void display_stmt( Pstmt, char* = 0, int = 0 );
extern void display_type( Ptype );
extern void display_namelist( Plist, char* = 0, int = 0 );

extern fprintf(const FILE*, const char* ...);
extern void process_debug_flags( char* );
#define DB(a) if(scan_started){a;}
extern int Adebug; // allocation (ctor/del) debugging
extern int Ddebug; // dcl debugging
extern int Edebug; // expr debugging
extern int Ldebug; // lex/lalex debugging
extern int Mdebug; // trace function matching
extern int Ndebug; // norm debugging
extern int Pdebug; // print debugging
extern int Rdebug; // run() debugging
extern int Sdebug; // simpl debugging
extern int Tdebug; // typ debugging
#define Ydebug yydebug
extern int Ydebug; // yacc debugging

#else

#define DB(a) /**/

#endif

#endif
/* end */
0707071010112043661004440001630000160000010071100466055375100000600000112027dcl.c/*ident	"@(#)ctrans:src/dcl.c	1.5" */
/**************************************************************************

	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.

dcl.c:

	``declare'' all names, that is insert them in the appropriate symbol tables.

	Calculate the size for all objects (incl. stack frames),
	and find store the offsets for all members (incl. auto variables).
	"size.h" holds the constants needed for calculating sizes.

	Note that (due to errors) functions may nest

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


#include "cfront.h"
#include "size.h"

class dcl_context ccvec[MAXCONT], * cc = ccvec;
int byte_offset;
int bit_offset;
int max_align;
int friend_in_class;
static Pstmt itail;

Pname dclass(Pname, Ptable);
Pname denum(Pname, Ptable);
void merge_init(Pname, Pfct, Pfct);

void dosimpl(Pexpr e, Pname n)
{
//error('d',"dosimpl %k %n",e?e->base:0,n);
	if (n==0) {
		if (dummy_fct == 0) make_dummy();
		n = dummy_fct;
	}
	Pname cf = curr_fct;
	curr_fct = n;
	e->simpl();
	curr_fct = cf;
}

static Pexpr co_array_init(Pname n, Ptable tbl)
/*
	handle simple arrays only. To be done well list_check() must
	be rewritten to handle dynamic initialization.
*/
{
// error('d',"Ir forCO%n\[\]",n);
	Pexpr init = n->n_initializer;

	if (init->base != ILIST) {
		error("badIr for array ofCOs %n",n);
		return 0;
	}

	Pexpr el = 0;
	Pvec v = Pvec(n->tp);
	while (v->base==TYPE) v = Pvec(Pbase(v)->b_name->tp);
	Pname cn = v->typ->is_cl_obj();
	Pclass cl = cn ? Pclass(cn->tp) : 0;
//error('d',"v %t cl %d %t",v,cl,cl);
	int i = v->size;

	int count = 0;
	Pexpr il2;
	for (Pexpr il = init->e1; il; il = il2) {
			// generate	n[0].cl(initializer),
			//		...
			//		n[max].cl(initializer),
		Pexpr e = il->e1;
		il2 = il->e2;
		il->e2 = 0;
		if  (e == dummy) break;
//error('d',"il %k e %k",il->base,e?e->base:0);
		if (e->base == VALUE) {
			switch (e->tp2->base) {
			case CLASS:
				if (Pclass(e->tp2)!=cl) e = new texpr(VALUE,cl,il);
				break;
			default:
				Pname n2 = e->tp2->is_cl_obj();
				if (n2==0 || Pclass(n2->tp)!=cl) e = new texpr(VALUE,cl,il);
			}
		}
		else
			e = new texpr(VALUE,cl,il);
		e->e2 = new expr(DEREF,n,new ival(count++));
		e = e->typ(tbl);
		dosimpl(e,cc->nof);
	//	e->simpl();
		if (sti_tbl == tbl) {
			Pstmt ist = new estmt(SM,no_where,e,0);
			if (st_ilist == 0)
				st_ilist = ist;
			else
				itail->s_list = ist;
			itail = ist;
		}
		else {
			el = el ? new expr(G_CM,el,e) : e;
		}
	}

	if (i==0)
		v->size = count;
	else if (i==count)
		;
	else if (i<count) {
                error("too manyIrs for%n (%d)",n, count);
		return 0;
	}	
	else {
//              error('d',"too fewIrs for%n (%d)",n, count);
		if (cl->has_ictor())
                	error('s',"too fewIrs for%n",n);
		else error( "too fewIrs for%n (C %srequires a defaultK)", n, cl->string );
		return 0;
	}
	return el;
}

int need_sti(Pexpr e, Ptable tbl, bit accept_name)
/*
	check if non-static variables or operations are used
	INCOMPLETE 
*/
{
	if (e == 0) return 0;
// error('d',"need_sti: %d - %d %k %t",tbl?1:0,accept_name,e->base,e->tp);

	switch (e->base) {
	case QUEST:
		if (need_sti(e->cond,tbl,0) && tbl==0) return 1;
	case PLUS:
	case MINUS:
	case MUL:
	case DIV:
	case MOD:
	case ER:
	case OR:
	case ANDAND:
	case OROR:
	case LS:
	case RS:
	case EQ:
	case NE:
	case LT:
	case LE:
	case GT:
	case GE:
	case INCR:
	case DECR:
	case ASSIGN:
		if (need_sti(e->e1,tbl,accept_name) && tbl==0) return 1;
		// no break;

	case UMINUS:
	case UPLUS:
	case NOT:
	case COMPL:
		if (need_sti(e->e2,tbl,accept_name) && tbl==0) return 1;
		// no break

	case SIZEOF:
	default:

		return 0;

	case CAST:

		return need_sti(e->e1,tbl,accept_name);

	case ADDROF:
	{
		int i = need_sti(e->e2,tbl,1);
		return i;
	}

	case NAME:
		if (accept_name && Pname(e)->n_stclass==STATIC) return 0;

//		if ((Pname(e)->n_stclass==AUTO || Pname(e)->n_stclass==REGISTER)
//		&&   strncmp(Pname(e)->string,"__Q",3) != 0 ) {
//			error("localN%n inIr for static",e);
//			return 0;
//		}

		if (e->tp->tconst()) {
			if (vec_const || fct_const) return 0;
			Neval = 0;
			e->eval();
			if (Neval == 0) return 0;
		}
		return 1;

	case DEREF:
	case REF:
	case DOT:
		if (accept_name||(e->tp && e->tp->base==VEC)) {
			int x1 = need_sti(e->e1,tbl,e->base == DOT);
			int x2 = need_sti(e->e2,tbl,0);
			return x1 || x2;
		}
		// no break

	case ELIST:
//	case ILIST:
	case G_CM:
	case CM:
		if (e->base==CM) {
			if (need_sti(e->e1,tbl,0) || need_sti(e->e2,tbl,0))
				return 1;
			else
				return 0;
		}
	case CALL:
	case G_CALL:
	case NEW:
	case GNEW:
	case 0:			// hack for `new type (expr)'
		if (tbl) {
			need_sti(e->e1,tbl,accept_name);
			need_sti(e->e2,tbl,accept_name);
			if ( e->tp && e->tp->base == VEC &&
				e->base == NEW || e->base == GNEW )
				// preserve ICON,STRING,CCON,FCON
				need_sti(Pvec(e->tp)->dim,tbl);
		}
                else if (e->base == 0)
                      return 0;
		// no break
	case ICALL:
		return 1;
	case ICON:
	case STRING:
	case CCON:
	case FCON:
//error('d',"save %k tbl %d",e->base,tbl);
		if (tbl) {
			char* p = new char[strlen(e->string)+1];
			strcpy(p,e->string);
			e->string = p;
		}
		return 0;
	}
}

static void check_def_name( Pname nn, int scope ) 
{
// error('d', "check_def_name: nn: %n n_sto: %k scope: %k", nn,nn->n_sto,scope );
	if ( def_name==0 && pdef_name==0 && friend_in_class == 0 &&
		scope == EXTERN && nn->n_scope != STATIC &&  
		nn->n_oper != NEW && nn->n_oper != DELETE ) { 
     			Pfct f = Pfct(nn->tp);
     			if (f->body && 
				f->f_inline == 0 && 
				f->f_imeasure == 0) {
// error('d', "check_def_name: do it: %n", nn );
					pdef_name = def_name = nn;
					ptbl_init(0);
					def_name = 0;
			}
    	}
}

int stat_init = 0; // in an expression initializing a local static
Pname name::dcl(Ptable tbl, TOK scope)
/*
	enter a copy of this name into symbol table "tbl";
		- create local symbol tables as needed
	
	"scope" gives the scope in which the declaration was found
		- EXTERN, FCT, ARG, PUBLIC, or 0
	Compare "scope" with the specified storage class "n_sto"
		- AUTO, STATIC, REGISTER, EXTERN, OVERLOAD, FRIEND, or 0

	After name::dcl()
	n_stclass ==	0		class or enum member
			REGISTER	auto variables declared register
			AUTO		auto variables not registers
			STATIC		statically allocated object
	n_scope ==	0		private class member
			PUBLIC		public class member
			EXTERN		name valid in this and other files
			STATIC		name valid for this file only
			FCT		name local to a function
			ARG		name of a function argument
			ARGT		name of a type defined in an
					argument list
                        ARGS            temporary class object with dtor in
                                        initialization of a local static


	typecheck function bodies;
	typecheck initializers;

	note that functions (error recovery) and classes (legal) nest

	The return value is used to chain symbol table entries, but cannot
	be used for printout because it denotes the sum of all type information
	for the name

	names of typenames are marked with n_oper==TNAME

	WARNING: The handling of scope and storage class is cursed!
*/
{
	Pname nn;
	Ptype nnt = 0;
	Pname odcl = Cdcl;
	int sti_vb = 0;	// set if initialize with virtual base class

//	if (this == 0) error('i',"0->N::dcl()");
//	if (tbl == 0) error('i',"%n->N::dcl(tbl=0,%k)",this,scope);
//	if (tbl->base != TABLE) error('i',"%n->N::dcl(tbl=%d,%k)",this,tbl->base,scope);
//	if (tp == 0) error('i',"N::dcl(%n,%k)T missing",this,scope);

	Cdcl = this;
	Ptype tx = tp;

	DB( if(Ddebug>=1) error('d',"dcl %n %t",this,tx); );
// error('d',"dcl %n %t cc->cot: %d",this,tx,cc?cc->cot:0); 
	while (tx->base == TYPE) tx = Pbase(tx)->b_name->tp;

	switch (base) {
	case TNAME:
		nn = tbl->look(string,0);
		tp->dcl(tbl);
                if (nn && nn->lex_level == lex_level) {
//error('d', "dcl: cot: %s ccl: %s", cc->cot?cc->cot->string:"notset", ccl?ccl->string:"notset");

                        if ( tp->check(nn->tp,0) )
                                error("%n declared as %t and %t",nn,nn->tp,tp);
                        else if ( nn->base == NAME && cc->cot == 0 &&
			(tp->base != COBJ || tp->base != EOBJ))
                                error("%n declared as identifier and typedef", nn );
                        Cdcl = odcl;
                        return 0;

                }
		PERM(tp);
		nn = new name(string);
		nn->base = TNAME;
		nn->tp = tp;
		Pname tn = tbl->insert(nn,0);
		if (n_key == NESTED) {
			tn->n_key = NESTED;
			tn->tpdef = tpdef;
		}
		delete nn;
		Cdcl = odcl;
		return this;
	
	case NAME:
		switch (n_oper) {
		case COMPL:
			if (tp->base != FCT) {
				error("~%s notF",string);
				n_oper = 0;
			}
			break;
		case TNAME:
			if (tp->base != FCT) n_oper = 0;
			break;
		}
		break;
	default:
		error('i',"NX in N::dcl()");
	}

	if (n_qualifier) {	
				// c::f()
				// class function,
				// friend declaration, or 
				// static member initializer
		Pname cn = n_qualifier;

		switch (cn->base) {
		case TNAME:
			break;
		case NAME:
			cn = gtbl->look(cn->string,0);
			if (cn && cn->base==TNAME) break;
		default:
			error("badQr%n for%n",n_qualifier,this);
			Cdcl = odcl;
			return 0;
		}

		while (cn->tp->base == TYPE) cn->tp = Pbase(cn->tp)->b_name->tp;
// error('d',"actualQr%n %t",cn,cn->tp);
		if (cn->tp->base != COBJ) {
			error(&where,"Qr%nnot aCN",n_qualifier);
			Cdcl = odcl;
			return 0;
		}

		cn = Pbase(cn->tp)->b_name;
		if (n_oper) check_oper(cn);

		Pclass cl = Pclass(cn->tp);
		if (cl == cc->cot) {
			n_qualifier = 0;
			goto xdr;
		}
		else if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) {
			error("C%nU",cn);
			Cdcl = odcl;
			return 0;
		}
		else if (cl->c_body==1)	//III
			cl->dcl_print(0);

		Ptable etbl = cl->memtbl;
		Pname x = etbl->look(string,0);
		if (x==0 || x->n_table!=etbl) {
			error("%n is not aM of%n",this,cn);
			Cdcl = odcl;
			return 0;
		}

		if (tp->base == FCT) {	//III
		//	if (friend_in_class==0 && Pfct(tp)->body==0) {	// c::f(); needed for friend
			if (friend_in_class==0
			&& n_sto!=FRIEND
			&& Pfct(tp)->body==0) {	// c::f(); needed for friend
				error("QdN%n inFD",x);
				Cdcl = odcl;
				return 0;
			}

			if (Pfct(tp)->body==0) {
				Pfct(tp)->memof = cl;
				int xx;
				if (x->tp->base==OVERLOAD)
					xx = Pgen(x->tp)->find(Pfct(tp),0)==0;
				else
					xx = x->tp->check(tp,0);

				if (xx) {
					error("%n is not aM of%n",this,cn);
					Cdcl = odcl;
					return 0;
				}
			}
		}
		else {
			if (x->n_stclass != STATIC) {	// e.g. int c::i = 7
				error("D of non staticCM %n",this);
				Cdcl = odcl;
				return 0;
			}
			if (n_sto) error("staticCM declared%k",n_sto);
			tbl = etbl;
		}
	}
xdr:
	if (n_oper
	&& tp->base!=FCT
	&& n_sto!=OVERLOAD) error("operator%k not aF",n_oper);


	/*	if a storage class was specified
			check that it is legal in the scope 
		else
			provide default storage class
		some details must be left until the type of the object is known
	*/

	n_stclass = n_sto;
	n_scope = scope;	/* default scope & storage class */

	switch (n_sto) {
	default:
		error('i',"unX %k",n_sto);
	case FRIEND:
	{
		Pclass cl = cc->cot;

		switch (scope) {
		case 0:
		case PUBLIC:
			break;
		default:
			error("friend%n not inCD(%k)",this,scope);
			base = 0;
			Cdcl = odcl;
			return 0;
		}

		switch (n_oper) {
		case 0:
		case NEW:
		case DELETE:
		case CTOR:
		case DTOR:
		case TYPE:
			n_sto = 0;
			break;
		default:
			n_sto = OVERLOAD;
		}

		switch (tx->base) {
		case COBJ:
			nn = Pbase(tx)->b_name;
			break;
		case CLASS:
			nn = this;
			break;
		case FCT:
			cc->stack();
			cc->not = 0;
			cc->tot = 0;
			cc->cot = 0;
			friend_in_class++;
		//	n_sto = EXTERN;
			n_sto = 0;
			nn = dcl(gtbl,EXTERN);
			if (nn == 0) {
				Cdcl = odcl;
				return 0;
			}
			friend_in_class--;
			cc->unstack();
			if (nn->tp->base == OVERLOAD) nn = Pgen(nn->tp)->find(Pfct(tx),1);
			break;
		default:
			error("badT%tof friend%n",tp,this);
			Cdcl = odcl;
			return 0;
		}
		PERM(nn);
		cl->friend_list = new name_list(nn,cl->friend_list);
		Cdcl = odcl;
		return nn;
	}
	case OVERLOAD:
		if (strict_opt||warning_opt)
			error(strict_opt?0:'w',"`overload' used (anachronism)");
		n_sto = 0;
		// ignore overload!
		switch (tp->base) {
		case FCT:
			break;
		default:
			base = 0;
			Cdcl = odcl;
			return this;
		}
		break;
	case REGISTER:
		if (tp->base == FCT) {
			error('w',"%n: register (ignored)",this);
			goto ddd;
		}
	case AUTO:
		switch (scope) {
		case 0:
		case PUBLIC:
		case EXTERN:
			error("%k not inF",n_sto);
			goto ddd;
		}
		if (n_sto==AUTO) n_sto = 0;	// always redundant
		break;
	case EXTERN:
		switch (scope) {
		case ARG:
			//error("externA");
			goto ddd;
		case 0:
		case PUBLIC:
			/* extern is provided as a default for functions without body */
			if (tp->base != FCT) error("externM%n",this);
			goto ddd;
		case FCT:
			{
			Pname nn = gtbl->look( string, 0 );
			tp->dcl(tbl);
			if ( nn && tp->base != FCT &&
				tp->check(nn->tp,0)) 
				{
				error("twoDs of%n;Ts:%t and%t",this,nn->tp,tp);
				Cdcl = odcl;
				return 0;
				}
			}
		}
		n_stclass = STATIC;
		n_scope = EXTERN;	/* avoid FCT scoped externs to allow better checking */
		break;
	case STATIC:
		switch (scope) {
		case ARG:
			//error("static used forA%n",this);
			goto ddd;
		case 0:
		case PUBLIC:
			n_stclass = STATIC;
			n_scope = scope;
			break;
		default:
			n_scope = STATIC;
		}
		break;
	case 0:
	ddd:
		switch (scope) {	/* default storage classes */
		case EXTERN:
			n_scope = EXTERN;
			n_stclass = STATIC;
			break;
		case FCT:
			if (tp->base == FCT) {
				n_stclass = STATIC;
				n_scope = EXTERN;
			}
			else
				n_stclass = AUTO;
			break;
		case ARG:
			n_stclass = AUTO;
			break;
		case 0:
		case PUBLIC:
			n_stclass = 0;
			break;
		}
	}

	
	/*
		now insert the name into the appropriate symbol table,
		and compare types with previous declarations of that name

		do type dependent adjustments of the scope
	*/
//error('d',"sw %d",tx->base);
	static int warn_ldouble=0;

	switch (tx->base) {
	case ASM:
	{	Pbase b = Pbase(tp);
		Pname n = tbl->insert(this,0);
		n->assign();
		n->use();
		char* s = (char*) b->b_name;	// save asm string. Shoddy
		int ll = strlen(s);
		char* s2 = new char[ll+1];
		strcpy(s2,s);
		b->b_name = Pname(s2);
		Cdcl = odcl;
		return this;
	}

	case CLASS:
		tp = tx;
		nn = dclass(this,tbl);
		Cdcl = odcl;
		return nn;

	case ENUM:
		tp = tx;
		nn = denum(this,tbl);
		Cdcl = odcl;
		return nn;
	
	case FCT:
		tp = tx;
		nn = dofct(tbl,scope);
		if (nn == 0) {
			Cdcl = odcl;
			return 0;
		}

// error('d', "%s n_oper: %k, scope: %k", string, n_oper, scope );
		if (pdef_name == 0) check_def_name(nn, scope);
		break;

	case FIELD:
		switch (n_stclass) {
		case 0:
		case PUBLIC:
			break;
		default:
			error("%k field",n_stclass);
			n_stclass = 0;
		}

		if (cc->not==0 || cc->cot->csu==UNION || cc->cot->csu==ANON) {
			error(cc->not?"field in union":"field not inC");
			PERM(tp);
			Cdcl = odcl;
			return this;
		}

		if (string) {
			nn = tbl->insert(this,0);
			n_table = nn->n_table;
			if (Nold) error("twoDs of field%n",this);
		}

		tp->dcl(tbl);
		field_align();
		break;
	
	case COBJ:
	{	Pclass cl = Pclass(Pbase(tx)->b_name->tp);
//error('d',&where,"dcl %n; tx->base == cobj",this);
		if (cl->lex_level > lex_level) 
     			error("C%t is not visible in this scope",cl);

		if (cl->csu == ANON) {	// export member names to enclosing scope
                        if (tbl==gtbl && n_sto!=STATIC) error("extern anonymous union (declare as static)");
			char* p = cl->string;
			while (*p++ != 'C');	/* sneaky */
			int uindex = (int)str_to_long(p);

// error('d', "%n->dcl() n_scope: %k n_protect: %k", this, n_scope, n_protect );
		// cannot cope with use counts for ANONs:
			Pbase(tp)->b_name->n_used = 1;
			Pbase(tp)->b_name->n_assigned_to = 1;

			Ptable mtbl = cl->memtbl;
                        int i, err_msg = 0;
			for (Pname nn=mtbl->get_mem(i=1); nn; nn=mtbl->get_mem(++i)) {
				if (nn->tp->base == FCT) {
					error("FM%n for anonymous union",nn);
					break;
				}
				Ptable tb = nn->n_table;
				nn->n_table = 0;
				nn->n_scope = n_protect?n_protect:n_scope; 
				Pname n = tbl->insert(nn,0);
				if (Nold) {
					error("twoDs of%n (one in anonymous union)",nn);
					break;
				}

				Pclass tc;
				if (tc = cl->in_class) 
					--n->lex_level;
				if ( tc && tc->csu == ANON) {
//error('d', "tc->csu anon %k %s", tc->csu, string );
					if ( n->n_anon ) {
						if ( !err_msg ) 
							error('s', "anonymous unions nested deeper than 2 levels" );
						err_msg = 1;
					}
					n->n_anon = string;
				}

				n->n_union = uindex;
				nn->n_table = tb;
			}
		}
		if (cl->c_abstract) error("D ofO of abstractC%t",cl);
		goto cde;
	}

	case VOID:
		if (n_scope != ARG) {
			error("badBT:%k%n",tx->base,this);
			Cdcl = odcl;
			return 0;
		}
		break;

	case LDOUBLE:
                if (warn_ldouble==0 && ansi_opt==0) {
                        ++warn_ldouble;
                        error('w',"long double supported under ``+a1'' option only, generating ``double%n''", this);
                }
		goto cde;

	case PTR:
	case VEC:
	case RPTR:
		tp->dcl(tbl);

	default:
	cde:
//error('d',"cde: %n %t",this,tp);
		nn = tbl->insert(this,0);
		n_table = nn->n_table;

		if (Nold) {

			if ( nn->base == PUBLIC ) { // X::i
     				error("twoDs ofCM%n", nn);
     				Cdcl = odcl;
     				return 0;
			}

			if (nn->tp->base == ANY) goto zzz;

			if (tp->check(nn->tp,0)) {
				error("twoDs of%n;Ts:%t and%t",this,nn->tp,tp);
				Cdcl = odcl;
				return 0;
			}
//error('d',"%n: %k %k scope %k",this,n_sto,nn->n_sto,nn->n_scope);
			if (n_sto && n_sto!=nn->n_scope) {
				if (n_sto==EXTERN && nn->n_scope==STATIC) {
					error('w',"%n declared extern after being declared static",this);
					goto ext_fudge;
				}
				else
					error("%n declared as both%k and%k",this,n_sto,(nn->n_sto)?nn->n_sto:(scope==FCT?AUTO:EXTERN));
			}
			else if (nn->n_scope==STATIC && n_scope==EXTERN) {
				error('w',"static%n followed by definition",this);
			ext_fudge:
				if (n_initializer) {
//					error('d',"static%n redefined (WIr)",this);
					n_initializer = 0;
				}
				n_sto = EXTERN;
			}
			else if (nn->n_sto==STATIC && n_sto==STATIC ) 
				error("static%n declared twice",this);
			else {
				if (n_sto==0
				&& nn->n_sto==EXTERN
				&& n_initializer
				&& tp->tconst())
					n_sto = EXTERN;
				n_scope = nn->n_scope;

				switch (scope) {
				case FCT:
					if (n_sto != EXTERN) {
						error("twoDs of%n",this);
						Cdcl = odcl;
						return 0;
					}
					break;
				case ARG:
					error("twoAs%n",this);
					Cdcl = odcl;
					return 0;
				case 0:
				case PUBLIC:
					error("twoDs ofM%n",this);
					Cdcl = odcl;
					return 0;
				case EXTERN:
					if (n_sto==0) {
						switch(nn->n_sto) {
						case 0:
							error("two definitions of%n",this);
							Cdcl = odcl;
							return 0;
						case EXTERN:
							if(nn->n_initializer) {
								error("two definitions of%n",this);
								Cdcl = odcl;
							}
							else
								nn->n_sto=0;
							break;
						}
					}
					else if(n_sto==EXTERN && n_initializer) {
						switch(nn->n_sto) {
						case 0:
							error("two definitions of%n",this);
							Cdcl = odcl;
							return 0;
						case EXTERN:
							nn->n_sto=0;
							break;
						}
					}
					break;
				}
			}
			n_scope = nn->n_scope;
/* n_val */
			if (n_initializer) {
				if (nn->n_initializer || nn->n_val) error("twoIrs for%n",this);
				nn->n_initializer = n_initializer;
			}
			if (tp->base == VEC) {
			//	handle:	 extern v[]; v[200];
			//	and	extern u[10]; u[11];

				Ptype ntp = nn->tp;
				while (ntp->base == TYPE) ntp = Pbase(ntp)->b_name->tp;
				if (Pvec(ntp)->dim == 0) Pvec(ntp)->dim = Pvec(tp)->dim;
				if (Pvec(ntp)->size) {
					if (Pvec(tp)->size
					&& Pvec(ntp)->size!=Pvec(tp)->size)
						error("bad array size for%n: %d %dX",this,Pvec(tp)->size,Pvec(ntp)->size);
				}
				else
					Pvec(ntp)->size = Pvec(tp)->size;
			}
		}
		else {
//error('d',"%n %t scope %d sto %k",this,tp,scope,n_sto);		
			if (scope!=ARG
			&& n_sto!=EXTERN
			&& (!((scope==0 || scope==PUBLIC) && n_sto==STATIC)) // static member
			&& n_initializer==0
			&& tp->base==VEC
			&& Pvec(tp)->size==0)
				error(&where,"dimension missing for array%n",this);

			if (scope==EXTERN
			&& n_sto==0
			&& tp->tconst()
			&& vec_const==0
			&& fct_const==0)
				nn->n_sto = n_sto = STATIC;
		}
	
	zzz:
		if (base != TNAME) {
			Ptype t = nn->tp;

			if (t->base == TYPE) {
				Ptype tt = Pbase(t)->b_name->tp;
				if (tt->base == FCT) nn->tp = t = tt;
			}

			switch (t->base) {
			case FCT:
			case OVERLOAD:
				break;
			default:
				fake_sizeof = 1;
				switch (nn->n_stclass) {
				default:
					if (nn->n_scope != ARG) {
						int x = t->align();
						int y = t->tsizeof();

						if (max_align < x) max_align = x;

						while (0 < bit_offset) {
							byte_offset++;
							bit_offset -= BI_IN_BYTE;
						}
						bit_offset = 0;

						if (byte_offset && 1<x) byte_offset = ((byte_offset-1)/x)*x+x;
						nn->n_offset = byte_offset;
						byte_offset += y;
					}
					break;
				case STATIC:
					if (n_sto != EXTERN
					&& nn->n_scope
					&& nn->n_scope!=PUBLIC)
					t->tsizeof();	// check that size is known
				}
				fake_sizeof = 0;
			}
		}

	{	Ptype t = nn->tp;
		int const_old = const_save;
		bit vec_seen = 0;
		Pexpr init = n_initializer;

	lll:
// error('d',"lll %n %t init %d %k",this,t,init,init?init->base:0);
		switch (t->base) {
		case COBJ:
		{	Pname cn = Pbase(t)->b_name;
			Pclass cl = (Pclass)cn->tp;
			Pname ctor = cl->has_ctor();
			Pname dtor = cl->has_dtor();
			int stct = 0;
//error('d',"obj %n; class '%s'; ctor '%s'; dtor '%s'",nn,cn->string,ctor?ctor->string:"???",dtor?dtor->string:"???");
			if (dtor) {
				Pstmt dls;

				// if dtor is not public check scope of class object

//error('d',"dcl %n has dtor",nn);
				if (dtor->n_scope != PUBLIC)  {
//error('d',"dcl %n->n_scope: %d fct %n",nn,nn->n_scope,cc->nof);
					switch (nn->n_scope) {
					case ARG:
					case 0:
					case PUBLIC:
						break;
					default: 
						check_visibility( dtor, 0, cl, tbl, cc->nof );
					}
			//		if (nn->n_scope == FCT) 
			//			check_visibility( dtor, 0, cl, tbl, cc->nof );
			//		else if ( nn->n_sto != EXTERN )
			//			error("%k%n cannot access%n: %sM",nn->n_scope,nn,dtor,dtor->n_protect?"protected":"private");
				}

				switch ( nn->n_scope ) {
				case 0:
				case PUBLIC:
					if (n_stclass==STATIC) { //III
						Pclass cl = Pclass(nn->n_table->t_name->tp);
						if (cl->defined&DEFINED) goto dtdt;
					}
					break;
				case EXTERN:
					if (n_sto==EXTERN) break;

				case STATIC:
				{	Pexpr c;
				dtdt:
// local static class objects have destructors set up in simpl2.c
// special case: temporary class object generated in init expression
					if (stat_init && scope == ARGS ) {
     						nn->n_scope = ARGS;
     						goto ggg;
 					}

					if ( nn->lex_level
					&&   nn->n_sto == STATIC ) {
						if (ctor==0) 
						    error('s',"local static%n has%n but noK(add%n::%n())", nn, dtor, cn, cn );
						goto static_init;
					}

					Ptable otbl = tbl;
					    // to collect temporaries generated
					    // in static destructors where we
					    // can find them again (in std_tbl)
					if (std_tbl == 0) std_tbl = new table(8,gtbl,0);
					tbl = std_tbl;
					if (vec_seen) {
						c = cdvec(vec_del_fct,nn,cl,dtor,0,zero);
					} else {	// nn->cl::~cl(0);
						c = call_dtor(nn,dtor,0,DOT,one);
					}
					c->tp = any_type; // avoid another check
					dls = new estmt(SM,nn->where,c,0);
					
					// destructors for statics are executed in reverse order
					if (st_dlist) dls->s_list = st_dlist;
					st_dlist = dls;
					tbl = otbl;
				} // case STATIC
				} // switch nn->n_scope
			} // if dtor

// local static class objects must defer setting up static dtor
static_init:
			if (ctor) {
// error('d',"ctor %n scope %k",ctor,nn->n_scope);
				Pexpr oo = nn;
				for (int vi=vec_seen; vi; vi--) oo = oo->contents();
				int sti = 0;
				switch (nn->n_scope) {
				case EXTERN:
					if (init==0 && n_sto==EXTERN) goto ggg;
				case STATIC:
					if (tbl == gtbl)
						sti = 1;
					else
						stct = 1;
				default:
					if (vec_seen && init) {
						if (1<vec_seen) {
/* ?????
							if (init->base != ILIST)
								error("badIr forO ofC %t withK%n",cl,this);
							else
*/
								error('s',"Ir for multi-dimensional array%n ofOsofC %t withK",this,cl);
							}
						else {
							if (sti) {
								if (sti_tbl==0) sti_tbl = new table(8,gtbl,0);
								const_save = 1;
								(void) co_array_init(nn,sti_tbl);
								const_save = 0;
								n_initializer = init = 0;
							}
							else {
								n_initializer = init = co_array_init(nn,tbl);
								if (stct)  
									nn->n_initializer = n_initializer = init = new expr( STAT_INIT, init, 0 );
							}
						}
						goto ggg;
					}
					break;
				case PUBLIC:
				case 0:
					if (n_stclass==STATIC) { //III
						Pclass cl = Pclass(nn->n_table->t_name->tp);
						if (cl->defined&DEFINED) {
							sti = 1;
							break;
						}
					}
					{
						Pname c;
						if (vec_seen) {
							c = cl->has_ictor();
							if (c == 0)
								error("array ofC%n that does not have aK taking noAs",cn);
							else if (Pfct(c->tp)->nargs)
								error("defaultAs forK for array ofC%n",cn);
						}
					}
					// no break
				case ARG:
					goto ggg;
				}

				const_save = 1;
				nn->assign();
				Ptable otbl = tbl;
				if (sti) {	// to collect temporaries generated
						// in static initializers where we
						// can find them again (in sti_tbl)
					if (sti_tbl == 0) sti_tbl = new table(8,gtbl,0);
					tbl = sti_tbl;
					if (n_sto == EXTERN) nn->n_sto = n_sto = 0;
				}

				if (init) {
// error('d',"init %k",init->base);
					if (init->base==VALUE) {
						switch (init->tp2->base) {
						case CLASS:
// error('d',"class %t %t",Pclass(init->tp2),cl);
							if (Pclass(init->tp2)!=cl) goto inin;
							break;
						default:
							Pname  n2 = init->tp2->is_cl_obj();
// error('d',"default %t %t",n2->tp,cl);
							if (n2==0 || Pclass(n2->tp)!=cl) goto inin;
						}

						Pexpr ee = init->e1;
// error('d',"init->e1 %k",ee->base);
						if (ee && vec_seen==0)
						switch (ee->base) {
						case CALL:	// T a = f();
							init = ee;
							goto inin;
						case ELIST:	// T a(f());
							if (ee->e1->base==CALL
							&& ee->e2 == 0) {
								init = ee->e1;
								goto inin;
							}
						} // end switch

						init->e2 = oo;
						init = init->typ(tbl);

						if (init->base == G_CM)	// beware of type conversion operators
						switch (init->tp2->base) {
						case CLASS:
							if (Pclass(init->tp2)!=cl) goto inin;
							break;
						default:
							Pname  n2 = init->tp2->is_cl_obj();
							if (n2==0 || Pclass(n2->tp)!=cl) goto inin;
						}
					}
					else {
					inin:
// error('d',"inin %k",init->base);
						init = init->typ(tbl);
//error('d', "inin: init->typ: %d %k n->tp %t init->tp %t",init->base,init->base,nn->tp,init->tp);
						if (init->base==G_CM
						&& nn->tp->check(init->tp,0)==0)
							(void) replace_temp(init,nn->address());
						else
							init = class_init(nn,nn->tp,init,tbl);
					}
				}
				else if (vec_seen == 0) {
//error('d',"make value");
					init = new texpr(VALUE,cl,0);
					init->e2 = oo;
					init = init->typ(tbl);
				}

				Pname c;
				if (vec_seen) {
					c = cl->has_ictor();
					if (c == 0)
						error("array ofC%n that does not have aK taking noAs",cn);
					else if (Pfct(c->tp)->nargs)
						error("defaultAs forK for array ofC%n",cn);
				}

// error( 'd', "stct: %d init: %d", stct, init );
				if (stct) {
					if (tbl!=gtbl && nn->n_sto==EXTERN) {
						error(&where,"Id local extern%n",this);
						init = 0;
					}
					else if (init) 
						init->base = STAT_INIT;
					else {
  						if (tp->base == VEC && Pvec(tp)->size ) {
  							Pexpr ilist = 0;
  							for (int i=Pvec(tp)->size; i>0; i--) {
  								Pexpr e = new texpr(VALUE,cl,0);
  								ilist = new expr(ELIST, e, ilist);
  							}
  							nn->n_initializer=new expr(ILIST,ilist,0);
  							init = co_array_init(nn,tbl);
  							nn->n_initializer = n_initializer = init = new expr( STAT_INIT, init, 0 );
  						}
  						else
						error('s',"local staticC%n (%t)",this, tp);
				 	}
				}

// error('d', "%n->sti: %d vec_seen: %d n_stclass: %k", this, sti, vec_seen, n_stclass );
	if (sti) {
		if (vec_seen) {	// _vec_new(vec,noe,sz,ctor);
// error('d', "%n->dcl: n_stclass: %k ", this, n_stclass );
			if ( n_stclass == STATIC && n_initializer ) {
				const_save = 1;
				(void) co_array_init(nn,sti_tbl);
				const_save = 0;
				n_initializer = init = 0;
				goto ggg;
			}

			init = cdvec(vec_new_fct,nn,cl,c,-1,0);
			init->tp = any_type;
		}
		else {
			switch (init->base) {
			case DEREF:		// *constructor?
				if (init->e1->base == G_CALL) {	
					Pname fn = init->e1->fct_name;
					if (fn==0 || fn->n_oper!=CTOR) goto as;
					init = init->e1;
					break;
				}
				goto as;
			case G_CM:
				init = init->e1;
					// suppress further type checking
				if (init->tp == 0) init->tp= any_type; 
				break;
			case ASSIGN:
				if (init->e1 == nn) break;	// simple assignment
			as:	
			default:	
				init = new expr(ASSIGN,nn,init);
			}
		}
		Pstmt ist = new estmt(SM,nn->where,init,0);
		// constructors for statics are executed in order
		if (st_ilist == 0)
			st_ilist = ist;
		else
			itail->s_list = ist;
		itail = ist;
		init = 0;	// suppress further processing
	} // if (sti)
				nn->n_initializer = n_initializer = init;
				const_save = const_old;
				tbl = otbl;
			}
			else if (init == 0)		// no initializer
				goto str;
			else if (cl->is_simple()
			//	&& cl->csu!=UNION	// accept ANSIism
				&& cl->csu!=ANON
				) {	// struct
				init = init->typ(tbl);
				if (nn->tp->check(init->tp,0)==0
				&& init->base==G_CM) 
					(void) replace_temp(init,nn->address());
				else {
					if (ansi_opt==0
					&& init->base==ILIST
					&& cl->csu==UNION)
						error('s',"initialization of union withIL");
					goto str;
				}
			}
			else if (init->base == ILIST) {	// class or union
				error("cannotI%nWIrL",nn);
			}
			else {			// bitwise copy ok?
						// possible to get here?
				init = init->typ(tbl);
//error('d',"init22 %t %t",nn->tp,init->tp);
				if (nn->tp->check(init->tp,0)==0) {
					if (init->base==G_CM) 
						(void) replace_temp(init,nn->address());
					else
						goto str;
				}
				goto str;
			//	else
			//		error("cannotI%n:%k %s has noK",nn,cl->csu,cl->string);
			}
			break;
		}
		case VEC:	
			t = Pvec(t)->typ;
			vec_seen++;
			goto lll;
		case TYPE:
			if (init==0 && Pbase(t)->b_const) {
				switch (n_scope) {
				case ARG:
					break;
				case 0:
				case PUBLIC:
					if ( cc->cot ) break;
				default: {
					Pname n = t->is_cl_obj();
					Pclass cl;
					if ( n ) cl = Pclass( n->tp );

					if (n_sto!=EXTERN && 
					   (n==0 || (cl->has_ctor()==0 && is_empty(cl,1)==0))) 
						error("uninitialized const%n",this);
					}
				}
			}
			t = Pbase(t)->b_name->tp;
			goto lll;
		case RPTR:
			if (init) {
				if (nn->n_scope == ARG) break;
				if (Pptr(nn->tp)->memof) error("R toCM%n ofT%t illegal",nn,nn->tp);
				ref_initializer++;
				init = init->typ(tbl);
				ref_initializer--;
				Nvirt = 0; // set within ref_init() call
				const_ptr = Pbase(Pptr(t)->typ)->tconst(); 

				if (n_sto==STATIC
				&& init->lval(0)==0
				&& fct_const==0)
					error("Ir for staticR%n not an lvalue",this);
				else
					nn->n_initializer = n_initializer = init = ref_init(Pptr(t),init,tbl);

				const_ptr = 0;
				if (Nvirt == VIRTUAL) sti_vb = 1;
				nn->assign();

				if (init->base==ILIST && init->e2==0) {
					new_list(init);
					list_check(nn,nn->tp,0,tbl);
					if (next_elem()) error(&where,"IrL too long");
				}

			}
			else {
				switch (nn->n_scope) {
				default:
					if (n_sto == EXTERN) break;
					error("uninitializedR%n",this);
				case ARG:
					break;
				case PUBLIC:
				case 0:
			//III		if (n_sto == STATIC) error("a staticM%n cannot be aR",this);
// error('d', "%n->dcl cot: %s", this, cc->cot?cc->cot->string:"notset");
					if ( cc->cot == 0 )
						error("uninitializedR%n",this);
					break;
				}
			}
			goto stgg;
		default:
		str:
// error('d',"str %n %t %k %t",this,tp,init?init->base:0,init?init->tp:0);
			if (init == 0) {
				switch (n_scope) {
				case ARG:
					break;
				case 0:
				case PUBLIC:
					if ( cc->cot ) break;
				default:
					if (n_sto!=EXTERN && t->tconst()) error("uninitialized const%n",this);
				}

				break;
			}

			const_save = 	   const_save
					|| n_scope==ARG
					|| (t->tconst() && vec_const==0);

			if ( tp->base == PTR ) {
				if ( cc && cc->nof 
					&& Pfct(cc->nof->tp)->f_const ) 
						cm_const_save = Pbase(Pptr(tp)->typ)->b_const; 
				const_ptr = Pbase(Pptr(tp)->typ)->b_const; 
			}

  			if (n_sto==STATIC) stat_init++;
                        nn->n_initializer = n_initializer = init = init->typ(tbl);
  			if (n_sto==STATIC) stat_init--;

			cm_const_save = 0;
			const_ptr = 0;

			if (const_save) PERM(init);
			nn->assign();
			const_save = const_old;
//error('d',"init2 %k %t",init->base,init->tp);
			switch (init->base) {
			case ILIST:
				if (init->e2) goto dfdf;//break; // pointer to member
				new_list(init);
				list_check(nn,nn->tp,0,tbl);
				if (next_elem()) error(&where,"IrL too long");
				break;
			case STRING:
			{	Ptype v = nn->tp;
				while (v->base == TYPE) v = Pbase(v)->b_name->tp;
				if (v->base==VEC) {
					Ptype vv = Pvec(v)->typ;
					while(vv->base==TYPE) vv = Pbase(vv)->b_name->tp;
					if(vv->base==CHAR) {
						int sz = Pvec(v)->size;
						int isz = Pvec(init->tp)->size;
						if (sz == 0)
							Pvec(v)->size = isz;
						else if (sz < isz)
							error(&where,"Ir too long (%d characters) for%n[%d]",isz,nn,sz);
						break;
					}
				}
				// no break
			}
			default:
			dfdf:
			{	Ptype nt = nn->tp;
				int ntc = Pbase(nt)->b_const;

				if (vec_seen) {
					error("badIr for array%n",nn);
					break;
				}
			tlx:
				switch (nt->base) {
				case TYPE:
					nt = Pbase(nt)->b_name->tp;
					ntc |= Pbase(nt)->b_const;
					goto tlx;
				case INT:
				case CHAR:
				case SHORT:
				case EOBJ:
				//	if (init->base==ICON && init->tp==long_type)
				//		error('w',"longIr constant for%k%n",nn->tp->base,nn);
				{	Ptype t = init->tp;
				csi:
					switch (t->base) {
					case TYPE:
						t = Pbase(t)->b_name->tp; goto csi;
					case LONG:
					case FLOAT:
					case DOUBLE:
					case LDOUBLE:
						error('w',"%tIdW %t",nt,init->tp);
					}
				}
					// no break
				case LONG:
					if (Pbase(nt)->b_unsigned
					&& init->base==UMINUS
					&& init->e2->base==ICON)
						error('w',"negativeIr for unsigned%n",nn);
					if (ntc && scope!=ARG) {
						long i;
						Neval = 0;
						i = init->eval();
						if (Neval == 0) {
							DEL(init);
							nn->n_evaluated = n_evaluated = 1;
							nn->n_val = n_val = i;
							DEL(init);
							nn->n_initializer = n_initializer = 0;
						}
					}
					break;
				case PTR:
					Nvirt = 0;
					nn->n_initializer = n_initializer = init = ptr_init(Pptr(nt),init,tbl);
//display_expr(init,string);
					if (Nvirt == VIRTUAL) sti_vb = 1;
					if (Pchecked) goto stgg;
				} 

			{	Pexpr x = try_to_coerce(nt,init,"initializer",tbl);
				if (x) {
					nn->n_initializer = n_initializer = init = x;
					goto stgg;
				}
			}
//error('d',"check %t %t %k",nt,init->tp,init->base);
		//	if (nt->check(init->tp,ASSIGN)) {
				Pname c1 = nt->is_cl_obj();
				Pname c2 = init->tp->is_cl_obj();
				if (c1
				&& c2
				&& Pclass(c2->tp)->has_base(Pclass(c1->tp))) {
					init = new texpr(CAST,new ptr(PTR,nt),init->address());
					init = init->typ(tbl);
					nn->n_initializer = n_initializer = init = init->contents();
					goto stgg;
				}

				if (nt->check(init->tp,ASSIGN)) {
					error("badIrT%t for%n (%tX)",init->tp,this,nn->tp);
					break;
				}
		}

		stgg:
// error('d',"stgg %n init %k %t Nvirt: %k",this,init?init->base:0,init?init->tp:0, Nvirt);
			if (init && n_stclass==STATIC && (sti_vb || need_sti(init))) {
				/* check if non-static variables are used */
				int local = (0<lex_level);
// error('d',"init %n %t local %d",nn,init->tp,local);
				if (local==0) need_sti(init,tbl);	// save consts

				Pptr r = nn->tp->is_ref();	//III

				if (r) init = init->address();
				init = new expr(ASSIGN,nn,init);
// error('d',"init r %t: nn %n %t init %t",r,nn,nn->tp,init->tp);
				if (r)
					init->tp = nn->tp;
				else if (nn->tp!=init->tp) { // static member refs
					TOK t = nn->tp->set_const(0);	//JJJ
					init = init->typ(tbl);
					nn->tp->set_const(t);		//JJJ
				}

				if (local) {
					if (init->base != ASSIGN) error('s',"Ir for local static too complicated");
					if (nn->n_sto == EXTERN) {
						error(&where,"Id local extern%n",this);
							init = 0;
					}
					else init->base = STAT_INIT;
					nn->n_initializer = n_initializer = init;
					
				}
				else {
					Pstmt ist = new estmt(SM,nn->where,init,0);
					// constructors for statics are executed in order
		
					if (st_ilist == 0)
						st_ilist = ist;
					else
						itail->s_list = ist;
					itail = ist;
					nn->n_initializer = n_initializer = init = 0;	// suppress further processing
					nn->n_val = n_val = 1;
				}
			}
			
		
		} /* switch */
	} /* block */
	} /* default */

	} /* switch */
ggg:
//error('d',"ggg");
	PERM(nn);
	switch (n_scope) {
	case FCT:
		nn->n_initializer = n_initializer;
		break;
	default:
	{	Ptype t = nn->tp;
	px:
		PERM(t);
		switch (t->base) {
		case PTR:
		case RPTR:
		case VEC:	t = Pptr(t)->typ; goto px;
		case TYPE:	t = Pbase(t)->b_name->tp; goto px;
		case FCT:	t = Pfct(t)->returns; goto px; /* args? */
		} 
	}
	}
	
	Cdcl = odcl;
	return nn;
}
0707071010112043671004440001630000160000010172100466055375400000700000067044dcl2.c/*ident	"@(#)ctrans:src/dcl2.c	1.2" */
/**************************************************************************

	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.

dcl2.c:

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

#include "cfront.h"
#include "size.h"

Pname conv_dominates(Pname on1, Pname on2)
/*
	compare for duplicates and dominance:

	on1 and on2 are two conversion operator functions
	return the the one that dominates the other (according to the
	class hierarchy) otherwise 0 (0 thus indicats ambiguous conversion)
*/
{ 
	Ptype r1 = on1->tp->base==FCT ? Pfct(on1->tp)->returns 
			: Pfct(Pgen(on1->tp)->fct_list->f->tp)->returns;
	Ptype r2 = on2->tp->base==FCT ? Pfct(on2->tp)->returns 
			: Pfct(Pgen(on2->tp)->fct_list->f->tp)->returns;
//error('d',"conv_dominates(%n,%n)",on1,on2);
	if (r1==r2 || r1->check(r2,0)==0) return on1;
	Pptr p1 = r1->is_ptr_or_ref();
	Pptr p2 = r2->is_ptr_or_ref();
	if (p1 && p2) {
		Pname cn1 = p1->typ->is_cl_obj();
		Pname cn2 = p2->typ->is_cl_obj();
		if (cn1 && cn2) {
// is_cl_obj() returns b_name
//			Pclass c1 = Pclass(Pbase(cn1->tp)->b_name->tp);
//			Pclass c2 = Pclass(Pbase(cn2->tp)->b_name->tp);
			Pclass c1 = Pclass(cn1->tp);
			Pclass c2 = Pclass(cn2->tp);
			if (c1 && c2) {
				//if (c1==c2 || c1->has_base(c2)) 
				if (c1->has_base(c2)) 
					return on1;
				else if (c2->has_base(c1)) 
					return on2;
			}
		}
	}
	return 0;
}


Pstmt curr_loop;
Pstmt curr_switch;
Pblock curr_block;

void stmt::reached()
{
	register Pstmt ss = s_list;

	if (ss == 0) return;

	switch (ss->base) {
	case LABEL:
	case CASE:
	case DEFAULT:
		break;
	default:
		error('w',&ss->where,"S after%k not reached",base);
		for (; ss; ss=ss->s_list) {	// delete unreacheable code
			switch (ss->base) {
			case LABEL:
			case CASE:
			case DEFAULT:		// reachable
				s_list = ss;
				return;
			case DCL:		// the dcl may be used later
						// keep to avoid cascading errors
			case IF:
			case DO:
			case WHILE:
			case SWITCH:
			case FOR:
			case BLOCK:		// may hide a label
				s_list = ss;
				return;
			}
		}
		s_list = 0;
	}
}

Pexpr check_cond(Pexpr e, TOK b, Ptable tbl)
{
//error('d',"check_cond(%k %k) tbl %d",e->base,b,tbl);
	Pname cn;
	if (e == dummy) error("empty condition for %k",b);

	int const_obj = 0;
	const_obj = e->tp->tconst();
	Pexpr ee = e;
        while (ee && (ee->base==DOT || ee->base==REF)) {
               	Pexpr m = ee->mem;
               	if ( ee->base==REF && m->tp &&  m->tp->is_ptr())
                       	break;
               	ee = ee->e1;
        }
        if (ee) {
               	Ptype ttt = ee->tp;
               	switch (e->base) {
               	case REF:
               	        Pptr p = ttt?ttt->is_ptr():0;
                       	if (p && p->typ->tconst())
                               	const_obj = 1;
                       	break;
               	case DOT:
                       	if (ttt && ttt->tconst())
                               	const_obj = 1;
               	}
        }

	if (cn = e->tp->is_cl_obj()) {	
		Pclass cl = Pclass(cn->tp);
		int i = 0;
		Pname found = 0;
		for (Pname on = cl->conv; on; on=on->n_list) {
			Pfct f = on->tp->base == FCT ? Pfct(on->tp)
				 : Pfct(Pgen(on->tp)->fct_list->f->tp);
			Ptype t = f->returns;
		xx:
			switch (t->base) {
			case TYPE:
				t = Pbase(t)->b_name->tp;
				goto xx;
			case FLOAT:
			case DOUBLE:
			case LDOUBLE:
			case PTR:
				if (b == DEREF) break;
			case CHAR:
			case SHORT:
			case INT:
			case LONG:
			case EOBJ:
//                              if (found==0 || found->tp->check(on->tp,0)) {
//error('d',"found %n on %n",found,on);
			{	Pname xx = found;
                                if (found == 0) {
                                        i = 1;
                                        found = on;
                                }
                                else if ((found = really_dominate(found,on,const_obj)) == 0) {
                                        i = 2;
                                        found = on;
                                        error("two conversions for%nO in%kE: %n and %n",cn,b,xx,on);
					return e;
				}
			}
			}
		}
//error('d',"i %d",i);
		switch (i) {
		case 0:
			error("%nO in%kE",cn,b);
			return e;
/*
		case 1:
		{	Pname xx = new name(found->string);
			Pref r = new ref(DOT,e,xx);
			Pexpr rr = r->typ(tbl);
			Pexpr c = new expr(G_CALL,rr,0);

			if (e->lval(0)) {
			//	Pref r = new ref(DOT,e,found);
			//	r->tp = found->tp;
			//	Pexpr c = new expr(G_CALL,r,0);
			//	c->fct_name = found;
				return c->typ(tbl);
			}
			else {	// (temp=init,temp.coerce())
				Pname tmp = make_tmp('U',e->tp,tbl); 
				Pexpr ass = init_tmp(tmp,e,tbl);
			//	Pref r = new ref(DOT,tmp,found);
			//	Pexpr rr = r->typ(tbl);
			//	Pexpr c = new expr(G_CALL,rr,0);
			//	c->fct_name = found;
				ass = new expr(CM,ass,c);
				return ass->typ(tbl);
			}
		}
*/
		case 1:
		{	Pname xx = new name(found->string);
			Pexpr c;

			if (e->lval(0)) {
				Pref r = new ref(DOT,e,xx);
				Pexpr rr = r->typ(tbl);
				c = new expr(G_CALL,rr,0);
			}
			else {	// (temp=init,temp.coerce())
				Pname tmp = make_tmp('U',e->tp,tbl); 
				Pexpr ass = init_tmp(tmp,e,tbl);
				Pref r = new ref(DOT,tmp,xx);
				Pexpr rr = r->typ(tbl);
				c = new expr(G_CALL,rr,0);
				c = new expr(CM,ass,c);
			}
			return c->typ(tbl);
		}
	//	default:
	//		error("%d possible conversions for%nO in%kE",i,cn,b);
	//		return e;
		}
		
	}
	if (e->tp->memptr()) {
		e = new mdot("i",e);
		e->i1 = 9;
		e = new expr(NE,e,zero);
	}
	else if (e->tp->num_ptr(b) == FCT)
		error("%k(F)",b);
	return e;
}

void stmt::dcl()
/*
	typecheck statement "this" in scope "curr_block->tbl"
*/
{
	Pstmt ss;
	Pname n;
	Pname nn;
	Pstmt ostmt = Cstmt;
	DB( if(Ddebug>=1) error('d',&where,"'%k'->stmt::dcl()",base); );
	for (ss=this; ss; ss=ss->s_list) {
		Pstmt old_loop, old_switch;
		Cstmt = ss;
		enum_promote = 0;
		Ptable tbl = curr_block->memtbl;
//error('d',"stmt::dcl %k",ss->base);
		switch (ss->base) {
		case BREAK:
			inline_restr |= 16;
			if (curr_loop==0 && curr_switch==0)
				error("break not in loop or switch");
			ss->reached();
			break;

		case CONTINUE:
			inline_restr |= 32;
			if (curr_loop == 0) error("continue not in loop");
			ss->reached();
			break;

		case DEFAULT:
			if (curr_switch == 0) {
				error("default not in switch");
				break;
			}
			if (curr_switch->has_default) error("two defaults in switch");
			curr_switch->has_default = ss;
			ss->s->s_list = ss->s_list;
			ss->s_list = 0;
			ss->s->dcl();
			break;

		case SM:
		{	if (ss->e ==0) break;
			TOK b = ss->e->base;
			switch (b) {
			case DUMMY:
				ss->e = 0;
				break;
					// check for unused results
					// don't check operators that are likely
					// to be overloaded to represent "actions":
					// ! ~ < <= > >= << >>
			case EQ:
			case NE:
			case PLUS:
			case MINUS:
			case REF:
			case DOT:
			case MUL:
			case DIV:
			case ADDROF:
			case AND:
			case OR:
			case ER:
			case DEREF:
			case ANDAND:
			case OROR:
			case NAME:
			case VALUE:
				if (ss->e->tp) break;	// avoid looking at generated code
				ss->e = ss->e->typ(tbl);
				if (ss->e->base == CALL) break;
				if (ss->e->tp->base != VOID) {
					if ( ss->e->base == DEREF )
					   error('w',"result of %sE not used",ss->e->e2?"[]":"*");
					else 
					   error('w',"result of%kE not used",b);
					if (ss->e->not_simple()==0) ss->e = dummy;
				}
				break;
			default:
				ss->e = ss->e->typ(tbl);
			}
			break;
		}
		case RETURN:
		{	Pname fn = cc->nof;
			Pfct f = Pfct(fn->tp);
			Ptype rt = f->returns;
			Pexpr v = ss->e;
//error('d',"rt %t",rt);
			while (rt->base == TYPE) rt = Pbase(rt)->b_name->tp;
			if (v != dummy) {
				if (rt->base == RPTR || rt->base == PTR) {
					const_ptr = Pbase(Pptr(rt)->typ)->tconst();
				}
				if (rt->base == RPTR) {
					ref_initializer++;
					v = v->typ(tbl);
					ref_initializer--;
				} else
					v = v->typ(tbl);
				const_ptr = 0;

				if (fn->n_oper==CTOR
				|| fn->n_oper==DTOR
				|| (rt->base==VOID && v->tp!=void_type)) {
					error("unexpected return value");
					// refuse to return the value:
					ss->e = dummy;
				}
				else {
					switch (rt->base) {
					// case TYPE: laready done above
					case RPTR:
						switch (v->base) {
						case NAME:
							if (Pname(v)->n_scope==FCT
							|| Pname(v)->n_scope==ARG)
								error('w',"R to localV returned");
							break;
						case ICON:
						case CCON:
						case FCON:
						case STRING:
							if (Pptr(rt)->typ->tconst()==0)
								error('w',"R to literal returned");
						}
						v = ref_init(Pptr(rt),v,tbl);
						if (v->base==G_CM
						&& v->e2->base==G_ADDROF
						&& v->e2->e2->base==NAME)
							error('w',"R to temporary returned (return value is not lvalue or of wrongT)");
					case ANY:
						break;
					case COBJ:
if (v->base == DEREF) {
	Pexpr v1 = v->e1;
	if (v1->base==CAST) {
		Pexpr v2 = v1->e1;
		if (v2->base == G_CM) {	// *(T)(e1,e2) => (e1,*(T)e2)
			Pexpr v3 = v2->e2;
			v2->e2 = v;
			v2->tp = v->tp;
			v = v2;
			v1->e1 = v3;
		}
	}
}
	if (f->f_result) {
		if (v->base==G_CM && rt->check(v->tp,0/*ASSIGN*/)==0)
			v = replace_temp(v,f->f_result);
		else {
			v = class_init(f->f_result->contents(),rt,v,tbl);
			Pname rcn = rt->is_cl_obj();
			if (Pclass(rcn->tp)->has_itor()==0) {
				// can happen for virtuals and for user defined conversions
				v->tp = rt;
				v = new expr(ASSIGN,f->f_result->contents(),v);
				v->tp = rt;
			}
		}
	}
	else
		v = class_init(0,rt,v,tbl);
						break;
					case PTR:
					{	Pexpr x = v;
						v = ptr_init(Pptr(rt),v,tbl);
						if (v->base == ADDROF
						&& v->e2->base == NAME
						&& Pname(v->e2)->n_stclass == AUTO)
							error('w',"P to local variable%n returned",Pname(v->e2));
					//	if (v==x ||v->e2==x) goto def;
						if (Pchecked == 0) goto def;
						goto ret_save;
					//	break;
					}
					case INT:
					case CHAR:
					case LONG:
					case SHORT:
						if (Pbase(rt)->b_unsigned
						&& v->base==UMINUS
						&& v->e2->base==ICON)
							error('w',"negative returned fromF returning unsigned");
					default:
					def:
					{
						Pexpr x = try_to_coerce(rt,v,"return value",tbl);
						if (x)
							v = x;
						else if (rt->check(v->tp,ASSIGN))
							error("bad return valueT for%n:%t (%tX)",fn,v->tp,rt);
					}

					}
				ret_save:
					ss->ret_tp = rt;
					ss->e = v;
				}
			}
			else {
				if (rt->base != VOID) error("return valueX");
			}
			ss->reached();
			break;
		}

		case DO:	// in DO the stmt is before the test
			inline_restr |= 8;
			old_loop = curr_loop;
			curr_loop = ss;
			{ Pstmt st = ss->s;
			  while(st && st->base == FOR) st = st->for_init;
			  if (st && st->base == DCL)
			  	if (st==ss->s) error("D as onlyS in do-loop");
			}
			ss->s->dcl();
			ss->e = ss->e->typ(tbl);
			ss->e = check_cond(ss->e,DO,tbl);
			curr_loop = old_loop;
			break;

		case WHILE:
			inline_restr |= 8;
			old_loop = curr_loop;
			curr_loop = ss;
			ss->e = ss->e->typ(tbl);
			ss->e = check_cond(ss->e,WHILE,tbl);
			{ Pstmt st = ss->s;
			  while(st && st->base == FOR) st = st->for_init;
			  if (st && st->base == DCL)
				if(st==ss->s) error("D as onlyS in while-loop");
			}
			ss->s->dcl();
			curr_loop = old_loop;
			break;

		case SWITCH:
		{	int ne = 0;
			inline_restr |= 4;
			old_switch = curr_switch;
			curr_switch = ss;
			ss->e = ss->e->typ(tbl);
			ss->e = check_cond(ss->e,SWITCH,tbl);
			{ Pstmt st = ss->s;
			  while(st && st->base == FOR) st = st->for_init;
			  if (st && st->base == DCL)
				if(st==ss->s) error("D as onlyS in switchS");
			}
			{	Ptype tt = ss->e->tp;
			sii:
				switch (tt->base) {
				case TYPE:
					tt = Pbase(tt)->b_name->tp; goto sii;
				case EOBJ:
					ne = Penum(Pbase(tt)->b_name->tp)->no_of_enumerators;
				case ZTYPE:
				case ANY:
				case CHAR:
				case SHORT:
				case INT:
				case LONG:
				case FIELD:
					break;
				default:
					error("%t switchE",ss->e->tp);
				}
			}
			ss->s->dcl();
			if (ne) {	/* see if the number of cases is "close to"
					   but not equal to the number of enumerators
					*/
				int i = 0;
				Pstmt cs;
				for (cs=ss->case_list; cs; cs=cs->case_list) i++;
				if (i && i!=ne) {
					if (ne < i) {
				ee:		error('w',"switch (%t)W %d cases (%d enumerators)",ss->e->tp,i,ne);
					}
					else {
						switch (ne-i) {
						case 1: if (3<ne) goto ee;
						case 2: if (7<ne) goto ee;
						case 3: if (23<ne) goto ee;
						case 4: if (60<ne) goto ee;
						case 5: if (99<ne) goto ee;
						}
					}
				}
			}
			curr_switch = old_switch;
			break;
		}
		case CASE:
			if (curr_switch == 0) {
				error("case not in switch");
				break;
			}
			ss->e = ss->e->typ(tbl);
			ss->e->tp->num_ptr(CASE);
			{	Ptype tt = ss->e->tp;
			iii:
				switch (tt->base) {
				case TYPE:
					tt = Pbase(tt)->b_name->tp; goto iii;
				case ZTYPE:
				case ANY:
				case CHAR:
				case SHORT:
				case INT:
				case LONG:
				case EOBJ:
					Neval = 0;
					long i = ss->e->eval();
					if (Neval == 0) {
						Pstmt cs;
						if (largest_int<i) error("long case value");
						for (cs=curr_switch->case_list; cs; cs=cs->case_list) {
							if (cs->case_value == i) error("case %d used twice in switch",i);
						}
						ss->case_value = int(i);
						ss->case_list = curr_switch->case_list;
						curr_switch->case_list = ss;
					}
					else
						error("bad case label: %s",Neval);
					break;
				default:
					error("%t caseE",ss->e->tp);
				}
			}
		//	if (1) {
		//		Neval = 0;
		//		long i = ss->e->eval();
		//		if (Neval == 0) {
		//			Pstmt cs;
		//			if (largest_int<i) error("long case value");
		//			for (cs=curr_switch->case_list; cs; cs=cs->case_list) {
		//				if (cs->case_value == i) error("case %d used twice in switch",i);
		//			}
		//			ss->case_value = int(i);
		//			ss->case_list = curr_switch->case_list;
		//			curr_switch->case_list = ss;
		//		}
		//		else
		//			error("bad case label: %s",Neval);
		//	}
			if (ss->s->s_list) error('i',"case%k",ss->s->s_list->base);
			ss->s->s_list = ss->s_list;
			ss->s_list = 0;
			ss->s->dcl();
			break;

		case GOTO:
			inline_restr |= 2;
			ss->reached();
		case LABEL:
			/* Insert label in function mem table;
			   labels have function scope.
			*/
			n = ss->d;
			nn = cc->ftbl->insert(n,LABEL);

			/* Set a ptr to the mem table corresponding to the scope
			   in which the label actually occurred.  This allows the
			   processing of goto's in the presence of ctors and dtors
			*/
			if (ss->base == LABEL) {
				nn->n_realscope = curr_block->memtbl;
				inline_restr |= 1;
			}

			if (Nold) {
				if (ss->base == LABEL) {
					if (nn->n_initializer) error("twoDs of label%n",n);
					nn->n_initializer = (Pexpr)1;
				}
				if (n != nn) ss->d = nn;
			}
			else {
				if (ss->base == LABEL) nn->n_initializer = (Pexpr)1;
				nn->where = ss->where;
			}
			if (ss->base == GOTO)
				nn->use();
			else {
				if (ss->s->s_list) error('i',"label%k",ss->s->s_list->base);
				ss->s->s_list = ss->s_list;
				ss->s_list = 0;
				nn->assign();
			}
			if (ss->s) ss->s->dcl();
			break;

		case IF:
		{	
			Pexpr ee = ss->e->typ(tbl);
			if (ee->base == ASSIGN) {
				Neval = 0;
				(void)ee->e2->eval();
				if (Neval == 0)
					error('w',"constant assignment in condition");
			}
			ss->e = ee = check_cond(ee,IF,tbl);

			if (ss->s->base == DCL) error("D as onlyS after `if'");

			// pointer to member returns with a tp set to 0
			if ( ee->tp ) switch (ee->tp->base) {
			case INT:
			case EOBJ:
			case ZTYPE:
			{	long i;
				Neval = 0;
				i = ee->eval();

				if (Neval == 0) {
					Pstmt sl = ss->s_list;
					if (i) {
						DEL(ss->else_stmt);
						ss->s->dcl();
						*ss = *ss->s;
					}
					else {
						DEL(ss->s);
						if (ss->else_stmt) {
							ss->else_stmt->dcl();
							*ss = *ss->else_stmt;
						}
						else {
							ss->base = SM;
							ss->e = dummy;
							ss->s = 0;
						}
					}
					ss->s_list = sl;
					continue;
				}
			}
			}
			ss->s->dcl();
			if (ss->else_stmt) {
				if (ss->else_stmt->base == DCL) error("D as onlyS after `else'");
				ss->else_stmt->dcl();
			}
			break;
		}
		case FOR:
			inline_restr |= 8;
			old_loop = curr_loop;
			curr_loop = ss;
			if (ss->for_init) {
				Pstmt fi = ss->for_init;
				switch (fi->base) {
				case SM:
					if (fi->e == dummy) {
						ss->for_init = 0;
						break;
					}
					fi->dcl();
					break;
				default:
					// for (stmt; e1; e2) stmt1 stmt2
					// => {stmt; for(; e1; e2) stmt1 stmt2}
					//    if stmt != declaration
					// if stmt == declaration, temporarily
					//    rewrite to avoid symbol table
					//    problems in some contexts.
					//    Then put decl back to avoid
					//    extraneous {}.
					// Note: to maintain pointers, ss
					//       must not change
				{	Pstmt tmp = new stmt (SM,curloc,0);
					*tmp = *ss;	// tmp = original for
					tmp->for_init = 0;
					fi->s_list = tmp;
					*ss = *fi;
					curr_loop = old_loop;
					ss->dcl();
					tmp = ss->s_list;
					if ( ss->base == DCL
					&&   tmp->base == FOR   // sanity check
					&&   tmp->for_init == 0 // sanity check
					) {
						// put DCL back in for init
						*fi = *ss;
						*ss = *tmp;
						ss->for_init = fi;
						fi->s_list = 0;
					} else {
						// non-decl stmt in for init
						// put stmts in block in case
						//    they follow a condition...
						// allocate tmp to be sure
						//    fields are initialized
						*fi = *ss;
						tmp = new block(ss->where,0,fi);
						tmp->own_tbl = 0;
						tmp->memtbl = curr_block->memtbl;
						tmp->permanent = ss->permanent;
						*ss = *tmp;
						tmp->permanent = 0; delete tmp;
					}
					// don't repeat stmt::dcl() for
					//    remaining stmts
					goto done;
				}
				}
			}
			if (ss->e == dummy)
				ss->e = 0;
			else {
				ss->e = ss->e->typ(tbl);
				ss->e = check_cond(ss->e,FOR,tbl);
			}
			{ Pstmt st = ss->s;
			  while(st && st->base == FOR) st = st->for_init;
			  if (st && st->base == DCL)
				if(st==ss->s) error("D as onlyS in for-loop");
			}
			ss->s->dcl();
			ss->e2 = (ss->e2 == dummy) ? 0 : ss->e2->typ(tbl);
			curr_loop = old_loop;
			break;

		case DCL:	/* declaration after statement */
		{
			/*	collect all the contiguous DCL nodes from the
				head of the s_list. find the next statement
			*/
			int non_trivial = 0;
			int count = 0;
			Pname tail = ss->d;
			for (Pname nn=tail; nn; nn=nn->n_list) {
				//	find tail;
				//	detect non-trivial declarations
				count++;

				if (nn->n_list) tail = nn->n_list;
				Pname n = tbl->look(nn->string,0);

				if (n && n->n_table==tbl) non_trivial = 2;
				if (non_trivial == 2) continue;
				if ((nn->n_sto==STATIC && nn->tp->base!=FCT)
				|| nn->tp->is_ref()
				|| (nn->tp->tconst() && fct_const==0)) {
					non_trivial = 2;
					continue;
				}

				Pexpr in = nn->n_initializer;
				if (in)
					switch (in->base) {
					case ILIST:
					case STRING:
						non_trivial = 2;
						continue;
					}
				non_trivial = 1;
				Pname cln = nn->tp->is_cl_obj();
				if (cln == 0) cln = cl_obj_vec;
				if (cln == 0) continue;
				if (Pclass(cln->tp)->has_ctor()) {
					non_trivial = 2;
					continue;
				}
				if (Pclass(cln->tp)->has_dtor()) non_trivial = 2;
			}

			while( ss->s_list && ss->s_list->base==DCL ) {
				Pstmt sx = ss->s_list;
				tail = tail->n_list = sx->d;	// add to tail
				for (nn=sx->d; nn; nn=nn->n_list) {
					//	find tail;
					//	detect non-trivial declarations
					count++;
					if (nn->n_list) tail = nn->n_list;
					Pname n = tbl->look(nn->string,0);
					if (n && n->n_table==tbl) non_trivial = 2;
					if (non_trivial == 2) continue;
					if ((nn->n_sto==STATIC && nn->tp->base!=FCT)
					|| nn->tp->is_ref()
					|| (nn->tp->tconst() && fct_const==0)) {
						non_trivial = 2;
						continue;
					}
					Pexpr in = nn->n_initializer;
					if (in)
						switch (in->base) {
						case ILIST:
						case STRING:
							non_trivial = 2;
							continue;
						}
					non_trivial = 1;
					Pname cln = nn->tp->is_cl_obj();
					if (cln == 0) cln = cl_obj_vec;
					if (cln == 0) continue;
					if (Pclass(cln->tp)->has_ctor()) {
						non_trivial = 2;
						continue;
					}
					if (Pclass(cln->tp)->has_dtor()) non_trivial = 2;
				}
				ss->s_list = sx->s_list;
			/*	delete sx;	*/
			}

			Pstmt next_st = ss->s_list;
//error('d',"dcl stmt : d %n  non_trivial %d  curr own_tbl %d  inline_restr 0%o",ss->d,non_trivial,curr_block->own_tbl,inline_restr);
			if (non_trivial==2	// must
			|| (non_trivial==1	// might
				&& ( curr_block->own_tbl==0	// why not?
				|| inline_restr&3	/* label seen */)
			  	)
			) {
				if (curr_switch && non_trivial==2) {
					Pstmt cs = curr_switch->case_list;
					Pstmt ds = curr_switch->has_default;
					Pstmt bl;
					if (cs == 0)
						bl = ds;
					else if (ds == 0)
						bl = cs;
					else if (cs->where.line<ds->where.line)
						bl = ds;
					else
						bl = cs;

					if ((bl==0 || bl->s->base!=BLOCK) && curr_switch->s->memtbl==tbl)
						error('s',"non trivialD in switchS (try enclosing it in a block)");
				}

				/*	Create a new block,
					put all the declarations at the head,
					and the remainder of the slist as the
					statement list of the block.
				*/
				//ss->base = BLOCK; //DCL 

				/*	check that there are no redefinitions
					since the last "real" (user-written,
					non-generated) block
				*/
				{ Pname lastnn = 0;
				  for( nn=ss->d; nn; nn=nn->n_list ) {
					Pname n;
//n=curr_block->memtbl->look(nn->string,0);
//error('d',"checking %n  lex_level: %d  n: %n  n->lex_level: %d",nn,nn->lex_level,n,n?n->lex_level:0);
//error('d',"   own_tbl: %d  curr_block: %d  n->n_table: %d",curr_block->own_tbl,curr_block,n->n_table);
//error('d',"   real_block: %d  n's real_block: %d",curr_block->memtbl->real_block,n->n_table->real_block);
					//if( curr_block->own_tbl
					if ( (n=curr_block->memtbl->look(nn->string,0))
					&& n->n_table->real_block==curr_block->memtbl->real_block
					&& n->tp->base!=FCT
					&& n->tp->base!=OVERLOAD
					&& nn->lex_level == n->lex_level ) {
						error("twoDs of%n",n);
						if (lastnn==0) ss->d=nn->n_list;
						else lastnn->n_list=nn->n_list;
					} else lastnn = nn;
				  } // for nn
				}

				/*	attach the remainder of the s_list
					as the statement part of the block.
				*/
				ss->s = next_st;
				ss->s_list = 0;

				/*	create the table in advance,
					in order to set the real_block
					ptr to that of the enclosing table
				*/
				ss->memtbl = new table(count+4,tbl,0);
				ss->memtbl->real_block = curr_block->memtbl->real_block;
				Pblock(ss)->dcl(ss->memtbl);
			}
			else {	/*	to reduce the number of symbol tables,
					do not make a new block,
					instead insert names in enclosing block,
					and make the initializers into expression
					statements.
				*/
				Pstmt sss = ss;
				{ Pname lastnn = 0;
				  for( nn=ss->d; nn; nn=nn->n_list ) {
					Pname n;
//error('d',"nn %n",nn);
					//if( curr_block->own_tbl
					if ( (n=curr_block->memtbl->look(nn->string,0))
					&& n->n_table->real_block==curr_block->memtbl->real_block
					&& n->tp->base!=FCT && n->tp->base!=OVERLOAD
					&& nn->lex_level == n->lex_level ) {
						error("twoDs of%n",n);
						n = 0;
						if (lastnn==0) ss->d=nn->n_list;
						else lastnn->n_list=nn->n_list;
					} else {
						n = nn->dcl(tbl,FCT);
						lastnn=nn;
					}

					if (n == 0) {
						if (ss) {
							ss->base = SM;
							ss->e = 0;
						}
						continue;
					}
//error('d',"hoisted %n to outer blk",n);

					Pexpr in = n->n_initializer;
					n->n_initializer = 0;

					if (ss) {
						sss->base = SM;
						ss = 0;
					}
					else
						sss = sss->s_list = new estmt(SM,sss->where,0,0);
					if (in) {
						switch (in->base) {
						case G_CALL:	/* constructor? */
						{
							Pname fn = in->fct_name;
							if (fn && fn->n_oper==CTOR) break;
						}
						default:
							in = new expr(ASSIGN,n,in);
							in->tp = n->tp;
						}
					//	sss->e = in->typ(tbl);
						sss->e = in;
					}
					else
						sss->e = dummy;
				  } // for nn
				}

				ss = sss;
				ss->s_list = next_st;
			}
			break;
		}

		case BLOCK:
			Pblock(ss)->dcl(tbl);
			break;

		case ASM:
			/* save string */
		{
			char* s = (char*)ss->e;
			int ll = strlen(s);
			char* s2 = new char[ll+1];
			strcpy(s2,s);
			ss->e = Pexpr(s2);
			break;
		}
		default:
			error('i',"badS(%p %d)",ss,ss->base);
		}
	}
done:
	Cstmt = ostmt;
}

void block::dcl(Ptable tbl)
/*
	Note: for a block without declarations memtbl denotes the table
	for the enclosing scope.
	A function body has its memtbl created by fct::dcl().
*/
{
	int bit_old = bit_offset;
	int byte_old = byte_offset;
	int max_old = max_align;
	Pblock block_old = curr_block;

	if (base != BLOCK && base != DCL) error('i',"block::dcl(%d)",base);

	curr_block = this;
//error('d',"%d->block::dcl(%d) base %k",this,tbl,base);
//error('d',"    memtbl %d  own_tbl %d  d %n  s %k",memtbl,own_tbl,d,s?s->base:0);
	if (d) {
		own_tbl = 1;
		base = BLOCK;
		if (memtbl == 0) {
			int nmem = d->no_of_names()+4;
			memtbl = new table(nmem,tbl,0);
			memtbl->real_block = this;
			/*	this is a "real" block from the
				source text, and not one created by DCL's
				inside a block. */
		}
		else
			if (memtbl != tbl) error('i',"block::dcl(?)");

		Pname nx;
		for (Pname n=d; n; n=nx) {
			nx = n->n_list;
			n->dcl(memtbl,FCT);
			switch (n->tp->base) {
			case CLASS:
			case ANON:
			case ENUM:
				break;
			default:
				delete n;
			}
		}
	}
	else if ( base == BLOCK ) {
		own_tbl = 1;
		if (memtbl == 0) {
			int nmem = 4;
			memtbl = new table(nmem,tbl,0);
			memtbl->real_block = this;
			/*	this is a "real" block from the
				source text, and not one created by DCL's
				inside a block. */
		} else
			if (memtbl != tbl) error('i',"block::dcl(?)");
	} else {
		base = BLOCK;
		memtbl = tbl;
	}

	Pname odcl = Cdcl;
	if (s) s->dcl();
	if (own_tbl) {
		Pname m;
		int i;
		for (m=memtbl->get_mem(i=1); m; m=memtbl->get_mem(++i)) {
			Ptype t = m->tp;

if (in_class_dcl) m->lex_level -= 1;

			if (t == 0) {
				if (m->n_assigned_to == 0)
				   error("label %sU",m->string);
				if (m->n_used == 0)
				   error('w',"label %s not used", m->string);
				continue;
			}
		ll:
			switch (t->base) {
			case TYPE:	t = Pbase(t)->b_name->tp; goto ll;
			case CLASS:
			case ANON:
			case ENUM:
			case FCT:
			//case VEC:
				continue;
			}

			if (m->n_addr_taken == 0) {
				if (m->n_used) {
					if (m->n_assigned_to) {
					}
					else if ( t->base != VEC ) {
						switch (m->n_scope) {
						case FCT:
							Cdcl = m;
							if (m->string[0] != '_' && m->string[1] != '_' )
								error('w',&m->where,"%n used but not set",m);
						}
					}
				}
				else {
					if (m->n_assigned_to) {
					}
					else if (m->string[0]!='_' || m->string[1]!='_') {
						switch (m->n_scope) {
						case ARG:
						case FCT:
							Cdcl = m;
							error('w',&m->where,"%n not used",m);
						}
					}
				}
			}
		}
	}
	Cdcl = odcl;

	d = 0;

	if (bit_offset) byte_offset += SZ_WORD;
	bit_offset = bit_old;
	byte_offset = byte_old;
	curr_block = block_old;
}

void name::field_align()
/*
	 adjust alignment
*/
{
	Pbase fld = (Pbase)tp;
	int nbits = fld->b_bits;

	int a = (F_SENSITIVE) ? fld->b_fieldtype->align() : SZ_WORD;
	if (max_align < a) max_align = a;

	if (nbits == 0) {		// force word alignment
		int b;
		if (bit_offset)
			nbits = BI_IN_WORD - bit_offset;
		else if (b = byte_offset%SZ_WORD)
			nbits = b * BI_IN_BYTE;
	//	else
	//		nbits = BI_IN_WORD;
		if (max_align < SZ_WORD) max_align = SZ_WORD;
	}
	else if (bit_offset == 0) {	// take care of part of word
		int b = byte_offset%SZ_WORD;
		if (b) {
			byte_offset -= b;
			bit_offset = b*BI_IN_BYTE;
		}
	}
//error('d',"byteoff %d bitoff %d bits %d",byte_offset,bit_offset,nbits);
	int x = (bit_offset += nbits);
	if (BI_IN_WORD < x) {
		fld->b_offset = 0;
		byte_offset += SZ_WORD;
		bit_offset = nbits;
	}
	else {
		fld->b_offset = bit_offset;
		if (BI_IN_WORD == x) {
			bit_offset = 0;
			byte_offset += SZ_WORD;
		}
		else
			bit_offset = x;
	}
	n_offset = byte_offset;
}
0707071010112043701004440001630000160000010172500466055376100000700000171674dcl3.c/*ident	"@(#)ctrans:src/dcl3.c	1.7" */
/**************************************************************************

	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.

dcl3.c:
	Routines used by ::dcl fucntions: fct::dcl() etc.

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

#include "cfront.h"
#include "size.h"
#include "template.h"

static void vbase_pointers(Pname fn, Pclass cl)
/*
	insert argument for virtual base pointers (if any)
	after f_this and before f_argtype
*/
{
//error('d',"vbase_pointers(%n,%t) %d %k",fn,cl,fn->tp,fn->n_oper);
	Pfct f = Pfct(fn->tp);
	if (fn->n_oper == CTOR) {
		Pname d = 0;
		for (Pbcl b = cl->baselist; b; b=b->next) {
			if (b->base != VIRTUAL) continue;
			Pname a = new name(b->bclass->string);
			a->tp = b->bclass->this_type;
			a->n_list = d;
			a->n_table = f->body ? f->body->memtbl : 0;
			a->where = fn->where;
			d = a;
		}	
				
		if (d) {
			for (Pname dd =d;;) {
				if (d->n_list == 0) {
					d->n_list = f->f_args->n_list;
					break;
				}
				d = d->n_list;
			}
			f->f_args->n_list = dd;
		}
	}
	if (fn->n_oper == DTOR) {	// add __free argument
//error('d',"add __free to %n",fn);
		Pname fa = new name;
		fa->tp = int_type;
		fa->n_scope = ARG;
		fa->where = fn->where;

		Pname a = f->f_args;
		if (a == 0)
			f->f_args = fa;
		else {
			for(;;a = a->n_list) {
// error('d',"a %d %t",a,a->tp);
				if (a->n_list == 0) {
					a->n_list = fa;
					break;
				}
			}
		}
	}
}

void make_res(Pfct f)
/*
	returns X where X(X&) has been declared
	add "_result" argument of type X*
*/
{
	Pname cl = f->returns->is_cl_obj();
	if (cl==0 || Pclass(cl->tp)->has_itor()==0) return;

	Pname rv = new name("_result");
	rv->tp  = f->returns->addrof();
	rv->n_scope = FCT;	// not a ``real'' argument
	rv->n_used = 1;
	rv->n_list = f->argtype;
	if (f->f_this)
		f->f_this->n_list = rv;
	else
		f->f_args = rv;
	f->f_result = rv;
	f->s_returns = void_type;
}

void name::check_oper(Pname cn)
/*
	check declarations of operators, ctors, dtors
*/
{
// error('d', "%n->check_oper( %n ): n_oper: %k", this, cn, n_oper );
	switch (n_oper) {
	case CALL:
	case DEREF:
	case REF:
		if (cn == 0) error("operator%s must be aM",keys[n_oper]);
		break;
	case ASPLUS:
	case ASMINUS:
	case ASMUL:
	case ASDIV:
	case ASMOD:
	case ASAND:
	case ASOR:
	case ASER:
	case ASLS:
	case ASRS:
		if ( warning_opt ) {
			if ( cn == 0 || Pfct(tp)->f_static )
				error('w', "operator%s should be a non-staticMF",keys[n_oper]);
		}
		break;
	case ASSIGN:
		if (cn == 0) 
			error(strict_opt?0:'w',"non-member operator%k() (anachronism)",n_oper);
		break;
	case NOT: 	/* unary operators only */
	case COMPL:
	// case INCR:
	// case DECR:
		Pfct f = Pfct(tp);
		if (cn && f->argtype) 
			error("%n::%n takes noA",cn, this);
		else if (f->nargs == 2)
			error("%n takes 1A only",this);
		break;
	case INCR:
	case DECR:
		// check for postscript instance
		f = Pfct(tp);
		if (cn) { // member
			if ( f->argtype && f->nargs == 1 ) {
				Pname n = f->argtype;
				if ( n->tp->base != INT )
					error("%n must takeA ofT int, not %t",this,n->tp);
			}
		}
		else 
		if (f->nargs == 2) { // non-member
			Pname n = f->argtype->n_list;
			if ( n->tp->base != INT )
				error("%n must takeA ofT int, not %t",this,n->tp);
		}
		break;

	case 0:
	case TNAME:	/* may be a constructor */
		if (cn && ((strcmp(cn->string,string)==0) ||
			((Pclass(cn->tp)->class_base == 
				instantiated_template_class) &&
			(strcmp(string, 
				Ptclass(cn->tp)->unparametrized_tname()->string) == 0)))) 
		{
			if (tp->base == FCT) {
				Pfct f = Pfct(tp);
				if (f->returns!=defa_type)
					error("%s::%s()W returnT",string,string);
				f->returns = void_type;
				string = "__ct";
				n_oper = CTOR;
			}
			else
				error('s',"struct%nM%n",cn,cn);
		}
		else
			n_oper = 0;
		break;
	case DTOR:	/* must be a destructor */
//error('d',"dtor %s",string);
		if (cn == 0) {
			n_oper = 0;
			error("destructor ~%s() not inC",string);
		}
                else 
		if ((strcmp(cn->string,string) == 0) ||
			((Pclass(cn->tp)->class_base ==
				instantiated_template_class) &&
                         (strcmp(string,
				Ptclass(cn->tp)->unparametrized_tname()->string)==0)))
		{
		dto:
			Pfct f = (Pfct)tp;
			string = "__dt";
			if (tp->base != FCT) {
				error("%s::~%s notF",cn->string,cn->string);
				tp = new fct(void_type,0,1);
			}
  			else if (f->returns!=defa_type/* && f->returns!=void_type*/) {
  				if ( f->returns != void_type ||
  					f->body != 0 || friend_in_class == 0 ) 
  						error("%s::~%s()W returnT",cn->string,cn->string);
  			}

			if (f->argtype) {
				error("%s::~%s()WAs",cn->string,cn->string);
				f->nargs = 0;
				f->nargs_known = 1;
				f->argtype = 0;
			}
			f->returns = void_type;
		}
		else {
			if (strcmp(string,"__dt") == 0) goto dto;
			error("~%s in %s",string,cn->string);
			n_oper = 0;
		}
		break;
	case TYPE:
// cond stores the type of the operator function
// error('d',"type %t",cond);
		if (cn == 0) {
			// error("operator%t() not aM",Ptype(n_initializer));
			error("operator%t() not aM",Ptype(cond));
			n_oper = 0;
			// n_initializer = 0;
			cond = 0;
		}
		else {
			Pfct f = Pfct(tp);
			// n_initializer = 0;
			Ptype tx = Ptype(cond);
			cond = 0;
			if (f->base != FCT) error("badT for%n::operator%t()",cn,tx);
			if (f->returns != defa_type) {
			//	if (f->returns->check(tx,0)) error("bad resultT for%n::operator%t()",cn,tx);
				error("resultT for%n::operator%t()",cn,tx);
				DEL(f->returns);
			}
			if (f->argtype) {
				error("%n::operator%t()WAs",cn,tx);
				f->argtype = 0;
			}
			f->returns = tx;
			Pname nx = tx->is_cl_obj();
			if (nx && can_coerce(tx,cn->tp)) error("both %n::%n(%n) and %n::operator%t()",cn,cn,nx,tx);
			char buf[1024];
			char* bb = tx->signature(buf);
			int l2 = bb-buf;
			if (1023<l2) error('i',"N::check_oper():N buffer overflow");
			char* p = new char[l2+5];
			p[0] = '_';
			p[1] = '_';
			p[2] = 'o';
			p[3] = 'p';
			strcpy(p+4,buf);
			string = p;
		}
		break;
	}
}

Pexpr vbase_args(Pfct a, Pname bn)
/*
	constructor a calls the constructor bn for a base class
	generate argument list needed for virtual base arguments
*/
{
	Pfct b = Pfct(bn->tp);
//error('d',"vbase_args%n: %t %k",bn,b,b->base);
	Pexpr args = 0;
	Pexpr tail = 0;
	if (b->base == OVERLOAD) b = Pfct(Pgen(b)->fct_list->f->tp);	// doesn't matter which
	for (Pname d = b->f_args->n_list; d!=b->argtype; d=d->n_list) {
		for (Pname dd = a->f_args->n_list; dd; dd=dd->n_list)
			// using strcmp is a trick
			if (strcmp(dd->string,d->string)==0) break;

		Pexpr aa = new expr(ELIST,dd,0);
		if (args == 0)
			args = aa;
		else
			tail->e2 = aa;
		tail = aa;
	}
	return args;
}

void fct::init_bases(Pclass cl, Pexpr)
/*
	in "cl"'s constructor "this" generate code to initialize base classes
	and members using the initializers "f->f_init"
	
	this->f_init == list of names of classes to be initialized
		COLON(b)	=> base class b
				=> constructor call in f_init->n_initializer
		COLON()		=> unnamed base class
				=> constructor call in f_init->n_initializer
		NAME(m)		=> member m
				=> constructor call in m->n_initializer
*/
{
	Ptable ftbl = body->memtbl;
	DB( if(Ddebug>=1) error('d',"init_bases %t init %d",cl,f_init); );

	// explicit initializers
	if ( cl && cl->csu == UNION && f_init && f_init->n_list )
		error(&f_init->where,"multipleIrs in unionK %s:: %s",cl->string,cl->string);
	for (Pname nx, nn=f_init; nn; delete nn,(nn=nx) ) {
		Pexpr i = nn->n_initializer;
		nn->n_initializer = 0;
		nx = nn->n_list;

// error('d',"init_base %s %d",nn->string,i);
		if (nn->string) {
			// lookup in case type name hides a "real" member
			{ Pname mmm = cl->memtbl->look(nn->string,0);
			  if ( mmm ) nn->base = mmm->base;
			}
			if (nn->base == TNAME) {	// base class
				char *bn;
				while ( nn->tp && nn->tp->base == TYPE )
					nn->tp = Pbase(nn->tp)->b_name->tp;
				if ( nn->tp && nn->tp->base == COBJ )
				    bn = Pbase(nn->tp)->b_name->string;
				else
				    bn = nn->string;
				for (Pbcl l = cl->baselist; l; l=l->next) {
					Pclass bcl = l->bclass;
					if ((strcmp(bcl->string,bn) == 0) ||
						((bcl->class_base ==
							instantiated_template_class) &&
						((strcmp(nn->string,
							Ptclass(bcl)->unparametrized_tname()->string)) == 0)))
					{

						// l->init is zeroed out in ctor_simpl
						// if error_count, simpl() not invoked
						if (l->init && error_count == 0) 
							error("twoIrs for%t",bcl);
						else
							l->init = base_init(bcl,i,ftbl,l->obj_offset);
						goto con;
					}
				}
				error(&nn->where,"unexpectedAL: noBC%n",nn);
			con:
				continue;
			}
			else {	// member initializer
				Pname m = cl->memtbl->look(nn->string,0);
				if (m && m->n_table==cl->memtbl)
					m->n_initializer = mem_init(m,i,ftbl);
				else
					error(&nn->where,"%n not inC %s",nn,cl->string);
			}
		}
		else {			// unnamed base class
			Pbcl l = cl->baselist;
			if (l == 0) {
				error("unexpectedAL: noBC called");
				continue;
			}

			if (l->next) {
				bit cnt = 0, rvb = 0; // remote virtual base classes
				for (Pbcl ll = l; ll; ll = ll->next, ++cnt ) 
     					if (ll->base==VIRTUAL && ll->promoted) ++rvb;
         			if ( rvb ) 
					error("unnamedBCIr: %dBCes(%d non-explicit virtualBC%s)",cnt,rvb,rvb==1?"":"es");
				else error("unnamedBCIr: %dBCes",cnt);
				continue;
			}
			
			if (l->init)
				error("twoIrs for%t",l->bclass);
			else {
				error(strict_opt?0:'w',&nn->where,"N ofBC%t missing from BCIr (anachronism)",l->bclass);
				l->init = base_init(l->bclass,i,ftbl,l->obj_offset);
			}
		}
	} // for

	for (Pbcl l = cl->baselist; l; l=l->next) {
		// default initialization of base classes
		Pname ctor;
		Pclass bcl = l->bclass;
		if (l->init==0 && (ctor=bcl->has_ctor()))
			l->init = base_init(bcl,0,ftbl,l->obj_offset);
	}
}

int inline_restr;	/* report use of constructs that the inline expanded
			   cannot handle here */

void fct::dcl(Pname n)
{
	int nmem = TBLSIZE;
	Pname a;
	Pname ll;
	Ptable ftbl;

	Pptr cct = 0;
	int const_old = const_save;

	int bit_old = bit_offset;
	int byte_old = byte_offset;
	int max_old = max_align;

	if (base != FCT) error('i',"F::dcl(%d)",base);
	if (body == 0) error('i',"F::dcl(body=%d)",body);
	if (n==0 || n->base!=NAME) error('i',"F::dcl(N=%d %d)",n,(n)?n->base:0);
	DB( if(Ddebug>=1) error('d',"fct::dcl(%n) %k %d %t",n,n->n_scope,body->own_tbl,this); );
	if (body->own_tbl) return;	// done already

//	if (f_inline==0 ) n->n_dcl_printed = 1;	// beware of recursive calls, no decl needed
//	if (f_inline && debug_opt) n->n_dcl_printed = 2;
	if (body->memtbl == 0) body->memtbl = new table(nmem+3,gtbl,0);
	body->own_tbl = 1;
	ftbl = body->memtbl;
	ftbl->real_block = body;

	max_align = 0;//AL_FRAME;
	bit_offset = 0;

	cc->stack();
	cc->nof = n;
	cc->ftbl = ftbl;

	switch (n->n_scope) {
	case 0:
	case PUBLIC:
	{	cc->not = n->n_table->t_name;
		cc->cot = Pclass(cc->not->tp);
		cc->tot = cc->cot->this_type;
	//	if (f_this==0 || cc->tot==0) error('i',"F::dcl(%n): f_this=%d cc->tot=%d",n,f_this,cc->tot);
		if (f_this) f_this->n_table = ftbl;	// fake for inline printout
		cc->c_this = f_this;


		Pclass cl = Pclass(cc->not->tp);

		if (cl->c_body!=3
		|| n->n_initializer
		|| n->n_sto==STATIC
		|| f_inline
		|| f_imeasure
		|| f_virtual==0)
			;
		else {		// could be the function where we need to
				// output the vtbl
			int i;
			for (Pname nn=cl->memtbl->get_mem(i=1); nn; nn=cl->memtbl->get_mem(++i) ) {
			Ptype t = nn->tp;
			if (t)
			switch (t->base) {
			case FCT:
				if (nn == n) goto prnt;
				if (nn->n_initializer
				|| nn->n_sto==STATIC
				|| Pfct(nn->tp)->f_inline
				|| Pfct(nn->tp)->f_imeasure
				|| Pfct(nn->tp)->f_virtual==0) break;
				goto zaq;

			case OVERLOAD:
			{	for (Plist gl=Pgen(t)->fct_list; gl; gl=gl->l) {
					Pname nn = gl->f;
					if (nn == n) goto prnt;
					if (nn->n_initializer
					|| nn->n_sto==STATIC
					|| Pfct(nn->tp)->f_inline
					|| Pfct(nn->tp)->f_imeasure
					|| Pfct(nn->tp)->f_virtual==0) continue;
					goto zaq;
				}
			}
			}
		}
			goto zaq;
		prnt:
			cl->print_all_vtbls(cl);
			goto zaq;
		}
	}
	}
zaq:
		// protect against: class x; x f(); class x { x(x&); ....
	if (f_result == 0) make_res(this);
	if (f_result) f_result->n_table = ftbl;		// fake for inline printout

	returns->tsizeof();	// make sure size is known

	Pname ax;
	for (a=argtype, ll=0; a; a=ax) {
		ax = a->n_list;
		Pname nn = a->dcl(ftbl,ARG);
		Pname cn = nn->tp->is_cl_obj();
		if (cn == 0) cn = cl_obj_vec;
		if (cn) (void)cn->tp->tsizeof();	// make sure it is printed
		nn->n_assigned_to = nn->n_used = nn->n_addr_taken = 0;
		nn->n_list = 0;

		switch (nn->tp->base) {
		case CLASS:
		case ENUM:	/* unlink types declared in arg list */
			nn->dcl_print(0);
			break;
		default:
			if (ll)
				ll->n_list = nn;
			else
				f_args = argtype = nn;
			ll = nn;
		}
		delete a;
	}

	if (f_result) {		// link in f_result
		f_args = f_result;
		f_result->n_list = argtype;
	}

	if (f_this) {		// link in f_this
		f_args = f_this;
		f_this->n_list = f_result ? f_result : argtype;
	}

	if (n->n_oper==CTOR || n->n_oper==DTOR) vbase_pointers(n,cc->cot);

	if (n->n_oper == CTOR) {
		const_save = 1;
		init_bases(cc->cot,f_init);
	}
	else if (f_init)
		error(0,"unexpectedAL: not aK");

	PERM(returns);
	const_save = f_inline&&debug_opt==0;
	inline_restr = 0;
	body->dcl(ftbl);
	
	defined |= DEFINED;
	if (f_inline && inline_restr && returns->base!=VOID) {
		f_inline = 0;
		char* s = (inline_restr & 32) ? "continue"
			: (inline_restr & 16) ? "break"
			: (inline_restr & 8) ? "loop"
			: (inline_restr & 4) ? "switch"
			: (inline_restr & 2) ? "goto"
			: (inline_restr & 1) ? "label"
			: "" ;
		if (warning_opt) {
			error('w', "\"inline\" ignored, %n contains %s",n,s);
			error('w', "out-of-line copy of %n created",n);
		}
	//	if (cc->cot)
		n->simpl();	//BS6
		n->dcl_print(0);
	}
	const_save = const_old;

	if (f_inline && debug_opt==0) isf_list = new name_list(n,isf_list);

	bit_offset = bit_old;
	byte_offset = byte_old;
	max_align = max_old;
	cc->unstack();

//error('d',"fct-> returns %t",returns);
}

Pexpr fct::base_init(Pclass bcl, Pexpr i, Ptable ftbl, int offset)
/*
	have base class bcl and expr list i
	return "( *(base*)this ) . ctor( i )"
	ctor call generated in expr.typ()
*/
{
	Ptype ty = bcl->this_type;
	Pexpr th = rptr(ty,f_this,offset);		// base*
	Pname ctor = bcl->has_ctor();

//error('d',"fct::B_init(C %t, i %d, %d) ctor %n",bcl,i,i?i->tp:0,ctor);

	Pexpr ii = (i && i->base==ELIST)?i->e1:i;

	if (ii
	&& ii->base==DEREF
	&& ii->e1->base==CAST
	&& th->base==CAST) th->i2 = ii->e1->i2;

	if (ctor == 0) {
		if (i && i->base!=ELIST) i = new expr(ELIST,i,0);

		Pexpr v = new texpr(VALUE,bcl,i);	// ?.base(i)
		v->e2 = new expr(DEREF,th,0);		// (*(base*)this).base(i)
		v = v->typ(ftbl);			// *base(&*(base*)this,i)
//error('d',"v %k",v->base);
		switch (v->base) {
		case DEREF:
			return v->e1;			// base(&*(base*)this,i)
		case ASSIGN:		// degenerate base(base&): *(base*)this=i
			th = new texpr(CAST,ty,f_this);
			v = new expr(CM,v,th);		// (*(base*)this=i,(base*)this);
			return v->typ(ftbl);
		default:
			return 0;
		}
	}


	Pname icn;
	if (i) {
		ii = ii->typ(ftbl);
		if (bcl->has_itor()==0
		&& (icn=ii->tp->is_cl_obj())
		&& (Pclass(icn->tp)==bcl || Pclass(icn->tp)->has_base(bcl))) {
			// degenerate base(base&): *(base*)this=i
			// memberwise copy
//error('d',"copy %t",ty);
		//	th = new cast(ty,f_this);
		//	th = th->contents();
			th = new texpr(CAST,ty,f_this);
			th = th->contents();
			th = th->typ(ftbl);
			if (Pclass(icn->tp)!=bcl) {	// cast needed
				Pptr r = new ptr(RPTR,Pptr(ty)->typ);
				ii = new texpr(CAST,r,ii);
				ii = ii->typ(ftbl);
			}
			ii = new expr(ASSIGN,th,ii);
			ii->tp = th->tp;
					// simulate `return this':
					// *(base*)this=i,(base*)this
			ii = new expr(CM,ii,new cast(ty,f_this));
			ii->tp = th->tp;
			return ii;
		//	return ii->typ(ftbl);	// don't find cl::operator=()
		}
		if (i->base == ELIST) i->e1 = ii;
	}
//Pexpr x = call_ctor(ftbl,th,ctor,i,REF,vbase_args(this,ctor));
//error('d',"call %n %t -> %d %k",ctor,ctor->tp,x,x->base);
//	return x;
	return call_ctor(ftbl,th,ctor,i,REF,vbase_args(this,ctor));
}


Pexpr fct::mem_init(Pname mn, Pexpr i, Ptable ftbl)
/*
	return "member_ctor( m, i )"
*/
{
// a new entry for B::B_pub, in general, has no tp and no
// real info: all the tp-> only work on our systems because
// 0 pointer dereference isn't system memory.  it core dumps
// in set_const since no test is made on this == 0.
//error('d',"mem_init %n",mn);

//	if (mn->n_stclass == STATIC) error('s',"MIr for static%n",mn);
        switch (mn->n_stclass) {
        case STATIC:
                error("MIr for static%n",mn);
                break;
        case ENUM:
                error("MIr for enumeration constant%n", mn);     
                break;
        }

	Pname member = (mn->base==PUBLIC && mn->n_qualifier) ? mn->n_qualifier : mn;

	if (i) i = i->typ(ftbl);
	Pname cn = member->tp->is_cl_obj();	// first find the class name

//	if (member->n_stclass == STATIC) error('s',"MIr for static%n",member);
//	if (i) i = i->typ(ftbl);
//	Pname cn = member->tp->is_cl_obj();	// first find the class name
	Pref tn = new ref(REF,f_this,member);
	tn->tp = member->tp;
//error('d',"MI for %n %t = %t",member,member->tp,i?i->tp:0);
//error('d',"fthis %d %t member %n tp %t",f_this,f_this->tp,member,tn->tp);
	if (cn) {
		Pclass mcl = Pclass(cn->tp);	// then find the classdef
		Pname ctor = mcl->has_ctor();
		Pname icn;

		if (i
		&& mcl->has_itor()==0
		&& (icn=i->tp->is_cl_obj())
		&& Pclass(icn->tp)==mcl) {	// bitwise copy
			Pexpr init = new expr(ASSIGN,tn,i);
			init->tp = tn->tp;
		//	return init->typ(ftbl);	// don't look for mcl.operator=()
			member->assign();
			return init;
		}
		
		if (ctor) return call_ctor(ftbl,tn,ctor,i,DOT);

		error("Ir forM%nW noK",member);
		return 0;
	}

	if (cl_obj_vec) {
		if (i && i->base == ELIST)
			error("illegalIrL for %t%nWinM initializationL",mn->tp,mn);
		else error('s',"Ir forCM %t%nWK",mn->tp,mn);
		return 0;
	}

	if (i && i->base == ELIST) {
		if (i->e2) error("Ir for%n not a simpleE",member);
		i = i->e1;
	}

	if (member->tp->is_ref() && (i == 0)) {
		error("empty Ir for reference %n", member);
		return 0 ;
	}

// error( 'd', "fct_mem_init: %n %k", member, member->tp->base );
	switch (member->tp->base) {
	// case RPTR:
	// 	if ( i == 0 ) {
	// 		error( "empty Ir for reference %n", member );
	// 		return 0;
	// 	}
	// 	break;
	case VEC:
	case FCT:
	case OVERLOAD:
		error("Ir for%n ofT %t",member,member->tp);
		return 0;
	}

//error('d',"tp %t",member->tp);
	if (member->tp->tconst()) {
                int save_ignore_const = ignore_const;
                ignore_const = 1;
                i = new expr(ASSIGN,tn,i);
                i = i->typ(ftbl);
                ignore_const = save_ignore_const;
                return i;
	}

	Pptr pt;
	if (pt = member->tp->is_ref()) {
		switch (pt->typ->base) {
		case FCT:
		case OVERLOAD:
			i = ptr_init(pt,i,ftbl);
			break;
		default:
			i = ref_init(pt,i,ftbl);
		}
		i = new expr(ASSIGN,tn,i);
		i->tp = tn->tp;
		member->assign();	// cannot call typ: would cause dereference
		return i;
	}

	i = new expr(ASSIGN,tn,i);
	return i->typ(ftbl);	// typ performs the type check on the assignment
}

Pexpr replace_temp(Pexpr e, Pexpr n)
/*
	e is on the form
				f(&temp,arg) , temp
			or
				&temp->ctor(arg) , temp
			or
				x->f(&temp,arg) , temp
	change it to
				f(n,arg)
			or
				n->ctor(arg)
*/
{
	Pexpr c = e->e1;	// f(&temp,arg) or &temp->ctor(args)
	Pexpr ff = c->e1;
	Pexpr a = c->e2;	// maybe ELIST(&temp,arg)
	Pexpr tmp = e->e2;

//error('d',"suppress(%d %k) %n",tmp->base,tmp->base,tmp->base==NAME?tmp:0);
	if (tmp->base==DEREF) tmp = tmp->e1;
	if (tmp->base==CAST) tmp = tmp->e1;
	if (tmp->base==ADDROF || tmp->base==G_ADDROF) tmp = tmp->e2;
        if (tmp->base != NAME) return e; //error('i',"replace %k",tmp->base);
	tmp->tp = any_type;	// temporary not used: suppress it

//error('d',"replace_temp(%k %k) c %k ff %k",e->base,n->base,c->base,ff->base);
	switch (ff->base) {
	case REF:
		if (ff->e1->base==G_ADDROF && ff->e1->e2==tmp)
			a = ff;				// &tmp -> f()
		break;
	case DOT:
		if (ff->e1->base==NAME && ff->e1==tmp) {
			a = ff;				// tmp . f()
			a->base = REF;
		}
		break;
	}
	a->e1 = n;
	return c;
}

Pname classdef::has_ictor()
/*
	does this class have a constructor taking no arguments?
*/
{
	Pname c = has_ctor();
	if (c == 0) return 0;
	
	Pfct f = Pfct(c->tp);

	switch (f->base) {
	default:
		error('i',"%s: badK (%k)",string,c->tp->base);
	
	case FCT:
		switch (f->nargs) {
		case 0:		return c;
		default:	if (f->argtype->n_initializer) return c;
		}
		return 0;

	case OVERLOAD:
	{	for (Plist l=Pgen(f)->fct_list; l; l=l->l) {
			Pname n = l->f;
			f = (Pfct)n->tp;
			switch (f->nargs) {
			case 0:		return n;
			default:	if (f->argtype->n_initializer) return n;
			}
		}
		return 0;
	}
	}
}

int add_first; // fudge, use ctor arg instead
Pname gen::add(Pname n)
/*
	add "n" to the tail of "fct_list"
	(overloaded names are searched in declaration order)

	detect:	 	multiple identical declarations
			declaration after use
			multiple definitions
*/
{
	Pfct f = Pfct(n->tp);
	Pname nx;
//error('d',"add(%n) %d",n,add_first);
	if (f->base != FCT) error("%n: overloaded nonF",n);

	if ( fct_list && (nx=find(f,1)) ) {
//error('d',"found %n %t",nx,nx->tp);
		Linkage l1 = Pfct(nx->tp)->f_linkage;
		Linkage l2 = f->f_linkage;
		if ( l2 != linkage_default && l1 != l2 )
			error("inconsistent linkage specifications for%n",n);
		Nold = 1;
	}
	else {
		if (add_first==0 && f->f_signature==0) f->sign();
//error('d',"signature: %d \"%s\" fct_list %d",f->f_signature,f->f_signature,fct_list);
		nx = new name;
		*nx = *n;
		// nx->n_tbl_list = Pname(n->string);
                nx->n_gen_fct_name = n->string;
		PERM(nx);
		Nold = 0;
		if (fct_list) {
			int clink = (f->f_linkage==linkage_C);
			Plist gl=fct_list;
			for(;;) {
				if (clink
				&& Pfct(gl->f->tp)->f_linkage == linkage_C ) {
					error("two%ns with c linkage",n);
					if(f->f_signature==0) f->sign();
				}
				if (gl->l)
					gl = gl->l;
				else
					break;
			}
			gl->l = new name_list(nx,0); 
		}
		else
			fct_list = new name_list(nx,0);
		nx->n_list = 0;
	}
	return nx;
}

void fct::sign()
{
	switch ( f_linkage ) {
	case linkage_C:
		f_signature = "";
		return;
	case linkage_Cplusplus:
	case linkage_default:
		break;
	}
	char buf[1024];
	char* bb = signature(buf);
	int ll = bb-buf;
	if (1023 < ll) error('i',"gen::add():N buffer overflow");
	char* p = new char[ll+1];
	strcpy(p,buf);
	f_signature = p;
//error('d',"fct::sign %s",p);
}

Pname gen::find(Pfct f, bit warn)
{	
	for (Plist gl=fct_list; gl; gl=gl->l) {
		Pname n = match(gl->f,f,warn);
		if (n) return n;
	}
	return 0;
}

Pname gen::match(Pname nx, Pfct f, bit warn)
{
	Pfct fx = Pfct(nx->tp);
	Pname a, ax;
	int op = 0;	// overloading problem: const, ref, vec/ptr, or basetype
//error('d',"fx %d %d f %d %d",fx->nargs_known,fx->nargs,f->nargs_known,f->nargs);

	if (f->nargs_known != fx->nargs_known) return 0; // the bets are off
							 // must rely on checks at
							 // call points
	if (f->f_const != fx->f_const) return 0;

	if (fx->nargs != f->nargs
	&& fx->nargs_known==1
	&& f->nargs_known==1) return 0;	// no warning for potential
					// problems due to default args
	
	for (ax=fx->argtype, a=f->argtype; a&&ax; ax=ax->n_list, a=a->n_list) {
		Ptype at = ax->tp;
		Ptype atp = a->tp;
//error('d',"at %t atp %t",at,atp);
		if (at->check(atp,OVERLOAD) == 0) {
//error('d',"at %t atp %t cp %d vrp %d",at,atp,const_problem,vrp_equiv);
			continue;
		}
//error('d',"warn %d",warn);
		if (warn == 0) goto xx;

		/*
			warn against:
				overload f(X&), f(X);		error
				overload f(int), f(const);	error
				overload f(int*), f(int[10]);	warn
			etc.
		*/

//error('d',"vrp_equiv %d const_problem %d",vrp_equiv,const_problem);
		if (const_problem) {	// differ only in X vs const X
			if (at->is_ptr_or_ref()) return 0;
			op++;
			continue;
		}

	aaa:
		switch (atp->base) {
		case TYPE:
			atp = Pbase(atp)->b_name->tp;
			goto aaa;
	//	case EOBJ:
	//		atp = Penum(Pbase(atp)->b_name->tp)->e_type;
	//		goto aaa;
		case RPTR:	// differ only by X vs X& ?
			if (Pptr(atp)->typ->check(at,0)==0) {
				op++;
				continue;
			}
		}

	atl:
		switch (at->base) {
		case TYPE:
			at = Pbase(at)->b_name->tp;
			goto atl;
	//	case EOBJ:
	//		at = Penum(Pbase(at)->b_name->tp)->e_type;
	//		goto atl;
		case RPTR:	// differ only by X& vs X ?
			if (Pptr(at)->typ->check(atp,0)==0) {
				op++;
				continue;
			}
			break;
	//	case CHAR:	// differ only by int vs char ?
	//	case SHORT:
	//	case INT:
		//	if (atp->base!=at->base && atp->base==EOBJ) {
		//		op++;
		//		continue;
		//	}
	//		break;
		}
//error('d',"return 0");
		//goto xx;
		// some argument is really different
		// e.g. f(int), f(char*);
		return 0;
	}

	// arguments checked. Now look at leftover args, return type,etc.

//	if (warn && a && fx->nargs_known==ELLIPSIS) error('w',"... in%n'sAT hidesATs from the overloading mechanism",nx);

	if (a || ax) return 0;

	if (op == 0) {
		if (warn && fx->returns->check(f->returns,0))
			error("two different return valueTs for%n: %t and %t",nx,fx->returns,f->returns);

		return nx;
	}
xx:
	if (warn && op)
		error("the overloading mechanism cannot tell a%t from a%t",fx,f);

	return 0;
}

int name::no_of_names()
{
	register int i = 0;
	register Pname n;
	for (n=this; n; n=n->n_list) i++;
	return i;
}

static Pexpr lvec[20], *lll, *curr_e;
static Pexpr last_il = 0;
static Pexpr list_back = 0;
static Pexpr last_el = 0, *last_lll;

void new_list(Pexpr lx)
{
	if (lx->base != ILIST) error('i',"IrLX");

	lll = last_lll = lvec;
	lll++;
	*lll = last_el = lx->e1;
}

Pexpr next_elem()
{
	Pexpr e;
	Pexpr lx;

	if (lll == lvec) return 0;

 	lx = *lll;

	if (list_back) {
		e = list_back;
		list_back = 0;
		return e;
	}

	if (lx == 0) {				/* end of list */
		lll--;
		return 0;
	}

	switch (lx->base) {
	case ELIST:
		e = lx->e1;
		curr_e = &lx->e1;
		last_el = lx;
		last_lll = lll;
		*lll = lx->e2;
		switch (e->base) {
		case ILIST:
			lll++;
			*lll = e->e1;
			last_il = e;
			return Pexpr(1);	// start of new ILIST
		case ELIST:
			error("nestedEL");
			return 0;
		default:
		{
			if (need_sti(e)) error('s',"generalIr inIrL");
			return e;
		}
		}
	case IVAL:
	case ZERO:
		lll--;
		return 0;
	default:
		error('i',"IrL %k",lx->base);
	}
}

static Pexpr insert_init(Pexpr newval) {
// splice an initializer in front of the next element in the
// initializer list.  Provides initializers for unnamed bitfields.
	Pexpr t = new expr(ELIST,last_el->e1,last_el->e2);

	last_el->e1=newval;
	last_el->e2=t;
	lll = last_lll;
	*lll = last_el;
	return next_elem();
}

void skip_ilist()
// skip ilist use to represent pointer to member function literal
{
	Pexpr e = next_elem();
	e = next_elem();
}

void list_check(Pname nn, Ptype t, Pexpr il, Ptable tbl)
/*
	see if the list "lll" can be assigned to something of type "t"
	"nn" is the name of the variable for which the assignment is taking place.
	"il" is the last list element returned by next_elem()
*/
{
	Pexpr e;
	bit lst = 0;
	int i;
	Pclass cl;
	int tdef = 0;

//error('d',"list_check%n: %t (%d)",nn,t,il);
	if (il == Pexpr(1)) {
		lst = 1;
		e = il;
	}
	else if (il)
		list_back = il;

zzz:
	switch (t->base) {
	case TYPE:
		t = Pbase(t)->b_name->tp;
		tdef = 1;

		// did it used to be a VEC before arg_fudge was applied?
                if (t->base==PTR && Pvec(t)->size)
                        t->base=VEC;
                goto zzz;

	case VEC:
	{	Pvec v = Pvec(t);
		Ptype vt = v->typ;

		if (v->size) {	/* get at most v->size initializers */
			if (v->typ->base == CHAR) {
				e = next_elem();
				if (e->base == STRING) {	// v[size] = "..."
					int isz = Pvec(e->tp)->size;
					if (v->size < isz) error("Ir too long (%d characters) for%n[%d]",isz,nn,v->size);
					break;
				}
				else
					list_back = e;
			}
			for (i=0; i<v->size; i++) { // check next list element type
				Pfct MP = 0;
			ee:
				e = next_elem();
				if (e == 0) goto xsw; // too few initializers are ok
			vtz:
//error('d',"vtz: %d",vt->base);
				switch (vt->base) {
				case TYPE:
					vt = Pbase(vt)->b_name->tp;
					goto vtz;
				case VEC:
				case COBJ:
					list_check(nn,vt,e);
					break;
				case PTR:
					if ((MP = vt->memptr()) &&
					    e==Pexpr(1)) {
						if (vt->check(last_il->tp,ASSIGN))
							error("badIrT for%n:%t (%tX)",v,last_il->tp,vt);
						skip_ilist();
						break;
					}
					if (MP && e && e->base==ZERO) {
						*curr_e = new expr(ELIST,zero,zero);
						*curr_e = new expr(ILIST,*curr_e,zero);
						(*curr_e)->tp = zero_type;
						break;
					}
					if (MP && e && e->tp->base==OVERLOAD) {
						Pexpr op = ptof(Pfct(Pptr(vt)->typ),e,tbl);
						if(op) {
							*curr_e = op;
							break;
						}
					}
					// no break
				default:
				{
					if (e == (Pexpr)1) {
						error("unexpectedIrL");
						goto ee;
					}

					if (vt->check(e->tp,ASSIGN))
						error("badIrT for%n:%t (%tX)",nn,e->tp,vt);

					Pptr p;
					if (vt->check(e->tp,0)
					&& (p=vt->is_ptr())
					&& Ptype(p)!=zero_type
  					&& p->typ!=char_type) {
  						Pexpr te = e;
  						Ptype t = p->typ;
  						while ( t->base == TYPE ) t = Pbase(t)->b_name->tp;
  						if ( t->base == COBJ )
  							te = ptr_init( p, e, tbl );
  						if ( te == e )
  							*curr_e = new cast(vt,e);
  						else *curr_e = te;
					}
				}
				}
			}
			if ( lst && (e=next_elem()) ) error("end ofIrLX after array");
		xsw:;
		}
		else {		/* determine v->size */
			i = 0;
			(void) v->typ->tsizeof();
		xx:
			while ( e=next_elem() ) {	// get another initializer
				Pfct MP = 0;
				i++;
			vtzz:
//error('d',"vtzz");
				switch (vt->base) {
				case TYPE:
					vt = Pbase(vt)->b_name->tp;
					goto vtzz;
				case VEC:
				case COBJ:
					list_check(nn,vt,e);
					break;
				case PTR:
					if((MP = vt->memptr()) &&
					    e==Pexpr(1)) {
						if (vt->check(last_il->tp,ASSIGN))
							error("badIrT for%n:%t (%tX)",v,last_il->tp,vt);
						skip_ilist();
						break;
					}
					if (MP && e && e->base==ZERO) {
						*curr_e = new expr(ELIST,zero,zero);
						*curr_e = new expr(ILIST,*curr_e,zero);
						(*curr_e)->tp = zero_type;
						break;
					}
					if (MP && e && e->tp->base==OVERLOAD) {
						Pexpr op = ptof(Pfct(Pptr(vt)->typ),e,tbl);
						if(op) {
							*curr_e = op;
							break;
						}
					}
					// no break
				default:
				{	if (e == Pexpr(1)) {
						error("unexpectedIrL");
						goto xx;
					}

					if (vt->check(e->tp,ASSIGN))
						error("badIrT for%n:%t (%tX)",nn,e->tp,vt);

					Pptr p;
					if (vt->check(e->tp,0)
					&& (p=vt->is_ptr())
					&& Ptype(p)!=zero_type
  					&& p->typ!=char_type) {
  						Pexpr te = e;
  						Ptype t = p->typ;
  						while ( t->base == TYPE ) t = Pbase(t)->b_name->tp;
  						if ( t->base == COBJ )
  							te = ptr_init( p, e, tbl );
  						if ( te == e )
  							*curr_e = new cast(vt,e);
  						else *curr_e = te;
					}
				}
				}
			}
			if (tdef==0) v->size = i;
		}
		break;
	}

	case CLASS:
		cl = Pclass(t);
		goto ccc;

	case COBJ:	/* initialize members */
		cl = Pclass(Pbase(t)->b_name->tp);
	ccc:
		if (cl->defined == 0) {
			lll = lvec;	// we are lost: ignore rest of list
			return;
		}

		if (cl->c_body == 1) cl->dcl_print(0);

	{	Ptable tbl = cl->memtbl;
		Pname m;

		if (cl->baselist) {
			if (cl->baselist->next) error("IrL forO ofC with multipleBCs");
			list_check(nn,cl->baselist->bclass,0);
		}

		for (m=tbl->get_mem(i=1); m; m=tbl->get_mem(++i)) {
			Ptype mt = m->tp;
			Pfct MP = 0;
			switch (mt->base) {
			case FCT:
			case OVERLOAD:
			case CLASS:
			case ENUM:
				continue;
			}
			if (m->n_stclass == STATIC ||
				m->n_stclass == ENUM ) continue;
			/* check assignment to next member */
		dd:
			while (mt->base == TYPE)
				mt = Pbase(mt)->b_name->tp;

			if ((MP = mt->memptr()) &&
			    e==Pexpr(1) &&
				last_il->tp->base == PTR) {
				if(i==1) lst=0;
			}
			else e = next_elem();

			if (e == 0) return; //break;

			if(
				mt->base == FIELD
					&&
				m->string[0]=='_'
					&&
				m->string[1]=='_'
					&&
				m->string[2]=='F'	// unnamed bitfield
			) {
				e = insert_init(zero);
			}

//error('d',"mtz%n: %d",m,mt->base);
			switch (mt->base) {
			case CLASS:
			case ENUM:
				break;
			case VEC:
			case COBJ:
				list_check(nn,m->tp,e);
				break;
			case PTR:
				if (MP && e==Pexpr(1)) {
					if (mt->check(last_il->tp,ASSIGN))
						error("badIrT for%n:%t (%tX)",m,last_il->tp,mt);
					skip_ilist();
					break;
				}
				if (MP && e && e->base==ZERO) {
					*curr_e = new expr(ELIST,zero,zero);
					*curr_e = new expr(ILIST,*curr_e,zero);
					(*curr_e)->tp = zero_type;
					break;
				}
				if (MP && e && e->tp->base==OVERLOAD) {
					Pexpr op = ptof(Pfct(Pptr(mt)->typ),e,tbl);
					if(op) {
						*curr_e = op;
						break;
					}
				}
				// no break
			default:
			{	if (e == Pexpr(1)) {
					error("unexpectedIrL");
					goto dd;
				}

				if (mt->check(e->tp,ASSIGN))
					error("badIrT for%n:%t (%tX)",m,e->tp,m->tp);

				if(MP && e && e->base==CAST)
					*curr_e = e->e1;

				Pptr p;
				if (mt->check(e->tp,0)
				&& (p=mt->is_ptr())
				&& Ptype(p)!=zero_type
				&& p->typ!=char_type)
					*curr_e = new cast(mt,e);
			}
			}
		}
		if (lst && (e=next_elem()) ) error("end ofIrLX afterCO");
		break;
	}
	default:
		e = next_elem();

		if (e == 0) {
			error("noIr forO");
			break;
		}
		
		if (e == Pexpr(1)) {
			error("unexpectedIrL");
			break;
		}
//error('d',"t %t e->tp %t",t,e->tp);
		if (t->check(e->tp,ASSIGN)) error("badIrT for%n:%t (%tX)",nn,e->tp,t);
		Pptr p;
		if (t->check(e->tp,0)
		&& (p=t->is_ptr())
		&& Ptype(p)!=zero_type
		&& p->typ!=char_type)
			*curr_e = new cast(t,e);
		if (lst && (e=next_elem()) ) error("end ofIrLX afterO");
		break;
	}
}

int
is_anon(char* string) {
// error('d',"is_anon: %s", string );
	if ( string == 0 )
		return 0;

	if ( string[0]=='_' && string[1]=='_' &&
		(string[2]=='C' || string[2]=='E')) 
			return 1;
	return 0;
}

Pname dclass(Pname n, Ptable tbl)
{	
	Pclass cl;
	Pbase bt;
	Pname bn;
	Pname ntbl = tbl->t_name;
	Ptype ntp = 0; 
	TOK tscope;

	Pname nx = ktbl->look(n->string,0);		// TNAME
	if (ntbl && ntbl->tp) ntp = ntbl->tp;

	tscope = ntp&&ntp->base==CLASS?NESTED:(n->lex_level?LOCAL:HIDDEN);

	DB( if(Ddebug>=1) error( 'd', &n->where, "dclass n %n %d nx %d", n,n->lex_level, nx); );
// error( 'd', &n->where, "dclass n %n ll %d nx %d tbl: %n", n,n->lex_level, nx, tbl->t_name); 
	if (nx == 0 || n->lex_level || 
		ntp && is_anon(n->string) == 0 && ntp->base == CLASS 
		&& (ktbl->look(n->string,tscope))) 
	{
		if ( nx && ntp && ntp->base == CLASS ) { 
			bt = (Pbase)nx->tp;
			bn = bt->b_name;
			cl = bn ? (Pclass)bn->tp : 0;
			if (cl && cl->lcl && 
				strcmp(cl->lcl,"FUDGE007")==0)
					goto bbb;
			else { bt=0; bn=0; cl=0; }
		}

		int tn = 0;
		for (nx=ktbl->look(n->string,tscope); nx; nx=nx->n_tbl_list) 
		{
			if (nx->n_key != tscope) continue;
			if (tscope==LOCAL && 
				nx->lex_level != n->lex_level ) continue;

			if (nx->tp->base != COBJ) {
				tn = 1;
				continue;
			}

			bt = (Pbase)nx->tp;
			bn = bt->b_name;
			cl = (Pclass)bn->tp;

			if (cl == 0) continue;

			// is this class nested within class table?
			if (tscope==NESTED && 
				strcmp(ntbl->string,cl->in_class->string))
					continue;
			else
			if ( tscope==LOCAL && 
   				(cl->lcl==0 || strcmp(cl->lcl,Pclass(n->tp)->lcl))) 
					continue;

			goto bbb;
		}

		if (tn)
			error("%n redefined using Tdef",n);
		else
			error('i',"%n is not aCN",n);
	}
	else {
		bt = Pbase(nx->tp);			// COBJ
                if ( bt->base != COBJ ) {
                        error("%n redefined using typedef",n);
                        Pname tn = ktbl->look(n->string,HIDDEN); 
                        if ( tn->tp->base == COBJ )  
                                bt = Pbase(tn->tp);
                        else error('i',"%n is not a CN", n );
                }
		bn = bt->b_name;
	}
bbb:
	bn->where = nx->where;
	Pname bnn = tbl->insert(bn,CLASS);		// copy for member lookup
	cl = Pclass(bn->tp);

	if (cl->class_base == template_class)
		error("C%n defined previously asYC", bn);
							
	if (cl->defined&(DEFINED|SIMPLIFIED))
		error("C%n defined twice",n);
	else {
		if (bn->n_scope == ARG) bn->n_scope = ARGT;
		cl->dcl(bn,tbl);
	}
	n->tp = cl;
	return bnn;
}

Pname denum(Pname n, Ptable tbl)
{
	Penum en;
	Pbase bt;
	Pname bn;
	Pname ntbl = tbl->t_name;
	Ptype ntp = 0; 
	TOK tscope;

	Pname nx = ktbl->look(n->string,0);		// TNAME
	if (ntbl && ntbl->tp) ntp = ntbl->tp;

// note: ***** add for local enumeration declaration
// error( 'd', &n->where, "denum n %n ll %d nx %d tbl: %n", n,n->lex_level, nx, tbl->t_name); 
	if (nx == 0 || /* n->lex_level ||*/ 
		ntp && is_anon(n->string)==0 && ntp->base == CLASS ) 
	{
		int tn = 0;
		tscope = ntp&&ntp->base==CLASS?NESTED:(/*n->lex_level?LOCAL:*/HIDDEN);
		for (nx=ktbl->look(n->string,tscope); nx; nx=nx->n_tbl_list) 
		{
			if (nx->n_key != tscope) continue;
//			if (tscope==LOCAL && 
//				nx->lex_level != n->lex_level ) continue;

			bt = (Pbase)nx->tp;
			bn = bt->b_name;
			en = (Penum)bn->tp;

			// is this class nested within class table?
			if (tscope==NESTED && en->in_class &&
				strcmp(ntbl->string,en->in_class->string))
					continue;
		}
	}
	else {
			bt = (Pbase)nx->tp;
			bn = bt->b_name;
			en = (Penum)bn->tp;
	}

	Pname bnn = tbl->insert(bn,CLASS);
	if (en->defined&(DEFINED|SIMPLIFIED))
		error("enum%n defined twice",n);
	else {
		if (bn->n_scope == ARG) bn->n_scope = ARGT;
		en->dcl(bn,tbl);
	}
	n->tp = en;
	return bnn;
}

static int
is_probably_temp( char *str ) 
{
// error( 'd', "is_probably_temp( %s )", str );

	if ( str[0] != '_' || str[1] != '_' )
		return 0;

	switch (str[2]) {
		default:
			return 0;
		case 'A': case 'C': case 'D': case 'E': case 'F': 
		case 'I': case 'K': case 'L': case 'M': case 'N': 
		case 'Q': case 'R': case 'S': case 'T': case 'U': 
		case 'V': case 'W': case 'X':
			return 1;
	}

}

static void
check_for_local( Pexpr ee )
{
	static Pname n[2] = {0,0}; // try not to flag multiple errors 
	static index = 0;

	if ( ee==0 ) return; 

// error('d', "check_for_local( %k ) e1: %d e2: %d", ee->base, ee->e1, ee->e2);

	switch ( ee->base ) {
		case NAME:  
		{
			Pname nn = Pname(ee);
			if ((nn->n_scope==FCT || nn->n_scope==ARG) 
			    && is_probably_temp(nn->string) == 0  
			    && n[0]!=nn && n[1]!=nn) 
			{
				error("local%n used as defaultA", nn );
				n[index] = nn;
				index = index==0?1:0;
			}	
			// no break;
		}
		case TNAME: case STRING: case IVAL:
		case ICON: case CCON: case FCON:
		case ZERO: case DUMMY: case SIZEOF:
			return;
		case QUEST:
			check_for_local( ee->cond );
			break;
		case MDOT:
			check_for_local( ee->mem );
			return;
	}

	check_for_local( ee->e1 );
	check_for_local( ee->e2 );
}

void dargs(Pname, Pfct f, Ptable tbl)
{
	int argnamesize = 0; // if +a1, make sure arg names can be printed
	int oo = const_save;
	const_save = 1;
	if ( ansi_opt ) {
	    Pname th = f->f_this;
	    if ( th && th->string ) argnamesize += strlen(th->string) + 1;
	    th = f->f_result;
	    if ( th && th->string ) argnamesize += strlen(th->string) + 1;
	}

	for (Pname a=f->argtype; a; a=a->n_list) {
		Pexpr init;

		if (a->tp == 0) {
			error( "A has noT" );
			a->tp = any_type;
			continue;
		}
		if (ansi_opt && a->string) argnamesize += strlen(a->string) + 1;

		Pname cln = a->tp->is_cl_obj();
//error('d',"dargs %t",a->tp);
		if (cln && Pclass(cln->tp)->has_itor())	// mark X(X&) arguments
			a->n_xref = 1;
		else {
			Ptype t = a->tp;
			while (t->base == TYPE) t = Pbase(t)->b_name->tp;
			if (t->base == FCT) a->tp = new ptr(PTR,a->tp);
		}

//       	if (init = a->n_initializer) {	// default argument
                if ( a->n_key != NESTED &&
                    (init = a->n_initializer)) { // default argument
			Pptr pt;
			if (init == dummy) {
				error("emptyIr");
				a->n_initializer = 0;
				continue;
			}
			if (cln) {
				if (init->base==VALUE) {
					switch (init->tp2->base) {
					case CLASS:
						if (Pclass(init->tp2)!=Pclass(cln->tp)) goto inin2;
						break;
					default:
						Pname n2 = init->tp2->is_cl_obj();
						if (n2==0 || Pclass(n2->tp)!=Pclass(cln->tp)) goto inin2;
					}

					a->n_initializer = init = 0;
					error('s',"K as defaultA");
				}
				else {
				inin2:
					if (init->base == ILIST) error("list as AIr");
					Pexpr i = init->typ(tbl);
					init = class_init(a,a->tp,i,tbl);
					if (i!=init && init->base==DEREF) {
						error('s',"K needed forAIr");
						init = 0;
					}
					else {
						dosimpl(init,cc->nof);
					//	init->simpl();
						init->permanent = 2;
					}
					a->n_initializer = init;
				}
			}
			else if (pt = a->tp->is_ref()) {
				ref_initializer++;
				init = init->typ(tbl);
				ref_initializer--;
				int tcount = stcount;
				init = ref_init(pt,init,tbl);
				if (tcount != stcount) {
					error('s',"needs temporaryV to evaluateAIr");
					init = 0;
				}
				else {
					dosimpl(init,cc->nof);
				//	init->simpl();
					init->permanent = 2;
				}
				a->n_initializer = init;
			}
			else {
				Pptr p = a->tp->is_ptr();
				init = init->typ(tbl);
				if (p) init = ptr_init(p,init,tbl);

				if (a->tp->check(init->tp,ARG)) {
					int i = can_coerce(a->tp,init->tp);

					switch (i) {
					case 1:
						if (Ncoerce) {
							Pname cn = init->tp->is_cl_obj();
							Pname xx = new name(Ncoerce->string);
							Pref r = new ref(DOT,init,xx);
							init = new expr(G_CALL,r,0);
							init = init->typ(tbl);
						}
						break;
					default:
						error("%d possible conversions for defaultA",i);
					case 0:
						error("badIrT%t forA%n (%tX)",init->tp,a,a->tp);
						DEL(init);
						a->n_initializer = init = 0;
					}
				}
				
				if (init) {
					dosimpl(init,cc->nof);
				//	init->simpl();
					init->permanent = 2;
					a->n_initializer = init;
					Neval = 0;
					long i = init->eval();
					if (Neval == 0) {
						a->n_evaluated = 1;
						a->n_val = i;
					}
				}
			}
			if ( a->n_initializer ) 
				check_for_local(a->n_initializer);
		}
	}
	if ( ansi_opt && argnamesize ) {
		char* ps = new char[ argnamesize ];
		Pname a = f->f_this;
		if ( a && a->string ) {
			int i = strlen(a->string) + 1;
			if ( (argnamesize -= i) < 0 ) goto bad;
			strcpy(ps,a->string);
			a->string = ps;
			ps += i;
		}
		a = f->f_result;
		if ( a && a->string ) {
			int i = strlen(a->string) + 1;
			if ( (argnamesize -= i) < 0 ) goto bad;
			strcpy(ps,a->string);
			a->string = ps;
			ps += i;
		}
		for ( a = f->argtype;  a;  a = a->n_list ) {
			if ( a->string == 0 ) continue;
			int i = strlen(a->string) + 1;
			if ( (argnamesize -= i) < 0 ) goto bad;
			strcpy(ps,a->string);
			a->string = ps;
			ps += i;
		}
		if ( argnamesize ) bad:error('i',"bad argN size for%t",f);
	}
	const_save = oo;
}

void merge_init(Pname nn, Pfct f, Pfct nf)
{
//	Pname a1 = f->f_args; if (a1==0) a1 = f->argtype;
//	Pname a2 = nf->f_args;//nf->argtype; 
	Pname a1 = f->argtype;
	Pname a2 = nf->argtype; 

	for (; a1; a1=a1->n_list, a2=a2->n_list) {
		int i1 = a1->n_initializer || a1->n_evaluated;
		int i2 = a2->n_initializer || a2->n_evaluated;

		if (i1 && i2) error(&a1->where,"twoIrs for%nA%n",nn,a1);

		if (i1) {
			a2->n_initializer = a1->n_initializer;
			a2->n_evaluated = a1->n_evaluated;
			a2->n_val = a1->n_val;
		}
		if (i2) {
			a1->n_initializer = a2->n_initializer;
			a1->n_evaluated = a2->n_evaluated;
			a1->n_val = a2->n_val;
		}

	}
}

Pexpr try_to_coerce(Ptype rt, Pexpr e, char* s, Ptable tbl)
/*
	``e'' is of class ``cn'' coerce it to type ``rt''
*/
{
	int i;
	Pname cn;
//error('d',"try_to_coerce(%t, %t, %s, %d)",rt,e->tp,s,tbl);

	if ((cn=e->tp->is_cl_obj()) && (i=can_coerce(rt,e->tp)) && Ncoerce) {
		if (1 < i) error("%d possible conversions for %s",i,s);
//error('d',"coerce %n",Ncoerce);
		Pclass cl = Pclass(cn->tp);
	//	Pref r = new ref(DOT,e,Ncoerce);
	//	Pexpr rr = r->typ(tbl);
	//	Pexpr c = new expr(G_CALL,rr,0);
	//	c->fct_name = Ncoerce;
		Pname xx = new name(Ncoerce->string);
		Pref r = new ref(DOT,e,xx);
		Pexpr c = new expr(G_CALL,r,0);
	//	return c->typ(tbl);
		c = c->typ(tbl);
//error('d',"coerce -> %k %t",c->base,c->tp);
		return c;
	}
//error('d',"coerce ->0");
	return 0;
}

int in_class_dcl;

Pname name::dofct(Ptable tbl, TOK scope)
{	
	Pfct f = Pfct(tp);
	Pname class_name;
	Ptable etbl;
	in_class_dcl = cc->not!=0;
	int just_made = 0;
//	int fvirt = 0;  //BSopt
	DB( if(Ddebug>=1) error('d',"dofct %n %d %t %s",this,tp,tp,tbl==gtbl?"global":""); );
// error( 'd', "%n->dofct(): n_initializer: %d f->f_virtual: %d", this, n_initializer, f->f_virtual);

	if (f->f_inline) n_sto = STATIC;

	if (n_stclass)
		switch (n_stclass) {
		case EXTERN:
		case STATIC:
		case OVERLOAD:
			break;
		default:
			error("%n declared%k",this,n_stclass);
			n_stclass = EXTERN;
		}

	tp->dcl(tbl);		// must be done before the type check

	if (n_qualifier) {	// qualified name: c::f() checked above
		class_name = Pbase(n_qualifier->tp)->b_name;
		etbl = Pclass(class_name->tp)->memtbl;

          	if (f->f_virtual) {
                         error("virtual specifier illegal outsideCD(%n::%s())",class_name,this->string);
			 f->f_virtual = 0;
		}


		if (n_sto
		&& n_sto!=FRIEND	// friend X::f();
		&& f->f_inline==0) {	// inline causes n_sto==STATIC
			error("%k specified for QdN%n",n_sto,this);
			n_sto = 0;
		}
	}
	else {
		class_name = cc->not;

		// beware of local function declarations in member functions
		if (class_name && tbl!=cc->cot->memtbl) {
			class_name = 0;
			in_class_dcl = 0;
		}

		if (f->f_static && f->f_virtual) {
 			 error("virtual staticM");
			 f->f_virtual = 0;
		}

		if (n_oper) check_oper(class_name);
		etbl = tbl;
	}

//	Pfct(tp)->memof = class_name ? Pclass(class_name->tp) : 0;

	if (class_name) {
		Pclass cl;
		f->memof = cl = Pclass(class_name->tp);
		if (f->f_virtual==0 && find_virtual(f->memof,this))
			f->f_virtual = VTOK;
//error('d',"class_name: %s fct: %s virtual: %d", class_name->string, string, f->f_virtual );

		if (f->f_static && f->f_virtual) {
 			 error("virtual staticM");
			 f->f_virtual = 0;
		}

		if ( cl->csu == UNION && f->f_virtual ) // don't worry about ANON
			error( "%n: cannot declare a virtualFWin union", this ); 
        }

	if(f->f_const && f->memof==0) {
		error("onlyMFs can be constant");
	}

	if (etbl==0 || etbl->base!=TABLE) error('i',"N::dcl: etbl=%d",etbl);

	switch (n_oper) {
	case CTOR:
		if (f->f_virtual) {
			error("virtualK");
			f->f_virtual = 0;
		}

//	case DTOR:
//		f->f_const = 1;
		break;

	case REF:
		if (f->argtype) 
			error("%n takes no argument",this);
		else if (f->returns->is_ptr() == 0) {
			Pname cn = f->returns->is_cl_obj();
			if (cn==0 && f->returns->base==RPTR) cn = Pptr(f->returns)->typ->is_cl_obj();
			if (cn==0 || Pclass(cn->tp)->has_oper(REF)==0) {
				if ( cn && class_name &&  // B B::operator->();
     					strcmp(cn->string, class_name->string)==0 )
						error("%s::%n cannot return aR orCO ofC%n",cn->string,this,cn);
				else error("%n must return aP toCO, aR toCO, or aCO",this);
				tp = any_type; // suppress further checking
			}
		}
		break;

	case NEW:	// void* operator new(long)
		if (f->f_virtual)
			error("virtual%n (operator new() is static)",this);
		if (class_name) f->f_static = 1;	// if member: static by default
		if (f->nargs_known != 1)
                       error("ATs must be fully specified for%n",this);
		else if (f->nargs<1)
			error("%n requires a firstA ofT size_t",this);
		else if (f->argtype->tp->check(size_t_type,0)) {
				if (strict_opt==0
				&& ( f->argtype->tp->check(long_type,0)==0 ||
				     f->argtype->tp->check(ulong_type,0)==0)) {
					error('w',"%n firstA should be size_t (anachronism)",this);
					f->argtype->tp = size_t_type;
					if (f->f_signature) f->sign();
				}
				else
					error("%n requires a firstA ofT size_t",this);
		}
		else {
			Ptype t = f->s_returns  ? f->s_returns : f->returns;
			if (t->check(Pvoid_type,0)) error("bad returnT for %n",this);
		}
		break;

		case DELETE:	// void operator delete(void*) or
				// void operator delete(void*, long)
			if (f->f_virtual)
				error("virtual%n (operator delete() is static)",this);
			if (class_name) f->f_static = 1;	// if member: static by default
			if (f->nargs_known != 1)
                       		error("ATs must be fully specified for%n",this);
			else {
				Ptype t = f->s_returns ? f->s_returns : f->returns;
				if (t->base != VOID)
					error("bad returnT for %n", this);
				else {
					switch (f->nargs) {
					default:
						error("%n takes 1 or 2As",this);
						break;
					case 1:
					case 2:
					{	Pname a = f->argtype;
						if (a->tp->check(Pvoid_type,0))
                               				error("%n's 1stA must be a void*",this);
						else if (a = a->n_list) {
							if (class_name == 0)
								error("%n takes only oneA",this);
							else if (a->tp->check(size_t_type,0)) {
								if (strict_opt==0
								&& a->tp->check(long_type,0)==0) {
									error('w',"%n's 2ndA should be a size_t (anachronism)",this);
									a->tp = size_t_type;
									if (f->f_signature) f->sign();
								}
								else
									error("%n's 2ndA must be a size_t",this);
							}
						}
					}
					}
				}
               		}
               break;

	case ASSIGN:
		if (class_name && f->nargs==1) {
			Ptype t = f->argtype->tp;
			Pname an = t->is_cl_obj();  // X::operator=(X) ?
			if (an==0 && (t=t->is_ref())) { // X::operator=(X&) ?
				t = Pptr(t)->typ;
			rx1:
				switch (t->base) {
				case TYPE:	t = Pbase(t)->b_name->tp; goto rx1;
				case COBJ:	an = Pbase(t)->b_name;
				}
			}
			if (an && an==class_name) Pclass(an->tp)->c_xref |= C_ASS;
		}
		else if (f->nargs == 2) {
			Ptype t = f->argtype->tp;
			Pname an1;
			if (t=t->is_ref()) { // operator=(X&,?) ?
				t = Pptr(t)->typ;
			rx2:
				switch (t->base) {
				case TYPE:	t = Pbase(t)->b_name->tp; goto rx2;
				case COBJ:	an1 = Pbase(t)->b_name;
				}
			}
			t = f->argtype->n_list->tp;
			Pname an2 = t->is_cl_obj(); // operator=(X&,X) ?
			if (an2==0 && (t=t->is_ref())) { // operator=(X&,X&) ?
				t = Pptr(t)->typ;
			rx3:
				switch (t->base) {
				case TYPE:	t = Pbase(t)->b_name->tp; goto rx3;
				case COBJ:	an2 = Pbase(t)->b_name;
				}
			}
			if (an1 && an1==an2) Pclass(an1->tp)->c_xref |= C_ASS;
		}
	}

	switch (scope) {
	case FCT:
	case ARG:
		if (n_sto == STATIC) error("D of staticF in aF");
		else { // detect local re-definition
			Pname nx = gtbl->look(string,0);
			if (nx) {
				switch (nx->tp->base) {
				case FCT:
					if (tp->check(nx->tp,0))
						error('w',"%n has been locally re-declared as%t",this,tp);
					else {
						if(Pfct(nx->tp)->f_signature==0)
							Pfct(nx->tp)->sign();
						if (Pfct(tp)->f_signature == 0)
							Pfct(tp)->sign();
						if ( strcmp(Pfct(nx->tp)->f_signature,Pfct(tp)->f_signature))
							error('w',"%n of type %t has been locally re-declared with different linkage",this,tp);
					}
					break;
				case OVERLOAD:
				{	Pname ny = Pgen(nx->tp)->find(f,0);
					if (ny == 0)
						error('w',"overloadedF%n has been locally declared as%t",this,tp);
					else {
						if(Pfct(ny->tp)->f_signature==0)
							Pfct(ny->tp)->sign();
						if (Pfct(tp)->f_signature == 0)
							Pfct(tp)->sign();
						if (strcmp(Pfct(ny->tp)->f_signature,Pfct(tp)->f_signature))
							error('w',"overloadedF%n of type %t has been locally re-declared with different linkage",this,tp);
					}
				}
					break;
				} // switch nx->base
			} // if nx
		} // else
	} // switch scope

	Pname nn = etbl->insert(this,0);
	if ( f->body ) nn->where = where;
	nn->assign();
	n_table = etbl;
//error('d',"%n->dofct(): n_initializer:%d f->f_virtual:%d",this,n_initializer,f->f_virtual);
	if (n_initializer) {
		if (f->f_virtual == 0) error("Ir for non-virtualF%n",this);
		if (n_initializer != zero) error("virtualFIr must be 0");
	}
			
	if (Nold) {
		Pfct nf = Pfct(nn->tp);
// error('d',"old %n: %t and %t",nn,nf,tp);
		int flag = 0;
		Pname af=0,anf=0;
		if (nf->base==ANY || f->base==ANY)
			; // wild card -- do nothing
		else 
		if (nf->base == OVERLOAD) {
			string = nn->string;
			nn = Pgen(nf)->add(this);

			if (Nold == 0) {
				if (f->body && n_qualifier) {
					error("badAL for%n",this);
					return 0;
				}
				goto thth;
			}
		//	else {
		//		if (f->body==0 && friend_in_class==0) error('w',"%n redeclared",nn);
		//	}
			nf = Pfct(nn->tp);
			if (f->body && nf->body) {
                         	// Preserve the original definition 
				// in the case of a PT class; i.e, 
				// the one supplied by the user
                          	if (!(class_name &&
                                	(Pclass(class_name->tp)->class_base ==
                                 		instantiated_template_class) && 
					nn->n_redefined))
                       		{
					error("two definitions of%n",nn);
					f->body = 0;
				}
				return 0;
			}
			if (f->body) goto bdbd;
			goto stst;
		}
		else if (nf->base != FCT) {
			error("%n declared both as%t and asF",this,nf);
			f->body = 0;
		}
		else  {
// error('d',"%t->check(%t) -> %d %d",nf,f,nf->check(f,OVERLOAD));
			if (nf->check(f,OVERLOAD) || const_problem) {
				if (f->body && n_qualifier) {
					error("%nT mismatch: %t and %t",nn,nf,f);
					return 0;
				}
				Pgen g = new gen;
				add_first = 1;
				Pname n1 = g->add(nn);
				add_first = 0;
				string = nn->string;
				Pname n2 = g->add(this);
				nn->tp = g;
				nn = n2;
				goto thth;
			}

                        af = f->argtype;
                        anf = nf->argtype;
			for (; af && anf; af=af->n_list,anf=anf->n_list) {
				Ptype at = af->tp;
				Ptype atp = anf->tp;
				if(!exact1(af,atp)) break;
				if(at->base!=PTR || 
				   Pptr(at)->rdo == Pptr(atp)->rdo) continue;
				int k = Pptr(at)->typ->tconst();
				int l = Pptr(atp)->typ->tconst();
				if(k==l) flag=1;
			}
			if ( flag && !af && !anf) {
				error("the overloading mechanism cannot tell a%t from a%t",nf,f);
			}
				
			if (in_class_dcl) {
			//	error("twoDs of%n",this);
			//	f->body = 0;
			//	return 0;
			}
			else if (nf->f_static && f->f_inline==0 && n_sto==STATIC) {
				//error('d',"MF%n declared static outsideF",this);
				n_sto = 0;
			}
			else if (n_sto && n_sto!=nn->n_scope) {
				if (n_sto==EXTERN && nn->n_scope==STATIC)
					error('w',"%n declared extern after being declared static",this);
				else if (nf->f_inline==0 && f->f_inline==0) {
					if (nn->tp==new_fct->tp || nn->tp==del_fct->tp)
						nn->n_sto = n_sto;
					else
						error("%n declared as both%k and%k",this,n_sto,(nn->n_sto)?nn->n_sto:EXTERN);
				}
			}

//error('d',"fct %n: %k %k scope %k",this,n_sto,nn->n_sto,nn->n_scope);	
//error('d',"link %d lcount %d sig %s",linkage,lcount,nf->f_signature);

			{ 
				Linkage l1 = nf->f_linkage;
				Linkage l2 = f->f_linkage;
			  	if ( l2!=linkage_default && l1!=l2)
					error("inconsistent linkage specifications for%n",this);
			}
			if (nf->body && f->body) {
                         	// Preserve the original definition 
				// in the case of a PT class; i.e, 
				// the one supplied by the user
                          	if (!(class_name &&
                                	(Pclass(class_name->tp)->class_base ==
                                 		instantiated_template_class) && 
					nn->n_redefined))
                       		{
				error("two definitions of%n",this);
				f->body = 0;
				}
				return 0;
			}
				
			if (f->body) goto bdbd;

			goto stst;
	
		bdbd: 
// error('d',"nn %n init: %d f_virt: %d f->body: %d", nn,nn->n_initializer,nf->f_virtual,f->body);
			if (f->nargs_known && nf->nargs_known) merge_init(nn,f,nf);
			f->f_virtual = nf->f_virtual;
			f->f_this = nf->f_this;
			f->f_result = nf->f_result;
			f->s_returns = nf->s_returns;
			f->f_args = nf->f_args;
		//	f->argtype = nf->argtype;
			f->f_signature = nf->f_signature;
			f->f_const = nf->f_const;
			f->f_static = nf->f_static;
			nn->tp = f;
			if (f->f_inline) {
				if (nf->f_inline==0) {
                                          if (nn->n_used && nn->n_sto!=STATIC)
						error("%n declared with external linkage and called before defined as inline",nn);
				//	else if (nf->memof)
				//		error('w',"%n declared as non-inline but defined as inline",nn);
					else if (nn->n_used) {
						nn->take_addr(); // force printout
						if (warning_opt) error('w',"%n called before defined as inline",nn);
				}
				}
				nf->f_inline = 1;
				nn->n_sto = STATIC;
			}
			else if (nf->f_inline) {
		//		error('w',"%n defined as inline but not declared as inline",this);
				f->f_inline = 1;
			}
			goto stst2;

		stst:
//error('d',"stst");
			if (f->nargs_known && nf->nargs_known) merge_init(nn,f,nf);
			f->f_args = nf->f_args;
		//	f->argtype = nf->argtype;
		stst2:
//error('d',"stst2 %n printed %d",nn,nn->n_dcl_printed);
			if (f->f_inline) n_sto = STATIC;

/* superceded above (line 1978 and following)
			if (n_sto
			&& nn->n_scope!=n_sto
			&& friend_in_class==0
			&& f->f_inline==0){ // allow re-def to "static"
				if (n_sto == STATIC)
					nn->n_sto = STATIC;
				else {
					error("%n both%k and%k",this,n_sto,nn->n_scope);
				}
			}
*/

//// addition for 2.1

 			if(n_sto == STATIC && nn->n_sto == EXTERN &&
 			    (!strcmp(string,"__nw") || !strcmp(string,"__dl")))
 				nn->n_sto = STATIC;

//// end of addition

			n_scope = nn->n_scope; // first specifier wins
			n_sto = nn->n_sto;
		}
	}
	else {	// new function: make f_this for member functions
	thth:
		just_made = 1;
		if (f->f_inline)
			nn->n_sto = STATIC;
		else if (class_name==0 && n_sto==0 && f->body==0)
			nn->n_sto = EXTERN;
//error('d',"thth %n %t static %d sto %k",nn,f,f->f_static,nn->n_sto);
		if (f->f_static)
			switch (n_oper) {	// what about + ??
			case CTOR:
			case DTOR:
			case TYPE:
			case CALL:
			case DEREF:
			case REF:
			case ASSIGN:
				error("%n cannot be a staticMF",nn);
				f->f_static = 0;
			}

		if (class_name
		&& f->f_static==0	// no ``this'' in static members
		&& n_oper!=NEW	 	// X::operator new() static by default
		&& n_oper!=DELETE	// X::operator delete() static by default
		&& etbl!=gtbl) {	// beware of implicit declaration 
			Pname cn = nn->n_table->t_name;
			Pname tt = new name("this");
			tt->n_scope = ARG;
			tt->where = no_where;
		//	tt->n_sto = ARG;
			tt->tp = Pclass(class_name->tp)->this_type;
			PERM(tt);
			Pfct(nn->tp)->f_this = f->f_this = Pfct(nn->tp)->f_args = f->f_args = tt;
			tt->n_list = f->argtype;
//error('d',"nn %n tp %t const %d",nn,nn->tp,f->f_const);
			if (f->f_const /*&& n_oper!=CTOR && n_oper!=DTOR*/) {
				Pbase x = Pbase(Pptr(tt->tp)->typ);
				Pbase y = new basetype(COBJ,0);
				*y = *x;
				y->b_const = 1;
				tt->tp = new ptr(PTR,y);
				Pptr(tt->tp)->rdo = 1;
				PERM(tt->tp);
			}
		}
		else {
			Pfct(nn->tp)->f_args = f->f_args = f->f_result?f->f_result:f->argtype;
			Pfct(nn->tp)->f_signature = f->f_signature;
			Pfct(nn->tp)->f_const = f->f_const;
			Pfct(nn->tp)->f_static = f->f_static;
		}

		// if C++ linkage encode type in function name
		if (Pfct(nn->tp)->f_signature==0) Pfct(nn->tp)->sign();

		if (f->f_result == 0) {
//error('d',"re1 %n %t %d",this,f,f);
			make_res(f);
		}
		else if (f->f_this)
			f->f_this->n_list = f->f_result;

		if (nn->n_oper==CTOR || nn->n_oper==DTOR) vbase_pointers(nn,Pclass(class_name->tp));

		if (f->f_virtual) {
			switch (nn->n_scope) {
			default:
				error("nonC virtual%n",this);
				break;
			case 0:
			case PUBLIC:
				//      if (fvirt)      //BSopt
				cc->cot->virt_count = 1;
				Pfct(nn->tp)->f_virtual = f->f_virtual;
				break;
			}
		}
	}

		/*	an operator must take at least one class object or
			reference to class object argument
		*/

	if (just_made)
	switch (n_oper) {
	case CTOR:
		switch (f->nargs) {	// check for X(X) and X(X&)
		case 0:
			break;
		default:		// handle X(X&, int i = 0)
		{	Pname n2 = f->argtype->n_list;
			if (n2->n_initializer==0 && n2->n_evaluated==0) break;
		}
		case 1:
		{
			Ptype t = f->argtype->tp;
		clll:
			switch (t->base) {
			case TYPE:
				t = Pbase(t)->b_name->tp;
				goto clll;
			case RPTR:			/* X(X&) ? */
				t = Pptr(t)->typ;
			cxll:
				switch (t->base) {
				case TYPE:
					t = Pbase(t)->b_name->tp;
					goto cxll;
				case COBJ:
					if (class_name == Pbase(t)->b_name)
						Pclass(class_name->tp)->c_itor = nn;
				}
				break;
			case COBJ:			/* X(X) ? */
				if (class_name == Pbase(t)->b_name) {
					error("badK %s(%s) use %s(%s&)",class_name->string,class_name->string,class_name->string,class_name->string);
					f->argtype->tp = any_type;
				}
			}
		}
		}
		if (Pclass(class_name->tp)->c_ctor == 0) Pclass(class_name->tp)->c_ctor = nn;
		break;

	case TYPE:
		// somewhat simple minded solution to the inheritance of
		// conversion operator problem
		nn->n_list = Pclass(class_name->tp)->conv;
		Pclass(class_name->tp)->conv = nn;
		break;

	case DTOR:
		Pclass(class_name->tp)->c_dtor = nn;
		break;

	case NEW:	
	case DELETE:
	case CALL:
	case 0:
		break;

	default:
		for (Pname a=f->argtype; a; a=a->n_list) {
			if ( a->n_initializer )
     				error( "%n: operatorFs cannot take defaultA", this );
		}

		if (f->nargs_known != 1) {
			error("ATs must be fully specified for%n",nn);
		}
		// this doesn't catch unary operator off by one errors
		// for simplicity, placed that check in check_oper(), above
		else if (class_name == 0) {
			switch (f->nargs) {
			case 1:
			case 2:
				for (a=f->argtype; a; a=a->n_list) {
					Ptype tx = a->tp;
					while (tx->base == TYPE) tx = Pbase(tx)->b_name->tp;
					if (tx->is_ref()) tx = Pptr(tx)->typ;
					if (tx->is_cl_obj()) goto cok;
				}
				error("%n must take at least oneCTA",nn);
				break;
			default:
				error("%n must take 1 or 2As",nn);
			}
		}
		else {
			switch (f->nargs) {
			case 0:
			case 1:
				break;
			default:
				error("%n must take 0 or 1As",nn);
			}
		}
	cok:;
	}

	int i = 0;	// check that every argument after an argument with
			// initializer have an initializer
	for (Pname a = f->f_args/*f->argtype*/; a; a=a->n_list) {
		if (a->n_initializer)
			i = 1;
		else if (i)
			error("trailingA%n withoutIr",a);
	}

	/*
		the body cannot be checked until the name
		has been checked and entered into its table
	*/
	if (f->body) f->dcl(nn);
	return nn;
}

0707071010112043711004440001630000160000010174600466055376600000700000154273dcl4.c/*ident	"@(#)ctrans:src/dcl4.c	1.4" */
/**************************************************************************

	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.

dcl4.c:
	Declaration of class and enum

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

#include "cfront.h"
#include "size.h"
#include "template.h"

Pname find_vptr(Pclass);
void fix_args(Pfct f, Pclass cl)
/*
	This function is used to cope with the case where cl::cl(cl&) is
	declared AFTER f has been declared
	set n_xref bit for f
*/
{
	for (Pname a = f->argtype; a; a = a->n_list) {
		Pname n = a->tp->is_cl_obj();
		if (n && Pclass(n->tp)==cl) a->n_xref = 1;
	}
}

Pname merge_conv(Pname c1, Pname c2)
{
	if (c1 == 0) return c2;
	if (c2 == 0) return c1;
	if (c1 == c2) return c1;
	error('s',"cannot merge lists of conversion functions");
	return c1;
}

static Eppp;

char* get_classname(char* s)
/*
	retrieve the outermost class name in a vtable name
*/
{
//error('d',"get_classname(%s)",s);
	char* s1 = 0;

	while (*s) {
		s1 = s;
		for ( ; s[0] && (s[0] != '_' || s[1] && s[1] != '_'); s++);
		if (*s) s += 2;	// bypass "__"
	}

	return s1;
}

char* drop_classname(char* s)
/*
	retrieve all but the outermost class name in a vtable name
*/
{
//error('d',"drop_classname(%s)",s);
	char* r = new char[strlen(s)+1];
	sprintf(r,s);
	s = r;

	char* s1 = s;
	while (*s) {
		for ( ; s[0] && (s[0] != '_' || s[1] && s[1] != '_'); s++);
		if (*s) {
			s1 = s;
			s += 2;	// bypass "__"
		}
	}

	*s1 = '\0';

	return (*r) ? r : 0;
}
		
Pbcl classdef::get_base( char *s )
/*
	Find the base class whose name matches the argument
*/
{
//error('d',"%t::get_base(%s)",this,s);
	for (Pbcl b = baselist; b; b = b->next) {
		for ( char *s1 = s, *s2 = b->bclass->string;
		     *s1 && *s2 && *s1 == *s2;
		     s1++, s2++);
		
		if (!(*s1 || *s2))
			break;
	}

	return b;
}

int classdef::get_offset(char* s)
/*
	Get offset represented by string as viewed from "this"
*/
{
//error('d',"%t::get_offset(%s)",this,s);
	if (!s) return 0;

	Pbcl b = get_base(get_classname(s));

	return b->obj_offset + b->bclass->get_offset(drop_classname(s));
}

char* vtbl_str(char* s1, char* s2)
/*
	combine two pieces of a vtbl name
*/
{
//error('d',"vtbl_str(%s,%s)",s1,s2);
	char* s3;
	if (s1)
		if (s2) {
			s3 = new char[strlen(s1)+strlen(s2)+3];
			sprintf(s3,"%s__%s",s1,s2);
			return s3;
		}
		else
			return s1;
	else
		return s2;
}

void classdef::add_vtbl(velem* v, char* s, bit virt_flag, int n_init)
/*
	add vtbl to virt_list
*/
{
// error('d',"%t->add_vtbl(%d,%s)",this,v,s);
	Pvirt vtab = new virt(this, v, s, virt_flag, n_init);

	if (virt_flag) has_vvtab = 1;

	if (!virt_list) {
		virt_list = vtab;
		return;
	}

	// If conficting vtable entries are made because of
	// a virtual base class, must be considered an error.
	for (Pvirt vt = virt_list; vt; vt = vt->next )
//		if (strcmp(vt->string,s)==0) {
                if (vt->string && strcmp(vt->string,s)==0) {
			velem* ivec = vt->virt_init;
			Pname on = ivec[0].n;
			Pname nn = v[0].n;
			Pclass ocl,ncl;
			for (int i=0; on && nn; i++,on=ivec[i].n,nn=v[i].n) {
				ocl = Pfct(on->tp)->memof;
				ncl = Pfct(nn->tp)->memof;
				if (on != nn)
					if (!ocl->has_base(ncl))
						if (!ncl->has_base(ocl))
							break;
						else {
							ivec[i].n = nn;
							ivec[i].offset = v[i].offset;
						}
			}
			if (on || nn)
				error("virtualB: ambiguous%n and%n", on, nn);
			return;
		}

	vtab->next = virt_list->next;
	virt_list->next = vtab;
}

static int Voffset;	// cope with offsets of virtuals in deep nests
int vcounter;
static vmax;
const vpChunk = 32;

int classdef::do_virtuals(Pvirt vtab, char* str, int leftmost, bit virt_flag)
/*
	make vtbl for b in "this"
	match up virtuals and assign virtual indices for the base or delegate "bcl"
	first base class shares ``this'' and vtbl with this class
*/
{
	if (vmax<vcounter) vmax = vcounter;
        int vpsz = (vmax+vcounter)/vpChunk+1;   // fragmentation prevention
        vpsz *= vpChunk;
	Pname* vp = new Pname[vpsz];
	velem* ivec = vtab ? vtab->virt_init : 0;
	int vo = Voffset;
	int vc = 0;
	int changed = 0;

// error('d',"%t->do_virtuals(%d,%s) voffset %d",this,vtab,str,Voffset);
// error('d',"virt_count %d vpsz %d vcounter %d",virt_count,vpsz,vcounter);

if (ivec) {	// vtbl replacement for ivec

	if (vtab->is_vbase) {
		str = 0;
		Voffset = get_offset(vtab->string);
	}
	else
		Voffset = Voffset + vtab->vclass->get_offset(vtab->string);
	Pname vn;
	for (int i=0; vn=ivec[i].n; i++) {

	/*	go through virtual table's list of virtuals:
		first see if the function is simply inherited
		if not, check for a match
		if not, then add as new
	*/
	//	Pname vn = ivec[i];
                if ( i >= vpsz ) { // resize vp vector
                        int tvpsz = vpsz + vpChunk;
                        Pname *tvp = new Pname[ tvpsz ];
                        for ( int j = 0; j < i; ++j )
                                tvp[ j ] = vp[ j ];
                        delete [vpsz] vp;
                        vp = tvp;
//error( 'd',"resizing: i: %d vpsz: %d tvpsz: %d", i, vpsz, tvpsz );
                        vpsz = tvpsz;
                }

		// char* s = Pchar(vn->n_tbl_list);
                char* s = vn->n_gen_fct_name;
		Pname n = memtbl->look(s?s:vn->string, 0);

// error('d',"vn %n %s n %n %d",vn,s,n,Voffset);
// error('d',"n %n %k", n, n?n->base:0 );
		if (n == 0 || 				// FCT + FCT
			n->base == PUBLIC ) {		// base::FCT
		inher:			// inherit
// 			if (vn->n_initializer) error("cannot inherit pure virtualF%n",vn);
                        if (vn->n_initializer) c_abstract = 1;
			vp[i] = vn;
                        if ( ivec[i].offset && vtab->is_vbase )
                                vp[i]->n_offset = Voffset - vo;
                        else
                                vp[i]->n_offset = ivec[i].offset;
			continue;
		}

		Pfct f = Pfct(n->tp);
// error ('d', "f %d", f );
		if (f == 0 ) continue;
// error('d',"f %t %d",f,f->f_virtual);

		if (s && f->base==OVERLOAD) {	// OVERLOAD + OVERLOAD
			// vn is overloaded and s is its name
			for (Plist gl=Pgen(f)->fct_list; gl; gl=gl->l)
				if (gl->f == vn)  goto inher;
		}

		Pfct vnf = Pfct(vn->tp);
						// re-define?
		switch (f->base) {
		default:
			error('w',&n->where,"%n hides virtual%n",n,vn);
			vp[i] = vn;	// not a new overloaded: inherit 
			if ( ivec[i].offset && vtab->is_vbase )
       				vp[i]->n_offset = Voffset - vo;
			else
       				vp[i]->n_offset = ivec[i].offset;
			break;
		case FCT:			// derived::FCT
		{
			if (vnf->check(f,VIRTUAL) == 0) { // derived::FCT match base::FCT
// error('d',"vnf1 %t f %t vcheck %d",vnf,f,Vcheckerror);
				// VTOK: virtual, but no index assigned
				// you can only inherit an index from your first base
				if (Vcheckerror) error("bad virtualT match for %n",vn);
				if (f->f_virtual==VTOK) f->f_virtual = i+1;
				vp[i] = n;
				vp[i]->n_offset = Voffset;
				changed = 1;
			}
			else {
// error('d',"vnf2 %t f %t vcheck %d",vnf,f,Vcheckerror);
				if (Vcheckerror)
					error("bad virtualT match for %n",vn);
				else
					switch (f->f_virtual) {
						case 0:
						case VTOK:
							error('w',&n->where,"%n hides virtual%n",n,vn);
					}
				vp[i] = vn;	// not a new overloaded: inherit
                                if ( ivec[i].offset && vtab->is_vbase )
                                        vp[i]->n_offset = Voffset - vo;
                                else
                                        vp[i]->n_offset = ivec[i].offset;
			}
			break;
		}
		case OVERLOAD:			// derived::OVERLOAD
		{				
			int hit = 0;
			for (Plist gl=Pgen(f)->fct_list; gl; gl=gl->l) {
				// try each fct from derived class
				Pname fn = gl->f;
				Pfct f = Pfct(fn->tp);
			
				if (f->check(vnf,VIRTUAL) == 0) {	// derived::FCT
					if (Vcheckerror) error("bad virtualT match for %n",vn);
					if  (f->f_virtual==VTOK) f->f_virtual = i+1;
					vp[i] = fn;
					vp[i]->n_offset = Voffset;
					changed = 1;
					goto found;
				}
				else {
					if (Vcheckerror) error("bad virtualT match for %n",vn);
				}
				if (Vcheckerror == 0)
					switch (f->f_virtual) {
						case 0:
						case VTOK:
							hit = 1;
				}
	
			}

			if (hit) 
				error('w',&n->where,"%n hides virtual%n ofT %t",n,vn,vn->tp);

			vp[i] = vn;	// not a new overloaded: inherit
                        if ( ivec[i].offset && vtab->is_vbase )
                                vp[i]->n_offset = Voffset - vo;
                        else
                                vp[i]->n_offset = ivec[i].offset;
		found:
			break;
		}
		}
	}

	Voffset = vo;
	vc = i;
}

// error( 'd', "do_virtuals: out of loop: vc: %d vpsz: %d changed: %d", vc, vpsz,changed );

	if (leftmost) {
		/*
			add new virtuals:
			`VTOK' marks ``new virtual, no index assigned''.
			You can only be new once (no base or first base).
		*/
		int i;
		for (Pname nn=memtbl->get_mem(i=1); nn; nn=memtbl->get_mem(++i) ) {
			Pfct f = Pfct(nn->tp);

                	if ( vc >= vpsz ) { // resize vp vector
                        	int tvpsz = vpsz + vpChunk;
                        	Pname *tvp = new Pname[ tvpsz ];
                        	for ( int j = 0; j < vc; ++j )
                                	tvp[ j ] = vp[ j ];
                        	delete [vpsz] vp;
                        	vp = tvp;
                        	vpsz = tvpsz;
                	}

// error('d',"f %n %t",nn,f);
                        if (f)
                        switch (f->base) {
			case FCT:
//error('d',"fv %d",f->f_virtual);
				if (f->f_virtual == VTOK) {
					// declared virtual, or
					// virtual in some base
					f->f_virtual = ++vc;
					vp[f->f_virtual-1] = nn;
                                        vp[f->f_virtual-1]->n_offset = 0;
					f->f_vdef = 1;
					changed = 2;
				}
				break;
			case OVERLOAD:
			{	for (Plist gl=Pgen(f)->fct_list; gl; gl=gl->l) {
					Pname fn = gl->f;
					Pfct f = Pfct(fn->tp);

 
                 		if ( vc >= vpsz ) { // resize vp vector
                         		int tvpsz = vpsz + vpChunk;
                         		Pname *tvp = new Pname[ tvpsz ];
                         		for ( int j = 0; j < vc; ++j ) {
                                 		tvp[ j ] = vp[ j ];
 					}
                         		delete [vpsz] vp;
                         		vp = tvp;
                         		vpsz = tvpsz;
                 		}
 

					if (f->f_virtual == VTOK) {
						f->f_virtual = ++vc;
						vp[f->f_virtual-1] = fn;
						vp[f->f_virtual-1]->n_offset = 0;
						f->f_vdef = 1;
						changed = 2;
					}
				}
				break;
			}
			}
		}
// error('d',"%s changed %d has_vvtab %d",string,changed,has_vvtab);
// error('d',"vc %d vpsz %d",vc,vpsz);
		virt_count = 0;
		if (changed)
			virt_count = vc;
		else if (has_vvtab) {
			virt_merge = 1;
			if (vc && vtab->is_vbase)
				leftmost = 0;
		}
	}

// error('d',"vc %d ch %d vp[%d] virt_count %d",vc,changed,vpsz,virt_count);
	if (changed || !leftmost) {
		// vc==0 if all explicit virtuals in fact were declared in base
		velem* v = new velem[vc+1];

		for (int i=0; i<vc; i++) {
			v[i].n = vp[i];
			v[i].offset = vp[i]->n_offset;
		}
		v[vc].n = 0;

		if (leftmost)
			add_vtbl(v,0,0,0);
		else
			add_vtbl(v,vtbl_str(vtab->string,str),virt_flag||vtab->is_vbase,vc+1);
		delete vp;
		vcounter = 0;
		return 1;
	}

	delete vp;
	vcounter = 0;
	return 0;
}

int classdef::all_virt(Pclass bcl, char* s, int leftmost, bit virt_flag)
{
	int i = 0;
	if (bcl->virt_count) {
		for (Pvirt blist = bcl->virt_list; blist; blist = blist->next) {
			// if (has_base(blist->vclass))
			//	if (blist->vclass==bcl
			//		// bcl is virtual in both
			//	|| ((Nvirt=0,blist->vclass->has_base(bcl)) && Nvirt==VIRTUAL
			//		&& (Nvirt=0,has_base(bcl)) && Nvirt==VIRTUAL
			//	   )
			//	)
			if (virt_merge && !(virt_flag || blist->is_vbase))
				continue;

			i += do_virtuals(blist, s, leftmost, virt_flag);
			if (!i && leftmost && !virt_merge)
				return 0;

			leftmost = 0;
		}
	}

	// finding virt_list stops recursive step
	// if vtables found and updated, return number
	if (i) return i;

	for (Pbcl b = bcl->baselist; b; b = b->next) {
	//	if (b->base==PTR) continue;
		if (b->promoted) continue;
// error('d',"b %t vl %d bl %d",b->bclass,b->bclass->virt_list,b->bclass->baselist);
		if (leftmost && b->base == VIRTUAL) {
			i += do_virtuals(0, 0, 1, 0);
			if (!i && !virt_merge)
				return 0;
			leftmost = 0;
		}
		int vo = Voffset;
		Voffset += b->obj_offset;
// error('d',"offset %t %d",b->bclass,Voffset);

		if (b->base==VIRTUAL)
			i += all_virt(b->bclass, b->bclass->string, leftmost, 1);
		else
			i += all_virt(b->bclass, vtbl_str(b->bclass->string,s), leftmost, virt_flag);
		if (!i && leftmost && !virt_merge)
			return 0;

		Voffset = vo;
		leftmost = 0;
	}

	// if recursion updated vtables, return number
	if (i) return i;

	// no vtables updated in recursion
	// look for new virtuals
	if (leftmost)
		return do_virtuals(0, 0, 1, 0);
	else
		return 0;
}

Pexpr copy_obj(Pexpr l, Pexpr r, int sz)
/*
	generate:
	struct _s { char[sz]; };
	*(struct _s*)this->m = *(struct _s*)arg.mem;
*/
{
	if ( !sz ) sz = 1;
//error('d',"copy(%d)",sz);
	char* s = make_name('S');
	fprintf(out_file,"struct %s { char v[%d]; };\n",s,sz);
	Pname n = new name(s);
	Ptype t = new basetype(COBJ,n);
	t = new ptr(PTR,t);

	l = new texpr(CAST,t,l);//new cast(t,l);
	l = l->contents();

	r = new texpr(CAST,t,r);//new cast(t,r);
	r = r->contents();

	return new expr(ASSIGN,l,r);
}

/*
Pname make_default_ctor(Pclass cl)
{
//error('d',"make_ctor %t",cl);
	Pname cn = ktbl->look(cl->string,0);
	if (cn) cn = Pbase(cn->tp)->b_name;
	cc->stack();
	cc->not = cn;
	cc->cot = cl;
	Pname fn = new name(cl->string);
	Pfct f = new fct(defa_type,0,1);
	fn->tp = f;
	fn->n_oper = TNAME;
//	fn->n_sto = STATIC;

	Pfct(f)->f_inline = 1;
	f->body = new block(curloc,0,0);

	Pname nn = fn->dcl(cl->memtbl,PUBLIC);
	delete fn;

	cc->unstack();
	nn->simpl();
	if (debug_opt) nn->dcl_print(0);
//error('d',"make_ctor->");
	return nn;
}

Pname make_default_dtor(Pclass cl)
{
//error('d',"make_dtor %t",cl);
	Pname cn = ktbl->look(cl->string,0);
	if (cn) cn = Pbase(cn->tp)->b_name;
	cc->stack();
	cc->not = cn;
	cc->cot = cl;
	Pname fn = new name(cl->string);
	Pfct f = new fct(defa_type,0,1);
	fn->tp = f;
	fn->n_oper = DTOR;
//	fn->n_sto = STATIC;

	Pfct(f)->f_inline = 1;
	f->body = new block(curloc,0,0);

	Pname nn = fn->dcl(cl->memtbl,PUBLIC);
	delete fn;

	cc->unstack();
	nn->simpl();
	if (debug_opt) nn->dcl_print(0);
//error('d',"make_dtor->");
	return nn;
}
*/

Ptype find_arg_type(Pclass cl)
// first determine argument type
{
	int i;
	int mod = 0;
	for (Pbcl b = cl->baselist; b; b = b->next) {
		Pclass bcl = b->bclass;
		switch (b->base) {
		case VIRTUAL:
		case NAME:	//	generate :b(*(b*)&arg)
		{
			Pname itor = bcl->has_itor();
			if (itor && itor->tp->base==FCT) {
				Pname a = Pfct(itor->tp)->argtype;
				Pptr p = a->tp->is_ref();
				if (p && p->typ->tconst()==0) {
					mod = 1;
					goto ll1;
				}
			}
		}
		}
	}
ll1:
    if (mod == 0) {
	for (Pname m=cl->memtbl->get_mem(i=1); m; m=cl->memtbl->get_mem(++i) ) {
		Pname cln;
		// ignore static members
		if (m->n_evaluated || m->n_stclass==STATIC) continue;

		if (cln = m->tp->is_cl_obj()) {
			Pname itor = Pclass(cln->tp)->has_itor();
			if (itor && itor->tp->base==FCT) {
				Pname a = Pfct(itor->tp)->argtype;
				Pptr p = a->tp->is_ref();
				if (p && p->typ->tconst()==0) {
					mod = 1;
					goto ll2;
				}
			}
		}
	}
    }
ll2:
//error('d',"mod %d",mod);
		Pbase bp = new basetype(INT,0);
		*bp = *Pbase(Pptr(cl->this_type)->typ);
		if (mod == 0) bp->b_const = 1;
		return new ptr(RPTR,bp);
}

Pname classdef::make_itor(int def)
/*
	make cn::cn(const cn&) :bases_and_members_of_cn {}
*/
{
//error('d',"%t->make_itor(%d) %d",this,def,obj_size);
	Pstmt s;
	Pname e;
	int i;
	Pname arg = new name(make_name('A'));
	arg->tp = find_arg_type(this);

//	c_xref = 2;  // now it has X(X&)
	c_xref |= C_XREF;  // now it has X(X&)

    if (def) {
	// define itor
	int slow = 0;	// slow==0 => copy using vector copy
	int first = 1;
	Pexpr es = 0;
	s = new estmt(SM,no_where,0,0);
	e = 0;


	if (warning_opt && 128<obj_size)
		error('w',"copying a %d byte object (ofC %s)",obj_size,string);

	if (baselist) slow = 1;
		
	//for (Pbcl v = baselist; v; v = v->next)
	//	if (v->base == VIRTUAL) {
	//		slow = 1;
	//		break;
	//	}

	// initialize bases:
    if (slow) {
	for (Pbcl b = baselist; b; b = b->next) {
		Pclass bcl = b->bclass;
		Ptype pt = bcl->this_type;
//error('d',"base %t %k offset %d ptroffset %d",bcl,b->base,b->obj_offset,b->ptr_offset);
		switch (b->base) {
		case VIRTUAL:
		case NAME:	//	generate :b(*(b*)&arg)
		{
			Pexpr b2 = new name(arg->string);
			b2 = b2->address();
			b2 = new texpr(CAST,pt,b2);//new cast(pt,b2);
			b2->i2 = 1;
			b2 = b2->contents();

			Pname ee = new name(bcl->string);
			ee->base = TNAME;
			ee->n_initializer = b2;
			if (e) ee->n_list = e;
			e = ee;
			break;
		}
		}
	}
    }

	// initialize members
	for (Pname m=memtbl->get_mem(i=1); m; m=memtbl->get_mem(++i) ) {
		// ignore static members
		if (m->n_evaluated || m->n_stclass==STATIC) continue;

		if (strcmp(m->string,"__vptr")==0) {
// error('d',"%t vptr: %d",this,first);
			if (first==0 && m->n_offset) {
				Pexpr th = new expr(THIS,0,0);
				Pexpr a = new name(arg->string);
				a = a->address();
				Pexpr ee = copy_obj(th,a,m->n_offset);
				es = es ? new expr(CM,es,ee) : ee;
			}
			slow = 1;
			first = 0;
			continue;
		}
		Ptype mt = m->tp;
	tx:
		switch (mt->base) {
		case TYPE:
			mt = Pbase(mt)->b_name->tp;
			goto tx;
		case VEC:
		{	Pname cn = Pvec(mt)->typ->is_cl_obj();
//error('d',"vec %n %t xref %d",m,mt,cn?Pclass(cn->tp)->c_xref:0);
			if (cn && Pclass(cn->tp)->c_xref&(C_XREF|C_VBASE)) {
				error('s',"copy of %n[], no memberwise copy for%n",cn,cn);
				slow = 1;	// make sure an assignment operator
						// is generated so that there will
						// be no more error messages
			}

			if (slow && mt->tsizeof()) {
			/*
				generate:
				struct _s { char[sizeof(m)]; };
				*(struct _s*)this->m = *(struct _s*)arg.mem;
			*/
				Pexpr l = new name(m->string);
				Pexpr r = new name(m->string);
				r = new ref(DOT,new name(arg->string),r);
				Pexpr ee = copy_obj(l,r,mt->tsizeof());
				es = es ? new expr(CM,es,ee) : ee;
				break;
			}
		}
		case FCT:
		case OVERLOAD:
		case CLASS:
		case ENUM:
			break;
		case COBJ:
		{	Pclass mcl = Pclass(Pbase(mt)->b_name->tp);
			if (slow==0	// if slow, previous members have
					// already been copied
			&& mcl->c_xref&(C_VBASE|C_XREF)) {
				slow = 1;
				if (first==0 && m->n_offset) {
						//AAA copy up to here
					Pexpr th = new expr(THIS,0,0);
					Pexpr a = new name(arg->string);
					a = a->address();
					Pexpr ee = copy_obj(th,a,m->n_offset);
					es = es ? new expr(CM,es,ee) : ee;
				}
			}
			// no break
		}

		default:
			if (slow) {
//error('d',"slow %s %s",m->string,arg->string);
				Pname ee = new name(m->string);
				ee->n_initializer = new ref(DOT,new name(arg->string),new name(m->string));
				if (e) ee->n_list = e;
				e = ee;
			}
		}
		first = 0;
	}
	
	if (slow == 0) {
	/*	really simple just copy:
		the only problem was a vptr which can be
		ignored since X(X&) is going to reset it anyway
		don't use assignment of this struct to avoid operator=
	*/
		Pexpr th = new expr(THIS,0,0);
		Pexpr a = new name(arg->string);
		a = a->address();
		Pexpr ee = copy_obj(th,a,obj_size);
		es = es ? new expr(CM,es,ee) : ee;
	}

	s->e = es;
	Pname cn = ktbl->look(string,0);
	if (cn) cn = Pbase(cn->tp)->b_name;
	cc->stack();
	cc->not = cn;
	cc->cot = this;
}
	Pname fn = new name(string);
	Pfct f = new fct(defa_type,arg,1);
	fn->tp = f;
	fn->n_oper = TNAME;
//	fn->n_sto = STATIC;

	Pfct(f)->f_inline = def?1:ITOR;	// ITOR means ``define itor() if used''
	if (def) {
		f->body = new block(curloc,0,s);
		f->f_init = e;
	}

	Pname nn = fn->dcl(memtbl,PUBLIC);
	delete fn;

	if (def) {
		cc->unstack();
		nn->simpl();
		if (debug_opt) nn->dcl_print(0);
	}
//error('d',"make_itor->");
	return nn;
}

int make_assignment(Pname cn)
/*
	write the function:

	X& X::operator=(const X&) { assign all bases and members }

	return 1 is a function is really synthesized
*/
{
	Pclass cl = Pclass(cn->tp);
	Pstmt s = new estmt(SM,no_where,0,0);
	Pexpr e = 0;
	Pname arg = new name(make_name('A'));
	basetype* bp = new basetype(INT,0);
	*bp = *Pbase(Pptr(cl->this_type)->typ);
	bp->b_const = 1;
//	arg->tp = new ptr(RPTR,bp);
	arg->tp = find_arg_type(cl);
//error('d',"make_assignment %t %d",cl,cl->obj_size);
//	cl->c_xref |= 4;  // now it has X::operator=(const X&)

	if (warning_opt && 128<cl->obj_size)
		error('w',"copying a %d byte object (ofC %s)",
			cl->obj_size,cl->string);
{
	int slow = 0;	// slow==0 => copy using vector copy
	int first = 1;	// first==1 => first member of (derived) class

	if (cl->baselist) slow = 1;	// be dumb and safe
//	for (Pbcl v = cl->baselist; v; v = v->next)
//		if (v->base==VIRTUAL || v->c_xref&(C_VBASE|C_ASS)) {
//			slow = 1;
//			break;
//		}

    if (slow) {
	for (Pbcl b = cl->baselist; b; b = b->next) {
		Pclass bcl = b->bclass;
		Ptype pt = bcl->this_type;
		switch (b->base) {
		case NAME:
		{	// generate: *(bcl*)this = *(bcl*)&arg;
//error('d',"base %t",bcl);
			Pexpr b1 = new expr(THIS,0,0);
			b1 = new texpr(CAST,pt,b1);
			b1 = b1->contents();

			Pexpr b2 = new name(arg->string);
			b2 = b2->address();
			b2 = new texpr(CAST,pt,b2);
			b2->i2 = 1;
			b2 = b2->contents();

			Pexpr ee = new expr(ASSIGN,b1,b2);
			e = e ? new expr(CM,e,ee) : ee;
			break;
		}
		case VIRTUAL:
			if (warning_opt)
				error('w',"copying an object ofC%n with a virtualBC",cn);
			if (b->ptr_offset) {
				// copy object, but not pointer
				// generate: *(bcl*)this->Pw = *(bcl*)arg->Pw;

				// I don't know how to avoid copying the object
				// once for each pointer

				Pexpr b1 = new expr(THIS,0,0);
				b1 = new mdot(bcl->string,b1);
				b1->i1 = 3;
				b1->tp = pt;
				b1 = new expr(DEREF,b1,0);//b1->contents();

				Pexpr b2 = new name(arg->string);
				b2 = b2->address();
				b2 = new mdot(bcl->string,b2);
				b2->i1 = 3;
				b2->tp = pt;
				b2 = new expr(DEREF,b2,0);//b2->contents();

				Pexpr ee = new expr(ASSIGN,b1,b2);
				e = e ? new expr(CM,e,ee) : ee;
			}
			break;
		}
	}
    }

	int i;
	for (Pname m=cl->memtbl->get_mem(i=1); m; m=cl->memtbl->get_mem(++i) ) {
		// ignore static members
		if (m->n_evaluated || m->n_stclass==STATIC) continue;

		if (strcmp(m->string,"__vptr")==0) {	// don't copy vptrs
							// we may be copying
							// into a base class object
		if (first==0 && m->n_offset) {
					// copy up to (but not including) vptr
					// don't copy if first member
				Pexpr th = new expr(THIS,0,0);
				Pexpr a = new name(arg->string);
				a = a->address();
				Pexpr ee = copy_obj(th,a,m->n_offset);
				e = e ? new expr(CM,e,ee) : ee;
			}
			slow = 1;
			first = 0;
			continue;
		}
		Ptype mt = m->tp;
	tx:
		switch (mt->base) {
		case TYPE:
			mt = Pbase(mt)->b_name->tp;
			goto tx;
		case VEC:
		{	Pname cn = Pvec(mt)->typ->is_cl_obj();
			if (cn && Pclass(cn->tp)->c_xref&(C_ASS|C_VBASE)) {
				error('s',"copy of %n[], no memberwise copy for%n",cn,cn);
				slow = 1;	// make sure an assignment operator
						// is generated so that there will
						// be no more error messages
			}

			if (slow && mt->tsizeof()) {
				// protect against sizeof(mt)==0: char[]
			/*
				generate:
					struct _s { char[sizeof(m)]; };
					*(struct _s*)this->m = *(struct _s*)arg.mem;
			*/	
				Pexpr l = new name(m->string);
				Pexpr r = new name(m->string);
				r = new ref(DOT,new name(arg->string),r);
				Pexpr ee = copy_obj(l,r,mt->tsizeof());
				e = e ? new expr(CM,e,ee) : ee;
				break;
			}
		}
		case FCT:
		case OVERLOAD:
		case CLASS:
		case ENUM:
			break;
		case RPTR:
			error("cannot assignC%t:RM%n",cl,m);
			break;
		case COBJ:
//error('d',"cobj %n %d %d",m,slow,Pclass(Pbase(mt)->b_name->tp)->c_xref);
			if (slow==0
			&& Pclass(Pbase(mt)->b_name->tp)->c_xref&(C_VBASE|C_ASS)) {
				// must use its assignment operation
				if (first==0 && m->n_offset) {
						// copy up to this member 
					Pexpr th = new expr(THIS,0,0);
					Pexpr a = new name(arg->string);
					a = a->address();
					e = copy_obj(th,a,m->n_offset);
				}
				slow = 1;
			}
			// no break: copy cobj itself
		default:
 //error('d',"defa %n %d",m,slow);
			if (slow) {
				if (m->tp->tconst()) error("cannot assignC%t: const M%n",cl,m);
				Pname ms = new name(m->string);
				Pname as = new name(arg->string);
				Pexpr ee = new ref(DOT,as,new name(m->string));
				ee = new expr(ASSIGN,ms,ee);
				e = e ? new expr(CM,e,ee) : ee;
			}
		}
		first = 0;
	}

        if (slow == 0) {
        /*      really simple just copy:
        */
//error('d',"slow");
/*
                Pexpr th = new expr(THIS,0,0);
                Pexpr a = new name(arg->string);
                a = a->address();
                Pexpr ee = copy_obj(th,a,cl->tsize());
                e = e ? new expr(CM,e,ee) : e;
*/
//error('d',"%n simple assignment",cn);
	//	cl->c_xref ^= C_ASS; // Didn't mean it: No X::operator=(X&)
		return 0;
        }

}

	Pexpr rv = new expr(THIS,0,0);
	rv = new expr(DEREF,rv,0);//b1->contents();
	
	s->e = e ? new expr(CM,e,rv) : e;
	s->s_list = new estmt(RETURN,no_where,rv,0);

	cc->stack();
	cc->not = cn;
	cc->cot = cl;

	cl->c_xref |= C_ASS;  // now it has X::operator=(const X&)

	Pname fn = new name(oper_name(ASSIGN));
	Pfct f = new fct(new ptr(RPTR,Pptr(cl->this_type)->typ),arg,1);
	f->f_inline = 1;
	fn->tp = f;
	fn->n_oper = ASSIGN;
	fn->n_sto = STATIC;
	Pname nn = fn->dcl(cl->memtbl,PUBLIC);
	delete fn;
	Pfct(nn->tp)->body = new block(curloc,0,s);
	Pfct(nn->tp)->dcl(nn);

	cc->unstack();
	nn->simpl();
//error('d',"make_assign->");
	return 1;
}

void classdef::dcl(Pname cname, Ptable tbl)
{
	int bvirt = 0;
	int dvirt = 0;
	int scope = PUBLIC;
	int protect = 0;
	int st = 1;		// nothing private or protected seen: a struct
	// int nstd = (in_class && nested_sig)?2:(in_class?1:0); // nested class

	int byte_old = byte_offset;
	int bit_old = bit_offset;
	int max_old = max_align;
	int boff = 0;

	int in_union = 0;
	int usz;
	int make_ctor = 0;
	int make_dtor = 0;

	/* this is the place for paranoia */
	if (this == 0) error('i',"0->Cdef::dcl(%p)",tbl);
	if (base != CLASS) error('i',"Cdef::dcl(%d)",base);
	if (cname == 0) error('i',"unNdC");
	if (cname->tp != this) error('i',"badCdef");
	if (tbl == 0) error('i',"Cdef::dcl(%n,0)",cname);
	if (tbl->base != TABLE) error('i',"Cdef::dcl(%n,tbl=%d)",cname,tbl->base);
	DB( if(Ddebug>=1) error('d',&cname->where,"classdef::dcl %s tbl %d gtbl %d",string,tbl,gtbl); );
// error('d',&cname->where,"classdef::dcl %s tbl %d gtbl %d",string,tbl,gtbl); 

	switch (csu) {
	case UNION:
		in_union = UNION;
		break;
	case ANON:
		in_union = ANON;
		break;
	case CLASS:
		scope = 0;
	}

	max_align = AL_STRUCT;

	if (lex_level) {
// error('d',&cname->where,"%t::dcl in_class: %t lex_level %d ",this,in_class, lex_level); 
		if ( in_class )
			lex_level = 0;
		else {
    			in_fct = cc->nof;
    			if ( lcl == 0 ) lcl = make_name( 'L' );
		}
	}

	if (strlen == 0) strlen = ::strlen(string);
	if (baselist) {
		/*
			check base classes.
			duplicates were removed in start_cl() in norm.c.
			remove bad classes.
			add virtual bases from bases to the list.

			check against
				class b : a {}
				class c : a, b {}	// first a inaccessible
		*/
		
		Pbcl ll = 0;
		Pbcl lll = 0;
		Pbcl vlist = 0;
		for (Pbcl lx, l=baselist; l; l=lx) {	// remove bad bases
			Pclass cl = l->bclass;
			/* restriction lifted: nested and local classes
			int b_nstd = (cl->in_class && cl->nested_sig) 
					?2:(cl->in_class?1:0); 

			if (b_nstd) 
				error((b_nstd==2)?0:'w',"%s derived from nestedC %s", string, cl->string);
			if (cl->lex_level) 
				error('w',"%s derived from localC  %s", string, cl->string);
			*/

			lx = l->next;

//error('d',"base1 %t %k init %d",cl,l->ppp,l->init);
			// ``class'' => private base ``struct'' => public base
			if (l->ppp == 0) {
				l->ppp = csu==CLASS ? PRIVATE : PUBLIC;
#ifndef OLD
				if (l->ppp == PRIVATE) error('w',"B%t private by default: please be explicit ``: private%t",cl,cl);
#endif
			}
			// if you have a ``class'' as base you cannot remain a
			// ``mere struct''
			if (cl && cl->csu == CLASS) st = 0;

			if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) {
				error("BC %sU",cl->string);
				continue;
			}
			else
				(void)cl->tsizeof();	// ensure printout

			if (cl->csu==UNION || cl->csu==ANON) {
				error("C derived from union");
				continue;
			}

			if (in_union) {
				error("derived union");
				continue;
			}

			if (l->base==VIRTUAL) {
			// constraint removed ...
			//	if (cl->has_ictor()==0 && cl->has_ctor()) {
			//		error("virtualB%t has no defaultIr",cl);
			//		continue;
			//	}
				// order of virtual classes doesn't matter
				l->next = vlist;
				vlist = l;
			}
			else {	// keep ordinary base classes in order
				if (ll == 0) {
					lll = l;
					l->next = 0;
				}
				else
					ll->next = l;
				ll = l;
			}
		}
		if (ll) {
			ll->next = vlist;	// put virtual bases at end
			baselist = lll;
		}
		else
			baselist = vlist;

		lll = 0;
		for (l=baselist; l; l=l->next) {	// detect unmanageable duplicates
			Pclass b = l->bclass;
			for (ll=baselist; ll; ll=ll->next)
				if (b!=ll->bclass && ll->bclass->check_dup(b,l->base)) {
					if (lll)
						lll->next = l->next;
					else
						baselist = l->next;
					goto mmm;
				}
						
			lll = l;
			mmm:;
		}

		for (l=baselist; l; l=l->next) {	// promote virtual bases
			Pclass b = l->bclass;
			for (ll=b->baselist; ll; ll=ll->next) {
				if (ll->base == VIRTUAL) {
					Pclass v = ll->bclass;
					for (Pbcl lll=baselist; lll; lll=lll->next)
						if (lll->bclass == v) goto nnn;
		//			error('w',"%t is virtualB of%t",v,this);
					baselist = new basecl(v,baselist);
					baselist->base = VIRTUAL;
					baselist->promoted = 1;
// needs a more complete check of visibility rules
//error('d',"promote %t %k",v,ll->ppp);
					baselist->ppp = ll->ppp;
				}
				nnn:;
			}
		}

		ll = 0;
		lll = 0;
		l=baselist;
		baselist = 0;
		vlist = 0;
		for (; l; l=lx) {
			// sort virtual bases so that no virtual base
			// is ahead of its own virtual base
			lx = l->next;
			if (l->base == VIRTUAL) { // add to sorted vlist
						  // each class before its bases
				if (vlist == 0) {
					vlist = l;
					l->next = 0;
				}
				else {
					Pclass lb = l->bclass;
					Pbcl v_prev = 0;
					for (Pbcl vx, v = vlist; v; v=vx) {
						Pclass vb = v->bclass;
						vx = v->next;

						if (lb->has_base(vb)) {
							// put l ahead of v
							l->next = v;
							if (v_prev)
								v_prev->next = l;
							else
								vlist = l;
							break;
						}
						if (vx == 0) {
							// stick l at end
							v->next = l;
							l->next = 0;
							break;
						}	
						v_prev = v;
					}
				}
			}
			else {	// keep in order
				if (ll == 0) {
					lll = l;
					l->next = 0;
				}
				else
					ll->next = l;
				ll = l;
			}
		}

		if (ll) {
			ll->next = vlist;	// put virtual bases at end
			baselist = lll;
		}
		else
			baselist = vlist;

		for (l=baselist; l; l=l->next) { // allocate base class objects
			Pclass cl = l->bclass;
//error('d',"base %t %k init %d",cl,l->ppp,l->init);
			if (l->base == VIRTUAL) {	// : virtual bclass
				// pointer and object for virtual base MAY
				// be allocated at the end - but not here
				c_xref |= C_VBASE;
				dvirt += cl->virt_count;
			}
			else {				// : bclass =>allocate
				int ba = cl->align();
				if (max_align<ba) max_align = ba;

				if (cl == baselist->bclass) {
					// pad to ensure alignment:
					boff = cl->real_size;
					// not obj_size-real_size, we can
					// optimize vbase object away
					int xtra = boff%ba;
					// align
					if (xtra) boff += ba-xtra;
				}
				else {	// let C handle the padding:
					int xtra = boff%ba;
					if (xtra) boff += ba-xtra;	// align
					l->obj_offset = boff;
					// don't use waste
					boff += cl->obj_size;
				}
				bvirt += cl->virt_count;
			}

                        if (cl->has_vvtab) has_vvtab = 1;
			c_xref |= cl->c_xref;

//error('d',"%t: base %t conv %d base conv %d",this,cl,conv,cl->conv);
			conv = merge_conv(conv,cl->conv);
		}
	}

	memtbl->set_name(cname);

//	int nmem = mem_list->no_of_names();
	int nmem = 0;
	int fct_mem = 0;
	{	for (Pname m = mem_list; m; m=m->n_list) {
			nmem++;
			if (m->tp && m->tp->base==FCT) fct_mem++;
		}
	}
	if (nmem) memtbl->grow((nmem<=2)?3:nmem);

	cc->stack();
	cc->not = cname;
	cc->cot = this;

	byte_offset = usz = boff;
	bit_offset = 0;
	
	int real_virts = 0;
	Pbase bt = new basetype(COBJ,cname);
	bt->b_table = memtbl;
	Ptype cct = bt->addrof();
	// for strict opt type of `this': X *const
	// '2' distinguishes this case from a real constant object
	if (strict_opt) Pptr(cct)->rdo = 2;
	this_type = cc->tot = cct;
	PERM(cct);
	PERM(bt);

	for (Pname px, p=mem_list; p; p=px) {
	/*
		look at each member;
		declare it and determine its visibility
		calculate offsets and sizes
	*/
		px = p->n_list;
// error( 'd', "p: %n %k n_scope: %d", p, p->base, p->n_scope );

		switch (p->base) {
		case PUBLIC:
			scope = PUBLIC;
			protect = 0;
			goto prpr;

		case PRIVATE:
			scope = 0;
			protect = 0;
			goto prpr;

		case PROTECTED:
			scope = 0;
			protect = PROTECTED;
		prpr:
			if (in_union == ANON) error(&p->where,"%k in anonymous unionD",p->base);
			continue;

		case PR:	// visibility control:	C::M
		{
			char* qs = p->n_qualifier->string;
			char* ms = p->string;
			TOK ppp = scope?PUBLIC:(protect?PROTECTED:PRIVATE);

			p->base = NAME;
			p->n_scope = scope;
			p->n_protect = protect;

			if (strcmp(ms,qs) == 0) ms = "__ct";

			ppbase = PUBLIC;

			if (is_base(qs) == 0) {
				error("%kQr %s not aBC of %s",ppp,qs,string);
				continue;
			}

			mex = 1;
			tcl = mec = this;
			c_body = 0; // this search must not be interpreted as a use
			Pname os = Cdcl;
			Cdcl = p;
			Pexpr ee = find_name(ms,0,1);
			Cdcl = os;
			c_body = 1;

// error('d', "ee: %k ", ee->base );

//			while (ee->base == MDOT || ee->base == REF) 
                        while (ee && (ee->base == MDOT || ee->base == REF))
				ee = ee->mem;
			Pname mx = Pname(ee);

// error('d', "ee: %k mx: %n", ee->base, mx );

			if (mx == 0) {
				error("C %s does not have aM %s",qs,ms);
				continue;
			}

			if (mx->tp->base == OVERLOAD) {
				error('s',"%k specification of overloaded%n",ppp,mx);
				continue;
			}

			TOK pp = mx->n_scope?PUBLIC:mx->n_protect?PROTECTED:PRIVATE;
			
// error('d',"mx %n pp %k ppp %k",mx,pp,ppp);
			if (ppp != pp) {
				error(&p->where,"%kM%n specified%k",pp,mx,ppp);
				continue;
			}	
			
		
			p->n_qualifier = mx;
			Pname m = memtbl->insert(p,0);
			m->base = PUBLIC;
			if (Nold) error("twoDs ofCM%n",p);
			continue;
		}
		}

// error('d',"mem%n tp %d %k scope %d",p,p->tp->base,p->tp->base,scope);

		if (scope==0) { 
			if (p->n_sto != STATIC) st = 0;
		}
		else 
		if ( p->tp->base == TYPE ) {
			Pname nn = p->tp->is_cl_obj();
			if (nn) { 
// error( 'd', "nn: %n %k tp %t %k", nn, nn->base, nn->tp, nn->tp->base );
                                if ((Pclass(nn->tp)->csu == CLASS) && (strcmp(this->string,nn->string))) st = 0;
			}
		}

		if (p->tp->base == FCT) {
			int ff = 0;
			Pfct f = Pfct(p->tp);
			Pblock b = f->body;
			f->body = 0;
			if (b) 
				f->f_inline = 1;
			/* restriction lifted: nested classes
			else
			if (nstd) 
				error((nstd==2)?0:'w',&p->where,"non-inlineMF%n in nestedC %s",p,string);
			*/
			else
			if (lex_level) 
				error('w',&p->where,"non-inlineMF%n in localC %s",p,string);

			switch (p->n_sto) {
			case FRIEND:
				ff = 1;
				break;
			case STATIC:	// accept static member functions
//error('d',"inline %d",f->f_inline);
			//	if (f->f_inline==0)
				/* restriction lifted: nested classes
				if (nstd) 
					error((nstd==2)?0:'w',"staticMF%n in nestedC %s",p,string);
				else
				*/
				if (lex_level) 
					error('w',"staticMF%n in localC %s",p,string);
				f->f_static = 1;
				p->n_sto = 0;
				break;
			case AUTO:
		//	case STATIC:
			case REGISTER:
			case EXTERN:
				error(&p->where,"M%n cannot be%k",p,p->n_sto);
				p->n_sto = 0;
			}

			if (f->f_virtual) real_virts++;

			Pname m = p->dcl(memtbl,scope);
			if (m == 0 || m->tp->base != FCT) continue;
                        if (m->n_initializer) {
                                c_abstract = 1;
                                if (m->n_oper == DTOR)
                                       error('w',"please provide an out-of-line definition: %n {}; which is needed by derived classes",m);
                        }
			if (ff == 0) m->n_protect = protect;
			if (b) {
				if (m->tp->defined&DEFINED || Pfct(m->tp)->body )
					error(&p->where,"two definitions of%n",m);
				else
					Pfct(m->tp)->body = b;
			//	Pfct(m->tp)->f_inline = 1;
			}
			if (ff==0 && p->where.line!=m->where.line)
				error(&p->where,"%n cannot be redeclared inCD",p);
		}
		else {
			Eppp = scope?scope:protect?protect:0;

			if (p->base == TNAME) {
				// typedef names are exported to
				// surrounding non-class scope
				// NOTE: name should actually be declared in
				//       the innermost block of the current
				//       function, but this info isn't available
				if ( cc->nof ) {
					if (p->tp && 
						Pbase(p->tp)->base != COBJ && 
						Pbase(p->tp)->base != EOBJ) {
							Pname n = cc->ftbl->look(p->string,0);
							if (n && n->base != TNAME && 
                                                                 n->lex_level &&
								n->tp != p->tp ) {
									error('s',"transitional model of nestedTs within%n (%s asTdef and%t)",cc->nof,p->string,n->tp); 
									error('i', "cannot recover from previous errors" );
							}
					}
					else p->dcl(cc->ftbl,scope);
				}
				else
					p->dcl(gtbl,scope);

				// typedefs need to be generated outside class
                                if ( p->tp && Pbase(p->tp)->base != COBJ ) {
                                        Pname n = gtbl->look(p->string,0);
					if ( n && lex_level == 0 && n->base != TNAME )
                                                error(&p->where,"%nredefined: identifier and typedef",p); 
                                	p->dcl_print(0);
                                }
                                continue;
                        };

			if (p->n_initializer) {
				error(&p->where,"Ir forM%n",p);
				p->n_initializer = 0;
			}

			if (p->tp->base==OVERLOAD) {
				for (Plist gl=Pgen(p->tp)->fct_list; gl; gl=gl->l) { 
					Pname nn = gl->f;
					Pfct ff = Pfct(nn->tp);
					if ( ff->f_virtual ) real_virts++;
				}
			}

// error('d',"lex_level %d p %n lex %d nested_scope: %k",lex_level,p,p->lex_level, nested_scope);

			TOK is_friend = p->n_sto;
			if ( lex_level && p->tp->base == VEC ) lcl_tbl = tbl;
			if ( protect && p->tp->base == COBJ && 
				Pclass(Pbase(p->tp)->b_name->tp)->csu == ANON ) 
					p->n_protect = protect;
			Pname m = p->dcl(memtbl,scope);
			lcl_tbl = 0;
			Eppp = 0;
			if (m == 0) continue;

			m->n_protect = protect;

			if (m->n_stclass==STATIC) {
				if (in_union) error("staticM%n in union",m);
				if ( is_friend != FRIEND ) {
					/* restriction lifted: nested classes
					if (nstd)
						error((nstd==2)?0:'w',"staticM%n in nestedC %s",m,string);
					else
					*/
					if (lex_level)
						error(strict_opt?0:'w',"staticM%n in localC %s (anachronism)",m,string);
				}
			//	Ptype t = m->tp;
			//	Pname cn = t->is_cl_obj();
			//	if ((cn && Pclass(cn->tp)->has_ctor())
			//	|| t->is_ref()
			//	|| (t->tconst() && vec_const == 0))
				m->n_sto = EXTERN;
				if (tbl == gtbl) stat_mem_list = new name_list(m,stat_mem_list);
				if (m->n_initializer) error('s',"staticM%nWIr",m);
			}

			if (in_union) {
				if (usz < byte_offset) usz = byte_offset;
				byte_offset = 0;
				if(in_union==ANON) m->n_offset+=byte_old;
			}
		}
	}

	/* restriction lifted: nested and local classes
	if (real_virts) {
		if (nstd)
			error((nstd==2)?0:'w',"nestedC%s contains%d virtualF",string,real_virts);
		else
		if (lex_level)
			error('w',"localC%s contains%d virtualF",string,real_virts);
	}
	*/

	if (st && csu==CLASS) csu = STRUCT;	// nothing private => STRUCT
	if (st==0 && csu==STRUCT) csu = CLASS;	// all is not public => CLASS

	if (in_union) byte_offset = usz;

	// now look look at the members

	Pname ct = has_ctor();
	Pname dt = has_dtor();

	int i;

	int omex = mex; mex = 0;
	Pname on = has_oper(NEW);
	Pname od = has_oper(DELETE);
	mex = omex;

	if (dt && ct==0 && Pfct(dt->tp)->f_virtual == 0 ) error('w',"%s has%n but noK",string,dt);
	if (on && od==0) error('w',"%s has%n but no operator delete()",string,on);
	if (od && on==0) error('w',"%s has%n but no operator new()",string,od);

	if (dt==0 && od && od && od->n_table==memtbl) make_dtor = 1;

	for (Pname m=memtbl->get_mem(i=1); m; m=memtbl->get_mem(++i) ) {
	/*
		The members have been declared.
		now look at each to see if it needs defining
	*/
		Ptype t = m->tp;

		if (t == 0) continue;	// public declarations
// error('d', "m %n %d", m, m->n_scope );

		switch (t->base) {
		default:
			if (ct==0
			&& m->n_stclass!=ENUM
			&& m->n_stclass!=STATIC) {
				if (t->is_ref()) error("R%n inC %sWoutK",m,string);
				if (t->tconst()
				&& vec_const==0
				&& m->n_evaluated==0)
					error("const%n inC %sWoutK",m,string);
			}
		case VEC:
			break;
		case FCT:
		case OVERLOAD:
		case CLASS:
		case ENUM:
			continue;
		}

		Pname cn = t->is_cl_obj();
		if (cn == 0) cn = cl_obj_vec;
		if (cn == 0) continue;

		Pclass cl = Pclass(cn->tp);
                c_xref |= cl->c_xref;
//error('d',"m %n %t %d",m,cl,cl->c_xref);
		if (cl->has_ctor()) {
			if (m->n_stclass == STATIC)
				; // error('s',"staticM%n ofC%nWK",m,cn);
			else if (in_union) {
				if (strncmp("__C",string,3) == 0)
				    error("M %s ofC%nWK in union",m->string,cn); // tagless union
				else error("M%n ofC%nWK in union",m,cn);
			}
			else if (ct == 0) {
				// does mctor have a default constructor?
				if (make_ctor==0 && cl->has_ictor()==0)
					error("%t needs aK; it has aMWK requiringAs",this);
				make_ctor = 1;
			}
		}

		if (cl->has_dtor()) {
			if (m->n_stclass==STATIC)
				; // error('s',"staticM%n ofC%nW destructor",m,cn);
			else if (in_union) {
				if (strncmp("__C",string,3) == 0) // tagless union
				    error("M %s ofC%nW destructor in union",m->string,cn);
				else error("M%n ofC%nW destructor in union",m,cn);
			}
			else if (dt==0)
				make_dtor = 1;
		}
	}

	if (has_dtor()==0 && make_dtor==0) {
		// can dtor be inherited (from single base class)?
		Pclass bcl = 0;
		for (Pbcl b = baselist; b; b = b->next) {
			switch (b->base) {
			case NAME:
				if (bcl == 0) {
					Pname d = b->bclass->has_dtor();
					if (d==0) break;
					if (strict_opt == 0) {
						if (d->n_scope==PUBLIC
						&& Pfct(d->tp)->f_virtual==0) {
							bcl = b->bclass;
							break;
						}
					}
				}
				// two dtors or non-public dtors force creation
                                make_dtor = 1;
                                goto zbzb;
                        case VIRTUAL:
                                if (b->bclass->has_dtor()) make_dtor = 1;
                                goto zbzb;
			}
		}
		if (bcl) c_dtor = bcl->has_dtor();
	zbzb:;
	}

	if (make_dtor && dt==0) {	// make x::~x() {}

		// must be done before vtbls are made in case dtor is virtual
//error('d',"%t: make_dtor",this);
		Pname n = new name(string);
		Pfct f = new fct(defa_type,0,1);
		f->f_inline = /*IDTOR; */ 1;
		n->tp = f;
		n->n_oper = DTOR;
		dt = n->dcl(memtbl,PUBLIC);
		delete n;
		Pfct(dt->tp)->body  = /*0; */ new block(curloc,0,0);
		dt = has_dtor();
	}

	if (virt_count && find_vptr(this)==0) {
		// we only need a vptr if this class has virtual
		// functions and none of its first bases have vptrs
//error('d',"%s virt_count %d",string,virt_count);
		Pname vp = new name("__vptr");
		vp->tp = Pvptr_type;
		(void) vp->dcl(memtbl,0);
		delete vp;
		c_xref |= C_VPTR;
	}
	else {
//error("byte_offset %d bit_offset %d bitsinbyte %d",byte_offset,bit_offset,BI_IN_BYTE);
//error("   div %d mod %d",bit_offset/BI_IN_BYTE,bit_offset%BI_IN_BYTE);
	    // no more bit fields. absorb bit_offset
	    if (bit_offset) {
		byte_offset += (bit_offset/BI_IN_BYTE + (bit_offset%BI_IN_BYTE?1:0));
		bit_offset = 0;
	    }
	}
//error("byte_offset %d bit_offset %d",byte_offset,bit_offset);

	for (Pbcl b = baselist; b; b = b->next) { // allocate virtual base pointers
		if (b->base != VIRTUAL) continue;
		Pclass bcl = b->bclass;

		// search non-virtual bases for this virtual base
		for (Pbcl bb = baselist; bb; bb = bb->next)
			if (bb->base == NAME) {
				for (Pbcl l = bb->bclass->baselist; l; l=l->next)
					if (l->base==VIRTUAL && l->bclass==bcl) goto eee;
			}
		{
		if (obj_align<AL_WPTR) obj_align = AL_WPTR;
		if (max_align<AL_WPTR) max_align = AL_WPTR;
		int waste = byte_offset%AL_WPTR;
		if (waste) byte_offset += AL_WPTR-waste;	// align
		b->ptr_offset = byte_offset+1;			// ensure != 0
		byte_offset += sizeof(int*);
		}
	eee:;
	}

	real_size = byte_offset;	// the rest may be optimized away

	for (b = baselist; b; b = b->next) {	// allocate virtual class objects
		if (b->base != VIRTUAL) continue;
		Pclass bcl = b->bclass;

		// if necessary
		if (b->obj_offset = has_allocated_base(bcl)) continue;

		int ba = bcl->align();
		if (obj_align<ba) obj_align = ba;
		if (max_align<ba) max_align = ba;
		int waste = byte_offset%ba;
		if (waste) byte_offset += ba-waste;	// align
		b->obj_offset = byte_offset;		// offset in this
		b->allocated = 1;
//error('d',"virtual %t in %t at %d",bcl,this,b->obj_offset);
		byte_offset += bcl->tsizeof();
	}

	// no more data members.
	// pad object (so that copying into a base object
	// doesn't destroy derevid class members):
	if (byte_offset==0) {	// empty struct: waste a member
		Pname c = new name (make_name('W'));
		c->tp = char_type;
		(void) c->dcl(memtbl,0);
		real_size = byte_offset = 1;
	}
	if (byte_offset < SZ_STRUCT) byte_offset = SZ_STRUCT;
	int waste = byte_offset%max_align;
//error('d',"max_align %d waste %d byte_offset %d",max_align,waste,byte_offset);
	if (waste) byte_offset += max_align-waste;
	obj_size = byte_offset;
	obj_align = max_align;

	// make vtbls
	// this cannot be done until the bases
	// have been allocated in this class
	// so that the offsets (deltas) are known
	if (all_virt(this,0,1,0)) {
		if (has_ctor()==0) make_ctor = 1;
	}
	else if (has_vvtab)
		error("virtualB: conflicting vtable initialization");

// error('d',"%t->classdef: virt_count: %d virt_merge: %d",this,virt_count,virt_merge);

	Pname hito = has_itor();

	if (hito) c_xref |= C_XREF;	// has user defined X(X&)
//error('d',"%t hito %d ctor %d",this,hito,make_ctor);
	if (hito==0 && c_xref&(C_VPTR|C_VBASE|C_XREF)) {
		// X(X&) needed if bitwise copy is illegal
		// or if any constructor is defined
		
		hito = make_itor(0);
			// if the base has B::B(void)
			// the derived should have D::D(void)
		if (baselist) {
			int mc = 1;	// can make and ictor
			for (Pbcl b = baselist; b; b = b->next) {
				if (b->bclass->has_ctor()
				&& b->bclass->has_ictor()==0)
						mc = 0;
			}
			make_ctor = mc;
/*
			int mc = 1;	// can make an ictor
			for (Pbcl b = baselist; b; b = b->next) {
				if (b->bclass->has_ctor()) {
					Pname c = b->bclass->has_ictor();
						// no copy constructor?
						// non-public copy constructor?
					if (c==0 || c->n_scope==0) mc = 0;
				}
			}
			make_ctor = mc;
*/
		}
		else
			make_ctor =  1;
	}

	if (c_ctor==0 && make_ctor==0) {	// can ctor be inherited (from single base class)?
/*
		int bb = 0;
		for (Pbcl b = baselist; b; b = b->next) {
			switch (b->base) {
			case NAME:
			{	Pname c = b->bclass->has_ctor();
			//	if (b->bclass->has_ctor() == 0) break;
				if (c == 0) break;
				if (c->n_scope==PUBLIC && bb++==0) break;
			}
				// no break: two bases: needs ctor
			case VIRTUAL:
				make_ctor = 1;	// virtual base: need ctor
				goto zaza;
			}
		}
*/
		Pname btor = 0;
		Pclass bc = 0;
		for (Pbcl b = baselist; b; b = b->next) {
			switch (b->base) {
			case NAME:
			{	Pname c = b->bclass->has_ctor();
				if (c == 0) break;
				if (c->n_scope==PUBLIC && b==baselist) {
					bc = b->bclass;
					btor = bc->has_ictor();
					break;
				}
			}
				// no break: two bases: needs ctor
			case VIRTUAL:
				make_ctor = 1;	// virtual base: need ctor
				goto zaza;
			}
		}
	//	c_ctor = btor;
//error('d',"btor %n",btor);
		if (bc) {
			if (btor)
				make_ctor = 1;
			else
				error("K needed for %s, BC%t hasK",string,bc);
		}
	zaza:;
	}

	if (make_ctor && ct==0) {	// make x::x() {}
//error('d',"%t: make_ctor",this);
		Pname n = new name(string);
		Pfct f = new fct(defa_type,0,1);
		f->f_inline = 1; // ICTOR; // ICTOR means ``define ctor() if used''
		n->tp = f;
		n->n_oper = TNAME;
		ct = n->dcl(memtbl,PUBLIC);
		delete n;
		Pfct(ct->tp)->body = /* 0; */ new block(curloc,0,0);
	}

	defined |= DEFINED;

	if (ansi_opt) {
		char* s = csu==UNION || csu==ANON ? "union" : "struct";
		fprintf(out_file,"%s %s;",s,string);
	}
//error('d',"defined %s",string);

	// fix argument lists for inlines
	for (p=memtbl->get_mem(i=1); p; p=memtbl->get_mem(++i)) {
		Pfct f = Pfct(p->tp);
		if (f==0) continue;	// public declarations

		switch (f->base) {
		case FCT:
			/* prohibit something like the following:
				typedef int t1;
				class x {
					typedef int t1;
					t1 foo();
				};
			*/
			if (f->returns->base == TYPE) {
				Pname nn = Pbase(f->returns)->b_name;
				while ( nn->tp->base == TYPE ) 
					nn = Pbase(nn->tp)->b_name;
				if (nn->n_key == NESTED) {
					Ptype tt;
					if ( nn->tp->base != EOBJ && 
						nn->tp->base != COBJ )
							tt = nn->tpdef;
					else  tt = Pbase(nn->tp)->b_name->tp; 
					if ( tt && tt->nested_sig )
						error('w',"nested %s as returnT for non-inlineMF, use %t::%s %n{} in definition (anachronism)",nn->string,tt->in_class,nn->string,p);
				}
			}

			if (hito && f->argtype) fix_args(f,this);
			if (p->n_oper == CTOR) f->s_returns = this_type;
			if (f->body) p->n_sto = STATIC;
			break;
		case OVERLOAD:
		{	Pgen g = Pgen(f);
			for (Plist gl=g->fct_list; gl; gl=gl->l) {
				Pname n = gl->f;
				Pfct f = Pfct(n->tp);

				if (hito && f->argtype) fix_args(f,this);
				if (n->n_oper == CTOR) f->s_returns = this_type;
				if (f->body) n->n_sto = STATIC;
			}
		}
		}
	}

	// define members defined inline
	for (p=memtbl->get_mem(i=1); p; p=memtbl->get_mem(++i)) {
		Pfct f = Pfct(p->tp);
		if (f==0) continue;	// public declarations

		switch (f->base) {
		case FCT:
			if (f->body) {
				f->dcl(p);
				p->simpl();
			}
			break;
		case OVERLOAD:
		{	Pgen g = Pgen(f);
			for (Plist gl=g->fct_list; gl; gl=gl->l) {
				Pname n = gl->f;
				Pfct f = Pfct(n->tp);

				if (f->body) {
					f->dcl(n);
					n->simpl();
				}
			}
		}
		}
	}

	byte_offset = byte_old;
	bit_offset = bit_old;
	max_align = max_old;

	cc->unstack();	// friends are not in class scope

	// fix arguments lists for friends defined inline 
	for (Plist fl=friend_list; fl; fl=fl->l) {
		Pname p = fl->f;
		Pfct f = Pfct(p->tp);

		switch (f->base) {
		case FCT:
			if (hito && f->argtype) fix_args(f,this);
			if (f->body &&
			   (f->defined&(DEFINED|SIMPLIFIED)) == 0) 
				p->n_sto = STATIC;
			else 
			if (p->n_scope == STATIC)
                        	error(strict_opt?0:'w',"static%n declared friend toC%t",p,this);
			break;
		case OVERLOAD:
		{	Pgen g = Pgen(f);
			for (Plist gl=g->fct_list; gl; gl=gl->l) {
				Pname n = gl->f;
				Pfct f = Pfct(n->tp);

				if (hito && f->argtype) fix_args(f,this);
				if (f->body &&
				   (f->defined&(DEFINED|SIMPLIFIED)) == 0) 
					n->n_sto = STATIC;
				else 
				if (p->n_scope == STATIC)
                                	error(strict_opt?0:'w',"static%n declared friend toC%t",p,this);
			}
		}
		}
	}

	// define friends defined inline and modify return types if necessary
	for (fl=friend_list; fl; fl=fl->l) {
		Pname p = fl->f;
		Pfct f = Pfct(p->tp);

		switch (f->base) {
		case FCT:
			if (f->body &&
			   (f->defined&(DEFINED|SIMPLIFIED)) == 0) {
				f->dcl(p);
				p->simpl();
			}
			break;
		case OVERLOAD:
		{	Pgen g = Pgen(f);
			for (Plist gl=g->fct_list; gl; gl=gl->l) {
				Pname n = gl->f;
				Pfct f = Pfct(n->tp);

				if (f->body &&
				   (f->defined&(DEFINED|SIMPLIFIED)) == 0) {
					f->dcl(n);
					n->simpl();
				}
			}
		}
		}
	}

	if (tbl != gtbl) this->simpl();

        if ( statStat && strcmp(statStat->string,string)==0) {
//error('d', "classdef::dcl: statstat: %n this %s", statStat, string);
                statStat->hide();
                statStat = 0;
        }
// error('d',"classdef::dcl defined: %d",defined);
	// catch refs to this class in body of nested class function
	// (i.e., ref to member of this class...)
	if ( (defined&REF_SEEN) != 0 ) dcl_print(0);

     if ( debug_opt ) {
	for (p=memtbl->get_mem(i=1); p; p=memtbl->get_mem(++i)) {
		Pfct f = Pfct(p->tp);
		if (f==0) continue;	// public declarations

		switch (f->base) {
			case FCT:
				if (f->body) {
					if ( c_body == 1 ) dcl_print(0);
					p->dcl_print(0);
				}
				break;
			case OVERLOAD: 
			{	
				Pgen g = Pgen(f);
				for (Plist gl=g->fct_list; gl; gl=gl->l) {
					Pname n = gl->f;
					Pfct f = Pfct(n->tp);
					if (f->body) {
						if ( c_body == 1 ) dcl_print(0);
						p->dcl_print(0);
					}
				}
			}
		}
	}

	for (fl=friend_list; fl; fl=fl->l) {
		Pname p = fl->f;
		Pfct f = Pfct(p->tp);

		switch (f->base) {
			case FCT:
				if (f->body &&
			   	   (f->defined&(DEFINED|SIMPLIFIED)) == 0) 
					p->dcl_print(0);
				break;
			case OVERLOAD:
			{	
				Pgen g = Pgen(f);
				for (Plist gl=g->fct_list; gl; gl=gl->l) {
					Pname n = gl->f;
					Pfct f = Pfct(n->tp);

					if (f->body &&
				   	   (f->defined&(DEFINED|SIMPLIFIED)) == 0) 
						p->dcl_print(0);
				}
			}
		}
	}
    } // end, if (debug_opt)
}

void enumdef::dcl(Pname n, Ptable tbl)
{
//	if (this == 0) error('i',"0->enumdef::dcl(%p)",tbl);
	Pname px;
	Pname p = mem;
	DB( if(Ddebug>=1) error('d',&n->where,"enumdef(%n,%d)",n,tbl); );
	Pbase b = new basetype(EOBJ,n);
	b->b_const = 1;

#define FIRST_ENUM 0
	int enum_count = FIRST_ENUM;
	no_of_enumerators = mem->no_of_names();
	int largest = 0;

	if (p == 0) mem = new name(make_name('e'));

	for (; p; p=px) {
		px = p->n_list;
// error( 'd', "p %n", p );
		if (p->n_initializer) {
			Pexpr i = p->n_initializer->typ(tbl);
			Neval = 0;
			long ii = i->eval();
			if (largest_int<ii) error("long enumerator");
			enum_count = int(ii);
			if (Neval) error("%s",Neval);
			DEL(i);
			p->n_initializer = 0;
		}
		p->n_evaluated = 1;
		largest |= enum_count;
		p->n_val = enum_count++;
		p->tp = b;

		Pname nn = tbl->insert(p,0);
		if (Nold) {
			if (nn->n_stclass == ENUM) {
			//	error( (p->n_val!=nn->n_val)?0:'w',"enumerator%n declared twice",nn);
		//	if (p->n_val!=nn->n_val)
			error("enumerator%n declared twice",nn);
			
			}
			else
				error("incompatibleDs of%n",nn);
		}
		else {
			nn->n_stclass = ENUM; // no store will be allocated
			if (Eppp == PROTECTED)
				nn->n_protect = PROTECTED;
			else if (Eppp == PUBLIC)
				nn->n_scope = PUBLIC;
		}
		p->string = nn->string;
//		delete p;
	}

//	mem = 0;

//	chose a shorter representation for the enum?
//	if (largest&0133 == largest)
//		e_type = char_type;
//	else if largest&077777 == largest)
//		e_type = short_type;
//	else
		e_type = int_type;

	defined |= DEFINED;
}


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

del.c:

	walk the trees to reclaim storage

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

#include "cfront.h"

void name::del()
{
	DB( if(Adebug>=1) {
		fprintf(stderr,"\n*** '%s'->del()",string?string:"???");
		display_type(tp); putc(' ',stderr);
		where.put(stderr); putc('\n',stderr);
	    }
	    if ( base!=NAME && base!=TNAME ) error('i',"name::del() of%k -- id==%ld",base,node::id);
	);
	Pexpr i = n_initializer;

// error('d', "\nname::del: %d %s", this, string?string:"no name" );
//	NFn++;
	DEL(tp);
	if(i && i!=(Pexpr)1) DEL(i);
	delete this;
}

void type::del()
{
	DB( if(Adebug>=1) {
		fprintf(stderr,"\n*** '");
		display_type(this);
		fprintf(stderr," '->del()\n");
	    }
	);
//fprintf(stderr,"DEL(type=%d %d)\n",this,base);
	permanent = 3;	/* do not delete twice */
	switch (base) {
	case TNAME:
	case NAME:
		error('i',"%d->T::del():N %s %d",this,Pname(this)->string,base);
	case FCT:
	{	Pfct f = (Pfct) this;
		DEL(f->returns);
		delete f;
		break;
	}
	case VEC:
	{	Pvec v = (Pvec) this;
		DEL(v->dim);
		DEL(v->typ);
		delete v;
		break;
	}
	case PTR:
	case RPTR:
	{	Pptr p = (Pptr) this;
		DEL(p->typ);
		delete p;
		break;
	}
	}
}

void expr::del()
{
	DB( if(Adebug>=1) {
		fprintf(stderr,"\n*** expr::del():  ");
		display_expr(this,0,1);
		if(Adebug>=2) display_expr(this);
	});
//fprintf(stderr,"DEL(expr=%d: %d %d %d)\n",this,base,e1,e2); fflush(stderr);
	permanent = 3;
	switch (base) {
	case IVAL:
		if (this == one) return;
	//case FVAL:
	case THIS:
	case ICON:
	case FCON:
	case CCON:
	case STRING:
	case TEXT:
		goto dd;
	case DUMMY:
	case ZERO:
	case NAME:
		return;
	case CAST:
	case SIZEOF:
	case NEW:
	case GNEW:
	case VALUE:
		DEL(tp2);
		break;
	case REF:
	case DOT:
		DEL(e1);
		if (e2) DEL(e2);
	case MDOT:
		if (mem && mem->base!=NAME) DEL(mem);
		if ( i1 == 5 ) delete string4;
		goto dd;
	case QUEST:
		DEL(cond);
		break;
	case ICALL:
		delete il->i_args;
		delete il;
		goto dd;
	case ELIST: { // limit recursion
		Pexpr tp = e2;
		while ( tp && tp->e2 && tp->e2->base == ELIST ) {
			Pexpr x = tp;
			if ( x->permanent ) break;
			x->permanent = 3;
			tp = tp->e2;
    			if ( x->e1 ) DEL(x->e1);
			delete x;
		}
		e2 = tp;
		break;
		}
	}

	DEL(e1);
	DEL(e2);
dd:
	delete this;
}

void stmt::del()
{
	DB( if(Adebug>=1) {
		fprintf(stderr,"\n*** stmt::del():  ");
		display_stmt(this,0,1);
		if(Adebug>=2) display_stmt(this);
	});
//fprintf(stderr,"DEL(stmt %d %s)\n",this,keys[base]); fflush(stderr);
	permanent = 3;
	switch (base) {
	case SM:
	case WHILE:
	case DO:
	case RETURN:
	case CASE:
	case SWITCH:
		DEL(e);
		break;
	case PAIR:
		DEL(s2);
		break;
	case BLOCK:
		DEL(d);
		DEL(s);
		if (own_tbl) DEL(memtbl);
		DEL(s_list);
		goto dd;
	case FOR:
		DEL(e);
		DEL(e2);
		DEL(for_init);
		break;
	case IF:
		DEL(e);
		DEL(else_stmt);
		break;
	}

	DEL(s);
	DEL(s_list);
dd:
	delete this;
}

void table::del()
{
// error('d',"\n*** %d::del() -- '%s'\n",this, t_name?t_name->string:"???");

	for (register i=1; i<free_slot; i++) {
		Pname n = entries[i];
		if (n==0) error('i',"table.del(0)");
		DB( if(Adebug>=2) { fprintf(stderr,"  name: '%s'",n->string);
			display_type(n->tp); putc('\n',stderr);
		});

// error( 'd',"\ntable::del: %s n_scope: %d, n_stclass: %d", n->string, n->n_scope, n->n_stclass );

		if (n->n_stclass == STATIC) continue;
		switch (n->n_scope) {
		case ARG:
		case ARGT:
			break;
		default:
		{	char* s = n->string;
			if (s && (s[0]!='_' || s[1]!='_' || s[2]!='X')) delete s;
			/* delete n; */
			n->del();
		}
		}
	}
	//delete entries;
	//delete hashtbl;
	delete this;
}

// local class
void delete_local() 
{
	DB( if(Adebug>=1) {
		fprintf( stderr, "delete_local: vlist: %d", vlist );
	});
// error( 'd', "delete_local: vlist: %d", vlist );
    do {
	for (vl* v = vlist; v; v = v->next) v->cl->really_print(v->vt);
	vlist = 0;

	for (Plist l=isf_list; l; l=l->l) {
		Pname n = l->f;
		Pfct f = Pfct(n->tp);
// error('d',"isf %n f %d",n,f);
		if ( f == 0 ) { error('d', "delete_local: f == 0" );break;} 
		if (f->base == OVERLOAD) {
			n = Pgen(f)->fct_list->f;	// first fct
			f = Pfct(n->tp);
		}

		if (debug_opt==0 && n->n_addr_taken) {
			f->f_inline = 0;
			if (n->n_dcl_printed<2) {
				if (warning_opt)
					error('w',"out-of-line copy of %n created",n);
				n->dcl_print(0);
			}
		}
	}
	//isf_list = 0;
    } while (vlist);

    for ( Plist l = local_class; l; l = l->l )
    {
          Pname n = l->f;
// error( 'd' , "delete_local() %d %n %t", n, n, n->tp );
    Pname nn = Pbase(n->tp)->b_name;
    Pclass cl = Pclass(nn->tp);
	for (Pname px, p=cl->mem_list; p; p=px) {
		px = p->n_list;
		if (p->tp)
		switch (p->tp->base) {
			case FCT:
			{	Pfct f = (Pfct)p->tp;
				if (f->body) {
 				    if (f->f_inline==0
				    && f->f_imeasure==0) {

					if (ansi_opt && f->f_this) {
						f->f_this->n_table = 0;
						for (Pname n=f->f_this->n_list; n; n=n->n_list) 
							n->n_table = 0;	
					}

					DEL(f->body);
					f->body = 0;
					}
				}
			}
			case COBJ:
			case EOBJ:
				DEL(p);
				break;
			case CLASS:
			case ENUM:
				break;
			default:
				delete p;
			} // end switch
		else delete p;
	} // end for mem
        DEL(cl->memtbl);
	cl->mem_list = 0;
	cl->permanent = 3;
        nn->permanent = 0;
	DEL(nn);
	n->permanent = 0;
	extern void table_delete( char*, TOK, int );
	table_delete( n->string, LOCAL, n->lex_level );
	DEL(n);
    }
}
0707071010112045761004440001630000160000010210600466055414200001200000013534discrim.c/* ident "@(#)ctrans:src/discrim.c	1.2" */
/************ add copyright **********************
 * union discriminator functions for nodes in cfront. 
 * all return 0 for none,
 *   -1 for bad union index, -2 for inconsistent
 *  or otherwise messed up nodes 
 */
#include "cfront.h"
#define DEFINE_TOKEN_CLASS_TABLE
#include "node_classes.h"

int basetype::discriminator(int which_union)
{
    switch(which_union)
    {
      case 0:
	switch(base) {
	  case FIELD: return 1;
	  case FCT: return 2;
	  default: return discrim_none_valid;
	}
      default:
	return discrim_bad_index;
    }
}

int fct::discriminator(int)
{
    return discrim_bad_index;
}

int expr::discriminator(int which_union)
{
    switch(which_union) {
      case 0:
	return 1;		/* tp, never syn_class */
      case 1:			/* e1, i1, string */
	switch(base) {
	  case DEREF:
	  case ICALL:
	  case REF:
	  case DOT:
	  case VALUE:
	  case SIZEOF:
	  case NEW:
	  case GNEW:
	  case DELETE:
	  case CAST:
	  case CALL:
	  case G_CALL:
	  case ASSIGN:
	  case EQ:
	  case NE:
	  case GT:
	  case GE:
	  case LE:
	  case LT:
	  case ELIST:
	  case ILIST:
	  case QUEST:
	  case CM:
	  case G_CM:
	  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 ASOR: 
	  case ASER: 
	  case ASAND:
	  case ASPLUS:
	  case ASMINUS:
	  case ASMUL:
	  case ASMOD:
	  case ASDIV:
	  case ASLS:
	  case ASRS:
	  case DECR:
	  case INCR:
	    return 1;
	  case MDOT:
	  case IVAL:
	    return 2;
	  case TNAME:
	  case NAME:
	  case ICON:
	  case FCON:
	  case CCON:
	  case ID:
	  case STRING:
	  case TEXT:
	    return 3;
	  default: return discrim_none_valid;
	}
      case 2:			/* e2, i2, string2, n_initializer */
	/* i2 is a complete mystery. It is set to 1,
	   and never referenced. But I'm not sure that
	   someone somewhere doesn't test one of the other
	   union elements for equal to 1, so therefore this test. */
	if(i2 == 1)return 2;
	switch(base) {
	  case DELETE:
	  case VALUE:
	  case ICALL:
	  case CALL:
	  case G_CALL:
	  case ASSIGN:
	  case EQ:
	  case NE:
	  case GT:
	  case GE:
	  case LE:
	  case LT:
	  case DEREF:
	  case ELIST:
	  case QUEST:
	  case CM:
	  case G_CM:
	  case UMINUS:
	  case NOT:
	  case COMPL:
	  case ADDROF:
	  case G_ADDROF:
	  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 ASOR: 
	  case ASER: 
	  case ASAND:
	  case ASPLUS:
	  case ASMINUS:
	  case ASMUL:
	  case ASMOD:
	  case ASDIV:
	  case ASLS:
	  case ASRS:
	  case DECR:
	  case INCR:
	  case NEW:	/*- the placement expression list hangs off e2 -*/
	    return 1;
	  case TEXT:
	    return 3;
	  case NAME:
	  case TNAME:
	    /* The n_initializer field is used for TNAMEs when describing base */
	    /* class initializations. The TNAME refers to the base class, and */
	    /* the actuals arguments are hung off the n_initializer list */
	    return 4;
	  default: return discrim_none_valid;
	}
      case 3:			/* tp2, fct_name, cond, mem, as_type, n_table, il, query_this */
	switch(base) {
	  case VALUE:
	  case SIZEOF:
	  case NEW:
	  case GNEW:	
	  case CAST:
	    return 1;
	  case CALL:
	  case G_CALL:
	    return 2;
	  case QUEST:
	    return 3;
	  case REF:
	  case DOT:
	  case MDOT: 
	    return 4;
	  case ASOR: 
	  case ASER: 
	  case ASAND:
	  case ASPLUS:
	  case ASMINUS:
	  case ASMUL:
	  case ASMOD:
	  case ASDIV:
	  case ASLS:
	  case ASRS:
	  case DECR:
	  case INCR:
	  case ASSIGN:
	    return 5;

	  case NAME:
	  case TNAME:
if (Pname(this)->n_oper==TYPE &&
(strcmp(Pname(this)->string, "_type")==0)) {
// error('d',"string %s n_oper: %k", string, Pname(this)->n_oper);
return 3;
}
	    return 6;

	  case ICALL:
	  case ANAME: 
	    return 7;

	  default: return discrim_none_valid;
	}
	    
      default:
	return discrim_bad_index;
    }
}

int name::discriminator (int which_union)
{
    switch(which_union) {
      case 0:			/* n_qualifier, n_realscope */
	if(base == LABEL) return 2;
	else return 1;
      default:
	return discrim_bad_index;
    }
}

int stmt::discriminator (int which_union)
{
    switch(which_union) {
      case 0:			/* d, e2, has_default, case_value, ret_tp */
	switch(base) {
	  case BLOCK:
	  case GOTO:
	  case LABEL:
	  case DCL:
	    return 1;
	  case FOR:
	    return 2;
	  case SWITCH:
	    return 3;
	  case PAIR:
	  case RETURN:
	    return 4;
	  default: return discrim_none_valid;
	}
      case 1:			/* e, own_tbl, s2 */
	switch(base) {
	  case FOR:
	  case IF:
	  case WHILE:
	  case DO:
	  case RETURN:
	  case SWITCH:
	  case SM:
	  case SM_PARAM:
	  case CASE:
	    return 1;
	  case BLOCK:
	    return 2;
	  case PAIR:
	    return 3;
	  default:
	    return discrim_none_valid;
	}
      case 2:			/* for_init, else_stmt, case_list */
	switch(base) {
	  case FOR:
	    return 1;
	  case IF:
	    return 2;
	  case SWITCH:
	  case CASE:
	    return 3;
	  default:
	    return discrim_none_valid;
	}
      default:
	return discrim_bad_index;
    }
}

static node_class token_to_class_map[DUMMY_LAST_NODE];
static char map_initialized;

node_class classify_node (Pnode node, int& error)
{
    int ncx;
    node_class nclass;

    error = 0;

    if (! map_initialized) {
	map_initialized = 1 ;
	for(ncx = 0; ncx < sizeof (token_classes) / sizeof (token_class);
	    ncx ++)
	    token_to_class_map[token_classes[ncx].token]
		= token_classes[ncx].nclass;
    }

    if (!((node->base > 0) && (node->base < DUMMY_LAST_NODE))) {
	error = 1;
	return nc_unused;
    }

    nclass = token_to_class_map[node->base];

    switch(nclass) {
      case nc_fct:
      case nc_name:
	if(node->baseclass) nclass = nc_baseclass;
    }

    return nclass;
}

node_class classify_node (Pnode node)
{
    int err;
    node_class nclass = classify_node (node, err);
    if(err) error ('i', "failed to classify node.");
    return nclass;
}
0707071010112045771004440001630000160000010210700466055414600001200000041601doprint.c/* ident "@(#)ctrans:src/doprint.c	1.2" */
/*
 ************* obviously, have to do something here!!!

 * Copyright (c) 1988 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/*
    $Header: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v 1.1.1.1 2018/04/24 17:21:35 root Exp $

    Copyright (c) 1989 by Object Design, Inc., Burlington, Mass.
    All rights reserved.

*/

#include <sys/types.h>
#include <stdarg.h>
#include <ctype.h>
#include <iostream.h>
#include <strstream.h>
#include <memory.h>
#include <math.h>
#include <string.h>
#include "print_self.h"

/* 11-bit exponent (VAX G floating point) is 308 decimal digits */
#define	MAXEXP		308
/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
#define	MAXFRACT	39

#define	DEFPREC		6

#define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */

#define	PUTC(ch)	(void) fp.put(ch)

#define	ARG() \
	_ulong = flags&LONGINT ? va_arg(argp, long) : \
	    flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);

#define	todigit(c)	((c) - '0')
#define	tochar(n)	((n) + '0')

#define	LONGINT		0x01		/* long integer */
#define	LONGDBL		0x02		/* long double; unimplemented */
#define	SHORTINT	0x04		/* short integer */
#define	ALT		0x08		/* alternate form */
#define	LADJUST		0x10		/* left adjustment */
#define	ZEROPAD		0x20		/* zero (as opposed to blank) pad */
#define	HEXPREFIX	0x40		/* add 0x or 0X prefix */


static char * exponent(char * p, int exp, u_char fmtch);
static char * round(double fract,
		    int * exp,
		    char * start,
		    char * end,
		    char ch,
		    char * signp);



static
cvt(double number,
    register int prec,
    int flags,
    char * signp,
    u_char fmtch,
    char * startp,
    char * endp)
{
    register char *p, *t;
    register double fract;
    int dotrim, expcnt, gformat;
    double integer, tmp;

    dotrim = expcnt = gformat = 0;
    fract = modf(number, &integer);

    /* get an extra slot for rounding. */
    t = ++startp;

    /*
	* get integer portion of number; put into the end of the buffer; the
	    * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
		*/
    for (p = endp - 1; integer; ++expcnt) {
	tmp = modf(integer / 10, &integer);
	*p-- = tochar((int)((tmp + .01) * 10));
    }
    switch(fmtch) {
    case 'f':
	/* reverse integer into beginning of buffer */
	if (expcnt)
	    for (; ++p < endp; *t++ = *p);
	else
	    *t++ = '0';
	/*
	    * if precision required or alternate flag set, add in a
		* decimal point.
		    */
	if (prec || flags&ALT)
	    *t++ = '.';
	/* if requires more precision and some fraction left */
	if (fract) {
	    if (prec)
		do {
		    fract = modf(fract * 10, &tmp);
		    *t++ = tochar((int)tmp);
		} while (--prec && fract);
	    if (fract)
		startp = round(fract, (int *)NULL, startp,
			       t - 1, (char)0, signp);
	}
	for (; prec--; *t++ = '0');
	break;
    case 'e':
    case 'E':
      eformat:	if (expcnt) {
	  *t++ = *++p;
	  if (prec || flags&ALT)
	      *t++ = '.';
	  /* if requires more precision and some integer left */
	  for (; prec && ++p < endp; --prec)
	      *t++ = *p;
	  /*
	      * if done precision and more of the integer component,
	  * round using it; adjust fract so we don't re-round
	      * later.
		  */
	  if (!prec && ++p < endp) {
	      fract = 0;
	      startp = round((double)0, &expcnt, startp,
			     t - 1, *p, signp);
	  }
	  /* adjust expcnt for digit in front of decimal */
	  --expcnt;
      }
	/* until first fractional digit, decrement exponent */
      else if (fract) {
	  /* adjust expcnt for digit in front of decimal */
	  for (expcnt = -1;; --expcnt) {
	      fract = modf(fract * 10, &tmp);
	      if (tmp)
		  break;
	  }
	  *t++ = tochar((int)tmp);
	  if (prec || flags&ALT)
	      *t++ = '.';
      }
      else {
	  *t++ = '0';
	  if (prec || flags&ALT)
	      *t++ = '.';
      }
	/* if requires more precision and some fraction left */
	if (fract) {
	    if (prec)
		do {
		    fract = modf(fract * 10, &tmp);
		    *t++ = tochar((int)tmp);
		} while (--prec && fract);
	    if (fract)
		startp = round(fract, &expcnt, startp,
			       t - 1, (char)0, signp);
	}
	/* if requires more precision */
	for (; prec--; *t++ = '0');

	/* unless alternate flag, trim any g/G format trailing 0's */
	if (gformat && !(flags&ALT)) {
	    while (t > startp && *--t == '0');
	    if (*t == '.')
		--t;
	    ++t;
	}
	t = exponent(t, expcnt, fmtch);
	break;
    case 'g':
    case 'G':
	/* a precision of 0 is treated as a precision of 1. */
	if (!prec)
	    ++prec;
	/*
	    * ``The style used depends on the value converted; style e
		* will be used only if the exponent resulting from the
		    * conversion is less than -4 or greater than the precision.''
			*	-- ANSI X3J11
			    */
	if (expcnt > prec || !expcnt && fract && fract < .0001) {
	    /*
		* g/G format counts "significant digits, not digits of
			 * precision; for the e/E format, this just causes an
			 * off-by-one problem, i.e. g/G considers the digit
			 * before the decimal point significant and e/E doesn't
			 * count it as precision."
			     */
	    --prec;
	    fmtch -= 2;		/* G->E, g->e */
	    gformat = 1;
	    goto eformat;
	}
	/*
	    * reverse integer into beginning of buffer,
	* note, decrement precision
	    */
	if (expcnt)
	    for (; ++p < endp; *t++ = *p, --prec);
	else
	    *t++ = '0';
	/*
	    * if precision required or alternate flag set, add in a
		* decimal point.  If no digits yet, add in leading 0.
		    */
	if (prec || flags&ALT) {
	    dotrim = 1;
	    *t++ = '.';
	}
	else
	    dotrim = 0;
	/* if requires more precision and some fraction left */
	if (fract) {
	    if (prec) {
		do {
		    fract = modf(fract * 10, &tmp);
		    *t++ = tochar((int)tmp);
		} while(!tmp);
		while (--prec && fract) {
		    fract = modf(fract * 10, &tmp);
		    *t++ = tochar((int)tmp);
		}
	    }
	    if (fract)
		startp = round(fract, (int *)NULL, startp,
			       t - 1, (char)0, signp);
	}
	/* alternate format, adds 0's for precision, else trim 0's */
	if (flags&ALT)
	    for (; prec--; *t++ = '0');
	else if (dotrim) {
	    while (t > startp && *--t == '0');
	    if (*t != '.')
		++t;
	}
    }
    return(t - startp);
}

static char * round(double fract,
		    int * exp,
		    char * start,
		    char * end,
		    char ch,
		    char * signp)
{
    double tmp;

    if (fract)
	(void)modf(fract * 10, &tmp);
    else
	tmp = todigit(ch);
    if (tmp > 4)
	for (;; --end) {
	    if (*end == '.')
		--end;
	    if (++*end <= '9')
		break;
	    *end = '0';
	    if (end == start) {
		if (exp) {	/* e/E; increment exponent */
		    *end = '1';
		    ++*exp;
		}
		else {		/* f; add extra digit */
		    *--end = '1';
		    --start;
		}
		break;
	    }
	}
    /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
    else if (*signp == '-')
	for (;; --end) {
	    if (*end == '.')
		--end;
	    if (*end != '0')
		break;
	    if (end == start)
		*signp = 0;
	}
    return(start);
}

static char * exponent(char * p, int exp, u_char fmtch)
{
    register char *t;
    char expbuf[MAXEXP];

    *p++ = fmtch;
    if (exp < 0) {
	exp = -exp;
	*p++ = '-';
    }
    else
	*p++ = '+';
    t = expbuf + MAXEXP;
    if (exp > 9) {
	do {
	    *--t = tochar(exp % 10);
	} while ((exp /= 10) > 9);
	*--t = tochar(exp);
	for (; t < expbuf + MAXEXP; *p++ = *t++);
    }
    else {
	*p++ = '0';
	*p++ = tochar(exp);
    }
    return(p);
}

int vostream_printf(const char *fmt0, va_list argp, ostream& fp)
{
    register const u_char *fmt;	/* format string */
    register int ch;		/* character from fmt */
    register int cnt;		/* return value accumulator */
    register int n;		/* random handy integer */
    register char *t;		/* buffer pointer */
    double _double;		/* double precision arguments %[eEfgG] */
    u_long _ulong;		/* integer arguments %[diouxX] */
    int base;			/* base for [diouxX] conversion */
    int dprec;			/* decimal precision in [diouxX] */
    int fieldsz;		/* field size expanded by sign, etc */
    int flags;			/* flags as above */
    int fpprec;			/* `extra' floating precision in [eEfgG] */
    int prec;			/* precision from format (%.3d), or -1 */
    int realsz;			/* field size expanded by decimal precision */
    int size;			/* size of converted field or string */
    int width;			/* width from format (%8d), or 0 */
    char sign;			/* sign prefix (' ', '+', '-', or \0) */
    char softsign;		/* temporary negative sign for floats */
    char *digs;			/* digits for [diouxX] conversion */
    char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */

    fmt = (const u_char *)fmt0;
    digs = "0123456789abcdef";
    for (cnt = 0;; ++fmt) {
	for (;(ch = *fmt) && ch != '%'; ++cnt, ++fmt)
	    PUTC(ch);
	if (!ch)return (cnt);

	flags = 0; dprec = 0; fpprec = 0; width = 0;
	prec = -1;
	sign = '\0';

      rflag:		switch (*++fmt) {
	case ' ':
	  /*
	   * ``If the space and + flags both appear, the space
	   * flag will be ignored.''
	   *	-- ANSI X3J11
	   */
	  if (!sign)
	      sign = ' ';
	  goto rflag;
	case '#':
	  flags |= ALT;
	  goto rflag;
	case '*':
	  /*
	   * ``A negative field width argument is taken as a
	   * - flag followed by a  positive field width.''
	   *	-- ANSI X3J11
	   * They don't exclude field widths read from args.
	   */
	  if ((width = va_arg(argp, int)) >= 0)
	      goto rflag;
	  width = -width;
	  /* FALLTHROUGH */
	case '-':
	  flags |= LADJUST;
	  goto rflag;
	case '+':
	  sign = '+';
	  goto rflag;
	case '.':
	  if (*++fmt == '*')
	      n = va_arg(argp, int);
	  else {
	      n = 0;
	      while (isascii(*fmt) && isdigit(*fmt))
		  n = 10 * n + todigit(*fmt++);
	      --fmt;
	  }
	  prec = n < 0 ? -1 : n;
	  goto rflag;
	case '0':
	  /*
	   * ``Note that 0 is taken as a flag, not as the
	   * beginning of a field width.''
	   *	-- ANSI X3J11
	   */
	  flags |= ZEROPAD;
	  goto rflag;
	case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
	  n = 0;
	  do {
	      n = 10 * n + todigit(*fmt);
	  } while (isascii(*++fmt) && isdigit(*fmt));
	  width = n;
	  --fmt;
	  goto rflag;
	case 'L':
	  flags |= LONGDBL;
	  goto rflag;
	case 'h':
	  flags |= SHORTINT;
	  goto rflag;
	case 'l':
	  flags |= LONGINT;
	  goto rflag;
	case 'c':
	  *(t = buf) = va_arg(argp, int);
	  size = 1;
	  sign = '\0';
	  goto pforw;
	case 'D':
	  flags |= LONGINT;
	  /*FALLTHROUGH*/
	case 'd':
	case 'i':
	  ARG();
	  if ((long)_ulong < 0) {
	      _ulong = -_ulong;
	      sign = '-';
	  }
	  base = 10;
	  goto number;
	case 'e':
	case 'E':
	case 'f':
	case 'g':
	case 'G':
	  _double = va_arg(argp, double);
	  /*
	   * don't do unrealistic precision; just pad it with
	   * zeroes later, so buffer size stays rational.
	   */
	  if (prec > MAXFRACT) {
	      if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
		  fpprec = prec - MAXFRACT;
	      prec = MAXFRACT;
	  }
	  else if (prec == -1)
	      prec = DEFPREC;
	  /*
	   * softsign avoids negative 0 if _double is < 0 and
	   * no significant digits will be shown
	   */
	  if (_double < 0) {
	      softsign = '-';
	      _double = -_double;
	  }
	  else
	      softsign = 0;
	  /*
	   * cvt may have to round up past the "start" of the
	   * buffer, i.e. ``intf("%.2f", (double)9.999);'';
	   * if the first char isn't NULL, it did.
	   */
	  *buf = NULL;
	  size = cvt(_double, prec, flags, &softsign, *fmt, buf,
		     buf + sizeof(buf));
	  if (softsign)
	      sign = '-';
	  t = *buf ? buf : buf + 1;
	  goto pforw;
	case 'n':
	  if (flags & LONGINT)
	      *va_arg(argp, long *) = cnt;
	  else if (flags & SHORTINT)
	      *va_arg(argp, short *) = cnt;
	  else
	      *va_arg(argp, int *) = cnt;
	  break;
	case 'O':
	  flags |= LONGINT;
	  /*FALLTHROUGH*/
	case 'o':
	  ARG();
	  base = 8;
	  goto nosign;
	case 'T':		// Type
	  {
	      streampos cur_pos;
	      streampos new_pos;

	      cur_pos = fp.tellp();

	      _Print_self * obj = va_arg (argp, _Print_self *);
	      obj->print_self (fp);

	      new_pos = fp.tellp();
		
	      cnt += int (new_pos - cur_pos);
	  }
	  break;

	case 'p':
	  /*
	   * ``The argument shall be a pointer to void.  The
	   * value of the pointer is converted to a sequence
	   * of printable characters, in an implementation-
	   * defined manner.''
	   *	-- ANSI X3J11
	   */
	  /* NOSTRICT */
	  _ulong = (u_long)va_arg(argp, void *);
	  base = 16;
	  goto nosign;
	case 's':
	  if (!(t = va_arg(argp, char *)))
	      t = "(null)";
	  if (prec >= 0) {
	      /*
	       * can't use strlen; can only look for the
	       * NUL in the first `prec' characters, and
	       * strlen() will go further.
	       */
	      char *p;

	      if (p = (char *) memchr(t, 0, prec)) {
		  size = p - t;
		  if (size > prec)
		      size = prec;
	      } else
		  size = prec;
	  } else
	      size = strlen(t);
	  sign = '\0';
	  goto pforw;
	case 'U':
	  flags |= LONGINT;
	  /*FALLTHROUGH*/
	case 'u':
	  ARG();
	  base = 10;
	  goto nosign;
	case 'X':
	  digs = "0123456789ABCDEF";
	  /* FALLTHROUGH */
	case 'x':
	  ARG();
	  base = 16;
	  /* leading 0x/X only if non-zero */
	  if (flags & ALT && _ulong != 0)
	      flags |= HEXPREFIX;

	  /* unsigned conversions */
	nosign:			sign = '\0';
	  /*
	   * ``... diouXx conversions ... if a precision is
	   * specified, the 0 flag will be ignored.''
	   *	-- ANSI X3J11
	   */
	number:			if ((dprec = prec) >= 0)
	    flags &= ~ZEROPAD;

	  /*
	   * ``The result of converting a zero value with an
	   * explicit precision of zero is no characters.''
	   *	-- ANSI X3J11
	   */
	  t = buf + BUF;
	  if (_ulong != 0 || prec != 0) {
	      do {
		  *--t = digs[_ulong % base];
		  _ulong /= base;
	      } while (_ulong);
	      digs = "0123456789abcdef";
	      if (flags & ALT && base == 8 && *t != '0')
		  *--t = '0';	/* octal leading 0 */
	  }
	  size = buf + BUF - t;

	pforw:
	  /*
	   * All reasonable formats wind up here.  At this point,
	   * `t' points to a string which (if not flags&LADJUST)
	   * should be padded out to `width' places.  If
	   * flags&ZEROPAD, it should first be prefixed by any
	   * sign or other prefix; otherwise, it should be blank
	   * padded before the prefix is emitted.  After any
	   * left-hand padding and prefixing, emit zeroes
	   * required by a decimal [diouxX] precision, then print
	   * the string proper, then emit zeroes required by any
	   * leftover floating precision; finally, if LADJUST,
	   * pad with blanks.
	   */

	  /*
	   * compute actual size, so we know how much to pad
	   * fieldsz excludes decimal prec; realsz includes it
	   */
	  fieldsz = size + fpprec;
	  if (sign)
	      fieldsz++;
	  if (flags & HEXPREFIX)
	      fieldsz += 2;
	  realsz = dprec > fieldsz ? dprec : fieldsz;

	  /* right-adjusting blank padding */
	  if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
	      for (n = realsz; n < width; n++)
		  PUTC(' ');
	  /* prefix */
	  if (sign)
	      PUTC(sign);
	  if (flags & HEXPREFIX) {
	      PUTC('0');
	      PUTC((char)*fmt);
	  }
	  /* right-adjusting zero padding */
	  if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
	      for (n = realsz; n < width; n++)
		  PUTC('0');
	  /* leading zeroes from decimal precision */
	  for (n = fieldsz; n < dprec; n++)
	      PUTC('0');

	  /* the string or number proper */

	  fp.write(t, size);

	  /* trailing f.p. zeroes */
	  while (--fpprec >= 0)
	      PUTC('0');
	  /* left-adjusting padding (always blank) */
	  if (flags & LADJUST)
	      for (n = realsz; n < width; n++)
		  PUTC(' ');
	  /* finally, adjust cnt */
	  cnt += width > realsz ? width : realsz;
	  break;
	case '\0':		/* "%?" prints ?, unless ? is NULL */
	  return (cnt);
	default:
	  PUTC(*fmt);
	  cnt++;
      }
    }
    /* NOTREACHED */
}

int ostream_printf(ostream& stream, const char * format ...)
{
    int ret;

    va_list args;
    va_start(args, format);
    ret = vostream_printf(format, args, stream);
    va_end(args);
    return ret;
}

// There are intended to be more convienient that stirring up
// an strstream by hand.

int printf_to_string (char * string, int length, const char * format ...)
{
    ostrstream& stream = ostrstream (string, length, (ios::open_mode)ios::app);

    va_list args;
    va_start(args, format);

    vostream_printf (format, args, stream);

    va_end(args);
    stream.str();
    return stream.pcount();
}

// caller of this must free() the string that comes back. 

char * printf_to_alloc_string (const char * format ...)
{
    ostrstream& stream = ostrstream ();

    va_list args;
    va_start(args, format);

    vostream_printf (format, args, stream);

    va_end(args);
    return stream.str();
}
0707071010112044141004440001630000160000010176000466055377500001000000031505error.c/*ident	"@(#)ctrans:src/error.c	1.4" */
/**************************************************************************

	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.

 error.c :

	write error messages

	Until scan_started != 0 no context can be assumed

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

#ifdef __cplusplus
#include <stdlib.h>
#endif

#include "cfront.h"
#include "size.h"
#include "template.h"

int error_count;
static int no_of_warnings;
char scan_started;

#define ERRTRACE    20

static char* abbrev_tbl[] = {
	" argument",
	" base",
	" class",
	" declaration",
	" expression",
	" function",
	" global",
	"H",
	" initialize",
	"J",
	" constructor",	// 'K' !
	" list",
	" member",
	" name",
	" object",
	" pointer",
	" qualifie",
	" reference",
	" statement",
	" type",
	" undefined",
	" variable",
	" with",
	" expected", // 'X'
	" template", // 'Y'???
	" parameter", // 'Z'???
};

ea* ea0;

void error_init()
{
	static char errbuf[BUFSIZ];
	setbuf(stderr,errbuf);
	ea0 = new ea;
}

#define INTERNAL 127

void ext(int n)
{
	int useit=n; // to avoid n not used warning during build
// for testing only
//	if (n == INTERNAL)
//	abort();
	exit(error_count?error_count:1);
}

/* static */ 
void print_loc()
{
	loc* sl = (Cstmt) ? &Cstmt->where : 0;
	loc* dl = (Cdcl && (Cdcl->base==NAME || Cdcl->base==TNAME)) ? &Cdcl->where : 0;
	if (sl && dl && sl->file==dl->file) {	// Cstmt and Cdcl in same file
		if (sl->line<=dl->line) {
			if (curloc.file==dl->file && curloc.line<dl->line)
				// hack to compensate for YACC's
				// bad manners in the use of line numbers
				sl->put(out_file);
			else
				dl->put(out_file);
		}
		else
			sl->put(out_file);
	}
	else if (sl && sl->file==curr_file)	// Cstmt in current file
		sl->put(out_file);
	else if (dl && dl->file==curr_file)	// Cdcl in current file
		dl->put(out_file);
	else
		curloc.put(out_file);
}

static void print_context()
{
	putc('\n',out_file);
}

static char in_error = 0;
static loc dummy_loc;

void yyerror(char* s)
{
	error(s);
}

int error(const char* s)
{
	return error(0,s);
}

int error(int t, const char* s)
{
	return error(t,&dummy_loc,s,*ea0,*ea0,*ea0,*ea0);
}

int error(const char* s, const ea& a0, const ea& a1, const ea& a2, const ea& a3)
{
	return error(0,&dummy_loc,s,a0,a1,a2,a3);
}

int error(loc* lc, const char* s, const ea& a0, const ea& a1, const ea& a2, const ea& a3)
{
	return error(0,lc,s,a0,a1,a2,a3);
}

int error(int t, const char* s, const ea& a0, const ea& a1, const ea& a2, const ea& a3)
{
	return error(t,&dummy_loc,s,a0,a1,a2,a3);
}

int suppress_error;

int error(int t, loc* lc, const char* s, const ea& a0, const ea& a1, const ea& a2, const ea& a3)
/*
	"int" not "void" because of "pch" in lex.c

	legal error types are:
		'w'		warning	 (not counted in error count)
		'd'		debug
		'D'		debug -- no prefix
		's'		"not implemented" message
		'l'		"compiler limit exceeded" message
    		0		error 
    		'i'		internal error (causes abort)
		't'		error while printing error message
*/
{
	if (suppress_error) return 0;

	if (in_error++)
		if (t == 't')
			t = 'i';
		else if (4 < in_error) {
			fprintf(stderr,"\nOops!, error while handling error\n");
			ext(13);
		}

	FILE * of = out_file;
	out_file = stderr;

	if (!scan_started || t=='t')
		putch('\n');
	else if (lc != &dummy_loc) {
		if(t != 'D') lc->put(out_file);
	} else {
		if(t != 'D') print_loc();
	}

	switch (t) {
    	case 0:
		putstring("error: ");
		break;
        case 'd':
		putstring("DEBUG: ");
        case 'D':
		break;
        case 'w':
		no_of_warnings++;
		putstring("warning: ");
		break;
        case 'l':
		putstring("compiler limit exceeded: ");
		break;
        case 's':
		putstring("sorry, not implemented: ");
		break;
        case 'i':
		if (error_count++) {
			fprintf(out_file,"sorry, %s cannot recover from earlier errors\n",prog_name);
			ext(INTERNAL);
		}
		else
			fprintf(out_file,"internal %s error: ",prog_name);
        }

	ea argv[4];
	ea* a = argv;
	argv[0] = a0;
	argv[1] = a1;
	argv[2] = a2;
	argv[3] = a3;

	int c;

	while (c = *s++) {
		if ('A'<=c && c<='Z')
			putstring(abbrev_tbl[c-'A']);
		else if (c == '%') {
			switch (c = *s++) {
			case 'k':	// TOK assumed passed as an int
			{	TOK x = TOK(a->i);
				if (0<x && x<=MAXTOK && keys[x])
					fprintf(out_file," %s",keys[x]);
				else
					fprintf(out_file," token(%d)",x);
				break;
			}
			case 't':	// Ptype 
			{	Ptype tt = Ptype(a->p);
				if (tt == 0) break;

				putch(' ');
			
				int nt = ntok;
				emode = 1;
				tt->dcl_print(0);
				emode = 0;
				ntok = nt;
				break;
			}
			case 'n':	// Pname
			{	Pname nn = Pname(a->p);
				if (nn && nn->string) {
					// suppress generated class names:
					if (nn->string[0]=='_'
					&& nn->string[1]=='_'
					&& nn->string[2]=='C') break;
					emode = 1;
					putch(' ');
					nn->print();
					emode = 0;
				}
				else
					putstring(" ?");
				break;
			}
			case 'p':	// pointer
			{	char* f = sizeof(char*)==sizeof(int)?" %d":" %ld";
				fprintf(out_file,f,a->p);
				break;
			}
			case 'c':	// char assumed passed as an int
				putch(a->i);
				break;

			case 'd':	// int
				fprintf(out_file," %d",a->i);
				break;

			case 'o':	// int
				fprintf(out_file," %o",a->i);
				break;

			case 's':	// char*
				char *s = ((char *)a->p);
				if ( s ) putst((char*)a->p);
				break;
			}
			a++;
		}
		else
			putch(c);
	}

/*
	switch (t) {
	case 'd':
	case 't':
	case 'w':
		putch('\n');
		break;
	default:
*/
		print_context();
/*
	}
*/

        templ_inst::head->print_error_loc();
	fflush(stderr);
	if (!scan_started && t!='d' && t!='w') ext(4);

        // now we may want to carry on 
	out_file = of;
	switch (t) {
	case 't':
		if (--in_error) return 0;
	case 'i': 
		ext(INTERNAL);
	case 0:
	case 'l':
	case 's':
		if (MAXERR<++error_count) {
			fprintf(stderr,"Sorry, too many errors\n");
			ext(7);
		}
	}

	in_error = 0;
	return 0;
}



#ifdef DBG
#define OPEREP(v) ((v)>MAXTOK || (v)<=0 ? 0 : keys[v])
void
display_type( Ptype t )
{
	if ( t ) { putc(' ',stderr);
		FILE * of = out_file;
		out_file = stderr;
		extern int ntok; int nt = ntok;
		emode=1; (t)->dcl_print(0); emode=0;
		//fprintf(stderr," <node %d",t->node::id);
		if(!t->allocated)fprintf(stderr," UNALLOCATED!");
		//putc('>',stderr);
		ntok = nt;
		out_file = of;
	} else fprintf(stderr," <null type>");
}
#define INDENT(in) { for ( int i = in;  i > 0;  --i ) fprintf(stderr,"  "); }
static indent = 0;

void
display_expr( Pexpr ptr, char* label, int oneline )
{
	INDENT(indent);
	if ( label ) fprintf(stderr, "%s:", label);
	if ( ptr == 0 ) {
		fprintf(stderr, "NULL EXPR\n" );
		return;
	}
	fprintf(stderr,"%d",ptr->node::id);
	if(!ptr->allocated)fprintf(stderr," UNALLOCATED!");
	putc(':',stderr);
	char* s = OPEREP(ptr->base);
	if ( s == 0 )
		fprintf(stderr, "token(%d)", ptr->base );
	else
		fprintf(stderr,"%s",s);
	if ( ptr->displayed ) { // recursion!!!
		if ( ptr->base == NAME )
			fprintf(stderr," '%s'",Pname(ptr)->string);
		fprintf(stderr,"   RECURSION!!!\n");
		ptr->displayed = 0;
		return;
	}
	ptr->displayed = 1;
	switch ( ptr->base ) {
	case QUEST:
		display_type(ptr->tp);
		putc('\n',stderr);
		if ( !oneline ) {
			++indent;
			display_expr( ptr->cond, "cond" ); 
			display_expr( ptr->e1, "e1" ); 
			display_expr( ptr->e2, "e2" ); 
			--indent;
		}
		break;
	case REF: case DOT:
		display_type(ptr->tp);
		putc('\n',stderr);
		if ( !oneline ) {
			++indent;
			display_expr( ptr->e1, "e1" );
			display_expr( ptr->mem, "mem" );
			--indent;
		}
		break;
	case MDOT:
		display_type(ptr->tp);
		fprintf(stderr," string2:'%s'\n",ptr->string2?ptr->string2:"");
		if ( !oneline ) {
			++indent;
			display_expr( ptr->mem, "mem" );
			--indent;
		}
		break;
	case ICALL:
		fprintf(stderr," fn=='%s'",ptr->il->fct_name->string);
		display_type(ptr->tp);
		putc('\n',stderr);
		if ( !oneline ) {
			++indent;
			for ( int i = 0;  i < ptr->il->i_slots;  ++i ) {
				ia *aa = &ptr->il->i_args[i];
				INDENT(indent);
				fprintf(stderr,"arg:'%s'",aa->local&&aa->local->string?aa->local->string:"");
				display_type(aa->tp);
				putc('\n',stderr);
				++indent;
				display_expr( aa->arg, "actual" );
				--indent;
			}
			display_expr( ptr->e1, "e1" );
			display_expr( ptr->e2, "e2" );
			--indent;
		}
		break;
	case SIZEOF:
		if ( ptr->tp2 ) {
			putc('(',stderr);
			display_type(ptr->tp2);
			putc(')',stderr);
		}
		display_type(ptr->tp);
		putc('\n',stderr);
		if ( !oneline ) {
		    if ( ptr->e1 ) {
			++indent;
			display_expr(ptr->e1,"e1");
			--indent;
		    }
		    if ( ptr->e2 ) {
			++indent;
			display_expr(ptr->e2,"e2");
			--indent;
		    }
		}
		break;
	case ZERO:
		display_type(ptr->tp);
		putc('\n',stderr);
		break;
	case NAME: case TNAME: case STRING:
	case ICON: case ID:
	case FCON: case CCON:
	case IVAL:
		fprintf(stderr," '%s'",(ptr->string)?ptr->string:"<0>");
		display_type(ptr->tp);
		if(ptr->string2)fprintf(stderr," string2=='%s'",ptr->string2);
		if ( ptr->permanent ) fprintf(stderr, " (permanent)");
		if ( ptr->base == IVAL ) fprintf(stderr, " i1==%d", ptr->i1);
		putc('\n',stderr);
		if ( !oneline && (ptr->base == NAME || ptr->base == TNAME) ) {
			Pname n = Pname(ptr);
			++indent;
			INDENT(indent);
			fprintf(stderr, "n_sto==%d", n->n_sto );
			fprintf(stderr, " n_stclass==%d",n->n_stclass);
			fprintf(stderr, " n_scope==%d",n->n_scope);
			fprintf(stderr, " n_protected==%d\n", n->n_protect );
			INDENT(indent);
			fprintf(stderr, "n_oper=='%s'", (s=OPEREP(n->base))?s:"0");
			fprintf(stderr, " n_val==%d", n->n_val );
			fprintf(stderr, " n_xref==%d",n->n_xref);
			fprintf(stderr, " lex_level==%d\n", n->lex_level );
			INDENT(indent);
			fprintf(stderr, "n_used==%d",n->n_used);
			fprintf(stderr, " n_assigned_to==%d",n->n_assigned_to);
			fprintf(stderr, " n_addr_taken==%d\n",n->n_addr_taken );
			INDENT(indent);
			fprintf(stderr, "n_union==%d", n->n_union);
			fprintf(stderr, " n_list=='%s'", n->n_list?n->n_list->string:"<0>" );
			fprintf(stderr, " n_qualifier=='%s'", n->n_qualifier?n->n_qualifier->string:"<0>" ); 
			if ( n->n_initializer ) {
				fprintf(stderr, " n_initializer:\n" );
				++indent;
				display_expr( n->n_initializer );
				--indent;
			} else fprintf(stderr, " n_initializer==<0>\n");
			--indent;
		}
		break;
	case BLOCK:
		((Pstmt)ptr)->where.put(stderr); putc(' ',stderr);
		putc('\n',stderr);
		break;
	default:
		display_type(ptr->tp);
		putc('\n',stderr);
		if ( !oneline && ptr->base > 0
		&&   (ptr->base<165 || ptr->base==MEMPTR) ) {
			++indent;
			display_expr( ptr->e1, "e1" ); 
			display_expr( ptr->e2, "e2" );
			--indent;
		}
		break;
	}
	ptr->displayed = 0;
	return;
}
void
display_stmt( Pstmt ptr, char* label, int oneline )
{
	INDENT(indent);
	if ( label ) fprintf(stderr, "%s:", label);
	if ( ptr == 0 ) {
		fprintf(stderr, "NULL STMT\n" );
		return;
	}
	fprintf(stderr,"%d",ptr->node::id);
	if(!ptr->allocated)fprintf(stderr," UNALLOCATED!");
	putc(':',stderr);
	char* s = OPEREP(ptr->base);
	if ( s == 0 )
		fprintf(stderr, "token(%d)", ptr->base );
	else
		fprintf(stderr,"%s",s);
	if ( ptr->displayed ) { // recursion!!!
		if ( ptr->base == NAME )
			fprintf(stderr," '%s'",Pname(ptr)->string);
		fprintf(stderr,"   RECURSION!!!\n");
		ptr->displayed = 0;
		return;
	}
	putc(' ',stderr);
	ptr->where.put(stderr);
	if ( oneline ) { putc('\n',stderr); return; }
	ptr->displayed = 1;
	switch ( ptr->base ) {
	case BLOCK:
		fprintf(stderr," .. ");
		ptr->where2.put(stderr);
		putc('\n',stderr);
		++indent;
		{ for( Pstmt st = ptr->s;  st;  st = st->s_list )
			display_stmt( ptr->s, "s" ); 
		}
		--indent;
		break;
	case IF:
		putc('\n',stderr);
		++indent;
		display_expr(ptr->e,"cond");
		display_stmt(ptr->s,"if-clause");
		--indent;
		if ( ptr->else_stmt ) {
			INDENT(indent);
			fprintf(stderr,"else\n");
			++indent;
			display_stmt(ptr->else_stmt,"else-clause");
			--indent;
		}
		break;
	case DO:
		putc('\n',stderr);
		++indent;
		display_stmt(ptr->s,"do-stmt");
		display_expr(ptr->e,"cond");
		--indent;
		break;
	case WHILE:
		putc('\n',stderr);
		++indent;
		display_expr(ptr->e,"cond");
		display_stmt(ptr->s,"while-stmt");
		--indent;
		break;
	case FOR:
		putc('\n',stderr);
		++indent;
		display_stmt(ptr->for_init,"init");
		display_expr(ptr->e,"cond");
		display_expr(ptr->e2,"incr");
		display_stmt(ptr->s,"stmt");
		--indent;
		break;
	case RETURN:
		putc('\n',stderr);
		++indent;
		display_expr(ptr->e,"e");
		--indent;
		break;
	case SM:
		putc('\n',stderr);
		++indent;
		display_expr(ptr->e,"e");
		--indent;
		break;
	default:
		putc('\n',stderr);
		break;
	}
	ptr->displayed = 0;
	return;
}

void
display_namelist( Plist nl, char* s, int verbose )
{
	error('d',"namelist:    %s",s?s:"");
	++indent;
	for ( Plist l = nl;  l;  l = l->l ) {
		Pname n = l->f;
		INDENT(indent);
		fprintf(stderr,"	%d",n);
		error('D'," %n %k n_key %d",n,n?n->tp->base:0,n?n->n_key:0);
		if ( verbose ) {
			++indent;
			display_expr(n);
			--indent;
		}
	}
	--indent;
}
#endif
0707071010112044151004440001630000160000010176300466055400100001100000053752expand.c/*ident	"@(#)ctrans: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"
static Ptable Scope;
// extern void display_expr(Pexpr);

static char* temp(char* vn, Pname fn)
//
//	make the name of the temporary: __Xvn00xxxxxx
//	xxxxxx is a representation of fn's address -
//	anything unique will do.  we use radix 32 here
//	add two bytes to make the name sensitive to the scope
//	to avoid re-using temps when an inline is expanded in
//	more than one other inline that is then called in the
//	same expression
//
{
	if (vn[0]!='_' || vn[1]!='_' || vn[2]!='X') {
		unsigned long a = (unsigned long) fn->tp;

		// al = the number of radix-32 chars in a
		unsigned long aa = a;
		int al = 0;
		while (aa) {
			al++;
			aa >>= 5;
		}

		// allocate memory for the result
		int ll = strlen(vn);
		char* s = new char[ll+al+8];
		register char* p = s;

		// append _ _ X vn
		*p++ = '_';
		*p++ = '_';
		*p++ = 'X';
		strcpy(p,vn);
		p += ll;
		*p++ = '0';
		*p++ = '0';

		// append representation of `a'
		while (a) {
			*p++ = "abcdefghijklmnopqrstuvwxyz012345"[a&037];
			a >>= 5;
		}

		// append scope representation and trailing null
		*p++ = 'a' + ((int(Scope)>>4)&15);
		*p++ = 'a' + ((int(Scope)>>8)&15);
		*p = '\0';
//tmp error('d',"temp(%s,%n) -- scope %d -- returning %s",vn,fn,scope,s);
		return s;
	}
	else {
//tmp error('d',"temp(%s,%n) -- scope %d -- returning %s",vn,fn,scope,vn);
		return vn;
	}

}

Pname dcl_local(Ptable scope, Pname an, Pname fn)
{
	if (scope == 0 || scope->base == 0) {
		if (sti_tbl == 0) sti_tbl = new table(8,gtbl,0);
		scope = sti_tbl;
	//	error('s',"cannot expand inlineF needing temporaryV in nonF context");
	//	return an;
	}

	if (an->n_stclass == STATIC) {
		if (an->tp->base!=FCT) error('s',&fn->where,"cannot expand inlineF with static%n",an);
		return an;
	}

	Pname cn = fn->n_table->t_name;
	char* s = temp(an->string,fn);
	Pname nx = new name(s);
	Ptype atp = an->tp;
//error('d',"dcl_local(%d,%n,%n) -> %s",scope,an,fn,s);
	while (atp->base == TYPE) atp = Pbase(atp)->b_name->tp;
	if (atp->base == VEC) {
		if (an->n_scope == ARG) {
			Pptr t = new ptr(PTR,Pvec(atp)->typ);
			nx->tp = t;
		}
		else {
			error('s',&fn->where,"cannot expand inlineF needing temporaryV of vectorT");
			return an;
		}
	}
	else
		nx->tp = atp;
	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;
	nx->n_xref = an->n_xref;
//error('d',"nx %n %t,",nx,nx->tp);
	Pname r = scope->look(nx->string,0);
	if (r) {
//error('d',"ll %n %t",ll,ll->tp);
		if (r->tp->check(nx->tp,0))
			error('s',&fn->where,"cannot expand inlineF %n with two local variables with the sameN (%s)",fn,an->string);
		else
			r = 0;
	}
	if (r==0) {
		r = scope->insert(nx,0);
//error('d',"%d %d %d %d",r->n_stclass,an->n_stclass,r->lex_level,an->lex_level);
		r->n_stclass = an->n_stclass;
		r->lex_level = an->lex_level;
		delete nx;
		r->where.line = 0;
	}
	return r;
}

int ck_cast(Ptype t1, Ptype t2)
/*
	return a value of type t2 from a function returning a t1
	return 1 if cast is needed
*/
{
st:
	while (t1->base == TYPE) t1 = Pbase(t1)->b_name->tp;
	while (t2->base == TYPE) t2 = Pbase(t2)->b_name->tp;

	if (t1 == t2) return 0;

	if (t1->base != t2->base) return 1;

	switch (t1->base) {
	case RPTR:
	case PTR:
	{	t1 = Pptr(t1)->typ;
		if (t1->base == VOID) return 1;
		t2 = Pptr(t2)->typ;
		goto st;
	}
	case CHAR:
	case SHORT:
	case INT:
	case LONG:
		if (Pbase(t1)->b_unsigned != Pbase(t2)->b_unsigned) return 1;
		break;
	case COBJ:
	{
		Pname nn = Pbase(t1)->b_name;

		if (Pclass(nn->tp)->csu==UNION ) return 0; 

		if (t2->base==COBJ && nn->tp==Pbase(t2)->b_name->tp) return 0;

		return 1;
	}
	}

	return 0;
}

int makeCM( Ptype t )
/* return 1 if the type is not a primitive type
 * this will cause the generation of (t,0) 
 * note: ``t'' is guaranteed not to be 0
 */
{
    while ( t->base == TYPE )
	t = Pbase(t)->b_name->tp;

    switch (t->base) {
	case FLOAT:
	case DOUBLE:
	case LDOUBLE:
	case CHAR:
	case SHORT:
	case INT:
	case LONG:
	case EOBJ:
		return 0;
	default: 
		return 1;
	}
}

static ret_seen = 0;

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->S::expand() for%n",expand_fn);
	Pstmt ostmt = Cstmt;
	if ( where.line ) Cstmt = this;

	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) {
				if (n->tp->base == FCT) continue;
				error('s',"cannot expand inlineF with static%n",n);
				n->n_stclass = AUTO;
			}
			n->where.line = 0;
		}
	}

	if (expand_tbl) {	/* make expression */
		Pexpr ee;

		if (memtbl) { // temporaries
			int i;
			for (Pname n=memtbl->get_mem(i=1); n; n=memtbl->get_mem(++i)) {
//error('d',"block %n %k %d %d",n,base,memtbl->real_block == this,n->lex_level);
				if (n->base!=NAME || n->tp==any_type) continue;

				if (base==BLOCK 
				&& memtbl->real_block == this 
				&& n->lex_level < 2
				&& (n->string[0]!='_'	// promoted from called
							// inlines
					|| n->string[1]!='_'
					|| (  n->string[2]!='X'
					   && n->string[2]!='K'))
				) {
//error('d',"not promoting%n",n);
					continue;
				}

 				if (memtbl != scope)
 				{
 			 		Pname nn = dcl_local(scope,n,expand_fn);
					nn->base = NAME;
					n->string = nn->string;
				}
				else if (n->tp->base!=FCT && n->tp->base!=OVERLOAD){
 					n->string = temp(n->string, expand_fn);
 					n->where.line = 0;
 				}
			}
		}

		switch (base) {
		default:
			error('s',"cannot expand inlineF%n with %kS in inline",expand_fn,base);
			Cstmt = ostmt;
			return Pstmt(dummy);

		case BLOCK:
DB(if(Edebug>=2){error('d',"stmt::expand() -- block");display_stmt(this);});
			if (s_list) {
				ee = Pexpr(s_list->expand());
				if (s) {
					ee = new expr(CM, Pexpr(s->expand()), ee);
					ee->tp = ee->e2->tp;
					PERM(ee);
				}
				Cstmt = ostmt;
				return Pstmt(ee);
			}

			if (s) {
				Pstmt st = s->expand();
				Cstmt = ostmt;
				return st;
			}

			Cstmt = ostmt;
			return Pstmt(zero);

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

		case RETURN:
			ret_seen = 1;
			s_list = 0;

			if (e == 0) 
				ee = zero;
			else {
				ee = e->expand();
				Ptype tt = Pfct(expand_fn->tp)->returns;
				if (tt == 0) tt = Pfct(expand_fn->tp)->returns;
//error('d',"return::expand() -- ee==%k  tt==%t",ee?ee->base:0,tt);
//display_expr(ee);
				if (tt!=ee->tp && ck_cast(tt,ee->tp)) ee = new cast(tt,ee);
			}
	
			Cstmt = ostmt;
			return Pstmt(ee);

		case SM:
			if (e== 0 || e==dummy)
				ee = zero;
			else {
				if (e->base == DEREF) e = e->e1;
				ee = e->expand();
			}
			// no break;

		case ASM:
			if (s_list) {
				ee = new expr(CM, ee, (Pexpr)s_list->expand());
				ee->tp = ee->e2->tp;
				PERM(ee);
			}
			Cstmt = ostmt;
			return (Pstmt)ee;

		case IF:
		{
			int ors = ret_seen;
			ret_seen = 0;
			ee = Pexpr(s->expand());
			if(ee->base==ASSIGN && ee->e1->tp &&
			    ee->e1->tp->base != PTR)
				ee = new expr(G_CM,ee,zero);
			Pexpr qq = new expr(QUEST,ee,zero);
			int ret1 = ret_seen;
			ret_seen = 0;

			qq->cond = e->expand();
			qq->e2 = else_stmt ? Pexpr(else_stmt->expand()) : zero;
			int ret2 = ret_seen; 
			if (ret1+ret2 && s_list) {
				error('s',"cannot expand inlineF%n with S after \"return\"",expand_fn);
				ret_seen = 0;
			}
			ret_seen += ret1;
			ret_seen += ret2;
			ret_seen += ors;

			// handle ``if (x) class_object_valued_expression;''

			Ptype t1 = qq->e1->tp;
			Ptype t2 = qq->e2->tp;

	if (t1 && t1->base==FCT)
		t1 = Pfct(t1)->s_returns ? Pfct(t1)->s_returns : Pfct(t1)->returns;

	if (t2 && t2->base==FCT)
		t2 = Pfct(t2)->s_returns ? Pfct(t2)->s_returns : Pfct(t2)->returns;

			Pname c1 = t1?t1->is_cl_obj():0;
			Pname c2 = t2?t2->is_cl_obj():0;

			int z1 = c1 && c1!=c2;
			int z2 = c2 && c1!=c2;

//error('d',"if()%k%t else%k%t",qq->e1->base,t1,qq->e2->base,t2);
//error('d',"c1%n c2%n %d %d",c1,c2,z1,z2);
//display_expr(qq);
			if (c1==0
			&& c2==0
			&& t1
			&& t2
			&& t2->check(t1,ASSIGN)
			&& t1->check(t2,ASSIGN)) {
				z1 = makeCM( t1 );
				z2 = makeCM( t2 );
				if ((z1 && ret1) || (z2 && ret2))
					error('s',"cannot expand inlineF with return in ifS");
			}

//error('d',"if()%k%t else%k%t",qq->e1->base,t1,qq->e2->base,t2);
//error('d',"c1%n c2%n %d %d",c1,c2,z1,z2);
//display_expr(qq);
			if (t1 && z1==0) {
				// since zero is acceptable to all pointer types
				// we need only ``fix'' z1 and z2 will take care
				// of itself
				z1 = t1->is_ptr_or_ref()
					&& t2
					&& t2->is_ptr_or_ref()
					&& t1->check(t2,0)
					&& !const_problem;
			}

//error('d',"if()%k%t else%k%t",qq->e1->base,t1,qq->e2->base,t2);
//error('d',"c1%n c2%n %d %d",c1,c2,z1,z2);
//display_expr(qq);
			if (z1) {
				Pexpr v = (z2==0 && (t2->is_ptr_or_ref())) ? new cast(t2,zero) : zero;
				qq->e1 = new expr(CM,qq->e1,v);
				qq->e1->tp = qq->e1->e1->tp;
			}

//error('d',"if()%k%t else%k%t",qq->e1->base,t1,qq->e2->base,t2);
//error('d',"c1%n c2%n %d %d",c1,c2,z1,z2);
//display_expr(qq);
			if (z2) {
				Pexpr v = (z1==0 && (t1->is_ptr_or_ref())) ? new cast(t1,zero) : zero;
				qq->e2 = new expr(CM,qq->e2,v);
				qq->e2->tp = qq->e2->e1->tp;
			}

//error('d',"if()%k%t else%k%t",qq->e1->base,t1,qq->e2->base,t2);
//error('d',"c1%n c2%n %d %d",c1,c2,z1,z2);
//display_expr(qq);
			if (s_list) {
				qq = new expr(CM,qq,Pexpr(s_list->expand()));
				qq->tp = qq->e2->tp;
			}
			else
				qq->tp = qq->e1->tp;
			PERM(qq);
			Cstmt = ostmt;
			return Pstmt(qq);
		}
		}
	}

	where.line = 0;

	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();
	case ASM:
		break;
//	case LABEL:
//	case GOTO:
	case RETURN:
//	case BREAK:
//	case CONTINUE:
		error('s',"cannot expand inlineF%n with %kS",expand_fn,base);
	}

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

Pexpr expr::expand()
{
	if (this == 0) error('i',"E::expand(0)");

	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]=='_' && s[2]=='X') break;
			Pname cn = expand_fn->n_table->t_name;
		//	n->string = temp(s,expand_fn->string,(cn)?cn->string:0);
			n->string = temp(s,expand_fn);
		}
	case DUMMY:
	case ICON:
	case FCON:
	case CCON:
	case IVAL:
	//case FVAL:
	//case LVAL:
	case STRING:
	case ZERO:
	case TEXT:
	case ANAME:
	case MDOT:
		break;
	case ICALL:
		if (expand_tbl && e1==0) {
			int ors = ret_seen;
			ret_seen = 0;
			Pname fn = il->fct_name;
			Pfct f = Pfct(fn->tp);
			if (f->f_expr==0
		// f->returns==void_type
		//	&& f->s_returns!=int_type
		//	&& fn->n_oper!=CTOR
			)
				error('s',&fn->where,"cannot expand value-returning inline%n with call of non-value-returning inline%n",expand_fn,fn);
		//	else
		//		error("inline%n called before defined",fn);
ret_seen = ors;
		}
		break;
	case SIZEOF:
	case CAST:
		if (tp2) PERM(tp2);
		goto rrr;
	case QUEST:
		cond = cond->expand();
	default:
		if (e2) e2 = e2->expand();
	case REF:
	case DOT:
	rrr:
		if (e1) e1 = e1->expand();
		break;
	}

	switch (base) {
	case CM:
	case G_CM:
		if (tp==0) tp=e2->tp;
	}

	PERM(this);
	return this;
}

int nin;

static int watch_out;
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 NAME:
		if (nin==0 && Pname(this)->n_table==gtbl) return 2;	// unsafe: aliasing
	case ZERO:
	case IVAL:
	//case FVAL:
	case ICON:
	case CCON:
	case FCON:
		return 0;
	case STRING:
		::watch_out = 1;
		return 0;
	case MDOT:
		return mem->not_simple();
	case SIZEOF:
		return (e1==0 || e1==dummy) ? 0 : e1->not_simple();
	case G_ADDROF:
	case ADDROF:
		return e2->not_simple();
	case CAST:
		return e1->not_simple();
	case DOT:
		::watch_out = 1;
		return e1->not_simple();
	case REF:
		::watch_out = 1;
		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 = 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:
			return (il->i_args[argno].local) ? 0 : il->i_args[argno].arg->not_simple();
		}
	bok:	error('i',"expand aname%n",this);
	case G_CM:
	case VALUE:
	case NEW:
	case GNEW:
	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;
	}
}

extern void uninline(Pname fn);
//extern Pname new_fct;	
//extern Pname del_fct;
extern Pstmt del_list;
extern Pstmt break_del_list;
extern Pstmt continue_del_list;
extern Pname curr_fct;
extern Pexpr init_list;

extern Pname make_default_ctor(Pclass cl);
void expand_itor(Pclass cl)
{
//error('d',"expand_itor(%t)",cl);
	Pexpr s2 = curr_expr;
	Pstmt s5 = del_list;
	Pstmt s6 = break_del_list;
	Pstmt s7 = continue_del_list;
	Pname s8 = curr_fct;
	Pexpr s9 = init_list;
	(void) cl->make_itor(1);
	curr_expr = s2;
	del_list = s5;
	break_del_list = s6;
	continue_del_list = s7;
	curr_fct = s8;
	init_list = s9;
}
/*
extern Pname make_default_dtor(Pclass cl);
void expand_dtor(Pclass cl)
{
//error('d',"expand_itor(%t)",cl);
	Pexpr s2 = curr_expr;
	Pstmt s5 = del_list;
	Pstmt s6 = break_del_list;
	Pstmt s7 = continue_del_list;
	Pname s8 = curr_fct;
	Pexpr s9 = init_list;
	(void) make_default_dtor(cl);
	curr_expr = s2;
	del_list = s5;
	break_del_list = s6;
	continue_del_list = s7;
	curr_fct = s8;
	init_list = s9;
}


void expand_ictor(Pclass cl)
{
//error('d',"expand_itor(%t)",cl);
	Pexpr s2 = curr_expr;
	Pstmt s5 = del_list;
	Pstmt s6 = break_del_list;
	Pstmt s7 = continue_del_list;
	Pname s8 = curr_fct;
	Pexpr s9 = init_list;
	(void) make_default_ctor(cl);
	curr_expr = s2;
	del_list = s5;
	break_del_list = s6;
	continue_del_list = s7;
	curr_fct = s8;
	init_list = s9;
}
*/
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
*/
{
	Scope = scope;
//error('d',"expand%s() body %d f_expr %d inline %d",fn->string,body,f_expr,f_inline);
	if (f_inline == ITOR) {
		Pexpr s1 = last_expanded;
		expand_itor(memof);
		last_expanded = s1;
		last_stmt = stmtno;
		this = Pfct(fn->tp);
		if (f_inline==0 && f_imeasure) {
			uninline(fn);
			return 0;
		}
	}

//error('d',"expand %n body %d f_expr %d defined %d",fn,body,f_expr,defined);
//error('d',"inline %d memtbl %d scope %d",f_inline,Pfct(fn->tp)->body->memtbl,scope);
//display_stmt(body);
	if ((body==0 && f_expr==0)			// before defined
	||  ((defined&SIMPLIFIED)==0)			// before simplified
	||  (Pfct(fn->tp)->body->memtbl==scope)		// while defining
	||  (f_inline>1)				// recursive call
	) {						// so don't expand
		if (warning_opt) error('w',"cannot inline%n in thisE",fn);
		if (fn->n_addr_taken++==0) fn->dcl_print(0);
		return 0;
	}

	if (fn->n_oper==CTOR) {
		Pclass cl = Pclass(fn->n_table->t_name->tp);
		if (cl->c_body == 3) cl->print_all_vtbls(cl);
	}

	Pin il = new iline;
	Pexpr ic = new texpr(ICALL,0,0);
	int ns = 0;
	for (Pname an = f_args; an; an=an->n_list) ns++;
	il->fct_name = fn;
	il->i_args = new ia[il->i_slots = ns];
	ic->il = il;
	ic->tp = s_returns ? s_returns : returns;
//	Pname at = (f_this) ? f_this : (f_result) ? f_result : argtype;
	Pname at = f_args;

	f_inline++;

	if (at) il->i_table = at->n_table;
	int i = 0;
	int not_simple = 0;	/* is a temporary argument needed? */

	for (Pname n=at; n; n=n->n_list, i++) {
		/*	check formal/actual argument pairs
			and generate temporaries as necessary
		*/

		if (ll == 0) error('i',"F::expand(%n):AX",fn);
		Pexpr ee;

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

		/* could be avoided when expanding into a block */
		il->i_args[i].local = 0;
		int s ;

 	// try to protect agains aliasing through pointers and references
	for (Pname m=at; m; m=m->n_list) {
		Pptr p;
		if (n!=m) {
		//	if ((p=m->tp->is_ptr()) || (p=m->tp->is_ref()))
			if (p=m->tp->is_ptr_or_ref())
				if (p->check(n->tp,0)==0 || p->typ->check(n->tp,0)==0) goto zxc;

		}
	}

		::watch_out = 0;
		int notsimple; notsimple = ee->not_simple();
		if ( notsimple==0 && ::watch_out && n->n_used > 1 ) goto zxc;
		if (n->n_assigned_to==FUDGE111
		&& ee!=zero
		&& notsimple==0) {
			if (ee && ee->e1 && (ee->e1->base == NAME) &&
			       (! strcmp (ee->e1->string,"this"))) goto zxc;
		}
		else if (n->n_addr_taken || n->n_assigned_to) 
			goto zxc;
		else if (s=notsimple) {
			if (/*n->n_used==0	// n_used not set for ``this''
			|| */1<s
			|| 1<n->n_used ) {	// not safe
		zxc:
			if (last_expanded && last_expanded==curr_expr && last_stmt==stmtno) {
				if (warning_opt)
					error('w',"%n not inlined, called twice in an expression",fn);
				f_inline--;
				delete il->i_args;
				delete il;
				if (fn->n_addr_taken++==0) fn->dcl_print(0);
				return 0;
			}
//error('d',"zxc %n %t ee %d %t",n,n->tp,ee->base,ee->tp);
			if (ee && ee->tp && (ee->tp->base==EOBJ) && ansi_opt) 
				; // do nothing
			else {
				Pname nn = dcl_local(scope,n,fn);
				nn->base = NAME;
				il->i_args[i].local = nn;
				++not_simple;
			//	if (nn->tp->is_ref()
			//	&& ee->tp
			//	&& ee->tp->is_ptr_or_ref()==0) ee = ee->address();
			}
			}
		}

		il->i_args[i].arg = ee;
		il->i_args[i].tp = n->tp;
	}
	
	Ptable tbl = body->memtbl;
	if (f_expr) {		// generate comma expression
		
		char loc_var = 0;

		/* look for local variables needing declaration: */
		for (n=tbl->get_mem(i=1); n; n=tbl->get_mem(++i) ) {
//error('d',"n %n %d",n,n->base);
//error('d',"loc %n %d %d %d",n,n->n_used,n->n_assigned_to,n->n_addr_taken);
			if (n->base==NAME	// don't re-declare the args
			&& (n->tp->base!=FCT && n->tp->base!=OVERLOAD)
			&& (n->n_used || n->n_assigned_to || n->n_addr_taken)) {
if (last_expanded && last_expanded==curr_expr && last_stmt == stmtno) {
	if (warning_opt) error('w',"cannot inline%n in thisE",fn);
	f_inline--;
	delete il->i_args;
	delete il;
	if (fn->n_addr_taken++==0) fn->dcl_print(0);
	return 0;
}
				Pname nn = dcl_local(scope,n,fn);
				nn->base = NAME;
				n->string = nn->string;

				loc_var++;
			}
		}

		if (i /*not_simple*/ || loc_var) {
			if(!curr_expr) curr_expr = dummy;
			last_expanded = curr_expr;
			last_stmt = stmtno;
		}

		Pexpr ex;
		if (not_simple) {
			Pexpr etail = ex = new expr(CM,0,0);
			for (i=0; i<il->i_slots; i++) {
				Pname n = il->i_args[i].local;
				if (n == 0) continue;
				Pexpr e = il->i_args[i].arg;
					// if used assign
					// otherwise (e.g. unused argument)
					// simply evaluate for sideeffects
				if (n->n_used
				|| n->n_assigned_to
				|| n->n_addr_taken) {
Pexpr mptr_assign(Pexpr n, Pexpr in);
				Pptr p1 = n->tp->is_ptr();
                                Pptr p2 = e->tp ? e->tp->is_ptr() : 0;
				if (p1 && p1->memof && p1!=p2) {
					switch (e->base) {
					case CM:
					case G_CM:
						e->e2 = mptr_assign(n,e->e2);
						break;
					case ICALL:
						break;
					default:
						e = mptr_assign(n,e);
					}
					etail->e1 = e;
				}
				else
					etail->e1 = new expr(ASSIGN,n,e);
				}
				else
					etail->e1 = e;
				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
			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);
				n->string = temp(n->string,fn);
			}
		}
		Pstmt ss;
		if (not_simple) {
			if(!curr_expr) curr_expr = dummy;
			last_expanded = curr_expr;
			last_stmt = stmtno;
			Pstmt st = new estmt(SM,curloc,0,0);
			st->where.line = 0;
			Pstmt stail = st;
			for (i=0; i<il->i_slots; i++) {
				Pname n = il->i_args[i].local;
				if (n == 0) continue;
				Pexpr e = il->i_args[i].arg;
				Pptr p1 = n->tp->is_ptr();
				Pptr p2 = e->tp->is_ptr();
				Pexpr mptr_assign(Pexpr n, Pexpr in);
				if (p1 && p1->memof && p1!=p2) {
					switch (e->base) {
					case CM:
					case G_CM:
						e->e2 = mptr_assign(n,e->e2);
						break;
					default:
						e = mptr_assign(n,e);
					}
					stail->e = e;
				}
				else
					stail->e = new expr(ASSIGN,n,e);
				if (--not_simple) {
					stail = stail->s_list = new estmt(SM,curloc,0,0);
					stail->where.line = 0;
				}
				else
					break;
			}
			stail->s_list = body;
			ss = new block(curloc,0,st);
			ss->where.line = 0;
		}
		else
			ss = body;
		ic->e2 = Pexpr(ss);
	}

	f_inline--;
//error('d',"expand%n -- returning%k", fn, ic?ic->base:0);
//display_expr(ic);
	return ic;
}
0707071010112044261004440001630000160000010177000466055400600000700000116316expr.c/*ident	"@(#)ctrans:src/expr.c	1.8" */
/***************************************************************************

	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.

expr.c:

	type check expressions

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

#include "cfront.h"
#include "size.h"

int const_save;
int const_ptr;
extern Ptype Pfct_type;

Pexpr expr::address()
{
// error('d',"address %k %d %s",base,base,base==NAME||base==ANAME?string:"?");
// error('d',"address e1 %d %k e2 %d %k", e1, e1?e1->base:0, e2, e2?e2->base:0); 
	switch (base) {
	case DEREF:
		if (e2 == 0) return e1;			// &*e	=> e
		break;
	case QUEST:					// &(a?b:c) => a?&b:&c
		e1 = e1->address();
		// no break;
	case G_CM:
		if ( e1 && e1->base == G_CALL &&
			e2 && e2->base == G_ADDROF)
			return this;
	case CM:
		e2 = e2->address();			// &(e1,e2) => (e1,&e2)
		tp = e2->tp;	//LLL
		return this;
	case INCR:
	case DECR:					// &(++a) => (++a,&a)
		if (e1) break;
		nin++;
		if (e2->not_simple()) error('s',"& of%k",base);
		nin--;
		e1 = new expr(base,0,e2);
		e2 = e2->address();
		base = G_CM;
		tp = e2->tp;
		return this;
	case ASSIGN:					// &(a=b) => ((a=b),&a)
	case ASPLUS:
	case ASMINUS:
	case ASMUL:
	case ASDIV:
	case ASMOD:
	case ASAND:
	case ASOR:
	case ASER:
	case ASLS:
	case ASRS:
		nin++;
		if (e1->not_simple()) error('s',"& of%k",base);
		nin--;
		Pexpr a = new expr(base,e1,e2);
		a->tp = a->e1->tp;
		base = G_CM;
		e1 = a;
		e2 = a->e1->address();
		tp = e2->tp;
		return this;

	case NAME:
		if (Pname(this)->n_stclass == REGISTER) error("& register%n",Pname(this));
		Pname(this)->take_addr();
		break;
	case CALL:
	case CAST:
	case NEW:
	case GNEW:
		if (tp && tp->is_ptr_or_ref()) {	// hack?
			return this;
		}
		break;
	}

	register Pexpr ee = new expr(G_ADDROF,0,this);
	if (tp) {					// tp==0 ???
		ee->tp = tp->addrof();

		switch (tp->base) {
		case PTR:
			Pptr(ee->tp)->memof = Pptr(tp)->memof;
			break;
		case FCT:
			if (Pfct(tp)->f_static==0)
			Pptr(ee->tp)->memof = Pfct(tp)->memof;
			break;
		case OVERLOAD:
			if (Pfct(Pgen(tp)->fct_list->f->tp)->f_static==0)
			Pptr(ee->tp)->memof = Pfct(Pgen(tp)->fct_list->f->tp)->memof;
		}
	}

	return ee;
}

Pexpr expr::contents()
{
//error('d',"deref %k %d %t",base,base,tp);
//	if (base==ADDROF || base==G_ADDROF) return e2;		// *&
	switch (base) {
	case ADDROF:
	case G_ADDROF:
		return e2;		// *&
	case ELIST:
//error('d',"contents of  elist");
		e1 = e1->contents();
		tp = e1->tp;
		return this;
	};

	register Pexpr ee = new expr(DEREF,this,0);
	if (tp) {			// tp==0 ???
		Ptype tt = tp;
		while (tt->base == TYPE) tt = Pbase(tt)->b_name->tp;
		ee->tp = Pptr(tt)->typ;
		Pname cn = ee->tp->is_cl_obj();
		if (cn) {
			Pclass cl = Pclass(cn->tp);
			if (cl->c_body==1) cl->dcl_print(0);	// look for first use of cl
		}
	}
	return ee;
}

static Pexpr 
make_postfix( Pexpr op ) 
{ // apply the postfix form of increment/decrement operator
	Pexpr e = op->e1->base==NAME?op->e1:op->e1->mem;
	for (Plist fl=Pgen(e->tp)->fct_list;fl; fl=fl->l) {
		Pname n = fl->f;
		Pfct f = Pfct(n->tp);
		if ((f->nargs==1 && f->f_this) ||
		    (f->nargs==2 && f->f_this==0)) {

			if (op->e1->base == NAME) {
				op->e1 = n;	
				op->e2->e2 = new expr(ELIST,zero,0);
			} else {
				op->e1->mem = n;  
				op->e2 = new expr(ELIST,zero,0); 
			}

			op->fct_name = n; 
			n->dcl_print(0); 
			return op;
		}
	}
	error('w',"no postfix instance of%n, although overloaded",Pname(e));
	return op; // as it were
}

int bound;
int chars_in_largest;	// no of characters in largest int
static Pclass mpglob;

Pexpr expr::typ(Ptable tbl)
/*
	find the type of "this" and place it in tp;
	return the typechecked version of the expression:
	"tbl" provides the scope for the names in "this"
*/
{
	//if (this == 0) error('i',"0->expr::typ");
	Pname n;
	Ptype t = 0;
	Ptype t1, t2;
	TOK b = base;
	TOK r1, r2;
#define nppromote(b)	t=np_promote(b,r1,r2,t1,t2,1)
#define npcheck(b)	(void)np_promote(b,r1,r2,t1,t2,0)
	if (tbl->base != TABLE) error('i',"expr::typ(%d)",tbl->base);

  	DB( if(Tdebug>=1) {
  		error('d',"%d->expr::typ(%d) %k %t",this,tbl,b,tp);
  		display_expr(this);
  	});
// error('d',"%k->typ %n tp: %t", b,b==NAME?this:0,tp);
// error('d',"     e1 %d %k e1 %d %k",e1,e1?e1->base:0,e2,e2?e2->base:0);

	if (tp) {
		switch (b) {
		case NAME:
//??			Pname(this)->use();
			break;
		case MDOT:
			mem = mem->typ(tbl);
		}	;
	//	if (b == NAME) Pname(this)->use();
		return this;
	}

extern Pname Ntmp;

	switch (b) {		// is it a basic type
	case MDOT:
		error('i',"mdot %s",string2);
	case DUMMY:
		error("emptyE");
		tp = any_type;
		return this;

	case ZERO:
		tp = zero_type;
		return this;

	case IVAL:
		tp = int_type;
		return this;

	//case FVAL:
	//	tp = float_type;
	//	return this;

	case ICON:
		/*	is it long?
			explicit long?
			decimal larger than largest signed int
			octal or hexadecimal larger than largest unsigned int
		 */
	{	int ll = strlen(string);
		switch (string[ll-1]) {
		case 'l':
		case 'L':
			switch (string[ll-2]) {
			case 'u':
			case 'U':
				string[ll-2] = 0;
				tp = ulong_type;
				goto cast_n_save;
			}
		lng:
			tp = long_type;
			goto save;
		case 'u':
		case 'U':			// 1u => unsigned(1)
			switch (string[ll-2]) {
			case 'l':
			case 'L':
				string[ll-2] = 0;
		ulng:
				tp = ulong_type;
				goto cast_n_save;
			default:
				string[ll-1] = 0;
		uint:
				tp = uint_type;
				goto cast_n_save;
			}
		}

		// no suffix - see if we can figure it out
		if  (string[0] == '0') {	// assume 8 bits in byte
			register index = 1;
			switch (string[1]) {
			case 'x':
			case 'X':
				while(string[++index]=='0') ;
				ll -= index;
				int HSZ = SZ_INT+SZ_INT;
				if(ll < HSZ) goto nrm;
				if(ll == HSZ)
					if(string[2]>='8') goto uint;
					else goto nrm;
				if(SZ_INT==SZ_LONG) break;
				HSZ = SZ_LONG+SZ_LONG;
				if(ll < HSZ) goto lng;
				if(ll == HSZ)
					if(string[2]>='8') goto ulng;
					else goto lng;
				break;
			default:   // OCTAL
				register IBITS = BI_IN_BYTE*SZ_INT;
				while(string[index]=='0') index++;
				register char x = string[index];
				int lbt = x=='1' ? 1 :
					( x=='2' || x=='3' ? 2 : 3 );
				int nbits = (ll-index-1)*3 + lbt;
				if(nbits < IBITS) goto nrm;
				if(nbits == IBITS) goto uint;
				if(nbits < BI_IN_BYTE*SZ_LONG) goto lng;
			}
			goto ulng;
		}
		else {  // DECIMAL
			if (ll<chars_in_largest) {
		nrm:
				tp = int_type;
				goto save;
			}
			if (ll>chars_in_largest) {
				if(SZ_INT==SZ_LONG || ll>2*chars_in_largest)
					goto ulng;
				goto lng;
			}
			// ll == chars_in_largest
			char* p = string;
			char* q = LARGEST_INT;
			do if (*p>*q) {
				if(SZ_INT==SZ_LONG) goto ulng;
				goto lng; 
			} while (*p++==*q++ && *p);
		}

		goto nrm;
	}
	case CCON:
		tp = c_strlen(string)<5 ? char_type : int_type;	// stored as 'a'
		goto save;

	case FCON:
	{	int ll = strlen(string);
		int last = string[ll-1];
		tp = double_type;
		if (last=='F' || last=='f') {
			tp = float_type;
			if (!ansi_opt) {
				string[ll-1] = 0;
				goto cast_n_save;
			}
		}
		else if (last=='L' || last=='l') {
			if (ansi_opt == 0) string[ll-1] = 0;
			tp = ldouble_type;
		}
		goto save;
	}
	case STRING:			// type of "as\tdf" is char[6]
					// c_strlen counts the terminating '\0'
	{	Pvec v = new vec(char_type,0);
		v->size = c_strlen(string);
		tp = v;
	}
	save:
		if (const_save) {	// "as\tdf" needs 7 chars for storage
			char* p = new char[strlen(string)+1];
			strcpy(p,string);
			string = p;
		}

		return this;

	cast_n_save:
		if (const_save) {	// "as\tdf" needs 7 chars for storage
			char* p = new char[strlen(string)+1];
			strcpy(p,string);
			string = p;
		}
		
		return new cast(tp,this);

	case THIS:
		delete this;
		if (cc->c_this) {
			cc->c_this->use();
			return cc->c_this;
		}
		error("``this'' used in nonC context");
		n = new name("this");
		n->tp = any_type;
		return tbl->insert(n,0); 

	case NAME:
	{	
		Pname q = Pname(this)->n_qualifier; // suppress virtual iff x::
		Pexpr ee = find_name(Pname(this),cc->cot,tbl,0,cc->nof);
		if (q && (ee->base==REF || ee->base==DOT))
			ee->n_initializer = Pexpr(q);
//error('d',"ee %k %t %n",ee->base,ee->tp,ee->base==NAME?ee:ee->base==REF?ee->mem:0);
	//	if (ee->tp->base == RPTR) return ee->contents();
		if (ee->tp->is_ref()) return ee->contents();

		if (ee->base==NAME && Pname(ee)->n_xref) {
		// fudge to handle X(X&) args
			ee = new expr(DEREF,ee,0);
			ee->tp = ee->e1->tp;	// !!
		}

		return ee;
	}

	case ADDROF:
	case G_ADDROF:	// handle lookup for &s::i
		mpglob = 0;
		if (e2->base == NAME) e2 = find_name(Pname(e2),cc->cot,tbl,ADDROF,cc->nof);
		if (e2->base==NAME && Pname(e2)->n_xref) {
			// fudge to handle X(X&) args
			e2 = new expr(DEREF,e2,0);
			e2->tp = e2->e1->tp;	// !!
		}
		if (e2->base==DOT) {	// &f().x  = > &(tmp=f(),&tmp)->x
			switch (e2->e1->base) {
			case CALL:
			case G_CALL:
			case VALUE:
				error("& non-lvalue");
			}
		}
		break;

	case SIZEOF:
		if (tp2) {	
			tp2->dcl(tbl);
			switch (tp2->base) {
			case VOID:
				error("sizeof(void)");
				break;
			case CLASS:
			{
				Pclass cl = Pclass(tp2);
				if (cl->c_body==1
				&& (cl->defined&(DEFINED|SIMPLIFIED)) == 0) 
					error('s',"class defined within sizeof");
			}
			}
	
			if (e1 && e1!=dummy) {
				e1 = e1->typ(tbl);
				DEL(e1);
				e1 = dummy;
			}
			Pptr r = tp2->is_ref();
			if (r) tp2 = r->typ;	// sizeof(T&)==sizeof(T)
		}
		else if (e1 == dummy) {
			error("sizeof emptyE");
			tp = any_type;
			return this;
		}
		else {
			e1 = e1->typ(tbl);
			tp2 = e1->tp;
			if(tp2->base == VEC) tp2->permanent = 1;
			if (e1->base==ILIST)	// PtoM
				e1 = dummy;
			else if (tp2 == char_type)	// sizeof ('a')
				e1 = dummy;
		}
		(void) tp2->tsizeof();
		tp = size_t_type;
		return this;

	case CAST:
//		return docast(tbl);

	{	Pexpr ee = docast(tbl);
		return ee->tp->is_ref() ? ee->contents() : ee;
	}


	case VALUE:
                if ( tp2->base == COBJ || tp2->base == EOBJ) {
                        char *s = Pbase(tp2)->b_name->string;
                        //Pname tn = gtbl->look( s, 0 );
			//??? non type name apparently takes precedence
			//    Don't use global ftn if it hides local
			//    class ctor.  (Note: More info is needed
			//    to detect all cases.)
                        Pname tn = tbl->look( s, 0 );
//error( 'd', "tn: %n %t lex_levels: %d %d", tn, tn?tn->tp:0, tn?tn->lex_level:0, Pbase(tp2)->b_name->lex_level );
			if ( tn && tn->n_qualifier == 0
			&&   tn->lex_level == Pbase(tp2)->b_name->lex_level
			&&   (tn->tp->base==FCT || tn->tp->base==OVERLOAD)) 
			{
                                Pexpr et = new expr( CALL, tn, e1 );
                                *this = *et;
                                b = CALL;
                                break;
			}
		}
		return dovalue(tbl);

	case NEW:
	case GNEW:
		return donew(tbl);

	case DELETE:	// delete e1 OR delete[e2] e1
	case GDELETE:
	{	int i;
		if (e1->base == ADDROF) error('w',"delete &E");
		e1 = e1->typ(tbl);
		i = e1->tp->num_ptr(DELETE);
		if (i != 'P') error("nonP deleted");
		if (e2) {
			e2 = e2->typ(tbl);
			e2->tp->integral(DELETE);
		}
		tp = void_type;
		return this;
	}

	case ILIST:	/* an ILIST is pointer to an ELIST */
		e1 = e1->typ(tbl);
		tp = any_type;
		return this;

	case ELIST:
	{	Pexpr e;
		Pexpr ex;

		if (e1 == dummy && e2==0) {
			error("emptyIrL");
			tp = any_type;
			return this;
		}
				
		for (e=this; e; e=ex) {
			Pexpr ee = e->e1;
//error('d',"e %d %d ee %d %d",e,e?e->base:0,ee,ee?ee->base:0);
			if (e->base != ELIST) error('i',"elist%k",e->base);
			if (ex = e->e2) {	/* look ahead for end of list */
				if (ee == dummy) error("EX in EL");
				if (ex->e1 == dummy && ex->e2 == 0) {
					/* { ... , } */
					DEL(ex);
					e->e2 = ex = 0;
				}
			}
			e->e1 = ee->typ(tbl);
			t = e->e1->tp;
			if (t->base == FCT) {	// yuk!
				ee = new expr(G_ADDROF,0,e->e1);
				e->e1 = ee->typ(tbl);
				t = e->e1->tp;
			}
		}
		tp = t;
		return this;
	}

	case DOT:
	case REF:
	{	if (e2) { // *. or ->*
			if (b == REF) b = base = REFMUL;
			break;
		}

		Pbase b;

		e1 = e1->typ(tbl);
		t = e1->tp;

		// check that . (->) is applied to class object (pointer)
		if (base == REF) {
		xxx:
			switch (t->base) {
			case TYPE:
				t = Pbase(t)->b_name->tp;
				goto xxx;
			case COBJ:
			{	Pname n = Pclass(Pbase(t)->b_name->tp)->has_oper(REF);
				if (n) {
					n->n_used += 2;
					e1 = new call(new ref(DOT,e1,n),0);
					return typ(tbl);
				}
				// no break;
			}
			default:
				error("nonP ->%n",mem);
				t = any_type;
				// no break;
			case ANY:
				goto qqq;
			case PTR:
			case VEC:
				b = Pbase(Pptr(t)->typ);
			}
		}
                else {  // base == DOT
		qqq:
			switch (t->base) {
			case TYPE:	t = Pbase(t)->b_name->tp;	goto qqq;
			default:	error("nonO .%n",mem); t = any_type;
			case ANY:
			case COBJ:	break;
			}
//error('d',"dot %k",e1->base);
			switch (e1->base) { 
			case QUEST:
			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:
			case CM:
			case G_CM:
				base = REF;
				e1 = e1->address();
				break;
                        case CALL:
                        case G_CALL:
//error('d'," f().  %n mem->tp %t",e1->fct_name,mem->tp);
#ifdef FDOTRIGHT
// this rewrite is only necessary on machines with broken C compilers
// there seems to be a lot of those
// and for inlines (a,b).c
                        if (e1->fct_name && Pfct(e1->fct_name->tp)->f_inline)
#endif
                        {       // f(). => (tmp=f(),&tmp)->
                                Pname tmp = make_tmp('Q',e1->tp,tbl);
//error('d',"fdot2 %k",e1->base);
                                e1 = init_tmp(tmp,e1,tbl);
                                Pexpr aa = tmp->address();
                                e1 = new expr(G_CM,e1,aa);
                                e1->tp = aa->tp;
                                base = REF;
                                break;
                        }
                        }
			b = Pbase(t);
		}

	xxxx:
		switch (b->base) {
		case TYPE:
			b = Pbase(b->b_name->tp);
			goto xxxx;
		default:
			error("(%t) before %k%n (%n not aM)",e1->tp,base,mem,mem);
		case ANY:
			tp = any_type;
			return this;
		case COBJ:
		{	Pclass cl = Pclass(Pbase(b)->b_name->tp);
			if (cl->c_body == 1) cl->dcl_print(0);
			break;
		}
		}	

/*
	x.m is not a const even if x is a const object, this case is handled
	by lval() rejecting it
*/

		if (mem->tp) {
			tp = mem->tp;
			for (Pexpr ee = mem; ee->base==REF; ee = ee->e1) {
				if (ee->e1 == cc->c_this) { // this-> => p->
					ee->e1 = e1;
					ee->base = base;
					return mem->tp->is_ref() ? mem->contents() : mem;
				}
			}

		//	return tp->base==RPTR ? contents() : this;
			return tp->is_ref() ? contents() : this;
		}

		
		Pname q = Pname(mem)->n_qualifier;
		Pexpr e = find_name(Pname(mem),Pclass(b->b_name->tp),0,base,cc->nof);		
		if (q && (e->base==REF || e->base==DOT))
			Pname(e)->n_initializer = Pexpr(q);
//error('d',"e %k %t %n",e->base,e->tp,e->base==NAME?e:e->base==REF?e->mem:0);	

		for (Pexpr ee = e; ee->base==REF; ee = ee->e1) {
			if (ee->e1 == cc->c_this) { // this-> => p->
				ee->e1 = e1;
				ee->base = base;
				break;
			}
		}

		if (e->base == NAME) {
			switch (e->tp->base) {
			case FCT:
			case OVERLOAD:
				mem = e;
				tp = e->tp;
				e = this;
			}
		}
			
			// function or static member
		return e->tp->is_ref() ? e->contents() : e;
	}

//??	case G_CALL:
	case CALL:	/* handle undefined function names */
//error('d',"call %k %t %k",e1->base,e1->tp,e2?e2->base:0);
		if (e1->base==NAME && e1->tp==0) {
			Pname q = Pname(e1)->n_qualifier;
			e1 = find_name(Pname(e1),cc->cot,tbl,CALL,cc->nof);
//error('d',"e1 %k %t %n",e1->base,e1->tp,e1->base==NAME?e1:e1->base==REF?e1->mem:0);
			if (q && (e1->base==REF ||e1->base==DOT)) // suppress virtual call
				e1->n_initializer = Pexpr(q);
		}

		if (e1->base==NAME && Pname(e1)->n_xref) {
			// fudge to handle X(X&) args
			e1 = new expr(DEREF,e1,0);
			e1->tp = e1->e1->tp;	// !!
		}

		switch (e1->base) {
		case DOT:
/*
#ifdef FDOTRIGHT
		{
//error('d',"fdot1 %k",e1->e1->base);
			switch (e1->e1->base) {
			case CALL:
			case G_CALL:	// f().g() => (tmp=f(),tmp.g())
			{	Pexpr ee = e1->e1;
				Pexpr ex = ee->typ(tbl);
				Pname tmp = make_tmp('Q',ex->tp,tbl);
				ex = init_tmp(tmp,ex,tbl);

				Pexpr ee2 = new expr(base,e1,e2);
				e1->base = DOT;
				e1->e1 = tmp;

				base = G_CM;
				e1 = ex;
				e2 = ee2;

				return typ(tbl);
			}
			}
			break;
		}
#endif
*/
		case REF:			// becomes ob.x::~x(0) or
			if (e2==0		// becomes p->x::~x(0)
			&& Pref(e1)->mem 
			&& Pref(e1)->mem->base==NAME
			&& Pname(Pref(e1)->mem)->n_oper==DTOR) {
				e1 = e1->typ(tbl);
				Pexpr ee = call_dtor(e1->e1,Pref(e1)->mem,0,e1->base,one);
				ee->tp = void_type;
				return ee;
			}
		}
		break;

	case QUEST:
		cond = cond->typ(tbl);
	case ANDAND:
	case OROR:
		Ntmp = 0;
	}

	if (e1) {
		e1 = e1->typ(tbl);
		if (e1->tp->is_ref()) e1 = e1->contents();
		t1 = e1->tp;
	//	if (t1->is_cl_obj()) t1->tsizeof();
	}
	else
		t1 = 0;

	if (e2) {
		e2 = e2->typ(tbl);
		if (e2->tp->is_ref()) e2 = e2->contents();
		t2 = e2->tp;
	//	if (t2->is_cl_obj()) t2->tsizeof();
	}
	else 
		t2 = 0;

// error('d',"b %k t1 %t t2 %t",b,t1,t2);
	switch (b) {	// filter out non-overloadable operators
	default:
	{	
		Pexpr x = try_to_overload(tbl);
		if (x) {
			if (b==INCR || b==DECR) {
				Pexpr fe = x->e1->base==NAME?x->e1:x->e1->mem;
				// by default, prefix version of operator is chosen
				// t2 set ==> ++n, t1 set ==> n++
				if (fe->tp->base==OVERLOAD && t2==0 && t1) 
					x=make_postfix(x);
			}	
			return x;
		}
//		if (x) return x;
// error('d',"e2: %t t2: %t", e2->tp, t2);
		if (t2 && t1==0 && t2!=e2->tp) t2 = e2->tp;
	}
	case DOT:
	case G_CM:
	case G_ADDROF:
	case G_CALL:
	case QUEST:
		break;
	}

	switch (b) {
	case QUEST:
	case ANDAND:
	case OROR:
		if (Ntmp) error('s',"temporary ofC%n with destructor needed in%kE",Ntmp,b);
	}

	t = (t1==0) ? t2 : (t2==0) ? t1 : 0;
// error('d', "expr::typ t %t", t );
// error('d',"b2 %d %k",b,b);
	switch (b) {		/* are the operands of legal types */
	case REFMUL:
		base = REF;
		// no break;
	case DOT:
	{	// a .* p => &a MEMPTR p => appropriate indirection
			// to be considered: what happens if a .* expression
			// is used except in a call/=?
		Pexpr a = e1->typ(tbl);
		Ptype at = a->tp;
		if (base == DOT) {
			a = a->address();
			at = at->addrof();	// beware of n_xref
		}

		while (at->base == TYPE) at = Pbase(at)->b_name->tp;
		Pname cn = Pptr(at)->typ->is_cl_obj();
		Pclass mm = cn ? Pclass(cn->tp) : 0;

		Pexpr p = e2->typ(tbl);
		Ptype pt = p->tp;
		Pname pcn = pt->is_cl_obj();

//error('d',"mm %t pt %t",mm,pt);
		if (pcn) {
			Pclass cl = Pclass(pcn->tp);
			Pname found = 0;
			for (Pname on=cl->conv; on; on=on->n_list) {
				Pfct f = Pfct(on->tp);
				Pptr frt = Pptr(f->returns);
				while (frt->base == TYPE) frt = Pptr(Pbase(frt)->b_name->tp);
				if (frt->base!=PTR || Pptr(frt)->memof==0) break;
				if (Pptr(frt)->memof==mm || mm->has_base(Pptr(frt)->memof)) {
					if (found)
						error("two possible conversions forP toM: %n and %n",found,on);
					else
						found = on;
				}
			}
//error('d',"found %n",found);
			if (found) {
				p = new ref(DOT,p,found);
				p = new call(p,0);
				p = p->typ(tbl);
				pt = p->tp;
			}
	
		}
		while (pt->base == TYPE) pt = Pbase(pt)->b_name->tp;
		if (pt->base!=PTR || Pptr(pt)->memof==0) {
			error("P toMX in .*E: %t",pt);
			tp = any_type;
			base = DUMMY;
			return this;
		}
		Pclass pm = Pptr(pt)->memof;

	//	while (at->base == TYPE) at = Pbase(at)->b_name->tp;
	//	Pname cn = Pptr(at)->typ->is_cl_obj();
	//	Pclass mm = cn ? Pclass(cn->tp) : 0;
//error('d',"mm %t %t %d %d",mm,pm,pm->baseof(mm),mm->has_base(pm));

	//	if (mm!=pm && pm->baseof(mm)==0 && mm->has_base(pm)==0) {
		if (mm != pm) {
			if (mm->has_base(pm) == 0) {
				error("badOT in .*E: %t (%s*X)",a->tp,pm->string);
				tp = any_type;
				//return this;
			}
			a = new texpr(CAST,pm->this_type,a);
			e1 = a = a->typ(tbl);
		}

		Ptype tpx = Pptr(pt)->typ;
		while (tpx->base == TYPE) tpx = Pbase(tpx)->b_name->tp;

		if (tpx->base == FCT) {	// a.*p => (&a MEMPTR p)
			base = MEMPTR;
			tp2 = mm;	// keep the class for simpl.c
			e1 = a;
			e2 = p;
		}
		else {	// a .* p => *(typeof(p))((char*)&a + (int)p-1)
			a = new cast(Pchar_type,a);
			p = new cast(int_type,p);
			p = new expr(MINUS,p,one);
			p->tp = int_type;
			Pexpr pl = new expr(PLUS,a,p);
			pl->tp = Pchar_type;
			base = DEREF;
			pt = new ptr(PTR,tpx);	// need a T* not a T C::*
			Pptr(pt)->rdo = Pptr(tpx)->rdo;
			mpglob = pm;
		//	PERM(pt);
			e1 = new cast(pt,pl);
			e2 = 0;
		}
		tp = tpx;
		return tp->is_ref() ? contents() : this;
	}

	case G_CALL:
	case CALL:
		tp = call_fct(tbl);	/* two calls of use() for e1's names */
		if (tp->is_ref()) return contents();
		return this;

	case DEREF:
		if (e1 == dummy) error("O missing before []\n");
		if (e2 == dummy) error("subscriptE missing");

		if (t) {	/*	*t	*/
			while (t->base == TYPE) t = Pbase(t)->b_name->tp;
		//	t->vec_type();
			if (t->base==PTR && Pptr(t)->memof) error("P toM dereferenced");
			tp = t->deref();
		}
		else {					// e1[e2] that is *(e1+e2)
//error('d',"deref %t[%t]",t1,t2);
			if (t1->vec_type()) {		// e1[e2]
				switch (t2->base) {
				case CHAR:
				case SHORT:
				case INT:
				case LONG:
				case EOBJ:
					break;
				default:
				{	Pname cn = t2->is_cl_obj();
					if (cn)	// conversion to integral?
						e2 = check_cond(e2,DEREF,tbl);
					else
						t2->integral(DEREF);
				}
				}
				while (t1->base == TYPE) t1 = Pbase(t1)->b_name->tp;
				if (t1->base==PTR && Pptr(t1)->memof) error("P toM dereferenced");
				tp = t1->deref();
				(void) tp->tsizeof();
			}
			else if (t2->vec_type()) {	// really e2[e1]
				t1->integral(DEREF);
				while (t2->base == TYPE) t2 = Pbase(t2)->b_name->tp;
				if (t2->base==PTR && Pptr(t2)->memof) error("P toM dereferenced");
				tp = t2->deref();
				(void) tp->tsizeof();
			}
			else {
				error("[] applied to nonPT:%t[%t]",t1,t2);
				tp = any_type;
			}
		}

		if (tp->is_ref()) return contents();

		return this;

	case G_ADDROF:
	case ADDROF:
//error('d',"addrof(%d) %k %d",base,e2->base,e2->base);
		switch (e2->base) {	// potential lvalues
		case G_CM:
			if (base==ADDROF && e2->e2->base==NAME) {
				// check for cfront generated result variable
				char* s = e2->e2->string;
				if (s[0]=='_' && s[1] && s[1]=='_') {
					if (s[2] && (s[2]=='R' || s[2]=='V')) {
						error("address of non-lvalue");
						break;
					}
				}
			}
		case CM:	// &(a,b) => (a,&b)
		{
			Pexpr ee = e2;
			ee->tp = 0;
			ee->e2 = new expr(base,0,ee->e2);
			delete this;
			return ee->typ(tbl);
		}
		case QUEST:	// & (a?b:c) => (a?&b:&c)
		{
			Pexpr ee = e2;
			ee->tp = 0;
			ee->e1 = new expr(base,0,ee->e1);
			ee->e2 = new expr(base,0,ee->e2);
			delete this;
			return ee->typ(tbl);
		}
		case INCR:
		case DECR:
			if (e2->e1) break;
		case ASSIGN:
		case ASPLUS:
		case ASMINUS:
		case ASMUL:
		case ASDIV:
		case ASMOD:
		case ASAND:
		case ASOR:
		case ASER:
		case ASLS:
		case ASRS:
			return e2->address();
		}

		if (e2->lval(ADDROF) == 0) {
			if (error_count) {	// error_count == 0 possible
						// in case of & const
				tp = any_type;
				return this;
			}
		}

		tp = t->addrof();

		if( base==ADDROF && mpglob)
			Pptr(tp)->memof = mpglob;

		if (e2->tp->base == VEC) {
			if(e2->base != NAME) {
				base = CAST;
				tp2 = tp;
				e1 = e2;
				e2 = 0;
				return this;
			}
		}

	//	tp = t->addrof();

		if (t->base==FCT) 
			Pptr(tp)->memof = Pfct(t)->memof;

//		if (t->tconst() && vec_const==0 && fct_const==0) Pptr(tp)->rdo = 1;
// ??? & (const T) is NOT T*const but const T*

		switch (e2->base) {
		case NAME:
		mname:					// check for &s::i
		{	Pname n2 = Pname(e2);
			Pname cn = (n2->n_table && n2->n_table!=gtbl) ? n2->n_table->t_name : 0;
// error('d',"n2 %k cn %n t %t",n2->base,cn,t);
			if (cn == 0) break;
		//	Pptr(tp)->memof = Pclass(cn->tp);

			if (t->base==FCT && Pfct(t)->f_this==0) {
				Pptr(tp)->memof = 0;
				break;
			}

			switch (t->base) {
			case OVERLOAD:
				return e2;
			case FCT:
// error('d', "cn->tp: %d, %k", cn->tp, cn->tp->base);
				Pptr(tp)->memof = Pclass(cn->tp); //SSS
				
				if (Pfct(t)->f_virtual)	{
					// { 0,vtbl index,0 }
					e1 = new ival(Pfct(t)->f_virtual);
					e1 = new expr(ELIST,zero,e1);
					e2 = zero;
					base = ILIST;
				//	tp = int_type;
					return this;
				}		// use the pointer
				
				// { 0,-1,(int(*)())ptr }
				e1 = new ival(-1);
				e1 = new expr(ELIST,zero,e1);
				// e2 is the name
				e2 = new cast(Pfct_type,e2);
				base = ILIST;
			//	tp = int_type;
				return this;

			//	return e2;

			default:
				if (n2->n_stclass != STATIC) {	// offset + 1
//error('d',"n2 %n %d",n2,n2->n_offset);
//error('d',"q %n cn %n",n2->n_qualifier,cn);
					e1 = new ival(n2->n_offset+1);
					Pptr(tp)->memof = Pclass(cn->tp);
//error('d',"cl %d %s i %d",Pclass(cn->tp),Pclass(cn->tp)?Pclass(cn->tp)->string:"0",n2->n_offset);
				}
				else
					return this;
			}
//error('d',"int_type");
			e1->tp = int_type;
			e2 = 0;
			tp2 = tp;
			base = CAST;
			return this;
		}
		case DOT:
                case REF:
                {       
                        Pname m = Pname(e2->mem);
// error( 'd', "e2->mem->base: %k", e2->mem->base );
//                      Pname m = (e2->mem->base == MDOT) ? Pname(e2->mem->mem) : Pname(e2->mem);
			while ( m->base == MDOT ) m = Pname(Pexpr(m)->mem);

			Pfct f = Pfct(m->tp);

			if (f->base == FCT || f->base == OVERLOAD) {  // &p->f
				Pexpr q = Pname(e2)->n_initializer;  // &p->x::f

				if (q && bound==0 && e2->e1==cc->c_this) {	
					// FUDGE: &this->x::f => &x::f
					DEL(e2);
					e2 = m;
					goto mname;
				}

				bound = 1;
				if(!f->f_static) {
					error(strict_opt?0:'w',
					    "address of boundF (try using ``%s::*'' forPT and ``&%s::%s'' for address) (anachronism)",
					    m->n_table->t_name->string,
					    m->n_table->t_name->string,
					    m->string
					);
				}

				if (q || f->f_virtual==0) {
					// & x.f  =>  & f
					DEL(e2);
					e2 = m;
				}
			}
			break;

		}
		case MEMPTR:
			// &(p->*q)
			error("& .* E");
		}

		return this;

	case UMINUS:
		t->numeric(UMINUS);
		tp = t;
		return this;

	case UPLUS:
		t->num_ptr(UPLUS);
		tp = t;
		if (ansi_opt==0) {
			base = PLUS;
			e1 = zero;
		}
		return this;

	case NOT:
		e2 = check_cond(e2,NOT,tbl);
		tp = int_type;
		return this;

	case COMPL:
		t->integral(COMPL);
		tp = t;
		return this;

	case INCR:
	case DECR:
		{
// error('d',"incr-decr: e1: %k e2: %k", e1?e1->base:0, e2?e2->base:0);
		Pexpr e = e1?e1:e2;	// e1!=0 ==> e++ or e--
					// e1==0 ==> ++e or --e

		e->lval(b);

		switch(e->base) {
		case QUEST:
			e->tp=0;
			e->e1 = e1 ? new expr(base,e->e1,0) : new expr(base,0,e->e1);
			e->e2 = e1 ? new expr(base,e->e2,0) : new expr(base,0,e->e2);
			delete this;
			return e->typ(tbl);
		case CM:
		case G_CM:
			e->tp=0;
			e->e2 = e1 ? new expr(base,e->e2,0) : new expr(base,0,e->e2);
			delete this;
			return e->typ(tbl);
		case INCR:
		case DECR:
			if(e->e1)
				break;
			nin++;
			if(e->e2->not_simple())
				error('s',"overly complex %k of %k",b,e->base);
			nin--;
			e = new expr(G_CM,e,e->e2->typ(tbl));
			if (e1) e1=e; else e2=e;
			// e1?e1:e2 = e;
			return typ(tbl);
		case ASSIGN:
		case ASPLUS:
		case ASMINUS:
		case ASMUL:
		case ASDIV:
		case ASMOD:
		case ASAND:
		case ASOR:
		case ASER:
		case ASLS:
		case ASRS:
			nin++;
			if(e->e1->not_simple())
				error('s',"overly complex %k of %k",b,e->base);
			nin--;
			e = new expr(G_CM,e,e->e1->typ(tbl));
			if (e1) e1=e; else e2=e;
			// e1?e1:e2 = e;
			return typ(tbl);
		}
		}

		r1 = t->num_ptr(b);
		if (r1='P' && t->check(Pvoid_type,0)==0) error("%k of void*",b);
		tp = t;
		return this;
	
	}

	if (e1==dummy || e2==dummy || e1==0 || e2==0) error("operand missing for%k",b);
	switch (b) {
	case MUL:
	case DIV:
		r1 = t1->numeric(b);
		r2 = t2->numeric(b);
		nppromote(b);
		break;

	case PLUS:
		r2 = t2->num_ptr(PLUS);
		r1 = t1->num_ptr(PLUS);
		nppromote(PLUS);
		goto void_check;

	case MINUS:
		r2 = t2->num_ptr(MINUS);
		r1 = t1->num_ptr(MINUS);
		if (r2=='P' && r1!='P' && r1!='A') error("nonP - P");
		nppromote(MINUS);
	void_check:
		if ((r1='P' && t1->check(Pvoid_type,0)==0) 
		||  (r2='P' && t2->check(Pvoid_type,0)==0))
			error("%k of void*",b);
		tp = t;
		break;

	case LS:
	case RS:
	case AND:
	case OR:
	case ER:
		switch (e1->base) {
		case LT:
		case LE:
		case GT:
		case GE:
		case EQ:
		case NE:
			error('w',"%kE as operand for%k",e1->base,b);
		}
		switch (e2->base) {
		case LT:
		case LE:
		case GT:
		case GE:
		case EQ:
		case NE:
			error('w',"%kE as operand for%k",e2->base,b);
		}
	case MOD:
		r1 = t1->integral(b);
		r2 = t2->integral(b);
		nppromote(b);
		break;

	case LT:
	case LE:
	case GT:
	case GE:
	case EQ:
	case NE:
		r1 = t1->num_ptr(b);
		r2 = t2->num_ptr(b);
		if (r1=='P' && r2=='I') {	// allow things like:
						// if (p==2-2)
						// YUCK!
			Neval = 0;
			long i = e2->eval();
			if (Neval==0 && i==0) {
				DEL(e2);
				e2 = zero;
				r2 = 'Z';
			}
		}
		else if (r2=='P' && r1=='I') {
			Neval = 0;
			long i = e1->eval();
			if (Neval==0 && i==0) {
				DEL(e1);
				e1 = zero;
				r1 = 'Z';
			}
		}

		if (b!=EQ && b!=NE) {
			if (r1=='P' && r2=='Z') error("P%k 0",b);
			if (r2=='P' && r1=='Z') error("P%k 0",b);
		}

		// make sure functions are properly converted to pointers to
		// functions and make sure overloaded functions are rejected
		Pexpr ptof(Pfct ef, Pexpr e, Ptable tbl);
		if (r1 == FCT) e1 = ptof(0,e1,tbl);
		if (r2 == FCT) e2 = ptof(0,e2,tbl);

		npcheck(b);

		if (r1=='P') { // need cast for pointers to virtual and second bases
			Pptr p1 = t1->is_ptr();
			Pptr p2 = t2->is_ptr();
			Pname cn = p1?p1->typ->is_cl_obj():0;
			Pname cn2 = p2?p2->typ->is_cl_obj():0;

			if (cn && cn2) {
				Pclass cl = Pclass(cn->tp);
				Pclass cl2 = Pclass(cn2->tp);

				if (cl->has_base(cl2)) {
					e1 = cast_cptr(cl2,e1,tbl,0);
					e1 = new cast(p2,e1);
				}
				else if (cl2->has_base(cl)) {
					e2 = cast_cptr(cl,e2,tbl,0);
					e2 = new cast(p1,e2);
				}
			}
		}

		if (r1=='P' && t1->memptr()) {
		mpmp:
			if (r2=='Z') {
				e2 = zero;
				e1 = new mdot("i",e1);
				e1->i1 = 9;
			}
			else if (r2=='P' && t2->memptr()) {
				// ERROR: no check for sideeffects
				Pexpr i1 = new mdot("i",e1);
				Pexpr i2;
				i1->i1 = 9;

				i2 = e2;
				while ( i2->base == CAST )
				    i2 = i2->e1;
				if ( i2->base == ILIST )
				    e2 = i2;

				if (e2->base==ILIST)
					i2 = e2->e1->e2;
				else {
					i2 = new mdot("i",e2);
					i2->i1 = 9;
				}

				Pexpr f1 = new mdot("f",e1);
				Pexpr f2;
				f1->i1 = 9;
				if (e2->base == ILIST)
				//	f2 = new cast(Pfct_type,e2->e2);
					f2 = e2->e2;
				else {
					f2 = new mdot("f",e2);
					f2->i1 = 9;
				}

				Pexpr ei = new expr(base,i1,i2);
				Pexpr fi = new expr(base,f1,f2);

				base = ANDAND;
				e1 = ei;
				e2 = fi;
			} else if (r2=='P') {
				error('s',"%t %k %t",t1,base,t2);
			}
		}
		else if (r2=='P' && t2->memptr()) {
			Pexpr ee = e1;	// swap
			e1 = e2;
			e2 = ee;
			int rr = r1;
			r1 = r2;
			r2 = rr;
			Ptype tt = t1;
			t1 = t2;
			t2 = tt;
			goto mpmp;
		}
		t = int_type;
		break;

	case ANDAND:
	case OROR:
		e1 = check_cond(e1,b,tbl);
		e2 = check_cond(e2,b,tbl);
		t = int_type;
		break;

	case QUEST:
		{
		Pname c1, c2;
		cond = check_cond(cond,b,tbl);
//error('d',"cond %k %t",cond->base,cond->tp);
//error('d',"t1 %t t2 %t",t1,t2);

		// still doesn't do complete checking for possible conversions...

		bit MPTR = 0; // local hack

		extern int suppress_error;                      // global hack
		suppress_error++;
		r1 = t1->num_ptr(b);
		r2 = t2->num_ptr(b);
		suppress_error--;
if (r1=='P' && r2=='P' && t1->memptr() && t2->memptr()) {

		++MPTR; // prevent later sorry

		// watch for casts
		Pexpr tt = e1;
		while ( tt->base == CAST ) tt = tt->e1;
		if ( tt->base == ILIST ) e1 = tt; 

		tt = e2;
		while ( tt->base == CAST ) tt = tt->e1;
		if ( tt->base == ILIST ) e2 = tt; 

		// cannot have sides return (expr?{}:{})
		// reuse same temp for both sides ?:
		Pname temp = make_tmp( 'A', mptr_type, tbl );

		e1 = mptr_assign( temp, e1 );
		e1 = new expr( G_CM, e1, temp );
		e1->tp = temp->tp;

		e2 = mptr_assign( temp, e2 );
		e2 = new expr( G_CM, e2, temp );
		e2->tp = temp->tp;
}

		if (t1==t2
		|| (	(c1=t1->is_cl_obj())
			&& (c2=t2->is_cl_obj())
			&& (c1->tp==c2->tp)
		))
			t = t1;
		else {
			r1 = t1->num_ptr(b);
			r2 = t2->num_ptr(b);

			if (r1=='P' && r2=='P') {
				Pptr p1 = t1->is_ptr();
				Pptr p2 = t2->is_ptr();
//error('d',"p1 %t p2 %t",p1,p2);
				if ((c1 = p1->typ->is_cl_obj())
				&& (c2 = p2->typ->is_cl_obj())) {
					Pclass cl1 = Pclass(c1->tp);
					Pclass cl2 = Pclass(c2->tp);
					if (cl1==cl2 || cl2->has_base(cl1)) {
						t = t1;
						goto caca;
					}
					else if (cl1->has_base(cl2)) {
						t = t2;
						goto caca;
					}
				}
			}

			if (r1==FCT && r2==FCT) {	// fudge
				if (t1->check(t2,ASSIGN))
					error("badTs in ?:E: %t and %t",t1,t2);
				else if (Pfct(t1)->memof) error('s',"conditionalE with%t",t1);
				t = t1;
			}
			else 
				nppromote(b);
		caca:
//error('d',"?: t %t t1 %t t2 %t",t,t1,t2);
			if (t!=t1 && t->check(t1,0)) {
				PERM(t);
				e1 = new cast(t,e1);
			}

			if (t!=t2 && t->check(t2,0)) {
				PERM(t);
				e2 = new cast(t,e2);
			}

			Pptr pt = t->is_ptr();
			//if (pt && pt->base==PTR && pt->memof) error('s',"conditionalE with%t",t);
			if (pt && pt->base==PTR && pt->memof && MPTR == 0) error('s',"conditionalE with%t",t);
		}
		}
		break;

	case ASPLUS:
		r1 = t1->num_ptr(ASPLUS);
		r2 = t2->num_ptr(ASPLUS);
		nppromote(ASPLUS);
		goto ass;

	case ASMINUS:
		r1 = t1->num_ptr(ASMINUS);
		r2 = t2->num_ptr(ASMINUS);
		if (r2=='P' && r1!='P' && r1!='A') error("P -= nonP");
		nppromote(ASMINUS);
		goto ass;

	case ASMUL:
	case ASDIV:
		r1 = t1->numeric(b);
		r2 = t1->numeric(b);
		nppromote(b);
		goto ass;

	case ASMOD:
		r1 = t1->integral(ASMOD);
		r2 = t2->integral(ASMOD);
		nppromote(ASMOD);
		goto ass;

	case ASAND:
	case ASOR:
	case ASER:
	case ASLS:
	case ASRS:
		r1 = t1->integral(b);
		r2 = t2->integral(b);
		npcheck(b);
		t = int_type;
		goto ass;
	ass:
		if (r1='P' && t1->check(Pvoid_type,0)==0) error("%k of void*",b);
		tp = t;
		as_type = t;	/* the type of the rhs */
		t2 = t;

	case ASSIGN:
//error('d',"assign %k: %t %t %s",b,t1,t2,ignore_const?"ignore const":"");
//error('d',"    e1 %d %k e1 %d %k",e1,e1->base,e2,e2->base);
		if (ignore_const) {	// handle static initializers
					// represented as assignments
					// ignore consts.
			tp = e1->tp;
			return this;
		}

		switch (e1->base) {
		case G_CM:
		case CM:	// (a,b)=c => *(a,&b)=c
		{
			e1->e2 = new expr(G_ADDROF,0,e1->e2);
			e1->tp = 0;
			e1 = new expr(DEREF,e1,0);
			return typ(tbl);
		}
		case QUEST:	// (a?b:c)=d => *(a?&b:&c)=c
		{
			e1->e1 = new expr(G_ADDROF,0,e1->e1);
			e1->e2 = new expr(G_ADDROF,0,e1->e2);
			e1->tp = 0;
			e1 = new expr(DEREF,e1,0);
			return typ(tbl);
		}
		case ASSIGN:	// (a*=b)=c => a*=b,a=c
		case ASPLUS:
		case ASMINUS:
		case ASMUL:
		case ASDIV:
		case ASMOD:
		case ASAND:
		case ASOR:
		case ASER:
		case ASLS:
		case ASRS:
		{
			base = G_CM;
			nin++;
			if (e1->e1->not_simple()) error('s',"lvalue %k too complicated",b);
			nin--;
			Pexpr aa = new expr(e1->base,e1->e1,e1->e2);
			Pexpr bb = new expr(b,e1->e1,e2);
			e1 = aa;
			e2 = bb;
			return typ(tbl);
		}
		case INCR:
		case DECR:	// ++a=b => ++a,a=b
		{
			if(!e1->e2) break ;
			base = G_CM;
			nin++;
			if (e1->e2->not_simple()) error('s',"lvalue %k too complicated",b);
			nin--;
			Pexpr aa = new expr(e1->base,0,e1->e2);
			Pexpr bb = new expr(b,e1->e2,e2);
			e1 = aa;
			e2 = bb;
			return typ(tbl);
		}
		case REF:
		{
			Pexpr r = e1;
			// hack to prevent
			//	f().i = j
			// transformed into
			//	((t=f()),&t)->i = j
			if (r->e1->base==G_CM
			&& r->e1->e2->base==G_ADDROF
			&& r->e1->e2->e2->base==NAME) {
				char* s = r->e1->e2->e2->string;
				if (s[0]=='_' && s[1]=='_')
					error("left hand side not lvalue");
			}
		}
		}

		if (e1->lval(b) == 0) {
			tp = any_type;
			return this;
		}
	lkj:
		switch (t1->base) {
		case TYPE:
			t1 = Pbase(t1)->b_name->tp;
			goto lkj;
		case INT:
		case CHAR:
		case SHORT:
		//	if (e2->base==ICON && e2->tp==long_type)
		//		error('w',"long constant assigned to%k",t1->base);
		{	Ptype t = e2->tp;
		csi:
			switch (t->base) {
			case TYPE:
				t = Pbase(t)->b_name->tp; goto csi;
			case LONG:
			case FLOAT:
			case DOUBLE:
			case LDOUBLE:
				error('w',"%t assigned to %t",e2->tp,t1);
			}
		}
			// no break
		case LONG:
			if (b==ASSIGN
			&& Pbase(t1)->b_unsigned
			&& e2->base==UMINUS
			&& e2->e2->base==ICON)
				error('w',"negative assigned to unsigned");
			break;
		case PTR:
			if (b == ASSIGN) {
//error('d',"ptr t1 %t %d %t",t1,t1->memptr(),t2);
			//??	if (t1->memptr() && t2->base!=OVERLOAD) break;
				e2 = ptr_init(Pptr(t1),e2,tbl);
				t2 = e2->tp;
//error('d',"pchecked %d",Pchecked);
				if (Pchecked) {
					tp = e1->tp;
					return this;
				}
			}
			break;
   		case COBJ:
		{	Pname c1 = t1->is_cl_obj();
				// test of c1->tp necessary for ``fake classes''
				// _Sdd generated for vector assignemnts
			if (c1
			&& c1->tp
		/*	&& Pclass(c1->tp)->memtbl->look("__as",0)==0*/) {
			//&& Pclass(c1->tp)->has_oper(ASSIGN)==0) {
				Pname c2 = t2->is_cl_obj();
// error('d', "expr::typ: c1: %n c2: %n", c1, c2 );
				if (c1 != c2) {
/*
	consider:

	struct A { A(B&); };
	struct B : A {};

	A aa;
	B bb;

	aa = bb;	// aa.operator=(A(bb));
			// optimize to aa.A(bb) when possible
			// avoid temporary where aa = *(A*)&bb is legal
*/
// error('d',"expr::typ c1 %n %d c2 %n %d",c1,c1?c1->tp:0,c2,c2?c2->tp:0);
					if (c2
					&& c2->tp
					&& can_coerce(t1,t2)==0
					//&& Pclass(c2->tp)->has_base(Pclass(c1->tp))
                                   	//&& (1<is_unique_base(Pclass(c2->tp),c1->string,0))
					&& (vcllist->clear(),vcllist=0,1<is_unique_base(Pclass(c2->tp),c1->string,0))
					&& Pclass(c1->tp)->c_xref&(C_VBASE|C_VPTR|C_ASS)) {
// error('d',"aaa");
						if (make_assignment(c1)) return try_to_overload(tbl);
					}
				// optimize
					else {
						e2 = new expr(ELIST,e2,0);
						e2 = new texpr(VALUE,t1,e2);
						if (Pclass(c1->tp)->has_dtor()==0 &&
							Pclass(c1->tp)->has_oper(ASSIGN)==0) {
				// optimize
// error('d',"bbb");
							e2->e2 = e1;
							e2 = e2->typ(tbl);
                                                	if (e2->base==DEREF && e2->e1->base==G_CALL ||
                                                    	e2->base==ASSIGN && e2->e1==e1) {
// error('d',"ccc");
                                                        	*this = *e2;
							}
							tp = t1;
							return this;
						}
						return typ(tbl);
					}
				}
					// test of c1->tp necessary for ``fake classes''
					// _Sdd generated for vector assignemnts
				else if (c1->tp && Pclass(c1->tp)->c_xref&(C_VBASE|C_VPTR|C_ASS)) {
					if (make_assignment(c1)) return try_to_overload(tbl);
				}
			}
			(void) t1->tsizeof();
			break;
		}
		}

//error('d',"check(%t,%t) -> %d",e1->tp,t2,try_to_coerce(t1,e2,"assignment",tbl));
		{	Pexpr x = try_to_coerce(t1,e2,"assignment",tbl);
			if (x)
				e2 = x;
			else if (e1->tp->check(t2,ASSIGN))
				error("bad assignmentT:%t =%t",e1->tp,t2);
			else if ((t1 = t1->is_ptr()) && t1->memptr()) {
				if (t2 == zero_type) {
					Pexpr ee = new expr(ELIST,zero,zero);
					e2 = new expr(ILIST,ee,zero);
				}
				else if (t2->base==PTR && t2->memptr()) {
					// do nothing: structure assignment
				}
				else {
					Pexpr x = ptr_init(Pptr(t1),e2,tbl);
					if (x != e2) e2 = x;
				}
			}
		}		
		t = e1->tp;	// the type of the lhs
		break;
	case CM:
	case G_CM:
		t = t2;
		break;
	default:
		error('i',"unknown operator%k",b);
	}

	tp = t;
	return this;
}
0707071010112044271004440001630000160000010200100466055401400001000000130600expr2.c/*ident	"@(#)ctrans:src/expr2.c	1.5" */
/***************************************************************************

	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.

expr2.c:

	type check expressions

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

#include "cfront.h"
#include "size.h"

extern Pname conv_dominates(Pname,Pname);
static int const_obj1,const_obj2;

Pname really_dominate(Pname on1, Pname on2, bit tc)
{
	Pfct f1 = on1->tp->base==FCT ? Pfct(on1->tp) :
		Pfct(Pgen(on1->tp)->fct_list->f->tp);
	Pfct f2 = on2->tp->base==FCT ? Pfct(on2->tp) :
		Pfct(Pgen(on2->tp)->fct_list->f->tp);

	// const check
	int c1 = f1->f_const;
	int c2 = f2->f_const;

	if(c1 == c2) ;
	else if(c1 && !c2) return tc ? on1 : on2;
	else if(c2 && !c1) return tc ? on2 : on1;

	// hierarchy check
	Pname on = conv_dominates(on1,on2);
	if(on) return on;
	else return 0;
}

void name::assign()
{
	if (n_assigned_to++ == 0) {
		switch (n_scope) {
		case FCT:
			if (n_used && n_addr_taken==0)  {
				Ptype t = tp;
			ll:
				switch (t->base) {
				case TYPE:
					t=Pbase(t)->b_name->tp; goto ll;
				case VEC:
					break;
				default:
					if (curr_loop)
						error('w',&where,"%n may have been used before set",this);
					else
						error('w',&where,"%n used before set",this);
				}
			}
		}
	}
}

void name::take_addr()
{
// error('d', "%n->take_addr tp: %t", this, tp?tp:0 );
// error('d', "%n->take_addr tp: %d %d", this, tp?tp:0, tp?tp->base:0 );
	if ( (warning_opt) && (! n_addr_taken) && (tp) && (tp->base==FCT) && Pfct (tp)->f_inline)
		error('w',"can't take address of inline function %n, %n not inlined", this, this);  
	n_addr_taken++; 
	if ( n_sto == EXTERN && tp ) {
		Ptype t = tp;
		while ( t->base == TYPE )  
			t = Pbase(t)->b_name->tp;
		switch ( t->base ) {
			case COBJ:
				t = Pbase(t)->b_name->tp; // no break
			case CLASS: {
				Pclass cl = Pclass(t);
				if ( cl->c_body == 1 )
					cl->dcl_print(0);
			}
		}
	}
}

int ignore_const;	// for use by ref_init
static is_dataMemPtr(Pexpr);

int expr::lval(TOK oper)
{
	register Pexpr ee = this;
	register Pname n;
	int deref = 0;
	char* es;

//error('d',"%k expr::lval %k",base,oper);

	switch (oper) {
	case ADDROF:
	case G_ADDROF:	es = "address of";	break;
	case DEREF:	es = "dereference of";	break;
	case INCR:	es = "increment of";	goto def;
	case DECR:	es = "decrement of";	goto def;
	default:	es = "assignment to";
	def:
		if (ignore_const==0 && tp->tconst()) {
			if (oper) {
				if (base == NAME) {
					if (vec_const && Pname(this)->n_scope==ARG) break;
					error("%s constant%n",es,this);
				}
				else
					error("%s constant",es);
			}
			return 0;
		}
	}

	for(;;) {
//error('d',"loop %k",ee->base);
		switch (ee->base) {
	//	case G_CALL:
	//	case CALL:
		default:
		defa:
			if (deref == 0) {
				if (oper) error("%s%k (not an lvalue)",es,ee->base);
				return 0;
			}
			return 1;
		case ZERO:
		case CCON:
		case ICON:
		case FCON:
			if (oper) error("%s numeric constant",es);
			return 0;
		case STRING:
			if (oper) error('w',"%s string constant",es);
			return 1;
		case CAST:
		switch( oper ) {
		case 0:
		case ADDROF:
		case G_ADDROF:
		case DEREF:
     			goto defa;
		default:
			if ( ee->tp->base == PTR 
			     && is_dataMemPtr(ee) ) 
			{ // check for const class object
    				Pexpr te;
				te = ee->e1->e1->e1;	 
       				if ( te->base == G_ADDROF )
					te = te->e2;
       				if ( te->base == NAME ) {
					Ptype pt = te->tp;
					if ( pt->base == PTR )
						pt = Pptr(pt)->typ;
					if ( pt->tconst() ) 
						error("%sCMP of const%n",es,te);
					return 0;
				}
			}
			goto defa;
		}

		case DEREF:
		{	
			Pexpr ee1 = ee->e1;
// error( 'd', "ee1: %k", ee1->base );
			switch (ee1->base) {	// *& vanishes
			case ADDROF:	// *&
				return 1;
			case G_CM:
			case CM:	// look for *(a,&b)
				if (ee1->e2->base==G_ADDROF
				|| ee1->e2->base==ADDROF)
					return 1;
				goto defaa;
			case QUEST:	// look for *(q?&a:&b)
				if ((ee1->e1->base==G_ADDROF
					|| ee1->e1->base==ADDROF)
				&& (ee1->e2->base==G_ADDROF
					|| ee1->e2->base==ADDROF))
					return 1;
				// no break
			default:
			defaa:
				ee = ee1;
				deref = 1;
			}
			break;
		}

		case QUEST:
		{	int x1 = ee->e1->lval(deref?0:oper);
			int x2 = ee->e2->lval(deref?0:oper);
			if (ee->e1->tp->check(ee->e2->tp,0)) return 0;
			if (deref) return 1;
			return x1 && x2;
		}

		case INCR:
		case DECR:
			if (e1) goto defa;	// postfix does not preserve lval
		case ASSIGN:
		case ASPLUS:
		case ASMINUS:
		case ASMUL:
		case ASDIV:
		case ASMOD:
		case ASAND:
		case ASOR:
		case ASER:
		case ASLS:
		case ASRS:
			return 1;

		case CM:
		case G_CM:
			if (ee->e2->lval(deref?0:oper)==0) return deref;
			return 1;

		case MEMPTR:
			ee = ee->e2;
			break;

		case MDOT:
			ee = ee->mem;
			break;

		case DOT:
		{
// error('d',"dot %k oper %k",ee->e1->base,oper);
			Pexpr e = 0;
			int e_const = 0; // to catch x.y.val = 1, where x is const

			switch (ee->e1->base) {		// update use counts, etc.
			case NAME:
				switch (oper) {
				case ADDROF:
				case G_ADDROF:	Pname(ee->e1)->take_addr();
				case 0:		break;
				case ASSIGN:	Pname(ee->e1)->n_used--;
				default:	Pname(ee->e1)->assign(); // asop
				}
				break;
			case DOT:
				e = ee->e1;
				do e=e->e1; while (e->base==DOT);
				if (e->base == NAME) {
					e_const = e->tp->tconst();
					switch (oper) {
					case ADDROF:
					case G_ADDROF:	Pname(e)->take_addr();
					case 0:		break;
					case ASSIGN:	Pname(e)->n_used--;
					default:	Pname(e)->assign(); // asop
					}
				}
			}

			n = Pname(ee->mem);
			while (n->base == MDOT) n = Pname(Pref(n)->mem);

			if (deref==0 && 
				(ee->e1->tp->tconst() || e_const)) {

				switch (oper) {
				case 0:
				case ADDROF:
				case G_ADDROF:
				case DEREF:
					break;
				default:
					error("%sM%n of%t",es,n,e_const?e->tp:ee->e1->tp);
				}
				return 0;
			}
		}
		goto xx;

		case REF:
			n = Pname(ee->mem);
			while (n->base == MDOT) n = Pname(Pref(n)->mem);

			if (deref==0 && ee->e1) {  //BR
				Ptype p = ee->e1->tp;
			zxc:
				switch (p->base) {
				case TYPE:	p = Pbase(p)->b_name->tp; goto zxc;
				case PTR:
				case VEC:	break;
				default:	error('i',"expr::lval %t->%n",p,n);
				}
				if (Pptr(p)->typ->tconst()) {
					switch (oper) {
					case 0:
					case G_ADDROF:
					case DEREF:
						break;
					case ADDROF:
						if ( cm_const_save == 0 && const_ptr == 0 ) 
							error(strict_opt?0:'w',"%sM%n of%t",es,n,Pptr(p)->typ);
						break;
					default:
						error("%sM%n of%t",es,n,Pptr(p)->typ);
					}
					return 0;
				}
			}
			goto xx;

		case NAME:
			n = Pname(ee);
		xx:
// error('d',"name xx: %n oper %d lex_level: %d",n,oper,n->lex_level);
			if (deref) return 1;
			if (oper==0) return n->n_stclass != ENUM ;

			if (n->tp->base==FIELD && Pbase(n->tp)->b_bits==0) {
				error("%s 0-length field%n",es,n);
				return 0;
			}

			switch (oper) {
			case ADDROF:
			case G_ADDROF:
			{	Pfct f = (Pfct)n->tp;

				if (n->n_sto == REGISTER) {
					if (warning_opt) error('w',"& register%n",n);
				//	return 0;
					n->n_sto = 0;
					n->n_stclass = AUTO;
				}

				if (f == 0) {
					error("& label%n",n);
					return 0;
				}

				if (n->n_stclass == ENUM) {
					error("& enumerator%n",n);
					return 0;
				}

				if (n->tp->base == FIELD) {
					error("& field%n",n);
					return 0;
				}

				n->n_used--;
				if (n->n_qualifier) { // oops, not the real one
					Pname tn = Pclass(n->n_table->t_name->tp)->memtbl->look(n->string,0);
					n = tn ? tn : n;
				}
				n->take_addr();

				// suppress hoisting of local consts
				int statmem = n->n_scope==0 || n->n_scope==PUBLIC || n->n_scope == FCT;
				if (n->n_evaluated && n->n_scope!=ARG) { // &const
					if (statmem == 0 && n->n_dcl_printed==0) {
						n->n_initializer = new ival(n->n_val);
						n->dcl_print(0);
					}
				}
				else if (f->base==FCT && n->n_dcl_printed==0)
					n->dcl_print(0);
				break;
			}

			case ASSIGN:
//error('d',"ass %n %d",n,n->n_used);
				n->n_used--;
				n->assign();
				break;
			//	goto check_void;
			default:	/* incr ops, and asops */
				if (cc->tot && n==cc->c_this) {
					error("%n%k",n,oper);
					return 0;
				}
		//	check_void:
		//		{	Ptype t = n->tp;
		//			while (t->base==TYPE) t = Pbase(t)->b_name->tp;
		//			if (t==Pvoid_type) {
		//				error("%s%t",es,n->tp);
		//				return 0;
		//			}
		//		}
				n->assign();
			}
			return 1;
		}
	}
}

int char_to_int(char* s)
/*	assume s points to a string:
		'c'
	or	'\c'
	or	'\0'
	or	'\ddd'
	or multi-character versions of the above
	(hex constants have been converted to octal by the parser)
*/
{
	register int i = 0;
	register char c, d, e;

	switch (*s) {
	default:
		error('i',"char constant store corrupted");
	case '`':
		error("bcd constant");
		return 0;
	case '\'':
		break;
	}

	for(;;)			/* also handle multi-character constants */
	switch (c = *++s) {
	case '\'':
		return i;
	case '\\':			/* special character */
		switch (c = *++s) {
		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7':	/* octal representation */
			c -= '0';
			switch (d = *++s) {		/* try for 2 */
				
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7':
				d -= '0';
				switch (e = *++s) {	/* try for 3 */
					
				case '0': case '1': case '2': case '3': case '4':
				case '5': case '6': case '7':
					c = c*64+d*8+e-'0';
					break;
				default:
					c = c*8+d;
					s--;
				}
				break;
			default:
				s--;
			}
			break;
		case 'a':
			c = '\a';
			break;
		case 'b':
			c = '\b';
			break;
		case 'f':
			c = '\f';
			break;
		case 'n':
			c = '\n';
			break;
		case 'r':
			c = '\r';
			break;
		case 't':
			c = '\t';
			break;
		case 'v':
			c = '\v';
			break;
		case '\\':
			c = '\\';
			break;
		case '\'':
			c = '\'';
			break;
		}
		/* no break */
	default:
		if (i) i <<= BI_IN_BYTE;
		i += c;
	}
}

const A10 = 'A'-10;
const a10 = 'a'-10;

long str_to_long(register const char* p)
{
	register c;
	register unsigned long i= 0;
	const char* pp = p;

// error( 'd', "str_to_long: %s", p );

	if ((c=*p++) == '0') {
		switch (c = *p++) {
		case 0:
			return 0;

		case 'l':
		case 'L':	/* long zero */
			return 0;

		case 'x':
		case 'X':	/* hexadecimal */
			while (c=*p++) {
				switch (c) {
				case 'l':
				case 'L':
				case 'U':
				case 'u':
					return i;
				case 'A':
				case 'B':
				case 'C':
				case 'D':
				case 'E':
				case 'F':
					i = i*16 + c-A10;
					break;
				case 'a':
				case 'b':
				case 'c':
				case 'd':
				case 'e':
				case 'f':
					i = i*16 + c-a10;
					break;
				default:
					i = i*16 + c-'0';
				}
			}
			return i;

		default:	/* octal */
			do 
				switch (c) {
				case 'l':
				case 'L':
				case 'U':
				case 'u':
					return i;
				default:
					i = i*8 + c-'0';
				}
			while (c=*p++);
			return i;
		}
	}	
				/* decimal */
	i = c-'0';
	while (c=*p++)
		switch (c) {
		case 'l':
		case 'L':
		case 'U':
		case 'u':
			return i;
		default:
		{       unsigned long ii = i;
			i = i*10 + c-'0';
			if (i<ii) goto bad;
		}
		}
	return i;
bad:
	error("integer constant %s larger than the largest long",pp);
	return i;
	
		
}

bit type::is_unsigned()
{
	Ptype t = this;
	while (t->base==TYPE) t = Pbase(t)->b_name->tp;
	if (t->base == PTR) return 0;
	return Pbase(t)->b_unsigned;
}

char* Neval;
bit binary_val;

unsigned long expr::ueval(long x1, long x2)
{
	unsigned long i1 = (unsigned long) x1;	
	unsigned long i2 = (unsigned long) x2;
//error('d',"ueval %k %ld %ld",base,x1,x2);
	switch (base) {
	case UMINUS:	return -i2;
	case UPLUS:	return i2;
	case NOT:	return !i2;
	case COMPL:	return ~i2;
	case CAST:	return i1;
	case PLUS:	return i1+i2;
	case MINUS:	return i1-i2;
	case MUL:	return i1*i2;
	case LS:	return i1<<i2;
	case RS:	return i1>>i2;
	case NE:	return i1!=i2;
	case EQ:	return i1==i2;
	case LT:	return i1<i2;
	case LE:	return i1<=i2;
	case GT:	return i1>i2;
	case GE:	return i1>=i2;
	case AND:	return i1&i2;
 	case ANDAND:	return i1&&i2;
	case OR:	return i1|i2;
	case OROR:	return i1||i2;
	case ER:	return i1^i2;
	case MOD:	if (i2 == 0) {
				if (Neval == 0) { 
					Neval = "mod zero";
					error("mod zero");
				}
				return 1;
			}
			return i1%i2;
	case QUEST:	return (cond->eval()) ? i1 : i2;
	case DIV:	if (i2 == 0) {
				if (Neval == 0) { 
					Neval = "divide by zero";
					error("divide by zero");
				}
				return 1;
			}
			return i1/i2;
	case CM:
	case G_CM:
		return i2;
	}

	Neval = "unsigned expression";
	return 0;
}

long expr::eval()
{
	if (Neval) return 1;
// error('d',"eval %k",base);

	static int targno=0;
	static int icallflag=0;

	switch (base) {
	case ZERO:	return 0;
	case IVAL:	return i1;
	case ICON:	return str_to_long(string);
	case CCON:	return char_to_int(string);
	case FCON:	Neval = "float in constant expression"; return 1;
	case STRING:	Neval = "string in constant expression"; return 1;
	case EOBJ:	return Pname(this)->n_val;
	case SIZEOF:
		extern no_sizeof;
		if (no_sizeof) Neval = "sizeof";
		return tp2->tsizeof();
		
	case NAME:
	{	Pname n = Pname(this);
// error('d',"eval %n eval %d %d",n,n->n_evaluated,n->n_val);
// error('d',"eval tp->tconst() %d, n->n_initializer: %k", n->tp->tconst(), n->n_initializer?n->n_initializer->base:0 );
		if (n->n_evaluated && n->n_scope!=ARG) return n->n_val;
		if (binary_val && strcmp(string,"_result")==0) return 8888;
		Neval = "cannot evaluate constant";
		return 1;
	}
	case ICALL:
		if (e1) {
			icallflag=1;
			targno=0;
			il->i_next = curr_icall;
			curr_icall = il;
			long i = e1->eval();
			curr_icall = il->i_next;
			icallflag=0;
			return i;
		}
		Neval = "void inlineF";
		return 1;
	case ANAME:
	{	Pname n = (Pname)this;

/*
		int argno;
		if (icallflag) {
		argno=targno;
		targno++;
		}
*/
		int argno = (int) n->n_val;
	
		Pin il;
		for (il=curr_icall; il; il=il->i_next)
			if (il->i_table == n->n_table) goto aok;
		goto bok;
	aok:
		if (il->i_args[argno].local) {
	bok:
			Neval = "inlineF call too complicated for constant expression";
			return 1;
		}
		Pexpr aa = il->i_args[argno].arg;
		return aa->eval();
	}
	case CAST:
	{	if (e1->base==FCON && tp2->base!=FLOAT && tp2->base!=DOUBLE) {
			char* p = e1->string;
			while (*p!='.') p++;
			if (p==e1->string) *p++ = '0';
			*p = 0;
			e1->base = ICON;
		}		
		long i = e1->eval();
		Ptype tt = tp2;
	strip:
		switch (tt->base) {
		default:
			Neval = "cast to non-integral type in constant expression";
			break;
		case TYPE:
			tt = Pbase(tt)->b_name->tp;
			goto strip;
		case EOBJ:
		case LONG:
		case INT:
		case CHAR:
		case SHORT:
			i &= ~(((~(unsigned long)0)<<(BI_IN_BYTE*(tp2->tsizeof()-1)))<<BI_IN_BYTE);
			break;
		}
		return i;
	}
	case UMINUS:
	case UPLUS:
	case NOT:
	case COMPL:
	case PLUS:
	case MINUS:
	case MUL:
	case LS:
	case RS:
	case NE:
	case LT:
	case LE:
	case GT:
	case GE:
	case AND:
	case OR:
	case ER:
	case DIV:
	case MOD:
	case QUEST:
	case EQ:
	case ANDAND:
		break;
	case OROR:
		if (binary_val) {	// a||b, don't evaluate b if a!=0
			long i1 = (e1) ? e1->eval() : 0;
			if (Neval==0 && i1 && e1->tp->is_unsigned()==0) return i1;
		}
		break;
	case CM:
	case G_CM:
		break;
	case G_ADDROF:
	case ADDROF:
		if (binary_val) {	// beware of &*(T*)0
			switch (e2->base) {
			case NAME:
			case DOT:
			case REF:	return 9999;
			}
		}
	default:
		Neval = "bad operator in constant expression";
		return 1;
	}

	long i1 = (e1) ? e1->eval() : 0;
	long i2 = (e2) ? e2->eval() : 0;

	if (binary_val && i1==9999 && i2==9999) {
		Neval = "";
		return 1;
	}
	
	if (Neval==0
	&& ((e1&&e1->tp->is_unsigned()) || (e2&&e2->tp->is_unsigned())))
		return (long) ueval(i1,i2);
	
	switch (base) {
	case UMINUS:	return -i2;
	case UPLUS:	return i2;
	case NOT:	return !i2;
	case COMPL:	return ~i2;
	case CAST:	return i1;
	case PLUS:	return i1+i2;
	case MINUS:	return i1-i2;
	case MUL:	return i1*i2;
	case LS:	return i1<<i2;
	case RS:	return i1>>i2;
	case NE:	return i1!=i2;
	case EQ:	return i1==i2;
	case LT:	return i1<i2;
	case LE:	return i1<=i2;
	case GT:	return i1>i2;
	case GE:	return i1>=i2;
	case AND:	return i1&i2;
 	case ANDAND:	return i1&&i2;
	case OR:	return i1|i2;
	case OROR:	return i1||i2;
	case ER:	return i1^i2;
	case MOD:	if (i2 == 0) {
				if (Neval == 0) { 
					Neval = "mod zero";
					error("mod zero");
				}
				return 1;
			}
			return i1%i2;
	case QUEST:	return (cond->eval()) ? i1 : i2;
	case DIV:	if (i2 == 0) {
				if (Neval == 0) { 
					Neval = "divide by zero";
					error("divide by zero");
				}
				return 1;
			}
			return i1/i2;
	case CM:
	case G_CM:
		return i2;
	}
}
bit classdef::baseof(Pname f)
/*
	is ``this'' class a public base class of "f"'s class
	or its immediate base class
*/
{
	Ptable ctbl = f->n_table;
	Pname b = ctbl->t_name;

	if (b == 0) return 0;
	Pclass cl = Pclass(b->tp);
	if (cl == 0) return 0;
	if (cl == this) return 1;
	ppbase = PUBLIC;
	Pclass bcl = is_base(cl->string);
	return (bcl && ppbase==PUBLIC);
}

bit classdef::baseof(Pclass cl)
/*
	is ``this'' class a public base class of "cl"
*/
{
	if (cl == 0) return 0;
	if (cl == this) return 1;
	ppbase = PUBLIC;
	Pclass bcl = is_base(cl->string);
	return (bcl && ppbase==PUBLIC);
}

static int mem_match(Pfct f1, Pfct f2)
/*
	check class membership.

	For some reason checking f_this==0 works and f_static doesn't
*/
{
//	if (f1->memof) return f2->f_this ?f2->memof==f1->memof : 0;
//	if (f1 && f1->memof) return f2->f_this?f2->memof==f1->memof : 0;
//	return f2->f_this==0;
	if (f1==0 || f2==0) return 0;
	if (f1->memof && f2->f_this && f2->memof!=f1->memof) return 0;
	if (f2->f_this) return 0;
	if (f1->memof && f2->f_static) return 0;
	if (f1->check(f2,ASSIGN)) return 0;
	return 1;
}

int Pchecked;

Pexpr ptof(Pfct ef, Pexpr e, Ptable tbl)
/*
	a kludge: initialize/assign-to pointer to function
*/
{
	Pfct f;
	Pname n = 0;
eee:
//error('d',"ptof %t %t %k",ef,e->tp,e->base);
	switch (e->base) {
	case QUEST:
		e->e1 = ptof(ef,e->e1,tbl);
		e->e2 = ptof(ef,e->e2,tbl);
		return e;
	case CM:
	case G_CM:
		e->e2 = ptof(ef,e->e2,tbl);
		return e;
	case NAME:
		f = Pfct(e->tp);
		Pname nn = Pname(e);

		switch (f->base) {
		case OVERLOAD:
			e = Pgen(f)->find(ef,0);
			if (e == 0) {
				error("cannot deduceT for &overloaded%n",nn);
				return e;
			}
		//	e = n;
			// no break
		case FCT:
			Pchecked = mem_match(ef,Pfct(e->tp));
			e = new expr(G_ADDROF,0,e);
			return e->typ(tbl);	// handle &B::f
			//e->tp = f;
		}
		goto ad;

	case ZERO:
		if (ef->memof) {
			e = new expr(ELIST,zero,zero);
			e = new expr(ILIST,e,zero);
			e->tp = zero_type;
			return e; 
		}
		break;

	case MDOT:
		// ?? error('s',"P toM of not firstB");
		do e = e->mem; while (e->base == MDOT);
		goto eee;

	case DOT:
	case REF:
		f = Pfct(e->mem->tp);

		switch (f->base) {
		case OVERLOAD:
			n = Pgen(f)->find(ef,0);
			if (n == 0) error("cannot deduceT for &overloaded%n",e->mem);
			else e = n;
			// no break
		case FCT:
			Pchecked = mem_match(ef,Pfct(e->tp));
			e = new expr(G_ADDROF,0,e);
			return e->typ(tbl);	// handle &B::f
		//	n = Pname(e->mem);
		//	e = n->address();
		}
		goto ad;

	case ADDROF:
	case G_ADDROF:
		f = Pfct(e->e2->tp);
	ad:
		if (f->base == OVERLOAD) {
			n = Pgen(f)->find(ef,0);
			if (n == 0) error("cannot deduceT for &overloaded %s()",Pgen(f)->fct_list->f->string);
			Pchecked = mem_match(ef,Pfct(n->tp));
			e->e2 = n;
			e->tp = n->tp;
		}
		if (n) n->lval(ADDROF);
		break;

	case CAST:
	{
		Pexpr te = e->e1;
		if (e->e1->base == G_ADDROF) te = e->e1->e2;
		(void) ptof(ef,te,tbl);
	}
	}
	return e;
}

Pexpr ptr_init(Pptr p, Pexpr init, Ptable tbl)
/*
	check for silly initializers

	char* p = 0L;	 ??	fudge to allow redundant and incorrect `L'
	char* p = 2 - 2; ??	worse
*/
{
// error('d',"ptr_init: p=%t init->tp=%t init->base %k",p,init->tp,init->base);

	Pchecked = 0;

	Ptype it = init->tp;
itl:
	switch (it->base) {
	case TYPE:
		it = Pbase(it)->b_name->tp; goto itl;
	case ZTYPE:
//		if (init == zero) break;
		break;
	case EOBJ:
	case INT:
	case CHAR:
	case SHORT:
	case LONG:
	{	Neval = 0;
		long i = init->eval();
		if (Neval)
			error("badPIr: %s",Neval);
		else
		if (i)
			error("badPIr value %d",i);
		else {
			DEL(init);
			init = zero;
		}
		break;
	}		
	}

	Pclass c1 = p->memof;

	if (c1) {
		if (init==zero)
			;
		else {
			Pclass c2;
// error('d',"it %t %d",it,it->base);
			switch (it->base) {
			case FCT:
				c2 = Pfct(it)->memof;
				break;
			case OVERLOAD:
				c2 = Pfct(Pgen(it)->fct_list->f->tp)->memof;
				break;
			case PTR:
			case RPTR:
				c2 = Pptr(it)->memof;
				break;
			default:
				c2 = 0;
			}

			if (c2 == 0) {
				// initialization by &A::f
//error('d',"curious");
			}
			else if (c1 != c2) {
                                Nptr = 0;
				Noffset = 0;
				vcllist->clear();
				vcllist=0;
				int u1 = is_unique_base(c1,c2->string,0);
//error('d',"c1 %t c2 %t u1 %d off %d",c1,c2,u1,Noffset);
                                if (u1 && (Nptr || Noffset)) {
					// requires offset manipulation
					int bad = 0;
        				if (u1 == 1 && !Nptr) {
						if (init->base==ILIST) {
							// d = d+Noffset;
							switch (init->e1->e1->base) {
								case IVAL:
									init->e1->e1->i1 += Noffset;
									break;
								case ZERO:
									init->e1->e1 = new ival(Noffset);
									break;
								default:
									bad = 1;
								}

							// if (i<0) f = vptroffset
							switch (init->e1->e2->base) {
								case IVAL:
									if (0<init->e1->e2->i1) {
									// extern Ptype Pfct_type;
									// store vptr offset
									//  init->e2=new cast(Pfct_type,zero);
									}
									else
										break;
								default:
									bad = 1;
								}	
						} // end if (init->base==ILIST)
						else
							bad = 1;
					} // end if (u1 == 1 ...
					else
						bad = 1;

				if (bad) error('s',"%t assigned to %t (too complicated)",init->tp,p);
				} // end if (u1 && ...

                                Nptr = 0;
				Noffset = 0;
				vcllist->clear();
				vcllist=0;
				int u2 = is_unique_base(c2,c1->string,0);
//error('d',"c1 %t c2 %t u2 %d off %d",c1,c2,u2,Noffset);
                                if (u2 && (Nptr || Noffset)) {
					// requires offset manipulation
					error('s',"%t assigned to %t",init->tp,p);
				}
			} // end if (c1 != c2
		} // end else
	} // end if (c1)

	Ptype pit = p->typ;
lll:
// error('d',"p %t pit %t",p,pit);
	switch (pit->base) {
	case TYPE:
		pit = Pbase(pit)->b_name->tp;
		goto lll;
	case FCT:
		return ptof(Pfct(pit),init,tbl);
	case COBJ:
	{	Pptr r;
// error('d',"cobj: ptr %t, ref %t",it->is_ptr(),it->is_ref());
		if (r=it->is_ptr_or_ref()) {
			Pchecked = 1;
			TOK b = p->base;		// could be REF
			TOK bb = r->base;
			if (b==RPTR) p->base = PTR;
			if (bb==RPTR) r->base = PTR;
			if (p->check(r,ASSIGN)) {
				if ( cc && cc->nof && 
					Pfct(cc->nof->tp)->f_const &&
        				cc->c_this == init )
						error("%n const: assignment of%n (%t) to%t",cc->nof,init,init->tp,p);
				else
					error("no standard conversion of %t to %t",init->tp,p);
			}
			p->base = b;
			r->base = bb;
			Pexpr cp = cast_cptr(Pclass(Pbase(pit)->b_name->tp),init,tbl,0);
			if (cp != init) {
				PERM(p);	// or else it will be deleted twice!
				return new cast(p,cp);
			}
		}
		// no break
	}
	default:
		return init;
	}
}

static Pname Lcoerce, Rcoerce;
extern int suppress_error;

int try_to_demote(TOK oper, Ptype t1, Ptype t2)
/*
	look at t1 and t2 and see if there are ``demotions'' of t1 and/or t2
	so that ``t1 oper t2'' can be made legal

	return	0 is not
		1 if there is exactly one way
		>1 if there is more than one way (if in doubt return 2)
*/
{
//error('d',"try_to_demote(%k : %t : %t)",oper,t1,t2);

	Pname n1 = t1 ? t1->is_cl_obj() : 0;
	Pclass c1 = n1 ? Pclass(n1->tp) : 0;
	Pname n2 = t2 ? t2->is_cl_obj() : 0;
	Pclass c2 = n2 ? Pclass(n2->tp) : 0;

	Ptype lt = t1;
	Ptype rt = t2;

	Lcoerce = Rcoerce = 0;

//	if (oper == DOT) return 0;

	if (c1)
		switch (oper) {
		case ASSIGN:
		case ASPLUS:
		case ASMINUS:
		case ASMUL:
		case ASDIV:
		case ASMOD:
		case ASAND:
		case ASOR:
		case ASER:
		case ASLS:
		case ASRS:	// don't coerce left hand side of assignment
		//	c1 = 0;
			if (c1->memtbl->look("__as",0)) return 0;
		}
	else
		switch (oper) {
		case ADDROF:
		case INCR:
		case DECR:	// don't coerce unary requiring an lval
			return 0;
		}

	if (c1) {
//error('d',"c1 %t",c1);
		for (Pname on1 = c1->conv; on1; on1=on1->n_list) {
// error( 'd', "on1: %s tp: %k", on1->string, on1->tp->base );
			Pfct f = Pfct(on1->tp);
			lt = f->base==FCT ? f->returns :
				Pfct(Pgen(on1->tp)->fct_list->f->tp)->returns;
			Pname cn = lt->is_cl_obj();

			if (cn && (Lcoerce==0 || Lcoerce->tp->check(f,0))) {
				Pclass cl = Pclass(cn->tp);
				Pname n = cl->has_oper(oper);
				if (n == 0) continue;
		//		while (n->base==REF || n->base==MDOT) n=Pname(n->mem) ;
				Pfct nf = Pfct(n->tp);
// error( 'd', "nf: %d %k", nf->base, nf->base );
				if (nf->base == FCT) {
					if (nf->nargs==1
					&& t2
					&& (nf->argtype->tp->check(t2,ARG)==0
						|| can_coerce(nf->argtype->tp,t2)==1)
					) {
						if (Lcoerce) return 2;
						Lcoerce = on1;
					}
				}
				else {
					for (Plist gl=Pgen(nf)->fct_list; gl; gl=gl->l) {
						Pfct nf = Pfct(gl->f->tp);
						if (nf->nargs==1
						&& t2
						&& (nf->argtype->tp->check(t2,ARG)==0
							|| can_coerce(nf->argtype->tp,t2)==1)
						) {
							if (Lcoerce) return 2;
							Lcoerce = on1;
						}
					}
				}
				continue;
			}
			//if (lt->is_cl_obj()) continue;
			if (c2) {
//error('d',"c2 %t",c2);
				for (Pname on2 = c2->conv; on2; on2=on2->n_list) {
					Pfct f = Pfct(on2->tp);
					rt = f->base==FCT ? f->returns :
						Pfct(Pgen(on2->tp)->fct_list->f->tp)->returns;
					if (rt->is_cl_obj()) continue;

					suppress_error = 1;
					int r1 = lt->kind(oper,0);
					int r2 = rt->kind(oper,0);
					if (np_promote(oper,r1,r2,lt,rt,1)!=any_type) {
						Pname sn = on1;
						if (Lcoerce) {
						    Pname tn = really_dominate(
							Lcoerce, 
							on1, 
							const_obj1
						    );
				    		    if(!tn) {
							suppress_error = 0;
							return 2;
						    }
						    else sn = tn;
						}
						Lcoerce = sn;
						Rcoerce = on2;
					
					}
					suppress_error = 0;
				}
					
			}
			else if (rt) {
				suppress_error = 1;
				int r1 = lt->kind(oper,0);
				int r2 = rt->kind(oper,0);
				if (np_promote(oper,r1,r2,lt,rt,1)!=any_type) {
					Pname sn = on1;
					if (Lcoerce) {
						Pname tn = really_dominate(
							Lcoerce, 
							on1, 
							const_obj1
						);
				    		if(!tn) {
							suppress_error = 0;
							return 2;
						}
						else sn = tn;
					}
					Lcoerce = sn;
				}
				suppress_error = 0;
			}
			else {
				Pname sn = on1;
				if (Lcoerce) {
					Pname tn = really_dominate(
						Lcoerce, 
						on1, 
						const_obj1
					);
				    	if(!tn) return 2;
					else sn = tn;
				}
				Lcoerce = sn;
			}
		}
	}
	else if (c2) {
//error('d',"c2 %n",c2);
		for (Pname on = c2->conv; on; on=on->n_list) {
			Pfct f = Pfct(on->tp);
			rt = f->base==FCT ? f->returns :
				Pfct(Pgen(on->tp)->fct_list->f->tp)->returns;
			Pname cn = rt->is_cl_obj();
//error('d',"cn %n",cn);
			if (cn && (Rcoerce==0 || Rcoerce->tp->check(f,0))) {
				Pclass cl = Pclass(cn->tp);
				Pname n = cl->has_oper(oper);
				if (n == 0) continue;

		//		while (n->base==REF || n->base==MDOT) n=Pname(n->mem);
				Pfct nf = Pfct(n->tp);
				if (nf->base == FCT) {
					if (nf->nargs == 0) {
						if (Lcoerce || Rcoerce) return 2;
						Rcoerce = on;
					}
				}
				else {
					for (Plist gl=Pgen(nf)->fct_list; gl; gl=gl->l) 
						if (Pfct(gl->f->tp)->nargs == 0) {
							if (Lcoerce || Rcoerce)	return 2;
							Rcoerce = on;
						}
				}
				continue;
			}
			//if (rt->is_cl_obj()) continue;
			if( lt ) {
				suppress_error = 1;
				int r1 = lt->kind(oper,0);
				int r2 = rt->kind(oper,0);

				if (np_promote(oper,r1,r2,lt,rt,1)!=any_type) {
					Pname sn = on;
					if (Lcoerce || Rcoerce) {
						Pname tn = really_dominate(
							Rcoerce, 
							on, 
							const_obj2
						);
				    		if(!tn) {
							suppress_error = 0;
							return 2;
						}
						else sn = tn;
					}
					Rcoerce = sn;
				}
				suppress_error = 0;
			}
		}
	}

//error('d',"->%d || %d",Lcoerce,Rcoerce);
	return (Lcoerce || Rcoerce);
}

Pexpr expr::try_to_overload(Ptable tbl)
{
//	TOK bb = (base==DEREF && e2==0) ? MUL : base;
// error('d',"try_to_overload %k %d",base,base);

	Pname n1 = 0;
	Ptype t1 = 0;
	const_obj1 = 0;
	const_obj2 = 0;

	if (e1) {
		t1 = e1->tp;
		Ptype tpx = t1;
		while (tpx->base == TYPE) tpx = Pbase(tpx)->b_name->tp;
		n1 = tpx->is_cl_obj();
		const_obj1 = t1->tconst();

		Pexpr ee = e1;
                while (ee && (ee->base==DOT || ee->base==REF)) {
                       	Pexpr m = ee->mem;
                       	if ( ee->base==REF && m->tp &&  m->tp->is_ptr())
                               	break;
                       	ee = ee->e1;
                }
                if (ee) {
			int tc;
                       	Ptype ttt = ee->tp;
                       	switch (e1->base) {
                       	case REF:
                       	        Pptr p = ttt?ttt->is_ptr():0;
                               	if (p && p->typ->tconst())
                                       	const_obj1 = 1;
                               	break;
                       	case DOT:
				tc = ttt ? ttt->tconst() : 0;
                               	if (ttt && tc && (!strict_opt || tc!=2))
                                       	const_obj1 = 1;
                       	}
                }
	}

	TOK bb = base;
	switch (bb) {
	case DEREF:
		if (e2 == 0) bb = MUL;
		// no break;
	case CALL:
	case G_CALL:
		if (n1 == 0) return 0;	// ignore type of argument list
	}

	Pname n2 = 0;
	Ptype t2 = 0;

	if (e2 && e2->base!=ELIST) {
		t2 = e2->tp;
		Ptype tpx = t2;
		while (tpx->base == TYPE) tpx = Pbase(tpx)->b_name->tp;
		n2 = tpx->is_cl_obj();
		const_obj2 = t2->tconst();
		Pexpr ee = e2;
                while (ee && (ee->base==DOT || ee->base==REF)) {
                       	Pexpr m = ee->mem;
                       	if ( ee->base==REF && m->tp &&  m->tp->is_ptr())
                               	break;
                       	ee = ee->e1;
                }
                if (ee) {
			int tc;
                       	Ptype ttt = ee->tp;
                       	switch (e2->base) {
                       	case REF:
                       	        Pptr p = ttt?ttt->is_ptr():0;
                               	if (p && p->typ->tconst())
                                       	const_obj2 = 1;
                               	break;
                       	case DOT:
				tc = ttt ? ttt->tconst() : 0;
                               	if (ttt && tc && (!strict_opt || tc!=2))
                                       	const_obj2 = 1;
                       	}
                }
	}

	if (n1==0 && n2==0) return 0;
	if (n1 && n1->tp == 0) return 0;	// make_assign() fudge
// error('d',"e1: %k e2: %k", e1?e1->base:0, e2?e2->base:0 );
// error('d',"t1 %t t2 %t",t1,t2);
// error('d',"n1 %n n2 %n",n1,n2);
	/* first try for non-member function:	op(e1,e2) or op(e2) or op(e1) */
	Pexpr oe2 = e2;
	Pexpr ee2 = (e2 && e2->base!=ELIST) ? e2 = new expr(ELIST,e2,0) : 0;
	Pexpr ee1 = e1 ? new expr(ELIST,e1,e2) : ee2;
	char* obb = oper_name(bb);
	Pname gname = tbl->look(obb,0);
	// if necessary check for ambiguities
	int go = gname ? over_call(gname,ee1) : 0;
//error('d',"go %d",go);
	if (go) gname = Nover;

	if (n1) {
		if (bb == ASSIGN) {
			Pclass c1 = Pclass(n1->tp);
//error('d',"look %k %d",bb,c1->memtbl->look(obb,0));
			if (c1->memtbl->look(obb,0)==0) {
				Pclass bcl = c1->baselist?c1->baselist->bclass:0;
				if (n2==0
				|| (Pclass(n2->tp)!=c1
					&& Pclass(n2->tp)->has_base(c1)==0)) {
					// if legal, a=1 can be optimized to a.ctor(1)
						if (2 < go) goto glob;
						return 0;
					}

				if (bcl
				&& c1->obj_size!=bcl->obj_size
				&& bcl->memtbl->look(obb,0)) {
					// cannot inherit from smaller base class
				//	make_assignment(n1);
				//	return try_to_overload(tbl);
					goto mkas;
				}

				if (c1->c_xref&(C_VBASE|C_VPTR|C_ASS)) {
					// make operator=() if
					//	no base (shouldn't happen
					//	different (smaller) sized base
					//	two bases
				mkas:
					if (2 < go) goto glob;
				//	make_assignment(n1);
				//	return try_to_overload(tbl);
					return make_assignment(n1) ? try_to_overload(tbl) : 0;
				}
// error('d',"n2 %n",n2);
			//	if (n2 && Pclass(n2->tp)==c1)
				return 0;
			}
			// now take care of other assignments, 
		}

		int dbconv = 0;
		Pclass ccl = Pclass(n1->tp);
		// Pexpr mn = Pclass(n1->tp)->memtbl->look(obb,0);
		Pexpr mn = ccl->memtbl->look(obb,0);
// error('d', "tcl %d %t cl %d %t", tcl, tcl, ccl, ccl);
  		if(strcmp(obb,"__as")) {
			tcl = ccl; // ugh!!! 
			if(!mn) dbconv = 2;
		}
//		tcl = ccl; // ugh!!! 
		mn = ccl->find_name(obb,0);

		Pname mname = Pname(mn);
// error('d',"mn %n %d %k %s",mname,mn,mn?mn->base:0,obb);
		if (mname == 0) goto glob;

	zaq:
		switch (mname->base) {
		case REF:
		case MDOT:
			mname = Pname(Pexpr(mname)->mem);
			goto zaq;
		}

		int mo = over_call(mname,e2);
		int smo = mo;
		if(mo && dbconv && mo >= dbconv) mo = dbconv;
//error('d',"mo %d (go %d)",mo,go);
		if (mo==0 || mo<go)
			goto glob;
		else if (mo && mo==go) {
//error('d',"t1 %t t2 %t",t1,t2);
			if (gname->tp->base == OVERLOAD) { // find right version
				for (Plist l = Pgen(gname->tp)->fct_list; l; l=l->l) {
					Pname n = l->f;
					int x = over_call(n,ee1);
					if (x == go) {
						gname = n;
						break;
					}
				}
			}
//error('d',"gname %n: %t",gname,gname->tp);
			Pname aa = Pfct(gname->tp)->argtype;
			Pptr p;
			Ptype gt1 = aa->tp;
			if (p = gt1->is_ref()) gt1 = p->typ;
			Ptype gt2 = aa->n_list->tp;
//error('d',"gt1 %t gt2 %t",gt1,gt2);
			if (mname->tp->base == OVERLOAD) { // find right version
				for (Plist l = Pgen(mname->tp)->fct_list; l; l=l->l) {
					Pname n = l->f;
					int x = over_call(n,e2);
					if (x == smo) {
						mname = n;
						break;
					}
				}
			}
//error('d',"mname %n: %t",mname,mname->tp);
			Ptype mt1 = Pfct(mname->tp)->f_this->tp;
			mt1 = Pptr(mt1)->typ;
			Ptype mt2 = Pfct(mname->tp)->argtype->tp;
//error('d',"mt1 %t mt2 %t",mt1,mt2);
			Pname mm = new name;
			Pname a1 = new name;
			a1->tp = mt1;
			Pname a2 = new name;
			a2->tp = mt2;
			a1->n_list = a2;
			mm->tp = new fct(void_type,a1,2);
			Pname gg = new name;
			Pname a3 = new name;
			a3->tp = gt1;
			Pname a4 = new name;
			a4->tp = gt2;
			a3->n_list = a4;
			gg->tp = new fct(void_type,a3,1);
extern Pname dominate(Pname,Pname,Pexpr,int,int);
			aa = dominate(gg,mm,ee1,0,1);
			delete a1;
			delete a2;
			delete a3;
			delete a4;
			DEL( gg->tp );
			DEL( mm->tp );
			//delete gg->tp;
			//delete mm->tp;
			if (aa == 0) {
				delete gg;
				delete mm;
				error("ambiguous operandTs%n and%t for%k",n1,t2,bb);
				tp = any_type;
				return this;
			}
			else if (aa == gg) {
				delete gg;
				delete mm;
				goto glob;
			}
			delete gg;
			delete mm;
		}
		else if (mo < 2) {	// user-defined conversion user

			if (try_to_demote(bb,t1,t2))
				error("ambiguous use of overloaded%k",bb);
		}

		base = G_CALL;				// e1.op(e2) or e1.op()
		Pname xx = new name(mname->string);	// do another lookup
							// . suppresses virtual
		e1 = new ref(DOT,e1,xx);
		if (ee1) delete ee1;
		return typ(tbl);
	}
	
	if (n2 && e1==0) {			/* look for unary operator */
		suppress_error++;
		Pexpr mn = Pclass(n2->tp)->find_name(obb,0);
		suppress_error--;
		Pname mname = Pname(mn);
		if (mname == 0) goto glob;
	zaqq:
		switch (mname->base) {
		case REF:
		case MDOT:
			mname = Pname(Pexpr(mname)->mem);
			goto zaqq;
		}	

		switch (mname->n_scope) {
		default:	goto glob;
		case 0:
		case PUBLIC:	break;		// try e2.op()
		}
		
		int mo = over_call(mname,0);
//error('d',"e2 mo %d (go %d)",mo,go);
		if (mo==0 || mo<go)
			goto glob;
		else if (mo==go) {
			error("ambiguous operandT%n for%k",n2,bb);
			tp = any_type;
			return this;
		}
		else if (mo < 2) {	// user-defined conversion user
			if (try_to_demote(bb,t1,t2))
				error("ambiguous use of overloaded%k",bb);
		}
		base = G_CALL;				// e2.op()
		Pname xx = new name(Nover->string);	// do another lookup
							// . suppresses virtual
		e1 = new ref(DOT,oe2,xx);
		e2 = 0;
		if (ee2) delete ee2;
		if (ee1 && ee1!=ee2) delete ee1;
		return typ(tbl);
	}
	
glob:
// error('d',"glob %d",go);

	if (go) {
		if (go < 2) {	// user-defined conversion necessary => binary
			if (try_to_demote(bb,t1,t2))
				error("ambiguous use of overloaded%k: %t and %t",bb,t1,t2);
		}

		base = gname->n_table == gtbl ? G_CALL : CALL;
//error('d',"gname %n %t",gname,gname->tp);
		e1 = new name(gname->string);
		// if global scope, look only for globals
		if(gname->n_table == gtbl) Pname(e1)->n_qualifier = sta_name;
		e2 = ee1;
		return typ(tbl);
	}

	if (ee2) delete ee2;
	if (ee1 && ee1!=ee2) delete ee1;
	e2 = oe2;

// error('d',"bb %d %k",bb,bb);
	switch (bb) {
	case CM:
	case G_CM:
	case G_ADDROF:
		return 0;
	case ASSIGN:
		if (n1
		&& n2
		&& (n1->tp==n2->tp || Pclass(n2->tp)->has_base(Pclass(n1->tp)))) {
			if (make_assignment(n1))
				return try_to_overload(tbl);
			else
				return 0;
		}
	case DEREF:
	case CALL:
		if (n1 == 0) break;

	default:	/* look for conversions to basic types */
		if (n1
		&& Pclass(n1->tp)->conv
		&& (bb==ANDAND || bb==OROR)) {
			e1 = check_cond(e1,bb,tbl);
			return 0;
		}

		if (n2
		&& Pclass(n2->tp)->conv
		&& (bb==ANDAND || bb==OROR || bb==NOT || 
			bb==UMINUS || bb==UPLUS || bb==COMPL)) {
				e2 = check_cond(e2,bb,tbl);
				return 0;
		}

// error( 'd', "bb: %k t1: %k t2: %k", bb, t1?t1->base:0, t2?t2->base:0 );
		switch (try_to_demote(bb,t1,t2)) {
		default:
			if (Lcoerce) error("ambiguous conversion of%n",n1);
			if (Rcoerce) error("ambiguous conversion of%n",n2);
		case 0:
			break;
		case 1:
			if (Lcoerce) {
				Pname xx = new name(Lcoerce->string);
				Pref r = new ref(DOT,e1,xx);
				e1 = new expr(G_CALL,r,0);
			}

			if (Rcoerce) {
				Pname xx = new name(Rcoerce->string);
				Pref r = new ref(DOT,e2,xx);
				e2 = new expr(G_CALL,r,0);
			}
			return typ(tbl);
		}

		switch (bb) {
		case CM:
		case ADDROF:	// has legal built-in meaning
			return 0;
		}

		if (t1 && t2)
			error("bad operandTs%t%t for%k",t1,t2,bb);
		else
			error("bad operandT%t for%k",t1?t1:t2,bb);

		tp = any_type;
		return this;
	}

	return 0;
}

Pexpr cast_cptr(Pclass ccl, Pexpr ee, Ptable tbl, int real_cast)
/*
	"ee" is being cast to pointer object of class "ccl"
	if necessary modify "ee"
*/
{

//	Ptype etp = ee->tp;
// error('d',"cast_cptr %k ccl %t ee->tp %t",ee->tp->base,ccl,ee->tp);
//	if (etp->base!=PTR && etp->base!=RPTR) return ee;
	Ptype etp = ee->tp->is_ptr_or_ref();
	if (etp == 0) return ee;

	Pname on = Pptr(etp)->typ->is_cl_obj();
	if (on == 0) return ee;

	Pclass ocl = Pclass(on->tp);
	if (ocl==ccl || ccl==0 || ocl==0) return ee;

// error('d',"cast_cptr %t(%t) real %d",ccl,ocl,real_cast);
	int oo = 0;
	Pexpr r = 0;

	if (ocl->baselist
	&& (ocl->baselist->bclass!=ccl || ocl->baselist->base!=NAME)) {
		// casting derived to second or virtual base?
		Nptr = 0;
		Nvis = 0; 
		Nalloc_base = 0;
		vcllist->clear();
		vcllist=0;
		int x = is_unique_base(ocl,ccl->string,0);
		if (Nvis) {
			if (real_cast==0)
				error("cast:%n* ->B%t*; privateBC",on,ccl);
			else if (warning_opt)
				error('w',"cast:%n* ->B%t*; privateBC",on,ccl);
			real_cast = 1;	// suppress further error mesages
			Nvis = 0;
		}

		switch (x) {
		default:
			error("cast:%n* ->B%t*;%t isB more than once",on,ccl,ccl);
		case 0:		// unrelated;
			break;
		case 1:
			oo = Noffset;
			break;
		}

		if (Nptr) {	// => ee?Nptr:0
                        if (ocl->c_body==1) ocl->dcl_print(0);
                        Nptr->mem = ee; // ee->Pbase_class
			if ( Nalloc_base ) {
// error('d', "cast_cptr: nalloc_base: %s", Nalloc_base);
				Nptr->i1 = 5;
				Nptr->string4 = new char[strlen(Nalloc_base)];
				strcpy(Nptr->string4,Nalloc_base);
				Nalloc_base = 0;
			}
			else Nptr->i1 = 3;

                        if (ee->base==ADDROF || ee->base==G_ADDROF)   
                                ee = Nptr;
                        else {
				Pexpr p = new expr(QUEST,Nptr,zero);
				nin = 1;
				if (ee->not_simple()) {	// need temp
					Ptype t = ee->tp;
					Pname pp = make_tmp('N',t,tbl);
					Pname(pp)->n_assigned_to = 1;
					ee = new expr(ASSIGN,pp,ee);
					ee->tp = t;
					Nptr->mem = pp;
				}
				nin = 0;
				p->cond = ee;
				p->tp = ee->tp;
                                ee = p;
			}
		}			
	}

	if (ccl->baselist
	&& (ccl->baselist->bclass!=ocl || ccl->baselist->base!=NAME)) {
		// casting second or virtual base to derived?
		Nptr = 0;
		vcllist->clear();
		vcllist=0;
		int x = is_unique_base(ccl,ocl->string,0);
		switch (x) {
		default:
			error("cast:%n* ->derived%t*;%n isB more than once",on,ccl,on);
		case 0:		// unrelated;
			break;
		case 1:
			oo = -Noffset;
                        if (Nptr)
                                error("cast:%n* ->derived%t*;%n is virtualB",on,ccl,on);
                        break;
		}
		Nvis = 0;	// visibility no concern when converting from base to derived
	}
// error('d',"oo %d ee %k",oo,ee->base);
	if (oo) {	// => ee?ee+offset:0
                if (ee->base==ADDROF || ee->base==G_ADDROF)
                        ee = rptr(ee->tp,ee,oo);
                else {
			Pexpr p;
			nin = 1;
			if (ee->not_simple()) {	// need temp
				Ptype t = ee->base==MDOT?ee->mem->tp:ee->tp;
				Pname pp = make_tmp('M',t,tbl);
				Pname(pp)->n_assigned_to = 1;
				ee = new expr(ASSIGN,pp,ee);
				ee->tp = t;
				p = rptr(t,pp,oo);
			}
			else
				p = rptr(ee->base==MDOT?ee->mem->tp:ee->tp,ee,oo);
			nin = 0;
			Pexpr pp = new expr(QUEST,p,zero);
			pp->tp = ee->tp;
			pp->cond = ee;
                        ee = pp;
		}
	}

	Nvis = 0; // Nvis set by has_base()
	if (ocl->has_base(ccl) && Nvis) {
		if (real_cast==0)
			error("cast:%n* ->B%t*; privateBC",on,ccl);
		else if (warning_opt)
			error('w',"cast:%n* ->B%t*; privateBC",on,ccl);
		Nvis = 0;
	}

// error('d',"return %d %k %t",ee,ee->base,ee->tp);
	return ee;
}

Pexpr expr::donew(Ptable tbl)
{
	Ptype tt = tp2;
	Ptype tpx = tt;
	bit v = 0;
	bit old = new_type;
	int init = 0;	// non-constructor initialization
	new_type = 1;

	tt->dcl(tbl);
	new_type = old;
// error('d',"donew %d %d (%k) tt %t",e1,e2,e2?e2->base:0,tt);
	if (e1) e1 = e1->typ(tbl);
	if (e2) e2 = e2->typ(tbl);
ll:
//error('d',"ll %d",tt->base);
	switch (tt->base) {
	default:
		if ( e1) {
			if (v) {
				error("Ir for array created using \"new\"");
				break;
			}
			init = 1;
		} 
	//	if (e1) {
	//		error("Ir for nonCO created using \"new\"");
	//		e1 = 0;
	//	}
		break;
	case VEC:
		if (v && Pvec(tt)->dim) error("only 1st array dimension can be non-constant");
		if (Pvec(tt)->size==0 && Pvec(tt)->dim==0) error("array dimension missing in `new'");
	//	if (Pvec(tt)->dim==zero) {
	//		Pvec(tt)->size = 0;
	//		Pvec(tt)->dim = 0;
	//	}
		v++;
		tt = Pvec(tt)->typ;
		goto ll;
	case TYPE:
		tt = Pbase(tt)->b_name->tp;
		goto ll;
	case VOID:
		error("badT for `new': void");
		break;
	case COBJ:
	{	Pname cn = Pbase(tt)->b_name;
		Pclass cl = Pclass(cn->tp);
		Pname icn = 0;

		if ( e1 ) { // arguments
			if ( e1->e2 == 0 && e1->base == ELIST ) {
				e1 = e1->e1;
				e1 = e1->typ(tbl);
			}
			icn = (e1->base!=ELIST)?e1->tp->is_cl_obj():0;
		}
		//Pname icn = (e1 && e1->base!=ELIST)?e1->tp->is_cl_obj() : 0;

		Pclass icl = icn ? Pclass(icn->tp) : 0;

		if (cl->c_abstract) {
			error("`new' of abstractC%t",cl);
			break;
		}

		if (v && e1) {
			error("Ir for array ofCO created using \"new\"");
			break;
		}

		if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) {
			error("new%n;%n isU",cn,cn);
			break;
		}

		Pname ctor = cl->has_ctor();

		if (ctor) {
			if (v) {
				Pname ic;
				if ((ic = cl->has_ictor())==0) {
					error("array ofC%n that does not have aK taking noAs",cn);
					break;
				}
					
				if (Pfct(ic->tp)->nargs) {
					error("defaultAs forK for array ofC%n",cn);
					break;
				}
			}

			if (icl
			&& cl->has_itor()==0	// incomplete:
						// what if X(Y&) exists
						// for class Y : X ?
			&& (icl==cl || icl->has_base(cl))) {
				init = 1;
				break;
			}
			e1 = call_ctor(tbl,0,ctor,e1);
		}
		else if (e1) {
			if (icl==cl || icl->has_base(cl)) 
				init = 1;
			else
				error("new%n(As ); %n does not have aK",cn,cn);
		}
	}
	}

	if (init) {
		Pname tmp = make_tmp('N',tt->addrof(),tbl);
		e1 = e1->typ(tbl);
		if (tt->check(e1->tp,ASSIGN))
			error("badIrT %t for new operator (%t X)",e1->tp,tt);
		e1 = new expr(0,tmp,e1);
		tmp->assign();
	}

//	tp = (v) ? tpx : tpx->addrof();
	switch (v) {
		case 0:
			tp = tpx->addrof();
			break;
		case 1:
			tp = tpx;
			break;
		default:
			tp = tpx;
	}
//error('d',"donew(%d) -> %t",v,tp);
	return this;
}

static is_dataMemPtr( Pexpr ee ) 
/* this is utterly implementation dependent 
 * called by expr::lval to determine 
 * const objects bounds to pointers to data members 
 */
{
	Pexpr te = ee->e1;
	if ( te == 0 ) return 0;
	if ( te->base != PLUS ) return 0;
	if ( (te = te->e2) == 0 ) return 0;
	if ( te->base != MINUS ) return 0;
	if ( (te = te->e1) == 0 ) return 0;
	if ( te->base != CAST ) return 0;
	if ( (te = te->e1) == 0 ) return 0;
	if ( te->tp->base != PTR ) return 0;
        if ( Pptr(te->tp)->memof == 0 ) return 0;
	return 1;
}
0707071010112044301004440001630000160000010200700466055402100001000000162346expr3.c/*ident	"@(#)ctrans:src/expr3.c	1.6" */
/***************************************************************************

	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.

expr3.c:

	type check function calls, casts, and explicit coercions

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

#include "cfront.h"
#include "size.h"

int pr_dominate(Ptype t1, Ptype t2)
/*
*/
{
	Pname cn1 = t1->is_cl_obj();
	Pname cn2 = t2->is_cl_obj();
//error('d',"pr_dominate(%t,%t)",t1,t2);

	if (cn1==0 || cn2==0) {
		Ptype p1 = t1->is_ptr();
		Ptype p2 = t2->is_ptr();
		if (p1 && p2) {			// pointers
			cn1 = Pptr(p1)->typ->is_cl_obj();
			cn2 = Pptr(p2)->typ->is_cl_obj();
			if (cn1==0 || cn2==0) return 0;
		}
		else {
			p1 = t1->is_ref();
			p2 = t2->is_ref();
			if (p1 && p2) {		// references
				cn1 = Pptr(p1)->typ->is_cl_obj();
				cn2 = Pptr(p2)->typ->is_cl_obj();
				if (cn1==0 || cn2==0) return 0;
			}
		//	else if (p1 && cn2) {
		//		cn1 = Pptr(p1)->typ->is_cl_obj();
		//	}
			else
				return 0;	// not the same and not classes
		}
	}
	Pclass c1 = Pclass(cn1->tp);
	Pclass c2 = Pclass(cn2->tp);
//error('d'," c1 : c2 %d; c2 : c1 %d",c1->has_base(c2),c2->has_base(c1));
	if (c1->has_base(c2)) return 1;
	if (c2->has_base(c1)) return 2;
	return 0;
}

int exact1(Pname,Ptype);
static exact2(Pname,Ptype);
static exact3(Pname,Ptype);

static Pname user_dominate(Pname n1, Pname n2, Pexpr arg)
{
	Pfct f1 = Pfct(n1->tp);
	Pfct f2 = Pfct(n2->tp);

	Pname a1 = f1->argtype;
	Pname a2 = f2->argtype;
//error('d',"user_dominate: %n %t %t",n1,f1,f2);

	for(; a1 && a2; a1 = a1->n_list, a2 = a2->n_list) {
		Ptype t1 = a1->tp;
		Ptype t2 = a2->tp;
	}

	if (a1 && !a1->n_evaluated) return n1;
	if (a2 && !a2->n_evaluated) return n2;

	a1 = f1->argtype;
	a2 = f2->argtype;

	Pname prev = 0;
	Pexpr e = arg;

	for(; a1 && a2 && e; a1 = a1->n_list, a2 = a2->n_list, e = e->e2) {
		Ptype t1 = a1->tp;
		Ptype t2 = a2->tp;
		Ptype at = e->e1->tp;

		int j = can_coerce(t1,at);
		Ptype tt1 = Ncoerce ? Pfct(Ncoerce->tp)->returns : 0;
		j = can_coerce(t2,at);
		Ptype tt2 = Ncoerce ? Pfct(Ncoerce->tp)->returns : 0;
		if(!tt1 || !tt2 || tt1->check(tt2,OVERLOAD)) 
			return 0;

		int one = 0, two = 0;
		if(exact1(a1,tt1)) one = 4;
		else if(exact2(a1,tt1)) one = 3;
		else if(exact3(a1,tt1)) one = 2;
		else one = 1;
		if(exact1(a2,tt1)) two = 4;
		else if(exact2(a2,tt1)) two = 3;
		else if(exact3(a2,tt1)) two = 2;
		else two = 1;

		if(one > two && (!prev || prev==n1)) prev = n1;
		else if(two > one && (!prev || prev==n2)) prev = n2;
		else if(one == two && one) ;
		else return 0;
	}
	if(prev) return prev;
	
	return 0;
}

Pname dominate(Pname n1, Pname n2, Pexpr arg, int const_obj, int level)
/*
	the two functions n1 and n2 can each respond to a call using
	standard conversions. Does the one dominate the other in the
	sense that all its arguments are identical to the other or
	classes defived from the class of the corresponding argument
	of the other.

	If so return it, otherwise return 0;
*/
{
	Pname res = 0;

	Pfct f1 = Pfct(n1->tp);
	Pfct f2 = Pfct(n2->tp);

	Pname a1 = f1->argtype;
	Pname a2 = f2->argtype;
	Pexpr e = arg;
//error('d',"dominate: %n %t %t e %d",n1,f1,f2,e);

	if (e == 0) {
		if (const_obj) {
			if (f1->f_const && f2->f_const==0) return n1;
			if (f2->f_const && f1->f_const==0) return n2;
		}
		else {
			if (f1->f_const==0 && f2->f_const) return n1;
			if (f2->f_const==0 && f1->f_const) return n2;
		}
		return 0;
	}

	for(; a1 && a2 && e; a1 = a1->n_list, a2 = a2->n_list, e = e->e2) {
		Ptype t1 = a1->tp;
		Ptype t2 = a2->tp;
		Ptype at = e->e1->tp;
//error('d',"t1 %t t2 %t at %t",t1,t2,at);
		if (t1==t2 || t1->check(t2,0)==0 )
			continue;
		Pptr r1 = t1->is_ref();
		Pptr r2 = t2->is_ref();
//error('d',"const_problem %t %t %t %d",t1,t2,at,const_problem);
		if (const_problem) {	// t1 and t1 differs only in const
			Pname rr;
			if (at->check(t1,0)==0 && const_problem==0) {
				if (t1->is_ptr())
					rr = n1;
				else
					goto nc;
			}
			else if (at->check(t2,0)==0 && const_problem==0) {
				if (t2->is_ptr())
					rr = n2;
				else
					goto nc;
			}
			else if (r1 && r1->typ->check(at,0)==0 && const_problem==0)
				rr = n1;
			else if (r2 && r2->typ->check(at,0)==0 && const_problem==0)
				rr = n2;
			else
				goto nc;
		
			if (res && res!=rr) return 0;	// mutual dominace
			res = rr;
			continue;	// identical
		}
	nc:
		if (r2 && (t1==r2 || t1->check(r2->typ,0)==0)) continue;
		if (r1 && (t2==r1 || t2->check(r1->typ,0)==0)) continue;

		Pname rr = 0;
		if (t1==at || exact1(a1,at))
			rr = n1;
		else if (t2==at || exact1(a2,at))
			rr = n2;
		else if (1<level) {	// try integral promotion
			if (exact2(a1,at))
				rr = n1;
			if (exact2(a2,at)) {
				if (rr) rr = 0;
				else rr = n2;
			}
		}
		if (!rr && 2<level) {	// try standard conversions
			if (exact3(a1,at))
				rr = n1;
			if (exact3(a2,at)) {
				if (rr) rr = 0;
				else rr = n2;
			}
		}
		if (rr) {
			if  (res && res!=rr) return 0;	// mutual dominance
			res = rr;
			continue;
		}

		int r = pr_dominate(t1,t2);
//error('d',"pr1 %d",r);
		if (r) {
			Pname rr = r==1?n1:n2;
			if (res && res!=rr) return 0;	// mutual dominace
			res = rr;
			continue;
		}

		r = pr_dominate(t1,at);
//error('d',"pr2 %d",r);
		if (r==2) {
			if (res && res!=n1) return 0;	// mutual dominace
			res = n1;
			r = pr_dominate(t2,at);
			if (r==2) return 0;	// mutual dominace
			continue;
		}

		r = pr_dominate(t2,at);
//error('d',"pr3 %d",r);
		if (r==2) {
			if (res && res!=n2) return 0;	// mutual dominace
			res = n2;
			continue;
		}

	}
	//if (a1==0 && a2 && a2->n_initializer==0) return 0;	// wrong number of arguments
	//if (a2==0 && a1 && a1->n_initializer==0) return 0;	// wrong number of arguments

	if (e) {
//error('d',"more args %t a1 %t a2 %t",e->e1->tp,a1?a1->tp:0,a2?a2->tp:0);
		int k1 = f1->nargs_known!=ELLIPSIS;
		int k2 = f2->nargs_known!=ELLIPSIS;
		if (a1 && a1->tp->check(e->e1->tp,ASSIGN)==0) return n1;
		if (a2 && a2->tp->check(e->e1->tp,ASSIGN)==0) return n2;
		if (k1 && k2) return 0;
	}

	if (a1==0 && a2 && a2->n_initializer==0) return 0;
	if (a2==0 && a1 && a1->n_initializer==0) return 0;
	if (res==0)
		if (const_obj) {
			if (f1->f_const && f2->f_const==0) return n1;
			if (f2->f_const && f1->f_const==0) return n2;
		}
		else {
			if (f1->f_const==0 && f2->f_const) return n1;
			if (f2->f_const==0 && f1->f_const) return n2;
		}
//error('d'," -> %n %t",res,res?res->tp:0);
	return res;
}

Pname Ntmp;

static refd;	// initialization routine called by ref_init, do not apply itor
static no_sti;
extern int stat_init;

Pname make_tmp(char c, Ptype t, Ptable tbl)
{
	int dt = 0; 
	Pname tn = tbl->t_name;
	Pname cn = t->is_cl_obj();

	if (tn && tn->tp) error('s',"defaultA too complicated");
	if (cn && Pclass(cn->tp)->has_dtor()) dt = 1;
	if (Ntmp == 0 && dt ) Ntmp = cn;

//error('d',"tbl %d cstmt %d %d sti %d",tbl,Cstmt,Cstmt?Cstmt->memtbl:0,sti_tbl);
	if (Cstmt) {	//	make Cstmt into a block
		if (Cstmt->memtbl == 0) Cstmt->memtbl = new table(4,tbl,0);
		tbl = Cstmt->memtbl;
	}
	else if (tbl == gtbl && no_sti == 0) {
		if (sti_tbl == 0) sti_tbl = new table(8,gtbl,0);
		tbl = sti_tbl;
	}

	Pname tmpx = new name(make_name(c));
	tmpx->where = no_where;
	tmpx->tp = t;
	(void) t->tsizeof();
	if ( t->base == COBJ ) {
     		Pclass cl = Pclass(Pbase(t)->b_name->tp);
     		if ( cl->lex_level ) tmpx->lex_level = cl->lex_level;
	}

	TOK scop = ARG;
	if (stat_init && dt) { 
		tmpx->n_sto = STATIC; scop = ARGS; 
	}

	// ARG[S]: no init; ARGS: static dtor
	Pname tmp = tmpx->dcl(tbl,scop); 
	delete tmpx;

	// n_scope == ARGS sets static dtor in simpl2.c
	tmp->n_scope = (scop==ARG) ? FCT : ARGS;
	return tmp;
}

Pexpr init_tmp(Pname tmp, Pexpr init, Ptable tbl)
{
	Pname cn = tmp->tp->is_cl_obj();
	Pname ct = cn ? Pclass(cn->tp)->has_itor() : 0;

	tmp->n_assigned_to = 1;
//error('d',"init_tmp %n ct %n refd %d",tmp,ct,refd);
	if (ct) {	// must initialize
		if (refd) {
//error('d',"'orrible %k",init->e1->base);
			switch (init->e1->base) {	// 'orrible 'ack
			case NAME:
			case REF:
			case DEREF:
				if (init->e1->tp->is_ptr())
					init = init->e1;
				else
					init = new expr(G_CM,init,init->e1->address());
					
			}
			if (ct->tp->base == OVERLOAD) ct = Pgen(ct->tp)->fct_list->f;	// first fct
			tbl = 0;
		}
		return call_ctor(tbl,tmp,ct,init,DOT);
	}
	Pexpr ass = new expr(ASSIGN,tmp,init); // no ctor: can assign
	ass->tp = tmp->tp;
	return ass;
}
/*
int exact0(Pname nn, Ptype at)
//	return 1 if
//	exact match

{
	if (nn == 0) return 0; //known==ELLIPSIS;
	Ptype nt = nn->tp;
	if (at == nt) return 1;
//error('d',"exact0 %d",nt->check(at,0));
	return nt->check(at,0)==0;
}
*/

int exact3(Pname nn, Ptype at)
/*
	return 1 if
	match with standard conversions
*/
{
	if (nn == 0) return 0; //known==ELLIPSIS;
	Ptype nt = nn->tp;

	while(nt->base == TYPE)
		nt = Pbase(nt)->b_name->tp;

	if (at == nt) return 1;

	switch (nt->base) {
	case RPTR:
		if (at==zero_type && Pptr(nt)->typ->is_ptr()==0) return 0; //break;
		if (nt->check(at,COERCE)) {
			Pptr pt = at->addrof();
			nt->base = PTR;		// handle derived classes
			if (nt->check(pt,COERCE)) {
				nt->base = RPTR;
				delete pt;
				return 0;
			}
			nt->base = RPTR;
			delete pt;
		}
		break;
	default:
		switch (at->base) {
		default: 
			if (nt->check(at,COERCE)) return 0;
			break;
		case OVERLOAD:
			// the actual argument is an overloaded function
			// we'll try each instance until one matches
			register Plist gl;
			int no_match = 1;

			for (gl = Pgen(at)->fct_list; gl; gl=gl->l) {
				if (nt->check(gl->f->tp,COERCE)==0) {
					no_match = 0;
					break;
				}
			}

			if ( no_match ) return 0;
		} 
	}
	return 1;
}

int exact1(Pname nn, Ptype at)
/*
	return 1 if
	exact match with
		T <-> const T
		X -> X&
		T* -> const T*
		T* -> T*const
	taken into account
*/
{
	if (nn == 0) return 0;//known==ELLIPSIS;
	Ptype nt = nn->tp;
	if (at == nt) return 1;

//error('d',"exact1 nt %t at %t",nt,at);
	if (nt->check(at,0)) {
//error('d',"nt %t at %t cp %d",nt,at,const_problem);
		if (const_problem)  return 1;	// handle T <-> const T

		Pptr rt = nt->is_ref();	//handle X -> X&
		if (rt && (at->check(Pptr(rt)->typ,0)==0 || const_problem))  return 1;

		Pptr art = at->is_ptr();
		if (rt && art) return 0; // ptrs do not match refs

		// handle T* -> const T* and
		// T* -> T*const
		if (rt || (rt = nt->is_ptr())) {
			if (art == 0) art = at->is_ref();
			if (art) {
//error('d',"art %t %t",art->typ,rt->typ);
				if (art->typ->check(rt->typ,0)) {
					if (const_problem)  return 1;
				}
				else	// T* -> T*const
					 return 1;
			}
		}
		return 0;
	}
	return 1;
}

Pexpr Ninit;	// default argument used;
int Nstd;	// standard coercion used (derived* =>base* or int=>long or ...)

bit exact_match(Pname n, Pexpr arg)
/*
	look for an exact match between "n" and the argument list "arg"
	This function goes through three stages:
	(1) exact match (no coercions at all)
	(2) do integral promotions and float->double and re-try exact match
	(3) try for unique standard conversions

*/
{
	Pfct f = Pfct(n->tp);
	register Pexpr e;
	register Pname nn;

// error('d',"exact_match(%n) %t",n,n->tp);

	for (e=arg, nn=f->argtype; e; e=e->e2, nn=nn->n_list) {
		Pexpr a = e->e1;
		Ptype at = a->tp;
		if (at->base == ANY) return 0;
		if (at->base == ZTYPE) at = int_type;
		if (exact1(nn,at)==0) return 0;
	}

//error('d',"exact %d -> %d",nn,nn?nn->n_initializer!=0:1);
	if (nn) {
		Ninit = nn->n_initializer;
		return Ninit!=0;
	}

//error('d',"return 1");
	return 1;	// exact match without any promotions
}

int exact2(Pname nn, Ptype at)
/*
	return 1 if
	do integral promotion and float->double on at, then match
*/
{
//error('d',"exact2 nt %t at %t",nn?nn->tp:0,at);
	while(at->base == TYPE)
		at = Pbase(at)->b_name->tp;

	switch (at->base) {
	case EOBJ:
		at = Penum(Pbase(at)->b_name->tp)->e_type;
		break;
	case ZTYPE:
		at = int_type;
		break;
	case CHAR:
	case SHORT:
		at = (Pbase(at)->b_unsigned && at->tsizeof()==SZ_INT) ? uint_type : int_type;
		break;
	case FLOAT:
		at = double_type;
	}

	if (nn == 0) return 0;//known==ELLIPSIS;
	Ptype nt = nn->tp;
//error('d',"	exact2 nt %t at %t",nt,at);
	if (at == nt) return 1;
	if (nt->check(at,0)) {
		if (const_problem) return 1;

		Pptr rt = nt->is_ref();	// handle X -> X&
		if (rt && (at->check(Pptr(rt)->typ,0)==0 || const_problem)) return 1;

		Pptr art = at->is_ptr();
		if (rt && art) return 0; // ptrs do not match refs

		// handle T* -> const T* and
		// T* -> T*const
		if (rt || (rt = nt->is_ptr())) {
			if (art == 0) art = at->is_ref();
			if (art) {
				if (art->typ->check(rt->typ,0)) {
					if (const_problem) return 1;
				}
				else	// T* -> T*const
					return 1;
			}
		}
		return 0;
	}
	return 1;
}

bit prom_match(Pname n, Pexpr arg)
/*
	look for an exact match between "n" and the argument list "arg"
	using integral promotions and float->double

*/
{
	Pfct f = Pfct(n->tp);
	register Pexpr e;
	register Pname nn;

// error('d',"prom_match(%n) %t",n,n->tp);

	for (e=arg, nn=f->argtype; e; e=e->e2, nn=nn->n_list) {
		Pexpr a = e->e1;
		Ptype at = a->tp;
		if (at->base == ANY) return 0;

		if (exact2(nn,at)==0) return 0;
	}
	
	if (nn) {
		Ninit = nn->n_initializer;
		return Ninit!=0;
	}

	return 1;	// exact match with promotions
}

bit std_match(Pname n, Pexpr arg)
/*
	look for an exact match between "n" and the argument list "arg"
	using standard conversions

*/
{
	Pfct f = Pfct(n->tp);
	register Pexpr e;
	register Pname nn;

// error('d',"std_match(%n) %t",n,n->tp);

	for (e=arg, nn=f->argtype; e; e=e->e2, nn=nn->n_list) {
		Pexpr a = e->e1;
		Ptype at = a->tp;

		if (at->base == ANY) return 0;
		if ( exact3(nn,at) == 0) return 0;
	}

	if (nn) {
		Ninit = nn->n_initializer;
		return Ninit!=0;
	}

	return 1;
}

Pname Ncoerce;
int ref_cast;

bit can_coerce(Ptype t1, Ptype t2)
/*	return number of possible coercions of t2 into t1,
	Ncoerce holds a coercion function (not constructor), if found
*/
{
	int zz = 0;
	Ncoerce = 0;
	if (t2->base == ANY) return 0;
// error('d',"can_coerce t1 %t t2 %t",t1, t2);

	while(t1->base == TYPE)
		t1 = Pbase(t1)->b_name->tp;

	switch (t1->base) {
	case RPTR:
		while(t2->base == TYPE)
			t2 = Pbase(t2)->b_name->tp;

		switch (t2->base) {
	//	case VEC:
	// 	case PTR:
	//	case RPTR:
  	//		if (t1->check(t2,COERCE) == 0) return 1;
		default:	
		{	Ptype tt2 = t2->addrof();
			if (t1->check(tt2,COERCE) == 0) return 1;
			if (ref_cast) break;//return 0;	// (T&): no coercions
							// except operator T&()
			Ptype tt1 = Pptr(t1)->typ;
			while (tt1->base==TYPE) tt1 = Pbase(tt1)->b_name->tp;
			int bc;
			if ( tt1->base != PTR && tt1->base != RPTR ) {
     				bc = Pbase(tt1)->b_const;
     				Pbase(tt1)->b_const = 0; 
			}
			int i = can_coerce(tt1,t2);
			if ( tt1->base != PTR && tt1->base != RPTR ) 
     				Pbase(tt1)->b_const = bc;
			if (i) return i;
			zz = 1;
		}
		}
	}

	Pname c1 = t1->is_cl_obj();
	Pname c2 = t2->is_cl_obj();
	int val = 0;
	if (ref_cast || zz) goto oper_coerce;
	if (c1) {
		Pclass cl = Pclass(c1->tp);
		if (c2 && c2->tp==cl) return 1;

                // A more comprehensive test for template classes
                if (c2 && (Pclass(c1->tp)->same_class(Pclass(c2->tp))))
			 return 1 ;

		/*	look for constructor
				with one argument
				or with default for second argument
			of acceptable type
		*/
		Pname ctor = cl->has_ctor();
		if (ctor == 0) goto oper_coerce;
		register Pfct f = Pfct(ctor->tp);
//error('d',"ctor %n f %t",ctor,f);
		switch (f->base) {
		case FCT:
			switch (f->nargs) {
			case 1:
			one:
			{	Ptype tt = f->argtype->tp;
					if (tt->check(t2,COERCE)==0)
						val = 1;
					else if (const_problem) {
						Pptr p1 = tt->is_ptr_or_ref();
						if (p1==0 || p1->typ->tconst()) val = 1;
					}
				if (tt = tt->is_ref()) {
					Pptr pt = t2->addrof();	// handle derived classed
					tt->base = PTR;
					if (tt->check(pt,COERCE) == 0) val = 1;
					tt->base = RPTR;
					delete pt;
				}
				goto oper_coerce;
			}
			default:
				if (f->argtype->n_list->n_initializer) goto one;
			case 0:
				goto oper_coerce;
			}
		case OVERLOAD:
		{	register Plist gl;

			for (gl=Pgen(f)->fct_list; gl; gl=gl->l) { // look for match
				Pname nn = gl->f;
				Pfct ff = Pfct(nn->tp);

				switch (ff->nargs) {
				case 0:
					break;
				case 1:
				over_one:
				{	Ptype tt = ff->argtype->tp;
//error('d',"over one %t %t -> %d %d",tt,t2,tt->check(t2,COERCE),const_problem);
					if (tt->check(t2,COERCE)==0)
						val = 1;
					else if (const_problem) {
						Pptr p1 = tt->is_ptr_or_ref();
						if (p1==0 || p1->typ->tconst()) val = 1;
					}
					if (tt=tt->is_ref()) {
						Pptr pt = t2->addrof();	// handle derived classed
						tt->base = PTR;
						if (tt->check(pt,COERCE) == 0) {
							tt->base = RPTR;
							delete pt;
							val = 1;
							goto oper_coerce;
						}
						tt->base = RPTR;
						delete pt;
					}
					break;
				}
				default:
					if (ff->argtype->n_list->n_initializer) goto over_one;
				}
			}
			goto oper_coerce;
		}
		default:
			error('i',"cannot_coerce(%k)\n",f->base);
		}
	}

oper_coerce:
//error('d',"oper_coerce %d",val);
	if (c2) {	
		Pclass cl = Pclass(c2->tp);
		int std = 0;
		int oval = val;
		extern Pname conv_dominates(Pname,Pname);
		for (Pname ox, on=cl->conv; on; on=ox) {
			ox = on->n_list;
// error( 'd', "can_coerce: ox: %s on: %s tp: %k", ox?ox->string:"", on->string, on->tp->base );
			Plist gl = 0;
			if ( on->tp->base == OVERLOAD ) {
				gl = Pgen(on->tp)->fct_list;
				on = gl->f;
				gl = gl->l;
			}

overlist: 
// error( 'd', "can coerce: on: %n tp: %t gl: %d", on, on->tp, gl );

			Pfct f = Pfct(on->tp);
			Nstd = 0;
			if (t1->check(f->returns,COERCE) == 0) {
				if (Nstd==0) {	// forget solutions involving standard conversions
					Pname old = Ncoerce;
					if (std) {	// forget
						val = oval+1;
						std = 0;
						Ncoerce = on;
					}
					else if (Ncoerce == 0) {
					//	val = 1;
						val++;
						Ncoerce = on;
					}
					else if ((Ncoerce = conv_dominates(Ncoerce,on))==0) {
						if (val == 1) {
//error('d',"val==1 on %n old %n",on,old);
							Ptype ton = Pfct(on->tp)->returns;
							Ptype tco = Pfct(old->tp)->returns;
							if (t1->check(ton,0)==0)
								;
							else if (t1->check(tco,0)==0)
								on = old;
							else
								val++;
						}
						else
							val++;
						Ncoerce = on;
					}
				}
				else {	// take note only if no exact match seen
					if (Ncoerce==0 || on->tp->check(Ncoerce->tp,0)) {
						if (val==0 || std) {

							if (Ncoerce) Ncoerce = conv_dominates(Ncoerce,on);
							if (Ncoerce == 0) {
								Ncoerce = on;
								val++;
								std = 1;
							}	
						}
					}
				}
			}
// error( 'd', "can_coerce: gl: %d", gl );
			if ( gl ) {
				on = gl->f;
				gl = gl->l;
				goto overlist; // must walk list of overloaded instances
			}
		}
	}
//error('d',"val %d",val);
	if (val) return val;
	if (c1 && Pclass(c1->tp)->has_itor()) return 0;
//error('d',"%t->check(%t) -> %d",t1,t2,t1->check(t2,COERCE));
	if (t1->check(t2,COERCE)) return 0;
	return 1;
}

int gen_coerce(Pname n, Pexpr arg)
/*
	look to see if the argument list "arg" can be coerced into a call of "n"
	1: it can
	0: it cannot or it can be done in more than one way
*/
{
	Pfct f = (Pfct) n->tp;
	register Pexpr e;
	register Pname nn;

//error('d',"gen_coerce(%n,%d) %t",n,arg,n->tp);
	for (e=arg, nn=f->argtype; e; e=e->e2, nn=nn->n_list) {
		if (nn == 0) return f->nargs_known==ELLIPSIS;
		Pexpr a = e->e1;
		Ptype at = a->tp;
		int i = can_coerce(nn->tp,at);
		if (i != 1) return 0;
	}
	if (nn && nn->n_initializer==0) return 0;
	return 1;
}


Pname Nover;
// int Nover_coerce;

int over_call(Pname n, Pexpr arg)
/*	
	return 4 if n(arg) can be performed without coercion of arg
	return 3 if n(arg) can be performed only with promotion coercion of arg
	return 2 if n(arg) can be performed only with standard coercion of arg
	return 1 if n(arg) can be performed only with user defined coercion of arg
	return 0 if n(arg) is an error
	Nover is the function found, if any
	Nstd is the number of standard coercions used
*/
{	
	register Plist gl;
	Pgen g = Pgen(n->tp);
	if (arg && arg->base!= ELIST) error('i',"ALX");

//error('d',"over_call(%n) %k",n,n->tp->base);
	extern suppress_error;
	suppress_error = 1;
//	Nover_coerce = 0;
	Nstd = 0;
	switch (g->base) {
	default:	error('i',"over_call(%t)\n",g);
	case OVERLOAD:	break;
	case FCT:
		Nover = n;
		Ninit = 0;
		if (exact_match(n,arg)) {suppress_error = 0; return 4;}
		if (prom_match(n,arg)) {suppress_error = 0; return 3;}
		if (std_match(n,arg) && Ninit==0) {suppress_error = 0; return 2;}
		Nstd = 0;
		suppress_error = 0;
		return gen_coerce(n,arg);
	}

	Pname exact = 0;
	int no_exact = 0;
	int ret = 0;
	Pname nret;
	for (gl=g->fct_list; gl; gl=gl->l) {		/* look for match */
		Nover = gl->f;
		Ninit = 0;
		Nstd = 0;
		if (exact_match(Nover,arg)) {suppress_error = 0; return 4;}	// no coercion
	//	if (prom_match(Nover,arg)) return 3;	// only promotion
	//	if (std_match(Nover,arg) && Ninit==0) return 2;	// only built-in conversion
		if (ret<3 && prom_match(Nover,arg)) {
			nret = Nover;
			ret = 3;
		}
		if (ret<2 && std_match(Nover,arg) && Ninit==0) {
			nret = Nover;
			ret = 2;
		}
	}

suppress_error = 0;
	if (ret) {
		Nover = nret;
		return ret;
	}

	Nover = 0;
	for (gl=g->fct_list; gl; gl=gl->l) {		/* look for coercion */
		Pname nn = gl->f;
		if (gen_coerce(nn,arg)) {
			Nover = nn;
			return 1;
		}
	}
	return 0;

}

Ptype expr::call_fct(Ptable tbl)
/*
	check "this" call:
		 e1(e2)
	e1->typ() and e2->typ() has been done
*/
{
	Pfct f;
	Pname fn;
	int x;
	int k;
	Pname nn;
	Pexpr e;
	Ptype t;
	Pexpr arg = e2;
	Ptype t1 = e1?e1->tp:0;
	int argno;
	Pexpr etail = 0;
	bit no_change = 0;
	Pname no_virt = 0;	// set if explicit qualifier was used: c::f()
	Pname chk = 0;		// set if visibility check is needed
				// that is if function name might have been
				// found without use of find_name()
	int const_obj = 0;

	if (t1 == any_type) return any_type;

	switch (base) {
	case CALL:
	case G_CALL:	break;
	default:	error('i',"call_fct(%k)",base);
	}

// error('d',"call %d %k %n arg %d",this,e1->base,e1->base==NAME?e1:0,arg);
	if (t1 == 0) error('i',"call_fct(e1=%d,e1->tp=%t)",e1,t1);
	if (arg && arg->base!=ELIST) error('i',"badAL%d%k",arg,arg->base);

	switch (e1->base) {
	case NAME:
		fn = Pname(e1);
//error('d',"name %n %k",fn,fn->n_oper);
		switch (fn->n_oper) {
		case 0:
		case CTOR:
		case DTOR:
		case TYPE:
		case NEW:
		case DELETE:
			break;
		default:	// real operator: check for operator+(1,2);
			if (arg == 0) break;
			Pexpr a = arg->e1;	// first operand

			if (Pfct(fn->tp)->memof	// obj.operator(1) is OK
			|| a->tp->is_cl_obj()
			|| a->tp->is_ref()) break;
			a = arg->e2;
			if (a == 0)		// unary
				error("%k of basicT",fn->n_oper);
			else {			// binary
				a = a->e1;	// second operand
				if (a->tp->is_cl_obj() || a->tp->is_ref()) break;
				error("%k of basicTs",fn->n_oper);
			}
			break;
		}
		break;
	case REF:
	case DOT:
		no_virt = Pname(e1->n_initializer);
		e1->n_initializer = 0;
		if (e1 && e1->e1) {
			Ptype t = e1->e1->tp;
			Pptr tt = t->is_ptr_or_ref();
			Ptype ft = tt ? tt->typ : t;
			Pexpr ee = e1->e1;
			const_obj = ft->tconst();
                	while (ee && (ee->base==DOT || ee->base==REF)) {
                        	Pexpr m = ee->mem;
                        	if ( ee->base==REF && m->tp &&  m->tp->is_ptr())
                                	break;
                        	ee = ee->e1;
                	}
                 	if (ee) {
                        	Ptype ttt = ee->tp;
				int tc;
                        	switch (e1->base) {
                        	case REF:
                        	        Pptr p = ttt?ttt->is_ptr():0;
                                	if (p && p->typ->tconst())
                                        	const_obj = 1;
                                	break;
                        	case DOT:
					tc = ttt ? ttt->tconst() : 0;
                                	if(ttt && tc && (!strict_opt || tc!=2))
                                        	const_obj = 1;
                        	}
                	}
		}
	case MDOT:
	{	Pexpr n = e1->mem;
	lxlx:
		switch (n->base) {
		case MDOT:
			// reverse mdot (see expr::print())
			//	p->a.b()  => (&p->a)->b() => b(&p->a)
			// or	p->a->b() => (p->a)->b()  => b(p->a)
			// or	oo.a.b()  => (&oo.a)->b() => b(&oo.a)
			// or	oo.a->b() => (oo.a)->b()  => b(oo.a)
		{	
			Pexpr r = e1;
			Pexpr p = r->e1;
			for (Pexpr m = r->mem; m->base==MDOT; m = r->mem) {
				p = new mdot(m->string2,p);
				p->i1 = m->i1+2;
				p->tp = p->mem->tp;
				r->mem = m->mem;
				r->e1 = p;
			}
		}
		case REF:
		case DOT:
			n = n->mem;
			goto lxlx;
		case NAME:
			break;
		default:
			error('i',"ref %k",n->base);
		}
		fn = Pname(n);
//error('d',"mem %n",fn);
		break;
	}
	case MEMPTR:
	default:
		fn = 0;
	};

lll:
//error('d',"lll: %t %k",t1,t1->base);
	switch (t1->base) {
	case TYPE:
		t1 = Pbase(t1)->b_name->tp;
		goto lll;

	case PTR:	// pf() allowed as shorthand for (*pf)()
		switch (Pptr(t1)->typ->base) {
		case FCT:
		case OVERLOAD:
			if (Pptr(t1)->memof) error("O missing in call throughP toMF");
			t1 = Pptr(t1)->typ;
			fn = 0;
			goto lll;
		}

	default:
		if (fn)
			error("call of%n;%n is a%t",fn,fn,e1->tp);
		else
			error("call of%kE ofT%t",e1->base,e1->tp);

	case ANY:
		return any_type;
	
	case OVERLOAD:
	{	register Plist gl;
		Pgen g = Pgen(t1);
		Pname found = 0;
		Pname exact = 0;
		int no_exact = 0;
		int no_gen = 0;

		for (gl=g->fct_list; gl; gl=gl->l) {	// look for exact match
			register Pname nn = gl->f;
			if (exact_match(nn,arg)) {
//error('d',"found exact %n %t",nn,nn->tp);
				if (found) {
					// check if one fct dominates the other
					Pname d = dominate(found,nn,arg,const_obj,0);
					if (d)
						nn = d;
					else
						error("two exact matches for%n:%t and%t",nn,nn->tp,found->tp);
				}
				found = nn;
			}
		}
//error('d',"found exact2 %n",found);
		if (found) goto fnd;

Pname mvec[20];

/****************************************************************************
   the next 2 loops have been commented out to eliminate the rule that calls
   requiring only promotions and standard conversions are preferred over
   calls requiring user-defined conversions.

		for (gl=g->fct_list; gl; gl=gl->l) {	// look for exact match
			register Pname nn = gl->f;

			if (prom_match(nn,arg)) {
				if (found) {
					// check if one fct dominates the other
					Pname d = dominate(found,nn,arg,const_obj,1);
					if (d)
						nn = d;
					else
						error("two exact matches (after integral promotions) for%n:%t and%t",nn,nn->tp,found->tp);
				}
				found = nn;
			}
		}
//error('d',"found exact2 %n",found);
		if (found) goto fnd;

	//	for (gl=g->fct_list; gl; gl=gl->l) {	// look for exact match
	//		register Pname nn = gl->f;
	//
	//		if (exact_match(nn,arg) || prom_match(nn,arg)) {
	//			found = nn;
	//			goto fnd;
	//		}
	//	}

		for (gl=g->fct_list; gl; gl=gl->l) {	// look for match
							// with standard conversion
			register Pname nn = gl->f;
			Ninit = 0;
			Nstd = 0;
			if (std_match(nn,arg)) {
			//	if (Nstd == 0)  {
			//		found = nn;
			//		goto fnd;
			//	}
				if (exact) {
					// check if one fct dominates the other
					Pname d = dominate(exact,nn,arg,const_obj,2);
					if (d == 0) {
						mvec[no_exact++] = nn;
					//	no_exact++;
					//	error("two standard conversions possible for%n: %t and %t",fn,exact->tp,nn->tp);
					}
					else
						exact = d;
				}
				else
					exact = nn;
			}
			
		}

//error('d',"excact %n",exact);
		if (exact) {
			if (no_exact) {
				while (no_exact) {
					Pname d = dominate(exact,mvec[--no_exact],arg,const_obj,2);
					if (d)
						exact = d;
					else
						error("two standard conversions possible for%n: %t and %t",fn,exact->tp,mvec[no_exact]->tp);
				}
				
			}
//error('d',"found exact3 %n",found);
			found = exact;
			goto fnd;
		}

    this is the end of the commented out section.
************************************************************************/

		for (gl=g->fct_list; gl; gl=gl->l) {	/* look for coercion */
			register Pname nn = gl->f;
			if (prom_match(nn,arg) ||
			    std_match(nn,arg)  ||
			    gen_coerce(nn,arg)) {
//error('d',"user2 %n %t",nn,nn->tp);
				if (found) {
					// check if one fct dominates the other
					Pname d = dominate(found,nn,arg,const_obj,3);
//error('d',"dom d %d",d);
					if (d == 0) d = user_dominate(found,nn,arg);
					if (d == 0) {
						mvec[no_gen++] = nn;
					}
					else
						found = d;
				}
				else
					found = nn;
			}
		}
		if(found) {
			while(no_gen) {
				Pname d = dominate(found,mvec[--no_gen],arg,const_obj,3);
				if(d==0) d = user_dominate(found,mvec[no_gen],arg);
				if(d)
					found = d;
				else {
					//error("ambiguousA for%n: %t and %t",fn,found->tp,mvec[no_gen]->tp);
					error("ambiguous call of%n: %t and %t",fn,found->tp,mvec[no_gen]->tp);
				}
			}
		}
	fnd:
//error('d',"fnd %t",found?found->tp:0);
		if (found) {
			overFound = chk = fn = found;
			f = Pfct(fn->tp);
		}
		else {
			error("badAL for%n (no match against any %n)",fn,fn);
			return any_type;
		}
		break;
	}
	case FCT:
		f = Pfct(t1);
		if (fn) {
			switch (fn->n_oper) {
			case CTOR:
			case TYPE:
				chk = fn;
			}
		}
	}

//error('d',"chk %n",chk);
	if (chk) {
		Ptype t = 0;
		Pexpr ee = e1->e1;

		switch (e1->base) {
		case REF:	// ptr->chk()
			if (ee == 0) {	// 0->x() fudge handling new x()
				check_visibility(chk,no_virt,Pclass(chk->n_table->t_name->tp),tbl,cc->nof);
				break;
			};
			t = ee->tp;
			while(t->base==TYPE) t = Pbase(t)->b_name->tp;
			t = Pptr(t)->typ;
			break;
		case DOT:	// obj.chk()
			t = ee->tp;
		}

		Pname cn = t?t->is_cl_obj():0;
		Pclass cl = cn?Pclass(cn->tp):0; // class of ``this'' for chk

		if (cl) {
			if (chk->n_oper==CTOR
				&& chk->n_protect
				&& cc->nof
				&& cc->nof->n_oper==CTOR)
					// BUG: cannot handle protected base
					// class constructor
				;
			else {
				check_visibility(chk,no_virt,cl,tbl,cc->nof);
			}
		}
	}

	if (fn && f->returns->is_cl_obj() && f->f_result==0) {
		// protect against class cn; cn f(); ... class cn { cn(cn&); ... };
		make_res(f);
//error('d',"returns %t",f->returns);
		f->returns->tsizeof();	// make sure it is declared
	}

//error('d',"fn %n %t printed %d",fn,fn?fn->tp:0,fn?fn->n_dcl_printed:0);
	if (fn && fn->n_dcl_printed==0) {
		if (f->f_inline==0 && f->f_imeasure) {
			extern void uninline(Pname fn);
			uninline(fn);
		}

		// ensure printout of class declaration:
		for (Pname nn=f->argtype; nn; nn=nn->n_list)
			if (nn->tp->is_cl_obj()) (void) nn->tp->tsizeof();

		fn->dcl_print(0);
	}

	if (no_virt && f->f_static==0) {
		if (e1->base==REF || e1->base==DOT) e1->n_initializer = fn;
	}
	else
		fct_name = fn;
//error('d',"fn %n %t %d %d",fn,f,f->f_this,f->f_static);
	if (f->f_this) {	//SSS call of non-static memberfunction
		switch (e1->base) {
		case MEMPTR:
		case REF:
		case DOT:
			break;
		default:
			error("O orP missing for%n ofT %t",fct_name,f);
		}
	}
	else if (fn) {	//SSS call of static function
	sss:
		switch (e1->base) {
		case REF:
		case DOT:
			e1 = e1->mem;
			goto sss;
		}
	}

	if (fn) fn->use();	// a patch: ctors are sometimes not use()d

	if (f->f_const==0
	&& (fn==0 || (fn->n_oper!=CTOR && fn->n_oper!=DTOR))) {	//CCC
		Pexpr ee = e1->e1;
                // while (ee && (ee->base==DOT || ee->base==REF)) ee = ee->e1;
                while (ee && (ee->base==DOT || ee->base==REF)) {
			Pexpr m = ee->mem;
// error('d', "m: %k tp %t", m?m->base:0, m?m->tp:0 ); 
			if ( ee->base==REF && m->tp &&  m->tp->is_ptr())
				break;
			ee = ee->e1;
		}
// error('d', "ee: %k tp %k", ee?ee->base:0, ee?ee->tp->base:0);

		if (ee) {
			Ptype tt = ee->tp;
			switch (e1->base) {
			case REF:
			{	Pptr p = tt?tt->is_ptr():0;
				if (p && p->typ->tconst())
					error(strict_opt?0:'w',"non-constMF%n called for constO (anachronism)",fn);
				// is really an error, but only warn to help transition
				break;
			}
			case DOT:
				int tc = tt ? tt->tconst() : 0;
				if (tt && tc && (!strict_opt || tc!=2))
					error(strict_opt?0:'w',"non-constMF%n called for constO (anachronism)",fn);
				// is really an error, but only warn to help transition
			}
		}
	}

	t = f->returns;
	x = f->nargs;
	k = f->nargs_known;

	e = arg;
	if (k == 0) goto rlab;

	for (nn=f->argtype, argno=1; e||nn; nn=nn->n_list, e=etail->e2, argno++) {
		Pexpr a;
		int save_base = 0;
		char* save_name = 0;

		if (e) {
			a = e->e1;
			etail = e;

			if (nn) {	/* type check */
				Ptype t1 = nn->tp;
//error('d',"argtp %t etp %t a %k",t1,a->tp,a->base);

				while(t1->base == TYPE)
					t1 = Pbase(t1)->b_name->tp;

				switch (t1->base) {
				case RPTR:
				{	Ptype pt = Pptr(t1)->typ;
					if (pt->base != FCT ||
						( pt->base == FCT && 
						  pt->check(a->tp,0)))
							a = ref_init(Pptr(nn->tp),a,tbl);
					goto cbcb;
				}
				case COBJ:
					if (a->base!=G_CM
					|| nn->tp->check(a->tp,ASSIGN))
						a = class_init(0,t1,a,tbl);
					else
						a->e2=class_init(0,t1,a->e2,tbl);
					if (nn->n_xref) {
						// (temp.ctor(arg),&arg)
						a = a->address();
					}
					else {
						// defend against:
						//	int f(X); ... X(X&);
						Pname cln = Pbase(t1)->b_name;	
						if (cln && Pclass(cln->tp)->has_itor()) {
							// mark X(X&) arguments
							nn->n_xref = 1;
							a = a->address();
						}
					}
	cbcb:
//error('d',"cbcb: a %d %k %t",a->base,a->base,a->tp);
		if (a->base==G_CM) {
			if (a->e1->base==DEREF) a->e1 = a->e1->e2; // (*e1,e2) => (e1,e2)
//error('d',"      a %d %k",a->e1->base,a->e1->base);
			if (a->e1->base==G_CALL
			&& Pname(a->e1->fct_name)
			&& Pname(a->e1->fct_name)->n_oper==CTOR
			&& (a->e2->base==G_ADDROF || a->e2->base==ADDROF)) {
				a = a->e1;	// (ctor(&tmp),&tmp) => ctor(&tmp)
//error('d',"tmp %k %n",a->e2->base,a->e2->e2);
				goto cccc;
			}
			else if (a->e2->base==G_ADDROF
			&& a->e2->e2->base==NAME)  {
			cccc:
//error('d',"cccc: a %d %k %t",a->base,a->base,a->tp);
	if (t1->base==RPTR
	&& Pptr(t1)->typ->tconst()==0) {	// temporary used
		if (warning_opt)
			error('w',"temporary used for non-const%tA",nn->tp);
		else {
			Ptype atp = a->tp;
			if (atp==void_type
			&& a->base==G_CALL
			&& a->e1->tp->base==FCT)
				atp = Pfct(a->e1->tp)->s_returns;

			Ptype tt = t1->is_ref();
//error('d',"tt %t atp %t",tt,atp);
			if (tt) {
				if (Pptr(tt)->typ->tsizeof()!=atp->tsizeof()) {	// sliced
					Ptype aat = atp->is_ptr_or_ref();
					if (aat==0
					|| Pptr(tt)->typ->tsizeof()!=Pptr(aat)->typ->tsizeof())
						error('w',"temporary used for non-const%tA",nn->tp);
				}
			}
			else if (t1->tsizeof()!=atp->tsizeof())	// sliced
				error('w',"temporary used for non-const%tA",nn->tp);
		}
		
	//	if (warning_opt				// blabber
	//	||  t1->tsizeof()!=a->tp->tsizeof()))	// sliced
	//		error('w',"temporary used for non-const%tA",nn->tp);

	}
			}
		}
					e->e1 = a;
					break;
				case ANY:
					goto rlab;
				case PTR:
				{
					save_base = e->e1->base;
					if(a->tp->base==OVERLOAD)
						save_name = Pgen(a->tp)->fct_list->f->string;
					Pexpr te_a = a;
					e->e1 = a = ptr_init(Pptr(t1),a,tbl);
					no_change = (te_a == a);
				//	if (x==a || x==a->e2) goto def;	// needs checking
					if (Pchecked == 0) goto def;
					break;
				}
				//	e->e1 = a = ptr_init(Pptr(t1),a,tbl);
				//	goto def;
				case CHAR:
				case SHORT:
				case INT:
				//	if (a->base==ICON && a->tp==long_type)
				//		error('w',"long constantA for%n,%kX",fn,t1->base);
				{	Ptype t = a->tp;
					while(t->base == TYPE)
						t = Pbase(t)->b_name->tp;

					switch (t->base) {
					case LONG:
					case FLOAT:
					case DOUBLE:
					case LDOUBLE:
						error('w',"A%d: %t passed as %t",argno,a->tp,t1);
					}
				}
					// no break
				case LONG:
					if (Pbase(t1)->b_unsigned
					&& a->base==UMINUS
					&& a->e2->base==ICON)
						error('w',"negativeA for%n, unsignedX",fn);
				default:
				def:
				{	Pexpr x = try_to_coerce(t1,a,"argument",tbl);
//error('d',"x %d t1 %t nn %t a1 %t",x,t1,nn->tp,a->tp);
					if (x) {
						if (Pchecked == 0 && no_change) { 
							Pexpr te_x = ptr_init(Pptr(t1), x, tbl);

							if ( te_x != x ) e->e1 = a = te_x; else e->e1=x;
						}
						else
							e->e1 = x;
					}
					else if (nn->tp->check(a->tp,ARG)) {
						error("badA %dT for%n:%t (%tX)",argno,fn,a->tp,nn->tp);
						return any_type;
					}
				}
				}

                                Pexpr tt = e->e1;
                                while ( tt->base == CAST )
                                        tt = tt->e1;
                                if ( tt->base == ILIST )
                                        e->e1 = tt;

                                if (e->e1->base == ILIST) {
                                        // memptr constant
                                        // f({1,2,f}) ==> memptr t; f((t={1,2,f},t))
					if(save_base == REF) {
						Pptr m = Pptr(a->tp);
						error(strict_opt?0:'w',
						"address of boundF (try using ``%s::*'' forPT and ``&%s::%s'' for address) (anachronism)",
						m->memof->string,
						m->memof->string,
						save_name
						);
					}
                                        Pname temp = make_tmp('A',mptr_type,tbl);
                                        e->e1 = mptr_assign(temp,e->e1);
                                        e->e1 = a = new expr(G_CM,e->e1,temp);
                                        a->tp = temp->tp;
                                }

			}
			else {
				if (k != ELLIPSIS) {
					error("unexpected %dA for%n",argno,fn);
					return any_type;
				}
				Pexpr te=e;
				while(e) {
                                	if (e->e1->base == ILIST) {
                                        	// memptr constant
                                        	// f({1,2,f}) ==> memptr t; f((t={1,2,f},t))
                                        	Pname temp = make_tmp('A',mptr_type,tbl);
                                        	e->e1 = mptr_assign(temp,e->e1);
                                        	e->e1 = a = new expr(G_CM,e->e1,temp);
                                        	a->tp = temp->tp;
                                	}
					e = e->e2;
				}
				e = te;
				goto rlab;
			}
		}
		else {	/* default argument? */
			a = nn->n_initializer;
			if (a == 0) {
				error("A %d ofT%tX for%n",argno,nn->tp,fn);
				return any_type;
			}
                                if (a->base == ILIST) {
                                        // memptr constant
                                        // f({1,2,f}) ==> memptr t; f((t={1,2,f},t))
                                        Pname temp = make_tmp('A',mptr_type,tbl);
                                        a = mptr_assign(temp,a);
                                        a = new expr(G_CM,a,temp);
                                        a->tp = temp->tp;
                                }
			a->permanent = 2;	// ought not be necessary, but it is
			e = new expr(ELIST,a,0);
			if (etail)
				etail->e2 = e;
			else
				e2 = e;
			etail = e;
		}
	}

rlab:
//error('d',"rlab fct_name %n %t",fct_name,fct_name?fct_name->tp:0);
	for (; e; e = e->e2) {	// unchecked arguments
		Pexpr a = e->e1;
		Pname cn;

		if (a->base==NAME && a->tp->base==FCT) {
			// function name that escaped the type system:
			// update use count
			a->lval(ADDROF);
		}
		else if (warning_opt && (cn = a->tp->is_cl_obj())) {
			Pclass cl = Pclass(cn->tp);
			if (cl->has_ctor() || cl->memtbl->look("__as",0))//cl->has_oper(ASSIGN)
			{
				if (fct_name)
				error('w',"O ofC%t withK or = copied asA to%n (%t)",cl,fct_name,fct_name->tp);
				else
				error('w',"O ofC%t withK or = copied asA to `...'",cl);
			}
		}
		else if (a->tp->is_ref())
			e->e1 = a->contents();
	}

	if (f->f_result) {		// f(args) => (f(&temp,args),temp)
		Pname tn = make_tmp('R',f->returns,tbl);
		e2 = new expr(ELIST,tn->address(),e2);
// error('d',"result %n refd: %d",fn, refd);
		Pexpr ee = new expr(0,0,0);
		*ee = *this;
		base = G_CM;		// (f(&temp,args),temp)
		e1 = ee;
		if (refd == 2)
			e2 = tn->address();
		else e2 = tn;
		tp = tn->tp;
	}

	return t;
}

int cm_const_save; 

Pexpr ref_init(Pptr p, Pexpr init, Ptable tbl)
/*
	initialize the "p" with the "init"
	remember to call ptr_init to ensure that pointers to second bases
	are handled correctly.
*/
{
	register Ptype it = init->tp;
	Pptr px = p;
	while (px->base == TYPE) px = Pptr(Pbase(px)->b_name->tp);
	Ptype p1 = px->typ;
	Pname c1 = p1->is_cl_obj();
// error('d',"ref_init: p %t, p1 %t, px %t, init->tp %t",p,p1,px,it);
// error('d', "ref_init: nof: %n f_const: %d", cc?cc->nof:0, cc?(cc->nof?Pfct(cc->nof->tp)->f_const:0):0);

	if (init->base == ILIST) error("IrL as RIr");

	if (init->base==NAME
	&& Pname(init)->n_scope==ARG
	&& init->tp->base==FLOAT)
		error('w',"initializing a float& with floatA is non-portable");

	while(it->base == TYPE)
		it = Pbase(it)->b_name->tp; 

	switch (it->base) {
	default:
		{	Ptype tt = it->addrof();
			px->base = PTR;	// allow &x for y& when y : public x
					// but not &char for int&
			int x = px->check(tt,COERCE);

			if (x == 0) {	//CCC type is fine check for constness:
				if (init->tp->tconst()
				&& vec_const==0
				&& fct_const==0) {
					// not ``it''
					if (init->base == ELIST) init = init->e1;
					if (px->typ->tconst() == 0) error("R to constO");
					px->base = RPTR;
					// if we have a const lvalue we can still pass its address
					ignore_const++;
					if (init->lval(0)) {
						init->lval(ADDROF); // force output
						ignore_const--;
//error('d',"in1 %t",init->tp);
						return ptr_init(px,init->address(),tbl);//return init->address();
					}
					ignore_const--;
					goto xxx;
				}
				px->base = RPTR;
                                if (init->lval(0)) {	// can pass the address							// no temporary needed 
					init->lval(ADDROF); // force output
//error('d',"px %t init %t init %t",px,init->tp,init->tp);
					return ptr_init(px,init->address(),tbl);
				}
				goto xxx;
			}

			px->base = RPTR;
		}
	}

//error('d',"c1 %n",c1);
	if (c1) {	// assigning to a const X & is fine
		ref_cast++;
		Pexpr x = try_to_coerce(p,init,"reference initialization",tbl);
		ref_cast--;
		if (x) {
			init = x;
			goto xxx;
		}
		while (p1->base==TYPE) p1 = Pbase(p1)->b_name->tp;
		int bc = Pbase(p1)->b_const;
		Pbase(p1)->b_const = 0;
//		refd = 1;	
		switch ( init->base ) {
			case STRING: case ZERO: case CCON:
			case ICON: case FCON: case IVAL:
			case NAME:
				refd = 1; 
				break;
			default:
				refd = (init->e1 && init->e1->base == NAME && 
					init->e1->tp->base != RPTR &&
					Pname(init->e1)->n_xref == 0) ? 2: 1;
				break;
		}
// error('d', "***** refd: %d", refd );
		Pexpr a = class_init(0,p1,init,tbl);
		Pbase(p1)->b_const = bc;
		refd = 0;
		if (a==init && init->tp!=any_type) goto xxx;
// error('d',"ri a %d %k",a->base,a->base);
		switch (a->base) {
		case G_CALL:
	//	case CM:
	//	case G_CM:
			init = a;
			goto xxx;
		}
		a = a->address();
		a =  ptr_init(px,a,tbl);
		return a;
//		return ptr_init(px,a->address(),tbl);//a->address();
	}

//error('d',"p1 %t it %t",p1,it);
	if (p1->check(it,0)) {

		if (p1->check(it,ASSIGN) == 0) {
		//	if (p1->is_ptr())  // check for base* = derived*
		//		goto xxx;

			// things like ``double& rr = 1;'' temporary needed
			// warn in case of ``slightly wrong lvalue'', e.g.
			//	int i; double& r = i;
			if (init->lval(0) && p1->tconst()==0)
				error('w',"temporary used toIR; no changes will be propagated to actualA");
			goto def;
		}

		Pexpr x = try_to_coerce(p1,init,"reference",tbl);	// x==init
		if (x==0) x = try_to_coerce(px,init,"reference",tbl);	// x&=init
		if (x) {
			init = x;
			goto def;
		}

		error("badIrT:%t (%tX)",it,p);
		if (init->base != NAME) init->tp = any_type;
		return init;
	}
	
xxx:	/*
		here comes the test of a ``fundamental theorem'':
		a structure valued expression is
			(1) an lvalue of type T (possibly const)
		or	(2) the result of a function (a _result if X(X&) is defined)
		or	(3) a * or [] or ? or , expression
	*/
//error('d',"xxx %k %d %t",init->base,init->base,init->tp);

	switch (init->base) {
	case NAME:
	case DEREF:
	case REF:
	case DOT:			// init => &init
		if (it->tconst() && vec_const==0 && fct_const==0) goto def;
		if ( cc && cc->nof && 
			Pfct(cc->nof->tp)->f_const ) 
				cm_const_save = Pbase(p->typ)->b_const;
		init->lval(ADDROF);
		cm_const_save = 0;

		if (vec_const) return init;
		if (fct_const && p1->is_ptr()) goto def;	// fptr& = fct
		// no break
	case CM:
	case G_CM:			// & (f(&temp), temp)
		return ptr_init(px,init->address(),tbl);//init->address();
	default:
	def:
	{
// error('d',"def: init->tp %t p1 %t ",init->tp,p1);	
// error('d',"p1: %t const_ptr: %d", p1, const_ptr);
		if (const_ptr == 0) {
			if (tbl == gtbl || strict_opt) 
				error("Ir for%snon-constR not an lvalue", strict_opt?"":" global ");
			else
			if (warning_opt) 
				error('w', "Ir for non-constR not an lvalue (anachronism)");
		}

                Pname tcl = p1->is_cl_obj ();
                if(tcl && Pclass(tcl->tp)->c_abstract)
                       error("a temporary is needed for a parameter, but the argument type is abstract class %t.", tcl->tp);

		Pname n = make_tmp('I',p1,tbl);
		Pexpr a;
		Pname ic = init->tp->is_cl_obj();

		if (p1->tconst()==0
		&& (init->tp->tconst() && vec_const==0 && fct_const==0)
		&& p1->check(it,ASSIGN)==0)
			error('w',"constIr: temporary used toI reference");

		switch (p1->base) {
		case INT:
		case CHAR:
		case SHORT:
			switch (it->base) {
			case LONG:
			case FLOAT:
			case DOUBLE:
			case LDOUBLE:
				error('w',"%t assigned to %t inRIr",it,p1);
			}
		}

		if (ic!=c1 && Pclass(ic->tp) != Pclass(c1->tp)) {
			// derived class1 => must cast: ``it Ix; (Ix=init,(p)&Ix);''
			n->tp = init->tp;
			a = ptr_init(px,n->address(),tbl);//n->address();
			PERM(p);
			a = new texpr(CAST,p,a);
			a->tp = p;
		}
		else
			a = n->address();

		refd = 1;
		Pexpr as = init_tmp(n,init,tbl);
		refd = 0;
		a = new expr(G_CM,as,a);
		a->tp = a->e2->tp;
		return a;
	}
	}
}

Pexpr class_init(Pexpr nn, Ptype tt, Pexpr init, Ptable tbl)
/*
	initialize "nn" of type "tt" with "init"
	if nn==0 make a temporary,
	nn may not be a name
*/
{	
	if (init == dummy) return 0;
//error('d',"class_init %t with %t init %k refd %d",tt,init->tp,init->base,refd);
	Pname c1 = tt->is_cl_obj();

        if (init == 0) {
                error("emptyIr");
                return dummy;
        }

	if (c1) {
		Pclass cl = Pclass(c1->tp);
		Pname c2 = init->tp->is_cl_obj();

		if (c1!=c2 || (refd==0 && cl->has_itor())) {
			/*	really ought to make a temp if refd,
				but ref_init can do that
			*/
			int i = can_coerce(tt,init->tp);
//error('d',"i %d nn %n",i,nn);
			switch (i) {
			default:
				error("%d ways of making a%n from a%t",i,c1,init->tp);
				init->tp = any_type;
				return init;
			case 0:
				if (c2 && Pclass(c2->tp)->has_base(cl)) {
					init = init->address();
					Pexpr x = cast_cptr(cl,init,tbl,0);

					if (x == init) {
						Ptype pt = tt->addrof();
						PERM(pt);
						x = new cast(pt,init);
					}

					return x->contents();
				}
				error("cannot make a%n from a%t",c1,init->tp);
				init->tp = any_type;
				return init;
			case 1:
//error('d',"ncoerce %n %k %d",Ncoerce,init->base,init->base);
				if (Ncoerce == 0) {
					Pexpr a = new expr(ELIST,init,0);
					a = new texpr(VALUE,tt,a);
					a->e2 = nn;
				//	return a->typ(tbl);
					a = a->typ(tbl);
//error('d',"ci a %k %d %t",a->base,a->base,a->tp);
					return a;
				}

				switch (init->base) {
				case CM:
				case G_CM:	//ddd
				case NAME:	/* init.coerce() */
	/* *ref */		case DEREF:
				{	Pref r = new ref(DOT,init,Ncoerce);
					Pexpr rr = r->typ(tbl);
					init = new expr(G_CALL,rr,0);
					init->fct_name = Ncoerce;
					break;
				}
				default:	// (temp=init,temp.coerce())
				{	Pname tmp = make_tmp('U',init->tp,tbl); 
					int x = refd;	
					refd = 0;	// ??
					Pexpr ass = init_tmp(tmp,init,tbl);
					refd = x;
					Pref r = new ref(DOT,tmp,Ncoerce);
					Pexpr rr = r->typ(tbl);
					Pexpr c = new expr(G_CALL,rr,0);
					c->fct_name = Ncoerce;
					c = c->typ(tbl);
					init = new expr(CM,ass,c);
					init->tp = c->tp;
					if (refd) {	// &f() => (t=f(), &t)
						Pname tmp2 = make_tmp('L',c->tp,tbl); 
						ass = init_tmp(tmp2,init,tbl);
						init = new expr(G_CM,ass,tmp2);
					}
				}
				}
//error('d',"nn %n",nn);
				if (nn) {
					Pexpr a = new expr(ELIST,init,0);
					a = new texpr(VALUE,tt,a);
					a->e2 = nn;
					return a->typ(tbl);
				}
			}
//error('d',"c1 %n c2 %n",c1,c2);
			return init->typ(tbl);
		}
		return init;
	}
//error('d',"ci check tt %t init->tp %t",tt,init->tp);
	if (tt->check(init->tp,ASSIGN) && refd==0) {
		error("badIrT:%t (%tX)",init->tp,tt);
		init->tp = any_type;
	}

	return init;
}

extern int bound;	// fudge for bound pointers to functions

Pexpr expr::docast(Ptable tbl)
{	
	// check cast against value, INCOMPLETE

//error('d',"docast %d %t %k",this,tp2,e1->base);
	if (e1 == dummy) {
		error("E missing for cast");
		tp = any_type;
		return this;
	}

	int pmf = 0;
	int ptom_cast = 0;
	Pexpr ee = e1;

//error('d',"ee %k %d",ee->base,ee->base);
	switch (ee->base) {
	case ADDROF:
		ee = ee->e2;
		switch (ee->base) {
		case NAME:	goto nm;
		case REF:	goto rf;
		}
		break;

	case NAME:
	nm:
		if (Pname(ee)->n_qualifier) pmf = 1;
		break;
		
	case REF:
	rf:
		if (ee->e1->base == THIS) bound = 1;
		break;
	}

	e1 = e1->typ(tbl);

	int b = bound;	// distinguish between explicit and implicit THIS
	bound = 0;
	pmf = pmf && e1->base==CAST;

	Ptype etp = e1->tp;
	Ptype tt = tp2;
	Ptype t = tt;
	tt->dcl(tbl);

	while (etp->base == TYPE) etp = Pbase(etp)->b_name->tp;
	while (tt->base == TYPE) tt = Pbase(tt)->b_name->tp;
	
//error('d',"e1 %k etp %t tt %t",e1->base,etp,tt);

	switch (etp->base) {
	case PTR:
	case RPTR:
		if (Pptr(etp)->typ->base == OVERLOAD) goto over;

		if (warning_opt && i2==0 && Pptr(etp)->typ->tconst()) {
			switch (tt->base) {
			case FCT:
				break;
			case PTR:
			case RPTR:
				if (Pptr(tt)->typ->tconst()) break;
			default:
				// casting away const
				// should be an error
				// but ANSI says OK so I chicken out
				// to be able to compile strtok(), etc.
				error('w',"const cast away:%t->%t",e1->tp,tp2);
			}
		}
		else
			i2 = 0; // to allow cfront to escape its own checking
		break;
	case COBJ:
	{	ref_cast = 1;
		Pexpr x = try_to_coerce(tt,e1,"cast",tbl);
		ref_cast = 0;
//error('d',"x %k %t tt %d %t",x?x->base:0,x?x->tp:0,tt,tt);
		if (x) {
			if (x!=e1 && x->base==DEREF && tt->is_ref()) x = x->e1;
			if (tt==x->tp || tt->check(x->tp,0)==0 || const_problem)
				return x;
			else
				return new cast(tt,x);
		}
	//	else if (e1->base==DEREF && tt->is_ref()) return e1;
		break;
	}
	case VOID:
		if (tt->base == VOID) {
			tp = t;
			return this;
		}
		error("cast of void value");
		// no break;
	case ANY:
	any:
		tp = any_type;
		return this;
	case FCT:
		if (tt->base == PTR && Pptr(tt)->typ->base != FCT)
			error('w',"P toF cast toP to nonF");
		break;
	case OVERLOAD:
	over:
		error("cast of overloaded");
		goto any;
	}

//error('d',"tt %t",tt);
	switch (tt->base) {
	case PTR:
		if (Pptr(tt)->typ->base==FCT && Pptr(tt)->memof) {
			if (etp->base!=PTR
			|| Pptr(etp)->typ->base!=FCT
			|| Pptr(etp)->memof==0)
				error("cast toP toM %t",tt);
			else {	// adjust delta in MI case
				// for the moment just suppress the cast
				// all pmfs are the same to cc
/*
				Pclass c1 = Pptr(tt)->memof;
				Pclass c2 = Pptr(etp)->memof;
*/
				ptom_cast = 1;
				tp2 = void_type;
			}
		}

		switch (etp->base) {
		case COBJ:
			error("cannot castCO toP");
			break;
		case FCT:
			e1 = new expr(G_ADDROF,0,e1);
			bound = b;
			e1 = e1->typ(tbl);
			bound = 0;
			if (e1->base == CAST)
				pmf = 1;
			else
				break;
			// no break;

		case PTR:
		{	Pname cn = Pptr(tt)->typ->is_cl_obj();
			if (cn) {
				Pexpr x = cast_cptr(Pclass(cn->tp),e1,tbl,1);

				if (x == e1) {
					PERM(tt);
					e1 = new cast(tt,e1);
					e1->i2 = i2;
				}
				else
					e1 = x;
			}
			if (pmf) {
				while(tt->base == TYPE)
					tt = Pbase(tt)->b_name->tp;

				switch (tt->base) {
				case PTR:
					if (Pptr(tt)->memof) break;
				default:
					error("%t cast to%t (%t is not aP toM)",e1->tp,tp2,tp2);
				}
			}
		}
		}
		break;

	case RPTR:		// (x&)e: pretend e is an x
	{	Ptype er = etp;
		Ptype cr = tt;
		do {
			if (er = er->is_ptr_or_ref()) er = Pptr(er)->typ;
			if (cr = cr->is_ptr_or_ref()) cr = Pptr(cr)->typ;
		} while (er && cr);
		int pp = er!=0;	//	if `e' is a suitable pointer cast it:
				// 	(x&)e => (x*)e, otherwise
				//	(x&)e => *(x*)&e
// error('d',"rptr tt %t e1->base %k e1->tp %t",tt,e1->base,e1->tp);
	//	if (Pptr(tt)->typ->tsizeof()>etp->tsizeof()) goto zse;
	// we need to be able to ``raise the type'' from base to derived
	//	if (etp->is_cl_obj() && Pptr(tt)->typ->is_cl_obj()==0) goto zse;

		if (e1->base==G_CM
		|| e1->base==CALL
		|| e1->base==G_CALL
		|| e1->lval(0))
			;
		else if (e1->tp->tconst()) {
				// casting away const
				// should be an error
				// but ANSI says OK so I chicken out
				// to be able to compile strtok(), etc.
			if (warning_opt && Pptr(tt)->typ->tconst()==0)
				error('w',"const cast away:%t->%t",e1->tp,tp2);

		}
		else
			error("cannot cast%t to%t",etp,t);
//error('d',"e1 %k %t %d",e1->base,e1->tp,pp);
		if (pp == 0) e1 = e1->address();	// *(x*)&e
		tp = t;

		// do proper pointer manipulation for multiple inheritance
		Pname cn = Pptr(tt)->typ->is_cl_obj();
		if (cn) {
			Pexpr x = cast_cptr(Pclass(cn->tp),e1,tbl,1);

			if (x == e1) {
				PERM(tt);
				e1 = new cast(tt,e1);
				e1->i2 = i2;
			}
			else
				e1 = x;
		}

		return pp ? this : contents();
//	zse:
//		error("cannot cast%t to%t",etp,t);
//		tp2 = tt = any_type;
//		break;
	}
	case COBJ:
		base = VALUE;	// (x)e => x(e): construct an x from e
		e1 = new expr(ELIST,e1,0);
		return typ(tbl);

	case CHAR:
	case INT:
	case SHORT:
	case LONG:
		switch (etp->base) {
		case FCT:
			e1 = new expr(ADDROF,0,e1);
			e1 = e1->typ(tbl);
			//etp = e1->tp;
		case PTR:
			if(!e1->tp->memptr() && e1->tp->tsizeof()>tt->tsizeof())
				error("type ``%t'' not large enough for values of ``%t ''",tt,etp);
			break;
		case COBJ:
			error("cannot castCO to%k",tt->base);
			break;
		}	
		break;

	case FLOAT:
	case DOUBLE:
	case LDOUBLE:
		switch (etp->base) {
		case FLOAT:
		case DOUBLE:
		case LDOUBLE:
		case CHAR:
		case INT:
		case SHORT:
		case LONG:
		case EOBJ:
		case ZTYPE:
			break;
		default:
			error("cannot cast ``%t '' to ``%t''",etp,tt);
			break;
		}	
		break;

	case FCT:
		error("cannot cast toFT");
		break;
	}

	tp = t;

	if (e1->base==ILIST && ptom_cast==0) { // pointer to member constant
		Pexpr ee = e1->e1;	// ELIST
		int i;
		switch (ee->e2->base) {
		case IVAL:
			i = int(ee->e2->i1);
			break;
		case ZERO:
			i = 0;
		}

		if (i<0)
			e1 = e1->e2;	// just the function
		else
			e1 = ee->e2;	// just the index
		return this;
	}

	if (etp->base==PTR && Pptr(etp)->memof && Pptr(etp)->typ->base==FCT) {
		Pclass cl = Pptr(etp)->memof;

		if (Pptr(tt)->memof==0 && b == 0 ) {
			Pexpr y = new mdot("f",e1);
			y->i1 = 9;
			y = new cast(tt,y);
			if (cl->virt_count && b==0) {
				// ERROR: no check for side effects
				Pexpr z = new mdot("i",e1);
				Pexpr x = new mdot("i",e1);
				x->i1 = 9;
				x = new cast(tt,x);
				z->i1 = 9;
				Pexpr q = new expr (QUEST,x,y);
				q->cond = new expr(LE,zero,z);
				q->tp = tt;
				delete this;
				return q;
			}
			delete this;
			return y;
		}
	}

	return this;
}

Pexpr expr::dovalue(Ptable tbl)
{
	Ptype tt = tp2;
	Pclass cl;
	Pname cn;

//error('d',"value %d %t e1 %d e2 %d",tt,tt,e1,e2);
	
	tt->dcl(tbl);

	while(tt->base == TYPE)
		tt = Pbase(tt)->b_name->tp;

	switch (tt->base) {
	case EOBJ:
	default:
		if (e1 == 0) {
			error("value missing in conversion to%t",tt);
			return dummy;
		}
		base = CAST;
		e1 = e1->e1;	// strip ELIST
		return typ(tbl);

	case CLASS:
		cl = Pclass(tt);
		tp2 = Pptr(cl->this_type)->typ;
		break;

	case COBJ:
		cn = Pbase(tt)->b_name;
		cl = Pclass(cn->tp);
	}

//error('d',"e1 %k e1->e2 %k",e1->base,e1?e1->e2->base:0);
	if (e1 && e1->e2==0) {		// single argument
		if (e1->e1->base==ELIST) e1->e1 = e1->e1->e1;	// spurious elist
		e1->e1 = e1->e1->typ(tbl);
		if (tt->base==COBJ) {
			Pexpr x = try_to_coerce(tt,e1->e1,"type conversion",tbl);
			if (x) return x;
		}

		Pname acn = e1->e1->tp->is_cl_obj();
//error('d',"acn %n %d",acn,cl->has_itor());
		if (acn && cl->has_itor()==0) {
			Pclass acl = Pclass(acn->tp);
			int hb = acl->has_base(cl);

			if (acl==cl || hb) {
				vcllist->clear();
				vcllist=0;
				if (1<is_unique_base(acl,cl->string,0)) error("ambiguous assignment to base %t",cl);
				Pexpr ee = e1->e1;
				if (ee->base == ELIST) ee = ee->e1;	// ???
				if (hb) {	// ee => *(tp2*)&ee
						// remember = may be overloaded
//error('d',"hb %k %t %d",ee->base,ee->tp,ee->lval(0));
					ignore_const++;
					if (ee->lval(0)==0) {
						Pname tmp = make_tmp('T',ee->tp,tbl);
						ee = init_tmp(tmp,ee,tbl);
						ee = new expr(G_CM,ee,tmp->address());
					}
					else
						ee = ee->address();
					ignore_const--;
					ee = new texpr(CAST,new ptr(PTR,tp2),ee); //new cast(new ptr(PTR,tp2),ee);
					ee = ee->contents();
					ee->typ(tbl);
				}

				if (e2) {	// x(x_obj) => e2=x_obj
					base = ASSIGN;
					e1 = e2;
					e2 = ee;
					tp = tp2;
					return this;
				}
				return ee;	// strip ELIST: x(x_obj) => x_obj
			}
		}
	}


	/* x(a) => obj.ctor(a); where e1==obj */
	Pname ctor = cl->has_ctor();
	if (ctor == 0) {
		error("cannot make a%t",cl);
		return dummy;
	}

// error('d',"e2 %k",e2?e2->base:0);
// error('d',"refd: %d const_ptr: %d", refd, const_ptr);
	if (e2 == 0) {		// x(a) => x temp; (temp.x(a),temp)
/* incomplete condition
		if ( refd && const_ptr == 0) {
    			if ( tbl == gtbl ) {
				error("Ir forG non-constCR not an lvalue");
    			}
    			else	
    			if (strict_opt) 
				error("Ir for non-constCR not an lvalue");
    			else
    			if (warning_opt) 
				error('w', "Ir for non-constR not an lvalue (anachronism)");
			}
*/
	
		no_sti = 1;
		Pname n = make_tmp('V',tp2,tbl);
		no_sti = 0;
		n->assign();
		if (tbl == gtbl) n->dcl_print(0);	// a hack
		Pexpr c = call_ctor(tbl,n,ctor,e1,DOT);
		c = new expr(G_CM,c,n);
		c->tp = n->tp;
//error('d',"tp1 %t",c->tp);
		return c;
	}
	else {
		Pexpr c = call_ctor(tbl,e2,ctor,e1,DOT);
		c = new expr(DEREF,c,0); // deref value returned by constructor
		c->tp = c->e1->tp;
//error('d',"tp2 %t",c->tp);
		return c;
	}
}

0707071010112044311004440001630000160000010201300466055402500000700000074341find.c/*ident	"@(#)ctrans:src/find.c	1.5" */
/******************************************************************

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

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

find.c:

	name lookup and visibility checks

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

#include "cfront.h"

Pname undef(Pname n, Ptable tbl, TOK f)
{
	switch (f) {
	case CCON:
		error("illegalF call: explicit call ofK %s()",n->string);
		break;
	case 0:		error("%nU",n);			break;
	case CALL:	error("UF%n called",n);		break;
	case REF:
	case DOT:	error("M%nU",n);		break;
	case ADDROF:	error("address ofU%n",n);	break;
	}

	if (tbl == gtbl) {
		Pname nn = tbl->insert(n,0);
		if (f == CALL) {
			nn->tp = new fct(defa_type,0,0);
			nn->n_sto = nn->n_scope = EXTERN;
		}
		else
			nn->tp = any_type;
		delete n;
		return nn;
	}
	
	n->n_table = tbl;
	n->tp = any_type;
	return n;
}



static int mptr;	// &C::m
static Pname me;	// name of fct requesting access to name using find_name()
static Pfct mef;	// fct requesting access to name using find_name()
Pclass tcl;		// class of original ``this''
Pclass mec;	 	// class requesting access to name using find_name()
int mex;

Ptable lcl_tbl = 0;	// handle local function reference of local const for dimen size


Pexpr find_name(Pname n, Pclass cl, Ptable tbl, int f, Pname m)
/*
	in function ``m'' find the true name for "n",
	implicitly define if undefined

	f==CALL:	n()		cl == cc->cot
	f==REF:		p->n		cl == class of *p
	f==DOT:		obj.n		cl == class of obj
	f==ADDROF:	&n		cl == cc->cot
	f==0		n   		(none of the above)

	"tbl" defines local scope (block or global)

*/
{
	if ( n == 0 ) error('i',"find_name(n==0,cl==%t,tbl==%d,f==%k,m==%n)",cl,tbl,f,m);
	Pname q = n->n_qualifier;
	char* s = n->string;
	Pexpr ee;
	DB( if(Ddebug>=3) {
		error('d',"find_name %s::%s cl %t",q?q->string:"",s,cl);
		error('d',"	f %d m %n",f,m);
		if(q&&q->tp&&q->tp->base==COBJ)
			fprintf(stderr," -- cb==%d\n",Pclass(q->tp)->c_body);
	});

	tcl = cl;

	//if (n) {
		mex = 1;
		if (me = m) {
			mef = Pfct(me->tp);
                        if (mef->base!=FCT) 
                                error('i',"mef %d %k",mef,mef->base);
			mec = mef->memof;
		}
		else {
			mef = 0;
			mec = cl;
		}
	//}
	//else
	//	mex = 0;

	if (n->base == MDOT) error('i',"find (mdot %n)",n);

	if (n->n_table) { me = 0; return n; }

//error('d',"q %n %t f %k",q,q?q->tp:0,f);
	if (q) {			// qualified name:	q::s

		if (q == sta_name) {	// explicitly global:	::s
			Pname nn = gtbl->look(s,0);
			if (nn == 0) { me = 0; return undef(n,gtbl,f); }
			nn->use();
			delete n;
			me = 0;
			return nn;
		}

		{
		  Pname aq = q; // actual q
		  while ( aq->tp->base == TYPE ) aq = Pbase(aq->tp)->b_name;
		  if (aq->tp->base != COBJ) {
		    error("Qr%nnot aCN",q);
		    me = 0;
		    return undef(n,gtbl,f);
		  }
		  q = aq;
		}
		Pclass qcl = Pclass(Pbase(q->tp)->b_name->tp);

		Pclass bcl = cl;

		if (cl==0 || f==ADDROF)
			bcl = cl = qcl; // Pclass(Pbase(q->tp)->b_name->tp);
		else {
		//	if (strcmp(q->string,cl->string)) {	// really a base?
		//		bcl = cl->is_base(q->string);
			if (strcmp(qcl->string,cl->string)) {	// really a base?
				bcl = cl->is_base(qcl->string);
				if (bcl == 0) {
					if (f==REF || f==DOT) {
						error("%s is not aBC of %t",q->string,cl);
						me = 0;
						return undef(n,cl->memtbl,7);
					}
					goto sss;
				}
				// else try in base or for static
			}
		}

		if (f == ADDROF) mptr = 1;		// &C::m
		ee = cl->find_name(s,bcl==cl?0:bcl);	// really a member?
		mptr = 0;

		if (ee == 0) {
		sss:
//error('d',"sss %k",f);
			if (f!=REF && f!=DOT) {
				// try for static member of other class:
				Pclass qcl = Pclass(Pbase(q->tp)->b_name->tp);
				mptr = 1;
				if ( cl && cl->csu == ANON ) {
					mec = (cc-1)->cot;
					ee = qcl->find_name(s,qcl);
				} else
					ee = qcl->find_name(s,qcl);
				mptr = 0;
				if (ee && ee->base==NAME) {
				//	switch (ee->tp->base) {
				//	case FCT:
				//	case OVERLOAD:
				//		break;
				//	default:
						delete n;
						me = 0;
						return ee;
				//	}
				}
			}
			error("QdN%n::%n not found in %t",q,n,cl);
			me = 0;
			return undef(n,bcl?bcl->memtbl:cl->memtbl,7);
		}

		if (ee->base==REF && ee->e1==0) {	// &C::f, no ``this''
//error('d',"ee %k %d f %k",ee->base,ee->e1,f);
			switch (f) {
			case 0:
			case CALL:	//SSS
				{	Pexpr mm = ee->mem;
					while (mm->base==REF || mm->base==MDOT) mm = mm->mem;
					if (mm->base==NAME)
						switch (mm->tp->base) {
						case FCT:
						case OVERLOAD:
							goto addrof;
						default:
							if (Pname(mm)->n_stclass == STATIC) goto addrof;
						}
				}
				error("O orOP missing forM%n",n);
					
			case ADDROF:
			addrof:
				Pexpr x = ee;
				ee = ee->mem;
				delete x;
			case REF:
			case DOT:
				break;
			default:
				error("QdN%n::%n used in nonC context",q,n);
			}
		}

		delete n;
		me = 0;
		return ee;
	}

	if (f!=DOT && f!=REF) {	// not .s or ->s: look for local, global, and member

		Pname nn = tbl->look(s,0);
		if (nn) {	// local, global, or member
			if (nn->n_table->t_name) {	// global or member
				if (cl) {		// might be member
					if ((ee = cl->find_name(s,0))==0 &&
						cl->in_class) 
					{ // nested class
						Pclass nstd_cl = cl->in_class;
						for (; nstd_cl; nstd_cl=nstd_cl->in_class) 
						{
// error( 'd', "find_name( %s ): nested class %t",s,nstd_cl ); 
							if (ee=nstd_cl->find_name(s,0)) 
							{
								if ( cl->nested_sig == 0 ) {
									error('w',"%s, accessed within nestedC%t, is visible bothGly and within enclosingC%t -- using %n (anachronism)", s, cl, nstd_cl, nn );
									ee = 0;
								}
								break;
							}
						}	
					} // nested class
				
					if ( ee ) 
					{  // class member name
						if (ee->base==REF && ee->e1==0 )
						{
							Pexpr mm = ee->mem;
							while (mm->base==REF || mm->base==MDOT) mm = mm->mem;
							if (mm->base==NAME)
								switch (mm->tp->base) {
								default:
									if (Pname(mm)->n_stclass != STATIC)
										break;
								case FCT:
								case OVERLOAD:
									delete n;
									me = 0;
									return mm;
								}
							error("O orOP missing for%n",Pref(ee)->mem);
						}
						delete n;
						me = 0;
						return ee;
					  }  // if ee
				}  // if cl
			} // else local, global, or member

			nn->use();
			delete n;
			me = 0;
			return nn;
		}

		if (cl) {
			if ( cl->csu == ANON ) {
				mec = (cc-1)->cot;
				ee = (cc-1)->cot->find_name(s,0);
			} else
				ee = cl->find_name(s,0);
			if (ee) {
			if (ee->base==REF && ee->e1==0) {
				Pexpr mm = ee->mem;
				while (mm->base==REF || mm->base==MDOT) mm = mm->mem;
				if (mm->base==NAME)
					switch (mm->tp->base) {
					default:
						if (Pname(mm)->n_stclass != STATIC)
							break;
					case FCT:
					case OVERLOAD:
						delete n;
						me = 0;
						return mm;
					
					}
				error("O orOP missing for%n",Pref(ee)->mem);
			}
				delete n;
				me = 0;
				return ee;
			}
		}

		if ( lcl_tbl && (nn=lcl_tbl->look(s,0)) ) {
			nn->use();
			delete n;
			me = 0;
			return nn;
		}

		if (nn = gtbl->look(s,0)) {	// global
			nn->use();
			delete n;
			me = 0;
			return nn;
		}

		me = 0;
		return undef(n,gtbl,f);
	}

	if (ee = cl->find_name(s,cl)) {	// .s or ->s
		delete n;
		me = 0;
		return ee;
	}

	if(!strcmp(s,cl->string)) {
		me = 0;
		return undef(n,gtbl,CCON);
	}

	me = 0;
	return undef(n,gtbl,f);
}

int classdef::check_dup(Pclass cl, TOK bb)
/*
	 see if cl is a base of this; return 0 if no clash
*/
{
	for (Pbcl b = baselist; b; b=b->next) {
		if (cl == b->bclass) {
			if (bb!=VIRTUAL) {
				if (b->base==VIRTUAL)
					error('w',"%t inaccessible because of virtual%t in%t",cl,cl,this);
				else
					error('w',"%t inaccessible because of%t in%t",cl,cl,this);
				return 1;
			}
			else if (b->base!=VIRTUAL) {
				error('w',"virtual %t inaccessible because of%t in%t",cl,cl,this);
				return 1;
			}
		}
		if (b->bclass->check_dup(cl,bb)) return 1;
	}
	return 0;
}


int Nvis;
TOK Nvirt;
TOK ppbase;

Pclass classdef::is_base(char* s)
/*
	is "s" a public base class of this?
*/
{
//error('d',"%s->is_base(%s) %k",string,s,ppbase);
	TOK pp = ppbase;
	for (Pbcl b = baselist; b; b=b->next) {
/*
		if (b->ppp!=PUBLIC
		&& cc->cot!=this
		&& (cc->nof==0 || this->has_friend(Pfct(cc->nof->tp))==0))
			ppbase = b->ppp<pp?pp:b->ppp;	// PUBLIC<PROTECTED<PRIVATE
*/
		if (strcmp(s,b->bclass->string) == 0) {
		if (b->ppp!=PUBLIC
		&& cc->cot!=this
		&& (cc->nof==0 || this->has_friend(Pfct(cc->nof->tp))==0))
			ppbase = b->ppp<pp?pp:b->ppp;	// PUBLIC<PROTECTED<PRIVATE
			Nvirt = b->base;
			return b->bclass;
		}
		else {
			Pclass bc = b->bclass->is_base(s);
			if (bc) {
		if (b->ppp!=PUBLIC
		&& cc->cot!=this
		&& (cc->nof==0 || this->has_friend(Pfct(cc->nof->tp))==0))
			ppbase = b->ppp<pp?pp:b->ppp;	// PUBLIC<PROTECTED<PRIVATE
				return bc;
			}
		}
	}
	ppbase = pp;
	return 0;
}

bit classdef::has_base(Pclass cl)
/*
	is "cl" a base of this?
*/
{
// error('d', "%t->has_base( %t ) cc->cot: %t", this, cl, cc->cot?cc->cot:0 );

	if (this == 0) return 0;
	for (Pbcl b = baselist; b; b=b->next) {
// error('d', "b: %t ppp: %k", b->bclass, b->ppp );
		if (b->bclass==cl) {
			if (b->ppp!=PUBLIC
			&& cc->cot!=this
			&& (cc->nof==0 ||
				this->has_friend(Pfct(cc->nof->tp))==0) 
			&& this->has_friend(cc->cot)==0)
				Nvis = 1;	// no standard coercion
			Nvirt = b->base;
			return 1;
		}
		if (b->bclass->has_base(cl)) return 1;
	}
	return 0;
}

int Noffset;
Pexpr Nptr;
char *Nalloc_base;
clist* vcllist;

int clist::onlist(Pclass c)
{
	for (clist* p = this; p; p = p->next)
		if (p->cl == c) return 1;
	return 0;
}

void clist::clear()
{
	if (this == 0) return;
	clist* p = next;
	while (p) {
		clist* q = p->next;
		delete p;
		p = q;
	};
	delete this;
}

Pbcl Nvbc_alloc;
int is_unique_base(Pclass cl, char* s, int offset, int in_base )
/*
	is "s" a unique base class of this?
*/
{
	int i = 0;
	static Pclass priSeen = 0;
// error('d',"is_unique_base(cl: %t, s: %s,%d,%d)",cl,s,offset,in_base);
	for (Pbcl b = cl->baselist; b; b=b->next) {
		int no = 0;
		if (b->base!=VIRTUAL)
			no = offset + b->obj_offset;
		else if (in_base)
			continue;
		if (strcmp(s,b->bclass->string) == 0) {
			Noffset = no;
			i++;
			if ((b->ppp!=PUBLIC || priSeen )
				&& (cc->cot!=cl || cc->cot != priSeen )
				&& (cc->nof==0 || cl->has_friend(Pfct(cc->nof->tp))==0)
			      		|| (priSeen && priSeen->has_friend(Pfct(cc->nof->tp))==0))
						Nvis = 1;	// no standard coercion

			if (b->base==VIRTUAL) {
				Nptr = new mdot(s,0);
				if (b->allocated == 0) {
					Nvbc_alloc = 0;
					Nalloc_base = cl->has_allocated_base(s);
				}
			}
		}
		else {
			if (b->base==VIRTUAL) {
				if (vcllist->onlist(b->bclass) )continue;
				vcllist = new clist(b->bclass,vcllist);
			}

			Pclass clscope = 0;
			if ( cc && cc->c_this ) {
				Ptype t = Pptr(cc->c_this->tp)->typ;
				clscope = Pclass(Pbase(t)->b_name->tp);
			}
// error('d', "cl: %t %d clscope: %t %d", cl, cl, clscope, clscope);
			if (b->ppp != PUBLIC && 
				cl != clscope && priSeen == 0 ) priSeen = cl;

			int ii = is_unique_base(b->bclass,s,no,1);
			if (in_base == 0) priSeen = 0;
// error('d',"base %t i %d ii %d",b->bclass,i,ii);
// error('d',"base %t %k allocated: %d", b->bclass, b->base, b->allocated);
			i += ii;
			if (ii==1 && b->base==VIRTUAL) {
			 	Nptr = new mdot(b->bclass->string,0);
				if (b->allocated == 0) {
					Nvbc_alloc = 0;
					Nalloc_base = cl->has_allocated_base(b->bclass->string);
				}
			}
		}
	}

	return i;
}

/*
int classdef::has_allocated_base(Pclass bcl)

	search the list of !first base classes for this virtual base
	space will have been allocated in !first bases for virtual bases
	declared in !first classes

	in addition bcl may bave been specified explicitly as a base

{
	int off;
	for (Pbcl l = baselist; l; l=l->next) {
		if (l->base == VIRTUAL) continue; // another non-allocated virtual base
		if (l==baselist) continue;	// first base

		Pclass bc = l->bclass;
		off = l->obj_offset;

		for (Pbcl ll = bc->baselist; ll; ll=ll->next) {
			// cannot share non-virtual base
			if (ll->base != VIRTUAL) continue;
			if (ll->bclass==bcl) return off + ll->obj_offset;
		}
	}
	return 0;
}
*/

int classdef::has_allocated_base(Pclass bcl)
/*
	search the list of base classes for this virtual base
	space will be allocated in first virtual version found.
	return offset.

	A virtual base cannot have offset 0 (its pointer at least is ahead)
*/
{
//error('d',"%t->has_allocated_base(%t) ",this,bcl);
	for (Pbcl l = baselist; l; l=l->next) {
		if (l->base==VIRTUAL
		&& l->bclass==bcl
		&& l->obj_offset)
			return l->obj_offset;

		if (l->base==VIRTUAL || l!=baselist) {
			// allocated as an object,
			// not unravelled as a set of members
			int i = l->bclass->has_allocated_base(bcl);
			if (i) return l->obj_offset + i;
		}
	}
	return 0;
}

char *classdef::has_allocated_base(char *str) 
/*
 *	str is an unallocated virtual base class of this
 *	return the name of the second or subsequent base class 
 *		containing the member ``struct str *P<str>''
 */
{
// error('d',"%t::has_allocated_base(%s) baselist: %t",this,str,baselist->bclass);
	for (Pbcl l = baselist; l; l=l->next) {
		if (l->base == VIRTUAL) {
			if ( l->allocated ) Nvbc_alloc = l; 
			continue; 
		}

		Pclass bc = l->bclass;
		for (Pbcl ll = bc->baselist; ll; ll=ll->next) {
			if (ll->base != VIRTUAL) continue;
			if (ll->allocated && 
			    strcmp( str, ll->bclass->string) == 0 )
				{ 
					if (bc == baselist->bclass) {
						// NfirstBase=1; 
						return 0;
					}
					return bc->string;
				}
		}
	}
	return 0;
}

/*
int allocated_base(Pclass cl,Pclass bcl)
{
static second;
int s2 = second;
	for (Pbcl l = cl->baselist; l; l=l->next) {
		if (l->base==VIRTUAL
		&& l->bclass==bcl
		&& l->obj_offset
		&& (second || l!=cl->baselist)) return (second=s2,1);
		int i = allocated_base(l->bclass,bcl);
		if (i) return (second=s2,1);
		second = 1;
	}
	second = s2;
	return 0;
}
*/
Pname vfct(Pclass cl, char* s)
/*
	Called for each name "s" in a vtbl for "cl"
	Find the "s" to go in the vtbl.
	The "s" that caused the vtbl entry to be created
		is found if nothing else is
*/
{
	Pname n = cl->memtbl->look(s,0);
	if (n) return n;

	for (Pbcl b = cl->baselist; b; b=b->next) {
		Pname nn = vfct(b->bclass,s);
		if (nn) {
//error('d',"nn %nn",nn);
			if (n && n!=nn) {
				Pclass ncl = Pclass(n->n_table->t_name->tp);
				Pclass nncl = Pclass(nn->n_table->t_name->tp);
//error('d',"ncl %t nncl %t",ncl,nncl);
				if (nncl->is_base(ncl->string))
					n = nn;		// use nn
			}
			else
				n = nn;
		}
	}

	return n;
}

Pexpr rptr(Ptype t, Pexpr p, int offset)
/*
	return rvalue of offset off pointer:
	(t)((char*)p+offset)
*/
{
	if ( t == 0 ) error( 'i', "rptr(), t==0 (type passed for cast)" );
	Pexpr pp = p;
//error('d',"rptr %t %d",t,offset);
	if (offset) {
		Pexpr i = new ival(offset);
	//	pp = new texpr(CAST,Pchar_type,pp);
		pp = new cast(Pchar_type,pp);
		pp = new expr(PLUS,pp,i);
	}
	pp = new cast(t,pp);
	return pp;
}
/*
Pexpr lptr(Ptype t, Pexpr p, int offset)

	return lvalue of offset off pointer:
	*(t*)((char*)p+offset)

{
	Pexpr pp = p;
	if (offset) {
		Pexpr i = new ival(offset);
	//	pp = new texpr(CAST,Pchar_type,pp);
		pp = new cast(Pchar_type,pp);
		pp = new expr(PLUS,pp,i);
	}
	pp = new cast(t->addrof(),pp);
	pp = new expr(DEREF,pp,0);
	pp->tp = t;
	return pp;
}
*/
int friend_check(Pclass start,Pclass stop, Pfct f)
/*
	is `f' a friend of a class between `start' and `stop'
	in a class DAG?
*/
{
//error('d',"friend_check(%t,%t)",start,stop);
	
	if (start->has_friend(f)) return 1;
	if (stop == start) return 0;
	for (Pbcl b = start->baselist; b; b = b->next) {
		if (b->bclass->has_friend(f)) return 1;
		if (friend_check(b->bclass,stop,f)) return 1;
	}
	return 0;
}

bit classdef::has_friend(Pfct f)
/*
	does this class have function "f" as its friend?
*/
{
// error('d',"%t->has_friend(%t) %d %d ",this,f,f,f->base);

	for (Plist l=friend_list; l; l=l->l) {
		Pname fr = l->f;
		Ptype frt = fr->tp;
//error('d',"frt %t %d %d",frt,frt,frt->base);
		switch (frt->base) {
		case FCT:
			if (f == frt) return 1;
			break;
		case OVERLOAD:
			l->f = fr = Pgen(frt)->fct_list->f;	// first fct
			if (fr->tp == f) return 1;
		case CLASS:
			break;
		default:
			error('i',"bad friend %k",fr->tp->base);
		}
	}
	return 0;
}

bit classdef::has_friend(Pclass cl)
/*
	does this class have class "cl" as its friend?
*/
{
// error('d',"%t->has_friend(%t) ",this,cl);

	for (Plist l=friend_list; l; l=l->l) {
		Pname fr = l->f;
		Ptype frt = fr->tp;
		switch (frt->base) {
		case CLASS:
// error('d',"class friend: %t", frt);
			if ((frt == cl) || cl->same_class(Pclass(frt))) 
				return 1;
		case FCT:
		case OVERLOAD:
			break;
		default:
			{error('i',"bad friend %k",frt->base);}
		}
	}
	return 0;
}

Pname find_virtual(Pclass cl, Pname s)
/*
	does ``cl'' have a virtual function ``s'' in some base class
*/
{
	for (Pbcl b = cl->baselist; b; b = b->next) {
		Pclass bcl = b->bclass;
		Pname n;
		if (n = bcl->memtbl->look(s->string,0)) {
// error('d', "find_virtual: n: %d base: %k", n, n->base );
			if ( n->base == PUBLIC ) // x::foo;
				continue;
			Pfct f = Pfct(n->tp);
			if (f->base == OVERLOAD) {
				for (Plist gl=Pgen(f)->fct_list; gl; gl=gl->l) {
					n = gl->f;
					// if (f != s->tp) continue;
					// Replaced by:
					if (n->tp->check(s->tp,VIRTUAL)) continue;
					if (Pfct(n->tp)->f_virtual) return n;
				}
			}
			// else if (f->f_virtual)
			else if (f->f_virtual && n->tp->check(s->tp,VIRTUAL)==0)
				return n;
		}
		else if (n = find_virtual(bcl,s))
			return n;
	}
	return 0;
}

Pname dummy_fct;

static int 
is_accessible(Pname n, Pclass this_class, bit noCdcl = 0)
// 0 means n is not accessible to this_class
{
// error('d',"is_accessible(%n,%t)", n, this_class
// error('d',"%n: %k mef %t",n,n->n_protect,mef);
// error('d',"		this_class %d %t",this_class,this_class);
// error('d',"		mec  %d %t",mec,mec);
// error('d',"		tcl  %d %t",tcl,tcl);
// error('d',"mec->has_base(this_class) %d",mec?mec->has_base(this_class):0);
// error('d',"tcl->has_base(mec) %d",tcl?tcl->has_base(mec):0);
// error('d',"tcl->has_base(this_class) %d",tcl?tcl->has_base(this_class):0);
// error('d',"tcl->has_friend(mef) %d",tcl?tcl->has_friend(mef):0);

	if (this_class==mec || 
		(mec && this_class->has_friend(mec)) || 
		(mef && this_class->has_friend(mef)))
			return 1;
	
	if ( n->n_protect && tcl ) {
		if ( mec ) 
		{
			if ( tcl->has_friend(mec) ||
				( mec->has_base(this_class) && 
					(tcl==mec || tcl->has_base(mec))))
						return 1;
		}	

		if ( mef ) 
		{
			if ( tcl->has_base(this_class) &&
				// && tcl->has_friend(mef))
				friend_check(tcl,this_class,mef))
					return 1;
		}
	}

	// call from check_visibility
	if ( noCdcl ) return 0; 
	
	if ( Cdcl && Cdcl->base == NAME && 
		Cdcl->n_stclass == STATIC && 
		Cdcl->n_initializer && 
		Cdcl->n_qualifier ) 
	{
		Pbase bn = Pbase(Cdcl->n_qualifier->tp);
		Pclass cl = Pclass(bn->b_name->tp);

		if ( cl == this_class ||
			(n->n_protect && cl->has_base(this_class)) || 
			cl->has_friend(this_class))
				return 1;
	}

	return 0;
}

Pexpr classdef::find_name(char* s, Pclass cl, int access_only)
/*
	look for "s" in "this" class and its base classes
	if (cl)
		accept only a member of "cl" or "cl"'s base classes
		(that is cl::s was seen)

	complicated by hiding rules: private, protected, friend
	
*/
{
// error('d',"%s->find_name(%s,%s) memtbl %d",string,s,cl?cl->string:"",memtbl);
	Pname n = memtbl->look(s,0);

	if (n) {
		if (n->tp) {
			switch (n->tp->base) {
			case OVERLOAD:
				break;
			case FCT:
				if (Pfct(n->tp)->f_virtual==0) {
					if (n->n_dcl_printed==0) n->dcl_print(0);
					break;
				}
			default:
                                 if (c_body==1) dcl_print(0);
			}
		}

		if (n->base == PUBLIC) {
			if (mex && n->n_scope==0) {
				if ( is_accessible(n,this) == 0 ) 
				{
					if ( me == dummy_fct )
						error("G scope cannot access%n: %sM",n,n->n_protect?"protected":"private");
					else error("%n cannot access%n: %sM",me,n,n->n_protect?"protected":"private");
					mex = 0;	// suppress further error messages
				}
			}
			mex = 0; // don't have find_in_base complain about n
			return find_in_base(s, cl);
		}

		if (cl==0 || cl==this) {
			if (mptr==0
			&& n->n_stclass!=STATIC
			&& n->n_stclass!=ENUM) {
				Ptype t = n->tp;

// error('d',"cl %d this %d",cl,this);

				if (mex && n->n_scope==0 && n->tp->base!=OVERLOAD) {
					if ( is_accessible(n,this)==0 )
					{
						if ( me == dummy_fct )
							error("G scope cannot access%n: %sM",n,n->n_protect?"protected":"private");
						else error("%n cannot access%n: %sM",me,n,n->n_protect?"protected":"private");
						mex = 0;	// suppress further error messages
					}
				}

				Pname th = cc->c_this;
				Pexpr r = new ref(REF,th,n);

				if ( access_only == 0 ) {
					if (th) th->use();
					n->use();
				}
				r->tp = t;
				return r;
			}

			if (mex && n->n_scope==0 && n->tp->base!=OVERLOAD) {
				if ( is_accessible(n,this)==0 )
				{
					if ( me == dummy_fct )
						error("G scope cannot access%n: %sM",n,n->n_protect?"protected":"private");
					else error("%n cannot access%n: %sM",me,n,n->n_protect?"protected":"private");
					mex = 0;	// suppress further error messages
				}
			}
			n->use();
			return n;
		}
	}

	if ((cl==0 || cl==this)	// not qualified to a base class
	&& csu!=UNION
	&& csu!=ANON
	&& strcmp(s,"__as")==0) { // assignment is special: you cannot inherit it
		if (baselist==0
		|| (baselist && baselist->bclass->obj_size!=obj_size)) {
			Pname cn = ktbl->look(string,0);
			if (cn->tp->base == COBJ) cn = Pbase(cn->tp)->b_name;
			Pname x = gtbl->look("__as",0);
			if (x) {	// what if there is an (illegal) global assignment operation?
					// hack hack don't declare global assignment operations!
				Pfct f = Pfct(x->tp);
				if (f->base == FCT) {
					Pptr r = f->argtype->tp->is_ref();
					if (r) {
						Pname cnn = r->typ->is_cl_obj();
						if (cnn && cn==cnn) return 0;
					}
				} else {
					for (Plist gl = Pgen(f)->fct_list; gl; gl=gl->l) {
						Pptr r = Pfct(gl->f)->argtype->tp->is_ref();
						if (r) {
							Pname cnn = r->typ->is_cl_obj();
							if (cnn &&cn==cnn) return 0;
						}
					}
				}
			}
			return make_assignment(cn) ? find_name(s,cl) : 0;
		}
	}

	return find_in_base(s, cl);
}

static Pclass rootClass;
static Pbcl pubVClass;
static struct PendingMessage { 
    Pbcl bc;
    Pname mf;
    char *nm;
} *pM;

Pexpr classdef::find_in_base(char* s, Pclass cl)
{
	Pbcl bc = 0;
	Pexpr e = 0;

// error('d',"%s->find_in_base(%s %s)",string,s,cl?cl->string:"");

	if ( me == 0 ) mef = 0;
	if (rootClass == 0) rootClass = this;
	for (Pbcl b=baselist; b; b=b->next) {
		Pclass ccl = cl==this?0:cl;
// error('d',"try %t %s %k",b->bclass,b->bclass?b->bclass->string:"?", b->base);
		Pexpr ee = b->bclass->find_name(s,ccl);

		if (ee) {
			if (c_body == 1) {	// look for first use (through this)
				if (b!=baselist || b->base==VIRTUAL)
					dcl_print(0);
				else {
					Pexpr ex = ee;
					while ((ex->base==MDOT && ex->i1==1)
					|| (ex->base==REF && ex->e1==cc->c_this)) ex = ex->mem;
					switch (ex->tp->base) {
					case OVERLOAD:
						break;
					case FCT:
						if (Pfct(ex->tp)->f_virtual==0) break;
					default:
						dcl_print(0);
					}
				}
			}

			if (e) {
// error( 'd', "find_in_base: b( %s ): %k %k ",b->bclass->string,b->base,b->ppp);
				Pexpr ex = e;
				int evb = 0; 	// number of vbase indirections
				int eb = 0;

// note that this does not catch enum members
				while (ex->base == MDOT
				|| (ex->base==REF && ex->e1==cc->c_this)) {
					if (ex->base==MDOT) evb += int(ex->i1);
					ex = ex->mem;
				}

				Pexpr eex = ee;
				int eevb = b->base==VIRTUAL; 	// number of vbase indirections (incl. possibly this one)
				int eeb = b->base!=VIRTUAL;

				while (eex->base == MDOT
				|| (eex->base==REF && eex->e1==cc->c_this)) {
					if (eex->base==MDOT) eevb += int(eex->i1);
					eex = eex->mem;
				}

// error('d', "find_in_base: ex: %k eex: %k, eevb: %d evb: %d", ex->base, eex->base, eevb, evb );
// relying on simple counts for sub-object identification isn't good enough

				if (ex != eex)	{
// error('d',"ex %k tp %k eex %k tp %k", ex->base, ex->tp->base, eex->base, eex->tp->base );
				//	if (!mqua) {
						Pclass ocl, ncl;
						if ( ex->tp->base == FCT ) 
     							ocl = Pfct(ex->tp)->memof;
						else 
						if ( ex->tp->base == OVERLOAD )
							ocl = Pfct(Pgen(ex->tp)->fct_list->f->tp)->memof;
						else ocl = Pclass(ex->n_table->t_name->tp);
//						else ocl = 0;

						if ( eex->tp->base == FCT ) 
     							ncl = Pfct(eex->tp)->memof;
						else 
						if ( eex->tp->base == OVERLOAD )
							ncl = Pfct(Pgen(eex->tp)->fct_list->f->tp)->memof;
						 else ncl = Pclass(eex->n_table->t_name->tp);
//						else ncl = 0;

//						Pclass ocl = Pfct(ex->tp)->memof;
//						Pclass ncl = Pfct(eex->tp)->memof;
						int eb = ocl?ocl->has_base(ncl):0;
						int eeb = ncl?ncl->has_base(ocl):0;

//error('d',"eb %d eeb %d evb %d eevb %d",eb,eeb,evb,eevb);
						if (eb==0 && eeb==0) {
							// different
							error("ambiguous%n and%n",ex,eex);
							break;
						}
						else if (eb) {	// ex dominates
							if (eevb<evb) error("ambiguous%n and%n (different sub-objects)",ex,eex);
						}
						else {	// eex dominates
							e = ee;
							bc = b;
							if (evb<eevb) error("ambiguous%n and%n (different sub-objects)",ex,eex);
						}
						if (evb==0 && eevb==0) {
							error("ambiguous%n and%n (different sub-objects)",ex,eex);
						}
				//	}
				//	else {
				//		// different
				//		error("ambiguous%n and%n",ex,eex);
				//		break;
				//	}
				}
				else if (ex->base==NAME
				&& (Pname(ex)->n_evaluated || Pname(ex)->n_sto==EXTERN)) {
//error('d',"enum");
				}
				else if (evb==0 && eevb==0) {
//error('d',"e %k",e->base);
					// no virtual base => different
					error("ambiguous%n and%n (no virtualB)",ex,eex);
					break;
				}
				else if ((evb && eevb==0) || (eevb && evb==0)) {
					// only one virtual base => different
					error("ambiguous%n and%n (one not in virtualB)",ex,eex);
					break;
				}
			}
			else {
				e = ee;
				bc = b;
			}
		}
	}

	if (rootClass == this ) {
    		if ( pM ) {
			// deferred until all base classes of ``this'' examined
			error("%n cannot access %s: %s is a privateBC",pM->mf,pM->nm,pM->bc->bclass->string);
        		delete pM; pM=0;
    		}
    		rootClass = 0;
    		pubVClass = 0;
	}

	if (e == 0) return 0;

	if (mex) {
		if ( bc->ppp==PRIVATE ) {	// private base
			if (this==mec || 
                           (mec && has_friend(mec)) || 
 			   (mef && has_friend(mef)))
				;
			else 
			if ( bc->base == VIRTUAL &&
     			     rootClass != this ) { 
				// if one instance is public, it dominates
				if ( pubVClass == 0 ||
                                     strcmp(pubVClass->bclass->string,bc->bclass->string)) {
					pM = (PendingMessage *) new char[sizeof(*pM)];
					pM->bc = bc; pM->mf = me; pM->nm = s;
				}
			}
			else {
				if ( me == dummy_fct )
					error("G scope cannot access %s: %s is a privateBC",s,bc->bclass->string);
				else error("%n cannot access %s: %s is a privateBC",me,s,bc->bclass->string);
				mex = 0;
			}
		}
		else { // public base class
		if ( bc->base == VIRTUAL ) {
			if ( pM && 
			     strcmp(bc->bclass->string,pM->bc->bclass->string)==0 ) {
				delete pM;
				pM=0;
				pubVClass = bc; 
				} // previous private member becomes public
			else pubVClass = bc; // ignore subsequent private instances
	 		}
		}
	}

	if (e->base==NAME
	&& Pname(e)->n_stclass==STATIC) {	// static member
		Pname(e)->use();
		return e;
	}
	if (e->base != NAME)
	if (bc->base == VIRTUAL) {	// this->mem => this->Pbclass->mem
		e->mem = new mdot(bc->bclass->string,e->mem);
		e->mem->i1 = 1;
		e->mem->tp = e->mem->mem->tp;
	}
	else if (bc!=baselist) {	// not first base
		if (e->e1 == cc->c_this) {	// this->mem => this->Obcl.mem
			e->mem = new mdot(bc->bclass->string,e->mem);
			e->mem->tp = e->mem->mem->tp;
		}
		else {	// this->p->mem => this->Obcl.p->mem
			Pexpr ee = e;
			while (ee->e1->base == REF) ee = ee->e1;
			ee->mem = new mdot(bc->bclass->string,ee->mem);
			ee->mem->tp = ee->mem->mem->tp;	
		}
	}

	return e;
}

int has_virt(Pclass cl)
{
	if (cl->virt_count) return 1;
	for (Pbcl b = cl->baselist; b; b = b->next)
		if (b->bclass->virt_count || has_virt(b->bclass)) return 1;
	return 0;
}

Pname find_vptr(Pclass cl)
/*
	find virtual function table
	in memtbl or memtbl of ``first bases''
*/
{
//error('d',"find_vptr %t",cl);
	while (cl) {
		Pname vp = cl->memtbl->look("__vptr",0);
		if (vp) return vp;
		Pbcl b = cl->baselist;
		cl = 0;
		for (; b; b = b->next)
			if (b->base == NAME) {
				cl = b->bclass;
				break;
			}
	}
//error('d',"return 0");
	return 0;
}

void make_dummy()
/* a function with no special privileges */
{
        Pname x = new name(".." /*"__static_initializer"*/);
        x->tp = new fct(Pvoid_type,0,1);
        dummy_fct = x->dcl(gtbl,EXTERN);
//	dummy_fct->string = "";
        delete x;
}

void check_visibility(Pname n, Pname q, Pclass cl, Ptable tbl, Pname fn)
/*
	"fn" calls "n" a member function of "cl"
	fn can be zero (for functions called in arguments to static constructors) 
*/
{
// error('d',"check_visibility(%n, %t, %d, %n)",n,cl,tbl,fn);
	if (fn==0) {
                if (dummy_fct == 0) make_dummy();
                fn = dummy_fct;
	}
	Pname nn = new name;
        char* s = n->n_gen_fct_name;    // overloaded name
	nn->string = s?s:n->string;
	nn->n_qualifier = q;
	Pname nx = Pname(find_name(nn,cl,tbl,REF,fn)); // nn deleted by find_name
	if (nx->tp->base != OVERLOAD) return;

	// can we get here?

	// overloaded not checked by find_name()
	// (since it looks for NAMEs not functions)

	for (Plist gl=Pgen(nx->tp)->fct_list; gl; gl=gl->l) {
		Pname nn = gl->f;
		if (n == nn) {
			if (nn->n_scope) return;	// public member

			Pfct omef = mef;
			Pclass omec = mec;
			Pclass otcl = tcl;

			Pclass ncl = Pclass(nn->n_table->t_name->tp);
			Pname fncn = fn->n_table->t_name;

			mec = fncn?Pclass(fncn->tp):0; 
			Pfct f = mef = Pfct(fn->tp);
			tcl = cl;

			int ok = is_accessible( n, ncl, 1 );

			// restore global values
			mef = omef; mec = omec; tcl = otcl;

			if ( ok ) return;

			if ( Cdcl && Cdcl->base == NAME && 
				Cdcl->n_stclass == STATIC && 
				Cdcl->n_initializer && 
				Cdcl->n_qualifier )
			{
				Pbase bn = Pbase(Cdcl->n_qualifier->tp);
				Pclass ccl = Pclass(bn->b_name->tp);

				if ( ccl == cl || ccl->has_friend(f) ||
          				(n->n_protect && ccl->has_base(ncl)))
						return;
			}

			if ( fn == dummy_fct )
				error("G scope cannot access%n: %sM",nn,nn->n_protect?"protected":"private");
			else error("%n cannot access%n: %sM",fn,nn,nn->n_protect?"protected":"private");
			return;
		}
	}
	error('i',"visibility check failed");
}
0707071010112044321004440001630000160000010202000466055403200000700000150132gram.y/*ident	"@(#)ctrans:src/gram.y	1.11" */
/*************************************************************************

	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.

gram.y:
	
	This is the C++ syntax analyser.

	Syntax extensions for error handling:
		nested functions
		any expression can be empty
		any expression can be a constant_expression

	A call to error() does not change the parser's state

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

%{
#include "cfront.h"
#include "size.h"
#include "template.h"
#include <string.h>
// include tqueue.h after YYSTYPE is defined ...


struct parstate {
	Ptype intypedef;
	int   defercheck;
	Pname intag;
} pstate[BLMAX];
static int px;
static void
SAVE_STATE()
{
	if ( px++ >= BLMAX ) error('i',"maximum scope depth exceeded");
	pstate[px].intypedef = in_typedef;
	in_typedef = 0;
	pstate[px].defercheck = defer_check;
	defer_check = 0;
	pstate[px].intag = in_tag;
	in_tag = 0;
}
static void
RESTORE_STATE()
{
	if ( --px < 0 ) error('i',"scope stack underflow");
	in_typedef = pstate[px].intypedef;
	defer_check = pstate[px].defercheck;
	in_tag = pstate[px].intag;
}

#define copy_if_need_be(s)  ((templp->in_progress || templp->parameters_in_progress) ? strdup(s) : s) 
#define YYMAXDEPTH 600

#ifdef DBG
#ifndef YYDEBUG
#define YYDEBUG 1
#endif
#endif

static init_seen = 0;
static cdi = 0;
static Pnlist cd = 0, cd_vec[BLMAX];
static char stmt_seen = 0, stmt_vec[BLMAX];

//local class
static Plist tn_vec[BLMAX], lcl_tn_vec[BLMAX], lcl_blk_vec[BLMAX];
extern void local_restore();
extern void local_name();

//nested class
static Plist nested_tn_vec[BLMAX], nested_type_vec[BLMAX];
extern void nested_restore();

static Pname err_name = 0;

// fcts put into norm2.c just to get them out of gram.y
void sig_name(Pname);	
Ptype tok_to_type(TOK);
void memptrdcl(Pname, Pname, Ptype, Pname);

static Pptr doptr(TOK p, TOK t)
{
	Pptr r = new ptr(p,0);
	switch (t) {
	case CONST:
		r->rdo = 1;
               // if (p == RPTR) error('w',"redundant `const' after &");
		break;
	case VOLATILE:
		error('w',"\"volatile\" not implemented (ignored)");
		break;
	default:
		error("syntax error: *%k",t);
	}
	return r;
}

static Pbcl dobase(TOK pr, Pname n, TOK v = 0)
{
	Pbcl b = new basecl(0,0);

	if (pr == PROTECTED) {
		pr = PUBLIC;
		error("protectedBC");
	}
	b->ppp = pr;	// save protection indicator

	if (n) {
		if (n->base != TNAME) {
			error("BN%n not aTN",n);
			return 0;
		}

		Pbase bt = Pbase(n->tp);
		while (bt->base == TYPE) bt = Pbase(bt->b_name->tp);

		if (bt->base != COBJ) {
			error("BN%n not aCN",n);
			return 0;
		}

		if (v) {
			if (v != VIRTUAL) error("syntax error:%k inBCD",v);
			b->base = VIRTUAL;
		}
		else
			b->base = NAME;

		b->bclass = Pclass(bt->b_name->tp);
	}

	return b;
}


#define Ndata(a,b)	b->normalize(Pbase(a),0,0)
#define Ncast(a,b)	b->normalize(Pbase(a),0,1)
#define Nfct(a,b,c)	b->normalize(Pbase(a),Pblock(c),0)
#define Ncopy(n)	(n->base==TNAME)?new name(n->string):n

#define Finit(p)	Pfct(p)->f_init
#define Fargdcl(p,q,r)	Pfct(p)->argdcl(q,r)
#define Freturns(p)	Pfct(p)->returns
#define Vtype(v)	Pvec(v)->typ
#define Ptyp(p)		Pptr(p)->typ

		/* avoid redefinitions */
#undef EOFTOK
#undef ASM
#undef BREAK
#undef CASE
#undef CONTINUE
#undef DEFAULT
#undef DELETE
#undef DO
#undef ELSE
#undef ENUM
#undef FOR
#undef FORTRAN
#undef FRIEND
#undef GOTO
#undef IF
#undef NEW
#undef OPERATOR
#undef RETURN
#undef SIZEOF
#undef SWITCH
#undef THIS
#undef WHILE
#undef LP
#undef RP
#undef LB
#undef RB
#undef REF
#undef DOT
#undef NOT
#undef COMPL
#undef MUL
#undef AND
#undef PLUS
#undef MINUS
#undef ER
#undef OR
#undef ANDAND
#undef OROR
#undef QUEST
#undef COLON
#undef ASSIGN
#undef CM
#undef SM
#undef LC
#undef RC
#undef ID
#undef STRING
#undef ICON
#undef FCON
#undef CCON
#undef ZERO
#undef ASOP
#undef RELOP
#undef EQUOP
#undef DIVOP
#undef SHIFTOP
#undef ICOP
#undef TYPE
#undef TNAME
#undef EMPTY
#undef NO_ID
#undef NO_EXPR
#undef FDEF
#undef ELLIPSIS
#undef AGGR
#undef MEM
#undef MEMPTR
#undef PR
#undef TSCOPE
#undef DECL_MARKER
#undef REFMUL
#undef LDOUBLE
#undef LINKAGE
#undef LOCAL
#undef TEMPLATE

#undef XVIRT
#undef XNLIST
#undef XILINE
#undef XIA
#undef STATEMENT
#undef EXPRESSION
#undef SM_PARAM
#undef TEMPLATE_TEST
#undef PTNAME
#undef NEW_INIT_KLUDGE
%}

%union {
	char*	s;
	TOK	t;
	int	i;
	loc	l;
	Pname	pn;
	Ptype	pt;
	Pexpr	pe;
	Pstmt	ps;
	Pbase	pb;
	Pnlist	nl;
	Pslist	sl;
	Pelist	el;
	Pbcl	pbc;
	Pptr	pp;
	PP	p;	// fudge: pointer to all class node objects
	Plist	pl;
	toknode* q;	// token queue
}
%{
#include "tqueue.h"
extern YYSTYPE yylval, yyval;
extern int yyparse();

// in_typedef should allow for nested in_typedef
extern int	declTag;	 // !1: inline, virtual mod permitted
int		in_sizeof = 0;
Ptype 		in_typedef = 0;  // catch redefinition of TNAME
Pname		in_tag = 0;      // handle complex typedefs: int (*)()
extern int	defer_check;	 // redefinition typedef check delay
Pname		curr_scope;

extern int 	must_be_id;	 // !0, TNAME => ID, i.e., int X
int	DECL_TYPE = 0; 	 // lalex() wants this set for global x(*fp)()
int	in_arg_list=0; 	 // !0 when parsing argument list
static int in_binit_list=0;
int	in_class_decl=0; // !0 when processing class definition
int	parsing_class_members=0; // !0 when parsing class def but not member function body
int	in_mem_fct=0;    // !0 when parsing member function definition

#define yylex lalex
#define NEXTTOK() ( (yychar==-1) ? (yychar=yylex(),yychar) : yychar )
#define EXPECT_ID() must_be_id = 1
#define NOT_EXPECT_ID() must_be_id = 0

Pname syn()
{
ll:
	switch (yyparse()) {
	case 0:		return 0;	// EOF
	case 1:		goto ll;	// no action needed
	default:	return yyval.pn;
	}
}

%}
/*
	the token definitions are copied from token.h,
	and all %token replaced by %token
*/
			/* keywords in alphabetical order */
%token EOFTOK		0
%token ASM		1
%token AUTO		2
%token BREAK		3
%token CASE		4
%token CONTINUE		7
%token DEFAULT		8
%token DELETE		9
%token DO		10
%token ELSE		12
%token ENUM		13
%token FOR		16
%token FORTRAN		17 
%token FRIEND		18 
%token GOTO		19
%token IF		20
%token NEW		23
%token OPERATOR		24
%token RETURN		28
%token SIZEOF		30
%token SWITCH		33
%token THIS		34
%token WHILE		39

			/* operators in priority order (sort of) */
%token LP		40
%token RP		41
%token LB		42
%token RB		43
%token REF		44
%token DOT		45
%token NOT		46
%token COMPL		47
%token MUL		50
%token AND		52
%token PLUS		54
%token MINUS		55
%token LT		58
%token GT		60
%token ER		64
%token OR		65
%token ANDAND		66
%token OROR		67
%token QUEST		68
%token COLON		69
%token ASSIGN		70
%token CM		71
%token SM		72
%token LC		73
%token RC		74

    /* = constants etc. */
%token ID	   80
%token STRING	   81
%token ICON	   82
%token FCON	   83
%token CCON	   84
%token NAME	   85
%token ZERO	   86
    /* groups of tokens */
%token ASOP   90	/* op= */
%token RELOP  91	/* LE GE LT GT */
%token EQUOP  92	/* EQ NE */
%token DIVOP  93	/* DIV MOD */
%token SHIFTOP		94	/* LS RS */
%token ICOP		95	/* INCR DECR */
%token TYPE		97
    /* TYPE =	INT FLOAT CHAR DOUBLE REGISTER STATIC EXTERN AUTO
	LONG SHORT UNSIGNED INLINE FRIEND VIRTUAL */

%token TNAME	  123
%token EMPTY	  124
%token NO_ID	  125
%token NO_EXPR	  126
%token FDEF	  127

%token ELLIPSIS	155
%token AGGR	156
%token MEM	160
%token MEMPTR	173
%token PR		175	/* PUBLIC PRIVATE PROTECTED */
%token TSCOPE		178	/* TNAME :: */
%token DECL_MARKER	179
%token REFMUL		180	/* ->*, .* */
%token LDOUBLE		181
%token LINKAGE		182	/* extern "asdf" */
%token LOCAL		183	/* local class */
%token TEMPLATE		185	/* local class */

/* "tokens" for aux data structures */

%token XVIRT	        200 /* class virt */
%token XNLIST		201 /* struct name_list */
%token XILINE		202
%token XIA		203
%token STATEMENT        205
%token EXPRESSION       206
%token SM_PARAM         207 
%token TEMPLATE_TEST    208
%token PTNAME           209
%token NEW_INIT_KLUDGE  210
%token XDELETED_NODE    211
%token DUMMY_LAST_NODE  212

%type <p>	external_def fct_dcl fct_def att_fct_def arg_dcl_list 
		base_init init_list binit
		data_dcl ext_def vec ptr
		type tp enum_dcl moe_list moe 
		tag ttag enumtag class_head class_dcl cl_mem_list 
		cl_mem dl decl_list 
		fname decl initializer stmt_list
		caselab_stmt caselablist
		block statement simple ex_list elist e ee term prim
		term_elist
		cast_decl cast_type c_decl c_type c_tp
		arg_decl formal_decl at arg_type arg_list arg_type_list
		new_decl new_type
		condition
		TSCOPE tscope TNAME tn_list MEMPTR
		qualified_tname
		PTNAME tname ptname template_def
%type <l>	LC RC SWITCH CASE DEFAULT FOR IF DO WHILE GOTO RETURN DELETE
		BREAK CONTINUE
%type <t>	oper ellipsis_opt
		EQUOP DIVOP SHIFTOP ICOP RELOP GT LT ASOP
		ANDAND OROR PLUS MINUS MUL ASSIGN OR ER AND 
		LP LB NOT COMPL AGGR
		TYPE PR REFMUL
		STATEMENT EXPRESSION stmt_or_expr
%type <s>	CCON ZERO ICON FCON STRING LINKAGE
%type <pn>	ID FDEF inline_fct_def identifier
%type <pbc>	base_list base_unit_list base_unit
%type <q>	EMPTY
%type <i>	fct_attributes
%type <pl>	arg_lp
%type <pe>      temp_inst_parm
%type <el>      temp_inst_parms

%left	EMPTY
%left	NO_ID
%left	RC LC ID BREAK CONTINUE RETURN GOTO DELETE DO IF WHILE FOR CASE DEFAULT
	AGGR ENUM TYPE TNAME TSCOPE
%left	NO_EXPR

%left	CM
%right	ASOP ASSIGN
%right	QUEST COLON
%left	OROR
%left	ANDAND
%left	OR
%left	ER
%left	AND
%left	EQUOP
%left	RELOP GT LT
%left	SHIFTOP
%left	PLUS MINUS
%left	MUL DIVOP MEMPTR
%left   REFMUL
%right	NOT COMPL NEW
%right	ICOP SIZEOF
%left	LB LP DOT REF MEM

%start ext_def

%%
/*
	this parser handles declarations one by one,
	NOT a complete .c file
*/


/************** DECLARATIONS in the outermost scope: returns Pname (in yylval) ***/

ext_def		:  external_def		{	return 2; }
		|  SM			{	return 1; }
		|  EOFTOK		{	return 0; }
		|  LINKAGE LC
			{
				set_linkage($<s>1);
				bl_level--;
				return 1;
			}
		|  RC
			{
				set_linkage(0);
				bl_level++;
				return 1;
			}
 		|  template              {  return 1; } 
                |  template_test         {  return 1 ;}
		;


template_test   : TEMPLATE_TEST identifier LT temp_inst_parms GT SM
	          { Ptreet t = tree_template::get($<pn>2->string) ;
                    Pexpr  e = 0 ;
	            if (t)
		      e = t->expand(expr_unlist($<el>4)) ;
	            else error ("%s wasn't an expression template",
		                	$<pn>2->string)  ;
	           } ;

template    :    TEMPLATE
                 { templp->start() ; }
                 LT template_parm_list GT
                 {templp->enter_parameters() ; }
                 template_def
                 {templp->end($<pn>7);
                  templp->in_progress = false ;
                  goto mod;}
                 ;

template_def   : att_fct_def
                 { goto mod; }
                | fct_def
                  { goto mod; }
                | class_dcl SM
                  { Pname pn = $<pb>1->aggr();
                    /* basetype:aggr() does not return the name for a forward */
		    /* declaration, so extract it directly */
                    $$ = (pn ? pn : $<pb>1->b_name) ;
                    DECL_TYPE = 0;  }
                /* internal template specification productions*/
                | STATEMENT 
                  {templp->curr_tree_template = $1 ; }
                   identifier COLON statement
                  {$<pn>3->n_initializer = $<pe>5 ; /* actually a stmt */
                    $<pn>$ = $<pn>3; }
                | EXPRESSION 
                  {templp->curr_tree_template = $1 ; }
		   identifier COLON ee SM
                  {$<pn>3->n_initializer = $<pe>5 ; /* actually a stmt */
                    $<pn>$ = $<pn>3 ; }
                 ;

identifier	: ID 
		|  qualified_tname
			{ $<pn>$ = Ncopy($<pn>1) ;} ;
		;

external_def	:  data_dcl
			{	
			/* if function declartion with arguments
			 * need to make sure modified_tn is traversed */
			if ( $<pn>1 != 0 
				&& $<pn>1->tp->base == FCT 
				&& Pfct($<pn>1->tp)->nargs !=0 ) 
					goto mod;
			else {
				modified_tn = 0;
				curr_scope = 0;
				if ($<pn>1==0) $<i>$ = 1; 
			     }
			}
		|  att_fct_def
			{	goto mod; }
		|  fct_def
			{	goto mod; }
		|  fct_dcl
			{ mod:	if (modified_tn) {
					restore();
					modified_tn = 0;
				}
				local_blk = 0;
				curr_scope = 0;
				if (local_tn) {
					local_restore();
					local_tn = 0;
				}
				
				if (nested_tn) { // x::f(){}
					nested_restore();
					nested_tn = 0;
					nested_type = 0;
				}
			}
		|  ASM LP STRING RP SM
			{	Pname n = new name(make_name('A'));
				n->tp = new basetype(ASM,0);
				Pbase(n->tp)->b_name = Pname($<s>3);
				$$ = n;
			}
		;

fct_dcl		: decl ASSIGN initializer SM
			{
				err_name = $<pn>1;
				if(err_name) err_name->n_initializer = $<pe>3;
				goto fix;
			}
		| decl SM
			{
				Ptype t;
				err_name = $<pn>1;
			fix:
				if (err_name == 0) {
					error("syntax error:TX");
					$$ = Ndata(defa_type,err_name);
				}
				else if ((t=err_name->tp) == 0) {
					error("TX for%n",err_name);
					$$ = Ndata(defa_type,err_name);
				}
				else if (t->base==FCT) {
					if (Pfct(t)->returns==0)
						$$ = Nfct(defa_type,err_name,0);
					else
						$$ = Ndata(0,err_name);
				}
				else {
					error("syntax error:TX for%k%n",t->base,err_name);
					$$ = Ndata(defa_type,err_name);
				}
			}
		;

att_fct_def	:  type decl arg_dcl_list check_inline base_init block
			{	Pname n = Nfct($1,$<pn>2,$6);
				Fargdcl(n->tp,name_unlist($<nl>3),n);
				Finit(n->tp) = $<pn>5;
				$$ = n;
				NOT_EXPECT_ID();
                        //???POP_SCOPE(); // undef arg names
			}
		|  type decl arg_dcl_list check_inline EMPTY
			{
				Pname n = Nfct($1,$<pn>2,dummy);
				Fargdcl(n->tp,name_unlist($<nl>3),n);
				$<q>5->retval.pn = n;
				$$ = n;
				NOT_EXPECT_ID();
			}
		|  type decl arg_dcl_list check_inline NO_ID /*syntax error*/
			{
				error(&$<pn>2->where,"syntax error -- did you forget a ';'?");
				Pname n = Nfct($1,$<pn>2,0);
				$$ = n;
				NOT_EXPECT_ID();
                   	//???POP_SCOPE(); // undef arg names
			}
		;

fct_def		:  decl arg_dcl_list check_inline base_init block
			{	Pname n = Nfct(defa_type,$<pn>1,$5);
				Fargdcl(n->tp,name_unlist($<nl>2),n);
				if ( $<pn>4 && $<pn>4->n_list && 
     					ccl && ccl->csu == UNION )  
						error( "multiple initializers in unionK %s::%n", $<pn>1->string, $<pn>1 );
				Finit(n->tp) = $<pn>4;
				$$ = n;
				NOT_EXPECT_ID();
                        //???POP_SCOPE(); // undef arg names 
			}
		|  decl arg_dcl_list check_inline EMPTY
			{
				Pname n = Nfct(defa_type,$<pn>1,dummy);
				Fargdcl(n->tp,name_unlist($<nl>2),n);
				$<q>4->retval.pn = n;
				$$ = n;
				NOT_EXPECT_ID();
			}
		|  decl arg_dcl_list check_inline NO_ID /*syntax error*/
			{
				error(&$<pn>1->where,"badD of%n -- did you forget a ';'?",$<pn>1);
				Pname n = Nfct(defa_type,$<pn>1,0);
				$$ = n;
				NOT_EXPECT_ID();
                         //???POP_SCOPE(); // undef arg names
			}
		;

inline_fct_def	:  FDEF 
			{//PUSH_ARG_SCOPE
                        	arg_redec($<pn>1);
                   	}
		   base_init block
			{
				Finit($1->tp) = $<pn>3;
				Pfct($1->tp)->body = Pblock($4);
				$$ = $1;
				NOT_EXPECT_ID();
                        //???POP_SCOPE(); // undef arg names
			}
		;


check_inline	:  /* empty */
		   {
			// if parsing implicit inline def, save body
			//   of function for parsing after class def
			switch ( NEXTTOK() ) {
			case LC: case COLON:
				if ( in_class_decl ) {
					// mem or friend inline def
					// save text of mem_init & ftn
					la_backup(yychar,yylval);
					// yylval used as dummy...
					la_backup(FDEF, yylval);
					if ( yylval.q = save_text() )
						yychar = EMPTY;
					else { // syntax error
						// just parse in place
						yylex(); // FDEF
						yychar = yylex();
					}
				} // if in_class_decl
				break;
			default:
				la_backup(yychar,yylval);
				yychar = NO_ID; // 'graceful' recovery
				break;
			}
		   }
		;

base_init	:  COLON { ++in_binit_list; } init_list
			{	
				$$ = $3; 
				in_arg_list = 0;
				--in_binit_list;
			}
		|  %prec EMPTY
			{	$$ = 0; }
		;

init_list	:  binit
			{ $$ = $1; }
		|  init_list CM binit
			{ $<pn>$ = $<pn>3;  $<pn>$->n_list = $<pn>1; }
		;

binit		:  LP elist RP
			{
				$<pn>$ = new name;
				$<pn>$->n_initializer = $<pe>2;
			}
		|  ttag LP elist RP
			{
				Pname n = Ncopy($<pn>1);
				n->base = $<pn>1->base;
				n->tp = $<pn>1->tp;
				n->n_initializer = $<pe>3;
				$<pn>$ = n;
			}

/*
		|  NEW LP elist RP
			{	Pname n = new name;
				n->base = NEW;
				n->n_initializer = $<pe>3;
				$<pn>$ = n;
			}
*/
		;




/*************** declarations: returns Pname ********************/

arg_dcl_list	:  arg_dcl_list data_dcl
			{	if ($<pn>2 == 0)
					error("badAD");
				else if ($<pn>2->tp->base == FCT)
					error("FD inAL (%n)",$<pn>2);
				else if ($1)
                                        $<nl>1->add_list($<pn>2);
				else
					$<nl>$ = new nlist($<pn>2);
			}
		|  %prec EMPTY
			{
                                $$ = 0; 
			}
		;

dl		:  decl
		|  ID COLON 
                        {
                                if ( in_typedef ) {
                                        error("Tdef field");
                                        in_typedef = 0;
                                }
                        //      ENTER_NAME($<pn>1);
                        }
		    e		%prec CM
			{	$$ = $<pn>1;
				$<pn>$->tp = new basetype(FIELD,$<pn>4);
		 	}
		|  COLON e		%prec CM
			{	$$ = new name;
				$<pn>$->tp = new basetype(FIELD,$<pn>2);
                                if ( in_typedef ) {
                                        error("Tdef field");
                                        in_typedef = 0;
                                }
			}
                |  decl ASSIGN
                        {
                        //      ENTER_NAME($<pn>1);
                        }
                   initializer
                        {       Pexpr e = $<pe>4;
                                if (e == dummy) error("emptyIr");
                                $<pn>1->n_initializer = e;
                                init_seen = 0;
                        }
                ;

decl_list	:  dl
			{	
				if ($1) $<nl>$ = new nlist($<pn>1); 
				if ( NEXTTOK() == CM && la_look() == TNAME ) 
					EXPECT_ID();
			}
		|  decl_list CM dl
			{	if ($1)
					if ($3)
						$<nl>1->add($<pn>3);
					else
						error("DL syntax");
				else {
					if ($3) $<nl>$ = new nlist($<pn>3);
					error("DL syntax");
				}
				if ( NEXTTOK() == CM && la_look() == TNAME ) 
					EXPECT_ID();
			}
		;

data_dcl	:  type decl_list SM	
			{ 
				extern int co_hack;
				co_hack = 1;
				/*$$ = Ndata($1,name_unlist($<nl>2));*/
				Pname n = Ndata($1,name_unlist($<nl>2)); 
				if ( in_typedef && in_tag ) { 
					if ( n->tp->check( in_tag->tp, 0 ))
    						error("%nredefined: previous: %t now: %t", in_tag, in_tag->tp, n->tp );
				}
				in_typedef = 0;
				in_tag = 0;
				co_hack = 0;
				DECL_TYPE = 0; 
				$$ = n;
			}
		|  type SM		
			{
				$$ = $<pb>1->aggr(); 
				in_typedef = 0;
				in_tag = 0;
				DECL_TYPE = 0; 
			}
		
		;

/* This is where parametrized types, and regular types come together. */

lt 		: LT { templp->parameters_in_progress++; };
gt 		: GT { templp->parameters_in_progress--; };

tname           : qualified_tname { $<pn>$ = templp->check_tname($<pn>1) ; }
                | qualified_tname lt temp_inst_parms gt
                  { 
		    $<pn>$ = parametrized_typename($<pn>1,
						  (expr_unlist($<el>3))) ; 
		  }
                | NAME LT temp_inst_parms GT
                  { extern Pbase any_type;
		    error("%n was not a parametrized type.", $<pn>$) ;
                    $<pn>$= $<pn>1->tdef() ;
                    $<pn>$->tp = any_type ; } ;



tp		:  TYPE			
			{ 
				$$ = new basetype($<t>1,0); 
				if ( $<t>1 == TYPEDEF ) in_typedef = $<pt>$;
				if (DECL_TYPE == -1) DECL_TYPE = 0;
			}
		|  LINKAGE		
			{	$$ = new basetype(EXTERN,0);
				$<pb>$->b_linkage = $<s>1;
				if (DECL_TYPE == -1) DECL_TYPE = 0;
			}
		|  qualified_tname
			{ 
				templp->check_tname($<pn>1);
				$$ = new basetype(TYPE,$<pn>1); 
				if (DECL_TYPE == -1) DECL_TYPE = 0;
			}
	/*XXX*/	|  tn_list DECL_MARKER
			{ // modified tn_list TNAME
				$$ = new basetype(TYPE,$<pn>2);
				//xxx qualifier currently ignored...
				if (DECL_TYPE == -1) DECL_TYPE = 0;
			}
		| qualified_tname lt temp_inst_parms gt
			{
				$<pb>$ = parametrized_basetype($<pn>1,(expr_unlist($<el>3)));
			}
		|  class_dcl 
		|  enum_dcl
		|  DECL_MARKER		
			{ 
				if (DECL_TYPE == TNAME)
					$$ = new basetype(TYPE,$<pn>1); 
		//	else if (DECL_TYPE == TSCOPE)
		//	$$ = 0;
				else
				if (DECL_TYPE == 0 &&
					$<p>1->base == TNAME)
						$$ = new basetype(TYPE,$<pn>1); 
				else
					$$ = new basetype($<t>1,0); 
				DECL_TYPE = -1;
			}
		;

type		:  tp
		|  type TYPE		
			{ 
				if ( DECL_TYPE != -1 ) {
					switch ($<pb>1->base) { Pbase bt;
					case COBJ: case EOBJ:
						bt = new basetype(0,0);
						*bt = *$<pb>1;
						DEL($<pb>1);
						$<pb>1 = bt;
					}
					$$ = $<pb>1->type_adj($<t>2); 
				}
				DECL_TYPE = 0;
			}
		|  type tname
			{
//error('d',"decl_type: %d  $1: %t  $2: %n",DECL_TYPE,$<pb>1,$<pn>2);
				if ( DECL_TYPE != -1 ) 
			 		$$ = $<pb>1->name_adj($<pn>2);
			/*XXX*/	else if($<pb>1==0) $$=new basetype(TYPE,$<pn>2);
				DECL_TYPE = 0;
			}
		|  type class_dcl	{ $$ = $<pb>1->base_adj($<pb>2); }
		|  type enum_dcl	{ $$ = $<pb>1->base_adj($<pb>2); }
		|  type DECL_MARKER		
			{ 
				if (DECL_TYPE == TYPE) {
					switch ($<pb>1->base) { Pbase bt;
					case COBJ: case EOBJ:
						bt = new basetype(0,0);
						*bt = *$<pb>1;
						DEL($<pb>1);
						$<pb>1 = bt;
					}
					$$ = $<pb>1->type_adj($<t>2);  
				}
			/*XXX*/	else if (DECL_TYPE == TSCOPE) {
			/*XXX*/		error('i',"type decl_marker(tscope)");
			/*XXX*/	//	$$ = $1;//ignore(?)
			/*XXX*/	}
				else
					$$ = $<pb>1->name_adj($<pn>2); 
				DECL_TYPE = -1;
			}
		;

temp_inst_parms : temp_inst_parms CM temp_inst_parm
                  {$<el>1->add(new expr(ELIST,$<pe>3,NULL)) ; }
                | temp_inst_parm { $<el>$ =
				     new elist(new expr(ELIST,$<pe>1,NULL)); } ;

temp_inst_parm  : new_type
                  {$<pn>1->n_template_arg = template_actual_arg_dummy ;
		   $<pe>$ = $<pn>1; /* keep yacc happy */ }
                | e %prec GT
                  { $<pe>$ = $<pe>1 ; } ; 

/***************** aggregate: returns Pname *****************/

enumtag	:  tag
		{ enumcheck:
			Ptype tx = $<pn>1->tp;
			$$ = $1;
			if ( tx->base == TYPE ) {
				$$ = Pbase(tx)->b_name;
				tx = $<pn>$->tp;
				if ( tx->base != EOBJ
				||   strcmp($<pn>$->string,$<pn>1->string)
				)
					error("%n of type%t redeclared as enum.",$<pn>1,tx);
			} else if ( tx->base != EOBJ )
				error("%n of type%t redeclared as enum",$<pn>1,tx);
		}
	|  DECL_MARKER { goto enumcheck; }
	;

enum_dcl	:  ENUM LC moe_list RC		{ $$ = end_enum(0,$<nl>3); }
		|  ENUM enumtag LC moe_list RC { $$ = end_enum($<pn>2,$<nl>4); }
		|  ENUM enumtag		{ $<pb>$ = (Pbase)$<pn>2->tp; }
		;

moe_list	:  moe
			{	if ($1) $<nl>$ = new nlist($<pn>1); }
		|  moe_list CM moe
			{	if( $3)
					if ($1)
						$<nl>1->add($<pn>3);
					else
						$<nl>$ = new nlist($<pn>3);
			}
		;

template_parm_list : template_parm_list CM template_parm
                   | template_parm
                   | { $<pn>$ = NULL ;} ;


stmt_or_expr    : STATEMENT | EXPRESSION ;

template_parm   : AGGR identifier
                  /* Build the name for the parameter
		  /* Check that AGGR is indeed CLASS */
                 { templp->collect($<t>1, $<pn>2) ; }
                 | stmt_or_expr identifier
                 { templp->collect($<t>1, $<pn>2) ; }	
                 |   type formal_decl
			{templp->collect(Ndata($1,$<pn>2)); } ;	


/* Sam: these productions are a variant of the ones for arg_decl,
 verify them against arg_decl for each release. */
formal_decl	:  ID
			{	$$ = $<pn>1; }
		|  ptr formal_decl		%prec MUL
			{	Ptyp($1) = $<pn>2->tp;
				$<pn>2->tp = (Ptype)$1;
				$$ = $2;
			}
		|  formal_decl vec		%prec LB
			{	Vtype($2) = $<pn>1->tp;
				$<pn>1->tp = (Ptype)$2;
			}
		|  formal_decl arg_list
			{	Freturns($2) = $<pn>1->tp;
				$<pn>1->tp = (Ptype)$2;
			} ;


moe		:  ID
			{	$$ = $<pn>1; $<pn>$->tp = moe_type; }
		|  ID ASSIGN e
			{	$$ = $<pn>1;
				$<pn>$->tp = moe_type;
				$<pn>$->n_initializer = $<pe>3;
			}
		|  /* empty: handle trailing CM: enum e { a,b, }; */
			{	$$ = 0; }
		;

class_dcl	:  class_head cl_mem_list RC
			{	parsing_class_members = 0;
				RESTORE_STATE();
				switch ( NEXTTOK() ) {
				case TYPE: case AGGR: case ENUM: case EOFTOK:
					error("`;' or declaratorX afterCD");
					la_backup(yychar,yylval);
					yychar = SM;
					break;
				}
				la_backup(yychar,yylval);
				yychar = -1;
				restore_text();
				++bl_level; // scope weirdness!
				++in_mem_fct;
			}
			inline_mem_defs
			{
				--in_mem_fct;
				--bl_level; // scope weirdness!
				if ( yychar == ID ) {
					// (yuk!) adjust lex level
					--yylval.pn->lex_level;
				}
				ccl->mem_list = name_unlist($<nl>2);
				if ( --in_class_decl )  // nested class
					// continue to parse enclosing class
					parsing_class_members = 1;
				ccl->nest_list = nested_type;
				if ( nested_tn ) nested_restore();
				nested_type = nested_type_vec[in_class_decl];
				nested_tn = nested_tn_vec[in_class_decl];
				end_cl();
				declTag = 1;
                        //POP_SCOPE();
			}
        	|  AGGR tag 
			{ aggrcheck:
				$<pb>$ = (Pbase)$<pn>2->tp; 
				if ( $$->base == TYPE ) {
					Pname nx = $<pb>$->b_name;
					$<pb>$ = (Pbase)nx->tp;
					if ( $$->base != COBJ
					||   strcmp(nx->string,$<pn>2->string)
					)
						error("%n of type%t redeclared as%k.",$<pn>2,$<pb>$,$<t>1);
				} else if ( $$->base != COBJ )
					error("%n of type%t redeclared as%k",$<pn>2,$<pb>$,$<t>1);
				check_tag();
			}
                | AGGR qualified_tname lt temp_inst_parms gt
                  { 
		    Pname p = parametrized_typename($<pn>2, (expr_unlist($<el>4))) ;
                    $<pb>$ = (Pbase)p->tp; 
                    check_tag(); 
		  }                   
        	|  AGGR DECL_MARKER 
			{
				goto aggrcheck;
			}
		;


inline_mem_defs	:  /* empty */
		|  inline_mem_defs inline_fct_def
		;

base_list	:  COLON base_unit_list		{ $$ = $2; }
		|  %prec EMPTY			{ $$ = 0; }
		;

base_unit_list	:  base_unit
		|  base_unit_list CM base_unit
			{	if ($3) { $$ = $3; $<pbc>$->next = $1; } }
		;

base_unit	:  ttag			{ $$ = dobase(0,$<pn>1); }
		|  PR ttag		{ $$ = dobase($<t>1,$<pn>2); }
		|  TYPE ttag		{ $$ = dobase(0,$<pn>2,$<t>1); }
		|  PR TYPE ttag		{ $$ = dobase($<t>1,$<pn>3,$<t>2); }
		|  TYPE PR ttag		{ $$ = dobase($<t>2,$<pn>3,$<t>1); }
		;

class_head	:  AGGR LC	
			{//PUSH_CLASS_SCOPE(0);
				parsing_class_members = 1;
				$$ = start_cl($<t>1,0,0); 
				nested_tn_vec[in_class_decl] = nested_tn;
				nested_type_vec[in_class_decl++] = nested_type;
				nested_tn = nested_type = 0;
				SAVE_STATE();
			}

		|  AGGR tag base_list LC
			{ //PUSH_CLASS_SCOPE($<pn>2->string);
				parsing_class_members = 1;
				$$ = start_cl($<t>1,$<pn>2,$<pbc>3);
				nested_tn_vec[in_class_decl] = nested_tn;
				nested_type_vec[in_class_decl++] = nested_type;
				nested_tn = nested_type = 0;
				SAVE_STATE();
			}
		;

tag		:  ID	{ $$ = $1; }
		|  qualified_tname { $$=$1; }
		;

ttag		:  ID	{ $$ = $1; }
		|  tname { $$=$1; }
		;

cl_mem_list	:  cl_mem_list cl_mem
			{
				if ($2) {
					if ($1)
						$<nl>1->add_list($<pn>2);
					else
						$<nl>$ = new nlist($<pn>2);
				}
			}
		|  %prec EMPTY { $$ = 0; }
		|  cl_mem_list TEMPLATE
			{
				error( "ZizedTD must be atG, notC scope" );
				error('i', "cannot recover from previous error" );
			}
		;

cl_mem		:  data_dcl
		|  att_fct_def SM
		|  fct_def SM
		|  fct_def
		|  att_fct_def
		|  fct_dcl
		|  PR COLON
			{	$$ = new name;
				$<pn>$->base = $<t>1;
			}
	/*XXX	|  tn_list TNAME SM
	 *		{	Pname n = Ncopy($<pn>2);
	 *			n->n_qualifier = $<pn>1;
	 *			n->base = PR;
	 *			$$ = n;
	 *		}
	 */	|  tn_list fname SM
			{	Pname n = Ncopy($<pn>2);
				if (n->n_oper == TYPE) {
					error('s',"visibilityD for conversion operator");
					// n->tp = Ptype(n->n_initializer);
					n->tp = Ptype(n->cond);
					n->cond = 0;
					// n->n_initializer = 0;
					n->n_oper = 0;
					sig_name(n);
				}
				n->n_qualifier = $<pn>1;
				n->base = PR;
				$$ = n;
			}
		;

/************* declarators:	returns Pname **********************/
/*	a ``decl'' is used for function and data declarations,
		and for member declarations
		(it has a name)
	an ``arg_decl'' is used for argument declarations
		(it may or may not have a name)
	an ``cast_decl'' is used for casts
		(it does not have a name)
	a ``new_decl'' is used for type specifiers for the NEW operator
		(it does not have a name, and PtoF and PtoV cannot be expressed)
*/

fname		:  ID
			{	$$ = $<pn>1; }
		|  COMPL TNAME  /* qualified_tname? */
			{	$$ = Ncopy($<pn>2);
				$<pn>$->n_oper = DTOR;
			}
		|  OPERATOR oper
			{	$$ = new name(oper_name($2));
				$<pn>$->n_oper = $<t>2;
			}
		|  OPERATOR c_type
			{	Pname n = $<pn>2;
				n->string = "_type";
				n->n_oper = TYPE;
				n->cond = Pexpr(n->tp);
				// n->n_initializer = Pexpr(n->tp);
				n->tp = 0;
				$$ = n;
			}
		;

oper		:  PLUS
		|  MINUS
		|  MUL
		|  AND
		|  OR
		|  ER
		|  SHIFTOP
		|  EQUOP
		|  DIVOP
		|  RELOP
		|  LT
		|  GT
		|  ANDAND
		|  OROR
		|  LP RP	{	$$ = CALL; }
		|  LB RB	{	$$ = DEREF; }
		|  NOT
		|  COMPL
		|  ICOP
		|  ASOP
		|  ASSIGN
		|  NEW		{	$$ = NEW; }
		|  DELETE	{	$$ = DELETE; }
		|  REF		{	$$ = REF; }
		|  CM		{	$$ = CM; }
		|  REFMUL	{	$$ = REFMUL;
					if ($<t>1 == DOT) error(".* cannot be overloaded");
				}
		;

tn_list		:  tscope
		/*XXX*/	{   if ( $<pn>1 != sta_name ) {
// error('d',"tn_list: tscope: pn1: %s", $<pn>1->string);
				Ptype t = $<pn>1->tp;
				while ( t->base == TYPE )
					t = Pbase(t)->b_name->tp;
				Pname n = Pbase(t)->b_name;
				if (NEXTTOK() == TNAME
				&& strcmp(n->string,yylval.pn->string)==0){
					// ctor -- change to ID to avoid
					//    parsing as type spec
					yychar = ID;
					yylval.pn = Ncopy(yylval.pn);
					yylval.pn->n_oper = TNAME;
				}
			    }
			    $<pn>$ = $<pn>1;
			}
/* YYY		|  tn_list tscope	{ $<pn>$ = $<pn>1; } */
 		|  tn_list tscope	{ error('s', "CNs do not nest, use typedef x::y y_in_x"); };
	/*XXX	|  tn_list ID DOT	{ error("CNs do not nest"); } */
		;

qualified_tname	: tn_list TNAME
			{	$<pn>$ = $<pn>2;
				//xxx qualifier currently ignored...
				// $<pn>$ = Ncopy( $<pn>2 );
				// $<pn>$->n_oper = TNAME;
				// $<pn>$->n_qualifier = $<pn>1;
			}
		| TNAME
			{	$<pn>$ = $<pn>1;
			//	$<pn>$ = Ncopy( $<pn>1 );
			//	$<pn>$->n_oper = TNAME;
			}
		;

fct_attributes	: /* empty */
			{ $$ = 0; }
		| fct_attributes TYPE
 			{ /* const/volatile function */
				switch ( $<t>2 ) {
				case VOLATILE:
					error('s',"volatile functions");
					break;
				case CONST:
					$$ = ($1 | 1);
					break;
				default:
					if ( NEXTTOK() != SM
					&&   yychar != COLON
					&&   yychar != LC ) {
						la_backup(yychar,yylval);
						yylval.t = $<t>2;
						la_backup(TYPE,yylval);
						yylval.t = SM;
						yychar = SM;
						error("syntax error: unexpected%k (did you forget a `;'?)",$<t>2);
					} else error("FD syntax: unexpected%k",$<t>2);
					break;
				}
 			}
		;

decl		:  decl arg_list
			{	Freturns($2) = $<pn>1->tp;
				$<pn>1->tp = $<pt>2;
			}
 		|  decl LP RP fct_attributes
 			{ /* function with no argument */
 				$<pn>1->tp = new fct($<pn>1->tp,0,1);
 				Pfct($<pn>1->tp)->f_const = ($<i>4 & 1);
 			}
		|  tname arg_list
			{	Pname n = $<pn>1;
				$$ = Ncopy(n);
                                //??? what if tname is qualified ???
				if (ccl && strcmp(n->string,ccl->string)) n->hide();
				$<pn>$->n_oper = TNAME;
				Freturns($2) = $<pn>$->tp;
				$<pn>$->tp = $<pt>2;
			}
		|  decl arg_lp elist RP
			/*	may be class object initializer,
				class object vector initializer,
				if not elist will be a CM or an ID
			*/
			{	
				$<pn>1->tp = new fct($<pn>1->tp,$<pn>3,1); 
 				in_arg_list = 0;
 				end_al($2,0);
				RESTORE_STATE();
                        //POP_SCOPE(); // similar to end_al()
			}
		|  tname LP MUL ID RP arg_list
			{
				Pptr p = new ptr( PTR, 0 );
				Ptyp(p) = new basetype(TYPE,$<pn>1);
				Freturns( $6 ) = Ptype(p);
				$<pn>4->tp = $<pt>6;
				$$ = $4;
				if (DECL_TYPE == -1) DECL_TYPE = 0;
			}
		|  tname LP elist RP
			{	$$ = Ncopy($<pn>1);
				$<pn>$->n_oper = TNAME;
				$<pn>$->tp = new fct(0,$<pn>3,1);
			} 
 		|  tname LP RP fct_attributes
 			{ /* function with no argument */
				$$ = Ncopy($<pn>1);
 				$<pn>$->n_oper = TNAME;
 				$<pn>$->tp = new fct(0,0,1);
 				Pfct($<pn>1->tp)->f_const = ($<i>4 & 1);
			}
		|  tname LP MEMPTR decl RP arg_list
			{	memptrdcl($<pn>3,$<pn>1,$<pt>6,$<pn>4);
				$$ = $4;
			}
		|  fname
		|  ID DOT fname
			{	$$ = Ncopy($<pn>3);
				$<pn>$->n_qualifier = $1;
				error(strict_opt?0:'w',"`.' used for qualification; please use `::' (anachronism)");
			}
		|  tn_list fname
			{	$$ = $2;
				if ( $<pn>1 != sta_name ) {
    					set_scope($<pn>1); 
    					$<pn>$->n_qualifier = $<pn>1;
				}
			}
	/*XXX*/	|  tn_list ID DOT fname
			{	$$ = Ncopy($<pn>4);
				$<pn>$->n_qualifier = $2;
				error(ansi_opt?0:'w',"anachronism `.' used for qualification; please use `::'");
				if ( $<pn>1 != sta_name ) {
    					set_scope($<pn>1); 
    					$<pn>2->n_qualifier = $<pn>1;
				}
			}
	/*XXX	|  tn_list TNAME
	 *		{
	 *			if ( $<pn>1 == sta_name ) 
     	 *				error( ":: applied to CN%n", $<pn>2 );
	 *			$$ = Ncopy($<pn>2);
	 *			set_scope($<pn>1);
	 *			$<pn>$->n_oper = TNAME;
	 *			$<pn>$->n_qualifier = $<pn>1;
	 *		}
	 */	|  ptr decl	%prec MUL
			{	Ptyp($1) = $<pn>2->tp;
				$<pn>2->tp = $<pt>1;
				$$ = $2;
			}
		|  ptr tname	%prec MUL
			{	$$ = Ncopy($<pn>2);
				$<pn>$->n_oper = TNAME;
				// cannot evaluate at this point: defer until data_dcl
				if ( in_typedef ) {
					defer_check = 1;
					in_tag = $<pn>2;
				}
				$<pn>2->hide();
				defer_check = 0;
				$<pn>$->tp = $<pt>1;
			}
		|  tname vec	%prec LB
			{	$$ = Ncopy($<pn>1);
				$<pn>$->n_oper = TNAME;
				if ( in_typedef ) {
					defer_check = 1;
					in_tag = $<pn>1;
				}
				$<pn>1->hide();
				defer_check = 0;
				$<pn>$->tp = $<pt>2;
			}
		|  decl vec	%prec LB	
			{	Vtype($2) = $<pn>1->tp;
				$<pn>1->tp = $<pt>2;
			}
/*
		|  LP decl RP arg_list
			{
				Freturns($4) = $<pn>2->tp;
				$<pn>2->tp = $<pt>4;
				$$ = $2;
			}
		|  LP decl RP vec
			{	Vtype($4) = $<pn>2->tp;
				$<pn>2->tp = $<pt>4;
				$$ = $2;
			}
*/
		|  arg_lp decl RP 
			{ 
				$$ = $2; 
				in_arg_list = 0;
				end_al($1,0);
				RESTORE_STATE();
                        //POP_SCOPE(); // similar to end_al()
			}
		;

arg_decl	:  ID
			{	$$ = $<pn>1; }
		|  ptr qualified_tname	%prec MUL
			{	$$ = Ncopy($<pn>2);
				$<pn>$->n_oper = TNAME;
				$<pn>2->hide();
				$<pn>$->tp = $<pt>1;
			}
		|  %prec NO_ID
			{	
				$$ = new name; 
				NOT_EXPECT_ID();
			}
		|  ptr arg_decl		%prec MUL
			{	Ptyp($1) = $<pn>2->tp;
				$<pn>2->tp = (Ptype)$1;
				$$ = $2;
			}
		|  arg_decl vec		%prec LB
			{	Vtype($2) = $<pn>1->tp;
				$<pn>1->tp = (Ptype)$2;
			}
		|  arg_decl arg_list
			{	Freturns($2) = $<pn>1->tp;
				$<pn>1->tp = (Ptype)$2;
			}
/*
		|  LP arg_decl RP arg_list
			{	Freturns($4) = $<pn>2->tp;
				$<pn>2->tp = (Ptype)$4;
				$$ = $2;
			}
		|  LP arg_decl RP vec
			{	Vtype($4) = $<pn>2->tp;
				$<pn>2->tp = (Ptype)$4;
				$$ = $2;
			}
*/
		|  arg_lp arg_decl RP	
			{ 
// error('d', "arg_lp arg_decl rp in_arg_list: %d", in_arg_list );
				$$ = $2; 
				in_arg_list = 0;
				end_al($1,0);
				RESTORE_STATE();
                        //POP_SCOPE(); // similar to end_al()
			}
		;

new_decl	:  %prec NO_ID
			{	$$ = new name; }
		|  ptr new_decl		%prec MUL
			{	Ptyp($1) = $<pn>2->tp;
				$<pn>2->tp = (Ptype)$1;
				$$ = $2;
                                NOT_EXPECT_ID();
			}
		|  new_decl vec		%prec LB
			{	Vtype($2) = $<pn>1->tp;
				$<pn>1->tp = (Ptype)$2;
			}
		;

cast_decl	:  %prec NO_ID { $$ = new name; }
		|  ptr cast_decl			%prec MUL
			{	Ptyp($1) = $<pn>2->tp;
				$<pn>2->tp = (Ptype)$1;
				$$ = $2;
				NOT_EXPECT_ID();
			}
		|  cast_decl vec			%prec LB
			{	Vtype($2) = $<pn>1->tp;
				$<pn>1->tp = (Ptype)$2;
			}
		|  LP cast_decl RP arg_list
			{	Freturns($4) = $<pn>2->tp;
				$<pn>2->tp = $<pt>4;
				$$ = $2;
			}
		|  LP cast_decl RP vec
			{	Vtype($4) = $<pn>2->tp;
				$<pn>2->tp = $<pt>4;
				$$ = $2;
			}
		;

c_decl		:  %prec NO_ID
			{	$$ = new name; }
		|  ptr c_decl				%prec MUL
			{	Ptyp($1) = $<pn>2->tp;
				$<pn>2->tp = (Ptype)$1;
				$$ = $2;
			}
		;



/***************** statements: returns Pstmt *****************/
stmt_list	:  /* empty */
			{
				$$ = 0; 
			}
		|  stmt_list TEMPLATE
			{
				error( "ZizedTD must be atG, not local scope" );
				error('i', "cannot recover from previous error" );
			}
         	|  stmt_list caselab_stmt
			{	
				if ($2)
					if ($1)
						$<sl>1->add($<ps>2);
					else {
						$<sl>$ =  new slist($<ps>2);
						stmt_seen = 1;
					}
			}
		;
caselab_stmt	:  caselablist statement
			{
				$$ = $2;
				if ($2)	stmt_seen = 1;
			}
		;

caselablist	: /* empty */
			{
				$$ = 0;
				check_decl();
			}
		;

condition	:  LP e RP
			{	$$ = $2;
			/*	if ($<pe>$ == dummy) error("empty condition");*/
				stmt_seen = 1;
			}
		;

block		:  LC
			{//PUSH_BLOCK_SCOPE	
				cd_vec[cdi] = cd;
				stmt_vec[cdi] = stmt_seen;
				tn_vec[cdi] = modified_tn;
				lcl_blk_vec[cdi++] = local_blk;
				lcl_tn_vec[cdi] = local_tn;
				local_blk = 0;
				local_tn = 0;
				cd = 0;
				stmt_seen = 0;
				modified_tn = 0;
			}
			stmt_list RC
			{	Pname n = name_unlist(cd);
				Pstmt ss = stmt_unlist($<sl>3);
				$$ = new block($<l>1,n,ss,$<l>4);
				if ( local_tn ) local_restore();
				if ( local_blk ) local_name();
				if (modified_tn) restore();
				cd = cd_vec[--cdi];
				stmt_seen = stmt_vec[cdi];
				modified_tn = tn_vec[cdi];
				local_tn = lcl_tn_vec[cdi];
				local_blk = lcl_blk_vec[cdi];
				if (cdi < 0) error('i',"block level(%d)",cdi);
				NOT_EXPECT_ID();
                        //POP_SCOPE(); // similar to end_al()
			}
		|  LC RC
			{	$$ = new block($<l>1,0,0,$<l>2); NOT_EXPECT_ID();}
		|  LC error RC
			{	$$ = new block($<l>1,0,0,$<l>3); NOT_EXPECT_ID();}
		;

simple		:  ee
			{	$$ = new estmt(SM,curloc,$<pe>1,0);	}
		|  BREAK
			{	$$ = new stmt(BREAK,$<l>1,0); }
		|  CONTINUE
			{	$$ = new stmt(CONTINUE,$<l>1,0); }
		|  GOTO ID
			{	$$ = new lstmt(GOTO,$<l>1,$<pn>2,0); }
		|  DO { stmt_seen=1; } caselab_stmt WHILE condition
			{	$$ = new estmt(DO,$<l>1,$<pe>5,$<ps>3); }
		|  ASM LP STRING RP
			{	
				if (stmt_seen)
					$$ = new estmt(ASM,curloc,(Pexpr)$<s>3,0);
				else {
					Pname n = new name(make_name('A'));
					n->tp = new basetype(ASM,(Pname)$<s>3);
					if (cd)
						cd->add_list(n);
					else
						cd = new nlist(n);
					$$ = 0;
				}
			}
		;

sm		: {
			if ( NEXTTOK() != SM ) {
				error("`;' missing afterS");
				la_backup(yychar,yylval);
				yychar = SM;
			}
		  } SM
		;

statement	:  simple sm
		|  SM
			{	$$ = new estmt(SM,$<l>1,dummy,0); }
		|  RETURN e SM
			{	$$ = new estmt(RETURN,$<l>1,$<pe>2,0); }
		|  TYPE STRING block
			{
				error("local linkage specification");
				$$ = $<pn>3;
			}
		|  data_dcl
			{	Pname n = $<pn>1;
				if (n) {
//error('d',"adding local dcl of%n%t ll %d in_typedef%t",n,n->tp,n->lex_level,in_typedef);
					if (stmt_seen) {
						$$ = new block(n->where,n,0);
						$<ps>$->base = DCL;
					}
					else {
						if (cd)
							cd->add_list(n);
						else
							cd = new nlist(n);
						$$ = 0;
					}
				} // if n
			}
		|  att_fct_def
			{
				Pname n = $<pn>1;
				error(&n->where,"%n's definition is nested (did you forget a ``}''?)",n);
				if (cd)
					cd->add_list(n);
				else
					cd = new nlist(n);
				$$ = 0;
			}
		|  block
		|  IF condition caselab_stmt
			{	$$ = new ifstmt($<l>1,$<pe>2,$<ps>3,0); }
		|  IF condition caselab_stmt ELSE caselab_stmt
			{	$$ = new ifstmt($<l>1,$<pe>2,$<ps>3,$<ps>5); }
		|  WHILE condition caselab_stmt
			{	$$ = new estmt(WHILE,$<l>1,$<pe>2,$<ps>3); }
		|  FOR LP { stmt_seen=1; } caselab_stmt e SM e RP caselab_stmt
			{	$$ = new forstmt($<l>1,$<ps>4,$<pe>5,$<pe>7,$<ps>9); }
		|  SWITCH condition caselab_stmt
			{	$$ = new estmt(SWITCH,$<l>1,$<pe>2,$<ps>3); }
		|  ID COLON { $$ = $1; stmt_seen=1; } caselab_stmt
			{	Pname n = $<pn>3;
				$$ = new lstmt(LABEL,n->where,n,$<ps>4);
			}
		|  TNAME COLON { $$ = new name($<pn>1->string); stmt_seen=1; } caselab_stmt
			{	Pname n = $<pn>3;
				$$ = new lstmt(LABEL,n->where,n,$<ps>4);
			}
		|  CASE { stmt_seen=1; } e COLON caselab_stmt
			{	if ($<pe>3 == dummy) error("empty case label");
				$$ = new estmt(CASE,$<l>1,$<pe>3,$<ps>5);
			}
		|  DEFAULT COLON { stmt_seen=1; } caselab_stmt
			{	$$ = new stmt(DEFAULT,$<l>1,$<ps>4); }
		;



/********************* expressions: returns Pexpr **************/
elist		: ex_list
			{	Pexpr e = expr_unlist($<el>1);
				while (e && e->e1==dummy) {
					register Pexpr ee2 = e->e2;
					if (ee2) error("EX inEL");
					delete e;
					e = ee2;
				}
				$$ = e;
			}
		;

ex_list		:  initializer		%prec CM
			{	$<el>$ = new elist(new expr(ELIST,$<pe>1,0)); }
		|  ex_list CM initializer
			{	$<el>1->add(new expr(ELIST,$<pe>3,0)); }
		;

initializer	:  e				%prec CM
		|  LC elist RC
			{
  			  	if ( in_arg_list ) 
       			  		error( "syntax error: IrL not permitted in AL" );
				else if ( in_binit_list )
					error( "syntax error: IrL not permitted inMIr" );
  			  	else 
					init_seen = 1;
				Pexpr e;
				if ($2)
					e = $<pe>2;
				else
					e = new expr(ELIST,dummy,0);
				$$ = new expr(ILIST,e,0);
			}
		;

ee		:  ee ASSIGN ee
			{	bbinop:	$$ = new expr($<t>2,$<pe>1,$<pe>3); }
		|  ee PLUS ee	{	goto bbinop; }
		|  ee MINUS ee	{	goto bbinop; }
		|  ee MUL ee	{	goto bbinop; }
		|  ee AND ee	{	goto bbinop; }
		|  ee OR ee	{	goto bbinop; }
		|  ee ER ee	{	goto bbinop; }
		|  ee SHIFTOP ee	{ 	goto bbinop; }
		|  ee EQUOP ee	{	goto bbinop; }
		|  ee DIVOP ee	{	goto bbinop; }
		|  ee RELOP ee	{	goto bbinop; }
		|  ee GT ee	{	goto bbinop; }
		|  ee LT ee	{	goto bbinop; }
		|  ee ANDAND ee	{	goto bbinop; }
		|  ee OROR ee	{	goto bbinop; }
		|  ee ASOP ee	{	goto bbinop; }
		|  ee CM ee	{	goto bbinop; }
		|  ee QUEST ee COLON ee
			{	$$ = new qexpr($<pe>1,$<pe>3,$<pe>5); }
		|  DELETE term 
			{ $$ = new expr(DELETE,$<pe>2,0); }
		|  DELETE LB e RB term
			{
				if($<pe>3 != dummy) {
					if ( warning_opt || strict_opt )
						error(strict_opt?0:'w',"v in `delete[v]' is redundant; use `delete[] instead (anachronism)");
				}
				$$ = new expr(DELETE,$<pe>5,$<pe>3);
			}
		|  MEM DELETE term 
			{	$$ = new expr(GDELETE,$<pe>3,0); }
		|  MEM DELETE LB e RB term
			{
				if($<pe>4 != dummy) { 
					if ( warning_opt || strict_opt )
						error(strict_opt?0:'w',"v in `::delete[v]' is redundant; use `::delete[] instead (anachronism)");
				}
				$$ = new expr(DELETE,$<pe>6,$<pe>4);
			}
		|  term
		; 

e		:  e ASSIGN e
			{	binop:	$$ = new expr($<t>2,$<pe>1,$<pe>3); }
		|  e PLUS e	{	goto binop; }
		|  e MINUS e	{	goto binop; }
		|  e MUL e	{	goto binop; }
		|  e AND e	{	goto binop; }
		|  e OR e	{	goto binop; }
		|  e ER e	{	goto binop; }
		|  e SHIFTOP e	{ 	goto binop; }
		|  e EQUOP e	{	goto binop; }
		|  e DIVOP e	{	goto binop; }
		|  e RELOP e	{	goto binop; }
		|  e LT e	{	goto binop; }
		|  e GT e	{	goto binop; }
		|  e ANDAND e	{	goto binop; }
		|  e OROR e	{	goto binop; }
		|  e ASOP e	{	goto binop; }
		|  e CM e	{	goto binop; }
		|  e QUEST e COLON e
			{	$$ = new qexpr($<pe>1,$<pe>3,$<pe>5); }
		|  DELETE term 
			{	$$ = new expr(DELETE,$<pe>2,0); }
		|  DELETE LB e RB term
			{
				if($<pe>3 != dummy) {
					if ( warning_opt || strict_opt )
						error(strict_opt?0:'w',"v in `delete[v]' is redundant; use `delete[] instead (anachronism)");
				}
				$$ = new expr(DELETE,$<pe>5,$<pe>3);
			}
		|  MEM DELETE term 
			{	$$ = new expr(GDELETE,$<pe>3,0); }
		|  MEM DELETE LB e RB term
			{
				if($<pe>4 != dummy) {
					if ( warning_opt || strict_opt )
						error(strict_opt?0:'w',"v in `::delete[v]' is redundant; use `::delete[] instead (anachronism)");
				}
				$$ = new expr(DELETE,$<pe>6,$<pe>4);
			}
		|  term { 
			init_seen = 0; 
			} 
		|  %prec NO_EXPR
			{	$$ = dummy; }
		; 

term		:  NEW cast_type	{ goto new1; }
		|  NEW new_type
			{	new1:
				Ptype t = $<pn>2->tp;
				$$ = new texpr(NEW,t,0);
			}
 		|  MEM NEW cast_type	{ goto new3; }
		|  MEM NEW new_type
 			{	new3:
				Ptype t = $<pn>3->tp;
 				$$ = new texpr(GNEW,t,0);
 			}
		|  term ICOP
			{	$$ = new expr($<t>2,$<pe>1,0); }
		|  cast_type term %prec ICOP
			{	$$ = new texpr(CAST,$<pn>1->tp,$<pe>2); }
		|  MUL term
			{	$$ = new expr(DEREF,$<pe>2,0); }
		|  AND term
			{	$$ = new expr(ADDROF,0,$<pe>2); }
		|  MINUS term
			{	$$ = new expr(UMINUS,0,$<pe>2); }
		|  PLUS term
			{	$$ = new expr(UPLUS,0,$<pe>2); }
		|  NOT term
			{	$$ = new expr(NOT,0,$<pe>2); }
		|  COMPL term
			{	$$ = new expr(COMPL,0,$<pe>2); }
		|  ICOP term
			{	$$ = new expr($<t>1,0,$<pe>2); }
		|  SIZEOF term
			{	
				$$ = new texpr(SIZEOF,0,$<pe>2); 
				in_sizeof = 0;
			}
		|  SIZEOF cast_type %prec SIZEOF
			{	
				$$ = new texpr(SIZEOF,$<pn>2->tp,0); 
				in_sizeof = 0;
			}
		|  term LB e RB
			{	$$ = new expr(DEREF,$<pe>1,$<pe>3); }
		|  term REF prim
			{	$$ = new ref(REF,$<pe>1,$<pn>3); }
		|  term REFMUL term
			{	$$ = new expr($<t>2,$<pe>1,$<pe>3); }
		|  term REF qualified_tname
			{	$$ = new ref(REF,$<pe>1,Ncopy($<pn>3)); }
		|  term DOT prim
			{	$$ = new ref(DOT,$<pe>1,$<pn>3); }
		|  term DOT qualified_tname
			{	$$ = new ref(DOT,$<pe>1,Ncopy($<pn>3)); }
		|  prim
		|  term_elist 
			{
			if ( init_seen )
     				error( "syntax error:IrL illegal within ()");
			}

		|  term_lp e RP
			{
				if ( $2 == dummy )
					error("syntax error: nullE");
				$$ = $2;
			}
		|  ZERO
			{	$$ = zero; }
		|  ICON
			{	$$ = new expr(ICON,0,0);
				$<pe>$->string = copy_if_need_be($<s>1);
			}
		|  FCON
			{	$$ = new expr(FCON,0,0);
				$<pe>$->string = copy_if_need_be($<s>1);
			}
		|  STRING
			{	$$ = new expr(STRING,0,0);
				$<pe>$->string = copy_if_need_be($<s>1);
			}
		|  CCON
			{	$$ = new expr(CCON,0,0);
				$<pe>$->string = copy_if_need_be($<s>1);
			}
		|  THIS
			{	$$ = new expr(THIS,0,0); }
		;

term_elist	: TYPE LP elist RP
			{ 	$$ = new texpr(VALUE,tok_to_type($<t>1),$<pe>3); }
/*
		|  qualified_tname LP elist RP
*/
		|  tname LP elist RP
			{	$$ = new texpr(VALUE,$<pn>1->tp,$<pe>3); }
                |  NEW term_lp elist RP cast_type    { goto new2; }
                |  NEW term_lp elist RP new_type     /* allow separate allocation */
			{	new2:
				Ptype t = $<pn>5->tp;
				$$=new texpr(NEW,t,0);
				$<pe>$->e2 = $<pe>3;
			}
		|  MEM NEW term_lp elist RP cast_type	{ goto new4; }
		|  MEM NEW term_lp elist RP new_type	/* allow separate allocation */
			{	new4:
				Ptype t = $<pn>6->tp;
				$$ = new texpr(GNEW,t,0);
				$<pe>$->e2 = $<pe>4;
			}
		|  term LP elist RP
			{	
				Pexpr ee = $<pe>3;
				Pexpr e = $<pe>1;
				if (e->base==NEW || e->base==GNEW)
					e->e1 = ee;
				else
					$$ = new call(e,ee);
			}

		;

ptname         : PTNAME lt temp_inst_parms  gt
                 {
		    $<pn>$ =parametrized_typename($<pn>1,(expr_unlist($<el>3))); 
	 	 }
               ;

tscope         :  TSCOPE
                       {       
				$<pn>$ = $<pn>1; 
				curr_scope = $<pn>1;
			}
               	|  MEM { $<pn>$ = sta_name; }
		|  ptname TSCOPE { $<pn>$ = $<pn>1; }
               ;


prim		:  ID
			{	$$ = $<pn>1; }
	/*XXX*/	|  tn_list ID
			{	$$ = Ncopy($<pn>2);
				$<pn>$->n_qualifier = $<pn>1;
			}
		|  OPERATOR oper
			{	$$ = new name(oper_name($2));
				$<pn>$->n_oper = $<t>2;
			}
		|  tn_list OPERATOR oper
			{	$$ = new name(oper_name($3));
				$<pn>$->n_oper = $<t>3;
				$<pn>$->n_qualifier = $<pn>1;
			}
		|  OPERATOR c_type
			{	$$ = $2;
				sig_name($<pn>$);
			}
		|  tn_list OPERATOR c_type
			{	$$ = $3;
				sig_name($<pn>$);
				$<pn>$->n_qualifier = $<pn>1;
			}
		|  tn_list COMPL tag	/* allow explicit call of destructor */
			{	
				if (strcmp($<pn>1->string,$<pn>3->string)) error("syntax error: inconsistent destructor notation");
				$$ = new name(oper_name(DTOR));
				$<pn>$->n_oper = DTOR;
				$<pn>$->n_qualifier = $<pn>1;
			}
		;



/****************** abstract types (return type Pname) *************/
cast_type	:  term_lp type cast_decl RP 
			{ $$ = Ncast($2,$<pn>3); }
		;

term_lp		:  LP { check_cast(); }
		;

c_tp		:  TYPE	
			{
				TOK t = $<t>1;

				switch (t) {
				case FRIEND:
				case OVERLOAD:
				case REGISTER:
				case STATIC:
				case EXTERN:
				case AUTO:
				case VIRTUAL:
					error("%k in operatorT",t);
					t = INT;
					
				}

				$$ = new basetype(t,0);

			}
		|  tname	{ $$ = new basetype(TYPE,$<pn>1); }
		|  c_tp TYPE		
			{ 
				if ( DECL_TYPE != -1 ) {
					switch ($<pb>1->base) { Pbase bt;
					case COBJ: case EOBJ:
						bt = new basetype(0,0);
						*bt = *$<pb>1;
						DEL($<pb>1);
						$<pb>1 = bt;
					}
					$$ = $<pb>1->type_adj($<t>2); 
				}
				DECL_TYPE = 0;
			}
		|  c_tp tname
			{ 
				if ( DECL_TYPE != -1 ) 
			 		$$ = $<pb>1->name_adj($<pn>2);
				DECL_TYPE = 0;
			}
		;

c_type		:  c_tp c_decl	{ $$ = Ncast($1,$<pn>2); }
		;

new_type	:  type new_decl	{ $$ = Ncast($1,$<pn>2); };

arg_type	:  type arg_decl
			{	
                         //      ENTER_NAME($<pn>2);
				$$ = Ndata($1,$<pn>2); 
			}
                |  type arg_decl ASSIGN
                        {
                        //      ENTER_NAME($<pn>2);
                        }
                   initializer
                        {       $$ = Ndata($1,$<pn>2);
                                $<pn>$->n_initializer = $<pe>5;
                        }
                ;

arg_lp		:  LP 
			{//PUSH_ARG_SCOPE 
				SAVE_STATE();
				check_decl(); 
				in_arg_list=1; 
				$$ = modified_tn;
				modified_tn = 0;
			}
		;

arg_list	:  arg_lp arg_type_list ellipsis_opt RP fct_attributes
		    {
			$$ = new fct(0,name_unlist($<nl>2),$<t>3); 
			if ( NEXTTOK() != COLON ) in_arg_list=0;
			//in_arg_list=0;
			Pfct($<pt>$)->f_const = ($<i>5 & 1);
			if ( parsing_class_members
			||   (NEXTTOK()!=LC && yychar!=COLON)) {
				end_al($1,1);
                        //POP_SCOPE(); // similar to end_al()
			} else
				end_al($1,0);
			RESTORE_STATE();
		    }
		;

arg_type_list	:  arg_type_list CM at
			{
				if ($3)
					if ($1)
						$<nl>1->add($<pn>3);
					else {
						error("AD syntax");
						$<nl>$ = new nlist($<pn>3); 
					}
				else
					error("AD syntax");
			}
		|  at	%prec CM
			{
				if ($1) $<nl>$ = new nlist($<pn>1); 
			}
		;

at		:  arg_type
		|  %prec EMPTY	{	$$ = 0; }
		;

ellipsis_opt	:  /* empty */
		    {	$$ = 1; }
		|  ELLIPSIS
		    {	$$ = ELLIPSIS; }
		|  CM ELLIPSIS
		    {	$$ = ELLIPSIS; }
		;

ptr		:  MUL %prec NO_ID
			{
			$$ = new ptr(PTR,0); 
			EXPECT_ID();
			}
		|  AND %prec NO_ID
			{
			$$ = new ptr(RPTR,0); 
			EXPECT_ID();
			}
		|  MUL TYPE %prec NO_ID
			{	$$ = doptr(PTR,$<t>2); }
		|  ptr TYPE %prec NO_ID
			{	
				switch ( $<t>2 ) {
				case CONST:
                                     $<pp>1->rdo = 1; break;
				case VOLATILE:
				     error('w',"\"volatile\" not implemented (ignored)");
				     break;
				default:
				    error( "syntax error: *%k", $<t>2 );
				}
				$$ = $<pp>1; 
			}
		|  AND TYPE %prec NO_ID
			{	$$ = doptr(RPTR,$<t>2); }
		|  ptname MEMPTR %prec NO_ID
			{	goto memptr1;  }
		|  MEMPTR %prec NO_ID
			{
			memptr1:
			$$ = new ptr(PTR,0);
			$<pp>$->memof = Pclass(Pbase($<pn>1->tp)->b_name->tp);
			EXPECT_ID();
			}
		|  ptname MEMPTR TYPE %prec NO_ID
			{	
				$<t>2 = $<t>3;
				goto memptr2;  
			}
		|  MEMPTR TYPE %prec NO_ID
			{	
				memptr2:
				$$ = doptr(PTR,$<t>2);
				$<pp>$->memof = Pclass(Pbase($<pn>1->tp)->b_name->tp);
			}
		;

vec		:  LB e RB		{ $$ = new vec(0,$<pe>2!=dummy?$<pe>2:0 ); }
		|  NOT %prec LB		{ $$ = new vec(0,0); }
		;

%%

static void
check_tag()
/*
        Allow the case of inline/virtual/overload as 
        modifiers of return type of form struct/class/union x foo() 
        SM, COLON, LC ==> real class declaration, not return type
*/
{
	switch ( NEXTTOK() ) {
	case SM: case COLON: case LC:
    		declTag = 1;
    		break;
	default:
    		declTag = 0;
    		break;
        }
}

static void
end_al( Plist mtn, int rst )
// unhide type names hidden by arg names
// mtn == saved modified_tn
{
	if ( rst == 0 ) {
		// not really an arg list, or we are entering a function def
		// merge modified_tn and don't restore
		if ( modified_tn == 0 ) modified_tn = mtn;
		else {
			for ( Plist l = modified_tn; l->l; l = l->l ) ;
			l->l = mtn;
		}
	} else {
		restore();
		modified_tn = mtn;
	}
}
static void
arg_redec( Pname fn )
{
	if ( fn==0 || fn->tp->base != FCT )
		error('i',"bad inline rewrite!");
	Pname al = Pfct(fn->tp)->argtype;
	Pname n = 0;
	for ( ;  al;  al = al->n_list ) {
		DB( if(Ydebug>=1)error('d',"arg_redec:  %n  %d",al,al->lex_level); );
		// nested function args should have lex_level >= 1
		if ( al->lex_level==1 && (n=ktbl->look(al->string,0)) )
			n->hide();
		else if ( al->lex_level>1 && (n=ktbl->look(al->string,LOCAL)) )
			n->hide();
		DB( if(Ydebug>=1)error('d',"   %n",n); );
	}
}


0707071010112046011004440001630000160000010211100466055415400000700000014643hash.c/* ident "@(#)ctrans:src/hash.c	1.2" */
/*
    $Header: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v 1.1.1.1 2018/04/24 17:21:35 root Exp $

    Copyright (c) 1989 by Object Design, Inc., Burlington, Mass.
    All rights reserved.

*/

#include <stdio.h>
#include "hash.h" 
#include <osfcn.h>

#define EMPTY   0
#define VALID   1
#define DELETED 2

void default_Hash_error_handler(const char* msg)
{
  fprintf(stderr, "Fatal Hash error: %s\n", msg) ;
  exit(1) ;
}

Error_Proc Hash_error_handler = default_Hash_error_handler ;

Error_Proc set_Hash_error_handler(Error_Proc f)
{
  Error_Proc old = Hash_error_handler ;
  Hash_error_handler = f ;
  return old ;
}

void Hash::error(const char* msg)
{
  (*Hash_error_handler)(msg) ;
}

Hash::Hash(int sz= DEFAULT_INITIAL_HASH_SIZE)
{
  tab = new HashTableEntry[size = sz] ;
  for (int i = 0; i < size; ++i) tab[i].status = EMPTY ;
  entry_count = 0 ;
}

Hash::Hash(Hash& a)
{
  tab = new HashTableEntry[size = a.size] ;

  key_hash_function = a.key_hash_function ;
  key_key_equality_function = a.key_key_equality_function ;

  for (int i = 0; i < size; ++i) tab[i].status = EMPTY ;
  entry_count = 0 ;
  for (HashWalker p(a); p; p.advance())
    (*this)[p.key()] = p.get() ;
}

Hash& Hash::operator = (Hash& a)
{
  if (a.tab != tab)
  {
    clear() ;
    delete [size] tab ;
    tab = new HashTableEntry[size = a.size] ;
    for (int i = 0; i < size; ++i) tab[i].status = EMPTY ;
    entry_count = 0 ;
    for (HashWalker p(a); p; p.advance())
      (*this)[p.key()] = p.get() ;
  }
  return *this ;
}

/* 
 * hashing method: double hash based on high bits of hash fct,
 * followed by linear probe. Can't do too much better if Assoc
 * sizes not constrained to be prime.
*/


static inline doublehashinc(unsigned int h, int s)
{
  return ((h / s) % s) >> 1 ;
}

// IWBNI we knew whether we were being called as an lvalue or rvalue.
// If the former, then we wouldn't have to scan through the whole
// table just to tell if we should rehash or not.  Sigh.
int& Hash::operator [](int key)
{
  unsigned int hashval = key_hash(key) ;
  while (1)
    {
      int bestspot = -1 ;
      int h = hashval % size ;
      for (int i = 0; i <= size; ++i)
	{
	  if (tab[h].status == EMPTY)
	    {
	      // resize if the hash table is more than 87.5% full
	      if (entry_count > ((size>>1)+(size>>2)+(size>>3)))
		// resize and insert again
		break ;
	      if (bestspot < 0) bestspot = h ;
	      tab[bestspot].key = key ;
	      tab[bestspot].status = VALID ;
	      ++entry_count ;
	      return tab[bestspot].cont ;
	    }
	  else if (tab[h].status == DELETED)
	    {
	      if (bestspot < 0) bestspot = h ;
	    }
	  else if (key_key_eq(tab[h].key, key))
	    return tab[h].cont ;
	  if (i == 0)
	    h = (h + doublehashinc(hashval, size)) % size ;
	  else if (++h >= size)
	    h -= size ;
	}
      resize(size << 1)  ;
    }
}

/* This seems convoluted, but it does whatever you want without
   redundant probing of the hash table. */

void Hash::action (int key, int val, insert_action what,
		   int& found, int& old_val)
{
  unsigned int hashval = key_hash(key) ;
  while (1)
    {
      int bestspot = -1 ;
      int h = hashval % size ;
      for (int i = 0; i <= size; ++i)
	{
	  if (tab[h].status == EMPTY)
	    {
	      // resize if the hash table is more than 87.5% full
	      if (entry_count > ((size>>1)+(size>>2)+(size>>3)))
		// resize and insert again
		break ;
	      if (bestspot < 0) bestspot = h ;
	      found = 0;
	      if(what != probe) {
		tab[bestspot].key = key ;
		tab[bestspot].status = VALID ;
		++entry_count ;
		tab[bestspot].cont = val;
	      } 
	      return;
	    }
	  else if (tab[h].status == DELETED)
	    {
	      if (bestspot < 0) bestspot = h ;
	    }
	  else if (key_key_eq(tab[h].key, key)) {
	    found = 1;
	    old_val = tab[h].cont;
	    if(what == replace) 
	      tab[h].cont = val;
	    return;
	  }
	  if (i == 0)
	    h = (h + doublehashinc(hashval, size)) % size ;
	  else if (++h >= size)
	    h -= size ;
	}
      resize(size << 1)  ;
    }
}

int Hash::contains(int key)
{
  unsigned int hashval = key_hash(key) ;
  int h = hashval % size ;
  for (int i = 0; i <= size; ++i)
  {
    if (tab[h].status == EMPTY)
      return 0 ;
    else if (tab[h].status == VALID && key_key_eq(tab[h].key, key))
      return 1 ;
    if (i == 0)
      h = (h + doublehashinc(hashval, size)) % size ;
    else if (++h >= size)
      h -= size ;
  }
  return 0 ;
}

int Hash::del(int key)
{
  unsigned int hashval = key_hash(key) ;
  int h = hashval % size ;
  for (int i = 0; i <= size; ++i)
  {
    if (tab[h].status == EMPTY)
      return 0 ;
    else if (tab[h].status == VALID && key_key_eq(tab[h].key, key))
    {
      tab[h].status = DELETED ;
      --entry_count ;
      return 1 ;
    }
    if (i == 0)
      h = (h + doublehashinc(hashval, size)) % size ;
    else if (++h >= size)
      h -= size ;
  }
  return 0 ;
}

void Hash::apply(intProc f)
{
  for (int i = 0; i < size; ++i)
    if (tab[i].status == VALID)
      (*f)(tab[i].cont) ;
}

void Hash::clear()
{
  for (int i = 0; i < size; ++i)
    tab[i].status = EMPTY ;
  entry_count = 0 ;
}

void Hash::resize(int newsize)
{
  if (newsize < entry_count)
    error("requested resize too small") ;
  HashTableEntry* oldtab = tab ;
  int oldsize = size ;
  tab = new HashTableEntry[size = newsize] ;
  for (int i = 0; i < size; ++i) 
    tab[i].status = EMPTY ;
  entry_count = 0 ;
  for (i = 0; i < oldsize; ++i)
    if (oldtab[i].status == VALID)
      (*this)[oldtab[i].key] = oldtab[i].cont ;
  delete [oldsize] oldtab ;
}

void HashWalker::reset()
{
  for (pos = 0; pos < h->size; ++pos)
    if (h->tab[pos].status == VALID)
      return ;
  pos = -1 ;
}

void HashWalker::advance()
{
  if (pos < 0)
    return ;
  for (pos++; pos < h->size; ++pos)
    if (h->tab[pos].status == VALID)
      return ;
  pos = -1 ;
}

/*
unsigned int foo(int bar) {return bar;}
int baz(int a, int b) {return a == b;}

main()
{
  Hash vh(10)  ;
  HashWalker vt(vh)  ;
  int i  ;

  vh.key_hash_function = &foo  ;
  vh.key_key_equality_function = baz  ;
  printf("Capacity=%d \n", vh.capacity()) ;
  for (i=0; i<500; i+= 5)
    {
      vh[i] = i * i  ;
    }
  vt.reset() ;
  while (vt.valid())
    {
      printf("key=%d, data=%d\t", vt.key(), vt.get());
      vt.advance()  ;
    }
  for (i=0; i<500; i+= 10)
    {
      vh.del (i) ;
      printf("After delete: %d\n", vh[i]);
    }
  printf("\n-----------------\n") ;
  vt.reset() ;
  while (vt.valid())
    {
      printf("key=%d, data=%d\t", vt.key(), vt.get());
      vt.advance()  ;
    }
}

*/
0707071010112046061004440001630000160000010212400466055420200000700000011465hash.h/* ident "@(#)ctrans:src/hash.h	1.2" */
/* Compiler interface to hash tables from odi library. 
	$Source: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v $ $RCSfile: cfront.cpio,v $
	$Revision: 1.1.1.1 $		$Date: 2018/04/24 17:21:35 $
	$Author: root $		$Locker:  $
	$State: Exp $

    $Header: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v 1.1.1.1 2018/04/24 17:21:35 root Exp $

    Copyright (c) 1989 by Object Design, Inc., Burlington, Mass.
    All rights reserved.

*/

#ifndef _HASH_H
#define _HASH_H

#include <string.h>

typedef void (*Error_Proc) (const char*) ;

extern void default_Hash_error_handler (const char*) ;
extern Error_Proc Hash_error_handler ;
extern Error_Proc set_Hash_error_handler (Error_Proc f) ;

#ifndef _hash_typedefs
#define _hash_typedefs 1
typedef void (*intProc)(int) ;
#endif

#define DEFAULT_INITIAL_HASH_SIZE 100

struct HashTableEntry
{
  int                   key ;
  int                   cont ;
  char                  status ;
} ;

class HashWalker ;

class Hash
{
  friend class          HashWalker ;

  HashTableEntry*       tab ;
  int                   size ;
  int                   entry_count ;

public:
  unsigned int		(*key_hash_function)(int)  ;
   int            	(*key_key_equality_function) (int, int) ;

  unsigned int          key_hash(int  a) ;
  int                   key_key_eq(int a, int  b);    

                        Hash(int sz) ;
                        Hash(Hash& a) ;
                        ~Hash() ;

  Hash&                 operator= (Hash& a) ;

  int                   count() ;
  int                   empty() ;
  int                   full() ;
  int                   capacity() ;

  void                  clear() ;
  void                  resize(int newsize) ;

  enum insert_action	{ probe, insert, replace };
  void			action (int key, int val, insert_action what,
				int& found, int& old_val);
  int&                  operator [] (int  k) ;
  int                   contains(int  key) ;
  int                   del(int  key) ;

  void                  apply (intProc f) ;
  void                  error(const char* msg) ;
} ;

class HashWalker
{
  Hash*     h ;
  int                   pos ;

public:
                        HashWalker(Hash& l) ;
                        ~HashWalker() ;

  int                   null() ;
  int                   valid() ;
                        operator void* () ;
  int                   operator ! () ;
  void                  advance() ;
  void                  reset() ;
  void                  reset(Hash& l) ;
  const int&            key() ;
  int&                  get() ;
} ;

inline unsigned int Hash::key_hash(int a)
{
#ifdef HASHFUNCTION
  return HASHFUNCTION(a) ;
#else
  return (*key_hash_function)(a) ;
#endif
}

inline int Hash::key_key_eq(int a, int b)
{
#ifdef EQUALITYFUNCTION
  return EQUALITYFUNCTION(a, b) ;
#else
  return (*key_key_equality_function)(a, b) ;
#endif
}


inline Hash::~Hash()
{
  delete [size] tab ;
}

inline int Hash::count()
{
  return entry_count ;
}

inline int Hash::empty()
{
  return entry_count == 0 ;
}

inline int Hash::full()
{
  return entry_count == size ;
}

inline int Hash::capacity()
{
  return size ;
}
inline HashWalker::HashWalker(Hash& a)
{
  h = &a ;
  reset() ;
}

inline void HashWalker::reset(Hash& a)
{
  h = &a ;
  reset() ;
}


inline HashWalker::~HashWalker() {}

inline int HashWalker::null()
{
  return pos < 0 ;
}

inline int HashWalker::valid()
{
  return pos >= 0 ;
}

inline HashWalker::operator void* ()
{
  return (pos < 0)? 0 : this ;
}

inline int HashWalker::operator ! ()
{
  return (pos < 0) ;
}


inline const int& HashWalker::key()
{
  if (pos < 0)
    h->error("operation on null Walker") ;
  return h->tab[pos].key ;
}

inline int& HashWalker::get()
{
  if (pos < 0)
    h->error("operation on null Walker") ;
  return h->tab[pos].cont ;
}

inline int pointer_hasheq (int a, int b)
{
    return a == b;
};

inline unsigned int pointer_hash_fcn (int x)
{
    unsigned X = (unsigned) x;
    return ((X << 16) | (X >> 16)) ^ x;
}

class pointer_hash : public Hash {
  public:
    pointer_hash (int sz = 0) : Hash (sz) {
	key_hash_function = pointer_hash_fcn;
	key_key_equality_function = pointer_hasheq;
    }

    pointer_hash (pointer_hash& h) : Hash (h) {};
};

inline int string_hasheq (int a, int b)
{
    return !strcmp((char *)a, (char *) b);
};

static unsigned int string_hash_fcn (int x)
{
    char * str = (char *)x;
    int l = strlen(str);
	
    if(x <= 4) return str[0];
    else {
	unsigned int * f4 = (unsigned int *) str;
	if (l < 8) return ((*f4 << 16) | (*f4 >> 16)) ^ *f4;
	else {
	    unsigned int * s4 = f4 ++;
	    return ((*f4 << 16) | (*f4 >> 16)) ^ *s4;
	}
    }
};


class string_hash : public Hash {
    public:

    string_hash (int sz = 0) : Hash (sz) {
	key_hash_function = string_hash_fcn;
	key_key_equality_function = string_hasheq;
    };

    string_hash (string_hash& h) : Hash (h) {};
};

#endif
0707071010112046071004440001630000160000010210470466055420500001500000001056ios_printf.h/* ident "@(#)ctrans:src/ios_printf.h	1.2" */
/* Begin iostream_printf.H -- printf functions that work on ostreams.
   someday, perhaps, scanf functions for istreams. */

#include <stdarg.h>
#include <iostream.h>

int vostream_printf(const char *format, va_list argp, ostream& fp);
int ostream_printf(ostream& stream, const char * format ...);

// returns count of characters added.
int printf_to_string (char * string, int length, const char * format ...);

// returns string which came from malloc.
char * printf_to_alloc_string (const char * format ...);
0707071010112044331004440001630000160000010202700466055403600001000000134002lalex.c/*ident	"@(#)ctrans:src/lalex.c	1.15" */
/**************************************************************************

	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.

lalex.c:

	lookahead 

*****************************************************************************/
#include <stdio.h>

#ifdef c_plusplus
overload is_empty;
#endif

#include "cfront.h"
#include "yystype.h"
#include "tqueue.h"
#include "template.h"

#ifdef DBG
#define LDB(val,a) { if(Ldebug>=val) {a;} }
#else
#define LDB(val,a) /**/
#endif

#ifdef DBG
static char*
image( int t )
{
	if(keys[t]) return keys[t];
	else { static char b[20];
		sprintf(b,"token(%d)",t);
		return b;
	}
}
static void
printok( toknode* t )
{
	switch(t->tok) {
	default:
		fprintf(stderr,"\t%s",image(t->tok));
		break;
	case ID: case ICON: case CCON: case FCON: case STRING:
		fprintf(stderr,"ID '%s'",t->retval.s);
		break;
	case TNAME:
		fprintf(stderr,"TNAME '%s'",t->retval.pn->string);
		break;
	case PTNAME:
		fprintf(stderr,"PTNAME '%s'",t->retval.pn->string);
		break;
	case TSCOPE:
		fprintf(stderr,"TSCOPE '%s'::",t->retval.pn->string);
		break;
	case MEMPTR:
		fprintf(stderr,"MEMPTR '%s'::*",t->retval.pn->string);
		break;
	}
	putc(' ',stderr);
	t->place.put(stderr);
	putc('\n',stderr);
}
static void
showQ( char* where )
/*
	display token Q
*/
{
	fprintf(stderr,"TOKEN Q (%s):\n",where);
	for (register toknode* t = front; t; t = t->next) printok(t);
	putc('\n',stderr);
}
#endif

int bl_level;

static int  laexpr( TOK );
static int  latype( TOK );
static int  la_decl();
static TOK  lookahead();

/* make this a toknode! */
static int lasttk = 0;		// one token history
static YYSTYPE lastval; 	// yylval lasttk value 

int must_be_expr = 0;		// handle redundant parentheses
int must_be_id = 0;		// !0, TNAME => ID, i.e., int X

loc curloc;
int curr_file;

toknode* latok;			// current lookahead token
toknode* front = 0;
toknode* rear  = 0;

const  TQCHUNK = 16;

void*
toknode::operator new(size_t)
{
	register toknode* p;

	if ((p=free_toks) == 0) {
		register toknode* q;
		free_toks = q = (toknode*)malloc( TQCHUNK * sizeof(toknode) );
		p = free_toks;
		for (; q != &p[TQCHUNK-1]; q->next = q+1, ++q);
		q->next = 0;
	}
	free_toks = p->next;
	return p;
}

toknode::toknode(TOK t, YYSTYPE r, loc tloc)
{
	tok = t;
	used = 0;
	retval = r;
	place = tloc;
	next = last = 0;
}

void
toknode::operator delete(void* vp,size_t)
{
	register toknode* p = (toknode*)vp;
	p->next = free_toks;
	free_toks = p;
	vp = 0;
}

#define USE_TOKEN(T,W) \
	LDB(2,error('d',&(T)->place,"use_token('%k','%s')",(T)->tok,W);); \
	if ( !(T)->used ) use_token(T);

Ptype
return_nstd_local_type( Pname n, TOK &sw )
{ 
    	Ptype tt;
	switch ( n->tp->base ) {
		case EOBJ:
		case COBJ:
			tt = Pbase(n->tp)->b_name->tp;
			sw = n->tp->base;
			break;
		default:
			tt = n->tpdef;
			sw = NESTED; // in repr.c, prints ``typedef''
			break;
	}
	return tt;
}

static Pname
local_nested_kludge( Pname n, Pname tn )
/*
 * for backward compatibility with 2.0
 * in transitional model of nested class types
 * 
 * struct T { ... };
 * foobar() {
 *	class X {
 *		typedef int T;
 *		// ...
 *	};
 *	T t;
 * }
 *
 * pure nested classes, choose global struct T{};
 * no nested classes, choose typedef int T
 * transitional model: choose typedef, and generate warning
 * BUG: local typedefs and enums do not have lex_level set
 */
{
// error( 'd', "local_nested_kludge: n: %n", n );
	for ( Pname nn = n; nn; nn = nn->n_tbl_list )
	{
		Pname local_class;
		TOK ntd;
		if ( nn->n_key != NESTED ) continue;
		Ptype tt = return_nstd_local_type(nn,ntd);
		Pclass cl = tt->in_class;
		while ( cl->in_class ) cl = cl->in_class;
		if (cl->lex_level && 
			(local_class = ktbl->look(cl->string,LOCAL)))
		{
			// same typedef at nested and non-nested scope
			if (ntd == NESTED && tn && tn->tp == nn->tp )
				; 
			else
				error('w',"%s occurs at outer and nested localC scope; using %k %t::%s", n->string,ntd,cl,n->string);

/*
			if ( ntd == NESTED && nn->n_dcl_printed != 2 ) {
				nn->dcl_print(0);
				nn->n_dcl_printed = 2;
			}
*/
			return nn;
		}
	}
	return 0;
}

enum { one_back, two_back };
	
static void
use_token( toknode* T )
/*
	lookup TNAMEs here instead of in tlex()
	maintain block level
*/
{
	static TOK last_tokens[2];  // TSCOPE not reduced at this point
	static Pname last_tname;    // tname :: id, where id is nested class
	static Pname tdef_name;     // typedef tname tdef_name
	T->used = 1;

	DB(if(Ldebug>=1) {
		error('d',&T->place,"\n*** use_token(%k )",T->tok);
		printok(T);
		error('D',&T->place,"    lasttk%k last_tname%n last tokens%k%k",lasttk,last_tname,last_tokens[one_back],last_tokens[two_back]);
	});

	switch ( T->tok ) {
	case ID:
		Pname n;
// error('d', &T->place, "use_token: %s", T->retval.s );
		if ( last_tokens[one_back] == MEM &&
			last_tokens[two_back] == TNAME &&
			(n=ktbl->look(T->retval.s,NESTED))) 
		{ // TYPEDEF :: ID, nested class ctor 
			if (tdef_name && tdef_name->n_key==NESTED &&
				strcmp(tdef_name->string,n->string)==0)
			{
				T->tok = TNAME;
				T->retval.pn = n;
				break;
			}	
			else { // TNAME :: ID, where ID may be nested class
			for ( Pname nn = n; nn; nn = nn->n_tbl_list )
			{
				TOK sw;
				if ( nn->n_key != NESTED ) continue;
				Ptype tt = return_nstd_local_type(nn,sw);
				Pclass cl = tt->in_class;
				if (strcmp(last_tname->string,cl->string)==0)
				{
					T->tok = TNAME;
					T->retval.pn = nn;
					break;
				}	
			}
			}
		}
		else
		if ( bl_level && 
			// TNAME:: and :: cannot refer to ``local'' TNAME
			last_tokens[one_back] != MEM  && 
			(n=ktbl->look(T->retval.s,LOCAL)) ) 
		{
			DB( if(Ldebug>=1)error( 'd', &T->place, "use_token: local class instance: %n", n ) );
			T->tok = TNAME;
			T->retval.pn = n;
		} 
		else if ( n=ktbl->look(T->retval.s,0) ) {
			DB( if(Ldebug>=1)error( 'd', &T->place, "use_token:GC instance: %n", n ) );
// error( 'd', &T->place, "use_token:GC instance: %n %t", n, n->tp );

			// X:: ?, then n cannot be a global TNAME
			// 	except in the case of a constructor
			if (last_tokens[one_back] == MEM &&
				last_tokens[two_back] == TNAME &&
			 	strcmp(T->retval.s,last_tname->string))
					; // do nothing; i.e., return ID
			else 
			if ( bl_level && n->tp->base != COBJ &&
				last_tokens[one_back] == MEM &&
				last_tokens[two_back] != TNAME &&
				gtbl->look(T->retval.s,0))
					; // do nothing: local typedefs & enums not implemented
			else {
				Pname nn = 0;
				TOK ntd;
				if (bl_level && (nn=ktbl->look(T->retval.s,NESTED)))
				{
					(void) return_nstd_local_type(n,ntd);
					nn = local_nested_kludge(nn,ntd==NESTED?n:0);
				}
				T->tok = TNAME;
				T->retval.pn = nn?nn:n;
			}
		}
#ifdef DBG
		else if(Ldebug>=1)
			error('d',&T->place,"use_token: id %s",T->retval.s);
#endif
		break;
	case LC: ++bl_level; break;
	case RC: --bl_level; break;
	}
	
	if (T->tok != COMPL || last_tokens[one_back] != MEM) {
		last_tokens[two_back] = last_tokens[one_back];
 		last_tokens[one_back] = T->tok;	
		if (T->tok == TNAME) last_tname = T->retval.pn;
		if ( last_tname && 
			last_tname->tp->base == TYPE )
		{
			tdef_name = last_tname;
			do
				tdef_name = Pbase(tdef_name->tp)->b_name;
			while ( tdef_name->tp->base == TYPE );
		}
	}
}

void
addtok(TOK t, YYSTYPE r, loc tloc)
{
	toknode* T = new toknode(t,r,tloc);
	if (front == 0)
		front = rear = T;
	else {
		rear->next = T;
		T->last = rear;
		rear = T;
	}
//error('d',&tloc,"addtok: %k '%s'",t,t==ID?r.s:"");
//showQ("addtok");
}

extern TOK
deltok( int noset = 0 )
{
	register toknode* T = front;
	USE_TOKEN(T,"deltok");
	register TOK tk = T->tok;
	if ( !noset ) { yylval = T->retval; curloc = T->place; }
	curr_file = curloc.file;
	if (front = front->next)
		front->last = 0;
	else
		latok = rear = 0;
	delete T;
	return tk;
}

static void
add_tokens()
/*
    extend lookahead token queue when depleted
*/
{
    TOK tk = tlex();
    if ( tk != ID )
	return;

    while (tk == ID || tk == MEM || tk == DOT )  
	tk = tlex(); 
}

extern TOK
la_look()
/*
	peek at head of token queue
*/
{
    LDB(1,fprintf(stderr,"\n*** la_look()"));
    if ( front == 0 )
	add_tokens();

    latok = front;
    USE_TOKEN(latok,"la_look");
    LDB(1,fprintf(stderr," -- %s\n",image(latok->tok)));
    return latok->tok;
}

#define NEXTTOK() ( (yychar==-1) ? (yychar=lalex(),yychar) : yychar )
void
check_decl()
/*
	Lookahead to direct parsing of local/arg type declarations
	la_decl() returns 1 if lookahead sees a declaration.
*/
{
	TOK tk2;
	switch( NEXTTOK() ) {
	default:
	break;
	case TSCOPE: //XXX
		tk2 = la_look();
		while ( tk2 == TSCOPE ) tk2 = lookahead();
		if ( tk2 == TNAME ) {
		    toknode* t = latok;
		    if(t->tok!=TNAME)
                   	error('i',&t->place,"check_decl() token scan");
		    tk2 = lookahead();
		    if ( tk2 == LP && la_decl() ) {
			t->tok = DECL_MARKER; //TNAME
		    }
		}
		break;
	case TYPE: case TNAME:
	    if ( la_look() == LP && la_decl() ) {
		must_be_id = 0;
		DECL_TYPE=yychar;
		yychar = DECL_MARKER;
	    }
	}
}

void
check_cast()
/*
	Lookahead to direct parsing of cast
	la_cast() returns 1 if lookahead sees an ambiguous old-style C cast.
*/
{
	TOK tk2;
	switch( NEXTTOK() ) {
	case TSCOPE: //XXX
		tk2 = la_look();
		while ( tk2 == TSCOPE ) tk2 = lookahead();
		if ( tk2 == TNAME ) {
		    toknode* t = latok;
		    if(t->tok!=TNAME)
                         error('i',&t->place,"check_cast() token scan");
		    tk2 = lookahead();
		    if ( tk2 == LP && la_decl() ) {
			t->tok = DECL_MARKER;//TNAME
		    }
		}
		break;
	case TYPE: case TNAME:
	    if ( la_look() == LP && la_cast() ) {
		must_be_id = 0;
		DECL_TYPE = yychar;
		yychar = DECL_MARKER;
	    }
	}
}


static int
latype( TOK t )
{
	switch ( t ) {
	default: // includes friend, typedef, storage classes, etc.
		return 0;
	case CHAR: case SHORT: case INT: case LONG:
	case FLOAT: case DOUBLE:
        case UNSIGNED:
		return 1;
	}
}

static int
laexpr( TOK t )
{
	switch ( t ) {
	default: 
		return 0;
	case RETURN: case NEW: case AND: case ANDAND: case OR: case OROR:
	case SIZEOF: case NOT: case COMPL: case MUL: case PLUS: case MINUS: 
	case ER: case ASSIGN: case ASOP: case RELOP: case EQUOP: case DIVOP: 
	case SHIFTOP: case ICOP:
		return 1;
	}
}

static toknode *get_next_token(toknode *t) {
  if (! t->next)
    add_tokens() ;
  
  return t->next ;
}


static int template_tscope(Pname tn, toknode *lt) 
/* provide the looakhead for determining TSCOPE tokens when the name is a
 * parametrized type name; the lookahead here is non-trivial, because it
 * involves stepping over the template arguments. 
 */
{
  int nest = 0 ; // the LT has been fetched

  if (lt->tok != LT) error ('i', "a `<' token was expected") ;  

  // assume the worst, ensure that name strings are consed in the heap
  templp->parameters_in_progress++ ;
  
  for (toknode *t = lt;; t = get_next_token(t))    
    switch (t->tok) {
      
    case LT:
      	++nest;
      	continue;
    case GT:
	// ***************
	// need to fold in awareness of x::y::z
      	if (--nest == 0) {
		t = get_next_token(t);
		if (t->tok == MEM) {
	  	// determine whether it is a memptr
	  		if (t->next == 0) add_tokens();
	  		if (t->next->tok == MUL) {
	    			t->tok = MEMPTR;
	    			t->next = t->next->next ;
	  	} else  t->tok = TSCOPE ;
		t->retval.pn  = tn ;
	  	--templp->parameters_in_progress;
	  	return 1;
	} 
	else  return 0 ;
      }
      continue;

    case SM: case LC: case RC: // a quick exit in case of error
    case EOFTOK:
      	--templp->parameters_in_progress;
      	return 0 ;
      
    default:
      	continue;
    }
}

static TOK
lookahead()
/*
    advance lookahead pointer, lexing at end of Q
    handle occurrences of TNAME and TSCOPE
    (should be kept up to date with lalex())
*/
{
    TOK tk;
    TOK tk2;
    TOK prev_tk = 0;
    YYSTYPE lastval;

    if ( latok == rear ) {
	add_tokens();
	if ( latok )
	    latok = latok->next;
	else
	    latok = front;
    }
    else
	latok = latok->next;

    if ( latok->last ) {
	prev_tk = latok->last->tok;
	lastval = latok->last->retval;
    }

nexttok:
    USE_TOKEN(latok,"lookahead1");
    tk = latok->tok;
    if ( tk == ID || tk == TNAME ) 
    {
	if (latok->next == 0) add_tokens();
	USE_TOKEN(latok->next,"lookahead2");
	/* TOK */ tk2 = latok->next->tok;
	if ( tk == TNAME ) {
	   if (tk2 == LT) {
	      // a parametrized type name -- differentiate from TNAME 
	      // so that it can be dealt with in the grammar. 
	      if (template_tscope(latok->retval.pn, latok->next)) tk = PTNAME;
	   }
           else  
	   if ( tk2 == MEM || tk2 == DOT ) {
tscope:	
		tk = TSCOPE;
// error('d',"lookahead: tk: %k tk2: %k", tk, tk2 );
// XXX -- should be modified to loop and do lookup
		latok = latok->next;
		if (latok->next == 0) add_tokens();
		USE_TOKEN(latok->next,"lookahead3");
		tk2 = latok->next->tok;
		if ( tk2 == MUL ) {
			tk = MEMPTR;
			latok = latok->next;
		}
	    }
	    else if (( prev_tk == MUL && tk2 != RP )
			|| prev_tk == AND )
		{
		tk = ID;
		latok->retval.pn->hide();
		latok->tok = ID;
		latok->retval.s = latok->retval.pn->string;
		}
	}
	else if ( tk2 == MEM ) {
	    	// ID ::
	//XXX	latok = latok->next->next;
	//XXX	goto nexttok;
		goto tscope; // treat as tscope
	}

	if ( tk == ID &&
   		( tk2 == ID ||
		( prev_tk == ID && ( tk2 == COLON || tk2 == LC )))) {
	    		// ID ID
	    		latok = latok->next;
	    		goto nexttok;
			}
    }

	if ( tk == ID ) {
		Pname nstd = ktbl->look(latok->retval.s,NESTED);
		if (nstd && (must_be_id == 0 ||
			must_be_id && prev_tk == LP)) {
extern Pname check_for_nested(Pname,TOK,YYSTYPE,TOK); // use this in lalex, too
				Pname n = check_for_nested(nstd,prev_tk,lastval,tk2);
				if ( n ) {
					tk = latok->tok = TNAME;
					latok->retval.pn = n;
				}
		}
	}

    return tk;
}

static Pname mem_sel = 0;

static Pname
do_local_class( Pname n, int lex_level ) 
{ /*
   * modify to ``do_local_type:
   *   do local types: enums and typedefs
   */
	Pname nn = n;
	if ( n->tp ) { // already a TNAME
    		Pclass cl = n->tp->base==COBJ ? Pclass(Pbase(n->tp)->b_name->tp) : 0;
    		if ( n->lex_level != lex_level || (cl && cl->lcl) ) {
			local_hide( n );
			nn = new name( n->string );
			nn->lex_level = lex_level>=0?lex_level:0;
		}
    		else 
		if ( lex_level == n->lex_level && cl->defined ) {
			error( "localC %n redefined", n );
			return n;
		}
	}

	nn = nn->tname( lastval.t );
	modified_tn = modified_tn->l;
	nn->n_key = LOCAL;
	local_class = new name_list( nn, local_class );
	local_blk = new name_list( nn, local_blk );

// error('d', "do_local_class: nn %n tp %t", nn, Pclass(Pbase(nn->tp)->b_name->tp));
	return nn;
}

static char*
make_nested_name( char *s, Pclass cl )
{ // Q<cnt>_<class_names><space><null>
	const nested_depth = 9;
    	char *str_arr[nested_depth];
    	int  size_arr[nested_depth];
    	int cnt = 2;
    	int size = 4; // Q,<cnt>,<_>,<null>

	str_arr[0] = s; str_arr[1] = cl->string; 

	size += size_arr[0] = strlen(s); 
	size += size_arr[1] = cl->strlen?cl->strlen:strlen(cl->string);

	for (Pclass nc = cl->in_class; nc; nc = nc->in_class ) {
		if (cnt > nested_depth-1) error('s',"nested depth class beyond %d unsupported",nested_depth);
		size += size_arr[cnt] = nc->strlen?nc->strlen:strlen(nc->string);
		str_arr[cnt++] = nc->string; 
	}

	for ( int i=0; i<cnt; i++ ) // <nnn><string>
		size += size_arr[i]>99?3:size_arr[i]<10?1:2;

//error('d', "make_nested_name( %s, %t ) cnt: %d size: %d", s, cl, cnt, size );
	char *result = new char[size];
	sprintf(result, "Q%d_", cnt );
	size = 3;
	for ( i=cnt; i; i-- ) {
		sprintf(result+size,"%d%s", size_arr[i-1], str_arr[i-1]);
		size += size_arr[i-1] + (size_arr[i-1]>99?3:size_arr[i-1]<10?1:2);
	}

//error('d', "size: %d ", size );
	result[size] = '\0';
//error('d', "make_nested_name result: %s", result );
    	return result;
}

int is_empty( Pclass cl, bit const_chk )
{ /* 	for nested class check, empty means *no* members
   *    for const object check, means no *data* members
   */

// error('d',"%t->is_empty: max: %d real_size: %d", cl, cl->memtbl->max(),cl->real_size );

	int mbr_cnt = cl->memtbl->max();
	if ( mbr_cnt == 0 ) return 1;

	if ( cl->baselist == 0 && cl->real_size!=1 )
		return 0;

	// empty class to turn on transitional nested class scope
	if ( const_chk == 0 && 
		( cl->baselist != 0 || mbr_cnt > 1 )) return 0;

	int i = 1;
    	for (Pname nn=cl->memtbl->get_mem(i); nn; nn=cl->memtbl->get_mem(++i)) {
    	  	if (nn->base==NAME && 
			nn->n_union==0 && 
			nn->tp->base!=FCT && 
			nn->tp->base!=OVERLOAD && 
			nn->tp->base!=CLASS && 
			nn->tp->base!=ENUM && 
			nn->tp->base!=EOBJ && 
			nn->n_stclass != STATIC) 
			{
				if ( nn->string[0]=='_' &&
					nn->string[1]=='_' &&
					nn->string[2]=='W' )
						return 1;
				else return 0;
			}
	}

	return 1; // if here, no data members encountered
}

static int
is_empty( Penum en )
{ // is this an empty enum ??

// error('d', "%t no_of_enumerators: %d", en, en->no_of_enumerators);
	if ( en->no_of_enumerators != 0 )
		return 0;

	return 1;
}

static Pname
check_nested_type( Pname nm )
{
// error('d', "check nested type: %n ccl: %t", nm, ccl );

	Pname nx, n = ktbl->look(nm->string, NESTED);
	if ( n == 0 || n == nm ) return nm;

	int cnt = 1;
	for (nx = n; n; n=n->n_tbl_list ) 
		if (n->n_key == NESTED) ++cnt;

	if ( cnt > 1 ) {
		error( "ambiguous nested type %s (%d instances), use x::y syntax", nm->string, cnt );
		error( 'i', "cannot recover from previous errors" );
	}
	else { 
		TOK ntk;
		Ptype tt = return_nstd_local_type(nx,ntk);
		error('w', "use %t:: to access nested %k %s (anachronism)", tt->in_class, ntk, nx->string);
	}
	return nx;
}

static int
in_local_class( Pclass cl )
{
	if ( cl->lex_level )
		return 1;
	if ( cl->in_class )
		return in_local_class( cl->in_class );
	return 0;
}

Pname
do_nested_type( Pname n ) 
{
	Pname nn = n;
	char *str = 0;

// error('d', "do_nested_type: %s in_typedef: %d ccl: %t", n->string, in_typedef, ccl );
	if ( in_typedef && ccl->string[0]=='_'
	&&  ccl->string[1]=='_'
	&&  ccl->string[2]=='C') return n;

	if ( n->tp ) 
        { // already a TNAME :
	  // hide existing instance, encode new instance
	  /*
	   * need handle the anomaly:
	   * class x;
	   * x *p;
	   * class y {
	   *	class x{ ... }; // oops
	   * };
	   */
		if (n->tp->base==COBJ) {
			Pclass cl = Pclass(Pbase(n->tp)->b_name->tp);
			if (cl->defined == 0 && lasttk == AGGR) {
				error('w',"forwardD ofC%n resolved to nested%t::%s",n,ccl,n->string);
				cl->lcl = new char[9];
				strcpy(cl->lcl,"FUDGE007"); // license to hack
				n->lex_level=Pbase(n->tp)->b_name->lex_level=0;
				return n;
			}
		} 
		else if (n->tp->base==EOBJ) { // watch out for enum x;
			Penum en = Penum(Pbase(n->tp)->b_name->tp);
			if (en->defined == 0 && lasttk == ENUM) return n;
		}

		nested_hide( n );
		nn = new name( n->string );
		str = make_nested_name( n->string, ccl );
	}
	else
	// make sure we haven't already seen a nested instance
	// if so, for transition, this needs to be an error
	if (ktbl->look( n->string, NESTED ))
		error("multiple type %s nestings (to do this define an empty class/enum %s {};)",n->string,n->string); 
	if ( in_typedef ) {
		if (strcmp(ccl->string, nn->string)==0) { // class x { typedef T x;
			error( "nested Tdef %s redefines immediately enclosing class", nn->string );
			error( 'i', "cannot recover from previous errors" );
		}

		// make sure there isn't an identifier at global scope being defined
		// by a nested typedef -- previously an error; keep it so for transition
		Pname tn;
		if ( n->tp == 0 && in_local_class(ccl)==0 &&
                     (tn=gtbl->look(n->string,0))) {
			error( "nested Tdef %s redefinesG %n", n->string, tn );
			error( 'i', "cannot recover from previous errors" );
		}

		nn->tpdef = new type;
		nn->tpdef->nested_sig = str;
		nn->tpdef->in_class = ccl;
		nn->tpdef->lex_level = NESTED;
		PERM(nn->tpdef);
	}
	else {
		nn = nn->tname( lastval.t );
		Pname tn = Pbase(nn->tp)->b_name;
		Ptype tt = tn->tp;
    		if ( tt->defined && tt->in_class == ccl) {
			error( "nested %t redefines immediately enclosing class", nn->string );
			error( 'i', "cannot recover from previous errors" );
		}
		tt->nested_sig = str;
		modified_tn = modified_tn->l;
		nn->lex_level = tn->lex_level = 0;
		nested_type = new name_list( nn, nested_type );
	}
	nn->n_key = NESTED;
	return nn;
}

static Pname dtor_seen;
static int in_expr;
extern int in_sizeof;

extern TOK
lalex()
/*  return next token to grammar  */
{
    register TOK tk;
    if ( front == 0 )
	add_tokens();		// extend lookahead queue
    LDB(1,fprintf(stderr,"\n*** lalex()\n");showQ("before"));

gettok:
    tk = deltok();
// error('d',&curloc,"lalex: just got %k '%s' in_typedef: %d",tk,tk==ID?yylval.s:tk==TNAME?yylval.pn->string:"", in_typedef);

    if ( tk == ID || tk == TNAME ) 
    {
	TOK tk2 = la_look();
	int lex_level = bl_level - in_class_decl - (tk2 == LC );

	if ( tk == TNAME )
	{
//error('d', "lalex tname %n;   lasttk: %k tk2: %k", yylval.pn, lasttk, tk2);
//error('d', "    must_be_id: %d must_be_expr %d  decl_type %d",must_be_id,must_be_expr,DECL_TYPE);
//error('d', "    bl_level: %d parsing_members %d",bl_level,parsing_class_members);
	    if ( tk2 == LP 
		&& (bl_level == 0 || parsing_class_members) 
		&& ( laexpr(lasttk) == 0 ) 
		&& must_be_expr == 0
		&& DECL_TYPE == 0 ) {
			if (la_decl()) {
				must_be_id = 0;
				DECL_TYPE = tk;
				tk = DECL_MARKER;
				goto ret;
			}
	    }

	    // note: *** can handle local typedefs here, too!
	    if ( in_typedef && 
			in_typedef->base != 0 && 
			ccl && in_mem_fct == 0 &&
			(tk2 == SM || tk2 == RP || tk2 == LB))
				yylval.pn = do_nested_type(yylval.pn);
 	
	    if ( lasttk == AGGR || lasttk == ENUM ) {
		if ( tk2 == LC || tk2 == COLON ) { // class definition	
			if ( lex_level 
				&& (in_class_decl==0 || in_mem_fct)
				&& lasttk != ENUM )  // temporary
					yylval.pn = do_local_class( yylval.pn, lex_level );
			else 
			if ( in_class_decl && ccl )
				yylval.pn = do_nested_type( yylval.pn );
		}
	    } 

	   if (tk2 == LT) {
	      // a parametrized type name
	      if (template_tscope(yylval.pn,latok)) 
			tk = PTNAME ;
	   } else  
	   if ( tk2 == MEM || (tk2 == DOT && mem_sel == 0 )) {  
		if (tk2==DOT)
			error(strict_opt?0:'w',"``.'' used for qualification; please use ``::'' (anachronism)");
crunch:
		tk = TSCOPE;
		{//XXX -- should be modified to do lookup and del at each ::
		  while ( (tk2 = lookahead()) == TSCOPE ) ;
		  if ( tk2 == TNAME ) {
			tk2 = lookahead();
			if ( tk2 == LP 
			&& (bl_level == 0 || parsing_class_members) 
			&& ( laexpr(lasttk) == 0 ) 
			&& must_be_expr == 0
			&& DECL_TYPE == 0 ) {
				if (la_decl()) {
					must_be_id = 0;
					//DECL_TYPE = tk;//???
					DECL_TYPE = TNAME;
					//front should be ::
					front->tok = TSCOPE;
					front->retval.pn = yylval.pn;
					yylval.pn = 0;
					tk = DECL_MARKER;
					goto ret;
				}
			}
		  }
		}
		tk2 = deltok(1);
		tk2 = la_look();
		if ( tk2 == MUL ) {
			tk = MEMPTR;
			tk2 = deltok(1);
		}
	    }
	    // Have a TNAME.  Check to be sure.
	    else if ( must_be_id ){
//error('d',"lalex: must_be_id: <tname %n> <%k>",yylval.pn,tk2);
		if ( in_class_decl 
			&& lasttk == TYPE 
			&& tk2 == LP
			&& strcmp(yylval.pn->string,ccl->string) == 0 )
			error("%nK with returnT", yylval.pn);

		else if ( lasttk == TYPE && lastval.t == OVERLOAD
			  && ( tk2 == SM || tk2 == LP ) )
		        { 
			tk = ID;
			yylval.pn->hide();
			yylval.pn = new name( yylval.pn->string );
			yylval.pn->n_oper = TNAME;
			}
		else if ( lasttk == OPERATOR ||
			in_typedef && yylval.pn->n_key == NESTED)
				must_be_id = 0;
		else if ( lasttk != TSCOPE // watch out for X::X
		     || lastval.pn != yylval.pn 
		     || (in_typedef && 
				in_typedef->check( yylval.pn->tp,0) == 0 )) 
		{
			tk = ID;
			if ( in_typedef && (lasttk == MUL || lasttk == REF)) {
     				defer_check = 1;
     				in_tag = yylval.pn;
			}

			if ( lasttk == MEM && yylval.pn->lex_level ) {
				Pname nn = gtbl->look( yylval.pn->string, 0 );
				if (nn == 0 )
    					error( "%k%s undeclared", lasttk, yylval.pn->string);
				else
    					yylval.pn = nn;
			}
			else {
// error('d',"lalex: else: lasttk: %k", lasttk );
				if (lasttk!=DOT && lasttk!=REF
				&&  lasttk!=TSCOPE && lasttk != GOTO ) {
				    // handle typedefs in basetype::check
				    //    when type is available
				    if (!in_typedef) {
// error('d',"\"%s\" line %d: hiding%n",__FILE__,__LINE__,yylval.pn);
					yylval.pn->hide();
				    }
				    yylval.pn = new name(yylval.pn->string);
				    yylval.pn->n_oper = TNAME;
				}
			}
			if ( defer_check ) defer_check = 0;
		}
	    } // must_be_id

	    if ( in_class_decl &&
		ccl->lex_level &&
		yylval.pn->lex_level != 0 && 
		yylval.pn->tp && 
		(yylval.pn->tp->base != COBJ && yylval.pn->tp->base != EOBJ)) 
	    {
		Pname n = gtbl->look( yylval.pn->string,0);
		if ( in_mem_fct ) {
		     if (n && n->base == TNAME ) {
			error('w', "local typedef %n(%t) is not in scope of local class %s members; usingG (%t)", yylval.pn, yylval.pn->tp, ccl->string, n->tp );
			yylval.pn = n;
		    } else
                	error( "local typedef %sis not in scope of inline member function of local class %s", yylval.pn->string, ccl->string);
		}
	    }

	    // if we still have a TNAME, make sure have the right TNAME
	    // possibility of ananchronistic reference to nested type
	    Ptype nbt = yylval.pn->tp;
	    if (tk == TNAME && curr_scope == 0 && nbt && // Y y; not X::Y y;
		(nbt->base == EOBJ || nbt->base == COBJ))
	    {
		Ptype t = Pbase(nbt)->b_name->tp;
		if ( ccl && t->in_class &&
			strcmp(t->in_class->string, ccl->string)) 
		{
			switch( nbt->base ) {
				case COBJ:
					if (is_empty(Pclass(t)))
						yylval.pn = check_nested_type( yylval.pn );
					break;
				case EOBJ:
					if (is_empty(Penum(t)))
						yylval.pn = check_nested_type( yylval.pn );
					break;
			};
		}
	    }
        }
	else 
        { // tk == ID 
    		char *s = yylval.s;
		Pname n = ktbl->look( s, HIDDEN );
		Pname nstd = ktbl->look( s, NESTED );

		// inside a class definition, ccl, that is nested 
		// s is a nested class name, and is the name of ccl
		if (ccl && ccl->in_class && nstd && 
			strcmp(s, ccl->string)==0)
		{
			for (Pname nn=nstd; nn; nn=nn->n_tbl_list) {
				Ptype tt = (nn->tp->base==COBJ || nn->tp->base==EOBJ)
						? Pbase(nn->tp)->b_name->tp : nn->tpdef;
				Pclass cl = tt->in_class; 
				if ( nn->n_key != NESTED ) continue;
				if (strcmp(ccl->in_class->string,cl->string) == 0) {
					tk = TNAME;
					yylval.pn = nn;
					n = nstd = nn;
					}
			}
		}

		if (tk2 == MEM) {
	            // ID ::
		    if (n) {
			yylval.pn = n;
		/*XXX*/	goto crunch;
		    } 
		    else
		    if (nstd &&
			nstd->n_tbl_list==0)
		    {
			yylval.pn = nstd;
			tk = TSCOPE;
			tk2 = deltok(1);
			tk2 = la_look();
			if (tk2 == MUL ) {
				tk = MEMPTR;
				tk2 = deltok(1);
			}
		    }
		    else {
			error( "%s:: %sis not aTN", s, s ); 
		    	tk2 = deltok(1);
	    	    	goto gettok;
		    }
		} 
		else  // transitional kludge
		if ( n && nstd && n == nstd )  
			; // null statement

		// Have an ID. Check last token to be sure.
		else if (lasttk==ENUM || lasttk==AGGR &&
                           	// template <class id, class id>
                           	(tk2 != GT && tk2 != CM)) 
			{
			int fd = tk2!=LC && tk2!=COLON;
			tk = TNAME;
			if ( nstd ) { 
				// in transitional model, need flag this as error
				if ( fd == 0 ) { // real definition
					if ( ccl == 0 )
						error("nested andG%k %s(to do this placeG%k %s {}; first)",lasttk==ENUM?lasttk:CLASS, s, lasttk==ENUM?lasttk:CLASS, s); 
					else
						error("multiple nested%k %s(to do this placeG%k %s {}; first)",lasttk==ENUM?lasttk:CLASS, s, lasttk==ENUM?lasttk:CLASS,s); 
					error( 'i', "cannot recover from previous errors" );
				}
			}
			else 
			// new tag, define it
			if (n==0 || 
				(n->n_template_arg == template_type_formal))
			{
// error('d', "ccl: %t fd: %d, in_mem_fct: %d, in_class_decl: %d", ccl, fd, in_mem_fct, in_class_decl);
				n = new name( s );
				if ( fd )  // struct X*, etc.
					n->lex_level=0; 
				else
					n->lex_level=lex_level>=0?lex_level:0;

				if ( ccl && fd == 0 && 
					in_class_decl && 
			(bl_level == ccl->lex_level + in_class_decl + 1))
						n = do_nested_type( n );
				else
				// note: ***** modify to handle local typedef
				// note: ***** add local enums
				if ( n->lex_level &&
					lasttk != ENUM ) // temporary
						n = do_local_class( n, n->lex_level );
				else {
					n = n->tname( lastval.t );
					modified_tn = modified_tn->l;
					if (fd && gtbl->look(n->string,0)) statStat = n;
				}
			}
			else {
				if (n->tp->base!=COBJ && n->tp->base!=EOBJ) {
					error( 'i', "hidden%n:%t",n,n->tp );
					goto gettok;
				}

				if ( tk2 == LC || tk2 == COLON ) { 
					// class declared and hidden but not yet defined
					// may have ctor defined which invalidates hiding
					statStat = n;
					n->n_key = 0; // inside class definition it cannot be hidden
				}
			}
			yylval.pn = nstd?nstd:n; 
		}
		else {
	    		tk = ID;
			yylval.pn = new name( s );
		}

		if ( tk == ID ) 
		{
		    switch ( tk2 ) {
		    case ID: case TNAME: case AGGR: case ENUM:
		    {
			Pname n = 0; 

			if ((curr_scope||ccl) && nstd) {
			// within class scope in which nested class is visible
			// curr_scope == set by TSCOPE, X::foo() { ... }
			// ccl == parsing class definition ``ccl''

				char *str = curr_scope?curr_scope->string:ccl->string;
				for (Pname nn=nstd; nn; nn=nn->n_tbl_list) {
					Ptype tt = (nn->tp->base==COBJ || nn->tp->base==EOBJ)
							? Pbase(nn->tp)->b_name->tp : nn->tpdef;
					Pclass cl = tt->in_class; 
					if ( nn->n_key != NESTED ) continue;
					if ( strcmp(str,cl->string) == 0){	
						tk = TNAME;
						yylval.pn = nn;
						if (lasttk == TYPE && 
							lastval.t == TYPEDEF )
								in_typedef = yylval.pn->tp;
						break;
					}
				}
			}
			if (tk == TNAME) break; // found nested class

			n = ktbl->look( s, HIDDEN ); 
			if ( n ) {
				Pname nn = n;
				switch ( n->tp->base ) {
					default:
						error("typedef %sis not visible in this scope", s );
						break;
					case COBJ:
						if (is_empty(Pclass(Pbase(n->tp)->b_name->tp)))
 							n = check_nested_type( nn );
						if (nn == n)
							error("%sis hidden: use struct %s%s", s,s,front->retval.s);
						break;
					case EOBJ:
						if (is_empty(Penum(Pbase(n->tp)->b_name->tp)))
 							n = check_nested_type( nn );
						if (nn == n)
							error("%sis hidden: use enum %s%s", s,s,front->retval.s);
						break;
				};
				tk = TNAME;
				yylval.pn = n;
			}
			else  
			if (n=ktbl->look(s,NESTED)) 
			{
				TOK ntk;
				bit ok = 0;
				Ptype tt = return_nstd_local_type(n,ntk);
				Pclass cl = tt->in_class; 
				if (ccl) {
					// x::y unncessary with in_class,
					// a derived class of in_class
					// or classes enclosing in_class
					if (ccl==cl || ccl->has_base(cl))
						ok++;
					else {
					for (Pclass eccl=ccl->in_class;eccl; eccl=eccl->in_class)
						if ( eccl == cl ) { ok++; break; }
					}
				}
				if (!ok)
					error('w', "use %t:: to access nested %k %s (anachronism)", cl, ntk, n->string );
				tk = TNAME;
				yylval.pn = n;
			}
			else { // probably a typo
			    if ( tk2 == ID )
  				error("%s%s: %sis not aTN", s,front->retval.s,s);
			    else if ( tk2 == TNAME )
  				error("%s%s: %sis not aTN", s,front->retval.pn->string,s);
			    else 
  				error("%s%k: %sis not aTN", s,front->retval.t,s);
			    goto gettok;
			}
    			 break;
		    }
		    case DOT: case REF:
    			 mem_sel = yylval.pn;
    			 break;
		    default:
			if ( lasttk == TNAME && tk2 == LC )  
			{
	    			error("T%s %k: %s is unexpected", s, tk2, s );
	    			goto gettok;
			}
			
			// have an ID.  lets just make sure it should not be a TNAME
			if (curr_scope||ccl||nstd) {
				if (ccl && in_typedef && 
					in_typedef->base != 0 &&  
					in_mem_fct == 0 &&
					(tk2 == SM || tk2 == RP || tk2 == LB)) 
					{
						yylval.pn = do_nested_type( yylval.pn );
						tk = TNAME;
					}
				else
				if (nstd && must_be_id == 0 && in_expr == 0) {
// error('d',"nstd: %n must_be_id 0 have id tk2: %k lasttk: %k",nstd,tk2,lasttk);
// error('d',"nstd: in_expr %d lex_level %d",in_expr,lex_level);
					Pclass xcl = curr_scope?Pclass(Pbase(curr_scope->tp)->b_name->tp):(ccl?ccl:0);
					for (Pname nn=nstd; nn; nn=nn->n_tbl_list) {
						TOK ntk;
						bit ok = 0;
						Ptype tt = return_nstd_local_type(nn,ntk);
						Pclass cl = tt->in_class; 
// error('d',"xcl: %t ccl: %t", xcl, ccl );
						if ( xcl ) {
							if (xcl==cl || xcl->has_base(cl) || ccl == cl)
								ok++;
							else {
							for (Pclass eccl=xcl->in_class;eccl;eccl=eccl->in_class)
								if ( eccl == cl ) { ok++; break; }
							}
						}
							
						if (nn == nstd)
						{
						if (
						    // special case: foo(X,
						    // in_arg_list not set until **after** X is handled
						    ((in_arg_list || lasttk==LP) &&  // foo(nestedX
							(tk2==CM || tk2==ASSIGN || 
								(tk2==RP && lasttk!=MUL && lasttk!=REF))) 
			     			    || // class x : public nestedX
			    				(tk2==LC && (lasttk==PR || lasttk==VIRTUAL))
						    || // nestedX [*&]
							(tk2 == MUL || tk2==AND)
						    || (lasttk==LP && tk2==RP)
						    || (lasttk==TSCOPE && lastval.pn == nn) 
						    || (lasttk==COMPL && dtor_seen == nn) 
						    || (lasttk==TYPE && lastval.t == TYPEDEF)
                                                    || lasttk == OPERATOR
						    || lasttk == NEW || in_sizeof )
						{  // must be type name, and it must be nested: 
    							if ( nstd->n_tbl_list == 0 ) { // only one: ok
								if (lasttk != TSCOPE && !ok )
									error('w', "use %t:: to access nested %k %s (anachronism)", cl, ntk, nn->string);
								break;
    							}
    							else {
								if (lasttk != TSCOPE && lasttk != TYPE && !ok){
									error("ambiguous nested type %s, use %t::%s",nn->string,xcl,nn->string);
									error( 'i', "cannot recover from previous errors" );
								}
							}
						}

					    }
						if ( nn->n_key != NESTED ) continue;
						if (xcl && 
							strcmp(xcl->string,cl->string) == 0) break;
					} // end: for nn = nstd

					if (nn) {
						tk = TNAME;
						yylval.pn = nn;
						if (lasttk == TYPE && 
							lastval.t == TYPEDEF )
								in_typedef = yylval.pn->tp;
					}
				}  // end: if (nstd)
			} // end: if (curr_scope||ccl)
    			 break;
		    } // end: switch tk2
    		} // end: if (tk == ID)
	    }

// error('d',"testing for in_expr: in_expr: %d tk: %k", in_expr, tk );
// error('d',"testing for in_expr: tk2: %k lasttk: %k", tk2, lasttk );
	    if (lex_level && tk==ID && tk2==LP &&
			(lasttk==LC || lasttk==RC || lasttk==RP ||
			lasttk == ASSIGN || lasttk == SM))
				in_expr = 1;
	    else in_expr = 0;
	
	}
        if ( tk == TNAME || ( tk == TYPE && latype(yylval.t) )
// XXX     || tk == TSCOPE || tk == MEM 
	   || tk == REF || tk == DOT || tk == GOTO 
	   || tk == MEMPTR )
	   // TNAME cannot immediately follow a type name,
	   // scope operator, right curly, selection, or goto
		must_be_id = 1;
    	else
		must_be_id = 0;

        switch ( tk ) {
	    case SM:
		mem_sel = 0; // no break
		in_expr = 0;
	    case RP: case RC: must_be_expr = 0; break;
	    case COLON: 
		if  (lasttk == RP || 
		    (lasttk == TYPE && lastval.t == CONST)) 
 		        must_be_expr = 1;
		break;
	    case SIZEOF:
		in_sizeof = 1;
		break;
	};
ret:
    if ( tk == COMPL && lasttk == TSCOPE )
	 dtor_seen = lastval.pn;
    else dtor_seen = 0;
    lasttk = tk;
    lastval = yylval;
    LDB(1,showQ("after");
	fprintf(stderr,"returning '%s'",image(tk));
	if ( tk==ID || tk==TNAME ) fprintf(stderr," -- '%s'",yylval.pn->string);
	fprintf(stderr,"\n");
    );
// error('d',"returning tk: %k dtor_seen: %n", tk,dtor_seen );
    return tk;
}

extern void
la_backup( TOK t, YYSTYPE r )
/*
    called by parser to push token back on front of queue
*/
{
    LDB(1,fprintf(stderr,"\n*** la_backup( '%s', ...)\n",image(t)));
    if ( t == ID ) { Pname n = r.pn; r.s = n->string; DEL(n); }
    register toknode* T = new toknode(t,r,curloc);
    if (front) {
	front->last = T;
	T->next = front;
	T->last = 0;
	front = T;
    } else
	front = rear = T;
    lasttk = 0;
}

extern int
la_sctype( TOK t )
{
//error('d',&latok->place,"la_sctype(%k ) -- latok ==%k",t,latok->tok);
	if ( t != latok->tok && t != TSCOPE && t != MEMPTR )
		error( 'i', &latok->place, "la_sctype, lalex.c" );

	switch( latok->retval.t ) {
		case TYPEDEF:
		case EXTERN:
		case STATIC:
		case AUTO:
		case REGISTER:
		case OVERLOAD:
		case INLINE:
		case FRIEND:
		case CONST:
		case VOLATILE:
			return 1; 
		default:
			return 0; 
	}
}

extern int
la_cast()
/*
	called in reduction of term_lp to check for ambiguous prefix-style cast
	if result is 1, caller inserts DECL_MARKER to force reduction of cast
*/
{
	// yychar already designates TYPE or TNAME
	// LP must start the lookahead queue!
	LDB(1,fprintf(stderr,"\n*** la_cast()\n"););
	int tk, tk2 = latok->tok;

	for ( ; ; ) {
	    tk = tk2;
	    tk2 = lookahead();

	    switch( tk ) {
	    case LP:
		if ( tk2 == MUL || tk2 == AND ||
     			tk2 == TSCOPE || tk2 == MEMPTR )
		    // T ( * ...
		    // T ( C ::* ...
		    continue;
		else
		    // T ( exp )
		    return 0;
	    case MUL: case AND:
		//if ( tk2 == SCTYPE )
		if ( la_sctype( tk2 ) )
		    // T ( * const ...
		    // T ( * volatile ...
		    tk2 = lookahead();
		continue;
	    case MEMPTR:
		if ( tk2 == RP ) continue;
		break;
	    case TSCOPE:
		if ( tk2 == MUL )
		    // T ( C :: * ...
		    continue;
		else
		    // T ( exp )
		    return 0;
	    case RP: case LB:
		// T (*)()
		// T (*[])()
		return 1;
	    }

	    return 0;
	}
}

static int
la_decl()
/*
	handles ambiguities
		type (*x) ()
		type (*x) []
	at start of arg list / statement
	return val == 1 if lookahead finds a declaration
		(used for error messages only)
	if declaration is "ambiguous" (i.e., can't be recognized with
		1-symbol lookahead), insert DECL_MARKER to force reduction
		of "type"
*/
{
	
	// LP must start the lookahead queue!
	LDB(1,fprintf(stderr,"\n*** la_decl()\n"););
	int tk, tk2 = latok->tok;
	int paren = 0;
	int ptr = 0;

	for ( ; ; ) {

	    tk = tk2;
	    tk2 = lookahead();

// fprintf(stderr,"\nla_decl:tk:%d %s tk2: %d %s", tk, keys[tk], tk2, keys[tk2]);
	    switch( tk ) {
	    case LP:
		if ( tk2 == MUL || tk2 == AND || tk2 == TSCOPE ) {
		    // T ( * ...
		    ++paren;
		    ptr = 1;
		    continue;
		} else
		if ( tk2 == MEMPTR ) {
		// T ( C ::*  ...
			return 1;
		} else 
		// possible redundant parens
		if ( tk2 == ID && lookahead() == RP ) {
			TOK tp = lookahead();
// error( 'd', "tp %k tk: %k tk2: %k", tp, tk, tk2 );
// error( 'd', "bl_level: %d, in_class_decl: %d", bl_level,in_class_decl );
			if ( tp == SM || tp == CM || tp == ASSIGN )
			{
				// member initialization list
				if ( tp != SM && in_arg_list == 0 ) return 1;
			}
			else 
			if ( tp == RP && (bl_level-in_class_decl==0))
				return 1;
			if ( tp != LP ) 
				return 0;
			latok=latok->last; // restore lookahead
			++paren;
			continue;
			}
		else
		    // T ( exp )
		    return 0;
	    case MUL: case AND:
		//if ( tk2 == SCTYPE )
		if ( la_sctype( tk2 ))
		    // T ( * const ...
		    // T ( * volatile ...
		    return 1;
		else {
		    ptr = 0;
		    continue;
		}
	    case MEMPTR:
		// T ( C :: * ...
		return 1;
	    case TSCOPE:
		if ( tk2 == MUL ) //??tk SHOULD HAVE TRANSLATED TO MEMPTR!!
		    // T ( C :: * ...
		    return 1;
		else if ( ptr )
		    // T ( exp )
		    return 0;
		else if ( tk2 == ID || tk2 == OPERATOR )
		    // T ( * C :: id ...
		    continue;
		else
		    // error
		    return 0;
	    }

	    break;
	}

	if ( tk == RP || tk == LB )
	    // T (*)()
	    // T (*[])()
	    return 1;

	if ( tk != ID && tk != OPERATOR )
	    // T ( exp )
	    return 0;

	if ( tk == OPERATOR )
	    switch ( tk2 ) {
	    case PLUS: case MINUS: case MUL: case REFMUL:
            case AND: case OR: case ER: case SHIFTOP: case EQUOP: 
	    case DIVOP: case RELOP: case ANDAND: case OROR: 
	    case NOT: case COMPL: case ICOP: case ASSIGN: 
            case ASOP: case NEW: case GNEW: case DELETE:
		// OPERATOR oper
		tk2 = lookahead();
		break;
	    case LP:
		// OPERATOR ()
		tk2 = lookahead();
		if ( tk2 == RP ) {
		    tk2 = lookahead();
		    break;
		} else
		    return 0;
	    case LB:
		// OPERATOR []
		tk2 = lookahead();
		if ( tk2 == LB ) {
		    tk2 = lookahead();
		    break;
		} else
		    return 0;
	    default:	// illegal operator
		return 0;
	    }

	int allow_lp = 1;
	int allow_rp = 1;
	for ( ; ; ) {
	    tk = tk2;
	    tk2 = lookahead();

// fprintf(stderr,"\nla_decl2:tk:%d %s tk2: %d %s", tk, keys[tk], tk2, keys[tk2]);
	    switch( tk ) {
	    case LP:
		if ( !allow_lp )
		    // T ( * id [ exp ] ( ...
		    return 0;

		// Current lookahead will be a decl if
		// the next lookahead is an arg decl
		if ( tk2 == RP || tk2 == ENUM || tk2==AGGR 
 			|| tk2==ELLIPSIS || la_sctype( tk2 )) 
		    // T ( * id ()
		    // T ( * id ) ()
		    return 1;

		if ( tk2 == TYPE || tk2 == TNAME ) {
		    // T ( * id ) ( T2 ...
		    if ( lookahead() == LP && !la_decl() )
			return 0;
		    return 1;
		}

		return 0;
	    case LB:
                if ( tk2 == RB || lookahead() == RB )
		    // T ( * id [] ...
		    return 1;
		else {
		    // T ( * id [ exp ] ...
		    allow_lp = 0;
		    allow_rp = 1;
		    while ( lookahead() != RB );
		    tk2 = lookahead();
		    continue;
		}
	    case RP:
// error ('d', "rp: allow_rp: %d paren: %d", allow_rp, paren );
		if ( !allow_rp || !paren )
		    // T ( * id ) )
		    return 0;
// permit redundant parentheses
		else 
		if ( tk2 == SM || tk2 == CM || tk2 == ASSIGN )
			return 1;
		else
		if ( tk2 == RP && (bl_level-in_class_decl == 0))
			return 1;
		else
		{
		    // T ( * id ) ...
		    allow_lp = 1;
		    allow_rp = 0;
		    --paren;
		    continue;
		}
	    default:
		return 0;
	    }
	}
}



/*
**	PROCESSING OF INLINE MEMBER FUNCTIONS
*/
static int la_snarf();

extern toknode*
save_text()
/*
	save text of inline def on q of class
*/
{
	// Q should contain at least the tokens < FDEF, X ... >
	// where X is either LC or COLON (start of ftn)
	LDB(2,fprintf(stderr,"save_text()"));
	LDB(3,fprintf(stderr,"front: %s",image(front->tok)));
	LDB(3,fprintf(stderr,"front->next: %s",image(front->next->tok)));
	latok = front->next;
	if ( la_snarf() ) {
		// append this set of tokens to
		// inline tokenq for class
		toknode* t = front; // FDEF
		if ( ccl->c_funqf == 0 )
			ccl->c_funqf = front;
		else {
			ccl->c_funqr->next = front;
			front->last = ccl->c_funqr;
		}
		ccl->c_funqr = latok;
		front = latok->next;
		latok->next = 0;
		if (front)  front->last = 0;
		return t;
	}
	return 0;
}


extern void
restore_text()
/*
	restore tokens for member inlines onto token q
*/
{
	LDB(2,fprintf(stderr,"restore_text()"));
	if (ccl->c_funqf == 0)	// no inlines on Q
		return;
	LDB(3,fprintf(stderr,"	Q present: %d,%d",ccl->c_funqf,ccl->c_funqr));
	LDB(3,fprintf(stderr,"	front==%s",image(ccl->c_funqf->tok)));
	LDB(3,fprintf(stderr,"	rear ==%s",image(ccl->c_funqr->tok)));
	ccl->c_funqr->next = front;
	if (front)  front->last = ccl->c_funqr;
	front = ccl->c_funqf;
	ccl->c_funqf = ccl->c_funqr = 0;
}


static void
del_tokens( toknode* marker )
/*
    delete tokens from marker to latok, not inclusive
*/
{
    if ( marker == 0 || marker == latok || marker->next == 0 )
	error('i', "bad token queue");

    LDB(2,fprintf(stderr,"del_tokens: %s..%s\n",image(marker->tok),image(latok->tok)));

    register toknode* tt = marker->next;
    if ( tt == latok ) return;
    marker->next = latok;
    latok->last->next = 0;
    latok->last = marker;
    register toknode* tx = tt;
    do {
	LDB(3,fprintf(stderr,"	deleting %s\n",image(tt->tok)));
	tx = tx->next;
	delete tt;
	tt = tx;
    } while ( tx );
}


static int
la_snarf()
/*
	scan function def without processing declarations
*/
{
	LDB(2,fprintf(stderr,"la_snarf()"));
	loc *L = &latok->place;
	//DBPLACE(1,L.l,L.f);
	int parens = 0;
	int paren_error = 0;
	toknode* marker = latok;
	switch ( latok->tok ) {
	default:
		error('i', L, "bad token Q snarfing function: %d", latok->tok);
	case COLON:
		break;
	case LC:
		--bl_level;
		goto eatf;
	}
	LDB(2,fprintf(stderr,"\"eat\" member initializers"));
	for (;;) {
		if (latok->next == 0) add_tokens();
		switch ( (latok=latok->next)->tok ) {
		case LP:
			++parens;
		default:
			LDB(3,fprintf(stderr,"...%s",image(latok->tok)));
			continue;
		case RP:
			if ( (--parens < 0) && (paren_error++ == 0) )
				error(0,&latok->place,"unbalanced ()");
			continue;
		case LC:
		case RC:
			if ( parens <= 0 )
				goto eatf;
			continue;
		case SM:
			if ( parens <= 0 ) {
				error(0, L, "illegal bit field");
				del_tokens( front );
				delete front;
				front = latok;
				front->last = 0;
				return 0;
			}
			continue;
		case EOFTOK:
			error('i',&latok->place,"unexpected end of file");
		} // switch
	} // for

	eatf:
	int level = 1;
	for (;;) {
		if (latok->next == 0) add_tokens();
		switch ( (latok=latok->next)->tok ) {
		case LC:
			++level;
		default:
			LDB(3,fprintf(stderr,"...%s",image(latok->tok)));
			continue;
		case RC:
			LDB(3,fprintf(stderr,"...RC"));
			if (--level <= 0) {
				if (level < 0) {
					error(0,&latok->place,"unexpected '}'");
					goto bad;
				}
				return 1;
			}
			break;
		case EOFTOK:
			error('e', &latok->place, "unbalanced {}");
			goto bad;
		} // switch
	} // for
	bad:
		del_tokens( marker );
		marker->tok = SM;
		return 0;
}

Pname check_for_nested( Pname nstd, TOK lasttk, YYSTYPE lastval, TOK tk2)
{
// error('d',"nstd: %n must_be_id 0 tk2: %k lasttk: %d",nstd,tk2,lasttk);
	TOK tk = ID;
	Pclass xcl = curr_scope?Pclass(Pbase(curr_scope->tp)->b_name->tp):(ccl?ccl:0);

	for (Pname nn=nstd; nn; nn=nn->n_tbl_list) {
		TOK ntk;
		bit ok = 0;
		Ptype tt = return_nstd_local_type(nn,ntk);
		Pclass cl = tt->in_class; 
		if ( xcl ) {
			if (xcl==cl || xcl->has_base(cl))
				ok++;
			else {
				for (Pclass eccl=xcl->in_class;eccl;eccl=eccl->in_class)
				if ( eccl == cl ) { ok++; break; }
			}
		}
							
		if (nn == nstd)
		{
			if ( ((in_arg_list || lasttk==LP) &&  // foo(nestedX
				(tk2==CM || tk2==ASSIGN || tk2==RP)) 
			    || (tk2==LC && (lasttk==PR || lasttk==VIRTUAL))
			    || (tk2 == MUL || tk2==AND)
			    || (lasttk==LP && tk2==RP)
			    || (lasttk==TSCOPE && lastval.pn == nn) 
			    || (lasttk==COMPL && dtor_seen == nn) 
			    || (lasttk==TYPE && lastval.t == TYPEDEF)
			    || lasttk == NEW || in_sizeof )
			{  
				if ( nstd->n_tbl_list == 0 ) { // only one: ok
					break;
    				} else {
					if (lasttk != TSCOPE && !ok){
						error("ambiguous nested type %s, use X::%s",nn->string,nn->string);
						error( 'i', "cannot recover from previous errors" );
					}
				}
			}
	        }
		if ( nn->n_key != NESTED ) continue;
		if (xcl && strcmp(xcl->string,cl->string) == 0) break;
	} // end: for nn = nstd
	return nn;
}

0707071010112044341004440001630000160000010203200466055404200000600000066146lex.c/*ident	"@(#)ctrans:src/lex.c	1.4" */
/***************************************************************************

	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.

lex.c:
	lexical analyser based on pcc's and cpre's scanners
	modified to handle classes:
	new keywords:	class
			public
			call
			etc.
	names are not entered in the symbol table by lex()
	names can be of arbitrary length
	error() is used to report errors
	{} and () must match
	numeric constants are not converted into internal representation
	but stored as strings

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

#include "cfront.h"
#include "yystype.h"
#include "size.h"
#include "tqueue.h"
#include "template.h"

# define  CCTRANS(x) x
#define copy_if_need_be(s)  ((templp->in_progress || templp->parameters_in_progress) ? strdup(s) : (s))

	/* lexical actions */

#define A_ERR	0		/* illegal character */
#define A_LET	1		/* saw a letter */
#define A_DIG	2		/* saw a digit */
#define A_1C	3		/* return a single character */
#define A_STR 	4		/* string */
#define A_CC	5		/* character constant */
#define A_BCD	6		/* GCOS BCD constant */
#define A_SL	7		/* saw a / */
#define A_DOT 	8		/* saw a . */
#define A_2C	9		/* possible two character symbol */
#define A_WS	10		/* whitespace (not \n) */
#define A_NL	11		/* \n */
#define A_LC	12		/* { */
#define A_RC	13		/* } */
#define A_L	14		/* ( */
#define A_R	15		/* ) */
#define A_EOF	16
#define A_ASS	17
#define A_LT	18
#define A_GT	19		/* > */
#define A_ER	20
#define A_OR	21
#define A_AND	22
#define A_MOD	23
#define A_NOT	24
#define A_MIN	25
#define A_MUL	26
#define A_PL	27
#define A_COL	28		/* : */
#define A_SHARP	29		/* # */
#define A_DOLL  30              /* $ */

	/* character classes */

# define LEXLET 01
# define LEXDIG 02
/* no LEXOCT because 8 and 9 used to be octal digits */
# define LEXHEX 010
# define LEXWS 020
# define LEXDOT 040

const FIRSTCHUNK = 8*1024-8;
const BUFCHUNK = 4*1024-8;

	/* text buffer */
static char inbuf[FIRSTCHUNK/*TBUFSZ*/];
static char* txtmax = &inbuf[FIRSTCHUNK/*TBUFSZ*/-1];
static char* txtstart = 0;
static char* txtfree = 0;

static struct buf* bufhead;
static buf* freebuf;
//static bufs;

struct buf {
	buf* next;
	char chars[BUFCHUNK];
//	buf() { next=bufhead; bufhead=this; }
};

new_buf(char c)
{
//fprintf(stderr,"new_buf %d\n",bufs++);
	buf* pbuf;
	if (freebuf) {
		pbuf = freebuf;
		freebuf = freebuf->next;
	}
	else
		pbuf = new buf;	// allocate and register new chunk
	pbuf->next = bufhead;
	bufhead = pbuf;

	if (BUFCHUNK < txtmax-txtstart) error('l',"lexical token too long");

	// copy current token:
	char* p = txtstart;
	txtstart = txtfree = &pbuf->chars[0];
	while (p<txtmax) *txtfree++ = *p++;
	*txtfree++=c;
	txtmax = &pbuf->chars[BUFCHUNK-1];
	return 0;
}


#define pch(c) ((txtmax<=txtfree)?new_buf(c):(*txtfree++=c))
#define start_txt()	txtstart = txtfree
#define del_txt()	txtfree = txtstart

static int Nfile;// = 1;
static char* file_name[MAXFILE*4];	// source file names
					// file_name[0] == src_file_name
					// file_name[0] == 0 means stdin
static short file_stack[MAXFILE];	// stack of file name indices
static int tcurr_file;			// current index in file_stack
					// that is current #include nest level

Linkage linkage = linkage_default; // linkage is default C++	
const LINKMAX = 10;
static Linkage lvec[LINKMAX] = { linkage_default };
static int lcount = 0;

void set_linkage(char* p)
{
	if (p==0 || *p == 0) {	// resume previous linkage
		if (lcount>0) linkage = lvec[--lcount];
	}
	else {
		if (LINKMAX<=++lcount) {
			error('l',"linkage directive nested too deep");
			--lcount;
		} else if (strcmp(p,"C")==0)
			lvec[lcount] = linkage = linkage_C;
		else if (strcmp(p,"C++")==0)
			lvec[lcount] = linkage = linkage_Cplusplus;
		else {
			error("%s linkage",p);
			--lcount;
		}
	}
}

static struct loc tloc;
FILE * out_file = stdout;
FILE * in_file = stdin;
Ptable ktbl;
Ptable keyword_table;

static int p_level = 0;		/* number of unmatched ``(''s */
static int b_level = 0;		/* number of unmatched ``{''s */

# ifdef ibm

# define CSMASK 0377
# define CSSZ 256

# else

# define CSMASK 0177
# define CSSZ 128

# endif

static short lxmask[CSSZ+1];

int saved = 0;	/* putback character, avoid ungetchar */
static int lxtitle();

// overload rt;
inline YYSTYPE rt(char* x) { YYSTYPE y; y.s  = x;        return y; }
inline YYSTYPE rt(int   x) { YYSTYPE y; y.t  = x;        return y; }
inline YYSTYPE rt(loc   x) { YYSTYPE y; y.l  = x;        return y; }
inline YYSTYPE rt(void* x) { YYSTYPE y; y.pn = Pname(x); return y; }

#define get(c)		(c=getc(in_file))
#define unget(c)	ungetc(c,in_file)

#define reti(a,b)	{ addtok(a, rt(b), tloc);          return a; }
#define retn(a,b)	{ addtok(a, rt((Pnode)b), tloc);   return a; }
#define rets(a,b)	{ addtok(a, rt(b), tloc);          return a; }
#define retl(a)		{ addtok(a, rt(tloc), tloc);       return a; }

// keys[] holds the external form for tokens with fixed representation 
// illegal tokens and those with variable representation have 0 entries
char* keys[MAXTOK+1];

static void 
new_key(char* s, TOK toknum, TOK yyclass)
/*
  make "s" a new keyword with the representation (token) "toknum"
  "yyclass" is the yacc token (for example new_key("int",INT,TYPE); )
  "yyclass==0" means yyclass=toknum;
*/
{
	Pname n = new name(s);

	keys[(toknum==LOC)?yyclass:toknum] = s;
	n = new name(s);
	Pname nn = keyword_table->insert(n,0);
	// if (Nold) error('i',"keyword %sD twice",s);
	nn->base = toknum;
	nn->syn_class = (yyclass) ? yyclass : toknum;
	delete n;
}

const int keyword_count = 67;
static void 
ktbl_init()
/*
	enter keywords into keyword table for use by lex()
	and into keyword representation table used for output
 
        ktbl is only for types. We put nothing in it. 
	keyword_table is for user-defined reserved words 
*/
{
	ktbl = new table(KTBLSIZE,0,0);
	keyword_table = new table(keyword_count,0,0);

	new_key("asm",ASM,0);
	new_key("auto",AUTO,TYPE);
	new_key("break",LOC,BREAK);
	new_key("case",LOC,CASE);
	new_key("continue",LOC,CONTINUE);
	new_key("char",CHAR,TYPE);
	new_key("do",LOC,DO);
	new_key("double",DOUBLE,TYPE);
	new_key("default",LOC,DEFAULT);
	new_key("enum",ENUM,0);
	new_key("else",LOC,ELSE);
	new_key("extern",EXTERN,TYPE);
	new_key("float",FLOAT,TYPE);
	new_key("for",LOC,FOR);
	new_key("goto",LOC,GOTO);
	new_key("catch",CATCH,CATCH);
	new_key("try",TRY,TRY);
	new_key("if",LOC,IF);
	new_key("int",INT,TYPE);
	new_key("long",LONG,TYPE);
	new_key("return",LOC,RETURN);
	new_key("register",REGISTER,TYPE);
	new_key("static",STATIC,TYPE);
	new_key("struct",STRUCT,AGGR);
	new_key("sizeof",SIZEOF,0);
	new_key("short",SHORT,TYPE);
	new_key("switch",LOC,SWITCH);
	new_key("typedef",TYPEDEF,TYPE);
	new_key("unsigned",UNSIGNED,TYPE);
	new_key("union",UNION,AGGR);
	new_key("void",VOID,TYPE);
	new_key("while",LOC,WHILE);

	new_key("class",CLASS,AGGR);
	new_key("const",CONST,TYPE);
	new_key("delete",LOC,DELETE);
	new_key("friend",FRIEND,TYPE);
	new_key("inline",INLINE,TYPE);
	new_key("new",NEW,0);
	new_key("operator",OPERATOR,0);
	new_key("overload",OVERLOAD,TYPE);
	new_key("private",PRIVATE,PR);
	new_key("protected",PROTECTED,PR);
	new_key("public",PUBLIC,PR);
	new_key("signed",SIGNED,TYPE);
	new_key("template",TEMPLATE,0);
	new_key("this",THIS,0);
	new_key("virtual",VIRTUAL,TYPE);
	new_key("volatile",VOLATILE,TYPE);

	new_key("__statement", STATEMENT, 0) ;
	new_key("__expression", EXPRESSION, 0) ;
	new_key("__template_test", TEMPLATE_TEST, 0) ;
}

loc last_line;
loc noloc = { 0, 0 };

void loc::putline()
{
	if (file==0 && line==0) return;
//   fix, Nfile, not MAXFILE; Nfile == MAXFILE*4
//	if (0<=file && file<MAXFILE) {
	if ( 0<=file && file <= Nfile ) {
		char* f = file_name[file];
		if (f==0) f = src_file_name;
		fprintf(out_file,line_format,line,f);
		last_line = *this;
	}
}

void loc::put(FILE* p)
{
//    fix, Nfile, not MAXFILE; Nfile == MAXFILE*4
//	if (0<=file && file<MAXFILE) {
	if ( 0<=file && file <= Nfile ) {
		char* f = file_name[file];
		if (f==0) f = src_file_name;
		fprintf(p,"\"%s\", line %d: ",f,line);
	}
}

void lxenter(register char* s, short m)
/* enter a mask into lxmask */
{
	register c;

	while( c= *s++ ) lxmask[c+1] |= m;

}


void lxget(register c, register m)
/*
	put 'c' back then scan for members of character class 'm'
	terminate the string read with \0
	txtfree points to the character position after that \0
*/
{
	pch(c);
	while ( (get(c), lxmask[c+1]&m) ) pch(c);
	unget(c);
	pch('\0');
}

struct LXDOPE {
	short lxch;	/* the character */
	short lxact;	/* the action to be performed */
	TOK   lxtok;	/* the token number to be returned */
} lxdope[] = {
#ifdef apollo
	'@',	A_ERR,	0,	/* illegal characters go here... */
#else
         '$',    A_DOLL, 0,
//       '$',    A_ERR,  0,      /* illegal characters go here... */
#endif
	'_',	A_LET,	0,	/* letters point here */
	'0',	A_DIG,	0,	/* digits point here */
	' ',	A_WS,	0,	/* whitespace goes here */
	'\n',	A_NL,	0,
	'"',	A_STR,	0,	/* character string */
	'\'',	A_CC,	0,	/* ASCII character constant */
	'`',	A_BCD,	0,	/* 'foreign' character constant, e.g. BCD */
	'(',	A_L,	LP,
	')',	A_R,	RP,
	'{',	A_LC,	LC,
	'}',	A_RC,	RC,
	'[',	A_1C,	LB,
	']',	A_1C,	RB,
	'*',	A_MUL,	MUL,
	'?',	A_1C,	QUEST,
	':',	A_COL,	COLON,
	'+',	A_PL,	PLUS,
	'-',	A_MIN,	MINUS,
	'/',	A_SL,	DIV,
	'%',	A_MOD,	MOD,
	'&',	A_AND,	AND,
	'|',	A_OR,	OR,
	'^',	A_ER,	ER,
	'!',	A_NOT,	NOT,
	'~',	A_1C,	COMPL,
	',',	A_1C,	CM,
	';',	A_1C,	SM,
	'.',	A_DOT,	DOT,
	'<',	A_LT,	LT,
	'>',	A_GT,	GT,
	'=',	A_ASS,	ASSIGN,
	'#',	A_SHARP, 0,
	EOF,	A_EOF,	EOFTOK
	};
/* note: EOF is used as sentinel, so must be <=0 and last entry in table */

static struct LXDOPE *lxcp[CSSZ+1];

void 
lex_init()
{
	register struct LXDOPE *p;
	register i;
	register char *cp;
	/* set up character classes */

	/* first clear lexmask */
	for(i=0; i<=CSSZ; i++) lxmask[i] = 0;

#ifdef apollo
	lxenter( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$", LEXLET );
#else
	lxenter( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_", LEXLET );
#endif
	lxenter( "0123456789", LEXDIG );
	lxenter( "0123456789abcdefABCDEF", LEXHEX );
		/* \013 should become \v someday; \013 is OK for ASCII and EBCDIC */
	lxenter( " \t\r\b\f\013", LEXWS );
	lxmask['.'+1] |= LEXDOT;

	/* make lxcp point to appropriate lxdope entry for each character */

	/* initialize error entries */

	for( i= 0; i<=CSSZ; ++i ) lxcp[i] = lxdope;

	/* make unique entries */

	for( p=lxdope; ; ++p ) {
		lxcp[p->lxch+1] = p;
		if( p->lxch < 0 ) break;
	}

	/* handle letters, digits, and whitespace */
	/* by convention, first, second, and third places */

	cp = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
	while( *cp ) lxcp[*cp++ + 1] = &lxdope[1];
	cp = "123456789";
	while( *cp ) lxcp[*cp++ + 1] = &lxdope[2];
	cp = "\t\b\r\f\013";
	while( *cp ) lxcp[*cp++ + 1] = &lxdope[3];

	file_name[0] = src_file_name;
	// set both curloc and tloc so curloc is valid at program startup
//	curloc.file = tloc.file = 0;
	curloc.line = tloc.line = 1;

	ktbl_init();
	lex_clear();
	saved = lxtitle();
}

void lex_clear()
{
	// delete extra buffers:
	buf* p = bufhead;	
	bufhead = 0;
//if (p) {
//fprintf(stderr,"lex_clear\n");
//bufs=0;
//}
	while (p) {
		buf* pp = p;
		p = p->next;
		pp->next = freebuf;
		freebuf = pp;
	}

	// re-set to static buffer:
	txtstart = txtfree = inbuf;
	txtmax = &inbuf[FIRSTCHUNK/*TBUFSZ*/-1];
}

int int_val(char hex)
{
	switch (hex) {
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
		return hex-'0';
	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
		return hex-'a'+10;
	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
		return hex-'A'+10;
	}
}

void hex_to_oct()
/*
	\x has been seen on input (in char const or string) and \ printed
	read the following hexadecimal integer and replace it with an octal
*/
{
	int i = 0;
	int c;
	get(c);
	if (lxmask[c+1] & LEXHEX) {
		i = int_val(c);
		get(c);					// try for two
		if (lxmask[c+1] & LEXHEX) {
			i = (i<<4) + int_val(c);
			get(c);				// try for three
			if (lxmask[c+1] & LEXHEX)
				i = (i<<4) + int_val(c);
			else
				unget(c);
		}
		else
			unget(c);
	}
	else {
		error("hexadecimal digitE after \\x");
		unget(c);
	}

//	if (0377 < i) error('l',"hexadecimal constant too large");
	i &= 0377;

	pch(('0'+(i>>6)));
	pch(('0'+((i&070)>>3)));
	pch(('0'+(i&7)));
}


char * chconst()
/*
	read a character constant into inbuf
*/
{
	register c;
	int nch = 0;

	pch('\'');

	for(;;) {
		char* p;
		char cc = 0;

		switch (get(c)) {
		case '\'':
			goto ex;
		case EOF:
			error("eof in char constant");
			goto ex;
		case '\n':
			error("newline in char constant");
			goto ex;
		case '\\':
			if (SZ_INT == nch++) error('l',"char constant too long");
			pch(c);
			switch (get(c)){
			case '\n':
				++tloc.line;
			default:
				pch(c);
				break;
			case '4': case '5': case '6': case '7': // octal
				p = txtfree;
				cc = c-4;
			case '0': case '1': case '2': case '3':
				pch(c);
				get(c);  /* try for 2 */
				if( lxmask[c+1] & LEXDIG && c<'8'){
					pch(c);
					get(c);  /* try for 3 */
					if (lxmask[c+1] & LEXDIG && c<'8') {
						if (cc) *p = cc; // zap high bit
						pch(c);
					}
					else
						unget(c);
				}
				else
					unget(c);
				break;
			case 'x':	// hexadecimal
				hex_to_oct();
				break;
			};
			break;
		default:
			if (SZ_INT == nch++) error('l',"char constant too long");
			pch(c);
		}
	}
ex:
	if(nch==0)
		error("empty char constant");
	pch('\'');
	pch('\0');
	return txtstart;
}

void lxcom()
/* process a "block comment" */
{
	register c;

	for(;;)
	switch (get(c)) {
	case EOF:
		error('w',"eof in comment");
		return;
	case '\n':
		tloc.line++;
//		Nline++;
		break;
	case '*':
		if (get(c) == '/') return;
		unget(c);
		break;
	case '/':
		if (get(c) == '*') error('w',"``/*'' in comment");
		unget(c);
		break;
	}
}


void linecom()
// process a "line comment"
{
	register c;

	get(c);
#ifdef DBG
	if ( c=='@' && get(c)=='!' ) {
		while ( get(c) != '\n' && c != EOF ) pch(c);
		pch('\0');
		process_debug_flags(txtstart);
		del_txt();
	}
#endif
	for(;;get(c))
	switch (c) {
	case EOF:
		error('w',"eof in comment");
		return;
	case '\n':
		tloc.line++;
//		Nline++;
		saved = lxtitle();
		return;
	}
}

char eat_whitespace()
{

	for(;;) {
		register c = get(c);
	lx:

		switch (c) {
		case EOF:
			error('w',"unexpected comment");
			return EOF;
		case '/':
			switch (get(c)) {
			case '*':
				lxcom();
				break;
			case '/':
				linecom();
				break;
			default:
				unget(c);
				return '/';
			}
			break;
		case '\n':
			++tloc.line;
			c = lxtitle();
			goto lx;
		case ' ':
		case '\t':
			break;
		default:
			return c;		
		}
	}	
}

void get_string()
{
	int lxchar;

	for(;;)
	switch (get(lxchar)) {
 	case '\\':
  		pch('\\');
 		switch (get(lxchar)){
 		case '\n':
 			++tloc.line;
 		default:
  			pch(lxchar);
 			break;
 		case 'x':	// hexadecimal
 			hex_to_oct();
 			break;
 		};
  		break;
	case '"':
        {       char* p = txtstart;     // eat_whitespace() moves txtstart
                if ((lxchar = eat_whitespace()) == '"') {
                        // string catenation, break with
                        // newline to avoid merging characters
                        // (e.g. "\xAB" "C")
                        pch('\\');
                        pch('\n');

                        continue;       // eat '\"' and carry on
                };

                txtstart = p;
		unget(lxchar);
		pch(0);
		return;
        }
	case '\n':
		error("newline in string");
		pch(0);
		return;
	case EOF:
		error("eof in string");
		pch(0);
		return;
	default:
		pch(lxchar);
	}
}

TOK tlex()
{
	TOK ret;
	Pname n;

//	Ntoken++;

	for(;;) {
		register lxchar;
		register struct LXDOPE *p;

		start_txt();

		if (saved) {
			lxchar = saved;
			saved = 0;
		}
		else
			get(lxchar);

 		if (lxchar+1 >= CSSZ )
		 error( "illegal input character encountered: %d", lxchar );

		switch( (p=lxcp[lxchar+1])->lxact ){

		case A_1C:	// eat up a single character, and return an opcode 
			reti(p->lxtok,p->lxtok);

		case A_EOF:
			if (p_level || b_level+lcount)
				error("'%s' missing at end of input",(b_level+lcount) ? "}" : ")");
		
			reti(EOFTOK,0);

		case A_SHARP:
			// cope with header file not ended with '\n'
			unget('#');
			saved = lxtitle();
			continue;

		case A_ERR:
		{	if (' '<=lxchar && lxchar<='~')	// ASCII printable
				error("illegal character '%c' (ignored)",lxchar);
			else
				error("illegal character '0%o' (ignored)",lxchar);
			continue;
		}

		case A_DOLL:
                { // lex a name of the for $id for template tree formals
                	Pname fn ;
                        lxget( lxchar, LEXLET|LEXDIG ) ;

                        if (!templp->in_progress ||  !txtstart[1]) {
                          // no name string immediately follows, treat it                                  
                          // like an illegal character
                          error("illegal character '0%o' (ignored)",lxchar);                               
                          continue;
                        }  

                        txtstart++ ;
                        if(fn=templ_compilation::tree_parameter(txtstart)) {                              
                        	switch (fn->n_template_arg) {
                          		case template_expr_tree_formal:
                            		// retain the $ in the name
                            			retn(ID, strdup(--txtstart)) ;

                          		case template_stmt_tree_formal:
                            			retn(SM_PARAM, fn) ;
                          	}  
                        }  
                        error("%s wasn't a statement or expression formal", txtstart);
                        rets(ID, copy_if_need_be(txtstart));
                }

		case A_LET:	// collect an identifier and check for keyword
		{
			char ll;
			switch (ll = lxchar) {
		//	case 'l':
			case 'L':
				switch (get(lxchar)) {
				case '\'':
					error('s',"wide character constant");
					unget(lxchar);
					continue;
				case '"':
					error('s',"wide character string");
					unget(lxchar);
					continue;
				}
				unget(lxchar);
				lxchar = ll;
			}
		}

			lxget( lxchar, LEXLET|LEXDIG );
                        /* look for a keyword or a global type */
			if ((n = keyword_table->look(txtstart,0))  /* keyword */
				|| (n = ktbl->look(txtstart, 0)))  /* local type */
			{
				TOK x;
				del_txt();
				switch (x=n->base) {
				case TNAME:
					rets(ID,n->string);
				case LOC:
					retl(n->syn_class);
				case EXTERN:
					if ((lxchar = eat_whitespace()) == '\"') {
						// linkage directive
						get_string();
						rets(LINKAGE,txtstart);
					}
					unget(lxchar);
					reti(TYPE,EXTERN);
				case CATCH:
				// case TEMPLATE:
					error('s',"%k",n->syn_class);
					continue;
				case TRY:
				{
					static int warn_try;
					if (!warn_try) { 
						Pname n = keyword_table->look("try",0);
						n->n_key = DEFAULT;
						error('w',&tloc,"%k is a future reserved keyword",n->syn_class);
						warn_try++;
					}
					rets(ID,n->string);
				}
				default:
					reti(n->syn_class,x);
				}
			}
			// rets(ID,txtstart);
                        rets(ID, copy_if_need_be(txtstart)) ;

		case A_DIG:

			ret = ICON;

			if (lxchar=='0') {
				int pkchar;
				get(pkchar);
				if(pkchar=='x' || pkchar=='X') {	// hex
					pch(lxchar);
					lxget(pkchar,LEXHEX);
					txtfree--;
					if (txtfree-txtstart<3) // minimum "0Xd\0"
						error("hex digitX after \"0x\"");
					get(lxchar);
					goto getsuffix;
				}
				unget(pkchar);
			}

			lxget(lxchar,LEXDIG);
			txtfree--;

			if (get(lxchar) == '.') {
		getfp:
				lxget('.', LEXDIG );
				txtfree--;
				ret = FCON;
				get(lxchar);
			};
		
			if (lxchar=='e' || lxchar=='E') {
				pch(lxchar);
				get(lxchar);
				if(lxchar=='-' || lxchar=='+') {
					pch(lxchar);
					get(lxchar);
				}
				if (lxmask[lxchar+1] & LEXDIG) {
					lxget( lxchar, LEXDIG );
					txtfree--;
					get(lxchar);
				}
				else
					error("missing exponent digits?");
				ret = FCON;
			};

			if(*txtstart=='0' && ret==ICON) {
				char *bch = txtstart;
				while (++bch <= txtfree) {
					if(*bch=='8' || *bch=='9')
						error("%c used as octal digit",*bch);
				}
			}

		getsuffix:
			switch (lxchar) {
			case 'f':
			case 'F':
				if (ret==ICON)
					error("%c suffix for integer constant",lxchar);
				else
					pch(lxchar);
				break;
			case 'u':
			case 'U':
				if (ret==FCON) {
					error("%c suffix for floating constant",lxchar);
					break;
				}
				pch(lxchar);
				switch(get(lxchar)) {
				case 'l':
				case 'L':
					pch(lxchar);
					break;
				default:
					saved=lxchar;
					break;
				}
				break;
			case 'l':
			case 'L':
				pch(lxchar);
				if (ret==FCON) {
					break;
				}
				switch(get(lxchar)) {
				case 'u':
				case 'U':
					pch(lxchar);
					break;
				default:
					saved=lxchar;
					break;
				}
				break;
			default:
				saved = lxchar;
				break;
			};

			if(*txtstart=='0' && txtfree-txtstart==1)
				reti(ZERO,0);	// plain zero

			pch(0);
			rets(ret,txtstart);


		case A_DOT:
			switch (get(lxchar)) {
			case '.':	// look for ellipsis
				if (get(lxchar) != '.') {
					error("token .. ?");
					saved = lxchar;
				}
				reti(ELLIPSIS,0);
			case '*':
				reti (REFMUL,DOT);
			}

			if (lxmask[lxchar+1] & LEXDIG){// look for floating constant
				unget(lxchar);
				goto getfp;
			}
			saved = lxchar;
			reti(DOT,0);

		case A_STR:
			/* save string constant in buffer */
			get_string();
			rets(STRING,txtstart);

		case A_CC:
			/* character constant */
			rets(CCON,chconst());

		case A_BCD:
			{
				register i;
				int j;
	
				pch('`');
	
				for (i=0; i<7; ++i) {
					pch(get(j));
					if (j == '`' ) break;
				}
				pch(0);
				if (6<i)
					error('l',"bcd constant exceeds 6 characters" );
				rets(CCON,txtstart);
			}

		case A_SL:	/* / */
			switch (get(lxchar))  {
			case '*':
				lxcom();
				break;
			case '/':
				linecom();
				break;
			case '=':
				reti(ASOP,ASDIV);
			default:
				saved = lxchar;
				reti(DIVOP,DIV);
			}

		case A_WS:
			continue;

		case A_NL:
			++tloc.line;
//			Nline++;
			saved = lxtitle();
			continue;

		case A_LC:
			if (BLMAX <= b_level++) {
				error('l',"blocks too deeply nested");
				ext(3);
			}
			retl(LC);

		case A_RC:
			if (lcount+b_level-- <= 0) {
				error("unexpected '}'");
				b_level = 0;
			}
			retl(RC);

		case A_L:
			p_level++;
			reti(LP,0);

		case A_R:
			if (p_level-- <= 0) {
				error("unexpected ')'");
				p_level = 0;
			}
			reti(RP,0);

		case A_ASS:
			switch (get(lxchar)) {
			case '=':
				reti(EQUOP,EQ);
			default:
				saved = lxchar;
				reti(ASSIGN,ASSIGN);
			}

		case A_COL:
			switch (get(lxchar)) {
			case ':':
				reti(MEM,0);
			case '=':
				error("':=' is not a c++ operator");
				reti(ASSIGN,ASSIGN);
			default:
				saved = lxchar;
				reti(COLON,COLON);
			}
		case A_NOT:
			switch (get(lxchar)) {
			case '=':
				reti(EQUOP,NE);
			default:
				saved = lxchar;
				reti(NOT,NOT);
			}
		case A_GT:
			switch(get(lxchar)) {
			case '>':
				switch (get(lxchar)) {
				case '=':
					reti(ASOP,ASRS);
					break;
				default:
					saved = lxchar;
					reti(SHIFTOP,RS);
				}
			case '=':
				reti(RELOP,GE);
			default:
				saved = lxchar;
				reti(GT,GT);
			}
		case A_LT:
			switch (get(lxchar)) {
			case '<':
				switch (get(lxchar)) {
				case '=':
					reti(ASOP,ASLS);
				default:
					saved = lxchar;
					reti(SHIFTOP,LS);
				}
			case '=':
				reti(RELOP,LE);
			default:
				saved = lxchar;
				reti(LT,LT);
			}
		case A_AND:
			switch (get(lxchar)) {
			case '&':
				reti(ANDAND,ANDAND);
			case '=':
				reti(ASOP,ASAND);
			default:
				saved = lxchar;
				reti(AND,AND);
			}
		case A_OR:
			switch (get(lxchar)) {
			case '|':
				reti(OROR,OROR);
			case '=':
				reti(ASOP,ASOR);
			default:
				saved = lxchar;
				reti(OR,OR);
			}
		case A_ER:
			switch (get(lxchar)) {
			case '=':
				reti(ASOP,ASER);
			default:
				saved = lxchar;
				reti(ER,ER);
			}
		case A_PL:
			switch (get(lxchar)) {
			case '=':
				reti(ASOP,ASPLUS);
			case '+':
				reti(ICOP,INCR);
			default:
				saved = lxchar;
				reti(PLUS,PLUS);
			}
		case A_MIN:
			switch (get(lxchar)) {
			case '=':
				reti(ASOP,ASMINUS);
			case '-':
				reti(ICOP,DECR);
			case '>':
				if (get(lxchar) == '*')
					{reti(REFMUL,REF);}
				else
					saved = lxchar;
				reti(REF,REF);
			default:
				saved = lxchar;
				reti(MINUS,MINUS);
			}
		case A_MUL:
			switch (get(lxchar)) {
			case '=':
				reti(ASOP,ASMUL);
			case '/':
				error('w',"*/ not as end of comment");
			default:
				saved = lxchar;
				reti(MUL,MUL);
			}
		case A_MOD:
			switch (get(lxchar)) {
			case '=':
				reti(ASOP,ASMOD);
			default:
				saved = lxchar;
				reti(DIVOP,MOD);
			}
		default:
			{error('i',"lex act==%d getc()->%d",p,lxchar);}

		}

		error('i',"lex, main switch");
	}

}

int lxtitle()
/*
	called after a newline; set linenumber and file name
*/
{
	register c;

	for(;;)
	switch ( get(c) ) {
	default:		// e.g. not '\n', not '#'
		return c;
	case '\n':
		tloc.line++;
//		Nline++;
	ll:
		break;
	case '#': 	/* # lineno "filename" */
	{	int cl = tloc.line;
		tloc.line = 0;
		for(;;) 
		switch (get(c)) {
		case '"':
			start_txt();
			for(;;)
			switch (get(c)) {
			case '"':
				pch('\0');

				while (get(c) != '\n') ;  // skip to eol.. ignore anything more

				if (*txtstart) {	// stack file name
					char* fn;
					if (tcurr_file == 0){
						if (( fn = file_name[0]) 
							&& (strcmp(txtstart,fn)!=0)){  // 1st include
							if (MAXFILE*4<++Nfile) error('i',"fileN buffer overflow");
							if (MAXFILE<++tcurr_file) error('i',"fileN stack overflow");
							file_stack[tcurr_file] = Nfile;
						
							char* p1 = new char[txtfree-txtstart];
							(void) strcpy(p1,txtstart);
							file_name[Nfile] = p1;
	//						Nstr++;
						}
						else { //&& line is dummy #line "input.c"
							// ignore
						}
//&& dead, dead, dead			goto push;
					}
					else if ( (fn=file_name[file_stack[tcurr_file]])
					&& (strcmp(txtstart,fn)==0) ) {
						//new line, same file: ignore
					}
					else if ( (fn=file_name[file_stack[tcurr_file-1]])
					&& (strcmp(txtstart,fn)==0) ) {
						// previous file: pop
						tcurr_file--;
					}
					else {	// new file name: push
//&&				push:
						if (MAXFILE*4<Nfile++) error('i',"fileN buffer overflow");
						if (MAXFILE<tcurr_file++) error('i',"fileN stack overflow");
						file_stack[tcurr_file] = Nfile;
						char* p = new char[txtfree-txtstart];
						(void) strcpy(p,txtstart);
						file_name[Nfile] = p;
//						Nstr++;
					}
				}
				else {	// no name .. back to the original .c file: ""
					tcurr_file = 0;
				}
				del_txt();
				tloc.file = file_stack[tcurr_file];
				goto ll;
			case '\n':
				error("unexpected end of line on '# line'");
			default:
				pch(c);
			}
		case ' ':
			break;

		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			tloc.line = tloc.line*10+c-'0'; 
			break;

		case 'l':	// look for "#line ..." and then ignore "line"
			if (get(c)=='i' && get(c)=='n' && get(c)=='e') break;
               case '\n':
                        tloc.putline();
                        goto ll;

		default: // pass #rubbish through
			tloc.line = cl;
			pch('#');
			pch(c);
			while (get(c) != '\n') pch(c);
			pch('\0');
			fprintf(out_file,"\n%s\n",txtstart);
			start_txt();
			tloc.line++;
//			Nline++;
			goto ll;
		}
	}
	}
}
0707071010112044351004440001630000160000010204200466055404600000700000046311main.c/*ident	"@(#)ctrans:src/main.c	1.9" */
/***********************************************************************

	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.

main.c:

	Initialize global environment
	Read argument line
	Start compilation
	Clean up and exit

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

#ifdef __cplusplus
#include <stdlib.h>
#endif

#include <ctype.h>
#include <string.h>
#include <libc.h>
#include <osfcn.h>
#include <fstream.h>
#include "size.h"
#include "cfront.h"
#include "tree_dump.h"
#include "template.h"
#include "hash.h"

char* prog_name = "<<AT&T C++ Translator <(3.0)(PT)> 08/08/90>>";
char* src_file_name = "";
char* line_format = "\n# %d \"%s\"\n";

int dump_tree;
int tree_dump_brief = 0;
dcn_arg dump_tree_arg;

#ifdef unix
#include <signal.h>

static void core_dump(int = 0)
{
	if (error_count)
		fprintf(stderr,"sorry, cannot recover from previous error\n");
	else 
		error('i',"bus error (or something nasty like that)");
	ext(99);
}
#endif

Plist isf_list;
Pstmt st_ilist;
Pstmt st_dlist;
Ptable sti_tbl;
Ptable std_tbl;
Plist stat_mem_list;

int vtbl_opt = -1;	// how to deal with vtbls:
			// -1 static and defined
			// 0 external and supposed to be defined elsewhere
			// 1 external and defined
int debug_opt;
int gplus_opt;		// -g to cc, overrides print optimization 
int ansi_opt;
int strict_opt;		// disallow features from the anachronism section
			// of the manual
int warning_opt;	// produce more warnings if set
bit stmtno = 0;

extern simpl_init();
extern typ_init();
extern syn_init();
extern lex_init();
extern error_init();

char *st_name(char*);	// generates names of static ctor, dtor callers, ptbl_vec
Pname def_name;		// first definition in file
Pname pdef_name;	// used with ptbl_vec if function is first definition

int syn_count = 0; // to set conditional breakpoints to find particular expressions  
Hash *dumper_node_hash_table;
  
void static
clean_dumper_hash_table() {
	if(!dumper_node_hash_table) 
		return;
	else {
        	HashWalker hi(*dumper_node_hash_table);
         	while(hi.valid ()) {
             		struct node& n = *(struct node*) hi.key();
             	if(n.permanent == 0 || n.permanent == 3) /* flush deleted nodes */          
                 	dumper_node_hash_table->del(hi.key());
             	hi.advance();                              
         	}                 
     	}     
}     
   
void run()
/*
	run the appropriate stages
*/
{
	Pname n;
	templp = new templ_compilation;  // canonical instance
                                        

	if(dump_tree) {
		dumper_node_hash_table =
			dump_tree_arg.nodes_seen_hash = new pointer_hash (10000);
		dump_tree_arg.verbose = dt_recursive_1;
	}    

	while (n=syn()) {
		if (n == Pname(1)) continue;
		if (n->n_list) PERM(n->tp);

		DB( if(Rdebug>=1) error('d',"run: syn(): '%s'", n->string););
                templp->instantiate_ref_templ();

		for (Pname nx, nn=n; nn; nn=nx) {
			Pname rr;
			++syn_count;
			nx = nn->n_list;
			nn->n_list = 0;

			DB( if(Rdebug>=1) error('d',"run: dcl(): %n, base: %k",nn,nn->base););

			if ((rr=nn->dcl(gtbl,EXTERN))==0
			|| nn->base==0
			|| error_count) continue;

			DB( if(Rdebug>=1) error('d',"run: simpl(): %n",nn););

			nn->simpl();

			if (error_count) {
				if(dump_tree) {
                         		display_cfront_node (dump_tree_arg, nn);
					*dump_tree_arg.output_stream << "---------------------------\n\n";
				}
				continue;
			}

			DB( if(Rdebug>=1) error('d',"run:print(): %n (%k) tp %t",nn,nn->base,nn->tp););

			if (nn->base == TNAME)
				nn->dcl_print(0);
			else {
				Ptype t = nn->tp;
			llxx:
				switch (t->base) {
				case TYPE:
					t = Pbase(t)->b_name->tp; goto llxx;
				case CLASS:
 					DB( if(Rdebug>=1) fprintf(stderr," -- class\n"););
					if (vtbl_opt==1 || gplus_opt) n->dcl_print(0);
					break;
				case ENUM:
 					DB( if(Rdebug>=1) fprintf(stderr," -- enum\n"););
					Penum(n->tp)->dcl_print(0);
					break;
				case FCT:
					DB( if(Rdebug>=1) error('d'," -- fct%n inline %d body %d",nn,Pfct(t)->f_inline,Pfct(t)->body););
					if (Pfct(t)->body==0
					|| (debug_opt==0 && Pfct(t)->f_inline && ((n->n_table!=gtbl) || strcmp(nn->string,"main")))
					|| Pfct(t)->f_imeasure && Pfct(t)->f_inline==0) break;
					DB( if(Rdebug>=1) error('d',"rr %n inline %d body %d",rr,Pfct(rr->tp)->f_inline,Pfct(rr->tp)->body););
					rr->dcl_print(0);
					break;
	
				default:
					DB( if(Rdebug>=1) error('d'," -- %n tpbase: %k",nn,nn->tp->base););
					// print class def, if appropriate
					// can't use tsizeof() since this may
					// print an error if class isn't defined
					{ for(Ptype tx = t;;) {
						switch ( tx->base ) {
						case VEC:
						    tx=Pvec(tx)->typ;
						    continue;
						case TYPE: case COBJ:
						    tx=Pbase(tx)->b_name->tp;
						    continue;
						}
						Pclass cl = Pclass(tx);
						if ( cl->base == CLASS
						&&  (cl->defined&(DEFINED|SIMPLIFIED))
						&&   cl->c_body==1 )
							cl->dcl_print(0);
						break;
					  }
					}
					nn->dcl_print(0);
				}
			}

			if(dump_tree) {
				display_cfront_node (dump_tree_arg, nn);
				*dump_tree_arg.output_stream << "---------------------------\n\n";
			}

			if (error_count) continue;

			DB( if(Rdebug>=1) error('d',"run: cleanup"););
			switch (nn->tp->base) {	// clean up
			default:
			{	
				Pexpr i = nn->n_initializer;
				DB( if(Rdebug>=1) error('d',"default nn %n i %d",nn,i););
				if (i && i!=Pexpr(1)) {
					DEL(i);
					nn->n_initializer = 0;
					if (def_name==0 && rr->n_scope != STATIC) { 
						def_name = rr;
						if (pdef_name == 0) ptbl_init(0);
					}
				}
				break;
			}

			case FCT:
			{	
				Pfct f = Pfct(nn->tp);
				DB( if(Rdebug>=1) error('d', "function nn: %n local_class: %d %d", nn, local_class, f->local_class ););
				if (f->body
				&& f->f_inline==0
				&& f->f_imeasure==0) {
                                        if ( local_class = f->local_class )  { 
						delete_local();
                                        	local_class = 0;
					}

                                        if (ansi_opt && f->f_this) {
                                                f->f_this->n_table = 0;
                                                for (Pname n=f->f_this->n_list; n; n=n->n_list)
                                                        n->n_table = 0;
                                        }

					DEL(f->body);
					if (def_name==0) { 
						def_name = rr;
						if (pdef_name == 0) ptbl_init(0);
					}
				}
				break;
			}

			case CLASS:
			{	Pclass cl = Pclass(nn->tp);
				for (Pname px, p=cl->mem_list; p; p=px) {
				    px = p->n_list;
				    if (p->tp) {
					switch (p->tp->base) {
					case FCT:
					{	Pfct f = (Pfct)p->tp;
						if (f->body) {
							if (f->f_inline==0
							&& f->f_imeasure==0) {
                                        			if ( local_class = f->local_class ) {
									delete_local();
                                        				local_class = 0;
								}
								DEL(f->body);
								f->body = 0;
							}
						}
					}
					case CLASS:
					case ENUM:
						break;
					case COBJ:
					case EOBJ:
						DEL(p);
						break;
					default:
						delete p;
					}
				    } else {
					delete p;
				    }
				} // for
				cl->mem_list = 0;
				cl->permanent = 3;
				break;
			}
			}
			DEL(nn);
		}
		lex_clear();
		if (dump_tree) clean_dumper_hash_table();
	}
	templp->end_of_compilation() ;

	switch (no_of_undcl) {
	case 1:		{error('w',"undeclaredF%n called",undcl);}
	case 0:		break;
	default:	{error('w',"%d undeclaredFs called; for example%n",no_of_undcl,undcl);}
	}

	switch (no_of_badcall) {
	case 1:		{error('w',"%n declaredWoutAs calledWAs",badcall);}
	case 0:		break;
	default:	{error('w',"%d Fs declaredWoutAs calledWAs; for example%n",no_of_badcall,badcall);}
	}

	if (error_count) return;

	int i = 1;
	for (Pname m=gtbl->get_mem(i); m; m=gtbl->get_mem(++i)) {
		if (m->base==TNAME
		|| m->n_sto==EXTERN
		|| m->n_stclass == ENUM) continue;

		Ptype t = m->tp;
		if (t == 0) continue;
		switch (t->base) {
		case CLASS:
		case ENUM:
		case OVERLOAD:	continue;
		case COBJ:
		//case ANON:
		case VEC:	break;
		case FCT:
				if (Pfct(t)->f_inline || Pfct(t)->body==0) continue;
		}

//error('d',&m->where,"%n %d %d %s",m,m->n_addr_taken,m->n_used,m->n_sto==STATIC?"static":"");
//xxx doesn't check anon union members as their use bits are set differently
		if (m->n_addr_taken==0
		&& m->n_used==0
		&& m->n_sto == STATIC) { // (static or anon?)
			for(;;) {
//error('d',&m->where,"  %t tconst(): %d",t,t->tconst());
				if(t->base==TYPE) {
					if(t->tconst()) break;
					t=Pbase(t)->b_name->tp;
				} else if(t->base==VEC) {
					t=Pvec(t)->typ;
				} else {
				    if ( t->tconst() == 0 ) {
//error('d',"m%n tp%t t%t",m,m->tp,t);
					if ( t->base != COBJ )
						error('w',&m->where,"%n defined but not used",m);
					else { Pclass cl;
					    cl = Pclass(Pbase(t)->b_name->tp);
					    if ( cl->has_ctor()==0 )
						if ( cl->csu == ANON )
						 ; //error('w',&m->where,"anonymous union defined but not used");
						else
						    error('w',&m->where,"%n defined but not used",m);
					}
				    } // if const
				    break;
				}
			} // for
		} // if static and not used
	}

        Pname ctor = 0;
	Pname dtor = 0;
	--curloc.line;

	if (st_ilist) {	//	make an "init" function;
			//	it calls all constructors for static objects
		DB( if(Rdebug>=1) error('d',"make sti"); );
		Pname n = new name( st_name("__sti__") );
		Pfct f = new fct(void_type,0,1);
		n->tp = f;
		f->body = new block(st_ilist->where,0,st_ilist);
	//	f->body->s = st_ilist;
		f->body->memtbl = sti_tbl;
		n->n_sto = EXTERN;
		// assignments here are really initializations:
		ignore_const++;
		f->f_linkage = linkage_C;
		f->sign();
		(void) n->dcl(gtbl,EXTERN);
		ignore_const--;
		n->simpl();
		n->dcl_print(0);
		ctor = n;
	}

	if (st_dlist) {	//	make a "done" function;
			//	it calls all destructors for static objects
		DB( if(Rdebug>=1) error('d',"make std"); );
		Pname n = new name( st_name("__std__") );
		Pfct f = new fct(void_type,0,1);
		n->tp = f;
		f->body = new block(st_dlist->where,0,st_dlist);
	//	f->body->s = st_dlist;
		f->body->memtbl = std_tbl;
		n->n_sto = EXTERN;
		f->f_linkage = linkage_C;
		f->sign();
		(void) n->dcl(gtbl,EXTERN);
		n->simpl();
		n->dcl_print(0);
		dtor = n;
	}

#ifdef PATCH
		/*For fast load: make a static "__link" */
	if (ctor || dtor)
	{
		printf("static struct __linkl { struct __linkl * next;\n");
		if ( ansi_opt )
			printf("void (*ctor)(); void (*dtor)(); } __link = \n");
		else
			printf("char (*ctor)(); char (*dtor)(); } __link = \n");
	//	printf("{ (struct __linkl *)0, %s, %s };\n",
	//		ctor_name ? ctor_name : "0",
	//		dtor_name ? dtor_name : "0");
		putstring("{ (struct __linkl *)0, ");
		if (ctor) ctor->print(); else putch('0');
		putch(',');
		if (dtor) dtor->print(); else putch('0');
		putstring("};\n");
	}
#endif

	 DB( if(Rdebug>=1) error( 'd', "run: vlist: %d", vlist ); );
	 do {
		for (vl* v = vlist; v; v = v->next) v->cl->really_print(v->vt);
		vlist = 0;

		for (Plist l=isf_list; l; l=l->l) {
			Pname n = l->f;
			Pfct f = Pfct(n->tp);
DB( if(Rdebug>=1)error('d',"isf %n %t f %d addr %d",n,f,f,n->n_addr_taken); );
			if (f->base == OVERLOAD) {
				n = Pgen(f)->fct_list->f;	// first fct
				f = Pfct(n->tp);
			}

			if (debug_opt==0 && 
				n->n_addr_taken) {
				f->f_inline = 0;
				if (n->n_dcl_printed<2) {
					if (warning_opt)
						error('w',"out-of-line copy of %n created",n);
					n->dcl_print(0);
				}
			}
		}
	} while (vlist);

	if (strict_opt == 0) { // define static members 
		// patch for SysV VAX -g linkage botch
		for (Plist l=stat_mem_list; l; l=l->l) {
			Pname n = l->f;
// error('d',"stat mem %n %d %d ",n,n->n_initializer,n->n_evaluated);
			if (n->n_initializer==0 && n->n_evaluated==0) {
				Ptype t = n->tp;
				n->n_sto = 0;
				Pname cn = t->is_cl_obj();
				if (cn==0) cn = cl_obj_vec;
				if (cn) (void) t->tsizeof();	// be sure to print class
				if ((cn && Pclass(cn->tp)->has_ctor())
				|| t->is_ref())
					; // force explicit definition
				else
					n->dcl_print(0);
			}
		}
	}

	i = 1;
	for (Pname nm=ptbl->get_mem(i); nm; nm=ptbl->get_mem(++i))  {
		DB( if(Rdebug>=1) error('d',"ptbl anme %s string2 %s key:%k",nm->string==0?"???":nm->string2,nm->string2==0?"???":nm->string2,nm->n_key); );
		if ( nm->n_key == 0 ) { // ptbl used in file, generate definition
			int str1 = (*src_file_name)?strlen(src_file_name)+2:0; // +2 for __
  			int str2 = strlen(nm->string2) - str1;
  		        char *ps = new char[ str2 + 1 ];
  			strncpy( ps, nm->string2, str2 ); // grab vtbl name
   			ps[str2]='\0';
			ps[2] = 'v';
        		fprintf(out_file,"extern struct __mptr %s[];\n",ps);
        		// fprintf(out_file,"struct __mptr* %s = %s;\n",nm->string2,ps);
			ptbl_add_pair(nm->string2,ps);
			delete ps;
		}
	}

	ptbl_init(1);
	curloc.putline();
	fprintf(out_file,"\n/* the end */\n");
}


#ifdef DBG
int Adebug = 0;
int Ddebug = 0;
int Edebug = 0;
int Ldebug = 0;
int Mdebug = 0;
int Ndebug = 0;
int Pdebug = 0;
int Rdebug = 0;
int Sdebug = 0;
int Tdebug = 0;
//Ydebug == yydebug initialized in y.tab.c
void
process_debug_flags( char* p )
{
	// arg to +Dxxx or debugging comments //@!xxx
	// format of xxx == sequence of any combination of
	//	+flags  --  increment flags (default)
	//	-flags  --  decrement flags
	//	0flags  --  unset flags
	// where flags are single chars
	int incr = 1;
	char c;
	fprintf(stderr,"\n*** processing debugging flags '%s'\n",p);
	while ( c = *p++ ) {
		switch ( c ) {
		case '+': incr =  1; break;
		case '-': incr = -1; break;
		case '0': incr =  0; break;
		case ' ': break;
		// flags...
		case 'A': if(incr==0) Adebug=0; else Adebug+=incr; break;
		case 'D': if(incr==0) Ddebug=0; else Ddebug+=incr; break;
		case 'E': if(incr==0) Edebug=0; else Edebug+=incr; break;
		case 'L': if(incr==0) Ldebug=0; else Ldebug+=incr; break;
		case 'M': if(incr==0) Mdebug=0; else Mdebug+=incr; break;
		case 'N': if(incr==0) Ndebug=0; else Ndebug+=incr; break;
		case 'P': if(incr==0) Pdebug=0; else Pdebug+=incr; break;
		case 'R': if(incr==0) Rdebug=0; else Rdebug+=incr; break;
		case 'S': if(incr==0) Sdebug=0; else Sdebug+=incr; break;
		case 'T': if(incr==0) Tdebug=0; else Tdebug+=incr; break;
		case 'Y': if(incr==0) Ydebug=0; else Ydebug+=incr; break;
		default: error('w',"unknown debugging flag '%c'",c);
		}
	}
}
#endif /*DBG*/

int no_of_undcl, no_of_badcall;
Pname undcl, badcall;

void pt_option(char * ostr) 
{ // options +O[BTo] for PT
    ostr ++;			/* skip the O */
    switch(*ostr) {
      default:
	fprintf(stderr, "cfront: argument syntax: invalidZizedTs option (+O[BTo].");
	exit(11);
    case 'B':
	tree_dump_brief = 1;
    case 'T':
	dump_tree = 1;
	if(0 == *(ostr + 1) || strcmp (ostr, "T-") == 0)
	    dump_tree_arg.output_stream = (ostream*)&cout;
	else {
	    dump_tree_arg.output_stream
		= new ofstream (ostr+1, ios::out);
	    if(dump_tree_arg.output_stream->fail()) {
		perror ("cfront");
		fprintf (stderr, "Failed to open %s\n", ostr + 1);
		exit (11);
	    }
	}
	break;
      case 'o':
	out_file = fopen (ostr+1, "w");
	if(out_file == NULL) {
	    perror ("cfront");
	    fprintf(stderr, "Failed to open %s\n", ostr+1);
	    exit(11);
	}
	break;
    }
}

main(int argc, char* argv[])
/*
	read options, initialize, and run
*/
{
	register char * cp;
	char* afile = "";
#ifdef unix

#ifdef COMPLETE_SIG_PF
        signal(SIGILL,core_dump);
        signal(SIGIOT,core_dump);
        signal(SIGEMT,core_dump);
        signal(SIGFPE,core_dump);
        signal(SIGBUS,core_dump);
        signal(SIGSEGV,core_dump);
#else
	typedef void (*ST)(int ...);	// trick to circumvent problems with old
	ST sick = ST(&signal);		// (or C) versions <signal.h>
	(*sick)(SIGILL,core_dump);
	(*sick)(SIGIOT,core_dump);
	(*sick)(SIGEMT,core_dump);
	(*sick)(SIGFPE,core_dump);
	(*sick)(SIGBUS,core_dump);
	(*sick)(SIGSEGV,core_dump);

#endif
#endif

// SUM: not needed
// #ifdef apollo
//	set_sbrk_size(1000000);	// resets free store size
//#else
#ifndef apollo
	//(void) malloc(0);	// suppress cashing in V8 malloc
#endif

	error_init();

	for (int i=1; i<argc; ++i) {
		switch (*(cp=argv[i])) {
		case '+':
			while (*++cp) {
				switch(*cp) {
				case 'O':   
					pt_option(cp);
					goto xx;
				case 'f':
					src_file_name = cp+1;
					goto xx;
				case 'x':	// read cross compilation table
					if (read_align(afile = cp+1)) {
						fprintf(stderr,"bad size-table (option +x)\n");
						exit(11);
					}
					goto xx;
				case 'e':
					switch (*++cp) {
					case '0':
					case '1': 
						vtbl_opt = *cp-'0';
						break;
					default:
						fprintf(stderr,"bad +e option\n");
						exit(11);
					}
					break;
				case 'd':
					debug_opt = 1;
					break;
				case 'g':
					gplus_opt = 1;
					break;
				case 'D':
#ifdef DBG
					process_debug_flags(++cp);
#else
					error('w',"cfront not compiled for debugging -- +D%s ignored",++cp);
#endif
					goto xx;
				case 'w':
					warning_opt = 1;
					break;
				case 'a':
					switch (*++cp) {
					case '0':
					case '1': 
						ansi_opt = *cp-'0';
						break;
					default:
						fprintf(stderr,"bad +a option\n");
						exit(11);
					}
					break;
				case 'p':
					strict_opt = 1;
					break;
				case 'L':
					line_format = "\n#line %d \"%s\"\n";
					break;
				default:
					fprintf(stderr,"%s: unexpected option: +%c ignored\n",prog_name,*cp);

				}
			}
		xx:
			break;
		default:
			fprintf(stderr,"%s: bad argument \"%s\"\n",prog_name,cp);
			exit(11);
		}
	}


	fprintf(out_file,line_format+1,1,src_file_name); // strips leading \n
	fprintf(out_file,"\n/* %s */\n",prog_name);
	if (*src_file_name) fprintf(out_file,"/* < %s > */\n",src_file_name);

//	if (Nspy) {
//		start_time = time(0);
//		print_align(afile);
//	}
	fflush(stderr);
	otbl_init();
	lex_init();
	syn_init();
	typ_init();
	simpl_init();
	scan_started = 1;
	curloc.putline();
	if ((BI_IN_BYTE==0) && (SZ_INT==0) && (SZ_WPTR==0))
		error("no size/alignment values - use +x of provide #ifdef in size.h");
	run();
	if(dump_tree) {
    		ostream_printf(*dump_tree_arg.output_stream, "------------ GTBL ------------\n\n");
    		display_cfront_node (dump_tree_arg, ktbl);
    		ostream_printf(*dump_tree_arg.output_stream, "------------ KTBL ------------\n\n");
    		display_cfront_node (dump_tree_arg, ktbl);
	}                                              

//	if (Nspy) {
//		stop_time = time(0);
//		spy(src_file_name);
//	}
	exit( (0<=error_count && error_count<127) ? error_count : 127);
}

char* st_name(char* pref)
/*
	make name "pref|source_file_name|_" or "pref|source_file_name|_"
	where non alphanumeric characters are replaced with '_'
	and add def_name at end to ensure uniqueness
*/
{
	int prefl = strlen(pref);
	int strl = prefl + 2;	// trailing '_' and 0
	if (*src_file_name) strl += strlen(src_file_name);
	char* defs;
	int defl;
	if (def_name) {
		defs = def_name->string;
		defl = strlen(defs)+1;	// '_'
	}
	else {
		defs = 0;
		defl = 0;
	}
	char* name = new char[strl+defl];
	strcpy(name,pref);
	if (*src_file_name) strcpy(name+prefl,src_file_name);
	name[strl-2] = '_';
	name[strl-1] = 0;
//	char *p = name;
//	while ( *++p ) if (!isalpha(*p) && !isdigit(*p)) *p = '_';
	for (char* p = name; *p; p++) if (!isalpha(*p) && !isdigit(*p)) *p = '_';
	if (defs) {
		strcpy(name+strl-1,defs);	// after the '_'
		name[strl+defl-2] = '_';
		name[strl+defl-1] = 0;
	}
#ifdef DENSE
	void chop(char*);
	chop(name);
#endif

	return name;
}
0707071010112041141004440001630000160000010112640466055427400001100000007532makefile#ident	"@(#)ctrans:src/makefile	1.3"
###############################################################################
#			Copyright (c) 1984 AT&T
#	  		  All Rights Reserved  	
#
#	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
#	
#	The copyright notice above does not evidence any   	
#	actual or intended publication of such source code.
#
###############################################################################
CC	=	CC

#The ANSI_OUT option has been replaced by the +a1 and +a0 compilation options

#for systems which only recognize identifiers of up to 31 characters
#setting DENSE to -DDENSE causes cfront to generate internal names
#of 31 characters or less 
DENSE=

# The use of RETBUG is nolonger needed with version 2.0 and has been removed.
# RETBUG was used in 1.* Translator versions to circumvent a C compiler bug.

CCFLAGS=-O

# top level makefile modifies the following
MPMACRO	= PATCH
MPFILE	= patch

OFILES	=	alloc.o dcl.o dcl2.o dcl3.o dcl4.o del.o \
		discrim.o doprint.o error.o expand.o \
		expr.o expr2.o expr3.o find.o hash.o lalex.o lex.o main.o \
		norm.o norm2.o print.o print2.o print_self.o repr.o simpl.o \
		simpl2.o size.o table.o template.o tree_copy.o tree_dump.o \
		tree_walk.o typ.o typ2.o y.tab.o 

cfront:	$(OFILES)
	$(CC)	-o cfront $(CCFLAGS) $(OFILES)

$(OFILES):	cfront.h token.h typedef.h

y.tab.c:	gram.y 
	yacc gram.y

alloc.o:	alloc.c
	$(CC) $(CCFLAGS) -c alloc.c 

dcl.o:	dcl.c size.h
	$(CC) $(CCFLAGS) -c dcl.c 

dcl2.o:	dcl2.c size.h
	$(CC) $(CCFLAGS) -c dcl2.c 

dcl3.o:	dcl3.c size.h
	$(CC) $(CCFLAGS) -c dcl3.c 

dcl4.o:	dcl4.c size.h
	$(CC) $(CCFLAGS) -c dcl4.c 

del.o:	del.c
	$(CC) $(CCFLAGS) -c del.c 

discrim.o:	discrim.c cfront.h
	$(CC) $(CCFLAGS) -c discrim.c

doprint.o:	doprint.c
	$(CC) $(CCFLAGS) -c doprint.c

error.o:	error.c size.h
	$(CC) $(CCFLAGS) -c error.c 

expand.o:	expand.c
	$(CC) $(CCFLAGS) -c expand.c 

expr.o:	expr.c size.h
	$(CC) $(CCFLAGS) -c expr.c 

expr2.o:	expr2.c size.h
	$(CC) $(CCFLAGS) -c expr2.c 

expr3.o:	expr3.c size.h
	$(CC) $(CCFLAGS) -c expr3.c 

find.o:	find.c 
	$(CC) $(CCFLAGS) -c find.c 

hash.o: hash.c hash.h
	$(CC) $(CCFLAGS) -c hash.c 

lalex.o:lalex.c yystype.h tqueue.h 
	$(CC) $(CCFLAGS) -c lalex.c

lex.o:	lex.c size.h tqueue.h yystype.h
	$(CC) $(CCFLAGS) -c lex.c 

# main depends on this makefile to force recompilation
# when going from patch to munch
main.o:	main.c makefile
	$(CC) -D$(MPMACRO) $(DENSE) $(CCFLAGS) -c main.c 

norm.o:	norm.c size.h
	$(CC) $(CCFLAGS) -c norm.c 

norm2.o:	norm2.c size.h
	$(CC) $(CCFLAGS) -c norm2.c 

print.o:	print.c
	$(CC) $(CCFLAGS) -c print.c 

print2.o:	print2.c
	$(CC) $(DENSE) $(CCFLAGS) -c print2.c 

print_self.o:   print_self.c
	$(CC) $(CCFLAGS) -c print_self.c 

repr.o:	repr.c
	$(CC) $(CCFLAGS) -c repr.c 

simpl.o:	simpl.c size.h
	$(CC) $(CCFLAGS) -c simpl.c 

simpl2.o:	simpl2.c size.h
	$(CC) $(CCFLAGS) -c simpl2.c 

size.o:	size.c size.h
	$(CC) $(CCFLAGS) -c size.c 

table.o:	table.c
	$(CC) $(CCFLAGS) -c table.c 

template.o: template.c
	$(CC) $(CCFLAGS) -c template.c 

tree_copy.o: tree_copy.c
	$(CC) $(CCFLAGS) -c tree_copy.c 

tree_dump.o:    tree_dump.c cfront.h
	$(CC) $(CCFLAGS) -c tree_dump.c

tree_walk.o: tree_walk.c
	$(CC) $(CCFLAGS) -c tree_walk.c 

typ.o:	typ.c size.h
	$(CC) $(CCFLAGS) -c typ.c 

typ2.o:	typ2.c size.h
	$(CC) $(CCFLAGS) -c typ2.c 

y.tab.o:	y.tab.c size.h 
	$(CC) -DGRAM $(CCFLAGS) -c y.tab.c 

cpio:	
	ls alloc.c dcl.c dcl2.c dcl3.c dcl4.c del.c discrim.c doprint.c \
		error.c expand.c expr.c expr2.c expr3.c find.c hash.c \
		lalex.c lex.c main.c norm.c norm2.c print.c print2.c \
		print_self.c repr.c simpl.c simpl2.c size.c table.c \
		template.c tree_copy.c tree_dump.c tree_walk.c typ.c typ2.c \
		gram.y \
		cfront.h token.h size.h tqueue.h typedef.h yystype.h \
		hash.h ios_printf.h node_classes.h print_self.h \
		template.h token_names.h tree_copy.h tree_dump.h tree_walk.h \
		makefile | cpio -oc > cfront.cpio

0707071010112046101004440001630000160000010212500466055421000001700000012215node_classes.h/* ident "@(#)ctrans:src/node_classes.h	1.2" */
/* 
 * node_classes.h 
 */

#ifndef _node_classes
#define _node_classes

enum discriminator_error {
    discrim_none_valid = 0,
    discrim_bad_index = -1,
    discrim_inconsistent_node = -2,
};

enum node_class {
    nc_unused = 0,
    nc_eof = 1,
    nc_virt = 2,
    nc_nlist = 3,
    nc_gen = 4,
    nc_vec = 5,
    nc_ptr = 6,
    nc_fct = 7,
    nc_table = 8,
    nc_basetype = 9,
    nc_name = 10,
    nc_expr = 11,
    nc_stmt = 12,
    nc_enumdef = 13,
    nc_classdef = 14,
    nc_baseclass = 15,
    nc_iline = 16,
    nc_ia = 17,
};
    
/* 
	searching this is slower than a directly indexed array,
	but this is more maintainable. We can speed it up later. 
*/

#ifdef DEFINE_TOKEN_CLASS_TABLE
struct token_class {
    TOK token;
    node_class nclass;
} token_classes[] = {
    { EOFTOK, nc_eof },
    { ASM, nc_stmt },
    { AUTO, nc_basetype },
    { BREAK, nc_stmt },
    { CASE, nc_stmt },
    { CHAR, nc_basetype },
    { CLASS, nc_classdef },
    { CONTINUE, nc_stmt },
    { DEFAULT, nc_stmt },
    { DELETE, nc_expr },
    { DO, nc_stmt },
    { DOUBLE, nc_basetype },
    { ELSE, nc_stmt },
    { ENUM, nc_enumdef },
    { EXTERN, nc_basetype },
    { FLOAT, nc_basetype },
    { FOR, nc_stmt },
    { FORTRAN, nc_unused },
    { FRIEND, nc_basetype },
    { GOTO, nc_stmt },
    { IF, nc_stmt },
    { INT, nc_basetype },
    { LONG, nc_basetype },
    { NEW, nc_expr },
    { OPERATOR, nc_fct },
    { RETURN, nc_stmt },
    { PUBLIC, nc_name },
    { CONST, nc_basetype },
    { REGISTER, nc_basetype },
    { RETURN, nc_stmt },
    { SHORT, nc_basetype },
    { SIZEOF, nc_expr },
    { STATIC, nc_basetype },
    { STRUCT, nc_unused },
    { SWITCH, nc_stmt },
    { THIS, nc_expr },
    { TYPEDEF, nc_basetype },
    { UNION, nc_unused },
    { UNSIGNED, nc_basetype },
    { VOID, nc_basetype },
    { WHILE, nc_stmt },
    { LP, nc_unused },
    { RP, nc_unused },
    { LB, nc_unused },
    { RB, nc_unused },
    { REF, nc_expr },
    { DOT, nc_expr },
    { NOT, nc_expr },
    { COMPL, nc_expr },
    { INCR, nc_expr },
    { DECR, nc_expr },
    { MUL, nc_expr },
    { DIV, nc_expr },
    { AND, nc_expr },
    { MOD, nc_expr },
    { PLUS, nc_expr },
    { MINUS, nc_expr },
    { LS, nc_expr },
    { RS, nc_expr },
    { LT, nc_expr },
    { LE, nc_expr },
    { GT, nc_expr },
    { GE, nc_expr },
    { EQ, nc_expr },
    { NE, nc_expr },
    { ER, nc_expr },
    { OR, nc_expr },
    { ANDAND, nc_expr },
    { OROR, nc_expr },
    { QUEST, nc_expr },
    { COLON, nc_unused },
    { ASSIGN, nc_expr },
    { CM, nc_expr },
    { SM, nc_stmt },
    { SM_PARAM, nc_stmt },
    { LC, nc_unused },
    { RC, nc_unused },
    { INLINE, nc_fct },
    { OVERLOAD, nc_gen },
    { VIRTUAL, nc_fct },	/* but might be a basecl */
    { COERCE, nc_unused },
    { PROTECTED, nc_name },
    { ID, nc_unused },
    { STRING, nc_expr },
    { ICON, nc_expr },
    { FCON, nc_expr },
    { CCON, nc_expr },
    { NAME, nc_name },		/* but might be basecl */
    { ZERO, nc_expr },
    { ASOP, nc_expr },
    { RELOP, nc_expr },
    { EQUOP, nc_expr },
    { DIVOP, nc_expr },
    { SHIFTOP, nc_expr },
    { ICOP, nc_expr },
    { UNOP, nc_expr },
    { TYPE, nc_basetype },
    { UMINUS, nc_expr },
    { FCT, nc_fct },
    { CALL, nc_expr },
    { VEC, nc_vec },
    { DEREF, nc_expr },
    { ADDROF, nc_expr },
    { CAST, nc_expr },
    { FIELD, nc_basetype },
    { LABEL, nc_stmt },
    { BLOCK, nc_stmt },
    { DCL, nc_stmt },
    { COBJ, nc_basetype },
    { EOBJ, nc_basetype },
    { TNAME, nc_name },
    { ILIST, nc_expr },
    { PTR, nc_ptr },
    { ASPLUS, nc_expr },
    { ASMINUS, nc_expr },
    { ASMUL, nc_expr },
    { ASDIV, nc_expr },
    { ASMOD, nc_expr },
    { ASAND, nc_expr },
    { ASOR, nc_expr },
    { ASER, nc_expr },
    { ASLS, nc_expr },
    { ASRS, nc_expr },    
    { ARG, nc_basetype },
    { ZTYPE, nc_basetype },
    { ARGT, nc_basetype },
    { ELIST, nc_expr },
    { ANY, nc_basetype },
    { TABLE, nc_table },
    { LOC, nc_unused },
    { DUMMY, nc_expr },
    { G_ADDROF, nc_expr },
    { G_CALL, nc_expr },
    { G_CM, nc_expr },
    { IVAL, nc_expr },
    { ELLIPSIS, nc_unused },
    { AGGR, nc_unused },
    { RPTR, nc_ptr },
    { HIDDEN, nc_unused },
    { MEM, nc_expr },
    { CTOR, nc_unused },
    { DTOR, nc_unused },
    { CONST_PTR, nc_ptr },
    { CONST_RPTR, nc_ptr },
    { TEXT, nc_expr },
    { PAIR, nc_stmt },
    { ANON, nc_unused },
    { ICALL, nc_expr },
    { ANAME, nc_expr },
    { VOLATILE, nc_basetype },
    { SIGNED, nc_basetype },
    { UPLUS, nc_expr },
    { MEMPTR, nc_unused },
    { PRIVATE, nc_name },
    { PR, nc_unused },
    { MDOT, nc_expr },
    { TSCOPE, nc_unused },
    { DECL_MARKER, nc_unused },
    { REFMUL, nc_expr },
    { LDOUBLE, nc_basetype },
    { LINKAGE, nc_unused },
    { LOCAL, nc_basetype },
    { GNEW, nc_expr },
    { TEMPLATE, nc_unused },
    { STAT_INIT, nc_unused },
    { CATCH, nc_unused },
    { GDELETE, nc_expr },
    { XVIRT, nc_virt },
    { XNLIST, nc_nlist },
    { XILINE, nc_iline },
    { XIA, nc_ia },
    { VALUE, nc_expr },
    { XDELETED_NODE, nc_unused },
};
#endif

node_class classify_node (Pnode, int&);
node_class classify_node (Pnode);

#endif
0707071010112044361004440001630000160000010204500466055405300000700000120447norm.c/*ident	"@(#)ctrans:src/norm.c	1.10" */
/************************************************************************

	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.

norm.c:

	"normalization" handles problems which could have been handled
	by the syntax analyser; but has not been done. The idea is
	to simplify the grammar and the actions accociated with it,
	and to get a more robust error handling

****************************************************************************/
#ifdef c_plusplus
overload nested_hide;
#endif

#include "cfront.h"
#include "size.h"
#include "template.h"

extern Pname do_nested_type(Pname);
extern int is_anon(char*);

Pname sta_name = 0;

void syn_init()
{
	any_type = new basetype(ANY,0);
	PERM(any_type); any_type->defined = DEFINED;
	dummy = new expr(DUMMY,0,0);
	PERM(dummy);
	dummy->tp = any_type;
	zero = new expr(ZERO,0,0);
	PERM(zero);
	sta_name = new name;
	PERM(sta_name);
//	Gtbl = new table(GTBLSIZE,0,0); //SYM
//	Ctbl = Gtbl; //SYM
}

int stcount;

char* make_name(TOK c)
{
	char* s = new char[8];	// as it happens: fits in two words

	if (10000 <= ++stcount) error('i',"too many generatedNs");

	sprintf(s,"__%c%d",c,stcount);
	return s;
}

Pbase basetype::type_adj(TOK t)
{
DB(if(Ndebug>=1)error('d',"'%k'->type_adj(%k) --%t b_xname%n",base,t,this,b_xname););
	if (b_xname) {
		if (base)
			error("badBT:%n%k",b_xname,t);
		else {
			base = TYPE;
			b_name = b_xname;
		}
		b_xname = 0;
	}

	switch (t) {
	case TYPEDEF:	b_typedef = 1;	break;
	case INLINE:	b_inline = 1;	break;
	case VIRTUAL:	b_virtual = 1;	break;
	case CONST:	if (b_const) error('w',"two const declarators");
			b_const = 1;	break;
	case UNSIGNED:	b_unsigned = 1;	break;
	case SHORT:	b_short = 1;	break;
	case LONG:	if (b_long) error('w',"two long declarators");
			if (base == DOUBLE)
				base = LDOUBLE;
			else
				b_long = 1;
			break;
	case FRIEND:
	case OVERLOAD:
	case EXTERN:
	case STATIC:
	case AUTO:
	case REGISTER:
		if (b_sto)
			error("badBT:%k%k",b_sto,t);
		else
			b_sto = t;
		break;
	case DOUBLE:
		if (b_long) {
			t = LDOUBLE;
			b_long = 0;
		}
		// no break
	case VOID:
	case CHAR:
	case INT:
	case FLOAT:
		if (base)
			error("badBT:%k%k",base,t);
		else
			base = t; 
		break;
	case SIGNED:
	case VOLATILE:
		error('w',"\"%k\" not implemented (ignored)",t);
		break;
	default:
		error('i',"BT::type_adj(%k)",t);
	}
	return this;
}

Pbase basetype::name_adj(Pname n)
{
DB(if(Ndebug>=1)error('d',"'%k'->name_adj(%n) --%t b_xname%n",base,n,this,b_xname));
	if (b_xname) {
		if (base)
			error("badBT:%n%n",b_xname,n);
		else {
			base = TYPE;
			b_name = b_xname;
		}
		b_xname = 0;
	}

	if ( base==0 
 		&& n->base == TNAME 
 		&& ( n->tp->base!=COBJ || in_arg_list )) {
 			base = TYPE;
 			b_name = n;
	}
	else
		b_xname = n;

	return this;
}

static TOK type_set( Pbase b )
{
	TOK t = 0;

	if ( b->b_long ) t = LONG;
	else if ( b->b_short ) t = SHORT;
	else if ( b->b_unsigned ) t = UNSIGNED;
	else if ( b->b_inline ) t = INLINE;
	else if ( b->b_virtual ) t = VIRTUAL;
	else if ( b->b_sto == OVERLOAD ) t = OVERLOAD;
	return t;
}

int declTag = 1;

Pbase basetype::base_adj(Pbase b)
{
DB(if(Ndebug>=1)error('d',"'%k'->base_adj(%t) --%t b_xname%n",base,b,this,b_xname));
	Pname bn = b->b_name;

	switch (base) {
	case COBJ:
	case EOBJ:
		error("NX after%k%n",base,b_name);
		return this;
	}

	TOK t;
	if (base) {
		if (b_name)
			error("badBT:%k%n%k%n",base,b_name,b->base,bn);
		else
			error("badBT:%k%k%n",base,b->base,bn);
	}
	else if ( t = type_set(this)) {
		if (b_name)
			error("badBT:%k%n%k%n",t,b_name,b->base,bn);
		else {
                        if ( declTag++ && (t!= INLINE)) error("badBT:%k%k%n",t,b->base,bn);
			base=b->base; b_name = bn;
// error('d',"base_adj: t: %k", t );
		}
	}
	else {
		base = b->base;
		b_name = bn;
		b_table = b->b_table;
	}

	if ( b->base == COBJ ) {
		Pclass cl = Pclass(bn->tp);
		if ( cl->in_class && 
			bn->tpdef &&
			bn->tpdef->lex_level == NESTED ) 
		{ // peculiar case: class x { typedef class bn {} _bn; ... 
		  // bn has been half dealt with in do_nested_type ...
			Pname n = new name(bn->string);
			n->tp = b;
			Pname nn = ktbl->insert(n, NESTED); //SYM
			nn->tpdef = bn->tpdef;
			nn->tpdef->lex_level = nn->lex_level = 0;
			bn->tpdef = 0;
		}
	}

	return this;
}

Pbase basetype::check(Pname n)
/*
	"n" is the first name to be declared using "this"
	check the consistency of "this"
	and use "b_xname" for "n->string" if possible and needed
*/
{
	b_inline = 0;
	b_virtual = 0;
//error('d',"basetype::check(%n) base %k b_xname %n",n,base,b_xname);

	if (b_xname && (n->tp || n->string)) {
		if (base)
			error("badBT:%k%n",base,b_xname);
		else {
			base = TYPE;
			b_name = b_xname;
		}
		b_xname = 0;
	}

	if (b_xname) {
		if (n->string)
			error("twoNs inD:%n%n",b_xname,n);
		else {
			n->string = b_xname->string;
			b_xname->hide();
		}
		b_xname = 0;
	}

	if (ccl==0
	&& n
	&& n->n_oper==TNAME
	&& n->n_qualifier==0
	&& n->string) {	// hide type name
		Pname nx = ktbl->look(n->string,0); //SYM
		if (nx) nx->hide();
	}

	int defa = 0;
	switch (base) {
	case 0:
		defa = 1;
		base = INT;
		break;
	case EOBJ:
	case COBJ:
		if (b_name->base == TNAME) error('i',"TN%n inCO %p",b_name,this);
	}

	if (b_long || b_short) {
		TOK sl = (b_short) ? SHORT : LONG;
		if (b_long && b_short) error("badBT:long short%k%n",base,n);
		if (base != INT)
			error("badBT:%k%k%n",sl,base,n);
		else
			base = sl;
		b_short = b_long = 0;
	}

	if (b_typedef && b_sto) error("badBT:Tdef%k%n",b_sto,n);
	b_typedef = b_sto = 0; 

	if (b_linkage) {
		if (1 <= bl_level) error("local linkage directive");
	}

	if (Pfctvec_type == 0) return this;

	if (b_const) {
		if (b_unsigned) {
			switch (base) {
			default:
				error("badBT: unsigned const %k%n",base,n);
				b_unsigned = 0;
			case LONG:
			case SHORT:
			case INT:
			case CHAR:
				return this;
			}
		}
		return this;
	}
	else if (b_unsigned) {
		switch (base) {
		case LONG:
			delete this;
			return ulong_type;
		case SHORT:
			delete this;
			return ushort_type;
		case INT:
			delete this;
			return uint_type;
		case CHAR:
			delete this;
			return uchar_type;
		default:
			error("badBT: unsigned%k%n",base,n);
			b_unsigned = 0;
			return this;
		}
	}
	else {
		switch (base) {
		case LONG:
			delete this;
			return long_type;
		case SHORT:
			delete this;
			return short_type;
		case INT:
                        if (this==int_type || this==defa_type) return this;
                //      if (this != int_type)
                                delete this;
                        if (defa) return defa_type;
                        return int_type;
		case CHAR:
			delete this;
			return char_type;
		case VOID:
			delete this;
			return void_type;
		case TYPE:
			/* use a single base saved in the keyword */
			if (b_name->n_qualifier) {
				Pbase rv = Pbase(b_name->n_qualifier);
				delete this;
				return rv;
			}
			else {
				PERM(this);
				b_name->n_qualifier = (Pname)this;
				return this;
			}
		default:
			return this;
		}
	}
}

Pname basetype::aggr()
/*
	"type SM" seen e.g.	struct s {};
				class x;
				enum e;
				int tname;
				friend cname;
				friend class x;
				int;
				
				typedef int i; // where i is tname

	convert
		union { ... };
	into
		union name { ... } name ;
*/
{
DB(if(Ndebug>=1)error('d',"'%k'->aggr() --%t b_xname%n ccl%t",base,this,b_xname,ccl));
	if (b_xname) {
		if (base) {
			Pname n = new name(b_xname->string);
		/*SYM?*/if (ccl && b_xname->tpdef)
		/*SYM?*/	n->tpdef = b_xname->tpdef;
                        b_xname->hide();
                        b_xname = 0;
			return n->normalize(this,0,0);
		}
		else {
			base = TYPE;
			b_name = b_xname;
			b_xname = 0;
		}
	}

	switch (base) {
	case COBJ:
	{	Pclass cl = Pclass(b_name->tp);
		char* s = cl->string;
	/*SYM?*/if (b_name->base == TNAME) error('i',"TN%n inCO",b_name);
		if (b_const) error("const%k%n",cl->csu,b_name);

		if (cl->c_body == 2) {	/* body seen */
			if (s[0]=='_' && s[1]=='_' && s[2]=='C') {
				char* ss = new char[8];	// max size of generated name is 7 chars, see make_name()
				Pname obj = new name(ss);
				strcpy(ss,s);
				if (cl->csu == UNION) {
					ss[2] = 'O';
					cl->csu = ANON;
					return obj->normalize(this,0,0);
				}
				error('w',"unusable%k ignored",cl->csu);
			}
			if ( b_sto == FRIEND )
				error("friend%k%n{...}",cl->csu,b_name);
			cl->c_body = 1;
			return b_name;
		}
		else {	/* really a typedef for cfront only: class x; */
			if (b_sto == FRIEND) goto frr;
			if (ansi_opt) printf("struct %s;\n",s);
			return 0;
		}
	}

	case EOBJ:
	{	Penum en = Penum(b_name->tp);
	/*SYM?*/if (b_name->base == TNAME) error('i',"TN%n in enumO",b_name);
		if (b_const) error("const enum%n",b_name);
		if (en->e_body == 2) {
			en->e_body = 1;
			return b_name;
		}
		else {
			error("forwardD of enum%n", b_name);
			en->e_type = int_type;
		}
		return 0;
	}

	case 0:
	{	Pname n = new name(make_name('D'));
		n->tp = defa_type;
		error("NX inDL");
		return n;
	}	
	default:
		if (b_typedef) error('w',"illegalTdef ignored");

		if (b_sto == FRIEND && b_name ) {
		frr:
			Pname fr = ktbl->look(b_name->string,0); //SYM
			if (fr == 0) error('i',"cannot find friend%n",b_name);
			Pname n = new name(b_name->string);
			n->n_sto = FRIEND;
			// If it is a parameterized type, use the instantiation 
			// type, not the general type.
			if ((fr->tp->base == COBJ) && 
			    (Pclass(Pbase(fr->tp)->b_name->tp)->class_base ==
			     	template_class))
			{
			    if (base == COBJ) 
				n->tp = this;
			    else 
			    if ((base == TYPE) &&
			        (Pbase(this)->b_name->base == TNAME) &&
			        (Pbase(this)->b_name->tp->base == COBJ))
			      		n->tp = Pbase(this)->b_name->tp;
			    else 
				error('i', "basetype wasn't a COBJ");
		        }
			else n->tp = fr->tp;
			return n;
		}
		else {
			Pname n = new name(make_name('D'));
			n->tp = defa_type;
			error('w',"NX inDL");
			return n;
		}
	}
}

void local_name() //SYM -- to be removed
{ /* need to provide an additional temporary name
   * to handle case of
   * f() {
   *	 { class x{...}; }
   *	 { class x{...}; }
   * }
   * generate name after closing } of block
   * to distinquish between separate blocks at same lexical level 
   */
	for (Plist l=local_blk; l; l=l->l) {
		Pname n = l->f;
		if ( n->tp == 0 ) error( 'i', "no tp yet: #0 local_name" );
		if ( Pbase(n->tp)->b_name == 0 ) error( 'i', "no tp yet: #1 local_name" );
		Pname bn = Pbase(n->tp)->b_name;
		if ( bn->tp == 0 ) error( 'i', "no tp yet#2: local_name" );
		Pclass cl = Pclass(bn->tp);
                cl->lcl = make_name( 'L' );
// error( 'd', "local_name(): %n bn: %n: cl : %s nof: %d", n, bn, cl->string, cc->nof );
        }
}

void local_restore() //SYM -- to be removed
{
	for (Plist l=local_tn; l; l=l->l) {
		Pname n = l->f;
// error('d',"local_restore: n %n %t %d bl_level: %d", n, n->tp, n->lex_level, bl_level );
		n->n_key = (n->lex_level==0) ? 0 
			: (n->lex_level && n->lex_level<=bl_level) ? LOCAL : HIDDEN;
	}
}

void local_hide( Pname n ) //SYM -- to be removed
{
// error('d',"local_hide(%n )",n);

   if ( n->base != TNAME ) return; 
   if ( n->n_key == 0 ) {
        local_tn = new name_list( n, local_tn );
        n->n_key = HIDDEN;
// error( 'd', "local_hide(): %n n_key: %d", n, n->n_key );
   }
}

void 
nested_restore() //SYM -- to be removed
{
	for (Plist l = nested_type; l; l=l->l)
	{
		Pname n = l->f;
		n->n_key = NESTED;
	}
		
	for (l=nested_tn; l; l=l->l) {
		Pname n = l->f;
		Ptype tp = n->tp;
// error('d',"nested_restore: n %n %t %d bl_level: %d", n, n->tp, n->lex_level, bl_level );
// error('d'," --- n_key %k", n->n_key );

		if ( tp->in_class ) 
			n->n_key = NESTED;
		else
		if ( tp->lex_level )
			n->n_key = LOCAL;
		else 
			n->n_key = 0;
// error('d'," --- n_key %k", n->n_key );
	}
}

void 
nested_hide( Pname n ) //SYM -- to be removed
{
// error('d',"nested_hide(%n )",n);

   if ( n->base != TNAME ) return; 
   if ( n->n_key == 0 ) {
        nested_tn = new name_list( n, nested_tn );
        n->n_key = HIDDEN;
// error( 'd', "nested_hide(): %n n_key: %d", n, n->n_key );
   }
}

static void 
nested_hide( Plist l ) //SYM -- to be removed
{
// error('d',"nested_hide( list )");

	for (; l; l=l->l) {
		Pname nn = l->f;
		Pname n = ktbl->look(nn->string,0);
// error('d',"nested_hide %n %t", n, n->tp, n->n_key);
		if (n==0) continue;

   		if ( n->base != TNAME ) 
			error('i', "nested_hide: %n not a type name (%t)", n, n->tp );
   		if ( n->n_key == 0 ) {
        		nested_tn = new name_list( n, nested_tn );
        		n->n_key = HIDDEN;
// error( 'd', "nested_hide(list): %n n_key: %d", n, n->n_key );
//		nn->n_key = 0;
		}
   	}
}

int defer_check = 0;
Pname statStat = 0;

void name::hide()
/*
	hide "this": that is, "this" should not be a keyword in this scope
*/
{
	if (base != TNAME) return;
// error('d',"'%n '->hide() -- %t lex_level %d bl_level %d",this,tp,lex_level,::bl_level);
	if (n_key == 0) {
                if (lex_level == bl_level && in_arg_list == 0) {
			if (tp->base != COBJ) { 
				if ( !in_typedef ) 
     				     error("%n redefined: typedef and identifier", this);
				else if ( in_typedef->base 
						&& tp->base != type_set(Pbase(in_typedef)) 
						&& in_typedef->check(tp,0) ) {
							if ( defer_check == 0 )
     								error("%n redefined: previous: %t now: %t", this, tp, in_typedef);
				} 
			} 
			else {
//error('d',"in_typedef%t %d tp%t %d",in_typedef,in_typedef,tp,tp);
//error('d',"in_typedef%k tp%k",in_typedef->base,tp->base);
				if ( in_typedef && in_typedef->base
				&&   in_typedef->check(tp, 0) ) {
					if ( defer_check == 0 )
						error( "%n redefined: previous: %t now: %t", this, tp, in_typedef);
				}
				else {
					Pname nn = Pbase(tp)->b_name;
					Pclass cl = Pclass( nn->tp );
					// check for 'typedef class X X;'
					//       and 'typedef X X;'
					if ( in_typedef )
					    while ( in_typedef->base == TYPE )
						in_typedef = Pbase(in_typedef)->b_name->tp;
					if ( in_typedef
					&&   in_typedef->base==COBJ
					&&   Pbase(in_typedef)->b_name->tp==cl )
						in_typedef = tp;
					else if ( cl->has_ctor() )
						error( "%n redefined: both aCNWK and %s", this, in_typedef?"a type name":"an identifier" );
				}
			}

                }
// error( 'd', "%n::hide", this );
		modified_tn = new name_list(this,modified_tn);
		n_key = HIDDEN;
	}
}

static Pname Ntncheck; // ensure TNAMES hidden within class scopes
static int notReally = 0;

void set_scope(Pname tn) //SYM -- to be shrunk
/* enter the scope of class tn after seeing "tn::f" */
{
// error( 'd', "set_scope: %n %t %d", tn, tn->tp, tn->tp->base );
// error( 'd', "set_scope: %d", notReally );

	Pbase b = Pbase(tn->tp);
	while ( b->base == TYPE )  b=Pbase(b->b_name->tp);  // typedef class X T
	if (b->base != COBJ) return; // error caught elsewhere

	Pclass cl = Pclass(b->b_name->tp);
	char *str = cl->string;

	if ( cl->nest_list && notReally == 0 ) { 
		nested_type = cl->nest_list; 
		nested_hide(cl->nest_list); 
	}

	Pname ntn = Ntncheck;
	if( notReally == 0 )
	    while ( ntn && ntn->tp->base == TYPE ) ntn = Pbase(ntn->tp)->b_name;

	if ( notReally || ntn == 0 || strcmp( str,ntn->string )) {
		if ( cl->baselist ) {
		    Pname nb = new name, nbc = new name;
		    nb->tp = new basetype(COBJ,0);
		    Pbase(nb->tp)->b_name = nbc;
		    for (Pbcl bx, bb=cl->baselist;  bb;  bb = bb->next) {
			bx = bb->next;
			if ( bb->bclass != 0 ) {
				nbc->tp = bb->bclass;
				notReally++; set_scope(nb); notReally--;
			}
		    }
		    DEL(nbc); /*DEL(nb->tp);*/ DEL(nb);
		}

		int i = 1;
		Pname n = 0;
		Plist ll = 0;
 		if (b->parametrized_class()) {
 		  for (Pname nn = cl->mem_list; nn; nn = nn->n_list)
 		    switch (nn->base) {
 		    case PUBLIC: case PRIVATE: case PROTECTED:
 		      	continue;
 		    default:
 		      	if (nn->tp->base == CLASS) continue;
 		      	if (nn->tp->base == ENUM) continue;
 		      	if ((nn->base == NAME) &&
			    ((nn->n_oper == TNAME) && (nn->tp->base == FCT)) ||
			    (nn->n_oper == CTOR) ||
			    (nn->n_oper == DTOR)) continue ;
 		        n = ktbl->look( nn->string, 0 );
 		        if (n) ll = new name_list( n, ll );
 		    }
 		} // if b->parametrized_class()
		else
		for (Pname nn=cl->memtbl->get_mem(i); nn; nn=cl->memtbl->get_mem(++i) ) {
			if (nn->base == TNAME || nn->base == PUBLIC) continue;
			if (nn->tp->base == CLASS) continue;
			if (nn->tp->base == ENUM) continue;
			n = ktbl->look( nn->string, 0 );
			if (n) ll = new name_list( n, ll );
		}

 		if ( ll ) cl->tn_list = ll;
		if (notReally == 0) Ntncheck = tn; 
	}
	
	for (Plist l=cl->tn_list; l; l=l->l) {
		Pname n = l->f;
		n->n_key = (n->lex_level) ? 0 : HIDDEN;
		modified_tn = new name_list(n,modified_tn);
	}
}

void restore() //SYM -- to be removed
{
	for (Plist l=modified_tn; l; l=l->l) {
		Pname n = l->f;
// error('d',"restore: n %n %t %d bl_level: %d", n, n->tp, n->lex_level, bl_level );
//fprintf(stderr," -- n_key %d\n",n->n_key);
		n->n_key = (n->lex_level==0 || (n->lex_level && n->lex_level<=bl_level)) ? 0 : HIDDEN;
//fprintf(stderr," -- n_key %d\n",n->n_key);
		if ( n->lex_level == 0 
			&& (n->tp->base == COBJ || n->tp->base == EOBJ)) {
			Pname nn = gtbl->look( n->string, 0 );
			if ( nn ) n->n_key = HIDDEN;
		}
//fprintf(stderr," -- n_key %d\n",n->n_key);
	}
}

Pbase start_cl(TOK t, Pname c, Pbcl b)
{
        int mk_local = 0;
	DB(if(Ndebug>=1)error('d',"start_cl(%k,%d,%d)",t,c,b););
	if (c == 0) {
	    c = new name(make_name('C'));
	    c->lex_level -= in_class_decl + 1;
	    if ( in_typedef && c->lex_level ) 
		 mk_local = 1;
	    else c->lex_level = 0;
	}

	for ( Pclass tc = ccl; tc; tc = tc->in_class ) {
	    if ( tc->lex_level == c->lex_level // c not local to mem ftn of tc
	    &&   strcmp( tc->string, c->string) == 0) {
		error( "C %s redefined", c->string );
		error('i', "can't recover from previous errors");
            }
	}

	Pname n = c->tname(t);			/* t ignored */

        if (templp->in_progress && (c->lex_level == 0))
        // bring the template in scope
        	templp->introduce_class_templ(n);

// typedef struct {} x;
	if ( mk_local ) {
	    n->n_key  = LOCAL;
	    extern Plist local_blk, local_class; // place in cfront.h
	    local_class = new name_list( n, local_class );
	    local_blk = new name_list( n, local_blk );
	    modified_tn = modified_tn->l;
	}

	n->where = curloc;
	Pbase bt = Pbase(n->tp);		/* COBJ */
	if (bt->base != COBJ) {
		error("twoDs of%n:%t andC",n,bt);
		error('i', "can't recover from previous errors");
	}

	Pclass occl = ccl;
	ccl = Pclass(bt->b_name->tp);		/* CLASS */
	if (ccl->defined) ccl->defined |= IN_ERROR;
	ccl->defined |= DEF_SEEN;

// error('d', "start_cl: %n ccl->in_class: %t lex_level: %d", n, ccl->in_class, n->lex_level );

	if (ccl->in_class = occl) {
		occl->tn_list = modified_tn;	// save  mod-list
		modified_tn = 0;
	}
	
	Ntncheck = 0;  // zero it out with each new class declaration
	ccl->string = n->string;
	ccl->csu = t;

	if (b) {	// list of base classes
		for (Pbcl bx, bb=b, l=0; bb; bb = bx) {
			bx = bb->next;
			bb->next = 0;

			if ( bb->bclass
			&&   strcmp(ccl->string,bb->bclass->string)==0 )
				error(&n->where,"%nderived from itself",n);
			else if (l == 0)
				l = bb;
			else {	// append and check for duplicates
				for (Pbcl ll = l;;) {
					 if (bb->bclass && ll->bclass==bb->bclass) {
						error("%s has %s asB twice",ccl->string,bb->bclass->string);
						break;
					}

					if (ll->next)
						ll = ll->next;
					else {
						bb->next = l;
						l = bb;
						break;
					}
				}
			}
		}

		ccl->baselist = l;
		notReally++; set_scope(n); notReally--;
	}
	return bt;	
}

void end_cl()
{
	Pclass occl = ccl->in_class;
	Plist ol = occl ? occl->tn_list : 0;	// saved modified name list
	ccl->c_body = 2;

	if (modified_tn) {	// export nested class names to outer scope:
		Plist local = 0;
		for (Plist l=modified_tn, nl=0; l; l=nl) {
			nl = l->l;
			Pname n = l->f;

			// in a pure implementation, no longer do this
			if (ktbl->look(n->string,0)) {
				// add it to enclosing class's modified name list
				l->l = ol;
				ol = l;
			}
			else {	// retain it in this class's modified name list
				l->l = local;
				local = l;
			}
		}
		if (ccl->tn_list = modified_tn = local) restore();
	}
	modified_tn = ol;	// restore mod-list (possibly modified)
/*
if ( occl ) {
Pname n = ktbl->look(ccl->string,NESTED);
for (;n; n=n->n_tbl_list) {
Ptype tt = Pbase(n->tp)->b_name->tp;
// error('d',"end_cl: ccl: %t occl: %t in_class: %t", ccl, occl, tt->in_class);
if (strcmp(tt->in_class->string, occl->string) == 0) {
	n->n_key = 0;
	}
} 
}
*/
	ccl = occl;
}

Pbase end_enum(Pname n, nlist* b)
{
// error( 'd', "end_enum: %n ccl: %t", n , ccl ); 
	if (n == 0) n = new name(make_name('E'));
	n = n->tname(ENUM);
	Pbase bt = (Pbase)n->tp;
	if (bt->base != EOBJ) {
		error("twoDs of%n:%t and enum",n,bt);
		error('i', "can't recover from previous errors");
	}
	Penum en = (Penum)bt->b_name->tp;
	en->e_body = 2;
	en->mem = name_unlist(b);
	if (en->defined) {
		// shouldn't be necessary anymore with nested types
		// if ( in_class_decl )
		//	error("%n redefined, enum tag not local to class", n);
		en->defined |= IN_ERROR;
        }
	en->defined |= DEF_SEEN;
	en->in_class = ccl;
	if (ccl && (bl_level==ccl->lex_level + in_class_decl) && is_anon(n->string))
		n=do_nested_type(n);
	return bt;
}

extern Ptype return_nstd_local_type(Pname,TOK&);
Pname name::tdef()
/*
	typedef "this"
*/
{
	DB(if(Ndebug>=1) {
	   error('d',&where,"'%n'->tdef()%t in_typedef %d",this,tp,in_typedef);
	   error('d',&where,"   lex_level %d tpdef%t",lex_level,tpdef);
	});
        int anon_cl = 0;
        if (n_qualifier) {
                error("QdN in typedef",this);
                n_qualifier = 0;
        }

	Pname n;
	if ( tpdef && tpdef->in_class ) { // nested typedef
// error('d', "*****%s->tdef: %d ccl: %t", string, tpdef, ccl );
		n = ktbl->insert(this,NESTED);
		n->tpdef = tpdef;
		n->tpdef->lex_level = n->lex_level = 0;
		nested_type = new name_list( n, nested_type );
	}
	else {
		Pname nn = ktbl->look(string,NESTED);
		if ( nn ) {
			TOK ntk = 0; // set by return_nstd...
			Ptype tt = return_nstd_local_type(nn,ntk);
			error("nested%k%t::%s seen beforeGTdef %s (to do this placeG definition first)",ntk, tt->in_class, string, string);
			error( 'i', "cannot recover from previous errors" );
		}
		lex_level = bl_level - in_class_decl;
		n = ktbl->insert(this,0);
	}

	if (tp == 0) error('i',"Tdef%n tp==0",this);
	n->base = base = TNAME;
	PERM(n);
	PERM(tp);

	if (tp->base == COBJ || tp->base == EOBJ ) 
	{	// typedef struct/enum { } s; => struct/enum s {};
		Pname b = Pbase(tp)->b_name;
		if (b->string[0] == '_' && b->string[1] == '_' ) 
		    	switch ( tp->base ) {
				case COBJ: {
		             		if (b->string[2] == 'C') {
						Pclass cl = Pclass(b->tp);
						b->string = n->string;
						cl->string = n->string;
						cl->strlen = strlen(cl->string);
						if ( lex_level ) {
			     				anon_cl = 1;
			     				n->n_key = LOCAL;
						}
			      		}
			      		break;
				}
				case EOBJ: {
		             		if (b->string[2] == 'E') {
						Penum en = Penum(b->tp);
						b->string = n->string;
						en->string = n->string;
						en->strlen = strlen(en->string);
					}	
		    		}
	        	}
	}

	if ( anon_cl == 0 )
		modified_tn = new name_list(n,modified_tn);
	DB(if(Ndebug>=1) {
	   error('d',&where,">>'%n'->tdef()%t returning",this,tp);
	   error('d',&where,"   lex_level %d tpdef%t",lex_level,tpdef);
	});
	return n;
}

Pname name::tname(TOK csu)
/*
	"csu" "this" seen, return typedef'd name for "this"
	return	(TNAME,x)
	x:	(COBJ,y)
	y:	(NAME,z)
	z:	(CLASS,ae);
*/
{
//error('d',"'%n'::tname(%k)",this,csu);
	switch (base) {
	case TNAME:
		return this;
	case NAME:
	{	Pname tn = ktbl->insert(this,0);
		Pname on = new name;
		tn->base = TNAME;
		tn->lex_level = lex_level;
		modified_tn = new name_list(tn,modified_tn);
		tn->n_list = n_list = 0;
		string = tn->string;
		*on = *this;
		switch (csu) {
		case ENUM:
			tn->tp = new basetype(EOBJ,on);
			on->tp = new enumdef(0);
			Penum(on->tp)->string = tn->string;
			break;
		case CLASS:
		case STRUCT:
		case UNION:
			on->tp =  new classdef(csu);
			Pclass(on->tp)->string = tn->string;
			Pclass(on->tp)->lex_level = lex_level;
			tn->tp = new basetype(COBJ,on);
			Pbase(tn->tp)->b_table = Pclass(on->tp)->memtbl;
			break;
		default:
			error('i',&where,"illegal csu%k for%n in name::tname()",csu,this);
		}
		PERM(tn);
		PERM(tn->tp);
		PERM(on);
		PERM(on->tp);
		return tn;
	}
	default:
		error('i',"tname(%s %d %k)",string,this,base);
	} 
}

int co_hack;
Pname name::normalize(Pbase b, Pblock bl, bit Cast)
/*
	if (bl) : a function definition (check that it really is a type

	if (Cast) : no name string

	for each name on the name list
	invert the declarator list(s) and attatch basetype
	watch out for class object initializers

	convert
		struct s { int a; } a;
	into
		struct s { int a; }; struct s a;
*/
{
	Pname n;
	Pname nn;
	TOK stc;
	bit tpdf;
	bit inli;
	bit virt;
	char * lnkg;
	DB( if(Ndebug>=1) {
	    error('d',"'%n'::normalize(b%t, bl %d, cast %d)",this,b,bl,Cast);
	    error('d',"    tp%k - lex_level %d - bl_level %d",tp?tp->base:0,lex_level,bl_level);
	});
	if (b) {
		stc = b->b_sto;
		tpdf = b->b_typedef;
		inli = b->b_inline;
		virt = b->b_virtual;
		lnkg = b->b_linkage;
	}
	else {
		stc = 0;
		tpdf = 0;
		inli = 0;
		virt = 0;
		lnkg = 0;
	}

	if (inli && stc==EXTERN)  {
		error("both extern and inline");
		inli = 0;
	}

	if ( stc==STATIC && tp && 
  		tp->base == FCT 
		&& Pfct(tp)->f_const ) 
     			error( "%n staticMF cannot be const", this ); 

	if (stc==FRIEND && tp==0) {
		/*	friend x;
			must be handled during syntax analysis to cope with
				class x { friend y; y* p; };
			"y" is not local to "x":
				class x { friend y; ... }; y* p;
			is legal

			examples:
				
				typedef void	SIG_TYP(int);
				class x {
					friend class y;
					friend z;
					friend x;		// dumb
					friend int i;		// error
					friend SIG_TYP sigFunc;	// subtle
					friend int f();
					friend g(int);
				};
		*/
		if (b && (b->base || b->b_name || b->b_xname)) goto ccc;

		if (n_list) {
			error("L of friends");
			n_list = 0;
		}

		if (!Cast) {
    			Pname nn = gtbl->look( string, 0 );
    			if ( nn ) {
				if (nn->tp->base == FCT) 
					error("friendF must include signature:%n", this ); 
				else
					error("illegal friendD:%n", this );
    			}
		}

//error( 'd', "%n ll: %d", ccl, ccl->lex_level );
		lex_level = ccl->lex_level;
		Pname nx = tname(CLASS);
		modified_tn = modified_tn->l;	/* global */
		n_sto = FRIEND;
		tp = nx->tp;
		return this;
	}
ccc:
	if (tp  			// FUDGE: fix the bad grammar
	&& tp->base==FCT
	&& (n_oper==TNAME || Pfct(tp)->returns)) {
		Pfct f = Pfct(tp);
		Pfct f2 = Pfct(f->returns);

		if (f2) {
			Ptype pt;
			Ptype t = f2;
		lxlx:
			switch (t->base) {
			case PTR:	// x(* p)(args) ?
			case VEC:	// x(* p[10])(args) ?
				if (pt = Pptr(t)->typ) {
					if (pt->base == TYPE) {
						Pptr(t)->typ = 0;
						b = Pbase(pt);
					//	stc = b->b_sto;
					//	tpdf = b->b_typedef;
					//	inli = b->b_inline;
					//	virt = b->b_virtual;
					}
					else {
						t = pt;
						goto lxlx;
					}
				}
				goto zse1;
			case FCT:
			{//	Pexpr e = f2->argtype;
				Pexpr e = Pfct(f)->argtype;
				if  (e && e->base==ELIST) { // get the real name; fix its type
					if (e->e2 || e->e1->base!=DEREF) goto zse1;
					Pexpr ee = e->e1;
					Ptype t = 0;
					Ptype tpx;
				ldld:
					switch (ee->base) {
					case DEREF:
					{	Ptype tt = (ee->e2) ? Ptype(new vec(0,ee->e2)) : Ptype (new ptr(PTR,0));
						if (t)
							Pptr(t)->typ = tt;
						else
							tpx = tt;
						t = tt;
						ee = ee->e1;
						goto ldld;
					}
					case NAME:
					{	Pname rn = Pname(ee);
						b = new basetype(TYPE,ktbl->look(string,0));
						f->returns = tpx;
						n_oper = 0;
						string = rn->string;
						base = NAME;
					}
					}
				}
			}
			}
		}
	}

zse1:
	if (b == 0) {
		error("BTX for %s",string);
		b = Pbase(defa_type);
	}
	
	if (Cast) string = "";
	b = b->check(this);

	switch (b->base) {	//	separate class definitions
				//	from object and function type declarations
	case COBJ:
		nn = b->b_name;
		if (Pclass(nn->tp)->c_body==2) {	/* first occurrence */
			if ( stc == FRIEND ) {
			    Pclass cl = Pclass(nn->tp);
			    if ( cl->csu == ANON )
				error( &nn->where, "friend anonymous union");
			    else
				error( &nn->where, "%k%n defined in friendD",cl->csu,nn);
			}
			if (tp && tp->base==FCT && co_hack == 0) {
				error(&this->where,"%k%n defined as returnT for%n (did you forget a ';' after '}' ?)",Pclass(nn->tp)->csu,nn,this);
				nn = this;
				break;
			}
			nn->n_list = this;
			Pclass(nn->tp)->c_body = 1;	/* other occurences */
		}
		else
			nn = this;
		break;
	case EOBJ:
		nn = b->b_name;
		if (Penum(nn->tp)->e_body==2) {
			if (tp && tp->base==FCT) {
				error(&this->where,"enum%n defined as returnT for%n (did you forget a ';'?)",nn,this);
				nn = this;
				break;
			}
			nn->n_list = this;
			Penum(nn->tp)->e_body = 1;
		}
		else {
			Penum en = Penum(nn->tp);
			if ( en->defined == 0 ) 
				error( "forwardD of enum%n", nn );
			en->e_type = int_type; 
			nn = this;
		}
		break;
	default:
		nn = this;
	}

//error('d',&where,"name::normalize: nn%n ll %d   nn %d this %d",nn,nn->lex_level,nn,this);
	Pname nx; 
	for (n=this; n; n=nx) {
		Ptype t = n->tp;
		nx = n->n_list;
		n->n_sto = stc;

		if (n->base == TNAME) error('i',"redefinition ofTN%n",n);

		if (t == 0) {
			if (bl == 0)
				n->tp = t = b;
			else {
				if ( n->base == NAME && n->n_oper )
					error(&n->where,"illegalD of %n",n);
				else
					error(&n->where,"body of nonF%n",n);
				t = new fct(0,0,0);
			}
		}

		switch (t->base) {
		case PTR:
		case RPTR:
			n->tp = Pptr(t)->normalize(b);
			break;
		case VEC:
			n->tp = Pvec(t)->normalize(b);
			break;
		case FCT:
			n->tp = Pfct(t)->normalize(b);
			break;
		case FIELD:
			if (n->string == 0) n->string = make_name('F');
			n->tp = t;
			Pbase tb = b;
// error('d', "field t %k tb %k", t->base, tb->base );
		flatten:
			switch (tb->base) {
			case TYPE:   /* chase typedefs */
				tb = (Pbase)tb->b_name->tp;
				goto flatten;
			case CHAR:
			case SHORT:
			case EOBJ:
			case INT:
//  typedef const unsigned cu_int;
//     struct x { x(); cu_int b1: 2; }

				Pbase(t)->b_fieldtype = (b->b_unsigned||tb->b_unsigned) ? uint_type : int_type;
		//		goto iii;
		//	case CHAR:
		//		Pbase(t)->b_fieldtype = (b->b_unsigned) ? uchar_type : char_type;
		//		goto iii;
		//	case SHORT:
		//		Pbase(t)->b_fieldtype = (b->b_unsigned) ? ushort_type : short_type;
		//		goto iii;
		//	iii:
				Pbase(t)->b_unsigned = b->b_unsigned?b->b_unsigned:tb->b_unsigned;
				Pbase(t)->b_const = b->b_const?b->b_const:tb->b_const;
				break;
			default:
				error("non-int field");
				n->tp = defa_type;
			}
			break;
		}

		Pfct f = Pfct(n->tp);

		if (f->base != FCT) {
			if (bl) {
				error("body for nonF%n",n);
				n->tp = f = new fct(defa_type,0,0);
				continue;
			}
			if (inli) error("inline nonF%n",n);
			if (virt) error("virtual nonF%n",n);
				
			if (tpdf) {
// error('d', "%n->normalize: ccl: %t", this, ccl );
				if (ccl && n->tpdef &&
					(n->tpdef->lex_level == NESTED ||
						n->tpdef->lex_level == LOCAL))
					; // using this field for nested/local type info
				else
				if (n->n_initializer) {
					error("Ir forTdefN%n",n);
					n->n_initializer = 0;
				}
				n->tdef();
				// because do_nested_type can't call tdef()
				if ( n->n_key == NESTED )
					modified_tn = modified_tn->l;
			}
			continue;
		}

		if ( lnkg ) set_linkage(lnkg);
		f->f_linkage = linkage;
		if ( lnkg ) set_linkage(0);
		// wait and call f->sign() after args are checked

		f->f_inline = inli;
		extern int vcounter;
                f->f_virtual = virt?(vcounter++,VTOK):0;

		if (tpdf) {
			if (f->body = bl) error("Tdef%n { ... }",n);
			if (n->n_qualifier) {
				// typedef T x::f(args);
				// a pointer to member fucntion:
				// equivalent to typedef T x::(f)(args);
				f->memof = Pclass(Pbase(n->n_qualifier->tp)->b_name->tp);
				n->n_qualifier = 0;
			}
			n->tdef();
			// because do_nested_type can't call tdef()
			if ( n->n_key == NESTED )
				modified_tn = modified_tn->l;
			continue;
		}

		if (f->body = bl) continue;

		/*
			Check function declarations.
			Look for class object instantiations
			The real ambiguity:		; class x fo();
				is interpreted as an extern function
				declaration NOT a class object with an
				empty initializer
		*/
		{	Pname cn = f->returns->is_cl_obj();
                        Ptype template_formal_type ;
			bit clob = (cn || cl_obj_vec);

			if (f->argtype) { /* check argument/initializer list */
				Pname nn;

				for (nn=f->argtype; nn; nn=nn->n_list) {
					if (nn->base != NAME) {
						if (!clob) {
							if ((f->returns->base == TYPE) &&
                                                  	    (Pbase(f->returns)->b_name->n_template_arg == template_type_formal))                                    
                                                {
                                                // T x(var); wher T is a template formal
                                                // it could be a class when instantiated
                                                // wait until then to issue error message
                                                		template_formal_type = f->returns;
                                                		Pname nnn = Pbase(f->returns)->b_name;
                                               		 	nnn->n_template_formal_must_be_class = 1;
                                                		goto is_obj;
                                                        }
							error(&n->where,"ATX for%n",n);
							goto zzz;
						}
						goto is_obj;
					}
					//if (nn->string) {
					//	error("AN%n inD of%n",nn,n);
					//	nn->string = 0;
					//}
					if (nn->tp) goto ok;
				}
				if (!clob) {
					error("FALX");
					goto zzz;
				}
		is_obj:
				/* it was an initializer: expand to constructor */
				n->tp = f->returns;
				if (f->argtype->base != ELIST) f->f_args = f->argtype = (Pname)new expr(ELIST,(Pexpr)f->argtype,0);
				if ( n->n_initializer ) {
					error(&n->where,"twoIrs for%n",n);
					DEL( ((Pexpr)f->argtype) );
					f->argtype = 0;
				} else
					// n->n_initializer = new texpr(VALUE,cn->tp,(Pexpr)f->argtype);
                                        n->n_initializer = new texpr(VALUE, cn ? cn->tp : template_formal_type, (Pexpr)f->argtype);
				goto ok;
			zzz:
				if (f->argtype) {
					DEL(Pexpr(f->argtype));
					f->argtype = 0;
					f->nargs = 0;
					f->nargs_known = 1;
				}
			}
			else {	/* T a(); => function declaration */
/*
				if (clob) {
					DEL(n->tp);
					n->tp = f->returns;
				}
*/
			}
		ok:
			;
		}
	}
	return nn;
}

Ptype vec::normalize(Ptype vecof)
{
	Ptype t = typ;
	typ = vecof;

	while(vecof->base == TYPE)
		vecof = Pbase(vecof)->b_name->tp;
		
	switch (vecof->base) {
	case RPTR:
			error("array ofRs");
			break;
	case FCT:
			error("array ofFs");
			break;
	default:
			break;
	}

	if (t == 0) return this;

	switch (t->base) {
	case PTR:
	case RPTR:	return Pptr(t)->normalize(this);
	case VEC:	return Pvec(t)->normalize(this);
	case FCT:	return Pfct(t)->normalize(this);
	default:	error('i',"bad arrayT(%d)",t->base);
	}

}

Ptype ptr::normalize(Ptype ptrto)
{
//	if (this == 0) error('i',"0->ptr.normalize()");
	Ptype t = typ;
	typ = ptrto;

	int bc = 0;
	while (ptrto->base == TYPE) {
		bc += Pbase(ptrto)->b_const;
		ptrto = Pbase(ptrto)->b_name->tp;
	}

	switch (ptrto->base) {
	case FCT:
		if (memof)
			if (Pfct(ptrto)->memof) {
				if (memof != Pfct(ptrto)->memof) error("P toMF mismatch: %s and %s",memof->string, Pfct(ptrto)->memof->string);
			}
			else
				Pfct(ptrto)->memof = memof;
		else
			memof = Pfct(ptrto)->memof;
		break;
	case RPTR:
		switch (base) {
		case PTR:	error("P toR"); break;
		case RPTR:	error("R toR"); break;
		}
	}

	if (t == 0) {
		Pbase b = Pbase(ptrto);
		if (Pfctvec_type
		&& rdo==0
		&& b->b_unsigned==0
		&& b->b_const==0
		&& bc == 0
		&& memof==0
		&& base==PTR) {
			switch (b->base) {
			case INT:	delete this;	return Pint_type;
			case CHAR:	delete this;	return Pchar_type;
			case VOID:	delete this;	return Pvoid_type;
			}
		}
		if (base==RPTR && b->base==VOID) error("void& is not a validT");
		return this;
	}

	switch (t->base) {
	case PTR:
	case RPTR:	return Pptr(t)->normalize(this);
	case VEC:	return Pvec(t)->normalize(this);
	case FCT:	return Pfct(t)->normalize(this);
	default:	error('i',"badPT(%k)",t->base);
	}
}

Ptype fct::normalize(Ptype ret)
/*
	normalize return type
*/
{
	register Ptype t = returns;
	returns = ret;

	if (argtype && argtype->base==NAME && argtype->n_qualifier) {
		error("syntax: ANX");
		argtype = 0;
		nargs = 0;
		nargs_known = 0;
	}

	while(ret->base == TYPE)
		ret = Pbase(ret)->b_name->tp;

	switch(ret->base) {
	case VEC:
		error("F returning array");
		break;
	case FCT:
		error("F returningF");
		returns = ret = t?t:int_type;
		break;
	default:
		break;
	}

	if (t == 0) return this;

	switch (t->base) {
	case PTR:
	case RPTR:	return Pptr(t)->normalize(this);
	case VEC:	return Pvec(t)->normalize(this);
	case FCT:	return Pfct(t)->normalize(this);
	default:	error('i',"badFT:%k",t->base);
	}
}

void fct::argdcl(Pname dcl, Pname fn)
/*
	sort out the argument types for old syntax:
			f(a,b) int a; char b; { ... }
	beware of
			f(a) struct s { int a; }; struct s a;
*/
{
	Pname n;
/*fprintf(stderr,"%d argtype %d %d dcl %d %d\n",this, argtype, argtype?argtype->base:0, dcl, dcl?dcl->base:0); fflush(stderr);*/
	switch (base) {
	case FCT:	break;
	case ANY:	return;
	default:	error('i',"fct::argdcl(%d)",base);
	}

	if (argtype) {
		switch (argtype->base) {
		case NAME:
			if (dcl) error("badF definition syntax");
			for (n=argtype; n; n=n->n_list) {
				if (n->string == 0) n->string = make_name('A');
			}
			return;
		case ELIST:	// expression list:	f(a,b,c) int a; ... { ... }
				// scan the elist and build a NAME list
		{
			Pname tail = 0;
			n = 0;

			error(strict_opt?0:'w',&fn->where,"old style definition of%n (anachronism)",fn);

			for (Pexpr e=Pexpr(argtype); e; e=e->e2) {
				Pexpr id = e->e1;
				if (id->base != NAME) {
					error("NX inAL");
					argtype = 0;
					dcl = 0;
					break;
				}
				Pname nn = new name(id->string);
				if (n)
					tail = tail->n_list = nn;
				else
					tail = n = nn;
			}
			f_args = argtype = n;
			break;
		}
		default:
			error("ALX(%d)",argtype->base);
			argtype = 0;
			dcl = 0;
		}
	}
	else if(nargs_known == ELLIPSIS) {
		return;
	}
	else {
		nargs_known = 1;
		nargs = 0;
		if (dcl) error("ADL forFWoutAs");
		return;
	}

//	nargs_known = 0;

	if (dcl) {
		Pname d;
		Pname dx;
		/*	for each  argument name see if its type is specified
			in the declaration list otherwise give it the default type
		*/

		for (n=argtype; n; n=n->n_list) {
			char* s = n->string;
			if (s == 0) {
				error("AN missing inF definition");
				n->string = s = make_name('A');
			}
			else if (n->tp) error("twoTs forA %s",n->string);

			for (d=dcl; d; d=d->n_list) {
				if (strcmp(s,d->string) == 0) {
					if (d->tp->base == VOID) {
						error("voidA%n",d);
						d->tp = any_type;
					}
					n->tp = d->tp;
					n->n_sto = d->n_sto;
					d->tp = 0;	// now merged into argtype
					goto xx;
				}
			}
			n->tp = defa_type;
		xx:;
			if (n->tp == 0) error('i',"noT for %s",n->string);
		}
	
		/*	now scan the declaration list for "unused declarations"
			and delete it
		*/
		for (d=dcl; d; d=dx) {
			dx = d->n_list;
			if (d->tp) {	/* not merged with argtype list */
				/*if (d->base == TNAME)  ??? */
				switch (d->tp->base) {
				case CLASS:
				case ENUM:
					/* WARNING: this will reverse the order of
					   class and enum declarations
					*/
					d->n_list = argtype;
					f_args = argtype = d;
					break;
				default:
					 error("%n inADL not inAL",d);
				}
			}
		}
	}

	/* add default argument types if necessary */
	for (n=argtype; n; n=n->n_list) {
		if (n->tp == 0) n->tp = defa_type;
		nargs++;
	}
}

Pname cl_obj_vec;	/* set if is_cl_obj() found a array of class objects */
Pname eobj;		/* set if is_cl_obj() found an enum */

Pname type::is_cl_obj()
/*
	returns this->b_name if this is a class object
	returns 0 and sets cl_obj_vec to this->b_name
		if this is a array of class objects
	returns 0 and sets eobj to this->b_name
		if this is an enum object
	else returns 0
*/
{
	bit v = 0;
	register Ptype t = this;

	if (t == 0) return 0;
	eobj = 0;
	cl_obj_vec = 0;
xx:
	switch (t->base) {
	case TYPE:
		t = Pbase(t)->b_name->tp;
		goto xx;

	case COBJ:
		if (v) {
			cl_obj_vec = Pbase(t)->b_name;
			return 0;
		}
		else
			return Pbase(t)->b_name;

	case VEC:
		t = Pvec(t)->typ;
		v=1;
		goto xx;

	case EOBJ:
		eobj = Pbase(t)->b_name;
	default:	
		return 0;
	}
}

/*
static Pname
lookup(char* s, Pclass cl)
{
	Pbcl bc = 0;
	Pname n = cl->memtbl->look(s,0);
	if ( n ) return n;
	Pname n2 = 0;
	for (Pbcl b=cl->baselist; b; b=b->next) {
		n = b->bclass->lookup(s,cl);
		if ( n == 0 ) continue;
		if ( n2 ) { // clash?
		}
		n2 = n;
	}
}
*/
0707071010112044371004440001630000160000010205100466055405600001000000011657norm2.c/*ident	"@(#)ctrans:src/norm2.c	1.4" */
/************************************************************************

	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.

norm2.c:

	"normalization" handles problems which could have been handled
	by the syntax analyser; but has not been done. The idea is
	to simplify the grammar and the actions associated with it,
	and to get a more robust error handling

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

#include "cfront.h"
#include "size.h"

#ifdef DBG
long node_id = 0;
#define DBCHECK() if(node::allocated) error('i',"allocated node (id %d, base%k) on free list! (src: \"%s\", %d",node::id,node::base,__FILE__,__LINE__);
#else
#define DBCHECK() /**/
#endif

fct::fct(Ptype t, Pname arg, TOK known)
{
	base = FCT;
	nargs_known = known;
	returns = t;
	argtype = arg; 
	DBID();

	if (arg==0 || arg->base==ELIST) return;
//error('d',"fct::fct %d sig %d",this,f_signature);
	register Pname n;
	Pname pn = 0;
	for (n=arg; n; pn=n,n=n->n_list) {
		if( n->n_sto==EXTERN ) error("externA");
		if( n->n_sto==STATIC ) error("static used forA%n",arg);
 
		switch (n->tp->base) {
		case VOID:
			argtype = 0;
			nargs_known = 1;
			if(n->n_initializer)
				error("voidFA");
			else if (n->string)
				error("voidFA%n",n);
			else if (nargs || n->n_list) {
				error("voidFA");
				nargs_known = 0;
			}
			nargs = 0;
			break;
		case CLASS:
		case ENUM:
			error("%k defined inAL (will not be in scope at point of call)",n->tp->base);
			if (n == argtype)
				argtype = n->n_list;
			else
				pn->n_list = n->n_list;
			break;
		default:
			nargs++;
		}
	}
}

expr::expr(TOK ba, Pexpr a, Pexpr b)
{
	DBCHECK();

	base = ba;
	e1 = a;
	e2 = b;
	DBID();
}

stmt::stmt(TOK ba, loc ll, Pstmt a)
{
	DBCHECK();

	base = ba;
	where = ll;
	s=a;
	DBID();
}

classdef::classdef(TOK b)
{
	base = CLASS;
	csu = b;
	memtbl = new table(CTBLSIZE,0,0);
	DBID();
}

classdef::~classdef()
{
	delete memtbl;
}

basetype::basetype(TOK b, Pname n)
{
	switch (b) {
	case 0:				break;
	case TYPEDEF:	b_typedef = 1;	break;
	case INLINE:	b_inline = 1;	break;
	case VIRTUAL:	b_virtual = 1;	break;
	case CONST:	b_const = 1;	break;
	case UNSIGNED:	b_unsigned = 1;	break;
	case FRIEND:
	case OVERLOAD:
	case EXTERN:
	case STATIC:
	case AUTO:
	case REGISTER:	b_sto = b;	break;
	case SHORT:	b_short = 1;	break;
	case LONG:	b_long = 1;	break;
	case ANY:
	case ZTYPE:
	case VOID:
	case CHAR:
	case INT:
	case FLOAT:
	case LDOUBLE:
	case DOUBLE:	base = b; 	break;
	case TYPE:
	case COBJ:
	case EOBJ:
	case FIELD:
	case ASM:
		base = b;
		b_name = n;
		break;
	case SIGNED:
	case VOLATILE:
		error('w',"\"%k\" not implemented (ignored)",b);
		break;
	default:
		error('i',"badBT:%k",b);
	}
	DBID();
}

name::name(char* s) : expr(NAME,0,0)
{
	// DBCHECK() called in expr::expr()
	string = s;
	where = curloc;
	lex_level = bl_level;
}

nlist::nlist(Pname n)
{
	head = n;
	for (Pname nn=n; nn->n_list; nn=nn->n_list);
	tail = nn;
}

void nlist::add_list(Pname n)
{
	if (n->tp && (n->tp->defined & IN_ERROR)) return;

	tail->n_list = n;
	for (Pname nn=n; nn->n_list; nn=nn->n_list);
	tail = nn;
}

Pname name_unlist(Pnlist l)
{
	if (l == 0) return 0;
	Pname n = l->head;

	delete l;
	return n;
}

Pstmt stmt_unlist(Pslist l)
{
	if (l == 0) return 0;
	Pstmt s = l->head;
//	NFl++;

	delete l;
	return s;
}

Pexpr expr_unlist(Pelist l)
{
	if (l == 0) return 0;
	Pexpr e = l->head;
//	NFl++;

	delete l;
	return e;
}

void sig_name(Pname n)
{
	static char buf[256];
	buf[0] = '_';
	buf[1] = '_';
	buf[2] = 'o';
	buf[3] = 'p';
	char* p = n->tp->signature(buf+4);
	if (255 < p-buf) error('i',"sig_name():N buffer overflow");
	char *s = new char [ p - buf + 1 ];
	strcpy(s,buf);
	n->string = s;
	n->tp = 0;
}

Ptype tok_to_type(TOK b)
{
	Ptype t;
	switch (b) {
	case CHAR:	t = char_type; break;
	case SHORT:	t = short_type; break;
	case LONG:	t = long_type; break;
	case UNSIGNED:	t = uint_type; break;
	case FLOAT:	t = float_type; break;
	case DOUBLE:	t = double_type; break;
	case LDOUBLE:	t = ldouble_type; break;
	case VOID:	t = void_type; break;
	default:	error("illegalK:%k",b);
	case INT:	t = int_type;
	}
	return t;
}

Pbase defa_type;
Pbase moe_type;
Pexpr dummy;
Pexpr zero;

Pclass ccl;
Plist modified_tn = 0;

Plist local_tn = 0;
Plist local_blk = 0;
Plist local_class = 0;

Plist nested_tn = 0;
Plist nested_type = 0;

void memptrdcl(Pname bn, Pname tn, Ptype ft, Pname n)
{
	Pptr p = new ptr(PTR,0);
	p->memof = Pclass(Pbase(bn->tp)->b_name->tp);
	Pbase b = new basetype(TYPE,tn);
	PERM(p);
	Pfct f = Pfct(ft);
	Ptype t = n->tp;
	if (t) {
		p->typ = t;
	ltlt:
		switch (t->base) {
		case PTR:
		case RPTR:
		case VEC:
			if (Pptr(t)->typ == 0) {
				Pptr(t)->typ = b;
				break;
			}
			t = Pptr(t)->typ;
			goto ltlt;
		default:
			error('s',"P toMFT too complicated");
		}
	}
	else
	p->typ = b;	
	f->returns = p;
	n->tp = f;
}
0707071010112044401004440001630000160000010205200466055406200001000000061331print.c/*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;
}
0707071010112044411004440001630000160000010205600466055406600001100000140076print2.c/*ident	"@(#)ctrans:src/print2.c	1.4" */
/**************************************************************************

	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.

print2.c:

	print names and declarations

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

#include "cfront.h"
#include "template.h"

bit Cast;
int last_ll = 1;
Pin curr_icall;
char emode;
int ntok;

static int MAIN;	// fudge to get _main() called by main()

#define eprint(e) if (e) Eprint(e)

#ifdef DENSE
void chop(char*);
#endif

void puttok(TOK t)
/*
	print the output representation of "t"
*/
{
//	if (t<=0 || MAXTOK<t) error("illegal token %d",t);
//	char* s = keys[t];
//	if (s == 0) error("V representation token %d",t);

	putstring(keys[t]);

	if (12<ntok++) {
		ntok = 0;
		last_line.putline();
	}
	else if (t == SM) {
		ntok = 0;
		putch('\n');
		if (last_ll) last_line.line++;
	}
	else
		putch(' ');
}

#define MX	20
#define NTBUF	10
class dcl_buf {
	/*
		buffer for assembling declaration (or cast)
		left contains CONST_PTR	=> *CONST
			     CONST_RPTR => &CONST
				PTR	=> *
				RPTR	=> &
				LP	=> (
		right contains	RP	=> )
				VEC	=> [ rnode ]
				FCT	=> ( rnode )
				FIELD	=> : rnode
	*/
	Pbase b;
	Pname n;
	TOK left[MX], right[MX];
	Pnode	rnode[MX];
	Pclass	lnode[MX];
	int li, ri;
public:
	void	init(Pname nn)		{ b=0; n=nn; li=ri=0; }
	void	base(Pbase bb)		{ b = bb; }
	void	front(TOK t)		{ left[++li] = t; }
	void	front(Pclass c)		{ left[++li] = MEMPTR; lnode[li] = c; }
	void	back(TOK t, Pnode nod)	{ right[++ri] = t; rnode[ri] = nod; }
	void	paran() 		{ front(LP); back(RP,0); }
	void	put();
} *tbufvec[NTBUF] = {0}, *tbuf = 0;

int freetbuf = 0;

void dcl_buf::put()
{
	int i;
	Pfct ff = 0;

	if (MX<=li || MX<=ri) error('i',"T buffer overflow");
	if (b == 0) error('i',"noBT%s",Cast?" in cast":"");

	if (n && n->n_sto && n->n_sto!=REGISTER) puttok(n->n_sto);

	b->dcl_print();
	
	for( ; li; li--) {
		switch (left[li]) {
		case LP:
			putch('(');
			break;
		case PTR:
			putch('*');
			break;
		case RPTR:
			if (emode)
				putch('&');
			else
				putch('*');
			break;
		case CONST_PTR:
			if (emode)
				putstring("*const ");
			else
				putch('*');
			break;
		case CONST_RPTR:
			if (emode)
				putstring("&const ");
			else
				putch('*');
			break;
		case MEMPTR:
			if (lnode[li]) fprintf(out_file,"%s::",lnode[li]->string);
		}
	}

	if (n) n->print();

	for(i=1; i<=ri; i++) {
		switch (right[i]) {
		case RP:
			putch(')');
			break;
		case VEC:
			putch('[');
			{	Pvec v = (Pvec) rnode[i];
				Pexpr d = v->dim;
				int s = v->size;
				if (d) d->print();
				if (s) fprintf(out_file,"%d",s);
			}
			putch(']');
			break;
		case FCT:	// beware of function returning pointer to
				// function expressed witout typedef
		{	Pfct f = Pfct(rnode[i]);
			if (f->body) ff = f;
			f->dcl_print();
			break;
		}
		case FIELD:
                {       Pbase f = (Pbase) rnode[i];
                        Pexpr d = (Pexpr)f->b_name;
                        int s = f->b_bits;
                        putch(':');
                        if (d)
                                d->print();
                        else if (s)
                                fprintf(out_file,"%d",s);
                        else
                                puttok(ZERO);
                        break;
                }
		}
	}
void print_body(Pfct);
	if (ff && emode==0) print_body(ff);
}

static Pexpr mk_zero_init( Ptype tt, Pname obname, Pname currname )
/*
	creates 0 initializer for defined objects
	side effect: generates right nesting level for {}
*/
{
zaq:
	switch (tt->base) {
	case TYPE:
		tt = Pbase(tt)->b_name->tp; goto zaq;
	case VEC: // type a[size]; => type a[size] = {0};
	{
		if ( obname == currname ) {
		//xxx initializing vectors blows up the size of some programs
			return 0;
		} else {
			Pexpr i = mk_zero_init(Pvec(tt)->typ,obname,currname);
			if ( i == 0 ) return 0;
			return new expr( ILIST, i, 0 );
		}
	}
	case COBJ: // "X a;" == "X a = {0};"
	{
		Pclass cl = Pclass(Pbase(tt)->b_name->tp);
		if ( !ansi_opt && (cl->csu == ANON || cl->csu == UNION) ) {
		    if ( warning_opt ) {
			// ridiculous handstands to avoid printing
			// compiler generated names in warning
			Ptype tn = obname->tp;
			for(;;) if(tn->base==VEC) tn=Pvec(tn)->typ; else break;
			if ( obname == currname && tt == tn ) {
			    if ( cl->string[0]=='_' && cl->string[1]=='_' )
				error('w',&obname->where,"cannot generate zeroIr for%n ofT union; toI, compile with +a1 or insert non-union object as first member",obname);
			    else
				error('w',&obname->where,"cannot generate zeroIr for%n ofT%t; toI, compile with +a1 or insert non-union object as first member",obname,obname->tp);
			} else { Pclass cx;
			    if ( tn->base == COBJ
			    &&   (cx=(Pclass)Pbase(tn)->b_name->tp,
				  cx->string[0]=='_' && cx->string[1]=='_') )
				error('w',&obname->where,"cannot generate zeroIr for%n (union or aggregate with union as first element); toI, compile with +a1 or insert non-union object as first member",obname);
			    else
				error('w',&obname->where,"cannot generate zeroIr for%n ofT%t (union or aggregate with union as first element); toI, compile with +a1 or insert non-union object as first member",obname,obname->tp);
			}
		    } // if warning_opt
		    return 0;
		}
		Pbcl l = cl->baselist;
		while ( l ) {
			if ( l->base == NAME ) cl = l->bclass;
			else return new expr(ILIST,zero,0);
			l = cl->baselist;
		}
		int i = 1;
		Pname nn = cl->memtbl->get_mem(i);
		for ( ;  nn;  nn = cl->memtbl->get_mem(++i) ) {
			Ptype tx = nn->tp;
			while ( tx->base == TYPE ) tx = Pbase(tx)->b_name->tp;
			if (nn->base==NAME
			&& nn->n_union==0
			&& tx->base!=FCT
			&& tx->base!=OVERLOAD
			&& tx->base!=CLASS
			&& tx->base!=ENUM
			&& nn->n_stclass != STATIC) {
				Pexpr i = mk_zero_init(tx,obname,nn);
				if ( i == 0 ) return 0;
				return new expr(ILIST,i,0);
			}
		}
		return 0;
	}
	case PTR:
		if (tt->memptr()) {
			Pexpr i = new expr(ELIST,zero,zero);
			return new expr(ILIST,i,zero);
		}
		// no break
	case RPTR:
	case CHAR:
	case SHORT:
	case INT:
	case EOBJ:
	case LONG:
	case FLOAT:
	case DOUBLE:
	case LDOUBLE:	// "int a;" == "int a = 0;"
	case FIELD:
	case ANY:
		return zero;
	}
	return 0;
}

void name::dcl_print(TOK list)
/*
	Print the declaration for a name (list==0) or a name list (list!=0):
		For each name
		(1) print storage class
		(2) print base type
		(3) print the name with its declarators
	Avoid (illegal) repetition of basetypes which are class or enum declarations
	(A name list may contain names with different base types)
	list == SM :	terminator SM
	list == 0:	single declaration with terminator SM
	list == CM :	separator CM
*/
{
	if (error_count) return;

	for (Pname n=this; n; n=n->n_list) {
		Ptype t = n->tp;
		int sm = 0;

// error('d',"%s->dcl_print() tp %t sto %k",n->string,t,n->n_sto);
		if (t == 0) error('i',"N::dcl_print(%n)T missing",n);

		if (n->n_stclass==ENUM) if (list) continue; else return;

		if (n->where.line!=last_line.line || n->where.file!=last_line.file)
//fprintf(stderr,"%s ",n->string?n->string:"<0>"); n->where.put(stderr); fprintf(stderr,"  last "); last_line.put(stderr); putc('\n',stderr);
			if (last_ll = n->where.line)
				n->where.putline();
			else
				last_line.putline();
	
		int tc = Pbase(t)->b_const;
		for (Ptype tt = t; tt->base==TYPE; tt = Pbase(tt)->b_name->tp)
			tc |= Pbase(tt)->b_const;
 
		switch (t->base) {
		case CLASS:
//fprintf(stderr,"class %s->dcl_print()\n",n->string);
			if (n->base != TNAME) {
				Pclass(t)->dcl_print(n);
				sm = 1;
			}
			break;

		case ENUM:
                        Penum(t)->dcl_print(0);
			sm = 1;
			break;

		case FCT:
		{	Pfct f = Pfct(t);

			if (n->base == TNAME) puttok(TYPEDEF);

// error('d',"fct %n->dcl_print() printed %d body %d defined %d",n,n->n_dcl_printed,f->body,f->defined);
// error('d',"n %d tbl %d tp %t inline %d",n,n->n_table,n->tp,f->f_inline);
			if (n->n_dcl_printed==2	// definition already printed
			|| (n->n_dcl_printed==1 && f->body==0)
						// declaration already printed
			) {
				// don't print again
				sm = 1;	// no SM
				break;
			}

			if (f->f_result == 0) make_res(f);

			if (f->body && n->n_sto==EXTERN) n->n_sto = 0;

			if (f->f_inline && ((n->n_table!=gtbl) || strcmp(n->string,"main"))) {
				if (debug_opt)  {
//error('d',"f %t defined %d inline %d",f,f->defined,f->f_inline);
					if (f->defined&DEFINED
					&& f->defined&SIMPLIFIED
					&& f->f_inline!=ITOR)
						goto prnt_def;
					else if (n->n_dcl_printed==0)
						goto prnt_dcl;
					else {
						sm = 1;
						break;
					}
				}
				if (f->f_virtual || n->n_addr_taken) {
				prnt_dcl:
//error('d',"prnt_dcl %d %n %k",n,n,n->n_sto);
					TOK st = n->n_sto;
					Pblock b = f->body;
					f->body = 0;
					t->dcl_print(n);
					n->n_dcl_printed = 1;
					n->n_sto = st;
					f->body = b;
					break;
				}
				else
					sm = 1;	// no SM
			}
			else if ((f->defined&DEFINED)==0
				|| (f->defined&SIMPLIFIED)==0)
				goto prnt_dcl;
			else if (n->n_table==gtbl && strcmp(n->string,"main")==0) {
				if (f->f_inline) {
					if (warning_opt) {
						error('w',"main() cannot be inlined");
						error('w',"out-of-line copy of main() created");
					}
					n->n_sto=0;
				}
				MAIN = 1;
				gtbl->look("main",0)->use();
				f->f_signature = 0;
				t->dcl_print(n);
				n->n_dcl_printed = f->body?2:1;
				MAIN = 0;
			}
			else {
			prnt_def:
// error('d',"prnt_def %n %k %d %k",n,n->n_oper,n,n->n_sto);
				if (n->n_oper==CTOR || n->n_oper==DTOR) {
					Pclass cl = Pclass(n->n_table->t_name->tp);
					if (cl->c_body == 3) cl->print_all_vtbls(cl);
				}

				if ( n->n_sto == STATIC && 
					pdef_name == 0 && def_name == 0 ) {
// error('d', "printing ptbl_vec without first definition" );
						pdef_name = n;
						ptbl_init(0);
				}
				t->dcl_print(n);
				n->n_dcl_printed = f->body?2:1;
			}
			if (f->body) sm = 1;
			break;
		}

		case OVERLOAD:
		{
			for (Plist gl=Pgen(t)->fct_list; gl; gl=gl->l) {
				Pname nn = gl->f;
				nn->dcl_print(0);
				sm = 1;
			}
			break;
		}

		case ASM:
			fprintf(out_file,"asm(\"%s\")\n",(char*)Pbase(t)->b_name);
			break;

		case INT:
		case EOBJ:
		case CHAR:
		case LONG:
		case SHORT:
		tcx:
			// do not allocate space for constants unless necessary
			if (tc
			&& n->n_sto!=EXTERN	// extern const one;
						// const one = 1;
						// allocates storage
			&& (n->n_scope==EXTERN	// FUDGE const one = 1;
						// is treated as static
						// need loader support
				|| n->n_scope==STATIC
				|| n->n_scope==FCT)
			) {
				if (n->n_evaluated && n->n_addr_taken==0) {
					sm = 1;	/* no ; */
					break;
				}
			}
			tc = 0;
			// no break;

		default:
		{
/*	
//  don't print local instance of const
			if ( n->n_dcl_printed == 3 ) {
				sm = 1;
				break;
			}
*/
			Pexpr i = n->n_initializer;
 			if (n->base == TNAME && n->n_key == NESTED) i = 0;
			if (tc) {
				switch (tt->base) {
				case CHAR:
				case SHORT:
				case INT:
				case LONG:
				case EOBJ:
					goto tcx;
				}
			}

			if (n->base == TNAME) {
       			/* Always print template formals, even when they have the same 
			 * formal name, since the instantiation name is different. This 
			 * fix should not be required when the copy mechanism is in place. */
          			if (! n_template_arg)
     				    	for (Pname tn=ktbl->look(n->string,HIDDEN); tn; tn=tn->n_tbl_list) 
     						if (tn && tn->lex_level && t==tn->tp) return;
				puttok(TYPEDEF);
			}

			if (n->n_stclass == REGISTER) {
				// (imperfect) check against member functions
				// register s a; a.f() illegal
				Pname cln = n->tp->is_cl_obj();
				if (cln) {
					Pclass cl = Pclass(cln->tp);
					if (cl->csu!=CLASS
					&& cl->baselist==0
					&& cl->has_itor()==0
					&& cl->virt_count==0) puttok(REGISTER);
				}
				else
					puttok(REGISTER);
			}

			if (i) {
				if (n->n_sto==EXTERN && n->n_stclass==STATIC) {
					n->n_initializer = 0;
					t->dcl_print(n);
					puttok(SM);
					n->n_initializer = i;
					n->n_sto = 0;
					t->dcl_print(n);
					n->n_sto = EXTERN;
				}
				else
					t->dcl_print(n);
				if(n->n_table) {
					Pname nn = n->n_table->look(n->string,0);
					if(nn)
						nn->n_dcl_printed = 1;
					else
						n->n_dcl_printed = 1;
				}
				else
					n->n_dcl_printed = 1;
			}
			else if (n->n_evaluated && Pbase(t)->b_const) {
				if (n->n_sto==EXTERN && n->n_stclass==STATIC) {
					int v = n->n_evaluated;
					n->n_evaluated = 0;
					t->dcl_print(n);
					puttok(SM);
					if (n->where.line!=last_line.line || n->where.file!=last_line.file)
						if (last_ll = n->where.line)
							n->where.putline();
						else
							last_line.putline();
					n->n_evaluated = v;
					n->n_sto = 0;
					t->dcl_print(n);
					n->n_sto = EXTERN;
				}
				else
					t->dcl_print(n);
				if(n->n_table) {
					Pname nn = n->n_table->look(n->string,0);
					if(nn)
						nn->n_dcl_printed = 1;
					else
						n->n_dcl_printed = 1;
				}
				else
					n->n_dcl_printed = 1;
			}
			else {
//error('d',"%n sto %k val %d stc %k",n,n->n_sto,n->n_val,n_stclass);
                               if ((n->n_sto==0 || (n->n_val && n->n_evaluated==0))
                                && n_stclass==STATIC
				&& n->n_sto!=STATIC
                                && n->n_table==gtbl) {
                                        if (n->n_val && n->n_evaluated==0) { 
                                                // extern x = f();
                                                // generate int x = 0;       
                                                // plus dynamic initialization
                                                n->n_sto = 0;
                                        }

					n->n_initializer = i = mk_zero_init(t,n,n);
				}
				t->dcl_print(n);
				if(n->n_table) {
					Pname nn = n->n_table->look(n->string,0);
					if(nn)
						nn->n_dcl_printed = 1;
					else
						n->n_dcl_printed = 1;
				}
				else
					n->n_dcl_printed = 1;
			}

			if (n->n_scope!=ARG) {
				if (i) {
					puttok(ASSIGN);

					Pexpr i2 = i;
					while (i2->base == CAST) i2 = i2->e1;
					if (i2->base == ILIST) i = i2;
					if (t!=i->tp
					&& i->base!=ZERO
					&& i->base!=ILIST /*&& i->tp!=Pchar_type*/) {
						Ptype t1 = n->tp;
					cmp:
						switch (t1->base) {
						case TYPE:	
							t1 = Pbase(t1)->b_name->tp;
							goto cmp;
						default:
							i->print();
							break;
					//	case EOBJ:
					//		goto cst;
						case VEC:
							if (Pvec(t1)->typ->base==CHAR) {
								i->print();
								break;
							}
							// no break
						case PTR:
						case RPTR:
							if (i->tp==0 || n->tp->check(i->tp,0)) {
                                          //      cst:
								putch('(');
								bit oc = Cast;
								Cast = 1;
								t->print();
								Cast = oc;
								putch(')');
							}
							eprint(i);
						}
					}
					else {
						if (i==zero) {
							while (t->base == TYPE) t = Pbase(t)->b_name->tp;
					//		if (t->base == EOBJ) {
					//			putch('(');
					//			bit oc = Cast;
					//			Cast = 1;
					//			t->print();
					//			Cast = oc;
					//			putch(')');
					//		}
						}
						eprint(i);
						
					//	i->print();
					}
				}
				else if (n->n_evaluated) {
					puttok(ASSIGN);
					if (n->tp->base!=INT || n->tp->is_unsigned()) {
						putstring("((");
						bit oc = Cast;
						Cast = 1;
						n->tp->print();
						Cast = oc;
						fprintf(out_file,")%d)",n->n_val);
					}
					else
						fprintf(out_file,"%d",n->n_val);
				}
			}
		}
		}

		switch (list) {
		case SM:
			if (sm==0) puttok(SM);
			break;
		case 0:
			if (sm==0) puttok(SM);
			return;
		case CM:
			if (n->n_list) puttok(CM);
			break;
		}
	}
} 

char *local_sign( Ptype pt )
{ // get function signature for local class
	char buf[1024];
	char* bb = pt->signature(buf);
	int ll = bb-buf;
	if (1023 < ll) error('i',"local class N buffer overflow");
	char *p = new char[ll+1];
	strcpy(p,buf);
	return p;
}

void enumdef::dcl_print(Pname cln)
/*
*/
{
	// note: ***** modify to handle local enums 
// error('d', "%t::dcl_print(%n) in_class: %t nested_sig: %s", this, cln, in_class, nested_sig );
	char* s = nested_sig?nested_sig:(cln ? cln->string:0);
	if ( nested_sig )
		fprintf(out_file,"enum __%s { ",nested_sig);
	else fprintf(out_file,"enum %s { ",string);

	for (Pname px, p=mem; p; p=px) {
		px = p->n_list;
		if (s) {
			if (p->n_evaluated)
				fprintf(out_file,"%s__%s = %d",p->string,s,p->n_val);
			else
				fprintf(out_file,"%s__%s",p->string,s);
		}
		else {
			if (p->n_evaluated)
				fprintf(out_file,"%s = %d",p->string,p->n_val);
			else
				fprintf(out_file,"%s",p->string);
		}
		if (px) puttok(CM);
		p->n_initializer = 0;
		delete p;
	}
	mem = 0;
	puttok(RC);
	puttok(SM);
}

void name::print()
{ // print just the name itself
	if (this == 0) error('i',"0->N::print()");
	if (string == 0) {
		if (emode) putch('?');
		return;
	}

// error( 'd', "%s->name::print(), base: %k", string, base );
	switch (base) {
	case TNAME:
		if (n_key == NESTED && tpdef &&
			tpdef->nested_sig) {
			if ( emode == 0 ) {
				putstring( " __" );
				putst(tpdef->nested_sig);
			}
			else {
				putst(tpdef->in_class->string);
				putstring( "::" );
				putst(string);
			}
			return;
		}

		if (emode && tp) {
			if (n_template_arg_string) {
				tp->dcl_print(0); return;
			} else
			if(tp->base == COBJ) {
				Pclass cl = Pclass(Pbase(tp)->b_name->tp);
				if(cl && cl->base == CLASS && 
				  (cl->class_base == instantiated_template_class)) {
					Ptclass(cl)->inst->print_pretty_name(); return;
				}
			}
		}

		putst(n_template_arg_string ? n_template_arg_string : string);
		return;

	case MDOT:
		Pexpr(this)->print();
		return;
	}

	if (emode) {
		Ptable tbl;
		char* cs = 0;
		bit f = 0;
		if (tp) {
			switch (tp->base) {
			case OVERLOAD:
			case FCT:
				f = 1;
			default:
				if (tbl=n_table) {
					if (tbl == gtbl) {
						if (f == 0) putstring("::");
					}
					else {
						if (tbl->t_name) {
							Ptclass pc = Ptclass(tbl->t_name->tp);
							cs = tbl->t_name->string;
							if ((pc->base == CLASS)  && 
			    					(pc->class_base == instantiated_template_class))
			  						pc->inst->print_pretty_name();
							else fprintf(out_file,"%s",cs);
							fprintf (out_file, "::") ;
						}
					}
				}

				if (n_scope==ARG && strcmp(string,"this")==0) {
					// tell which "this" it is
					Ptype tt = Pptr(tp)->typ;
					Pname cn = Pbase(tt)->b_name;
					fprintf(out_file,"%s::",cn->string);
				}

			case CLASS:
			case ENUM:
		//	case TYPE:
				break;
			}
		nop:
			switch (n_oper) {
			case TYPE:
				putstring("operator ");
				if (tp)	Pfct(tp)->returns->dcl_print(0);
				break;
			case 0:
				putstring(string);
				break;
			case DTOR:
				putch('~');
			case CTOR:
				if (cs) {
		    			if(tbl->t_name) {
						Ptclass pc = Ptclass(tbl->t_name->tp);
						if ((pc->base == CLASS) && 
			    				(pc->class_base == instantiated_template_class))
			    					pc->inst->print_pretty_name();
						else putstring(cs);
					}
				}
				else {
					if (string)
						fprintf(out_file,"%s()", n_template_arg_string 
							? n_template_arg_string : string);
					else putstring("constructor");
					f = 0;
				}
				break;
			case TNAME:
				putstring(string);
				break;
			default:
				putstring("operator ");
				putstring(keys[n_oper]);
				break;
			}
			if (f) putstring("()");
		}
		else {
			if (n_oper) goto nop;
			if (string) 
 				putstring(n_template_arg_string 
					? n_template_arg_string : string);
		}
		return;
	}
	
	char* sig = 0;
	Pclass cl = 0;
	Penum en = 0;
	int i = n_union;

	if (tp) {
		Ptable tbl;

		switch (tp->base) {
		default:
			if (tbl=n_table) {	// global or member
				Pname tn;
				if (tbl == gtbl) {
					// if (i) fprintf(out_file,"__O%d.",i);
					if ( i ) {
						if (n_anon) 
    						fprintf(out_file,"__O%d.%s.", i, n_anon );
					else fprintf(out_file,"__O%d.",i);
					}
					break;
				}

				if (tn=tbl->t_name) { 
					cl = Pclass(tn->tp);
					if (i) { 
						if (cl->string[0]=='_'	
						    && cl->string[1]=='_'
						    && cl->string[2]=='C' ) {
							if (n_anon)
    						    		fprintf(out_file,"__O%d.%s.", i, n_anon );
							else fprintf(out_file,"__O%d.",i);
						}
						else
						if ( cl->nested_sig ) 
							fprintf(out_file,"__O%d__%s.",i,cl->nested_sig);
						else
						if ( cl->lex_level ) {
							char *str = make_local_name(cl,1);
							fprintf(out_file,"__O%d%s.",i,str);
							delete str;
						}
						else fprintf(out_file,"__O%d__%d%s.",i,cl->strlen,cl->string);
						cl = 0;
					}
					else 
					if (cl->string[0]=='_'
						&& cl->string[1]=='_'
						&& cl->string[2]=='C'
						&& n_stclass != STATIC )
							cl = 0;
					break;
				}
			}

			switch (n_stclass) {	// local variable
			case STATIC:
			case EXTERN:
				if (i)
					fprintf(out_file,"__O%d.",i);
				else if (n_sto==STATIC && tp->base!=FCT) {
					if (lex_level == 0)
						putstring("__S");
					else
						fprintf(out_file,"__%d",lex_level);
				}
				break;
			default:
				// encode with lexical level UNLESS ``special''
				// e.g. __builtin
				if (string[0]!='_' || string[1]!='_' || string[2] != 'C' ) {
					if (i)
					{
						if (n_anon)
						    fprintf(out_file,"__%d__O%d.%s.",lex_level-1,i,n_anon);
						else fprintf(out_file,"__%d__O%d.",lex_level-1,i);
					}
					else
						fprintf(out_file,"__%d",lex_level);
				}
			}
			break;
		case CLASS:
		case ENUM:
			if (tp->in_class && tp->nested_sig) en = Penum(tp);
			break;
		}

		if (tp->base==FCT) {
			sig = Pfct(tp)->f_signature;
			if (sig && sig[0]==0) sig = 0;
		}
	}

	if (string) {
#ifdef DENSE
		int i = strlen(string);
		if (cl) i += cl->strlen+4;	// __dd<class name>
		if (sig) {
			if (cl == 0) i += 2;
			i += strlen(sig);
		}

		if (31<i) {
			char buf[256];
			if (cl && sig)
				sprintf(buf,"%s__%d%s%s",string,cl->strlen,cl->string,sig);
			else if (cl)
				sprintf(buf,"%s__%d%s",string,cl->strlen,cl->string);
			else if (sig)
				sprintf(buf,"%s__%s",string,sig);
			else 
				sprintf(buf,"%s",string);
			chop(buf);
			fprintf(out_file,"%s ",buf);
			return;
		}
#endif

		if ( en )
    			fprintf(out_file,"__%s", en->nested_sig);
		else 
        		putstring(n_template_arg_string 
				? n_template_arg_string : string);

		if ( cl ) {
			if ( cl->nested_sig )
		        	fprintf(out_file,"__%s",cl->nested_sig);
			else
			if ( cl->lex_level ) {
				char *str = make_local_name( cl, 1 );
				putstring( str );
				delete str;
			}
		        else fprintf(out_file,"__%d%s",cl->strlen,cl->string);
		}

		if (sig) {
			if (cl == 0) putstring("__");
			putstring(sig);
		}
		putch(' ');
	}
}

#ifdef DENSE
void chop(char* buf)
{
	static char alpha[] = "_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
	static const asz = sizeof(alpha)-1;
	int hash = 0;
	char* p = &buf[29];
			
	while (*p) {
		hash <<= 1;
		if (hash & (1<<12)) {
			hash &= ~(1<<12);
			hash++;
		}
		hash ^= *p++;
	}

	buf[29] = alpha[(int)(hash%asz)];
	buf[30] = alpha[(int)((hash/asz)%asz)];
	buf[31] = 0;
}
#endif

void type::print()
{
	switch (base) {
	case PTR:
	case RPTR:
	case VEC:
		Pptr(this)->dcl_print(0);
		break;
	case FCT:
		Pfct(this)->dcl_print();
		break;
//	case VEC:
//		Pvec(this)->dcl_print(0);
//		break;
	case CLASS:
	case ENUM:
		if (emode)
			fprintf(out_file,"%k",base);
		else
		//	error('i',"%p->T::print(%k %s)",this,base,Pclass(this)->string);	
			fprintf(out_file,"struct %s *",Pclass(this)->string);
		break;
	case TYPE:
		if (Cast||Pbase(this)->b_name->lex_level) {
			Pbase(this)->b_name->tp->print();
			break;
		}
		// no break
	default:
		Pbase(this)->dcl_print();
	}
}

char* type::signature(register char* p)
/*
	take a signature suitable for argument types for overloaded
	function names
*/
{
	Ptype t = this;
	int pp = 0;	// pointer to

xx:
//error('d',"xx(%d) %d %k",this,t,t->base);

	// first unroll typedefs and handle derived types:

	switch (t->base) {
	case TYPE:
		if (Pbase(t)->b_const) *p++ = 'C';
		t = Pbase(t)->b_name->tp;
		goto xx;

	case VEC:
               if (pp && Pvec(t)->size) {           // A<size>_
			*p++ = 'A';
			sprintf(p,"%d\0",Pvec(t)->size); // don't trust
							 // sprintf return value
			while (*++p);
			*p++ = '_';
		}
		else
			*p++ = 'P';
		t = Pvec(t)->typ;
		pp = 1;
		goto xx;

	case PTR:
		if (Pptr(t)->rdo) *p++ = 'C';		// *const
		if (Pptr(t)->memof) {			// M<size><classname>
			Pclass cl = Pptr(t)->memof;
			register char* s = cl->string;
			int d = cl->strlen;
			if (d==0) cl->strlen = d = strlen(s);
	 		*p++ = 'M';
			if (d/10) *p++ = '0'+d/10;
			*p++ = '0'+ d%10;	// assume <100 char
			while (*p++ = *s++);
			--p;				// not the '\0'
		}
	 	else
			*p++ = 'P';
		t = Pptr(t)->typ;
		pp = 1;
		goto xx;

	case RPTR:
		*p++ = 'R';
		t = Pptr(t)->typ;
		pp = 1;
		goto xx;

	case FCT:
	{	Pfct f = Pfct(t);
		Pname n = f->argtype;

		if (f->f_const) *p++ = 'C';	// constant member function
		if (f->f_static) *p++ = 'S';	// static member function
	//	if (f->memof && f->f_this==0) *p++ = 'S';	//SSS static member function
		*p++ = 'F';
		if (n == 0)
			*p++ = 'v';	// VOID, that is f() == f(void)
		else
	for ( ; n; n=n->n_list) {	// print argument encoding
					// check if argtype is the same
					// as previously seen argtype
		int i = 0;
		for (Pname nn=f->argtype; n!=nn; nn=nn->n_list) {
			i++;
			if (nn->tp==n->tp || nn->tp->check(n->tp,0)==0) {
				// typeof (n) == typeof(arg i)
				int x = 1;	// try for a run after n
				Pname nnn = n;
				while ((nnn=nnn->n_list) && x<9) {
					if (nnn->tp==n->tp
					|| nnn->tp->check(n->tp,0)==0) {
						x++;
						n = nnn;
					}
					else
						break;
				}

				if (x == 1)		// Ti
					*p++ = 'T';
				else {			// Nxi
					*p++ = 'N';
					*p++ = '0'+x;
				}
	
				// assume <100 arguments
				if (9<i) *p++ = '0'+i/10;
				*p++ = '0'+i%10;
				goto zk;
			}	
		}

		// ``normal'' case print argument type signature
	//	if (n->n_xref) *p++ = 'R';
		p = n->tp->signature(p);
		zk:;
	}

		if (f->nargs_known == ELLIPSIS) *p++ = 'e';

		if (pp) {		// '_' result type
			*p++ = '_';
			p = f->returns->signature(p);
		}

		*p = 0;
		return p;
	}
	}

	// base type modifiers:

	if ( Pbase(t)->b_const )	*p++ = 'C';
//	if ( Pbase(t)->b_signed )	*p++ = 'S';
	if ( Pbase(t)->b_unsigned )	*p++ = 'U';
//	if ( Pbase(t)->b_volatile )	*p++ = 'V';


	// now base types:

	register char *s, *ns = 0;;
	int d;
	Pclass cl;
//lll:
	switch (t->base) {
//	case TNAME:	t = Pbase(t)->b_name->tp; goto lll;
	case ANY:			break;
	case ZTYPE:			break;
	case VOID:	*p++ = 'v';	break;
	case CHAR:	*p++ = 'c';	break;
	case SHORT:	*p++ = 's';	break;
//	case EOBJ:
	case INT:	*p++ = 'i';	break;
	case LONG:	*p++ = 'l';	break;
	case FLOAT:	*p++ = 'f';	break;
	case DOUBLE:	*p++ = 'd';	break;
	case LDOUBLE:	*p++ = 'r';	break;
	case EOBJ:
//		*p++ = 'i';
//		break;
	{	Penum en = Penum(Pbase(t)->b_name->tp);
	//	t = en->e_type;
	//	goto lll;
		ns = en->nested_sig; 
		s = en->string;
		d = en->strlen;
		if (d==0) en->strlen = d = strlen(s);
		goto pppp;
	}

	case COBJ:
	{	cl = Pclass(Pbase(t)->b_name->tp);
		ns = cl->nested_sig;
		s = cl->string;
		d = cl->strlen;
		if (d==0) cl->strlen = d = strlen(s);
	pppp:
		if ( ns == 0 ) {
			if (d/10) *p++ = '0'+d/10;
			*p++ = '0'+ d%10;	// assume less that 99 characters
		}
		else s = ns;

		while (*p++ = *s++);
		--p;
		break;
	}
	case FIELD:
	default:
		error('i',"signature of %k",t->base);
	}

	*p = 0;
	return p;
}

void basetype::dcl_print()
{
	Pname nn;
	Pclass cl;

	if (emode) {
		if (b_virtual) puttok(VIRTUAL);
		if (b_inline) puttok(INLINE);
	}
	if(ansi_opt || emode)
		if (b_const) puttok(CONST);
	if (b_unsigned) puttok(UNSIGNED);

	switch (base) {
	case ANY:
		if (emode)
			putstring("any ");
		else
			putstring("int ");
		break;

	case ZTYPE:
		if (emode)
			putstring("zero ");
		else
			putstring("int ");
		break;

	case VOID:
                if (emode==0 && ansi_opt==0) {
                        // silly trick to bypass BSD C compiler bug
                        // void* (*)() dosn't work there
                        // note simpl.c knows that VOID -> CHAR grep for VCVC
                        puttok(CHAR);
			break;
                } 
	case CHAR:
	case SHORT:
	case INT:
	case LONG:
	case FLOAT:
	case DOUBLE:
        case LDOUBLE:
		puttok(base);
		break;

	case EOBJ:
		nn = b_name;
	eob:
		if (emode == 0)
		//	puttok(INT);
			Penum(nn->tp)->e_type->dcl_print();
        	else {
                        puttok(ENUM);
                        nn->print();
		}
                break;

	case COBJ:
		nn = b_name;
	cob:
		cl = Pclass(nn->tp);
		if (emode && (cl->base == CLASS)  &&
			(cl->class_base == instantiated_template_class)) {
				Ptclass(cl)->inst->print_pretty_name();
				break;
		} else
		if (cl && (cl->csu==UNION || cl->csu==ANON))
			puttok(UNION);
		else puttok(STRUCT);
		{ 
			char* s = 0;
			if ( cl && cl->nested_sig )
			       	fprintf(out_file," __%s ",cl->nested_sig);
			else {
				if ( cl && cl->lex_level )
					s = make_local_name( cl );
				putst(s?s:nn->string);
				delete s;
			}
		}
		break;

	case TYPE:
		if (emode == 0) {
			switch (b_name->tp->base) {
			case COBJ:
				nn = Pbase(b_name->tp)->b_name;
				goto cob;
			case EOBJ:
				nn = Pbase(b_name->tp)->b_name;
				goto eob;
			}
		}
		b_name->print();
		break;

	default:
		if (emode) {
			if (0<base && base<=MAXTOK && keys[base])
				fprintf(out_file," %s",keys[base]);
			else
				putch('?');
		}
		else
			error('i',"%p->BT::dcl_print(%d)",this,base);
	}
}
Pbase memptr_type;

void type::dcl_print(Pname n)
/*
	"this" type is the type of "n". Print the declaration
*/
{
//error('d',"%p::dcl_print(%n)",this,n);
	Ptype t = this;
	Pptr p;
	TOK pre = 0;

	if (t == 0) error('i',"0->dcl_print()");
	if (n && n->tp!=t) error('i',"not %n'sT (%p)",n,t);

	if (base == OVERLOAD) {
		for (Plist gl=Pgen(this)->fct_list; gl; gl=gl->l) {
			Pname nn = gl->f;
			nn->tp->dcl_print(nn);
			if (gl->l) puttok(SM);
		}
		return;
	}

	tbuf = tbufvec[freetbuf];
	if (tbuf == 0) {
		if (freetbuf == NTBUF-1) error('i',"AT nesting overflow");
		tbufvec[freetbuf] = tbuf = new class dcl_buf;
	}
	freetbuf++;
	if ( base==FIELD && Pbase(this)->b_bits == 0 )
		tbuf->init(0);// some compilers can't handle mangled names here
	else
		tbuf->init(n);
	if (n && n->n_xref) tbuf->front(PTR);

	while (t) {
		TOK k;

		switch (t->base) {
		case PTR:
			p = Pptr(t);
			k = (p->rdo) ? CONST_PTR : PTR;
			goto ppp;
		case RPTR:
			p = Pptr(t);
			k = (p->rdo) ? CONST_RPTR : RPTR;
		ppp:
			if (p->memof) {
				if (emode) {
					tbuf->front(k);
					tbuf->front(p->memof);
				}
				else {
					t = p->typ;
					while (t->base==TYPE) t = Pbase(t)->b_name->tp;
					if (t->base == FCT) {
						tbuf->base(mptr_type);
						goto zaq;
					}
					else
						tbuf->front(k);
				}
			}
			else
				tbuf->front(k);
			pre = PTR;
			t = p->typ;
			break;
		case VEC:
		{	Pvec v = Pvec(t);
			if (Cast && pre != PTR && pre != VEC) {	// for Macintosh: ptr to array uses [] notation
				tbuf->front(PTR);
				pre = PTR;
			}
			else {
				if (pre == PTR) tbuf->paran();
				tbuf->back(VEC,v);
				pre = VEC;
			}
			t = v->typ;
			break;
		}

		case FCT:
		{	Pfct f = Pfct(t);
			if (pre == PTR)
				tbuf->paran();
			else if (emode && f->memof && n==0)
				tbuf->front(f->memof);
			tbuf->back(FCT,f);
			pre = FCT;
			t = (f->s_returns) ? f->s_returns : f->returns;
			break;
		}
		case FIELD:
			tbuf->back(FIELD,t);
			tbuf->base( Pbase(Pbase(t)->b_fieldtype) );
			t = 0;
			break;
		case 0:
			if(!emode)error('i',"noBT(B=0)");
			goto dobase;
		case TYPE:
			if (Cast||Pbase(t)->b_name->lex_level) { // unravel type in case it contains vectors
				t = Pbase(t)->b_name->tp;
				break;
			}
		default: // the base has been reached
		dobase:
			if (emode) {
				char* s;
				for (Ptype tt = t; tt->base==TYPE; tt=Pbase(tt)->b_name->tp);
				switch (tt->base) {
				case CLASS:
					s = Pclass(tt)->string;
                                        if (Ptclass(this)->class_base == instantiated_template_class ||
                                            Ptclass(this)->class_base == uninstantiated_template_class) {
                                     		Ptclass(this)->inst->print_pretty_name();
                                        	--freetbuf;
                                        	return;
                                        }
					if (s[0]=='_' &&s[1]=='_' && s[2]=='C') s="class";
					goto fret;
				case ENUM:
					s = "enum";
					goto fret;
				case OVERLOAD:
					s = "overloaded";
				fret:
					putstring(s);
					freetbuf--;
					return;
				}
			}

			tbuf->base( Pbase(t) );
			goto zaq;
		} // switch
	} // while
zaq:
	tbuf->put();
	freetbuf--;
}

void fct::dcl_print()
{
	Pname nn;
//error('d',"fct::dcl_print()");
	if (emode) {
		putch('(');
		for (nn=argtype; nn;) {
			nn->tp->dcl_print(0);
			if (nn=nn->n_list) puttok(CM); else break;
		}
		switch (nargs_known) {
		case 0:		//	putst("?"); break;
		case ELLIPSIS:	puttok(ELLIPSIS); break;
		}
		putch(')');
		if (f_const) puttok(CONST);	
		if (f_static) puttok(STATIC);	// wrong place for ``static''
		return;
	}

	Pname at = f_args;
	putch('(');

	if (ansi_opt) {
		// print typed arguments:
		at = (f_this) ? f_this : (f_result) ? f_result : argtype; 
		// WNG -- note:  at = f_args had 0 value with ansi_opt set
		//               mystery fix added here
		if (at == 0) {
			if (nargs_known == ELLIPSIS) {
				putch(')');
				return;
			}
			puttok(VOID);
		}
		else if (body && Cast==0)
			at->dcl_print(CM);	// print argument type and name
		else {
			for (nn=at; nn;) {
			//	nn->tp->dcl_print(0);	// print argument type
				nn->tp->dcl_print(nn);	// print argument type
							// (there may not be a name)
				if (nn=nn->n_list) puttok(CM); else break;
			}
		}
		if (nargs_known == ELLIPSIS) putstring(",...");
		putch(')');
	}
	else {
		// print argument names followed by argument type declarations:
		if (body && Cast==0) {
			for (nn=at; nn;) {
				nn->print();
				if (nn=nn->n_list) puttok(CM); else break;
			}
#ifdef mips
			if (nargs_known == ELLIPSIS)
				putstring(", va_alist");
#endif
#ifdef sparc
                        if (nargs_known == ELLIPSIS)
                                putstring(", __builtin_va_alist");
#endif
			putch(')');
		}
		else
			putch(')');
	}
}

void print_body(Pfct f)
{
	if (Cast==0) {
		
		if (ansi_opt==0 && f->f_args) {
			f->f_args->dcl_print(SM);
			if ( last_ll==0 && (last_ll = f->body->where.line) )
				f->body->where.putline();
		}

		if (MAIN) {
			putstring("{ _main(); ");	// call constructors
			f->body->print();
			puttok(RC);
		}
		else 
			f->body->print();
	}
}

Pbcl shared_seen;

void classdef::print_members()
{
	int i;
	
	Pbcl l = baselist;
// error('d',"%t->print_members()",this);
	if (l) {
		if (l->base == NAME) {
			l->bclass->print_members();	// first base only
			// pad to ensure alignment:
			int boff = l->bclass->real_size;
			int ba = l->bclass->align();
			int xtra = boff%ba;
			int waste = (xtra) ? ba-xtra : 0;	// padding
//error('d',"%s: size % align %d waste %d",string,boff,ba,waste);
			if (waste) {
				// waste it to protect against structure
				// assignments to the base class
				char* s = make_name('W');
				fprintf(out_file,"char %s[%d];\n",s,waste);
				delete s;
			}
			l = l->next;
		}

		for (; l; l=l->next)
		/*	for second base etc. one must allocate as an object
			(rather than a list of members) to ensure proper alignment
			for shared base allocate a pointer
			size, alignment, & offset handled in cassdef::dcl()
		*/
			if (l->base == NAME) {
				Pclass bcl = l->bclass;
        			char *str =  0;
				char *cs = bcl->nested_sig?bcl->nested_sig:bcl->string;
				if (bcl->lex_level && 
					bcl->nested_sig==0) 
						str=make_local_name(bcl);
				puttok(STRUCT);
				putst(str?str:cs);
				putcat('O',bcl->string); // leave as unencoded
				puttok(SM);
				delete str;
			}
	}

    	// Sam: A class or an enum type declared within a class can hide a
    	// member with the same name, so make sure that it gets printed by
    	// traversing the n_tbl_list to get at these names.
    	for (Pname nn=memtbl->get_mem(i=1); nn; nn=memtbl->get_mem(++i)) {
    	  do { if (nn->base==NAME
		&& nn->n_union==0
		&& nn->tp->base!=FCT
		&& nn->tp->base!=OVERLOAD
		&& nn->tp->base!=CLASS
		&& nn->tp->base!=ENUM
		&& nn->n_stclass != STATIC) {
		//	if (nn->tp->base==FIELD && Pbase(nn->tp)->b_bits==0) continue;
			Pexpr i = nn->n_initializer;
			nn->n_initializer = 0;
			nn->dcl_print(0);
			nn->n_initializer = i;
    		}
    	  } while ((nn->base == NAME) &&
    		 ((nn->tp->base!=CLASS) || (nn->tp->base!=ENUM)) &&
    		 (nn = nn->n_tbl_list)) ;
	}

	for (l=baselist; l; l=l->next)
		if (l->base==VIRTUAL && l->ptr_offset) {
			Pclass bcl = l->bclass;
       			char* str =  0;
			char *cs = bcl->nested_sig?bcl->nested_sig:bcl->string;
			if (bcl->lex_level && 
				bcl->nested_sig==0) 
					str=make_local_name(bcl);
			puttok(STRUCT);
			putst(str?str:cs);
			putch('*');
			putcat('P',bcl->string); // leave unencoded
			puttok(SM);
			delete str;
		}
}

// void classdef::print_vtbl(Pvirt vtab)
// {
// error('d',"%s->print_vtbl(%s) vtbl_opt %d",string,vtab->string,vtbl_opt);
// error('d',"print_vtbl: lex_level: %d", lex_level );
// 
//	switch (vtbl_opt) {
//	case -1:
//	case 1:
// 		vlist = new vl(this,vtab,vlist);
//	}
//
//	int oo = vtbl_opt;	// make `simulated static' name
//	vtbl_opt = -1;
//      char* str =  lex_level ? make_local_name(this) : 0;
//      char* s = vtbl_name(vtab->string,str?str:string);
//	vtbl_opt = oo;
//	fprintf(out_file,"extern struct __mptr %s[];\n",s);
//	s[2] = 'p';	// pointer, not tbl itself
//	fprintf(out_file,"extern struct __mptr* %s;\n",s);
//
//       delete s;
//	delete str;
// }

vl* vlist;

void really_really_print(Pclass cl, Pvirt vtab, char* s, char* ss);

int p2(Pname nn, Ptype t, Pclass cl, Pvirt vtab, char* s)
{
	int init;

	if (t->base == FCT) {
		Pfct f = Pfct(t);

//error('d',"p2 %n init %d inline %d virtual %d",nn,nn->n_initializer,f->f_inline,f->f_virtual);
//error('d',"p2 %s expr %d imeasure %d body %d",s,f->f_expr,f->f_imeasure,f->body);
//error('d',"sto %k",nn->n_sto);
		if (nn->n_initializer
		|| nn->n_sto==STATIC
		|| f->f_inline
		|| f->f_imeasure
		|| f->f_virtual==0) return 0;
		init = f->body!=0;
	}
	else
		init = nn->n_initializer!=0;

	int oo = vtbl_opt;
	vtbl_opt = 1;	// make sure the name is universal
	char *cs = cl->nested_sig?cl->nested_sig:cl->string;
        char* sstr = (cl->lex_level&&cl->nested_sig==0)? make_local_name(cl) : 0;
        char* ss = vtbl_name(vtab->string,sstr?sstr:cs);

	if (init) {	// unique definition here
		really_really_print(cl,vtab,ss,s);
	}
	else {	// unique definition elsewhere
		char *vstr = 0;
		if ( vtab && vtab->string ) {
			vstr = new char[strlen(vtab->string)+cl->strlen+1];
			strcpy( vstr, vtab->string );
			strcat( vstr, cl->string );
		}
		Pname nn;
		if (nn=ptbl->look(vstr?vstr:cl->string,0)) { // use of ptbl in file
        		fprintf(out_file,"extern struct __mptr %s[];\n",ss);
			s[2] = 'p';
        		// fprintf(out_file,"struct __mptr* %s = ",s);
        		// fprintf(out_file,"%s;\n",ss);
			ptbl_add_pair(s, ss);
			nn->n_key=HIDDEN; 
		}
		delete vstr;
	}
	vtbl_opt = oo;

	delete ss;
	delete sstr;

	return 1;
}

void classdef::really_print(Pvirt vtab)
{
// error('d',"really_print %t %d",this,vtbl_opt);
	int oo = vtbl_opt;	// make `simulated static' name
	vtbl_opt = -1;
	char *cs = nested_sig?nested_sig:string;
        char* str = (lex_level&&nested_sig==0) ? make_local_name(this) : 0;
        char* s = vtbl_name(vtab->string,str?str:cs);
// error('d', "really_print: %s, vtab: %s, s: %s", string, vtab->string, s );
	vtbl_opt = oo;

	// see if needed
	int i;
	for (Pname nn=memtbl->get_mem(i=1); nn; nn=memtbl->get_mem(++i) ) {
		Ptype t = nn->tp;
	zse:
		if (t)
		switch (t->base) {
		case TYPE:
			t = Pbase(t)->b_name->tp;
			goto zse;
/*
		case COBJ:
			if (nn->n_sto == EXTERN)
			{	Pclass cl = Pclass(Pbase(t)->b_name->tp);
				if (cl->has_ctor()) {
					p2(nn,t,this,vtab,s);
					return;
				}
			}
			break;
*/
		case FCT:
			if (p2(nn,t,this,vtab,s))
				goto xyzzy;
			break;

		case OVERLOAD:
		{	for (Plist gl=Pgen(t)->fct_list; gl; gl=gl->l)
				if (p2(gl->f,gl->f->tp,this,vtab,s))
					goto xyzzy;
		}
		}
	}

        { // must be initialized var in block to permit goto
	char* ss = vtbl_name(vtab->string,str?str:cs);
// error('d', "really_print: %s, vtab: %s, ss: %s", cs, vtab->string, s );

	if (vtbl_opt)
		really_really_print(this,vtab,ss,s);
	else {
		char *vstr = 0;
		if ( vtab && vtab->string ) {
			vstr = new char[::strlen(vtab->string)+strlen+1];
			strcpy( vstr, vtab->string );
			strcat( vstr, string );
		}
		Pname nn;
		if (nn=ptbl->look(vstr?vstr:string,0)) { // use of ptbl in file
        		fprintf(out_file,"extern struct __mptr %s[];\n",ss);
			s[2] = 'p';
        		// fprintf(out_file,"struct __mptr* %s = ",s);
        		// fprintf(out_file,"%s;\n",ss);
			ptbl_add_pair(s, ss);
			nn->n_key=HIDDEN; 
		}
		delete vstr;
	}
	delete ss;
	}
xyzzy:
	delete s;
	delete str;
}

void really_really_print(Pclass cl, Pvirt vtab, char* s, char* ss)
{
// error('d',"really %s %s",s, ss);
	// make sure function is declared before using
	// it in vtbl initializer
	Pname nn;
	int i;
	for (i=0; nn = vtab->virt_init[i].n; i++) {
		Pfct f = Pfct(nn->tp);
                if (nn->n_initializer) {       // pure virtual
			static pv;
			if (pv == 0) {	// VCVC void->char assumed
				fprintf(out_file,"char __pure_virtual_called();\n");
				pv = 1;
			}
			continue;
		}
		if (f->base != FCT) error('i',"vtbl %n",nn);
//extern void expand_dtor(Pclass cl);
//		if (f->f_inline == IDTOR) expand_dtor(f->memof);

		if (nn->n_dcl_printed==0 /*|| f->f_inline*/) {
			if (f->f_inline && vtbl_opt) puttok(STATIC);
			if (f->f_result == 0) make_res(f);
			Ptype r = f->s_returns ? f->s_returns : f->returns;
			r->print();
			nn->print();
			putstring("()");
			puttok(SM);
			nn->n_dcl_printed = 1;
		}
	}

//	if (vtbl_opt == -1) puttok(STATIC);


        fprintf(out_file,"struct __mptr %s[] = {0,0,0,\n",s);

	Pname n;
	for (i=0; n=vtab->virt_init[i].n; i++) {
		if (n->n_initializer)
			putstring("0,0,(__vptp)__pure_virtual_called,\n");
		else {
			fprintf(out_file,"%d,0,(__vptp)",-vtab->virt_init[i].offset);
			n->print();
			n->n_addr_taken = 1;
			putstring(",\n");
		}
	}
	putstring("0,0,0};\n");

	ss[2] = 'p';
        // fprintf(out_file,"struct __mptr* %s = ",ss);
	s[2] = 'v';
        // fprintf(out_file,"%s;\n",s);
	ptbl_add_pair(ss,s);

        Pname nm;
	char *cstr = 0;
	char *vstr = 0;
	char *cs = cl->nested_sig?cl->nested_sig:cl->string;
	if (cl->lex_level && cl->nested_sig==0) cstr = make_local_name( cl );
	if ( vtab && vtab->string ) {
		vstr = new char[strlen(vtab->string)+(cstr?strlen(cstr):strlen(cs))+1];
		strcpy( vstr, vtab->string );
		strcat( vstr, cstr?cstr:cs );
	}

	if ( vstr == 0 ) vstr = cstr;
	if ( nm = ptbl->look(vstr?vstr:cl->string,0) ) 
		nm->n_key = HIDDEN;
	else 
	if ( ptbl->look(vstr?vstr:cl->string,HIDDEN) == 0 )
		ptbl->insert(new name(vstr?vstr:cl->string),HIDDEN);
        if (cstr == vstr) delete cstr;
        else {
                delete cstr;
                delete vstr;
        }

//error('d',"really-> %s",s);
}

#include <ctype.h>
char* vtbl_name(char* s1, char* s2)
{
	char* s3 = (vtbl_opt == -1 && *src_file_name) ? src_file_name : 0;
		// if vtbl_opt == -1 fake a static (there are no portable
		// way of doing a forward declaration of a static in C)
	int ll = s1 ? strlen(s1) : 0;
	int ll2 = strlen(s2);
	int ll3 = s3 ? strlen(s3) : 0;
        int sz = (ll+ll2+ll3+20)/32+1;  // avoid fragmentation

        sz *= 32;
// error('d',"vtbl_name(%s,%s,%s) %d",s1?s1:"",s2,s3?s3:"",sz);
        char* buf = new char[sz];
	if (s3) {
		if (s1)
			sprintf(buf,"__vtbl__%d%s__%d%s__%s",ll,s1,ll2,s2,s3);
		else
			sprintf(buf,"__vtbl__%d%s__%s",ll2,s2,s3);
	}
	else if (s1)
		sprintf(buf,"__vtbl__%d%s__%d%s",ll,s1,ll2,s2);
	else
		sprintf(buf,"__vtbl__%d%s",ll2,s2);

	if (vtbl_opt == -1) {
		for (char* p = buf+ll2+11; *p; p++)
			if (!isalpha(*p) && !isdigit(*p)) *p = '_';
	}
#ifdef DENSE
	chop(buf);
#endif
	return buf;
}

void classdef::print_all_vtbls(Pclass bcl)
{
//error('d',"%t->print_all_vtbls(%t) vlt %d bl %d",this,bcl,virt_list,baselist);

	for (Pvirt blist = bcl->virt_list; blist; blist = blist->next) {
		if (this != blist->vclass) continue;
		if (blist->printed) continue;
        //      if (blist->string==0 && find_vptr(this)==0) {        //BSopt
        //              continue;
        //      }
	//	print_vtbl(blist);
		vlist = new vl(this,blist,vlist);
		blist->printed = 1;
	}

	for (Pbcl b = bcl->baselist; b; b = b->next)
		print_all_vtbls(b->bclass);

	if (this==bcl) c_body = 0;
}

extern Pclass current_instantiation;
void classdef::dcl_print(Pname)
{ 
//error('d',"%t->classdef::dcl_print() -- c_body==%d defined==0%o",this,c_body,defined);
	defined |= REF_SEEN;
// ensure template instantiations are printed exactly once.
        if (class_base != vanilla_class && current_instantiation != this) return;

	if (c_body==0 || c_body==3 || (defined&DEFINED)==0) return;
	c_body = 3;

	int i;
	for (Pname nn=memtbl->get_mem(i=1); nn; nn=memtbl->get_mem(++i) ) {
		if (nn->base==NAME
		&& nn->n_union==0
		&& nn->tp->base==CLASS
		&& Pclass(nn->tp)->c_body==1)
			Pclass(nn->tp)->dcl_print(nn);
		else if (nn->base == TNAME && Pbase(nn->tp)->base != COBJ)
			nn->dcl_print(0);
                else if (nn->tp && nn->tp->base == ENUM) {
			if(nn->n_union==0) Penum(nn->tp)->dcl_print(nn);
		}
	}

	TOK lvl = in_class ? NESTED : lex_level ? LOCAL : 0;
	Pname n = ktbl->look(string,lvl);
	if (n==0) n = ktbl->look(string,HIDDEN);

	if (n) {
		if (n->where.line!=last_line.line
		|| n->where.file!=last_line.file)
			if (last_ll = n->where.line)
				n->where.putline();
			else
				last_line.putline();
	}

	TOK c = csu==CLASS ? STRUCT : csu;
	puttok(c);
//	if (string[0]!='_' || string[1]!='_' || string[2]!='C')

        char *str = 0;
	if ( lex_level && nested_sig == 0) str = make_local_name( this );
	if ( nested_sig ) putstring( " __" );
	putst(str?str:(nested_sig?nested_sig:string));

	int sm = 0;
	int sz = tsizeof();
	int dvirt = 0;

	if ( nested_sig )
		fprintf(out_file,"{\t/* sizeof __%s == %d */\n",nested_sig,obj_size);
	else
		fprintf(out_file,"{\t/* sizeof %s == %d */\n",str?str:string,obj_size);
	if ( last_ll ) last_line.line++;
	delete str;

	print_members();
	for (Pbcl b = baselist; b; b = b->next) {	// declare virtual classes
		if (b->base != VIRTUAL) continue;
		Pclass bcl = b->bclass;
		dvirt += bcl->virt_count;
//error('d',"%t in %t %d",b->bclass,this,b->allocated);
		if (b->allocated==0) continue;
        	char* str =  0;
		if (bcl->lex_level) str = make_local_name(bcl);
		puttok(STRUCT);			// struct bcl Obcl;
		putst(str?str:bcl->string);
		putcat('O',bcl->string); // leave unencoded
		puttok(SM);
		delete str;
	}
	putstring("};\n");
	if ( last_ll ) last_line.line++;

	for (nn=memtbl->get_mem(i=1); nn; nn=memtbl->get_mem(++i) ) {
		if (nn->base==NAME && nn->n_union==0) {
			Ptype t = nn->tp;
			switch (t->base) {
			case FCT:
			case OVERLOAD:
				break;
			default:
				if (nn->n_stclass == STATIC) {
					TOK b = nn->n_sto;
//error('d',"print nn %n tp %t b %k eval %d",nn,nn->tp,b,nn->n_evaluated);
				/*
					Pname cn;
					TOK bb = ((cn=nn->tp->is_cl_obj())
					&& Pclass(cn->tp)->has_ctor())==0
						?0:b; // force explicit initialization
					nn->n_sto = (nn->n_evaluated) ? STATIC : bb;
				*/
					nn->n_sto = (nn->n_evaluated) ? STATIC : b;
					nn->dcl_print(0);
					nn->n_sto = b;
				}
			}
		}
	}
	if (vtbl_opt != -1) print_all_vtbls(this);	// force declaration
//error('d',"dcl_print -> ");
}


char *
make_local_name( Pclass cl, int ln ) 
{
    char *buf; 
    if ( cl->in_fct == 0 ) error( 'i', "localC %s missingFN", cl->string ); 
    char *fsig = Pfct(cl->in_fct->tp)->f_signature;
    if ( fsig == 0 ) fsig = local_sign( cl->in_fct->tp );
    char *fs = cl->in_fct->string;
    int class_len=cl->strlen+strlen(fsig)+strlen(fs)+strlen(cl->lcl)+4;
    int sz = (class_len+20)/32+1; // from vtbl_name()

    if ( Pfct(cl->in_fct->tp)->memof == 0 ) {
	 sz *= 32;
	 buf = new char[ sz ];
// error('d', "make_local_name: sz: %d", sz );

         if (ln) 
             sprintf(buf, "__%d%s__%s__%s%s", class_len, cl->string, fs, fsig, cl->lcl);
	 else
             sprintf(buf, "%s__%s__%s%s", cl->string, fs, fsig, cl->lcl);
    }
    else 
    {
        char *cs = Pclass(Pfct(cl->in_fct->tp)->memof)->string;
        int len = Pclass(Pfct(cl->in_fct->tp)->memof)->strlen;
        if ( len < 10 )
	     ++class_len;
	else 
        if ( len > 99 )
	     class_len += 3;
	else class_len += 2;
	class_len += len;
        sz = (class_len+20)/32+1; 
	sz *= 32;
        buf = new char[ sz ];
// error('d', "make_local_name: sz: %d", sz );

	if ( ln )
             sprintf(buf, "__%d%s__%s__%d%s%s%s",class_len,cl->string,fs,len,cs,fsig,cl->lcl);
        else sprintf(buf, "%s__%s__%d%s%s%s",cl->string,fs,len,cs,fsig,cl->lcl);
    }

#ifdef DENSE
    chop( buf );
#endif

    return buf;
}

0707071010112046021004440001630000160000010210070466055415700001500000001262print_self.c/* ident "@(#)ctrans:src/print_self.c	1.2" */
/* print_self_default.C -- bailout versions of print_self and format_self */
/*
	$Source: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v $ $RCSfile: cfront.cpio,v $
	$Revision: 1.1.1.1 $		$Date: 2018/04/24 17:21:35 $
	$Author: root $		$Locker:  $
	$State: Exp $
*/

#include "print_self.h"

int ostream_printf (ostream&, const char * ...);

int _Print_self::print_self (ostream& stream) const
{
    return ostream_printf (stream, "<%s at 0x%p>", 
			   this->type_name(), (void *) this);
}

int _Print_self::format_self (ostream& stream) const
{
    return ostream_printf (stream, "<%s at 0x%p>", 
			   this->type_name(), (void *) this);
}
0707071010112046111004440001630000160000010211170466055421300001500000001261print_self.h/* ident "@(#)ctrans:src/print_self.h	1.2" */
/* print_self.H -- base class for objects that want to support
   the 'official' print self for \T in printf. */

/*
    $Header: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v 1.1.1.1 2018/04/24 17:21:35 root Exp $

    Copyright (c) 1989 by Object Design, Inc., Burlington, Mass.
    All rights reserved.

*/

#ifndef _PRINT_SELF_CLASS
#define _PRINT_SELF_CLASS
#include <iostream.h>

class _Print_self {
  public:
    virtual char * type_name () const { return "OBJECT"; }
    virtual int print_self (ostream&) const; // returns count of characters printed.
    virtual int format_self (ostream&) const; // returns count of characters printed.
};
#endif
0707071010112044421004440001630000160000010206300466055407100000700000010531repr.c/*ident	"@(#)ctrans:src/repr.c	1.4" */
/**************************************************************************

        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.

repr.c:

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

#include "cfront.h"

char* oper_name(TOK op)
/*
	return the string representation of operator "op"
*/
{
	switch (op) {
	default:	error('i',"oper_name(%k)",op);
	case GNEW:
	case NEW:	return "__nw";
	case GDELETE:
	case DELETE:	return "__dl";
	case MUL:	return "__ml";
	case DIV:	return "__dv";
	case MOD:	return "__md";
	case UPLUS:
	case PLUS:	return "__pl";
	case MINUS:
	case UMINUS:	return "__mi";
	case LS:	return "__ls";
	case RS:	return "__rs";
	case EQ:	return "__eq";
	case NE:	return "__ne";
	case LT:	return "__lt";
	case GT:	return "__gt";
	case LE:	return "__le";
	case GE:	return "__ge";
	case AND:
	case ADDROF:	return "__ad";
	case OR:	return "__or";
	case ER:	return "__er";
	case ANDAND:	return "__aa";
	case OROR:	return "__oo";
	case NOT:	return "__nt";
	case COMPL:	return "__co";
	case INCR:	return "__pp";
	case DECR:	return "__mm";
	case CALL:	return "__cl";
	case DEREF:	return "__vc";
	case ASSIGN:	return "__as";
	case REF:	return "__rf";
	case ASPLUS:	return "__apl";
	case ASMINUS:	return "__ami";
	case ASMUL:	return "__amu";
	case ASDIV:	return "__adv";
	case ASMOD:	return "__amd";
	case ASLS:	return "__als";
	case ASRS:	return "__ars";
	case ASAND:	return "__aad";
	case ASOR:	return "__aor";
	case ASER:	return "__aer";
	case CTOR:	return "__ct";
	case DTOR:	return "__dt";
//	operator T		"__op"<signature of T>
//	case SIZEOF:	return "sizeof";
	case CM:	return "__cm";
	case REFMUL:	return "__rm";
// library functions:
//				"_vec_delete"
//				"_vec_new"
//				"_main"
	}
}

#define new_op(ss,v) keys[v]=ss

void otbl_init()
/*
	operator representation table
*/
{
	new_op("->",REF);
	new_op("." ,DOT);
	new_op(".* or ->*" ,REFMUL);
	new_op("mdot" ,REFMUL);
	new_op("!" ,NOT);
	new_op("~" ,COMPL);
	new_op("++",INCR);
	new_op("--",DECR);
	new_op("*" ,MUL);
	new_op("&" ,AND);
	new_op("&" ,ADDROF);
	new_op("&" ,G_ADDROF);
	new_op("/" ,DIV);
	new_op("%" ,MOD);
	new_op("+" ,PLUS);
	new_op("+" ,UPLUS);
	new_op("-" ,MINUS);
	new_op("-" ,UMINUS);
	new_op("<<",LS);
	new_op(">>",RS);
	new_op("<" ,LT);
	new_op(">" ,GT);
	new_op("<=",LE);
	new_op(">=",GE);
	new_op("==",EQ);
	new_op("!=",NE);
	new_op("^" ,ER);
	new_op("|" ,OR);
	new_op("&&",ANDAND);
	new_op("||",OROR);
	new_op("?:" ,QUEST);
//	new_op(":" ,COLON);
	new_op("=" ,ASSIGN);
	new_op("," ,CM);
	new_op("," ,G_CM);

	new_op(";" ,SM);
	new_op("{" ,LC);
	new_op("}" ,RC);
	new_op("(" ,LP);
	new_op(")" ,RP);
	new_op("[" ,LB);
	new_op("]" ,RB);

	new_op("+=",ASPLUS);
	new_op("-=",ASMINUS);
	new_op("*=",ASMUL);
	new_op("/=",ASDIV);
	new_op("%=",ASMOD);
	new_op("&=",ASAND);
	new_op("|=",ASOR);
	new_op("^=",ASER);
	new_op(">>=",ASRS);
	new_op("<<=",ASLS);

//	new_op("sizeof",SIZEOF);
//	new_op("new",NEW);
//	new_op("delete",DELETE);

	new_op("0" ,ZERO);
	new_op("[]" ,DEREF);
	new_op("expression list", ELIST);
	new_op("initializer list", ILIST);
	new_op("static initializer", STAT_INIT);
	new_op("()", CALL);
	new_op("generated function call",G_CALL);
	new_op("inline function call",ICALL);
	new_op("cast",CAST);
	new_op("inline argument",ANAME);
	new_op("text",TEXT);
	new_op(".*",MEMPTR);

	new_op("class type", COBJ);
	new_op("enum type", EOBJ);
	new_op("union", ANON);

	new_op("function",FCT);
	new_op("pointer",PTR);
	new_op("reference",RPTR);
	new_op("array",VEC);
	new_op("identifier",ID);
	new_op("name",NAME);
	new_op("...",ELLIPSIS);
	new_op("::",MEM);
	new_op("type name",TYPE);
	new_op("tname",TNAME);
	new_op("{}",BLOCK);
	new_op("pair",PAIR);
	new_op("declaration",DCL);
	new_op("character constant",CCON);
	new_op("integer constant",ICON);
	new_op("float constant",FCON);
	new_op("integer value",IVAL);
	new_op("string",STRING);
	new_op("label",LABEL);
	new_op("'class', 'struct', or 'union'",AGGR);
	new_op(" argument",ARG);
	new_op(" empty expression",DUMMY);
	new_op(" ::new",GNEW);
	new_op(" constructor call",VALUE);
	new_op(" ::delete",GDELETE);
	new_op(ansi_opt?" long double":" double",LDOUBLE);
	new_op(" typedef",NESTED); // did not want to introduce new TOKEN
}
0707071010112044431004440001630000160000010206400466055407500001000000067265simpl.c/*ident	"@(#)ctrans:src/simpl.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.

simpl.c:

	simplify the typechecked function
	remove:		classes:
				class fct-calls
				operators
				value constructors and destructors
			new and delete operators (replace with function calls)
			initializers		(turn them into statements)
			constant expressions		(evaluate them)
			inline functions		(expand the calls)
			enums				(make const ints)
			unreachable code		(delete it)
	make implicit coersions explicit

	in general you cannot simplify something twice

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

#include "cfront.h"

Pname new_fct;
Pname del_fct;
Pname vec_new_fct;
Pname vec_del_fct;

Pstmt del_list;
Pstmt break_del_list;
Pstmt continue_del_list;

//bit not_inl;	// is the current function an inline?
Pname curr_fct;	// current function
Pexpr init_list;
Pexpr one;

Ptype Pfct_type;
Ptype Pvptr_type;
Pbase mptr_type;
Ptype size_t_type;

Pstmt trim_tail(Pstmt tt);
Pname find_vptr(Pclass);
char *get_classname(char*);
char *drop_classname(char*);
loc no_where;	// 0,0

int imeasure;	// a counter trying to measure the complexity of a function
		// body to try to avoid expanding ``monster'' inlines.

static Pclass topclass;

void simpl_init()
{
       char* ns = oper_name(NEW);
       char* ds = oper_name(DELETE);

	size_t_type = Pvoid_type->tsizeof()>uint_type->tsizeof()?ulong_type:uint_type;

       Pname nw = new name(ns);
       nw->n_oper = NEW;
       Pname a = new name;
       a->tp = size_t_type;
       nw->tp = new fct(Pvoid_type,a,1);
       new_fct = nw->dcl(gtbl,EXTERN); // void* operator new(long);
       delete nw;
 //    new_fct->use();

       Pname dl = new name(ds);
       dl->n_oper = DELETE;
       a = new name;
       a->tp = Pvoid_type;
       dl->tp = new fct(void_type,a,1);
       del_fct = dl->dcl(gtbl,EXTERN);
       delete dl;
 //    del_fct->use();


	Pname vn = new name("__vec_new");
	Pname vd = new name("__vec_delete");

	a = new name;
	a->tp = Pvoid_type;
	Pname al = a;
	a = new name;
	a->tp = int_type;
	a->n_list = al;
	al = a;
	a = new name;
	a->tp = int_type;
	a->n_list = al;
	al = a;
	a = new name;	
	a->tp = Pvoid_type;
	a->n_list = al;
	al = a;				/* (Pvoid, int, int, Pvoid) */

	vec_new_fct = gtbl->insert(vn,0);
	delete vn;
	vec_new_fct->tp = new fct(Pvoid_type,al,1);
	Pfct(vec_new_fct->tp)->f_linkage = linkage_C;
	vec_new_fct->n_scope = EXTERN;
	PERM(vec_new_fct);
	PERM(vec_new_fct->tp);
	vec_new_fct->use();
	vec_new_fct->dcl_print(0);

	a = new name;
	a->tp = int_type;
	al = a;
	a = new name;
	a->tp = int_type;
	a->n_list = al;
	al = a;
	a = new name;
	a->tp = Pvoid_type;
	a->n_list = al;
	al = a;
	a = new name;
	a->tp = int_type;
	a->n_list = al;
	al = a;
	a = new name;
	a->tp = int_type;
	a->n_list = al;
	al = a;
	a = new name;	
	a->tp = Pvoid_type;
	a->n_list = al;
	al = a;				/* (Pvoid, int, int, Pvoid, int, int) */

	vec_del_fct = gtbl->insert(vd,0);
	delete vd;
	vec_del_fct->tp = new fct(void_type,al,1);
	Pfct(vec_del_fct->tp)->f_linkage = linkage_C;
	vec_del_fct->n_scope = EXTERN;
	PERM(vec_del_fct);
	PERM(vec_del_fct->tp);
	vec_del_fct->use();
	vec_del_fct->dcl_print(0);

	one = new ival(1);
	one->tp = int_type;
	PERM(one);
	
	Pfct_type = new fct(int_type,0,1);	// int (*)()
	Pfct_type = Pfct_type->addrof();
	PERM(Pfct_type);

	putstring("typedef int (*__vptp)();\n");
	putstring("struct __mptr {short d; short i; __vptp f; };\n");
	Pname b = new name("__mptr");
        b->tp = new classdef(STRUCT);
        b->tp->defined = 1;
        Pclass(b->tp)->obj_size = 8;
	mptr_type = new basetype(COBJ,b);
	PERM(mptr_type);

	Pvptr_type = mptr_type->addrof();
	PERM(Pvptr_type);
}

Ptable scope;		/* current scope for simpl() */
Pname expand_fn;	/* name of function being expanded or 0 */
Ptable expand_tbl;	/* scope for inline function variables */

Pname classdef::has_oper(TOK op)
{
	Pexpr n = find_name(oper_name(op),0);
	if (n == 0) return 0;

	while (n->base==REF || n->base==MDOT) {
		Pexpr e = Pexpr(n);
		n = Pname(n->mem);
		delete e;
	}
	if (n->tp->base==FCT && Pname(n)->n_dcl_printed==0) Pname(n)->dcl_print(0);
	return Pname(n);
}

int is_expr(Pstmt s)
/*
	is this statement simple enough to be converted into an expression for
	inline expansion?
*/
{
	int i = 0;
	while (s->base == BLOCK) {
		if (s->s == 0) return 1;
		s = s->s;
	}
	for (Pstmt ss = s; ss; ss = ss->s_list) {
//error('d',"ss %k",ss->base);
		switch (ss->base) {
		case BLOCK:
			if (Pblock(ss)->memtbl || is_expr(ss->s)==0) return 0;
		case SM:
			if (ss->e && ss->e->base==ICALL) {
				Pname fn = ss->e->il->fct_name;
				Pfct f = Pfct(fn->tp);
				if (f->f_expr == 0) return 0;
			}
			break;
		case IF:
			if (is_expr(ss->s)==0) return 0;
			if (ss->else_stmt && is_expr(ss->else_stmt)==0) return 0;
			break;
		default:
			return 0;
		}
		i++;
	}
	return i;
}

int no_of_returns;

void name::simpl()
{
//error('d',"name::simpl%n %d %k",this,tp->base,tp->base);
	if (base == PUBLIC) return;

	if (tp == 0) error('i',"%n->N::simple(tp==0)",this);

	switch (tp->base) {
	case 0:
		error('i',"%n->N::simpl(tp->B==0)",this);

	case TYPE:
	case VEC:
	case PTR:
	{
		Ptype t = tp;
	xx:
		switch (t->base) {
		case TYPE:	t = Pbase(t)->b_name->tp;	goto xx;
		case VEC:	t = Pvec(t)->typ;		goto xx;
		case PTR:	t = Pptr(t)->typ;		goto xx;
		case FCT:	break;
		}
		break;
	}

	case OVERLOAD:
	{	for (Plist gl = Pgen(tp)->fct_list; gl; gl=gl->l) gl->f->simpl();
		break;
	}

	case FCT:
	{	Pfct f = Pfct(tp);
		Pname n;
		Pname th = f->f_this;

		if (th) {
			// Make "this" a register if it is used more than twice:
			if (th->n_addr_taken) error("&this");
			th->n_stclass = (2 < th->n_used) ? REGISTER : AUTO;
			if (warning_opt
			&& th->n_assigned_to
			&& th->n_assigned_to!=FUDGE111)
				error('w',&where,"assignment to this (anachronism)");
		}

		if (tp->defined & (SIMPLIFIED | ~DEFINED) ) return;

		for (n=f->f_args; n; n=n->n_list) n->simpl();

		if (f->body) {
			Ptable oscope = scope;
			Pname ocurr = curr_fct;
			int oim = imeasure;
			scope = f->body->memtbl;
//error('d',"body");
			if (scope == 0) error('i',"%n memtbl missing",this);
			curr_fct = this;
			f->simpl();
			if (f->f_inline==0 || debug_opt)
				f->f_imeasure = 0;	// not a converted inline
			else {
	
				if (warning_opt && f->f_virtual)
 					error('w',"virtual function %n cannot be inlined",this);
				// first check if the function is too large to
				// be worth inlining
				if (12<f->f_imeasure) {	// cut-over point:
							// about 12 assignments
							// f->f_imeasure indicates

					if (warning_opt) {
 						error('w',"%n too large for inlining",this);
 					}
					f->f_inline = 0;// a converted inline
//error('d',"don't inline%n %d %d %d",this,this,f,f->f_imeasure);
					scope = oscope;
					tp->defined |= SIMPLIFIED;
					return;
				}
				int i = 0;
				for (n=f->f_args; n; n=n->n_list) {
					n->base = ANAME;
					n->n_val = i++;
	// ??				if (n->n_table != scope) error('i',"aname scope: %d %n %d %d\n",n,n,n->n_table,scope);
				}
				expand_tbl = (f->returns->base!=VOID || n_oper==CTOR) ? scope : 0;
				expand_fn = this;

				if (expand_tbl) {
				genlab:
						// value returning: generate expr
						// the body still holds the memtbl
					Pexpr ee = Pexpr(f->body->expand());
					Ptype t = 0;
					if (f->s_returns) {
						if (ee->tp!=f->s_returns) t = f->s_returns;
					}
					else if (ee->tp!=f->returns)
						t = f->returns;
					// VCVC assumes VOID is output as CHAR:
					if (t && t==void_type)
						ee = new expr(CM,ee,new cast(char_type,zero));
					f->f_expr = (ee->base==CM) ? ee : new expr(CM,zero,ee);
					// print.c assumes expansion into comma expression
				}
				else {
					if (is_expr(f->body)) {
						// can generate expr: do
						expand_tbl = scope;
						goto genlab;
					}
					// not value return: can generate block
					f->f_expr = 0;
					f->body = Pblock(f->body->expand());
				}
				expand_fn = 0;
				expand_tbl = 0;
			}
			scope = oscope;
			curr_fct = ocurr;
			imeasure = oim;
		}
		break;
	}

	case CLASS:
		Pclass(tp)->simpl();
	}

//	if (n_initializer) n_initializer->simpl();
        if (n_key != NESTED && n_initializer) n_initializer->simpl();
	tp->defined |= SIMPLIFIED;
}

Pexpr call_ctor(Ptable tbl, Pexpr p, Pexpr ctor, Pexpr args, int d, Pexpr vb_args)
{
	Pexpr ee = new ref(d,p,ctor);
	if (p==0 || tbl==0) ee->tp = ctor->tp;
//error('d',"call_ctor(tbl %d, p %d, %n, args %d)",tbl,p,ctor,args);
	if (args && args->base!=ELIST) args = new expr(ELIST,args,0);
	ee = new expr(G_CALL,ee,args);
	Pname n = Pname(ctor);
	while (n->base == MDOT) n = Pname(n->mem);
	if (n->tp->base == FCT) ee->fct_name = n;
	if (tbl)
		ee = ee->typ(tbl);
	else if (n->tp->base == FCT)
		ee->tp = Pfct(n->tp)->s_returns;
	if (ee->tp == any_type) return ee;
	args = ee->e2;

	if (vb_args == 0) {		// attach zero vbase arguments
		Pfct f = Pfct(ee->fct_name->tp);	// not n->fct_name
		for (Pname nn = f->f_args->n_list; nn && nn!=f->argtype; nn=nn->n_list)
			args = new expr(ELIST,zero,args);
	}
	else {				// attach vbase arguments
		if (args) {
			for (Pexpr d = vb_args; d->e2; d=d->e2);
			d->e2 = args;
		}
		args = vb_args;
	}

	ee->e2 = args;
	return ee;
}

Pexpr call_dtor(Pexpr p, Pexpr dtor, Pexpr arg, int d, Pexpr vb_args)
{
// error('d',"call dtor %k %n %t vb_args %d",d,dtor,dtor->tp,vb_args);
	Pexpr r = new ref(d,p,dtor);

	if (arg && vb_args) 
		arg = new ival(3);
	else if (vb_args) 
		arg = new ival(2);
	else if (arg==0)
		arg = zero;
	if (arg->tp == 0) arg->tp = int_type;

	Pexpr aa = new expr(ELIST,arg,0); // argument controlling deallocation
					  // 2: destroy vbases
					  // 1: dealllocate, 0: don't

	Pfct f = Pfct(dtor->tp);		// attach virtual base arguments
//	for (Pname nn = f->f_args->n_list; nn && nn->n_list; nn=nn->n_list) {
//		Pexpr xx = vb_args ? new cast(nn->tp,one) : zero;
//		aa = new expr(ELIST,xx,aa);
//	}


	Pexpr ee = new call(r,aa);
	while (dtor->base == MDOT) dtor = dtor->mem;
	if (d == REF)	// could be virtual
		ee->fct_name = Pname(dtor);
	else {	// virtual suppressed, store fct name 
		r->n_initializer = dtor;
		ee->fct_name = 0;
	}
	ee->base = G_CALL;
	ee->tp = void_type;

        if (f->memof->c_body == 1) f->memof->dcl_print(0);
	if (Pname(dtor)->n_dcl_printed==0) Pname(dtor)->dcl_print(0);

	return ee;
}

//extern int new_used;	// pre-define new and delete only if the user didn't

Pstmt fct::dtor_simpl(Pclass cl, Pexpr th)
{
	Pstmt dtail = 0;
//error('d',"simpl_dtor(%t) a %d",cl,f_args);
//	if (new_used == 0) new_init();

	Pname fa = new name("__free");	// fake argument for dtor
	fa->tp = int_type;
	Pname free_arg = fa->dcl(body->memtbl,ARG);
	free_arg->where = no_where;
	delete fa;
	Pname a = f_args;
	if (a==0 || a->n_list==0) error('i',"__freeA missing in destructor for %t",cl);
	Pname p = 0;
	for(;;p=a,a=a->n_list) {	// replace nameless fake argument
//error('d',"a %d %t",a,a->tp);
		if (a->n_list == 0) {
		//	a->n_list = free_arg;
			DEL(p->n_list);
			p->n_list = free_arg;
			break;
		}
	} 

	// generate calls to destructors for all members of class cl:
	Ptable tbl = cl->memtbl;
	int i = 1;
	for (Pname m=tbl->get_mem(i); m; m=tbl->get_mem(++i) ) {

		if (m->n_stclass == STATIC || m->base == PUBLIC) continue;

		Ptype t = m->tp;
		Pexpr ee = 0;
		Pname cn;
		Pname dtor;

		if (cn = t->is_cl_obj()) {
			Pclass cl = (Pclass)cn->tp;
			if (dtor = cl->has_dtor()) {	// dtor(this,0,ones);
				ee = new ref(REF,th,m);
				ee->tp = m->tp;
				ee = call_dtor(ee,dtor,0,DOT,one);
				check_visibility(dtor,0,Pclass(dtor->n_table->t_name->tp),tbl,curr_fct);
			}
		}
		else if (cl_obj_vec) {
			Pclass cl = Pclass(cl_obj_vec->tp);
			if (dtor = cl->has_dtor()) {
	Pfct f = Pfct(dtor->tp);
	int i = 0;
	for (Pname nn = f->f_args->n_list; nn && nn->n_list; nn=nn->n_list) i++;
//error('d',"dtor %n i %d",dtor,i);
				ee = new ref(REF,th,m);
				ee->tp = m->tp;
				ee = cdvec(vec_del_fct,ee,cl,dtor,0,new ival(i));
				check_visibility(dtor,0,Pclass(dtor->n_table->t_name->tp),tbl,curr_fct);
			}
		}

		if (ee) {
			Pstmt es = new estmt(SM,curloc,ee,0);
			// reverse order of destructors for members
			es->s_list = del_list;
			del_list = es;
			if (dtail == 0) dtail = es;
		}
	}


	Pexpr ee = 0;
	// look for bases with destructors:
	// generate: dtor(base,0);

	Pbcl b = 0;	// get dtors in order with virtual bases last
	Pbcl t = 0;
	for (Pbcl l = cl->baselist; l; l=l->next) {
		if (l->base != VIRTUAL) {
			Pbcl x = new basecl(l->bclass,0);
			if (t == 0)
				b  = x;
			else
				t->next = x;
			t = x;
			x->base = l->base;
			x->obj_offset = l->obj_offset;
		}
	}
	for (l = cl->baselist; l; l=l->next) {
		if (l->base == VIRTUAL) {
			b = new basecl(l->bclass,b);
			b->base = l->base;
			b->obj_offset = l->obj_offset;
		}
	}
	Pexpr ve = 0;

	for (; b; b=l) {
		Pclass bcl = b->bclass;
		l = b->next;
		Pname dtor = bcl->has_dtor();

		if (dtor) { 
			Pexpr val = rptr(bcl->this_type,th,b->obj_offset);
			val = val->contents();
			Pexpr e = call_dtor(val,dtor);
			if (b->base == VIRTUAL) {
				// if (x) this->x.dtor(); where x is a vbase
				for (Pname dd = f_this->n_list; dd!=argtype; dd=dd->n_list) 
				if (strcmp(dd->string,bcl->string)==0) break;

 				if (ansi_opt) { // q?void:int would be an error
					e = new expr(G_CM,e,zero);
					e->tp = zero_type;
				}
				e = new expr(QUEST,e,zero);
				Pexpr two = new ival(2);
				two->tp = int_type;
				e->cond = new expr (AND,free_arg,two);//dd;
			}
			ee = ee ? new expr(CM,e,ee) : e;
		}
		delete b;
	}

	Pstmt es = ee ? new estmt(SM,curloc,ee,0) : 0;

	ee = new expr(ELIST,th,0);	// free storage
	Pname n = new name(oper_name(DELETE));
	Pexpr del = find_name(n,cl,scope,CALL,curr_fct);
	if (del->tp->base==OVERLOAD || Pfct(del->tp)->nargs==2) {
		Pexpr ss = new texpr(SIZEOF,cl,0);
		ss->tp = uint_type;
		ee->e2 = new expr(ELIST,ss,0);
	}
	ee = new call(del,ee);
	ee->tp = ee->call_fct(scope);

	Pstmt ess = new estmt(SM,curloc,ee,0);
	ess = new ifstmt(curloc,new expr(AND,free_arg,one),ess,0);
	if (es)
		es->s_list = ess;
	else
		es = ess;

	free_arg->use();
	Pname(th)->use();

	if (dtail)
		dtail->s_list = es;
	else
		del_list = es;

	del_list = new ifstmt(curloc,th,del_list,0);
	if (del_list) del_list->simpl();
	return dtail;
}


Pclass find_vbase_ptr(Pclass cl, Pclass vbase)
{
	for (Pbcl bb = cl->baselist; bb; bb = bb->next) {
		if (bb->base==VIRTUAL) {
			if (bb->bclass==vbase && bb->ptr_offset) return cl;
		}
		else {
			Pclass f = find_vbase_ptr(bb->bclass,vbase);
			if (f) return f;
		}
	}
	return 0;
}

Pclass second_base(Pclass cl, Pclass base)
{
//error('d',"second_base(%t,%t)",cl,base);
	for (Pbcl b = cl->baselist; b && b->base==NAME; b = b->next) {
		if (b->bclass==base) {
			if (b==cl->baselist) return 0;
			return base;
		}
		Pclass bb = second_base(b->bclass,base);
		if (bb == Pclass(-1)) continue;	// not found
		if (bb) {
			if (b!=cl->baselist) error('s',"C hierarchy too complicated");
			return bb;	// second base of b->bclass
		}
		if (b==cl->baselist) return 0;
		return b->bclass;	// b->bclass is second base
	}
	return Pclass(-1);
}

//Pclass topclass;

Pexpr classdef::get_vptr_exp(char *s)
{
//error('d',"%t::get_vptr_exp(%s)",this,s?s:"0");
	if (c_body == 1) dcl_print(0);
	if (c_body == 3) print_all_vtbls(this);
	if (s == 0) return find_vptr(this);
	Pbcl b = get_base(get_classname(s));
	Pexpr vp = b->bclass->get_vptr_exp(drop_classname(s));
	if (b==baselist && b->base!=VIRTUAL) return vp;
	vp = new mdot(b->bclass->string,vp);
	if (c_body == 1) b->bclass->dcl_print(0);
	if (c_body == 3) b->bclass->print_all_vtbls(b->bclass);
	if (b->base == VIRTUAL) {
		vp->i1 = 1;
		if (b->ptr_offset == 0) { // pointer to base in intermediate base
			Pclass bb = find_vbase_ptr(this,b->bclass);
			Pclass sb = second_base(topclass,bb);
//error('d',"mdot %t %t : %d %t ",topclass,bb,sb,sb==Pclass(-1)?0:sb);
			if (sb && sb!=Pclass(-1)) vp = new mdot(sb->string,vp);
		}
	}
	return vp;
}

int fct::ctor_simpl(Pclass cl, Pexpr th)
{
	Ptable tbl = cl->memtbl;

	int ass_count = 0;
	init_list = 0;
//error('d',"ctor_simpl %t: %t",cl,this);
	/*
		initialization order:
		(1)	virtual base pointers and virtual bases
				(they may be used in non-virtual bases)
		(2)	non-virtual bases
		(3)	virtual function pointers
		(4)	members
	*/

	// initialize virtual base pointers and virtual base objects
	for (Pbcl l = cl->baselist; l; l=l->next) {
		Pexpr i = l->init;
		if (l->base != VIRTUAL) continue;
		l->init = 0;
//error('d',"simpl virtual base %t i %d ",l->bclass,i);

		// assign virtual OP to virtual base AP
		Pclass bc = l->bclass;
		Pexpr dp = 0;

		// dd = pointer argument for this base;
		// non-zero if already initialized
		for (Pname dd = f_this->n_list; dd!=argtype; dd=dd->n_list) 
			if (strcmp(dd->string,bc->string)==0) break;

		// initialize virtual base object
//error('d',"bc %t dd %n offset %d init %d",bc,dd,l->obj_offset,l->init);
		// => bc_arg = (bc*)((char*)this+offset)
		int off = l->obj_offset;
		Pexpr val = rptr(bc->this_type,th,off);
		dp = new expr(ASSIGN,dd,val);
		dd->assign();

		// => bc::bc()
		if (i)  {
			switch (i->base) {
			case ASSIGN:
			case CM:
				break;
			case CALL:
			case G_CALL:
			{	Pcall cc = Pcall(i);
				Pname bn = cc->fct_name;
				ass_count = Pfct(bn->tp)->f_this->n_assigned_to;
				cc->simpl();
				break;
			}
			default:
				error('i',"badBCIr %k",i->base);
			}
			dp = new expr(CM,dp,i);
		}

		// => (bc_arg==0)?dp:bc_arg
		for (Pname a = f_args->n_list; a; a = a->n_list)
			if (strcmp(bc->string,a->string)==0) {
				dp = new expr(QUEST,dp,a);
				dp->cond = new expr(EQ,a,zero);
				break;
			}

		//	Pname dpp = find_vbase_ptr(bc,cl);
		for (Pbcl ll=cl->baselist; ll; ll=ll->next) {
			if (ll->bclass==bc && ll->ptr_offset) {
				// make sure that the delegate_arg is needed
				// here and not just in a base

				// this->Pd = (bc_arg==0)?dp:bc_arg
				Pexpr dpp = new mdot(bc->string,th);
				dpp->i1 = 3;
				dp = new expr(ASSIGN,dpp,dp);
//error('d',"dpp %n",dpp);
				break;
			}
		}

		// reverse init order
		if (dp) init_list = init_list ? new expr(CM,dp,init_list) : dp;
	}

	//	generate: this=base::base(args) (non-virtual bases)
{	
	for (Pbcl l = cl->baselist; l; l=l->next) {
		Pexpr i = l->init;
		if (i==0 || l->base==VIRTUAL) continue;
//error('d',"simpl base %t i %d ",l->bclass,i);
		l->init = 0;
	
		switch (i->base) {
		case ASSIGN:
		case CM:
			break;
		case CALL:
		case G_CALL:
		{	Pcall cc = Pcall(i);
			Pname bn = cc->fct_name;
			ass_count = Pfct(bn->tp)->f_this->n_assigned_to;
			cc->simpl();
			// assign to ``this'' only from only base
			if (l==cl->baselist && cl->baselist->next==0) i = new expr(ASSIGN,th,cc);
			break;
		}
		default:
			error('i',"badBCIr %k",i->base);
		}

		init_list = init_list ? new expr(G_CM,init_list,i) : i;
	}
}

	// initialize the vptrs that are updated by this class
	for (Pvirt blist = cl->virt_list; blist; blist = blist->next) {
	//	if (blist->string==0 && find_vptr(cl)==0) {	//opt
//error('d',"!!!vptr init %s in %s",blist->string,cl->string);
	//		continue;
	//	}
//error('d',"vptr init %s in %s",blist->string,cl->string);
		topclass = cl;
		Pexpr vp = cl->get_vptr_exp(blist->string);

                char *str = 0;
		char *cs = cl->nested_sig?cl->nested_sig:cl->string;
                if (cl->lex_level && cl->nested_sig==0) str = make_local_name( cl );
                Pexpr vtbl = new text_expr(blist->string,str?str:cs);
                //Pexpr vtbl = new text_expr(blist->string,cl->string);      
                //      vtbl = new cast(Pvptr_type,vtbl);

		Pexpr ee = new ref(REF,th,vp);
		ee->tp = vp->tp;
		ee = new expr(ASSIGN,ee,vtbl);
		init_list = init_list ? new expr(CM,init_list,ee) : ee;
	}

	// initialize members in declaration order:
	int i;
	for (Pname m=tbl->get_mem(i=1); m; m=tbl->get_mem(++i) ) {
		Ptype t = m->tp;
		Pname cn;
		Pname ctor;
		if (t == 0) continue;

		switch (t->base) {
		case FCT:
		case OVERLOAD:
		case CLASS:
		case ENUM:
			continue;
		}

		switch (m->n_stclass) {
		case STATIC:
		case ENUM:
			continue;
		}

		if (m->base == PUBLIC) continue;

		Pexpr ee = m->n_initializer;
		if (ee) m->n_initializer = 0;	// from fct must not persist until next fct
//error('d',"simpl m %n ee %d",m,ee);
		if (ee) {
			// init of non-class mem
			// set in fct::mem_init()
		}
		else if (cn=t->is_cl_obj()) {	// try for default
			Pclass cl = Pclass(cn->tp);
			if (ctor = cl->has_ictor()) {
				Pexpr r = new ref(REF,th,m);
				ee = call_ctor(tbl,r,ctor,0,DOT);
	check_visibility(ctor,0,Pclass(ctor->n_table->t_name->tp),tbl,curr_fct);
			}
			else if (cl->has_ctor()) {
				error("M%n needsIr (no defaultK forC %s)",m,cl->string);
			}
		}
		else if (cl_obj_vec) {
			Pclass cl = Pclass(cl_obj_vec->tp);
			if (ctor = cl->has_ictor()) { // _new_vec(vec,noe,sz,ctor);
				Pexpr mm = new ref(REF,th,m);
				mm->tp = m->tp;
				ee = cdvec(vec_new_fct,mm,cl,ctor,-1,0);
	check_visibility(ctor,0,Pclass(ctor->n_table->t_name->tp),tbl,curr_fct);
			}
			else if (cl->has_ctor()) {
				error("M%n[] needsIr (no defaultK forC %s)",m,cl->string);
			}
		}
		else if (t->is_ref()) {
			error("RM%n needsIr",m);
		}
		else if (t->tconst() && vec_const==0) {
			error("constM%n needsIr",m);
		}
	
		if (ee) {
			ee->simpl();
			init_list = init_list ? new expr(CM,init_list,ee) : ee;
		}
	} // for m
//error('d',"ctor->");
	return ass_count;
}

void fct::simpl()
/*
	call only for the function definition (body != 0)

	simplify argument initializers, and base class initializer, if any
	then simplify the body, if any

	for constructor:call allocator if this==0 and this not assigned to
			(auto and static objects call constructor with this!=0,
			the new operator generates calls with this==0)
			call base & member constructors
	for destructor:	call deallocator (no effect if this==0)
			case base & member destructors

	for arguments and function return values look for class objects
	that must be passed by constructor X(X&).

	Allocate temporaries for class object expressions, and see if
	class object return values can be passed as pointers.

	call constructor and destructor for local class variables.
*/
{
	Pexpr th = f_this;
	Ptable tbl = body->memtbl;
	Pstmt ss = 0;
	Pstmt tail;
	Pclass cl = th ? Pclass(Pbase(Pptr(th->tp)->typ)->b_name->tp) : 0;
	Pstmt dtail = 0;

	Pname ocurr_fct = curr_fct;
	int oret = no_of_returns;
	int oim = imeasure;

//error('d',"fct::simpl %n %t",curr_fct,this);
//	not_inl = f_inline==0;
	del_list = 0;
	continue_del_list = 0;
	break_del_list = 0;
	scope = tbl;
	if (scope == 0) error('i',"F::simpl()");
	int ass_count = 0;
	imeasure = 0;
	no_of_returns = 0;

	cc->stack();
	cc->nof = curr_fct;
	cc->ftbl = tbl;

//      modification for local classes defined within inline functions
// error( 'd', "simpl local_class: %d", local_class );
	for ( Plist l = local_class; l; l = l->l ) {
    		Pname n = l->f; 
    		Pclass cl = Pclass(Pbase(n->tp)->b_name->tp);
    		if ( cl->in_fct == 0 ) cl->in_fct = cc->nof;
    		if ( cl->lcl == 0 ) cl->lcl = make_name( 'L' );
    		if ( cl->c_body == 1 ) cl->dcl_print(0);
	}

	Pfct(cc->nof->tp)->local_class = local_class; 
	local_class = 0;
// error( 'd', "simpl nof: %n %d local_class: %d", cc->nof, cc->nof, Pfct(cc->nof->tp)->local_class );

	switch (curr_fct->n_scope) {
	case 0:
	case PUBLIC:
		cc->not = curr_fct->n_table->t_name;
		cc->cot = Pclass(cc->not->tp);
		cc->tot = cc->cot->this_type;
	}

	switch (curr_fct->n_oper) {
	case  DTOR:
		dtail = dtor_simpl(cl,th);
		break;
	case CTOR:
		ass_count = ctor_simpl(cl,th);
	}

	tail = body->simpl();

	if (returns->base!=VOID || f_result) {	// return must have been seen
		if (no_of_returns) {		// could be OK
			Pstmt tt = (tail->base==RETURN || tail->base==LABEL) ? tail : trim_tail(tail);

			switch (tt->base) {
			case RETURN:
			case GOTO:
				del_list = 0;	// no need for del_list
				break;
			case SM:
				if (tt->e)
					switch (tt->e->base) {
					case ICALL:
					case G_CALL:
						goto chicken;
					}
			default:
				if (warning_opt || strcmp(curr_fct->string,"main"))	
					error('w',"maybe no value returned from%n",curr_fct);
			case IF:
			case SWITCH:
			case DO:
			case WHILE:
			case FOR:
			case LABEL:
			chicken:		// don't dare write a warning
				break;
			}
		}
		else {	// must be an error
			// but we don't dare complain about main()
		//	if (strcmp(curr_fct->string,"main"))
		//		error(Pfct(curr_fct->tp)->returns->is_cl_obj()?0:'w',"no value returned from%n",curr_fct);
		//	else if (warning_opt)	
		//		error('w',"no value returned from%n",curr_fct);
			if (Pfct(curr_fct->tp)->f_inline
			&& Pfct(curr_fct->tp)->returns!=void_type
			&& Pfct(curr_fct->tp)->returns->is_cl_obj())
				// can cause code generation errors if allowed
				error("no value returned from%n",curr_fct);
			else if (warning_opt || strcmp(curr_fct->string,"main"))	
				error('w',"no value returned from%n",curr_fct);
		}
		if (del_list) goto zaq;
	}
	else if (del_list) {	// return may not have been seen
	zaq:
		if (tail)
			tail->s_list = del_list;
		else
			body->s = del_list;
		tail = dtail;
	}

	if (curr_fct->n_oper == DTOR) {	// body => if (this == 0) body

// reset the vptrs that were set by this class
	for (Pvirt blist = cl->virt_list; blist; blist = blist->next) {
//error('d',"vptr init %s in %s",blist->string,cl->string);
		topclass = cl;
		Pexpr vp = cl->get_vptr_exp(blist->string);

                char *str = 0;
		char *cs = cl->nested_sig?cl->nested_sig:cl->string;
                if (cl->lex_level && cl->nested_sig==0) str = make_local_name(cl);
                Pexpr vtbl = new text_expr(blist->string,str?str:cs);

		Pexpr ee = new ref(REF,th,vp);
		ee->tp = vp->tp;
		ee = new expr(ASSIGN,ee,vtbl);
		Pstmt es = new estmt(SM,curloc,ee,0);
		es->s_list = body->s;
		body->s = es;
	}

		body->s = new ifstmt(body->where,th,body->s,0);
	}

	if (curr_fct->n_oper == CTOR) {

		loc temploc=body->where;
		Pstmt tempss=body->s;
		while (tempss) {
			temploc=tempss->where;
			tempss=tempss->s_list;
		}
		
		if  (Pname(th)->n_assigned_to == 0) {
		/* generate:
			if (this || (this=_new( sizeof(class cl) ))) {
				init_list ;
				body;
			}
		*/
			Pname(th)->n_assigned_to = ass_count ? ass_count : FUDGE111;
			Pexpr sz = new texpr(SIZEOF,cl,0);
			(void) cl->tsizeof();
			sz->tp = uint_type;
			Pexpr ee = new expr(ELIST,sz,0);
				Pname n = new name(oper_name(NEW));
				Pexpr p = find_name(n,cl,scope,CALL,curr_fct);
//error('d',"in ctor %n call %n",curr_fct,p);
				ee = new call(p,ee);
				(void) ee->call_fct(cl->memtbl);
			ee->simpl();
			ee = new expr(ASSIGN,th,ee);
			ee = new expr(OROR,th,ee);
			/*ifs->simpl();
				do not simplify
				or "this = " will cause an extra call of base::base
			*/
			if (init_list) {
				Pstmt es = new estmt(SM,body->where,init_list,0);
				es->s_list = body->s;
				body->s = es;
			//	if (tail == 0) tail = es;
			}
			else if (body->s == 0)
				body->s = new estmt(SM,body->where,0,0);
			else if(tail->base==RETURN) {
				if(body->s == tail) {
					delete body->s;
					body->s = new estmt(SM,body->where,0,0);
				}
				else {
					Pstmt pr = body->s;
					while(pr->s_list != tail)
						pr = pr->s_list;
					delete pr->s_list;
					pr->s_list = 0;
				}
			}

			ifstmt* ifs = new ifstmt(body->where,ee,body->s,0);
			body->s = ifs;
		//	if (tail == 0) 
			tail = ifs;
		}
		// generate: body; return this;
		Pstmt st = new estmt(RETURN,temploc,th,0);
		if (tail)
			tail->s_list = st;
		else
			body->s = st;
		tail = st;
	}
	f_imeasure = imeasure;
	curr_fct = ocurr_fct;
	no_of_returns = oret;
	imeasure = oim;
	cc->unstack();
}


void classdef::simpl()
{
	int i;
//error('d',"classdef::simpl %s %d",string,defined&SIMPLIFIED);

	if (defined&SIMPLIFIED) return;

	Pclass oc = in_class;
	in_class = this;

	for (Pname m=memtbl->get_mem(i=1); m; m=memtbl->get_mem(++i) ) {
		Pexpr i = m->n_initializer;
		m->n_initializer = 0;
		m->simpl();
		m->n_initializer = i;
	}

	in_class = oc;

	for (Plist fl=friend_list; fl; fl=fl->l) {	// simplify friends
		Pname p = fl->f;
		switch (p->tp->base) {
		case FCT:
		case OVERLOAD:
			p->simpl();
		}
	}

	defined |= SIMPLIFIED;
}
0707071010112045111004440001630000160000010207100466055410100001100000140465simpl2.c/*ident	"@(#)ctrans:src/simpl2.c	1.5" */
/******************************************************************

	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.

simpl2.c:

	simplify the typechecked function
	remove:		classes:
				class fct-calls
				operators
				value constructors and destructors
			new and delete operators (replace with function calls)
			initializers		(turn them into statements)
			constant expressions		(evaluate them)
			inline functions		(expand the calls)
			enums				(make const ints)
			unreachable code		(delete it)
	make implicit coersions explicit

	in general you cannot simplify something twice

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

#include "cfront.h"
#include "size.h"
#include <ctype.h>

extern Pname Ntmp;
Pname find_vptr(Pclass);

extern int no_of_returns;

extern Pname new_fct;
//extern Pname del_fct;

extern Pstmt del_list;
extern Pstmt break_del_list;
extern Pstmt continue_del_list;

extern Pname curr_fct;	// current function
extern Pexpr init_list;
extern int imeasure;

Pexpr cdvec(Pname f, Pexpr vec, Pclass cl, Pname cd, int tail, Pexpr i, Pexpr vec2)
/*
	generate a call to construct or destroy the elements of a vector
*/
{
	Pexpr sz = new texpr(SIZEOF,cl,0);	// sizeof elem
	sz->tp = uint_type;
	(void) cl->tsizeof();
					
	Pexpr esz = new texpr(SIZEOF,cl,0);	// noe = sizeof(vec)/sizeof(elem)
	esz->tp = int_type;

Pexpr noe;
if (vec2) noe = new texpr(SIZEOF,vec2->tp,0);
else noe = new texpr(SIZEOF,vec->tp,0);

	// Pexpr noe = new texpr(SIZEOF,vec->tp,0);
	noe->tp = int_type;
	noe = new expr(DIV,noe,esz);
	noe->tp = uint_type;
// error('d',"cdvec tail %d i %d",tail,i);
//	Pexpr arg = (0<=tail) ? new expr(ELIST,zero,0) : 0;	// 0 or 1 for dtors
	Pexpr arg = (i) ? new expr(ELIST,i,0) : 0;
	arg = (0<=tail) ? new expr(ELIST,zero,arg) : arg;	// 0 or 1 for dtors
	arg = new expr(ELIST,cd,arg);		// constructor or destructor
	cd->lval(ADDROF);			// cd->take_addr();

	arg = new expr(ELIST,sz,arg);
	arg = new expr(ELIST,noe,arg);
	arg = new expr(ELIST,vec,arg);

	arg = new call(f,arg);
	arg->base = G_CALL;
	arg->fct_name = f;

	return arg;
}

/*
int new_used;	// pre-define new and delete only if the user didn't

void new_init()
{
	char* ns = oper_name(NEW);
	char* ds = oper_name(DELETE);

	new_used = 1;

	new_fct = gtbl->look(ns,0);
	del_fct = gtbl->look(ds,0);

	if (new_fct && !del_fct)
		error('w',"%n defined but not operator delete()",new_fct);
	if (del_fct && !new_fct)
		error('w',"%n defined but not operator new()",del_fct);

        if (Pfct(new_fct->tp)->body==0) new_fct->dcl_print(0);
        if (Pfct(del_fct->tp)->body==0) del_fct->dcl_print(0);
}
*/
Pstmt trim_tail(Pstmt tt)
/*
	strip off statements after RETURN etc.
	NOT general: used for stripping off spurious destructor calls
*/
{
	if (tt == 0) return 0;

	while (tt->s_list) {
		Pstmt tpx;
		switch (tt->base) {
		case PAIR:
			tpx = trim_tail(tt->s2);
			goto tpxl;
		case BLOCK:
			tpx = trim_tail(tt->s);
		tpxl:
			if (tpx == 0) return 0;

			switch (tpx->base) {
			case SM:
				break;
			case CONTINUE:
			case BREAK:
			case GOTO:
			case RETURN:
				if (tt->s_list->base != LABEL) tt->s_list = 0;
			default:
				return tpx;
			}
		default:
			if (tt = tt->s_list) break;
			return 0;
		case RETURN:
			if (tt->s_list->base != LABEL) tt->s_list = 0;
			return tt;
		}
	}

	switch (tt->base) {
	case PAIR:	return trim_tail(tt->s2);
//	case LABEL:	return trim_tail(tt->s);
	case BLOCK:	if (tt->s) return trim_tail(tt->s);
	default:	return tt;
	}
}

extern Ptype Pfct_type;

Pexpr mptr_assign(Pexpr n, Pexpr in)
{
	Pexpr i1;
	Pexpr i2;
	Pexpr i3;

	if ( n->base == NAME ) 
		Pname(n)->use();

	if (in->base == NAME) {
		i1 = new mdot("d",in);
		i1->i1 = 9;
		i2 = new mdot("i",in);
		i2->i1 = 9;
		i3 = new mdot("f",in);
		i3->i1 = 9;
	}
	else {
		i1 = in->e1->e1;
		i2 = in->e1->e2;
		i3 = in->e2;
	}
	Pexpr nd = new mdot("d",n);
	nd->i1 = 9;
	Pexpr e1 = new expr(ASSIGN,nd,i1);

	Pexpr ni = new mdot("i",n);
	ni->i1 = 9;
	Pexpr e2 = new expr(ASSIGN,ni,i2);

	Pexpr nf = new mdot("f",n);
	nf->i1 = 9;
//	Pexpr ii = in->e2; //new cast(Pfct_type,in->e2);
	Pexpr e3 = new expr(ASSIGN,nf,i3);

	Pexpr ee = new expr(CM,e2,e3);
	return new expr(CM,e1,ee);
}

Pstmt block::simpl()
{
	int i;
	Pname n;
	Pstmt ss=0, sst=0;
	Pstmt dd=0, ddt=0;
	Pstmt stail;
	Ptable old_scope = scope;
	DB( if(Sdebug>=1)
		error('d',"%d->block::simple() own_tbl %d  memtbl %d  curr_fct%n",this,own_tbl,memtbl,curr_fct);
	);
	if (own_tbl == 0) {
		ss = (s) ? s->simpl() : 0;
		return ss;
	}

	scope = memtbl;
	if (scope->init_stat == 0) scope->init_stat = 1; /* table is simplified. */

	for (n=scope->get_mem(i=1); n; n=scope->get_mem(++i)) {
		Pstmt st = 0;
		Pname cln;
		Pexpr in = n->n_initializer;
// error('d',"local %k %n in %k %t",n->n_sto,n,in?in->base:0,in?in->tp:0);
		if (in || n->n_evaluated) {
			scope->init_stat = 2; /* initializer in this scope */
			if (n->n_sto == EXTERN) {
				error(&n->where,"Id local extern%n",n);
				continue;
			}
		}

		switch (n->n_scope) {
		case ARG:
		case 0:
		case PUBLIC:
			 continue;
		}

		if (n->n_stclass == STATIC) { // local static class object
			/* initialization of local static objects; 
			 * set up first pass switch
			 *     temp_switch ? 0 
			 *       : (stat_obj=init_expr, temp_switch=1);
			 *
			 * ARGS: temporary class object in init_expr with dtor
			 *       must call dtor once in std function
			 */

			if ((in==0 && n->n_scope==ARGS) ||
				(in && in->base==STAT_INIT)) 
			{
				Pname cn;
				Pname x;
				Ptype ct;
				int vec_seen = 0;

				cn = n->tp->is_cl_obj();
				if ( cn == 0 ) { ++vec_seen; cn = cl_obj_vec; }

				if ( cn ) {
    					ct = new ptr(PTR,vec_seen?Pvec(n->tp)->typ:n->tp);
					x = make_tmp('F', ct, gtbl );
					x->n_initializer = zero;
				}
				else
					x = make_tmp('F',int_type,scope);

				x->n_sto = n->n_stclass = STATIC;
				
				if (in) {
					if (in->e2)
						in->base = ASSIGN;
					else in = in->e1;
				}

				Pexpr set;
				if ( cn ) {
					x->dcl_print(0);
					Pclass cl = Pclass(cn->tp);
					Pname dtor = cl->has_dtor();

					Pexpr cc;
					if ( dtor ) {
						if ( vec_seen == 0 ) {
							Pexpr eee = new expr(DEREF, x, 0 );
    							Pexpr c = call_dtor(eee,dtor,0,DOT,one);
    							c->tp = any_type;
    							cc = new expr( QUEST, c, zero );
    							cc->cond = x;
						}
						else cc = cdvec(vec_del_fct,x,cl,dtor,0,zero,n);
						cc->tp = any_type; // arghh!

    						Pstmt dls = new estmt( SM, n->where, cc, 0 );
    						if ( st_dlist ) dls->s_list = st_dlist;
    						st_dlist = dls;
					}

					Pexpr xe;
					if (cn) {
						if ( vec_seen == 0 )
							xe = new expr( G_ADDROF, 0, n );
						else {
							Pexpr ee = new expr( DEREF, n, zero );
							xe = new expr( G_ADDROF, 0, ee );
						}
					}

					set = new expr(ASSIGN,x,xe);
					set->tp = ct;
				}
				else {
					set = new expr(ASSIGN,x,one);
					set->tp = int_type;
				}

				// set pointer to static object and continue
				// sorry for goto, but beats rewriting code
				if ( n->n_scope == ARGS && in == 0 ) {
					set = new expr( QUEST, zero, set );
					set->cond = x;
					st = new estmt(SM,n->where,set,0);
					goto init_stat3;
				}

				in = new expr(G_CM,in,set);
				in = new expr(STAT_INIT,zero,in);
				in->cond = x;
			}
			else
				continue;
		}

    		if ( in ) {
	 		if ((in->base == ILIST && in->e2 == 0) ||
             		    (in->base == STRING && n->tp->base == VEC))
                  		if (ansi_opt==0) {
                      		    	error('s',&n->where,"initialization of%n (automatic aggregate)",n);
                      		    	continue;
                   		}
    		}    

		if (n->tp == 0) continue; /* label */
		if (n->n_evaluated) continue;

		/* construction and destruction of temporaries is handled locally */
		{	char* s = n->string;
			register char c3 = s[4];
			if (s[0]=='_' && s[1]=='_' && s[2]=='D' && isdigit(c3)) continue;
		}

		if ( cln=n->tp->is_cl_obj() ) {
			Pclass cl = Pclass(cln->tp);
			Pname d = cl->has_dtor();

			if ( n->n_stclass == STATIC   // local static class object
				&& in && in->base==STAT_INIT )  
					goto stat_init;

			if (d) {			// n->cl.dtor(0);
				Pexpr dl = call_dtor(n,d,0,DOT,one);
			//	Pstmt dls = new estmt(SM,n->where,dl,0);
				Pstmt dls = new estmt(SM,no_where,dl,0);
				if (dd) {
					dls->s_list = dd;
					dd = dls;
				}
				else
					ddt = dd = dls;
			}

//  error('d',"%n: in %d",n,in?in->base:0);
			if (in) {
				switch (in->base) {
				case DEREF:		// *constructor?
					if (in->e1->base == G_CALL) {
						Pname fn = in->e1->fct_name;
						if (fn==0 || fn->n_oper!=CTOR) goto ddd;
						st = new estmt(SM,n->where,in->e1,0);
						n->n_initializer = 0;
						break;
					}
					goto ddd;
				case STAT_INIT:
stat_init:
// error('d', "block::simpl: case #1 stat_init : n: %n", n );
					in->base = QUEST;
					st = new estmt(SM,n->where,in,0);
					n->n_initializer = 0;
					break;
				case G_CM:
					st = new estmt(SM,n->where,in->e1,0);
					n->n_initializer = 0;
					break;
				case ASSIGN:		// assignment to "n"?
					if (in->e1 == n) {
						st = new estmt(SM,n->where,in,0);
						n->n_initializer = 0;
						break;
					}
				default:
					goto ddd;
				}
			}
		}
		else if (cl_obj_vec) {
			Pclass cl = Pclass(cl_obj_vec->tp);
			Pname d = cl->has_dtor();
			Pname c = cl->has_ictor();
			n->n_initializer = 0;

			if ( n->n_stclass == STATIC   // local static class object
				&& in && in->base==STAT_INIT )  
					goto stat_init2;

			if (c) {	//  _vec_new(vec,noe,sz,ctor);
				if (in==0 || in->base==ILIST) {
					Pexpr a = cdvec(vec_new_fct,n,cl,c,-1,0);
					st = new estmt(SM,n->where,a,0);
				}
				else 
					st = new estmt(SM,n->where,in,0);
			}
			// no default ctor but provided all elements with argument
			else if ( in ) st = new estmt(SM,n->where,in,0);

			
			if (d) {	//  __vec_delete(vec,noe,sz,dtor,0);
				Pfct f = Pfct(d->tp);
				int i = 0;
				for (Pname nn = f->f_args->n_list; 
					nn && nn->n_list; nn=nn->n_list) i++;
				Pexpr a = cdvec(vec_del_fct,n,cl,d,0,new ival(i));
			//	Pstmt dls = new estmt(SM,n->where,a,0);
				Pstmt dls = new estmt(SM,no_where,a,0);
				if (dd) {
					dls->s_list = dd;
					dd = dls;
				}
				else
					ddt = dd = dls;
			}
		}
		else if (in) {
			switch (in->base) {
			case ILIST:
				switch (n->n_scope) {
				case FCT:
					if (in->e2) { // pointer to member
						Pexpr ee = mptr_assign(n,in);
						st = new estmt(SM,n->where,ee,0);
						n->n_initializer = 0;
						break;
					}
				case ARG:
					if (ansi_opt == 0) error('s',"Ir list for localV%n",n);	
				}
				break;
			case STAT_INIT:
stat_init2:
// error('d', "block::simpl: case #2 stat_init : n: %n", n );
				in->base = QUEST;
				st = new estmt(SM,n->where,in,0);
				n->n_initializer = 0;
				break;
			case STRING:
				if (n->tp->base==VEC) break; /* BUG char vec only */
			default:
			ddd:
			{	Pexpr ee = new expr(ASSIGN,n,in);
				st = new estmt(SM,n->where,ee,0);
				n->n_initializer = 0;
			}
			}
		}

init_stat3:	if (st) {
			if (ss)
				sst->s_list = st;
			else
				ss = st;
			sst = st;
		}
	}

	if (dd) {
		Pstmt od = del_list;
		Pstmt obd = break_del_list;
		Pstmt ocd = continue_del_list;

		dd->simpl();
		del_list = (od) ? Pstmt(new pair(curloc,dd,od)) : dd;
		break_del_list = (break_del_list&&obd) ? Pstmt(new pair(curloc,dd,obd)) : dd;
		continue_del_list = (continue_del_list&&ocd) ? Pstmt(new pair(curloc,dd,ocd)) : dd;

		stail  = s ? s->simpl() : 0;

		Pfct f = Pfct(curr_fct->tp);
		if (this!=f->body
		|| f->returns->base==VOID
		|| (f->returns->base!=VOID && no_of_returns==0 ) // you have been warned!
		|| strcmp(curr_fct->string,"main")==0 ) {
		// not dropping through the bottom of a value returning function
			if (stail) {
				Pstmt tt = (stail->base==RETURN || stail->base==LABEL) ? stail : trim_tail(stail);
				if (tt && tt->base != RETURN) stail->s_list = dd;
			}
			else
				s = dd;
			stail = ddt;
		}

		del_list = od;
		continue_del_list = ocd;
		break_del_list = obd;
	}
	else
		stail  = s ? s->simpl() : 0;

	if (ss) {	/* place constructor calls */
		ss->simpl();
		sst->s_list = s;
		s = ss;
		if (stail == 0) stail = sst;
	}
	
	scope = old_scope;

	return stail;
}

int no_sizeof;

void expr::simpl()
{
	DB(if(Sdebug>=2){
		error('d',"%d->expr::simpl() %k",this,this?base:0);
		if(Sdebug>=3) display_expr(this);
	});
	if (this==0 || permanent==2) return;	// already expanded
	static TOK obase = 0;

	switch (base) {
	case MDOT:
		obase = base;
		mem->simpl();
		obase = 0;
		// no break

	case ICALL:	// already expanded
		return;

	case G_ADDROF:
	case ADDROF:
// error('d',"simpl & %k",e2->base);

		e2->simpl();
		switch (e2->base) {
		case DOT:
		case REF:
		{	Pref r = Pref(e2);
			Pname m = Pname(r->mem);
			while (m->base == MDOT) m = Pname(m->mem);
			if (m->n_stclass == STATIC) {	// & static member
				Pexpr x;
			delp:
				x = e2;
				e2 = m;
				r->mem = 0;
				DEL(x);
			}
			else if (m->tp->base == FCT) {	// & member fct
				Pfct f = Pfct(m->tp);
				if (f->f_virtual) {	// &p->f ==> p->vtbl[fi].f
					int index = f->f_virtual;
					Pexpr ie = index ? new ival(index):0;
					if (ie) ie->tp = int_type;
					Pname cn = m->n_table->t_name;
					Pname vp = find_vptr(Pclass(cn->tp));
					r->mem = vp;

					if ( obase == MDOT ) {
						base = DEREF;
						e1 = e2;
						e2 = ie;
					}
					else { // support old style &b.vf
						base = MDOT;
						mem = new expr(DEREF,e2,ie);
						string2 = "f";
						i1 = 9;
					}
				}
				else {
					goto delp;
				}
			}
			break;
		}
		}
		break;
	
	case ANDAND:
	case OROR:
		Ntmp = 0;
		// no break

	default:
		if (e1) e1->simpl();
		if (e2) e2->simpl();
		break;

	case CM:
	case G_CM:
	{	
		Pname n = 0;
		e1->simpl();
		e2->simpl();
		if (e1->base==ICALL && e1->e1==0) n = e1->il->fct_name;
 		if (e2->base==ICALL && e2->e1==0) n = e2->il->fct_name;
		if (n) error('s',"cannot expand inline void%n called in commaE",n);
		// no break
	}
	case NAME:
	case DUMMY:
	case ICON:
	case FCON:
	case CCON:
	case IVAL:
	// case FVAL:
	// case LVAL:
	case STRING:
	case ZERO:
	case ILIST:
//	case MDOT:
		return;
/*
	case SIZEOF:
		base = IVAL;
		i1 = tp2->tsizeof();
		tp2 = 0;	// can't DEL(tp2)
		break;
*/
	case SIZEOF:
		if (e1) e1->simpl();
		return;

	case G_CALL:
	case CALL:
		Pcall(this)->simpl();
		break;

	case NEW:
	case GNEW:
		simpl_new();
		return;

	case DELETE:
	case GDELETE:
		simpl_delete();
		break;

	case QUEST:
		cond->simpl();
		Ntmp = 0;
		e2->simpl();
		// no break

	case CAST:
	case REF:
		e1->simpl();
		break;

	case DOT:
		e1->simpl();
		switch (e1->base) {
		case CM:
		case G_CM:
		 {	// &( , name). => ( ... , &name)->
			Pexpr ex = e1;
			cfr:
			switch (ex->e2->base) {
			case NAME:
				base = REF;
				ex->e2 = ex->e2->address();
				break;
			case CM:
			case G_CM:
				ex = ex->e2;
				goto cfr;
			}
		}
		}
		break;

	case ASSIGN:
	{	
		Pfct f = 0; 
		Pexpr th = 0;
		if ( curr_fct ) {
			f = Pfct(curr_fct->tp);
			th = f->f_this;
		}

		imeasure++;
		if (e1) e1->simpl();
		if (e2) {
			Pexpr c = e2;
			c->simpl();
			while (c->base == CAST) c = c->e1;
			if (c->base == ILIST) e2 = c;

			if (e2->base == ILIST) {	// pointer to member assignment
				Pexpr ee = mptr_assign(e1,e2);
				Pexpr eee = new expr(CM,ee->e2,e1);
				e1 = ee->e1;
				e2 = eee;
				base = CM;
				delete ee;
			}
		}

		if (th && th==e1 && curr_fct->n_oper==CTOR && init_list) {
			// this=e2 => (this=e2,init_list)
			Pclass cl = Pclass(Pbase(Pptr(th->tp)->typ)->b_name->tp);
			if (cl->c_body == 1) cl->dcl_print(0);
			imeasure++;
			base = CM;
			e1 = new expr(ASSIGN,e1,e2);
			e2 = init_list;
			if (warning_opt)	// timid
				error('w',"assignment to ``this'' inK: try defining%t::operator new() instead",f->memof);
		}
		break;
	}
	}

	switch (base) {
	case QUEST:
	case ANDAND:
	case OROR:
		if (Ntmp) error('s',"temporary ofC%n with destructor needed in%kE",Ntmp,base);
		// no break;
	default:
		Ntmp = 0;
	}
	
	if (tp==int_type || tp==defa_type) {
		Neval = 0;
		no_sizeof = 1;	// do not convert sizeof's to ints
		long i = eval();
		no_sizeof = 0;
		if (Neval == 0) {
			base = IVAL;
			i1 = i;
		}
	}

}

Pexpr vptr_entry(Pexpr pp, Pexpr ie, Pclass cl)
{
	Pptr ttemp = pp->tp->is_ptr_or_ref();

        if (ttemp) {
		Ptype pt = ttemp->typ;  // check if cast pp = (base*)pp
        	Pclass pc = Pclass(pt->is_cl_obj()->tp); // is needed
        	if (pc!=cl) pp = new cast(cl,pp);
        }
	Pname vp = find_vptr(cl);
	if (vp == 0) error('i',"can't find vptr");
	Pexpr vptr = new ref(REF,pp,vp);	// pp->vptr
	return new expr(DEREF,vptr,ie);	// pp->vptr[i]
}

Pexpr new_this(Pexpr pp, Pexpr ee)
{
//error('d',"new this");
	Pexpr dee =  new mdot("d",ee);		// pp->vptr[i].d
	dee->i1 = 9;
	Pexpr nthis = new cast(Pchar_type,pp);
	nthis = new expr(PLUS,nthis,dee);	// ((char*)pp)+delta
	Ptype ct = pp->tp;
	if (pp->base==NAME && Pname(pp)->n_xref) ct = pp->tp->addrof();
	return new cast(ct,nthis);
}

Pcall vcall(Pexpr pp, Pexpr ie, Pfct f, Pclass cl, Pexpr args)
/*
	generate a call of the virtual function with the index ``ie''
	and type "f" in class ``cl'' for the object pointed to by ``pp''

	multiple inheritance virtual call:

	p->f(x) is resolved like this
	pp = p;			// avoid side effects
	pp = p.base_object;	// often: pp = p;
				// done when the name was resolved
	i = index(f);
	entry = pp->_vtbl[i-1];
	pp = (T*)(((char*)pp)+entry.d)
	(*(ftype)entry.f)(pp,x)
*/
{
//error('d',"vcall %t",cl);
 	if (cl->c_body==1) cl->dcl_print(0);	// look for first use of cl
		
	imeasure+=6;
	Pexpr ee = vptr_entry(pp,ie,cl);

	Pexpr fee = new mdot("f",ee);
	fee->i1 = 9;
	Ptype pft = f->addrof();
	fee = new cast(pft,fee);		// (T)pp->vptr[i].f
	Pexpr r = new expr(DEREF,fee,0);	// *(T)pp->vptr[i].f
						// e1->tp must be 0, means "argtype encoded"
	r->tp2 = Ptype(f->f_this);		// encode argtype

	Pexpr nthis = new_this(pp,ee);

	args = new expr(ELIST,nthis,args);
	args->simpl();

	Pcall c = new call(r,args);
	c->tp = f->returns;
	return c;
}

void call::simpl()
/*
	fix member function calls:
		p->f(x) becomes f(p,x)
		o.f(x)  becomes f(&o,x)
	or if f is virtual:
		p->f(x) is resolved like this
			pp = p;
			i = index(f);
			entry = pp->_vtbl[i-1];
			pp = (T*)(((char*)pp)+entry.i)
			(*entry.f)(pp,x)
	replace calls to inline functions by the expanded code
*/
{
	Pname fn = fct_name;
//error('d',"%d call::simpl() fn %n %d e1 %d",this,fn,fn,e1);
	Pfct f = fn ? Pfct(fn->tp) : 0;

	if (fn == 0) e1->simpl();

	if (f) {
		switch(f->base) {
		case ANY:
			return;
		case OVERLOAD:
			fct_name = fn = Pgen(f)->fct_list->f;
			f = Pfct(fn->tp);
		}
	}

	switch (e1->base) {
	case MEMPTR:	// (p ->* q)(args)
	{	
		Pexpr p = e1->e1;
		Pexpr q = e1->e2;
		Pclass cl = Pclass(e1->tp2);
		Pfct f = Pfct(q->tp->deref());

		if (e2) e2->simpl();

		if (f->f_this == 0) {	// might not know about ``this'' yet
			if (f->memof == 0) error('i',"memof missing");
			Pname tt = new name("this");
			tt->n_scope = ARG;
			tt->tp = f->memof->this_type;
			PERM(tt);
		//	f->f_this = f->f_args = tt;
			tt->n_list = f->argtype;
		//	f->f_this = tt;
			tt->n_list = f->f_result ? f->f_result : f->argtype;
			f->f_this = f->f_args = tt;
		}
//error('d',"f_this %d",f->f_this);	
extern has_virt(Pclass);

		// beware of sideeffects:
		nin = 1;
		if (q->not_simple()) error('s',"2nd operand of .* too complicated");
		nin = 0;

		Pexpr qq = new mdot("f",q);	// the function: (*(right type)q.f)
		qq->i1 = 9;
		qq = new cast(f->addrof(),qq);
		Pexpr nc = new expr(DEREF,qq,0);
		nc->tp2 = Ptype(f->f_this);	// encode argtype

		Pexpr nthis = new_this(p,q);	// arguments: (p+q.d,args)
		Pexpr args = new expr(ELIST,nthis,e2);
		imeasure+=3;

		if (has_virt(cl) == 0) {	// no virtuals: simple
			if (cl->defined == 0) 
				error("call throughP toMF before definition ofC %t",cl);
//error('d',"no virt");
			// (p ->* q)(args) => (*q.f)(p+q.d,args)
			e1 = nc;
			e2 = args;
			return;
		}
		
		if (find_vptr(cl) == 0) {	// must be a call to a second base
						// that we cannot handle yet
						// it is OK not to to generate
						// a virtual call since a
						// `sorry' will have been generated
						// at the point of initialization
			e1 = nc;
			e2 = args;
			return;

		}
		// beware of sideeffects:
		nin = 1;
		if (p->not_simple()) error('s',"1st operand of .* too complicated");
		nin = 0;

		Pexpr c = new mdot("i",q);	// condition (q.i<0)
		c->i1 = 9;
		c = new expr(LT,c,zero);
		
		Pexpr ie = new mdot("i",q);
		ie->i1 = 9;

		base = QUEST;
		e1 = new call(nc,args);
		e2 = vcall(p,ie,f,cl,e2);
		cond = c;
		return;
	}
	case DOT:
		// if e1 is an object and not just a reference
		// the vtbl need not be used
	case REF:
	{	Pref r = Pref(e1);
		Pexpr a1 = r->e1;
		int obj = r->n_initializer!=0;	// if B::f don't use vcall

		if (obj == 0) {	// don't use vcall if we have an object
				// (not a pointer or a reference)
			if (e1->base==DOT && a1->base!=DEREF) obj = 1;
		}

//error('d',"fct_name %n f %d %d obj %d",fct_name,f,f->f_virtual,obj);
		if (f && obj==0 && f->f_virtual) {
			Pexpr a11 = 0;

			switch(a1->base) {	// see if temporary might be needed
			case NAME:
			case MDOT:
				a11 = a1;
				break;
			case REF:
			case DOT:
				if (a1->e1->base==NAME
				|| ((a1->e1->base==DOT || a1->e1->base==REF) && a1->e1->e1->base==NAME)) a11 = a1;
				break;
			case ADDROF:
			case G_ADDROF:
				if (a1->e2->base == NAME
				|| ((a1->e2->base==DOT || a1->e2->base==REF) && a1->e2->e1->base==NAME)) a11 = a1;
				break;
			case CAST:
				switch (a1->e1->base) {
				case NAME:
				case MDOT:
					a11 = a1;
				}
			}

//		   	if( a1->base==REF && fn->n_oper==DTOR ){
//				a11 = a1;
//				goto zsw;
//		   	}
//
			if (e1->base == DOT) {
//			zsw:
				if (a11) a11 = a11->address();
				a1 = a1->address();
			}
			
			if (a11 == 0) {	// temporary (maybe) needed
				   	// e->f() => (t=e,t->f(t))
				if (a1->base==NAME)
					a11 = a1;	// &*name has become name
				else {
					Pname nx = new name(make_name('K'));
					nx->tp = a1->tp;
					Pname n = nx->dcl(scope,ARG); // no init!
					delete nx;
					Pname cln = a1->tp->is_cl_obj();
					if (cln) {
						Pclass cl = Pclass(cln->tp);
						if (Ntmp==0 && cl->has_dtor()) Ntmp = cln;
						if (cl->has_itor()) n->n_xref = 1;
					}
					n->n_scope = FCT;
					n->assign();
					a11 = n;
					a1 = new expr(ASSIGN,n,a1);
					a1->tp = n->tp;
					a1->simpl();
					Pcall cc = new call(0,0);
					*cc = *this;
					base = CM;
					e1 = a1;
					e2 = cc;
					this = cc;
				}
			}

			int i = f->f_virtual;
			Pexpr ie = i?new ival(i):0;	// index
			Pname cn = fn->n_table->t_name;
			if (fn
			&& fn->n_initializer
			&& cc->nof
			&& cc->nof->n_oper==CTOR
			&& Pfct(cc->nof->tp)->memof->c_abstract
			&& strcmp(Pfct(cc->nof->tp)->memof->string, cn->string) == 0 ) {
				// permit x::x( x& xx ) { xx.pvf(); }
				Pexpr ee = e1->e1;
				while ( ee && ee->base != NAME ) ee = ee->e1;
				if ( ee && strcmp( ee->string, "this" )==0)
					error("call of pure virtualF%n inK%n",fn,cc->nof);
			}
			Pcall vc = vcall(a11,ie,f,Pclass(cn->tp),e2);
			*this = *vc;
			return;	
		}
	
		Ptype tt = r->mem->tp;
	llp:
//error('d',"llp %t",tt);
		switch (tt->base) {
		// default:	// pointer to function: (n->ptr_mem)(args); do nothing
		case TYPE:
			tt = Pbase(tt)->b_name->tp;
			goto llp;
		case OVERLOAD:	// n->fctmem(args);
		case FCT:
			if (fct_name==0) {
				// reconstitute fn destroyed to suppress "virtual" 
				fct_name = fn = Pname(e1->n_initializer);
				f = Pfct(fn->tp);
			}

			if (e1->base == DOT) a1 = a1->address();
			e2 = new expr(ELIST,a1,e2);
			e1 = r->mem;
		}
	}
	}

	if (e2) e2->simpl();
//error('d',"fn %n inl %d imes %d",fn,f->f_inline,f->f_imeasure);
	if (fn && f->f_inline && debug_opt==0) {
		imeasure += f->f_imeasure;
		Pclass cl = f->memof;
		if (cl && cl->c_body) cl->dcl_print(0);
		Ptable oscope = scope;
		Pexpr ee = f->expand(fn,scope,e2);
		scope = oscope;
		if (ee)	*Pexpr(this) = *ee;
	}
	else if (fn && f->f_inline==0 && f->f_imeasure) {
		extern void uninline(Pname fn);
		uninline(fn);
		imeasure += 3;
	}
	else if (fn && debug_opt && f->f_inline==ITOR) {
		extern void expand_itor(Pclass);
		expand_itor(f->memof);
	}
	else
		imeasure += 3;
}

void uninline(Pname fn)
	// inline turned static
{
	Pfct f = Pfct(fn->tp);
//error('d',"uninline %n %d %d",fn,f->body,f->f_expr);

	if (warning_opt) {
		error('w',"%n too complex for inlining",fn);
		error('w',"out-of-line copy of %n created",fn);
	}
	f->f_imeasure = 0;	// now it really is just static

	Pstmt s = f->body->s;
//	for (s = f->body->s; s; s=s->s_list)
//error('d',"start %d %k",s->e,s->e->base);
//	 s = f->body->s;
	while (s) {
//error('d',"s   %k %d %k",s->base,s->e,s->e->base);
		if (s->base == SM) {
			// turn comma expression into statement list
			Pexpr e = s->e;
			if (e)
				switch (e->base) {
				case CM:
				case G_CM:
				{	Pstmt ss = new estmt(SM,no_where,e->e2,0);
					s->e = e->e1;
					ss->s_list = s->s_list;
					s->s_list = ss;
					delete e;
					continue;
				}
				}		
		}
		s = s->s_list;
	}
//	for (s = f->body->s; s; s=s->s_list)
//error('d',"echo %k %d %k",s->base,s->e,s->e->base);

	fn->dcl_print(0);
}

/*
void ccheck(Pexpr e)

	 Is there a conditional in this expression? (not perfect)

{
//error('d',"ccheck(e %k)",e,e?e->base,0);
	if (e)
	switch (e->base) {
	case QUEST:
	case ANDAND:
	case OROR:
		error('s',"E too complicated: uses%k and needs temporary ofCW destructor",e->base);
		break;
	case LT:
	case LE:
	case GT:
	case GE:
	case EQ:
	case NE:
	case ASSIGN:
	case ASPLUS:
	case ASMINUS:
	case G_CM:
	case CM:
	case PLUS:
	case MINUS:
	case MUL:
	case DIV:
	case OR:
	case ER:
	case AND:
	case G_CALL:
	case CALL:
	case ELIST:
	case DEREF:
		ccheck(e->e1);
	case NOT:
	case COMPL:
	case CAST:
	case ADDROF:
	case G_ADDROF:
		ccheck(e->e2);
		break;
	case ICALL:	// check inlined arguments
	{	Pin il = e->il;
		for (int i = 0; il->args[i].arg && i<il->i_slots; i++) ccheck(il->args[i].arg);
	}
	}
}
*/

void temp_in_cond(Pexpr ee, Pstmt ss, Ptable tbl)
/*
	insert destructor calls 'ss' into condition 'ee'
	ee => (Qnn = ee, dtors, Qnn)
*/
{
//error('d',"temp_in_cond");
//	ccheck(ee);
	while (ee->base==CM || ee->base==G_CM) ee = ee->e2;
	Ptype ct = ee->tp;
	Pname n = new name(make_name('Q'));	// int Qnn;
	n->tp = ct;
	Pname tmp = n->dcl(tbl,ARG);
	delete n;
	tmp->n_scope = FCT;

	Pexpr v = new expr(0,0,0);
	*v = *ee;
	PERM(ct);
	v = new cast(ct,v);

	tmp->n_assigned_to = 1;
	Pexpr c = new expr(ASSIGN,tmp,v);	// Qnn = ee
	c->tp = ct;
	ee->base = CM;
	ee->e1 = c;

	Pexpr ex = 0;				// add dtors at end

	for (Pstmt sx = ss; sx; sx = sx->s_list) {
		if (ex) {
			ex = new expr(CM,ex,sx->e);
			ex->tp = sx->e->tp;
		}
		else
			ex = sx->e;
	}
	ee->e2 = new expr(CM,ex,tmp);	// add Qnn at end
	ee->e2->tp = ct;
}

bit not_safe(Pexpr e)
{

	switch (e->base) {
	default:
		return 1;
/*
	case CALL:
	case G_CALL:
	case DOT:
	case REF:
	case ANAME:
		return 1;
*/
	case NAME:
		// if the name is automatic and has a destructor it is not safe
		// to destroy it before returning an expression depending on it
	{	Pname n = Pname(e);
		if (n->n_table!=gtbl && n->n_table->t_name==0) {
			Pname cn = n->tp->is_cl_obj();
			if (cn && Pclass(cn->tp)->has_dtor()) return 1;
		}
	}
	case IVAL:
	case ICON:
	case CCON:
	case FCON:
	case STRING:
		return 0;
	case NOT:
	case COMPL:
	case ADDROF:
	case G_ADDROF:
		return not_safe(e->e2);
	case DEREF:
	//	return not_safe(e->e1) || e->e2?not_safe(e->e2):0;
	{	int i = not_safe(e->e1);
		if (i) return i;
		if (e->e2) return not_safe(e->e2);
		return 0;
	}
	case CM:
	case PLUS:
	case MINUS:
	case MUL:
	case DIV:
	case MOD:
	case ASSIGN:
	case ASPLUS:
	case ASMINUS:
	case ASMUL:
	case ASDIV:
	case OR:
	case AND:
	case OROR:
	case ANDAND:
	case LT:
	case LE:
	case GT:
	case GE:
	case EQ:
	case NE:
		return not_safe(e->e1) || not_safe(e->e2);
	case QUEST:
		return not_safe(e->cond) || not_safe(e->e1) || not_safe(e->e2);
	}
}
		
	
Pexpr curr_expr;	/* to protect against an inline being expanded twice
			   in a simple expression keep track of expressions
			   being simplified
			*/
Pstmt stmt::simpl()
/*
	return a pointer to the last statement in the list, or 0
*/
{
	if (this == 0) error('i',"0->S::simpl()");
	DB( if(Sdebug>=1){
		error('d',"%d->stmt::simpl():  %k",this,base);
		if(Sdebug>=2) display_stmt(this);
	});
	//Pstmt ostmt = Cstmt;
	//if ( where.line ) Cstmt = this;

	stmtno++;
	curr_expr = e;
//error('d',"stmt::simpl %k s_list %d",base,s_list);

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

	case ASM:
		break;

	case BREAK:
		if (break_del_list) {	// break => { _dtor()s; break; }
			Pstmt bs = new stmt(base,where,0);
			Pstmt dl = break_del_list->copy();
			base = BLOCK;
			s = new pair(where,dl,bs);
		}
		break;

	case CONTINUE:
		if (continue_del_list) { // continue => { _dtor()s; continue; }
			Pstmt bs = new stmt(base,where,0);
			Pstmt dl = continue_del_list->copy();
			base = BLOCK;
			s = new pair(where,dl,bs);
		}
		break;

	case DEFAULT:
		s->simpl();
		break;

	case SM:
		if (e) {
			if (e->base == DEREF) e = e->e1;
			e->simpl();
			if (e->base == DEREF) e = e->e1;
		}
		break;

	case RETURN:
	{	/*	return x;
			=>
				{ dtor()s; return x; }
			OR (returning an X where X(X&) is defined) =>
				{ ctor(_result,x); _dtor()s; return; }
			OR (where x needs temporaries)
			OR (where x might involve an object to be destroyed) =>
				{ _result = x; _dtor()s;  return _result; }
			return;		=>
				{ _dtor()s; return; }
			OR (in constructors) =>
				{ _dtor()s; return _this; }
		*/
		Pstmt sx = this;
		Pexpr ex = e;

		no_of_returns++;

		Pstmt dl = (del_list) ? del_list->copy() : 0;
		Pfct f = Pfct(curr_fct->tp);

		if (e == 0) e = dummy;
		if (e==dummy && curr_fct->n_oper==CTOR) e = f->f_this;


		//      need to generate a temporary for mptr return
		Pexpr tt = e;
		while ( tt->base == CAST )
			tt = tt->e1;
		if ( tt->base == ILIST )
			e = tt;

		if (e->base == ILIST) {
			extern Pbase mptr_type;
			extern Ptype Pvptr_type;
			Pexpr mptr_assign(Pexpr, Pexpr);
			// memptr constant
			// return({1,2,f}) ==> memptr t; return((t={1,2,f},&t))

			Ptable ftbl = Pfct(curr_fct->tp)->body->memtbl;
			Pname temp = make_tmp('A',mptr_type,ftbl);

			// placed in mptr_assign()
			// temp->use(); // necessary for inlines to force declaration

			e = mptr_assign(temp,e);
			e = new expr(G_CM,e,temp);
			e->tp = mptr_type;
		}

		if (f->f_result) {	// ctor(_result,x); dtors; return;
			if (e->base == G_CM) e = replace_temp(e,f->f_result);
			e->simpl();
			Pstmt cs = new estmt(SM,where,e,0);
			if (dl)	cs = new pair(where,cs,dl);
			base = PAIR;
			s = cs;
			s2 = new estmt(RETURN,where,0,0);
//#ifdef RETBUG
//			s2->empty = 1; // fudge to bypass C bug (see print.c)
//			s2->ret_tp = ret_tp;
//#endif
		}
		else {			// dtors; return e;
			e->simpl();
			if (dl) {
				if (e!=dummy && not_safe(e)) {
				// { _result = x; _dtor()s;  return _result; }
					Ptable ftbl = Pfct(curr_fct->tp)->body->memtbl;
					
					Pname r = ftbl->look("_result",0);
					if (r == 0) {
						r = new name("_result");
						r->tp = ret_tp;
						Pname rn = r->dcl(ftbl,ARG);
						rn->n_scope = FCT;
						rn->where = no_where;
						rn->assign();
						delete r;
						r = rn;
					}
					Pexpr as = new expr(ASSIGN,r,e);
					as->tp = ret_tp;	// wrong if = overloaded, but then X(X&) ought to have been used 
					Pstmt cs = new estmt(SM,where,as,0);
					cs = new pair(where,cs,dl);
					base = PAIR;
					s = cs;
					s2 = new estmt(RETURN,where,r,0);
				//	s2->ret_tp = ret_tp;
				}
				else { // { _dtor()s;  return x; }
					base = PAIR;
					s = dl;
					s2 = new estmt(RETURN,where,e,0);
				}
                                 s2->ret_tp = ret_tp;
			}
		}

//		if (sx->memtbl) {
//			int i;
//			for (Pname n=sx->memtbl->get_mem(i=1); n; n=sx->memtbl->get_mem(++i)) {
//				Pname cn = n->tp->is_cl_obj();
//				if (cn && Pclass(cn->tp)->has_dtor()) {
//					ccheck(ex);
//					break;
//				}
//			}
//		}
		break;
	}

	case WHILE:
	case DO:
		e->simpl();
		{	Pstmt obl = break_del_list;
			Pstmt ocl = continue_del_list;
			break_del_list = 0;
			continue_del_list = 0;
			s->simpl();
			break_del_list = obl;
			continue_del_list = ocl;
		}
		break;

	case SWITCH:
		e->simpl();
		{	Pstmt obl = break_del_list;
			break_del_list = 0;
			s->simpl();
			break_del_list = obl;
		}
		switch (s->base) {
		case DEFAULT:
		case LABEL:
		case CASE:
			break;
		case BLOCK:
			if (s->s)
			switch (s->s->base) {
			case BREAK:	// to cope with #define Case break; case
			case CASE:
			case LABEL:
			case DEFAULT:
				break;
			default:
				goto df;
			}
			break;
		default:
		df:
			error(&s->where,"S orIdE not reached: (case label missing?)");
		}
		break;

	case CASE:
		e->simpl();
		s->simpl();
		break;

	case LABEL:
		if (del_list) error('s',"label in blockW destructors");
		s->simpl();
		break;

	case GOTO:
		/*	If the goto is going to a different (effective) scope,
			then it is necessary to activate all relevant destructors
			on the way out of nested scopes, and issue errors if there
			are any constructors on the way into the target.

			Only bother if the goto and label have different effective
			scopes. (If mem table of goto == mem table of label, then
			they're in the same scope for all practical purposes.
		*/
		{
		Pname n = scope->look( d->string, LABEL );
		if (n == 0) error('i',&where,"label%n missing",d);
		if(n->n_realscope!=scope && n->n_assigned_to) {

			/*	Find the root of the smallest subtree containing
				the path of the goto.  This algorithm is quadratic
				only if the goto is to an inner or unrelated scope.
			*/

			Ptable r = 0;

			for(Ptable q=n->n_realscope; q!=gtbl; q=q->next) {
				for( Ptable p = scope; p != gtbl; p = p->next ) {
					if( p==q ) {
						r = p;	// found root of subtree!
						goto xyzzy;
					}
				}
			}

xyzzy:			if( r==0 ) error( 'i',&where,"finding root of subtree" );

			/* At this point, r = root of subtree, n->n_realscope
			 * = mem table of label, and scope = mem table of goto. */

			/* Climb the tree from the label mem table to the table
			 * preceding the root of the subtree, looking for
			 * initializers and ctors.  If the mem table "belongs"
			 * to an unsimplified block(s), the n_initializer field
			 * indicates presence of initializer, otherwise initializer
			 * information is recorded in the init_stat field of
			 * mem table. */

			for( Ptable p=n->n_realscope; p!=r; p=p->next )
				if( p->init_stat == 2 ) {
					error(&where,"goto%n pastDWIr",d);
					goto plugh; /* avoid multiple error msgs */
				}
				else if( p->init_stat == 0 ) {
					int i;
					for(Pname nn=p->get_mem(i=1);nn;nn=p->get_mem(++i))
						if(nn->n_initializer||nn->n_evaluated){
							error(&nn->where,"goto%n pastId%n",d,nn);
							goto plugh;
						}
				}
plugh:

			/* Proceed in a similar manner from the point of the goto,
			 * generating the code to activate dtors before the goto. */
			/* There is a bug in this code.  If there are class objects
			 * of the same name and type in (of course) different mem
			 * tables on the path to the root of the subtree from the
			 * goto, then the innermost object's dtor will be activated
			 * more than once. */

			{
			Pstmt dd = 0, ddt = 0;

			for( Ptable p=scope; p!=r; p=p->next ) {
				int i;
				for(Pname n=p->get_mem(i=1);n;n=p->get_mem(++i)) {
		Pname cln;
		if (n->tp == 0) continue; /* label */

		if ( cln=n->tp->is_cl_obj() ) {
			Pclass cl = (Pclass)cln->tp;
			Pname d = cl->has_dtor();

			if (d) {	/* n->cl::~cl(0); */
				Pexpr dl = call_dtor(n,d,0,DOT,one);
				Pstmt dls = new estmt(SM,n->where,dl,0);
				if (dd)
					ddt->s_list = dls;
				else
					dd = dls;
				ddt = dls;
			}

		}
		else if (cl_obj_vec) {
			Pclass cl = (Pclass)cl_obj_vec->tp;
		//	Pname c = cl->has_ictor();
			Pname d = cl->has_dtor();

			if (d) {	//  __vec_delete(vec,noe,sz,dtor,0);
				Pfct f = Pfct(d->tp);
				int i = 0;
				for (Pname nn = f->f_args->n_list; 
					nn && nn->n_list; nn=nn->n_list) i++;
				Pexpr a = cdvec(vec_del_fct,n,cl,d,0,new ival(i));
				Pstmt dls = new estmt(SM,n->where,a,0);
				if (dd)
					ddt->s_list = dls;
				else
					dd = dls;
				ddt = dls;
			}
		}
				} /* end mem table scan */
			} /* end dtor loop */

			/* "activate" the list of dtors obtained. */

			if( dd ) {
				dd->simpl();
				Pstmt bs = new stmt( base, where, 0 );
				*bs = *this;
				base = PAIR;
				s = dd;
				s2 = bs;
			}
			}
		} /* end special case for non-local goto */
		}
		break;

	case IF:
		e->simpl();
		s->simpl();
		if (else_stmt) else_stmt->simpl();
		break;

	case FOR:	// "for (s;e;e2) s2; => "s; for(;e,e2) s2"
		if (for_init) for_init->simpl();
		if (e) {
			curr_expr = e;
			e->simpl();
		}
		if (e2) {
			curr_expr = e2;
			e2->simpl();
 			if (e2->base==ICALL)
				if (e2->e1 == 0) error('s',"cannot expand inline void%n called in forE", e2->il->fct_name);
		}
		{	Pstmt obl = break_del_list;
			Pstmt ocl = continue_del_list;
			break_del_list = 0;
			continue_del_list = 0;
			s->simpl();
			break_del_list = obl;
			continue_del_list = ocl;
		}
		break;

	case BLOCK:
		Pblock(this)->simpl();
		break;

	case PAIR:
		break;
	}

	/*if (s) s->simpl();*/
//error('d',"base %k memtbl %d",base,memtbl);
	if (base!=BLOCK && memtbl) {
		Pstmt t1 = (s_list) ? s_list->simpl() : 0;
		Pstmt tpx = t1 ? t1 : this;

		Pstmt ss = 0;
		Pname cln;	// used for warnings
		int i;
		Pname tn = memtbl->get_mem(i=1);
		for (; tn; tn=memtbl->get_mem(++i)) {
			if (cln = tn->tp->is_cl_obj()) {
				Pname d = Pclass(cln->tp)->has_dtor();
				if (d) {	/* n->cl::~cl(0); */
					Pexpr dl = call_dtor(tn,d,0,DOT,one);
					Pstmt dls = new estmt(SM,tn->where,dl,0);
					dls->s_list = ss;
					ss = dls;
				}
			}
		}

		if (ss) {
			Pstmt t2 = ss->simpl();

			switch (base) {
			case IF:
			case WHILE:
			case DO:
			case SWITCH:
				temp_in_cond(e,ss,memtbl);
				break;

			case PAIR:	// can hide a return
			{	Pstmt ts = s2;
				while (ts->base==PAIR) ts = ts->s2;
				if (ts->base == RETURN) {	// sordid
					this = ts;
					goto retu;
				}
				goto def;
			}
			case RETURN:
			retu:
			{	
				if (e == 0) {
					// return; dtors; => dtors; return;
					Pstmt rs = new estmt(RETURN,where,0,0);
					//rs->empty = empty;	// BSD fudge
					rs->ret_tp = ret_tp;
					base = PAIR;
					s = ss;
					s2 = rs;
					//Cstmt = ostmt;
					return t1 ? t1 : rs;
				}

				Pname cln = e->tp->is_cl_obj();
				if (cln==0
				|| Pclass(cln->tp)->has_oper(ASSIGN)==0) {
					//  ... return e; dtors; =>
					//  ... X r; ... r = e; dtors; return r;
					Pname rv = new name("_rresult"); // NOT "_result"
					rv->tp = ret_tp /* e->tp */;
					if (memtbl == 0) memtbl = new table(4,0,0);
					Pname n = rv->dcl(memtbl,ARG);
					n->where = no_where;
					n->n_scope = FCT;
					n->n_assigned_to = 1;
					delete rv;
					Pstmt rs = new estmt(RETURN,where,n,0);
					rs->ret_tp = ret_tp;
					base = SM;
					e = new expr(ASSIGN,n,e);
					e->tp = n->tp;
					Pstmt ps = new pair(where,ss,rs);
					ps->s_list = s_list;
					s_list = ps;
					//Cstmt = ostmt;
					return t1 ? t1 : rs;
				}
			}
				
			case FOR:	// don't know which expression the temp comes from
				error('s',&where,"E in %kS needs temporary ofC%nW destructor",base,cln);
				break;

			case SM:	// place dtors after all "converted" DCLs
				if (t1) {
//					ccheck(e);
					for (Pstmt ttt, tt=this;
						(ttt=tt->s_list) && ttt->base==SM;
						tt = ttt) ;
					t2->s_list = ttt;
					tt->s_list = ss;
					//Cstmt = ostmt;
					return t1!=tt ? t1 : t2;
				}
			default:
			def:
//				if (e) ccheck(e);
				if (t1) {	// t1 == tail of statment list
					t2->s_list = s_list;
					s_list = ss;
					//Cstmt = ostmt;
					return t1;
				}
				s_list = ss;
				//Cstmt = ostmt;
				return t2;
			}
		}
		//Cstmt = ostmt;
		return (t1) ? t1 : this;
	}

	//Cstmt = ostmt;
	return (s_list) ? s_list->simpl() : this;
}

Pstmt stmt::copy()
// now handles dtors in the expression of an IF stmt
// not general!
{
	Pstmt ns = new stmt(0,curloc,0);

	*ns = *this;
	if (s) ns->s = s->copy();
	if (s_list) ns->s_list = s_list->copy();

	switch (base) {
	case PAIR:
		ns->s2 = s2->copy();
		break;
	}

	return ns;
}

Pname overFound = 0;

static Pexpr 
mk_new_with_args( Pexpr pe, Ptype tt, Pclass cl, Pexpr vec = 0 ) 
{ // allocate using operator new(sizeof(cl),args1)
	Pexpr p;
	Pexpr args = pe->e2;

	// Pexpr ce = new texpr(SIZEOF,tt,0);
	Pexpr ce;
	if (vec) 
  		ce = vec;
	else ce = new texpr(SIZEOF,tt,0);

	(void) tt->tsizeof();
	ce->tp = size_t_type;
	args = new expr(ELIST,ce,args);
	char* s = oper_name(NEW);
	Pname n = new name(s);
	if (pe->base == GNEW)	// ::new
		p = gtbl->look(s,0);
	else 
		p = find_name(n,cl,scope,CALL,curr_fct);
	p = new call(p,args);
	overFound=0; // set in call_fct
	(void) p->call_fct(cl->memtbl);
	if (overFound && overFound->n_scope != EXTERN) 
		check_visibility(overFound,0,cl,cc->ftbl,cc->nof);
	overFound=0;
	return p;
}

void expr::simpl_new()
/*
	change NEW or GNEW node to CALL node
*/
{
	Pname cln;
	Pname ctor;
	int sz = 1;
//	int esz;
	Pexpr var_expr = 0;
	Pexpr const_expr = 0;
	Ptype tt = tp2;
	Pexpr arg;
	Pexpr szof;
	Pname nf;
	Pexpr init = e1;

	if (init && init->base) init = 0;	// only non-ctor init
// error('d',"simpl_new %k e1 %k e2 %k init %k",base, e1?e1->base:0,e2?e2->base:0,init?init->base:0);

	if ((cln=tt->is_cl_obj()) && init == 0) {
		Pclass cl = Pclass(cln->tp);
		Pexpr p;
		ctor=cl->has_ctor();
// error('d',"cl %t ctor %n",cl, ctor);
		if (e2		// placement
		    || ctor==0	// no constructor
		    || ctor->n_table!=cl->memtbl // inherited constructor??? 
		    || (base==GNEW && cl->has_oper(NEW)) )
			p = mk_new_with_args( this, tt, cl ); // new(sizeof(cl),args1)
		else {
			p = zero;	// 0->ctor(args)
			// check visibility anyway...
			(void)mk_new_with_args(this,tt,cl);
		}

		if (ctor) {
			Pexpr c = e1;	// ctor call generated in expr::typ
			Ptype ttt = tp;
			c->e1->e1 = p;	// p->ctor
			c->simpl();
			*this = *c;
			tp = ttt;
			delete c;
		}
		else {		// (tp)new(args)
			base = CAST;
			tp2 = tp;
			e1 = p;
			e2 = 0;
			simpl();
		}
		return;
	} else if ( cln ) {
		Pclass cl = Pclass(cln->tp);
		// check visibility anyway...
		(void)mk_new_with_args(this,tt,cl);
	}
	
	Pclass covn = 0;
	if (cl_obj_vec) {
		covn = Pclass(cl_obj_vec->tp);
		ctor = covn->has_ictor();
		if (ctor == 0) {
			if (covn->has_ctor()) error("new %s[], no defaultK",covn->string);
			cl_obj_vec = 0;
		}
	}

xxx:
//error('d',"xxx %t",tt);
	switch (tt->base) {
	case TYPE:
		tt = Pbase(tt)->b_name->tp;
		goto xxx;

	default:
		(void) tt->tsizeof();
		szof = new texpr(SIZEOF,tt,0);
		szof->tp = uint_type;
		break;

	case VEC:
	{	Pvec v = Pvec(tt);
//error('d',"v %d %d",v->size,v->dim);
		if (v->size)
			sz *= v->size;
		else if (v->dim) 
			var_expr = v->dim;
		else
			sz = 0;
		tt = v->typ;
		goto xxx;
	}
	}

	if (cl_obj_vec) { // _vec_new(0,no_of_elements,element_size,ctor)
		const_expr = new ival(sz);
		Pexpr noe = (var_expr) ? (sz!=1) ? new expr(MUL,const_expr,var_expr) : var_expr : const_expr;
		const_expr = szof;
		const_expr->tp = uint_type;
		base = CALL;
		arg = new expr(ELIST,ctor,0);
		/*ctor->take_addr();*/
		ctor->lval(ADDROF);
		Pexpr sub=0;
		if (e2 && e2->e1 &&
			e2->e1->tp &&
			e2->e1->tp->base != PTR ) 
		{ // new(size_t, args)
			Pexpr vec_sz = new expr(MUL, noe, const_expr);
			sub = mk_new_with_args( this, tt, covn, vec_sz );
		}
		arg = new expr(ELIST,const_expr,arg);
		arg = new expr(ELIST,noe,arg);
		// arg = new expr(ELIST,e2?e2:zero,arg);	// may be preallocated
		arg = new expr(ELIST,e2?(sub?sub:e2):zero,arg);	// may be preallocated
		base = CAST;
		tp2 = tp;
		e1 = new expr(G_CALL,vec_new_fct,arg);
		e1->fct_name = vec_new_fct;
		e1->tp = Pfct(vec_new_fct->tp)->returns;
		simpl();
		return;
	}

	/* call _new(element_size*no_of_elements) */
//error('d',"sz %d var %d",sz,var_expr);
	if (sz == 1)
		arg = (var_expr) ? new expr(MUL,szof,var_expr) : szof;
	else {
		const_expr = new ival(sz);
		const_expr->tp = uint_type;
		const_expr = new expr(MUL,const_expr,szof);
		const_expr->tp = uint_type;
		arg = (var_expr) ? new expr(MUL,const_expr,var_expr) : const_expr;
	}

	arg->tp = uint_type;
	base = CAST;
	tp2 = tp;
	arg = new expr(ELIST,arg,e2);
	nf = gtbl->look(oper_name(NEW),0);	// always global,
						// all class object handled above
	e1 = new expr(G_CALL,nf,arg);
	(void) e1->call_fct(gtbl);
	simpl();

	if (init) {	// alloc(sz) => (p=alloc(sz),*p=init,p);
		Pexpr p = init->e1;
		Pexpr ee = new expr(0,0,0);
		*ee = *this;	
		ee = new expr(ASSIGN,p,ee);	// ee: p = alloc(sz);
		init->base = ASSIGN;
		init->e1 = p->contents();	// init: *p = init_val
		ee = new expr(CM,ee,init);
		ee->simpl(); 
		base = CM;
		e1 = ee;
		e2 = p;
	}
}

void expr::simpl_delete()
/*
	delete p => _delete(p);
		    or  cl::~cl(p,1);
	delete[s]p => _delete(p);
			or vec_del_fct(p,vec_sz,elem_sz,~cl,1);
*/		 
{
	for (Ptype tt = e1->tp; tt->base==TYPE; tt=Pbase(tt)->b_name->tp);
	tt = Pptr(tt)->typ;
//error('d',"simpl_delete() %t",e1->tp);
	Pname cln = tt->is_cl_obj();
	Pname n;
	Pclass cl;

	if (cln) {
		cl = Pclass(cln->tp);
		if ((cl->defined&DEFINED) == 0) error('w',"delete%t (%t not defined)",cl,cl);
	}
	else
		cl = 0;

	if (cl && (n=cl->has_dtor())) {	// ~cl() might be virtual
		//xxx check for private/protected op delete
		{
			Pexpr ee = new expr(ELIST,e1,0);
			char* s = oper_name(DELETE);
			Pname n;
//error('d',"%s( %k )",s,e1->base);
			if (base!=GDELETE) {
				n = new name(s);
				n = (Pname)find_name(n,cl,scope,CALL,curr_fct);
//error('d',"found%n  %t",n,n->tp);
				if (n->tp->base==OVERLOAD
				||  Pfct(n->tp)->nargs==2) {
					Pexpr ss = new texpr(SIZEOF,cl,0);
					ss->tp = size_t_type;
					ee->e2 = new expr(ELIST,ss,0);
				}
			}
			else
				n = gtbl->look(s,0);
//error('d',"found%n  %t",n,n->tp);
			ee = new call(n,ee);
			ee->base = G_CALL;
//error('d',"delete..."); display_expr(ee);
// following commented out to avoid typ::checking problems
			//overFound=0; // set in call_fct
			//(void) ee->call_fct(cl->memtbl);
			//if (overFound && overFound->n_scope != EXTERN) 
				//check_visibility(overFound,0,cl,cc->ftbl,cc->nof);
			//overFound=0;
		}

//if ( base!=GDELETE ) (void) cl->has_oper(DELETE);

		if(base==GDELETE && e2==0 || Pfct(n->tp)->f_virtual) {	// may need temp
			nin=1;
			int needtemp = e1->not_simple();
			nin=0;
			if(needtemp) {
				// convert:	delete [e2] e1
				// to:	(T=e1), delete [e2] T
				// where T is a new temporary.
				Pname tnx = new name(make_name('K'));
				tnx->tp = e1->tp;
				Pname tn = tnx->dcl(scope,FCT);
				delete tnx;
				tn->assign();
				e1 = new expr(ASSIGN,tn,e1);
				e2 = new expr(base,tn,e2);
				base=CM;

				simpl();
				return;
			}
		}
		Pexpr r = e1;
	
		// handle delete p, where p has a private destructor
		if (n->n_scope != PUBLIC) check_visibility(n,0,cl,cc->ftbl,cc->nof);
//error('d',"e2 %d %k",e2,base);
		if (e2 == 0) {		// e1->cl::~cl(1)
			Pexpr ee = call_dtor(r,n,base==GDELETE?0:one,REF,one);
			if (Pfct(n->tp)->f_virtual) {
				if (ansi_opt) { // q?void:int would be an error
					ee = new expr(G_CM,ee,zero);
					ee->tp = zero_type;
				}
				ee = new expr(QUEST,ee,zero);
				ee->tp = ee->e1->tp;
				ee->cond = r;
			}
			if (base == GDELETE) {
				char* s = oper_name(DELETE);
				Pexpr p = gtbl->look(s,0);
				e2 = new call(p,new expr(ELIST,e1,0));
				base = CM;
				e1 = ee;
			}
			else {
				*this = *ee;
				delete ee;
			}
			simpl();
			return;
		}
		else {		// del_cl_vec(e1,e2,elem_size,~cl,1);
			Pexpr sz = new texpr(SIZEOF,tt,0);
			(void)tt->tsizeof();
			Pfct f = Pfct(n->tp);
			int i = 0;
			Pname nn = f->f_args->n_list;
			for (; nn && nn->n_list; nn=nn->n_list) i++;
//error('d',"n %n i %d",n,i);
			Pexpr arg = new ival(i);
			sz->tp = uint_type;
		//	Pexpr arg = one;
			arg = new expr(ELIST,one,arg);
			if (Pfct(n->tp)->f_virtual) {
				Pexpr a = new ref(REF,e1,n);
				a = a->address();
				a = new mdot( "f", a );
				a->i1 = 9;
				arg = new expr(ELIST,a,arg);
			}
			else {
				arg = new expr(ELIST,n,arg);
				n->lval(ADDROF);	// n->take_addr();
			}

			arg = new expr(ELIST,sz,arg);
			if (e2->base==DUMMY) {
			        e2 = new ival(-1);      // handle `delete[]p'
			}

			arg = new expr(ELIST,e2,arg);
			arg = new expr(ELIST,e1,arg);
			Pexpr ee = new expr(G_CALL,vec_del_fct,arg);
			ee->fct_name = vec_del_fct;
			ee->tp = tp;
	//		if (ansi_opt) { // q?void:int would be an error
	//			ee = new expr(G_CM,ee,zero);
	//			ee->tp = zero_type;
	//		}
	//		ee = new expr(QUEST,ee,zero);
	//		ee->tp = tp;
	//		ee->cond = r;
			*this = *ee;
			simpl();
			return;
		}
	}
	else if (cl_obj_vec) {
		error("delete array of arrays");
	}
	else {					// _delete(e1)
		Pexpr ee = new expr(ELIST,e1,0);
		char* s = oper_name(DELETE);
		if (cl && base!=GDELETE) {
			Pname n = new name(s);
			e1 = find_name(n,cl,scope,CALL,curr_fct);
			if (e1->tp->base==OVERLOAD || Pfct(e1->tp)->nargs==2) {
				Pexpr ss = new texpr(SIZEOF,cl,0);
				ss->tp = size_t_type;
				ee->e2 = new expr(ELIST,ss,0);
			}
		}
		else
			e1 = gtbl->look(s,0);
		base = G_CALL;
		e2 = ee;
		overFound=0; // set in call_fct
		(void) call_fct(scope);
		if (overFound && overFound->n_scope != EXTERN) 
			check_visibility(overFound,0,cl,cc->ftbl,cc->nof);
		overFound=0;
	}

	Pcall(this)->simpl();
}
0707071010112045371004440001630000160000010207600466055410400000700000013461size.c/*ident	"@(#)ctrans:src/size.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 rigths Reserved
	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC.

size.c:

	initialize alignment and sizeof "constants"

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

#include "cfront.h"
#include "size.h"

int BI_IN_WORD = DBI_IN_WORD;
int BI_IN_BYTE = DBI_IN_BYTE;
int SZ_CHAR = DSZ_CHAR;
int AL_CHAR = DAL_CHAR;
int SZ_SHORT = DSZ_SHORT;
int AL_SHORT = DAL_SHORT;
int SZ_INT = DSZ_INT;
int AL_INT = DAL_INT;
int SZ_LONG = DSZ_LONG;
int AL_LONG = DAL_LONG;
int SZ_FLOAT = DSZ_FLOAT;
int AL_FLOAT = DAL_FLOAT;
int SZ_DOUBLE = DSZ_DOUBLE;
int AL_DOUBLE = DAL_DOUBLE;
int SZ_LDOUBLE = DSZ_LDOUBLE;
int AL_LDOUBLE = DAL_LDOUBLE;
int SZ_STRUCT = DSZ_STRUCT;
int AL_STRUCT = DAL_STRUCT;
//int SZ_FRAME = DSZ_FRAME;
//int AL_FRAME = DAL_FRAME;
int SZ_WORD = DSZ_WORD;
int SZ_WPTR = DSZ_WPTR;
int AL_WPTR = DAL_WPTR;
int SZ_BPTR = DSZ_BPTR;
int AL_BPTR = DAL_BPTR;
//int SZ_TOP = DSZ_TOP;
//int SZ_BOTTOM = DSZ_BOTTOM;
char* LARGEST_INT = DLARGEST_INT;
int F_SENSITIVE = DF_SENSITIVE;
int F_OPTIMIZED =  DF_OPTIMIZED;

int arg1 = 0;

int get_line(FILE* fp)
{
	char s[32];
	char s2[32];

	if (fscanf(fp,"%s %s",s2,s) == EOF) return 0;

	if (strcmp("DLARGEST_INT",s) == 0) { 
		if (fscanf(fp," %s",s2)==EOF) return 0;
//// get rid of quotes
		for(int i=0;i<=strlen(s2)+1;i++)
			if (s2[i]== '"') {
				for (int j=i;j<=strlen(s2)+1;j++)
					s2[j]=s2[j+1];
			}
		}
	else 
		if (fscanf(fp,"%d ",&arg1) == EOF) return 0;

	if (strcmp("DSZ_CHAR",s) == 0) {
		SZ_CHAR = arg1;
		return 1;
	}

	if (strcmp("DAL_CHAR",s) == 0) {
		AL_CHAR = arg1;
		return 1;
	}

	if (strcmp("DSZ_SHORT",s) == 0) {
		SZ_SHORT = arg1;
		return 1;
	}
	
	if (strcmp("DAL_SHORT",s) == 0) {
		AL_SHORT = arg1;
		return 1;
	}

	if (strcmp("DSZ_INT",s) == 0) {
		SZ_INT = arg1;
		return 1;
	}

	if (strcmp("DAL_INT",s) == 0) {
		AL_INT=arg1;
		return 1;
	}

	if (strcmp("DLARGEST_INT",s) == 0) {
		LARGEST_INT = new char[strlen(s2)+1];
		strcpy(LARGEST_INT,s2);
		return 1;
	}

	if (strcmp("DSZ_LONG",s) == 0) {
		SZ_LONG = arg1;
		return 1;
	}

	if (strcmp("DAL_LONG",s) == 0) {
		AL_LONG = arg1;
		return 1;
	}

	if (strcmp("DSZ_FLOAT",s) == 0) {
		SZ_FLOAT = arg1;
		return 1;
	}

	if (strcmp("DAL_FLOAT",s) == 0) {
		AL_FLOAT = arg1;
		return 1;
	}

	if (strcmp("DSZ_DOUBLE",s) == 0) {
		SZ_DOUBLE = arg1;
		return 1;
	}

	if (strcmp("DAL_DOUBLE",s) == 0) {
		AL_DOUBLE = arg1;
		return 1;
	}
	
	if (strcmp("DSZ_LDOUBLE",s) == 0) {
		SZ_LDOUBLE = arg1;
		return 1;
	}

	if (strcmp("DAL_LDOUBLE",s) == 0) {
		AL_LDOUBLE = arg1;
		return 1;
	}

	if (strcmp("DBI_IN_BYTE",s) == 0) {
		BI_IN_BYTE = arg1;
		return 1;
	}

	if (strcmp("DBI_IN_WORD",s) == 0) {
		BI_IN_WORD= arg1;
		return 1;
	}

	if (strcmp("DSZ_STRUCT",s) == 0) {
		SZ_STRUCT = arg1;
		return 1;
	}

	if (strcmp("DAL_STRUCT",s) == 0) {
		AL_STRUCT = arg1;
		return 1;
	}

	if (strcmp("DF_SENSITIVE",s) == 0) {
		F_SENSITIVE = arg1;
		return 1;
	}

	if (strcmp("DF_OPTIMIZED",s) == 0) {
		F_OPTIMIZED = arg1;
		return 1;
	}

	if (strcmp("frame",s) == 0) {
//		SZ_FRAME = arg1;
//		AL_FRAME = arg2;
		return 1;
	}

	if (strcmp("DSZ_WORD",s) == 0) {
		SZ_WORD = arg1;
		return 1;
	}

	if (strcmp("DSZ_WPTR",s) == 0) {
		SZ_WPTR = arg1;
		return 1;
	}

	if (strcmp("DAL_WPTR",s) == 0) {
		AL_WPTR = arg1;
		return 1;
	}

	if (strcmp("DSZ_BPTR",s) == 0) {
		SZ_BPTR = arg1;
		return 1;
	}

	if (strcmp("DAL_BPTR",s) == 0) {
		AL_BPTR = arg1;
		return 1;
	}

	if (strcmp("top",s) == 0) {
//		SZ_TOP = arg1;
//		SZ_BOTTOM = arg2;
		return 1;
	}
	return 0;
}

int read_align(char* f)
{
	char* p = f;
	if (*p == 0) {
		fprintf(stderr,"size/align file missing\n");
		ext(1);
	}
	FILE* fp = fopen(f,"r");
	if (fp == 0) return 1;
	while (get_line(fp)) ;
	return 0;
}
/*
print_align(char* s)
{
	fprintf(stderr,"%s sizes and alignments\n\n",s);

	fprintf(stderr,"	size	align	largest\n");
	fprintf(stderr,"char	%d	%d\n",SZ_CHAR,AL_CHAR);
	fprintf(stderr,"short	%d	%d\n",SZ_SHORT,AL_SHORT);
	fprintf(stderr,"int	%d	%d	%s\n",SZ_INT,AL_INT,LARGEST_INT);
	fprintf(stderr,"long	%d	%d\n",SZ_LONG,AL_LONG);
	fprintf(stderr,"float	%d	%d\n",SZ_FLOAT,AL_FLOAT);
	fprintf(stderr,"double	%d	%d\n",SZ_DOUBLE,AL_DOUBLE);
	fprintf(stderr,"ldouble	%d	%d\n",SZ_LDOUBLE,AL_LDOUBLE);
	fprintf(stderr,"bptr	%d	%d\n",SZ_BPTR,AL_BPTR);
	fprintf(stderr,"wptr	%d	%d\n",SZ_WPTR,AL_WPTR);
	fprintf(stderr,"struct	%d	%d\n",SZ_STRUCT,AL_STRUCT);
	fprintf(stderr,"struct2	%d	%d\n",F_SENSITIVE,F_OPTIMIZED);
//	fprintf(stderr,"frame	%d	%d\n",SZ_FRAME,AL_FRAME);

	fprintf(stderr,"%d bits in a byte, %d bits in a word, %d bytes in a word\n",
			BI_IN_BYTE, BI_IN_WORD, SZ_WORD);
	return 1;
}
*/

int c_strlen(const char* s)
/*
	return sizeof(s) with escapes processed
	sizeof("") == 1		the terminating 0
	sizeof("a") == 2
	sizeof("\0x") == 3	0 x 0
	sizeof("\012") == 2	'\012'
	sizeof("\01")		'\001'
	sizeof("\x") == 2 	\ ignored

*/
{
	int i = 1;
        for (const char* p = s; *p; i++,p++) {
		if (*p == '\\')	{					// '\?
			switch (*++p) {
			case '0':
				switch (p[1]) {		// '\01' or '\012'
				case '0': case '1': case '2': case '3':
				case '4': case '5': case '6': case '7':
					break;
				default:
					continue;	// '\0'
				}
				/* no break */
			case '1': case '2': case '3':
			case '4': case '5': case '6': case '7':		// '\123'
				switch (*++p) {
				case '0': case '1': case '2': case '3':
				case '4': case '5': case '6': case '7':
					switch (*++p) {
					case '0': case '1': case '2': case '3':
					case '4': case '5': case '6': case '7':
						break;
					default:
						--p;
					}
					break;
				default:
					--p;
					break;
				}
				break;
			case '\n':			// \newline doesn't count
				i--;
				break;
			}
		}
	}
	return i;
}
0707071010112045661004440001630000160000010207700466055411000000700000020157size.h/*ident	"@(#)ctrans:src/size.h	1.2" */
/*************************************************************************

	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 rigths Reserved
	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC.

size.h:
	sizes and alignments used to calculate sizeofs

	table and butffer sizes

***************************************************************************/
#ifndef GRAM
extern BI_IN_WORD;
extern BI_IN_BYTE;
				/*	byte sizes */
extern SZ_CHAR;
extern AL_CHAR;

extern SZ_SHORT;
extern AL_SHORT;

extern SZ_INT;
extern AL_INT;

extern SZ_LONG;
extern AL_LONG;

extern SZ_FLOAT;
extern AL_FLOAT;

extern SZ_DOUBLE;
extern AL_DOUBLE;

extern SZ_LDOUBLE;
extern AL_LDOUBLE;

extern SZ_STRUCT;	/* minimum struct size */
extern AL_STRUCT;

//extern SZ_FRAME;
//extern AL_FRAME;

extern SZ_WORD;

extern SZ_WPTR;
extern AL_WPTR;

extern SZ_BPTR;
extern AL_BPTR;	

//extern SZ_TOP;
//extern SZ_BOTTOM;

extern char* LARGEST_INT;
extern int F_SENSITIVE;	// is field alignment sensitive to the type of the field?
extern int F_OPTIMIZED;	// can the compiler fit a small int field into a char?
#endif
				// default sizes:
	// Note: #if doesn't work on all systems
#ifdef u3b
#define Abbb
#endif
#ifdef u3b2
#define Abbb
#endif
#ifdef u3b5
#define Abbb
#endif
#ifdef u3b15
#define Abbb
#endif
#ifdef pyr
#define Abbb
#endif


#ifdef alliant
#define Am68
#endif
#ifdef apollo
#define Am68
#endif
#if defined(sun2) || defined(mc68010)
#define Am68
#endif
#if defined(sun3) || defined(mc68020)
#define Am68
#endif
#if defined(mc68k) || defined(hp9000s200) || defined(hp9000s300)
#define Am68
#endif

#ifdef iAPX286
#ifdef LARGE
#define Ai286l
#endif
#endif

#ifdef Abbb
				/* AT&T 3Bs */
#define DBI_IN_WORD 32
#define DBI_IN_BYTE 8
#define DSZ_CHAR 1
#define DAL_CHAR 1
#define DSZ_SHORT 2
#define DAL_SHORT 2
#define DSZ_INT 4
#define DAL_INT 4
#define DSZ_LONG 4
#define DAL_LONG 4
#define DSZ_FLOAT 4
#define DAL_FLOAT 4
#define DSZ_DOUBLE 8
#define DAL_DOUBLE 4
#define DSZ_LDOUBLE 8
#define DAL_LDOUBLE 4
#define DSZ_STRUCT 4
#define DAL_STRUCT 4
//#define DSZ_FRAME 4
//#define DAL_FRAME 4
#define DSZ_WORD 4
#define DSZ_WPTR 4
#define DAL_WPTR 4
#define DSZ_BPTR 4
#define DAL_BPTR 4
//#define DSZ_TOP 0
//#define DSZ_BOTTOM 0
#define DLARGEST_INT "2147483647"	/* 2**31 - 1 */
#define DF_SENSITIVE 0
#define DF_OPTIMIZED 1
#else
#ifdef Am68
				/* most M68K boxes */
#if defined(hp9000s200) || defined(hp9000s300)
#define DBI_IN_WORD 32 
#else
#define DBI_IN_WORD 16
#endif
#define DBI_IN_BYTE 8
#define DSZ_CHAR 1
#define DAL_CHAR 1
#define DSZ_SHORT 2
#define DAL_SHORT 2
#define DSZ_INT 4
#define DAL_INT 2
#define DSZ_LONG 4
#define DAL_LONG 2
#define DSZ_FLOAT 4
#define DAL_FLOAT 2
#define DSZ_DOUBLE 8
#define DAL_DOUBLE 2
#define DSZ_LDOUBLE 8
#define DAL_LDOUBLE 2
#define DSZ_STRUCT 2
#define DAL_STRUCT 2
//#define DSZ_FRAME 4
//#define DAL_FRAME 4
#define DSZ_WORD 2
#define DSZ_WPTR 4
#define DAL_WPTR 2
#define DSZ_BPTR 4
#define DAL_BPTR 2
//#define DSZ_TOP 0
//#define DSZ_BOTTOM 0
#define DLARGEST_INT "2147483647"	/* 2**31 - 1 */
#define DF_SENSITIVE 0
#define DF_OPTIMIZED 1
#else
#ifdef Ai286l
				/* Intel 80286 large model */
#define DBI_IN_WORD 16
#define DBI_IN_BYTE 8
#define DSZ_CHAR 1
#define DAL_CHAR 1
#define DSZ_SHORT 2
#define DAL_SHORT 2
#define DSZ_INT 2
#define DAL_INT 2
#define DSZ_LONG 4
#define DAL_LONG 2
#define DSZ_FLOAT 4
#define DAL_FLOAT 2
#define DSZ_DOUBLE 8
#define DAL_DOUBLE 2
#define DSZ_LDOUBLE 8
#define DAL_LDOUBLE 2
#define DSZ_STRUCT 2
#define DAL_STRUCT 2
//#define DSZ_FRAME 4
//#define DAL_FRAME 4
#define DSZ_WORD 2
#define DSZ_WPTR 4
#define DAL_WPTR 2
#define DSZ_BPTR 4
#define DAL_BPTR 2
//#define DSZ_TOP 0
//#define DSZ_BOTTOM 0
#define DLARGEST_INT "32767"	/* 2**15 - 1 */
#define DF_SENSITIVE 0
#define DF_OPTIMIZED 1
#else
#if defined(uts) || defined(hp9000s800) || defined(sun4) || defined(sparc)
				/* Amdahl running UTS, HP RISC */
#define DBI_IN_WORD 32
#define DBI_IN_BYTE 8
#define DSZ_CHAR 1
#define DAL_CHAR 1
#define DSZ_SHORT 2
#define DAL_SHORT 2
#define DSZ_INT 4
#define DAL_INT 4
#define DSZ_LONG 4
#define DAL_LONG 4
#define DSZ_FLOAT 4
#define DAL_FLOAT 4
#define DSZ_DOUBLE 8
#define DAL_DOUBLE 8
#define DSZ_LDOUBLE 8
#define DAL_LDOUBLE 8
#define DSZ_STRUCT 1
#define DAL_STRUCT 1
#define DSZ_WORD 4
#define DSZ_WPTR 4
#define DAL_WPTR 4
#define DSZ_BPTR 4
#define DAL_BPTR 4
#define DLARGEST_INT "2147483647"	/* 2**31 - 1 */
#if defined(uts)
#define DF_SENSITIVE 1
#else
#define DF_SENSITIVE 0
#endif
#define DF_OPTIMIZED 1
#else
#ifdef hpux 
                                /* hp */
#define DBI_IN_WORD 32
#define DBI_IN_BYTE 8
#define DSZ_CHAR 1
#define DAL_CHAR 1
#define DSZ_SHORT 2
#define DAL_SHORT 2
#define DSZ_INT 4
#define DAL_INT 4
#define DSZ_LONG 4
#define DAL_LONG 4
#define DSZ_FLOAT 4
#define DAL_FLOAT 4
#define DSZ_DOUBLE 8
#define DAL_DOUBLE 8 
#define DSZ_LDOUBLE 8
#define DAL_LDOUBLE 8
#define DSZ_STRUCT 1 
#define DAL_STRUCT 1 
#define DSZ_WORD 4
#define DSZ_WPTR 4
#define DAL_WPTR 4
#define DSZ_BPTR 4
#define DAL_BPTR 4
#define DLARGEST_INT "2147483647"       /* 2**31 - 1 */
#define DF_SENSITIVE 1 
#define DF_OPTIMIZED 1
#else
#if defined(vax) || defined(ibm032) || defined(i386)
				/* VAX, IBM 32, Intel 386 */
#define DBI_IN_WORD 32
#define DBI_IN_BYTE 8
#define DSZ_CHAR 1
#define DAL_CHAR 1
#define DSZ_SHORT 2
#define DAL_SHORT 2
#define DSZ_INT 4
#define DAL_INT 4
#define DSZ_LONG 4
#define DAL_LONG 4
#define DSZ_FLOAT 4
#define DAL_FLOAT 4
#define DSZ_DOUBLE 8
#define DAL_DOUBLE 4
#define DSZ_LDOUBLE 8
#define DAL_LDOUBLE 4
#define DSZ_STRUCT 1
#define DAL_STRUCT 1
//#define DSZ_FRAME 4
//#define DAL_FRAME 4
#define DSZ_WORD 4
#define DSZ_WPTR 4
#define DAL_WPTR 4
#define DSZ_BPTR 4
#define DAL_BPTR 4
//#define DSZ_TOP 0
//#define DSZ_BOTTOM 0
#define DLARGEST_INT "2147483647"	/* 2**31 - 1 */
#define DF_SENSITIVE 0
#define DF_OPTIMIZED 1
#else
#ifdef mc300
#define DBI_IN_WORD 32
#define DBI_IN_BYTE 8
#define DSZ_CHAR 1
#define DAL_CHAR 1
#define DSZ_SHORT 2
#define DAL_SHORT 2
#define DSZ_INT 4
#define DAL_INT 4
#define DSZ_LONG 4
#define DAL_LONG 4
#define DSZ_FLOAT 4
#define DAL_FLOAT 4
#define DSZ_DOUBLE 8
#define DAL_DOUBLE 4
#define DSZ_LDOUBLE 8
#define DAL_LDOUBLE 4
#define DSZ_STRUCT 2
#define DAL_STRUCT 2
//#define DSZ_FRAME 4
//#define DAL_FRAME 4
#define DSZ_WORD 4
#define DSZ_WPTR 4
#define DAL_WPTR 4
#define DSZ_BPTR 4
#define DAL_BPTR 4
//#define DSZ_TOP 0
//#define DSZ_BOTTOM 0
#define DLARGEST_INT "2147483647"       /* 2**31 - 1 */
#define DF_SENSITIVE 0
#define DF_OPTIMIZED 1
#else
#ifdef mips
#define DBI_IN_BYTE 8
#define DBI_IN_WORD 32
#define DSZ_WORD 4
#define DSZ_CHAR 1
#define DAL_CHAR 1
#define DSZ_SHORT 2
#define DAL_SHORT 2
#define DSZ_INT 4
#define DAL_INT 4
#define DLARGEST_INT "2147483647"
#define DSZ_LONG 4
#define DAL_LONG 4
#define DSZ_FLOAT 4
#define DAL_FLOAT 4
#define DSZ_DOUBLE 8
#define DAL_DOUBLE 8
#define DSZ_LDOUBLE 8 
#define DAL_LDOUBLE 8 
#define DSZ_BPTR 4
#define DAL_BPTR 4
#define DSZ_WPTR 4
#define DAL_WPTR 4
#define DSZ_STRUCT 1
#define DAL_STRUCT 1
#define DF_SENSITIVE 0
#define DF_OPTIMIZED 1
#else
				/* defaults: 0 => error */
#define DBI_IN_WORD 0
#define DBI_IN_BYTE 0
#define DSZ_CHAR 1
#define DAL_CHAR 1
#define DSZ_SHORT 0
#define DAL_SHORT 0
#define DSZ_INT 0
#define DAL_INT 0
#define DSZ_LONG 0
#define DAL_LONG 0
#define DSZ_FLOAT 0
#define DAL_FLOAT 0
#define DSZ_DOUBLE 0
#define DAL_DOUBLE 0
#define DSZ_LDOUBLE 0
#define DAL_LDOUBLE 0
#define DSZ_STRUCT 0
#define DAL_STRUCT 0
#define DSZ_WORD 0
#define DSZ_WPTR 0
#define DAL_WPTR 0
#define DSZ_BPTR 0
#define DAL_BPTR 0
#define DLARGEST_INT "0"
#define DF_SENSITIVE 0
#define DF_OPTIMIZED 0
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif

#define KTBLSIZE	123	/*	initial keyword table size */
#define GTBLSIZE	257	/*	initial global name table size */
#define CTBLSIZE	12	/*	initial class table size */
#define TBLSIZE		20	/*	initial block table size */
#define BLMAX		50	/*	max block nesting */
#define MAXFILE		127	/*	max include file nesting */
#define MAXERR		13	/* maximum number of errors before terminating */

#ifndef GRAM
const CHUNK = 8*1024;
void* chunk(int);
#endif
0707071010112045671004440001630000160000010210000466055411300001000000015476table.c/*ident	"@(#)ctrans:src/table.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.

table.c:

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

#include "cfront.h"
#include "size.h"

#ifdef DBG
extern long node_id;
#define DBCHECK() if(node::allocated) error('i',"allocated node (id %d, base%k) on free list! (src: \"%s\", %d",node::id,node::base,__FILE__,__LINE__);
#else
#define DBCHECK() /**/
#endif

table::table(short sz, Ptable nx, Pname n)
/*
	create a symbol table with "size" entries
	the scope of table is enclosed in the scope of "nx"

	both the vector of class name pointers and the hash table
	are initialized containing all zeroes
	
	to simplify hashed lookup entries[0] is never used
	so the size of "entries" must be "size+1" to hold "size" entries
*/
{
	DBCHECK();
	base = TABLE;
	t_name = n;
	size = sz = (sz<=0) ? 2 : sz+1;
//fprintf(stderr,"table::table %d %s %d (%d %d)\n", this, (n)?n->string:"?", sz,(sz*3)/2);
	entries = new Pname[sz];
	hashsize = sz = (sz*3)/2;
	hashtbl = new short[sz];
	next = nx;
	free_slot = 1;
	DBID();
}

table::~table()
{
	delete entries;
	delete hashtbl;
}

Pname table::look(char* s, TOK k)
/*
	look for "s" in table, ignore entries which are not of "k" type
	look and insert MUST be the same lookup algorithm
*/
{
	Ptable t;
	register char * p;
	register char * q;
	register int i;
	Pname n;
	int rr;

//	if (s == 0) error('i',"%d->look(0)",this);
//	if (this == 0) error('i',"0->look(%s)",s);
//	if (base != TABLE) error('i',"(%d,%d)->look(%s)",this,base,s);

	/* use simple hashing with linear search for overflow */

	p = s;
	i = 0;
	while (*p) i += (i + *p++); /* i<<1 ^ *p++ better?*/
	rr = (0<=i) ? i : -i;

	for (t=this; t; t=t->next) {	
		/* in this and all enclosing scopes look for name "s" */
		Pname* np = t->entries;
		int mx = t->hashsize;
		short* hash = t->hashtbl;
		int firsti = i = rr%mx;

		do {			
			if (hash[i] == 0) goto not_found;
			n = np[hash[i]];
			if (n == 0) error('i',"hashed lookup");
			p = n->string;		/* strcmp(n->n_string,s) */
			q = s;
			while (*p && *q)
				if (*p++ != *q++) goto nxt;
			if (*p == *q) goto found;
		nxt:
			if (mx <= ++i) i = 0;		/* wrap around */
		} while (i != firsti);

	found:
		for (; n; n=n->n_tbl_list){	/* for  all name "s"s look for a key match */
			if (n->n_key == k) return n;
		}

	not_found:;
	}

	return 0;	/* not found && no enclosing scope */
}

bit Nold;	/* non-zero if last insert() failed */

Pname table::insert(Pname nx, TOK k)
/*
	the lookup algorithm MUST be the same as look
	if nx is found return the older entry otherwise a copy of nx;
	Nold = (nx found) ? 1 : 0;
*/
{
	register char * p;
	register int i;
	Pname n;
	Pname* np = entries;
	Pname* link;
	int firsti;
	int mx = hashsize;
	short* hash = hashtbl;
	char* s = nx->string;

	if (s==0) error('i',"%p->insert(0,%k)",this,k);
	nx->n_key = k;
	if (nx->n_tbl_list || nx->n_table) error('i',"%n in two tables",nx);
	/* use simple hashing with linear search for overflow */

	p = s;
	i = 0;
	while (*p) i += (i + *p++);
	if (i<0) i = -i;
	firsti = i = i%mx;

	do {	/* look for name "s" */
		if (hash[i] == 0) {
			hash[i] = free_slot;
			goto add_np;
		}
		n = np[hash[i]];
		if (n == 0) error('i',"hashed lookup");
		if (strcmp(n->string,s) == 0) goto found;
/*
		p = n->string;
		q = s;
		while (*p && *q) if (*p++ != *q++) goto nxt;
		if (*p == *q) goto found;
	nxt:
*/
		if (mx <= ++i) i = 0;	/* wrap around */
	} while (i != firsti);

	error("N table full");

found:	


	for(;;) {
		if ( k!=NESTED && n->n_key==k) { Nold = 1; return n; }

		if (n->n_tbl_list)
			n = n->n_tbl_list;
		else {
			link = &(n->n_tbl_list);
			goto re_allocate;
		}
	}

add_np:
	if (size <= free_slot) {
		grow(2*size);
		return insert(nx,k);
	}

	link = &(np[free_slot++]);

re_allocate:
	{	
		Pname nw = new name;
		*nw = *nx;
		char* ps = new char[strlen(s)+1]; // copy string to safer store
		strcpy(ps,s);
//		Nstr++;
		nw->string = ps;
		nw->n_table = this;
		*link = nw;
		Nold = 0;
//		Nname++;
		return nw;
	}
}

void table::grow(int g)
{
	short* hash;
	register int j;
	int mx; 
	register Pname* np;
	Pname n;

	if (g <= free_slot) error('i',"table.grow(%d,%d)",g,free_slot);
	if (g <= size) return;
//error('d',"grow %d %s %d->%d", this, (t_name)?t_name->string:"?", size, g+1);
	size = mx = g+1;

	np = new Pname[mx];
	for (j=0; j<free_slot; j++) np[j] = entries[j];
	delete entries;
	entries = np;

	delete hashtbl;
	hashsize = mx = (g*3)/2;
	hash = hashtbl = new short[mx];

	for (j=1; j<free_slot; j++) {	/* rehash(np[j]); */
		char * s = np[j]->string;
		register char * p;
		char * q;
		register int i;
		int firsti;

		p = s;
		i = 0;
		while (*p) i += (i + *p++);
		if (i<0) i = -i;
		firsti = i = i%mx;

		do {	/* look for name "s" */
			if (hash[i] == 0) {
				hash[i] = j;
				goto add_np;
			}
			n = np[hash[i]];
			if (n == 0) error('i',"hashed lookup");
			p = n->string;	/* strcmp(n->n_string,s) */
			q = s;
			while (*p && *q) if (*p++ != *q++) goto nxt;
			if (*p == *q) goto found;
		nxt:
			if (mx <= ++i) i = 0;	/* wrap around */
		} while (i != firsti);

		error('i',"rehash??");

	found:
		error('i',"rehash failed");

	add_np:;
	}
}

Pname table::get_mem(int i)
/*
	return a pointer to the i'th entry, or 0 if it does not exist
*/
{
	return (i<=0 || free_slot<=i) ? 0 : entries[i];
}

void table_delete(char* s, TOK k, int ll )
/*
	deletes local class entry from keyword table
	adjusts pointers if multiple entries
	uses same lookup as table::look and table::insert
*/
{
	Ptable t = ktbl;
	register char * p;
	register char * q;
	register int i;
	Pname n;
	int rr;

	p = s;
	i = 0;
	while (*p) i += (i + *p++); /* i<<1 ^ *p++ better?*/
	rr = (0<=i) ? i : -i;

// error ('d', "table_delete: %s ll: %d", s, ll );

		Pname* np = t->entries;
		int mx = t->hashsize;
		short* hash = t->hashtbl;
		int firsti = i = rr%mx;

		do {			
			if (hash[i] == 0) error('i',"table delete: not found: %s", s );
			n = np[hash[i]];
			if (n == 0) error('i',"table delete: hashed lookup");
			p = n->string;		/* strcmp(n->n_string,s) */
			q = s;
// error( 'd', "table_delete: %s", p );
			while (*p && *q)
				if (*p++ != *q++) goto nxt;
			if (*p == *q) goto found;
		nxt:
			if (mx <= ++i) i = 0;		/* wrap around */
		} while (i != firsti);

	found:
		for (Pname prev = n; n; prev = n, n=n->n_tbl_list){	
// error( 'd', "table_delete: found: %s %k lex: %d", n->string, n->n_key, n->lex_level );
			if (n->n_key == k && n->lex_level == ll ) {
// error( 'd', "table_delete: prev: %d n: %d n->tbl_list: %d", prev, n, n->n_tbl_list);
				if ( prev == n && n->n_tbl_list == 0 )
					hash[i] = 0;
				else
					prev->n_tbl_list = n->n_tbl_list;
				return;
		 	}
		}
}
0707071010112046031004440001630000160000010211300466055416400001300000206556template.c/* ident "@(#)ctrans:src/template.c	1.3" */
/*******************************************************************
* template.c
*
* This file contains most of the implementation for a subset of 
* parametrized types as defined by the 1989 Stroustrup JOOP paper.  
* The subset chosen here  was the subset relevant to the 
* implementation of aggregates in ObjectStore.
* 
* The following is a list of features supported by the 
* implementation. The list of features parallels the 
* description of templates in the JOOP paper. 
* 	
*	a) Class templates supported.
* 				
* 	b) Member function templates supported.  
*	Type-specific member functions as described at the 
*	end of the "Outline of an implementation" section 
*	are also supported. 
*
*	Non-member function templates are not supported.
* 						
* 	c) Template arguments may be of type "type" or 
*	simple integral, real, double and pointer types 
*	that are compile-time constants.
*
* 	Default arguments are not suported.
*
* 
* Restrictions:
* 	
* 	a) template definitions may not be nested.
* 						
* 	b) enums, or class definitions may not be 
*	nested within a template class definition.
* 	   					
* This file also supports an internal template facility 
* to facilitate the implementation of ObjectStore data 
* model features. The internal template facility is 
* only used by compiler implementors, and is not user visible.
* 							
************************************************************/


/***********************************************************
* 	
* TBD
* 
* 1) Error recovery, a never ending task, could stand improvement.
* 
* 2) The template copying process could probably be speeded up
* substantially, by only placing "graph-like" nodes in the hash 
* table. The current implementation plays it safe, and places 
* all nodes in the hash table.
* 			
* 3) Clean up $name processing, it needs to be remodularized 
* so that class templates and tree templates share the code.
* 							
* 4) Permit parametrized name default names within member 
* functions. 
*
****************************************************************/

#include "tree_copy.h"
#include "cfront.h"
#include <string.h>
#include "tree_dump.h"
#include "template.h"
#include <stdlib.h>
#include <ctype.h>
#include "hash.h"

extern int bound ; // is not mentioned in the header file

const int max_string_size = 1024 ;

const int default_copy_hash_size = 1000 ;

// Save and restore global state around a template instantiation
void state::save() {
  
  Cdcl = ::Cdcl ;
  Cstmt = ::Cstmt ;
  curloc   = ::curloc ;

  curr_file = ::curr_file ;
  curr_expr = ::curr_expr ;
  curr_icall = ::curr_icall ;
  curr_loop = ::curr_loop;
  curr_block = ::curr_block;
  curr_switch = ::curr_switch;

  bound    =  ::bound  ;   
  inline_restr = ::inline_restr ;
  last_line = ::last_line ;

  no_of_badcall = ::no_of_badcall;
  no_of_undcl = ::no_of_undcl ;
  
  badcall = ::badcall ;
  undcl = ::undcl ;
} ;


void state::restore() {
  ::Cdcl = Cdcl ;
  ::Cstmt = Cstmt ;
  ::curloc  = curloc ;

  ::curr_file = curr_file ;
  ::curr_expr = curr_expr ;
  ::curr_icall = curr_icall ;
  ::curr_loop = curr_loop;
  ::curr_block = curr_block;
  ::curr_switch = curr_switch;

  ::bound    =  bound  ;   
  ::inline_restr = inline_restr ;
  ::last_line = last_line ;

  ::no_of_badcall = no_of_badcall;
  ::no_of_undcl = no_of_undcl ;
  
  ::badcall = badcall ;
  ::undcl = undcl ;
} ;


void state::init()  {
  ::bound = 0 ;
  ::inline_restr = 0 ;
  ::no_of_badcall = ::no_of_undcl = 0 ;
  ::undcl = ::badcall = NULL ;
  // lastline  needs to be initialized probaly via a call to putline
  
}


bit basetype::parametrized_class()
{ return ((base == COBJ) && 
	  Ptclass(Pbase(this)->b_name->tp)->class_base == uninstantiated_template_class) ;
}

class_type_enum get_class_base (Pbase b) {
  if (b->base != COBJ) error('i', "badA top ::get_class_type") ;
  return Ptclass(Pbase(b)->b_name->tp)->class_base ;
}

Ptclass get_template_class (Pbase b) {
  class_type_enum t = get_class_base(b) ;

  if (! ((t == instantiated_template_class) ||
	 (t == uninstantiated_template_class)))
    error ('i', "C is not aYC") ;
  
  return Ptclass(Pbase(b)->b_name->tp) ;
}


Ptempl_inst get_templ_inst(Pbase b) {

  return (get_template_class(b))->inst ;
}

  
bit classdef::parametrized_class()
{ return (class_base == uninstantiated_template_class) ;
}

// Predicate to determine whether two classes are indeed the same. cfront
// normally relies on pointer identity, however this test is insufficient when
// parametrized class instantiationa are involved, since there are potentially
// many instances of a COBJ and CLASS for a given instantiation.
bit classdef::same_class(Pclass pc)
{
  if (this == pc) return true ;

  // An intermediate test to compensate for the fact that instantiations do
  // not cause a copy of the syntax tree to be generated. This kludge should
  // not be necessary once the template implementation is complete, and tree
  // copying is implemented.
  // Later, Sam: tree copying is now implemented, i need to remove the
  // following two statements and rerun the test suite.

  if ((this->class_base == template_class) &&
      (pc->class_base == instantiated_template_class) &&
      (Ptclass(pc)->inst->def_basetype()->b_name->tp == this))
    return true ;
  // The inverse symmetric test
  if ((pc->class_base == template_class) &&
      (this->class_base == instantiated_template_class) &&
      (Ptclass(this)->inst->def_basetype()->b_name->tp == pc))
    return true ;

  // Check whether the templates were determined to be identical after
  // instantiation. 
  if ((pc->class_base == instantiated_template_class) &&
      (this->class_base == instantiated_template_class) &&
      (Ptclass(this)->inst->same(Ptclass(pc)->inst)))
    return true ;
  return false ;
}

// determine whether two instantiations are identical; the test asumes that 
// the templates have been instantiated.
bool templ_inst::same(Ptempl_inst t)
{
  return ((forward && (forward == t->forward)) ||
	  (forward == t) || (t->forward == this)) ? true : false ;
}


                      /* Template parsing support */

// The canonical template compilation instance. 

templ_compilation *templp ;

templ_compilation::templ_compilation()
{ templates = new table(128, NULL, NULL) ;
  any_type =  new basetype(ANY, NULL);
  PERM(any_type) ;
}


// determine whether the string corresponds to a tree formal parameter
Pname templ_compilation::tree_parameter(char *s) {
  for (Plist formal = params ; formal ; formal = formal->l)
    if (strcmp(formal->f->string, s) == 0) {
      formal->f->n_used++ ;
      return formal->f ;
    }
  return 0 ;
}  
  
				       
// Determine whether the name refers to the canonical template class during
// syntax analysis.
Ptempl templ_compilation::is_template(Pname p) {
  if (p->tp && (p->tp->base == COBJ) &&
      (get_class_base(Pbase(p->tp)) == template_class))
    { Pname n = templates->look(p->string, 0) ;
      return (n ? Ptempl(n->tp) : 0) ;
    }
  return 0 ;
}


// determine whether the string names a template
Ptempl templ_compilation::is_template(char *s) {
  Pname n = templates->look(s,0) ;
  return (n ? Ptempl(n->tp) : 0) ;
}

  
// Set up the environment for parsing a template. This involves setting up a
// new nesting level into which the "type type" parameters of the template can
// be entered, so that the lexer can find them as TNAMES. The scope is
// deallocated by end().
void templ_compilation::start() 
{ templp->in_progress = true ;
  // Reinitialize the state.
  params = param_end = NULL ; owner = NULL ;
  modified_tn = 0 ;  // Initialize it here, since ::collect adds new types
}


  
// Collect each parameter as it is parsed, and add it to the list of parms.
// Validate each parameter to make sure that it is one of the acceptable
// types. 
void templ_compilation::collect(TOK parm_type, Pname n)
{
  switch (parm_type) {
  case CLASS:
    // A "type type" parameter, give it the "ANY" type normally used as a
    // wildcard match internally by the compiler in cases of error.
    n->tp =  new basetype(ANY, 0);
    n =  n->tdef() ;           // Set it up to be a typedef.
    n->lex_level = bl_level + 1 ; // Inner scope, so restore() can hack it
    n->n_template_arg = template_type_formal ;
    PERM(n) ; PERM(n->tp) ;
    break ;
  case STATEMENT:
  case EXPRESSION:
    // the argument is a post-syntax expression tree
    n->n_template_arg =
      ((parm_type == EXPRESSION) ? 
       template_expr_tree_formal : template_stmt_tree_formal) ;
    // canonical any_type is ok here
    n->tp = any_type ;
    PERM(n) ;
    break ;
  default:
    error("theZT for%n must be CLASS, not %k", n,parm_type);
  }
  append_parameter(n) ;
}

// append the "non-type" parameter to the end of the list
void templ_compilation::append_parameter(Pname n)
{
  if (params){
    param_end->l = new name_list(n, NULL) ;
    param_end = param_end->l ;
  }else params = param_end = new name_list(n, NULL) ;
  PERM(n) ; PERM(n->tp) ;
}


// collect non "type type" parameters. The tp field of the name
// indicates the type of the formal parameter. 
void templ_compilation::collect(Pname n) 
{
  // The grammar alone should be sufficient to protect against undesirable
  // types. Any additional checks go here.
  n->n_template_arg = template_expr_formal ;
  append_parameter(n) ;
}
  


// validate the type for a non-type formal, and make it a const.
static void check_non_type_formal(Pname n) {

  switch (n->tp->base) {
  case ZTYPE:
  case CHAR:
  case SHORT:
  case INT:
  case LONG:
  case FLOAT:
  case DOUBLE:
  case FIELD:
  case EOBJ:
  case COBJ:
  case TYPE:
  case ANY:
    { // a basetype node
      TOK bad_base = 0 ;
      
      if (Pbase(n->tp)->b_volatile)
	bad_base = VOLATILE ;
      if (Pbase(n->tp)->b_typedef)
	bad_base = TYPEDEF ;
      if (Pbase(n->tp)->b_inline)
	bad_base = INLINE ;
      if (Pbase(n->tp)->b_virtual)
	bad_base = VIRTUAL ;
      if (bad_base)
	error ("bad %k declarator forY formal %n", bad_base,n);
      
      Pbase b = new basetype(0, 0) ;
      *b= *Pbase(n->tp) ;
      b->b_const = 1 ;
      n->tp = b ;
      break  ;
    }
  case PTR:
    { Pptr b = new ptr(0,0) ;
      *b = *Pptr(n->tp) ;
      
      b->rdo = 1;
      n->tp = b ;
      break ;
    }
  case RPTR:
  case VEC:
    break;		// constant by definition
  default:
    error ("badZT %t for formalZ %n", n->tp, n);
  }
  return ;
}
		


// The template parameters if any, have been parsed. Member function templates
// may choose to default their template arguments to the class arguments, if
// so, make the defaulting happen.
void templ_compilation::enter_parameters()
{
  for (Plist list = params ; list ; list = list->l) {
    Pname n = list->f ;
    switch(n->n_template_arg) {
    case template_type_formal:
      // Set them up for restoration
      modified_tn = new name_list(n,modified_tn);
      // Bring the names out of hiding
      n->n_key = 0 ;
      break ;
    case template_expr_formal:
      check_non_type_formal(n) ;
      n->tp->dcl(gtbl) ;
      break ;
    case template_expr_tree_formal:
    case template_stmt_tree_formal:
      // simply note it, the guts of the processing takes place when the
      // copy of the syntax tree is generated.
      break ;
    default:
      error ('i', "badY formal" ) ;
    }
  }
  // Save away the list of modified_tn, since the body processing will clobber
  // it.
  param_tn = modified_tn ;
  modified_tn = 0 ;
}



// Resolve the forward declaration of a template to its true definition. The
// template and class type data structures must be reused, since there may be
// outstanding references to them.
void templ::resolve_forward_decl(Plist params, Pclass c) {
  check_formals(params) ; 
  formals = params ;
  defined = true ;
  definition_number = ++ definition_tick ;
  members = c->mem_list ;
}

void templ::instantiate_forward_decl() {
  for (Ptempl_inst i = insts ; i ; i = i->next)
    if (Ptclass(Pbase(i->tname->tp)->b_name->tp)->class_base ==
	instantiated_template_class &&
	! i->forward)
      { // reinstantiate it
	i->instantiate(true) ;
      }
}

  

// verify thet the qualifier used to declare the member function matches the
// template arguments in name, ie.
// template <class P, class Q, ..> c<P,Q,..>::member_function() {}
// match it's Ps and Qs.
bool templ_inst::check_qualifier(Plist formals)
{
  Pexpr actual = actuals ;
  for (Plist formal = formals ; formal && actual ; formal = formal->l,
       actual = actual->e2)
    
    switch (formal->f->n_template_arg) {
      
    case template_type_formal:
      { Pbase b = Pbase(actual->e1->tp) ;
	
	if (! ((b->base == TYPE) &&
	       (b->b_name->base == TNAME) &&
	       (strcmp (Pname(b->b_name)->string, formal->f->string) == 0)))
	  return false ;
	break ;
      }
      
    case template_expr_formal:
      if (! ((actual->e1->base == NAME) &&
	     (strcmp(Pname(actual->e1)->string, formal->f->string) == 0)))
	return false ;
      break ;
      
    case template_expr_tree_formal:
    case template_stmt_tree_formal:
    default:
      error ('i',"badY formal") ;
    }

  return true ;
}


// make the class template visible when compiling the template class
// defintion, so that it can be refernced while compiling the class body.
void templ_compilation::introduce_class_templ(Pname namep)
{
  owner = is_template(namep) ;
  // create a template definition if one did not already exist, due to a
  // forward declaration
  if (!owner){
    owner = new templ(params, namep) ;
    Pname lookup_name = templp->templates->insert(new name(namep->string), 0);
    lookup_name->tp = Ptype(owner) ;  // lie, to permit use of the table
  }
}
			    
			    
// The body of the template has been parsed. Finish the definition of the
// template class. 
void templ_compilation::end(Pname p) 
{
  bool forward_definition = false ;
  // Restore the name environment to the state before the template parameters
  // were processed.
  modified_tn = param_tn ;
  restore() ;
  modified_tn = 0 ;

  if (curr_tree_template) {
    // create an expression template
    new tree_template(curr_tree_template,
		      p->string, params, p->n_initializer, templ_refs) ;
  }else {
    if (!p->tp) {
      error ("aC, orMF definition wasX") ;
      return ;
    }
    switch(p->tp->base){
      
    case CLASS:
      // Create the template type to represent the parsed template, and enter it
      // into the global table. This is achieved simply by modifying the TNAME
      // that was entered into ktbl to represent the class definition.
      Pname namep = ktbl->look(p->string, 0) ;

      // check for nested definitions, they aren't supported currently. 2.1 is
      // a good time to start supporting them, since they are nested for real.
      for (Pname nn = Pclass(p->tp)->mem_list ; nn ; nn = nn->n_list)
	switch (nn->base) {
	case NAME:
	  switch(nn->tp->base) {
	  case CLASS:
	    error("CD %s not permitted within a ZizedC", nn->string) ;
	      break ;
	    case ENUM:
	      error("enumD %s not permitted within a ZizedC", nn->string) ;
	      break ;
	  }
	  break ;
	  
	case TNAME:
	  error("typedef %s not permitted within a ZizedC", nn->string) ;
	  break ;
	}

      owner = is_template(namep);
      if (owner) {
	Pclass c = Pclass(owner->basetype()->b_name->tp) ;
	// ignore it, if it is a forward declaration following a real
	// definition
	if (owner->defined && (Pclass(p->tp)->mem_list != owner->members))
	  error("YC %s multiply defined", p->string) ;

	forward_definition=bool((c->defined & DEF_SEEN) && (!owner->defined));
	if (forward_definition) owner->resolve_forward_decl(params, c) ;
      }else 
	// a forward declaration
	introduce_class_templ(namep) ;

      if (templ_refs) owner->templ_refs = templ_refs ;
      break ;
    
    case FCT:
      { Pname qual = p->n_qualifier ;
	// the function must belong to a declared template class
	if (! qual) {
	  error('s', "onlyYMFs may beZized currently") ;
	  return ;
	}
	if (qual->tp && (qual->tp->base == COBJ))
	  switch (get_class_base(Pbase(qual->tp))) {
	  case uninstantiated_template_class:
	    owner = Ptclass(Pbase(qual->tp)->b_name->tp)->inst->def ;
	    // verify that the formals specified, match the template formals
	    // in name, note that the length was already matched when the
	    // instantiation was generated.
	    if (!get_template_class
		(Pbase(qual->tp))->inst->check_qualifier(params))
	      error ("QrZs must match theY formals") ;
	    break ;
	  case template_class:
	    // the template reference was without any of the formals
	    owner = is_template(qual) ;
	    if (! owner->has_tree_expr_formals())
	      error('w',"Qr %n for %n must specifyYZs", qual, p) ;
	    break ;
	  default:
	    error ("Qr %n for %n wasn't aYC", qual, p) ;
	    return ;
	  }
	Pfunt ft= owner->collect_function_member(p) ;
	if (! Pfct(p->tp)->body)
	  error ("theYFM %n must have a body", p) ;
	ft->templ_refs = templ_refs ;
	ft->formals = params ;
	owner->check_formals(params) ;
	break ;
      }
    default: error ("C, or MF definitionX.") ;
    }
  }
  // Note the template references from this definition

  clear_ref_templ() ;
  param_end = params = 0;  // Indicates the end of template processing.
  curr_tree_template = 0 ;

  if (forward_definition) owner->instantiate_forward_decl() ;
  owner = 0 ;
}


				     

// Clear the list of templates referenced during the syntax analysis of a top
// level definition. Note that since this list is produced during syntax
// analysis, it does not recognize instantiations that may actualy turn out to
// be identical at instantiation after the substitution of actual parameters.
// Thus, the list may be longer than it would be after actual argument
// substitution. 
void templ_compilation::clear_ref_templ() {
  for (Pcons p = templ_refs ; p ; p = p->cdr)
    Ptempl_inst(p->car)->refp = false ;
  templ_refs = 0 ; last_cons = 0 ;
}


// Instantiate templates that were referenced by a non-template definition,
// after syntax analysis has been completed on it.
void templ_compilation::instantiate_ref_templ() {
  for (Pcons p = templ_refs ; p ; p = p->cdr)
    Ptempl_inst(p->car)->instantiate() ;
  clear_ref_templ() ;
}




// Compile all template member body instantiations. Set in motion the
// compilation of the graph of instantiation bodies. Note that compilation of
// a body may in turn initiate the instantiation of templates that had not
// previously been instantiated.
void templ_compilation::end_of_compilation() {
  bool change = false ;
  do {
    change = false ;
    for (Ptempl p = list ; p ; p = p->next)
      change = ( change | p->instantiate_bodies() ? true : false);
  } while (change) ;
}


// A predicate to validate that a tname without template parameters is legit
// in the scope, ie. that it does not need actual template arguments.
// Currently, a tname without parameters is ok within the class definition,
// but parameters are required within the member definition. They should not
// be required within the member function either to be consonance with their
// use in the class definition.
Pname templ_compilation::check_tname(Pname p) {
  Ptempl t = is_template(p) ;

  if (p->n_template_arg) p->n_used++ ;
  if (!t) return p ;
  if (in_progress && ((owner && (owner->namep == p)) ||
		      (!owner && t->basetype()->b_name->tp == ccl)))
     return p ;
  error ("%n needs Y instantiationAs.", p) ;
  return p ;
}


// This function determine when the parameters specified to a template are
// redundant, and really refer to the current template class. Thus,
//
// template c<class p1, class p2> c<p1,p2>::foo { ... } ;
// has the redundant template specification c<p1, p2> and can simply be a
// reference to a "c" instead, 
bool templ_compilation::current_template(Pname p, Pexpr actuals) {
  if (in_progress &&
      ((owner  && (owner->namep == p)) ||
       (!owner && ((p->tp->base == COBJ) &&
		   (Pbase(p->tp)->b_name->tp == ccl)))))
    { // Check whether the formal and actual types are identical
      Pexpr actual = actuals;
      for (Plist formal = params ; formal && actual ; formal = formal->l,
	   actual = actual->e2)
	if ((formal->f->tp == actual->e1->tp) || 
	    ((actual->e1->tp && (actual->e1->tp->base == TYPE)) &&
	     (Pbase(actual->e1->tp)->b_name->tp == formal->f->tp)))
	  continue ;
	else break ;
      if (!formal && !actual) return true ;
    }
  return false ;
}
  
  
	
// Add a new member function to the list of functions for the template class.
Pfunt templ::collect_function_member(Pname fname) {
  PERM(fname) ; PERM(fname->tp) ; PERM(Pfct(fname->tp)->body) ;
  return new function_template (*this, templp->params, fname) ;
}


// Check the formals specified for a member function or a forward definition
// of a class, against the formals for the class.
void basic_template::check_formals(Plist f2) {
  
  for (Plist f1 = formals; f1 && f2 ; f1 = f1->l, f2 = f2->l)
    if (f1->f->base != f2->f->base) 
      switch (f1->f->n_template_arg) {
      case template_type_formal:
	error ("Y formalZ mismatch,\
%n must be a type formal parameter.", f2->f) ;
	break ;
      case template_expr_formal:
	error ("formalZ mismatch, %n must be aZ ofT %t",
	       f2->f, f2->f->tp) ;
	break ;
      case template_expr_tree_formal:	
      case template_stmt_tree_formal:
	error ("formalZ mismatch, %n must be anE formalZ",
	       f2->f) ;
	break ;
      default:
	error ("formalZ mismatch betweenC formal: %n andM formal: %n", f1->f, f2->f) ;
      }else if (f1->f->n_template_arg == template_expr_formal) {
	// the types should be identical
	if (f1->f->tp->check(f2->f->tp, 0) == 1)
	  error ("type mismatch betweenM formal %n, andC formal %n", f2->f, f1->f) ;
      }
  if (f1)
    error ("insufficient formalZs,CZ parameter %n onwards are missing", f1->f) ;
  if (f2)
    error ("excess formalZs,Z %n onwards not defined forC", f2->f) ;
  
}

// predicate to determine whether the template has expression tree formals
bool templ::has_tree_expr_formals() {
  
  for (Plist formal= formals; formal ; formal = formal->l)
    if (formal->f->n_template_arg == template_expr_tree_formal)
      return true ;

  return false ;
}


// Check that those formals that require class actual arguments, due to their
// use in member function bodies get them.
bool basic_template::check_constraints(Pexpr actual)

{
  bool ret = true ;
  
  for (Plist formal = formals ; formal && actual ; formal = formal->l,
       actual = actual->e2)
    if ((formal->f->n_template_arg == template_type_formal) &&
	formal->f->n_template_formal_must_be_class) {

	  Pname n = Pname(actual->e1) ;

	  if (n && n->tp && n->tp->is_cl_obj())
	    continue ;
	  error("expected aCT actual, not %t, for the \"TT\" formal %s",
		n->tp, formal->f->string);
	  ret = false ;
	}
  return ret ;
}


// Check actual template arguments, against the formals.
bool templ::check_actual_args(Pexpr actual)
{
  for (Plist formal = formals ; formal && actual ; formal = formal->l,
       actual = actual->e2)
    switch (formal->f->n_template_arg) {
    case template_type_formal:
      {
	// A "type type" parameter, any actual type that was accepted by the
	// parse is acceptable here, just make sure that it is indeed a type.
	// If it was parsed as a type, the grammar should have created a name
	// node, and attached the type to it, having marked the name as a
	// template_actual_arg_dummy.

	Pname n = Pname(actual->e1) ;
	
	if (!((n->base == NAME) &&
	    (n->n_template_arg == template_actual_arg_dummy))) {
	  error ("Y %s A mismatch, the Y formal:%n\
 required aT actualZ.", namep->string, formal->f) ;
	  // recover from the error with a safe expression
	  n = new name("") ;
	  n->tp = any_type ;
	  actual->e1 = n ;
	}
	if ((formal->f->n_template_formal_must_be_class) &&
	    !(n->tp && n->tp->is_cl_obj()))
	  error("expected aCT actual, not %t, for the \"TT\" formal %s",
		n->tp, formal->f->string) ;
	break ;
      }
    case template_expr_formal:
      // checking can only be done at instantiation, so postpone it 
      break ;
    case template_expr_tree_formal:
    case template_stmt_tree_formal:
      // anything is acceptable, it is a case of "implementor beware". Any
      // illegalities will only be detected when dcl processing takes place.
      break ;
    default:
      error ('i',"badY formal") ;
    }
  // If we provide for optionals, this is where the processing should get done.
  if (formal)
    error ("too fewAs supplied forY %s", namep->string) ;
  if (actual && actual->e1) {
    error ("too manyAs supplied forY %s", namep->string) ;
  }
  return bool(~(formal || actual)) ;
}




// Append to the list of references.
void templ_compilation::append_ref(Ptempl_inst ref) 
{ cons *p = new cons(ref,0) ;
  if (last_cons)
    last_cons->cdr = p ;
  else templ_refs =  p ;
  last_cons = p ;
} ;


// Note the reference by a definition to the template, so that the template
// can be instantiated before the definition is processed. 
Ptempl_inst templ_inst::note_ref() 
{  if ((! refp)) {
    refp = true ;
    templp->append_ref(this) ;
  }
  return this ;
}
  
	    
	    
// Get an instantiation for the template with the given set of actuals. If one
// exists, return it, otherwise create a new one. 
Ptempl_inst templ::get_inst(Pexpr actuals, Ptempl_inst exclude)
{ Ptempl_inst inst = get_match(actuals, exclude, false) ;
  
  return (inst ? inst : new templ_inst(actuals, this))->note_ref() ;
}


// Find an instantiation that has the same set of actuals, exclude the
// instantaition passed in from the set of candidates
Ptempl_inst templ::get_match(Pexpr actuals,       
			     Ptempl_inst exclude,  // don't match this one
			     // Only instantiated templates match
			     bool match_instantiated_only)    
{  
  for (Ptempl_inst p = insts ; p ; p = p->next)
    if ((p != exclude) &&
	(p->actuals_match(actuals)) &&
	(match_instantiated_only ?
	 (Pclass(Pbase(p->tname->tp)->b_name->tp)->class_base ==
	  instantiated_template_class)
	 : true))
      return (p->forward ? p->forward : p) ;
  return NULL ;
}


// provides the basetype created for a given set of actuals.
Pbase templ::inst_basetype(Pexpr actuals)
{
  return (check_actual_args(actuals) ?
	  Pbase(get_inst(actuals)->tname->tp) : basep) ;
}


// Validate that the name denotes a parametrized type, and prodouce a TNAME
// for the instantiation.
Pname parametrized_typename (Pname p, Pexpr actuals) 
{ 
  Ptempl t = templp->is_template(p) ;
  // A template instantiation with redundant actuals identical to the formals
  // of the current template
  if (templp->current_template(p, actuals)) return p ;
  if (t) {
    Pname tname = t->typename(actuals)  ;
    return (tname ? tname : p) ;
  }
  error ("%n hasTAs but is not aZizedC", p) ;
  return p ;
}


Pbase parametrized_basetype (Pname p, Pexpr actuals) 
{ Ptempl t = templp->is_template(p) ;
  // A template instantiation with redundant actuals identical to the formals
  // of the current template 
  if (templp->current_template(p, actuals)) return Pbase(p->tp) ;
  if (t) return t->inst_basetype(actuals) ;
  error ("%n is not aZizedC", p) ;
  return new basetype(TYPE, p);
}


// Similar primitive for obtaining the typename associated with an
// instantiation. 
Pname templ::typename(Pexpr actuals) 
{
  return (check_actual_args(actuals) ? get_inst(actuals)->tname : 0) ;
}

// predicate to get past all the type nodes
static Ptype real_type (Ptype t)
{
  while (t->base == TYPE) t = Pbase(t)->b_name->tp ;
  return t ;
}

static int expr_match(Pexpr a1, Pexpr a2) ;

// Check whether the actuals provided match the actuals for this instantiation.
// The actuals match the formals, iff they are the same type or parametrized
// type. 
bool templ_inst::actuals_match(Pexpr check_actuals)
{ Pexpr ae1, ae2 ;     // the cons cells
  Plist formal = def->formals ;
  
  // The lists should be the same length, since check_actuals will have taken
  // appropriate action.
  for (ae1=actuals, ae2=check_actuals ; formal && ae1 && ae2 ;
       ae1=ae1->e2, ae2=ae2->e2, formal = formal->l)

    switch (formal->f->n_template_arg) {
    
    case template_type_formal:
      { Ptype t1 = ae1->e1->tp, t2 = ae2->e1->tp ;
	if (t1->check(t2,255) == 1)
	  return false ;
	break ;
      }
    case template_expr_formal:
      if (! expr_match(ae1->e1, ae2->e1)) return false ;
      break ;
      
    case template_expr_tree_formal:
    case template_stmt_tree_formal:
      // these are internal instantiations and consequently never match
      return false ;
      
    default:
      error ('i', "bad template formal") ;
    }
  return true ;
}


extern char emode ;


// This set of overloaded fuctions are used to accumulate name strings 
void stradd(char *&target, char *source) {
  while (*target++ = *source++) ;
  target-- ;
}
	
void stradd(char *&p, long i) {
  if (!emode) {
    *p++ = 'L' ;
  }
  char s[16] ;
  
  sprintf(s,"%ld", i) ;
  stradd(p,s) ;
}

void stradd(char *&p, Pname n) {
  if (!emode){
    char s[256] ;
    
    sprintf(s,"%d", strlen(n->string)) ;
    stradd(p,s) ;
  }
  stradd(p, n->string) ;
}

    

// produce a unique string suitable for use within a name; if in emode ie.
// printing in the context of an error, print a pretty name instead.  
char * mangled_expr(char *p, Pexpr e, bool mangle_for_address = false)
{
  static int mangle_address = 0 ;
  if (e == 0) return p;

  switch (e->base) {
  case ADDROF:
  case G_ADDROF:
    // unary using e2
    // rely on the
    mangle_address++ ;
    p = mangled_expr(p, e->e2) ;
    mangle_address -- ;
    break ;
    
  case NAME:
    if (mangle_address || mangle_for_address)
      stradd(p, Pname(e)) ;
    else if (Pname(e)->n_evaluated)
      stradd(p, Pname(e)->n_val) ;
    else if (Pname(e)->n_initializer)
      p = mangled_expr(p, Pname(e)->n_initializer, mangle_for_address) ;
    else error ('i', "couldn't mangle %n", e) ;
    break ;
      
  case IVAL:
    stradd(p, ((ival *)e)->i1) ;
    break ;

  case CAST:
    { // an IVAL hiding below the cast ?
      if (e->e1->base == IVAL) 
	stradd(p, ((ival *)e->e1)->i1) ;
      else error ('i', "unexpected cast") ;
      break ;
    }
  case ICON:
  case CCON:
  case FCON:
    *p++ = 'L' ;
    strcpy(p, e->string) ;
    // Sam: there needs to be a better encoding scheme, but it can wait.
    if (!emode)
      while (*p)
      if (! (isalnum(*p)))
	switch(*p) {
	case '+':
	  *p++ = 'p' ;
	  break ;
	  
	case '-':
	  *p++ = 'm' ;
	  break ;

	case '.':
	  *p++ = 'D' ;
	  break ;

	case 'e':
	  *p++ = 'E' ;
	  break ;
	
	default:
	  error ('i', "bad character in constant") ;
	  break ;
	} else p++ ;
    break ;
    
  case ZERO:
    *p++ = '0' ;
    break ;
    
  default:
    error ('i', "can't mangle %k", e->base) ;
  }
  return p ;
}

// this function is invoked once at the top level
char *mangled_expr(char *p, Pname n) {
  if (n->n_evaluated) {
    stradd(p, n->n_val) ;
    return p ;
  }
  return mangled_expr(p, n->n_initializer,
		      (real_type(n->tp)->base == PTR ? true : false)) ;
}

// Generate a template instantiation name suitable for printing when it is
// presented to the user.
void templ_inst::print_pretty_name() 
{
  extern char emode ;
  
  fprintf(out_file, " %s<", (def->namep ? def->namep->string : "?")) ;
  Plist formal = inst_formals ;
  emode ++ ;  // so that dcl_print generates c++ rather than c names
  
  for (Pexpr ae1=actuals; formal && ae1  ; ae1=ae1->e2, formal = formal->l) {
    switch (formal->f->n_template_arg) {
    case template_type_formal:
      ae1->e1->tp->dcl_print(0) ;
      break ;
    case template_expr_formal:
      { char buff[256] ;
       
       mangled_expr(buff, ae1->e1) ;
       fprintf(out_file, "%s", buff) ;
       break ;
      }
    case template_expr_tree_formal:
    case template_stmt_tree_formal:
      // doesn't participate in the name generation
      break ;
    default:
      error ('i', "unexpected formal") ;
    }

    // this comma is unfortunately misplaced, since it follows a space printed
    // out by dcl_print
    if (formal->l) fprintf(out_file, ", ") ;
  }
  fprintf(out_file, ">") ;
  emode -- ;
}

	

// there are different representations for ICON based upon whether it has been
// evaluated. 
int check_for_const(Pexpr a1, Pexpr a2) {
  Neval = 0 ;
  if ((a1->base == NAME) &&
      ((a2->base == ICON) || (a2->base == IVAL) || (a2->base == ZERO)))
    { Pname n = Pname(a1) ;
      return (n->n_evaluated && (n->n_val == a2->eval())) ;
    }else if (((a1->base == ICON) || (a1->base == IVAL) || (a1->base == ZERO))
	      && (a2->base == NAME))
      { Pname n = Pname(a2) ;
	return (n->n_evaluated && (n->n_val == a1->eval())) ;
      }
  return false ;
}
  

// get past the template parameter names to get the the real expression
static Pexpr real_expression(Pexpr e) 
{
  while (e && (e->base == NAME) &&
	 (Pname(e)->n_template_arg == template_expr_formal) &&
	 (! Pname(e)->n_evaluated) && Pname(e)->n_initializer)
    e = Pname(e)->n_initializer ;
  return e ;
}
	 

// determine whether two expressions supplied as actual arguments to
// a "template_expr_formal"  formal argument match. 
static int expr_match(Pexpr a1, Pexpr a2)
{
  static int addr_of = 0 ;

  a1 = (addr_of ? a1 : real_expression(a1)) ;
  a2 = (addr_of ? a2 : real_expression(a2)) ;
  
  if (a1 == a2) return true;

  // 
  if (a1->base != a2->base) return check_for_const(a1, a2) ;
  
  switch (a1->base) {
  case QUEST:
    // a ternary operator
    return ( expr_match(a1->cond, a2->cond) &&
	     expr_match(a1->e1, a2->e1) &&
	     expr_match(a1->e2, a2->e2)) ;
  
  case PLUS: case MINUS: case MUL: case DIV: case MOD:
  case ER: case OR: case ANDAND: case OROR:
  case LS: case RS:
  case EQ: case NE: case LT: case LE: case GT: case GE:
    // binary operator
    return (expr_match(a1->e1, a2->e1) &&
	     expr_match(a1->e2, a2->e2)) ;
  case UMINUS: case UPLUS:
  case NOT: case COMPL:
    return (expr_match(a1->e2, a2->e2)) ;
  case ADDROF:
    {
      // unary using e2
      addr_of ++ ;
      int result = (expr_match(a1->e2, a2->e2)) ;
      addr_of -- ;
      return result ;
    }
  case CAST:
    return (expr_match(a1->e1, a2->e1)) ;
  case NAME:
    if (! addr_of) {
      Pname n1 = Pname(a1), n2 = Pname(a2) ;

      if ((n1->n_evaluated) && n2->n_evaluated && (n1->n_val == n2->n_val))
	return true ;
      if (n1->n_initializer &&  (! n2->n_initializer))
	return check_for_const(n2, n1->n_initializer) ;
      if (n2->n_initializer && (! n1->n_initializer))
	return check_for_const(n1, n2->n_initializer) ;
      if (n1->n_initializer &&  n2->n_initializer)
	return expr_match(n1->n_initializer,  n2->n_initializer) ;
    }
    return false ;
  case DOT:
    return (expr_match(a1->e1, a2->e1)) ;
  case REF:
    return (expr_match(a1->e1, a2->e1)) ;
  case IVAL:
    return (ival *)a1->i1 == (ival *)a2->i1 ;
  case ICON:
  case CCON:
  case FCON:
  case STRING:
    return (strcmp (a1->string, a2->string) == 0) ;
  case ZERO:
    return true ;
  case SIZEOF:
    { long l1 = a1->eval(), l2 = a2->eval() ;
      return (l1 == l2) ;
    }
  }
  return false ;
}     


static char * non_type_argument_signature(Pexpr e, char *p) {
  p = e->tp->signature(p) ;
  return mangled_expr(p, e) ;
}
  


// generate array suffix information for an array signature. cfront does not
// normally generate this as part of the type signature, since it only deals
// with argument signatures, and arrays can't be arguments.
static void add_array_type_suffix(char *&s, Ptype t) {
  t = real_type(t) ;
  if (t->base == VEC) {
      Pvec v = Pvec(t);
      int dim;
      char a[32] ;
      Neval = 0 ;
      if(v->dim == 0) 
	  dim = v->size / v->typ->tsizeof();
      else dim = (int)v->dim->eval();
    sprintf(a, "A%d", dim) ;
    stradd(s,a) ;
    add_array_type_suffix(s, Pvec(t)->typ);
  }
}
    
			   
			   
// Generate a mangled template instantiation name. The syntax of as template
// mangled class name is of the form:
//   original_name__<argument type signatures>__unique_id
// Each non-type argument is replaced by a unique id.
char *templ_inst::mangled_name(char *ip)
{ static tree_formal_id = 0 ;
	 
  char *start = ip ;
  ip = start ;
  strcpy(ip, (def->namep ? def->namep->string : "?")) ;
  ip= start + strlen(start) ;
  stradd(ip, "__pt__") ;

  {
    char  a [max_string_size], *p = a ;
  
    Plist formal = inst_formals ;
  
    for (Pexpr ae1=actuals ; ae1 ; ae1=ae1->e2, formal = formal->l)
      switch (formal->f->n_template_arg) {
      case template_expr_formal:
	*p++ = 'X' ;
	// the formal must have been bound
	p = non_type_argument_signature(formal->f, p) ;
	break ;
      
      case template_type_formal:  
	p = ae1->e1->tp->signature(p) ;
	add_array_type_suffix(p,ae1->e1->tp) ;
	break ;
      
      case template_expr_tree_formal:
      case template_stmt_tree_formal:
	*p++ = 'Y' ;
	stradd(p, tree_formal_id++) ; 
	break ;
      
      default:
	error ("bad template formal:%d", formal->f->base) ;
	break ;
      }
    
    *p = 0 ;
    sprintf(ip, "%d_", strlen(a)+1) ;
    ip = start + strlen(start) ;
    strcpy(ip,a) ;
  }
    
  return start ;
}



// The C compiler barfs when it is passed on through C++ as an automatic
// variable 
const char leader[]= "\t" ;

// Explain the location of an instantiation in greater detail, since it may be
// far removed from it's textual definition.
void templ_inst::print_error_loc() {
  if (! head) return ; // No active instantiations

  extern void print_loc() ;
  state current_state ;
  char buffer[max_string_size] ;

  for (int i = 0 ; i < max_string_size; i++) buffer[i] = 0 ;

  current_state.save() ;
  fprintf (out_file, "%sanomaly detected during the instantiation of",
	   leader) ;
  print_pretty_name() ;
  fprintf(out_file, "\n") ;
  if (!head->next_active) {
    // A more compact message for a single level of instantiation
    context.restore() ;
    fprintf (out_file, leader) ;
    print_loc() ;    
    fprintf (out_file, "was the site of the instantiation\n") ; 
  }else {
    // The instantiation chain is longer than one
    fprintf (out_file, "%sthe instantiation path was:\n", leader) ;
    for (Ptempl_inst p = head ; p ; p = p->next_active) {
      p->context.restore() ;
      print_loc() ;
      fprintf (out_file, " template:") ;
      p->print_pretty_name() ;
      fprintf(out_file, "\n") ;
    }
  }
  current_state.restore() ;
}

  

// Generate a class name for the instantiated class. It is constructed in a
// manner similar to the names used in the construction of overloaded functions
char *templ_inst::instantiation_string() {
  char  inst_name[max_string_size] ;
  for (int i = 0 ; i < max_string_size; i++) inst_name[i] = 0 ;
  mangled_name(inst_name) ;
  return strdup(inst_name) ;
} 
  

    
// Change the names for the class, constructors, and destructors to reflect
// the new class instantiation name.
void classdef::modify_inst_names(char *s)
{
  char *old = string ;
  string = s ;   // Change the class name
  // Change the constructor names
  for (Pname p=mem_list; p; p=p->n_list)
    if (p->tp && (p->tp->base==FCT) && (!strcmp(old, p->string)))
      p->string = s ;
}

// Get past the fake template argument name typename types
Ptype non_template_arg_type(Pbase t) {
  if ((t->base == TYPE) &&
      (t->b_name->n_template_arg == template_type_formal))
    return non_template_arg_type(Pbase(t->b_name->tp)) ;
  else return t ;
}

// follow the chain until we hit a non
void non_template_arg_non_type(Pname n) {
  Pexpr i = n->n_initializer; 
  while (i &&
	 (i->base == NAME) &&
	 (Pname(i)->n_template_arg == template_expr_formal)) 
    {
      if (Pname(i)->n_initializer) {
	n->n_initializer = Pname(i)->n_initializer ;
	i = n->n_initializer ;
	continue ;
      }
      if (Pname(i)->n_evaluated) {
	n->n_evaluated = 1 ;
	n->n_val = Pname(i)->n_val ;
	return ;
      }
    }
  return ;
}
      


// Now that the actuals are truly resolved, ie. semantics is complete, and the
// template is about to be instantiated.
void forward_template_arg_types(Plist formal, Pexpr actuals)
{   
  for (Pexpr actual = actuals ; formal && actual ;
       formal = formal->l, actual = actual->e2)
    switch(formal->f->n_template_arg){
    case template_type_formal:
      actual->e1->tp = non_template_arg_type(Pbase(actual->e1->tp)) ;
      break ;
    case template_expr_formal:
      break ;
    case template_expr_tree_formal:
    case template_stmt_tree_formal:
      break ;
    default:
      error ('i', "bad template formal") ;
    }
}
     
// determine whether the expression supplied as an actual argument to
// atemplate formal of type "template_expr_formal" is suitable. We are nore
// restrictive than we need to be, simply so that the debugger can have an
// easier time. All expressions must be of the form constant integer
// expression, a float or double literal, or the address of a variable, or an
// array, or function
static int  suitable_const_expr(Pname n)
{
  if (n->n_evaluated) return 1 ;

  if (!n->n_initializer) return 0 ;

  switch (n->n_initializer->base) {

  case CAST:
    { // if it is a cast of an integer value, it's fine.
      if (n->n_initializer->e1->base == IVAL)
	return 1 ;
      else return 0 ;
    }
  
  case FCON:
  case ZERO:
    return 1  ;
  
  case ADDROF:
  case G_ADDROF:
    {
      Pname an = Pname(n->n_initializer->e2) ;
      if (an->base != NAME) return 0 ;
      if (an->n_stclass == STATIC) return 1 ;
      return 0 ;
    }
  case NAME:
    {
      Pname an = Pname(n->n_initializer) ;
      if ((an->n_stclass == STATIC) &&
	  (an->tp->base == VEC))
	// assumes that decl processing won, so that the formal could only
	// have been apointer
	return 1 ;
      return 0 ;
    }
  default:
    return 0 ;
  }
}



static bool is_stmt_node(Pnode p) {
  if (!p) return false ;
  switch(p->base) {
  case BREAK: case CONTINUE: case DEFAULT:
  case SM: case WHILE: case DO: case SWITCH: case RETURN: case CASE:
  case FOR:
  case IF:
  case BLOCK:
  case PAIR: // ?
    return true ;
  }
  return false ;
}
	


static void bind_tree_expr_formal(Pname f, Pexpr actual) 
{
  if (actual->e1->base == TNAME)
    error ('i', "a TNAME is not a valid argument for the formal %n",
	    f) ;
  if (is_stmt_node(actual->e1)) {
    error ("an expression node was expected for the expression formal parameter %n", f) ;
    actual->e1 = zero ;
  }
  // bind the formal to the expression, it will be accessed from here by
  // the hook function during the copy
  f->n_initializer = actual->e1 ;
}



// Bind the formals to the types passed in as the actuals, for the
// instantiation, bind the non-type names to their expressions.
void templ_inst::bind_formals()
{ Pexpr actual ;
  Plist formal ;
  
  for (formal = inst_formals, actual = actuals ;
       formal && actual ; formal = formal->l, actual = actual->e2)
    switch (formal->f->n_template_arg) {
      case template_type_formal:
	{
	  formal->f->tp = non_template_arg_type(Pbase(actual->e1->tp)) ;
	  PERM(formal->f->tp) ;
	  break ;
	}
	
      case template_expr_formal:
	{
	  actual->e1 = actual->e1->typ(gtbl);
	  if (formal->f->tp->check(actual->e1->tp,ASSIGN) == 1)
	    error("template argument mismatch, expected %t for formal %n, not %t",
		  formal->f->tp, formal->f, actual->e1->tp) ;
	  // hide the global name around decl processing of the formal name
	  Pname g = gtbl->look (formal->f->string, 0) ;
	  if (g) g->n_key = HIDDEN ;
	  // bind the non type arguments to their expressions
	  // parameters that are bound at syntax analysis, these parameters are
	  // bound during dcl processing, so ensure that they can be found.
	  formal->f->n_initializer = actual->e1 ;
	  formal->f->simpl() ;
	  formal->f = formal->f->dcl(gtbl, STATIC) ;
	  formal->f->n_key = HIDDEN ;
	  
	  PERM(formal->f) ;
	  non_template_arg_non_type(formal->f) ;
	  if (!suitable_const_expr(formal->f))
	      error("template argument for formal:%s, is not a suitable constant.",
		    formal->f->string) ;
	  if (g) g->n_key = 0 ;
	  break ;
	}
	
      case template_expr_tree_formal:
	{
	  bind_tree_expr_formal(formal->f, actual) ;
	  break ;
	}
      case template_stmt_tree_formal:
	{ 
	  error("a statement tree may not be specified for a class template") ;
	  break ;
	}
	
      default:
	error ('i', "bad template formal") ;
      }
  
  // now that the formals are bound, compute the instantiation string
  char *inst_name = instantiation_string() ;
  tname->string = instantiation_string() ;

  for (formal = inst_formals; formal ; formal = formal->l)
    if (formal->f->n_template_arg_string)
	error('i', "attempt to bind a template parameter multiple times") ;
    else
      formal->f->n_template_arg_string =
	strcat(strcpy(calloc(strlen(formal->f->string)+strlen(inst_name)+1,1),
		      formal->f->string), inst_name) ;
}


// Expose the non-type parameter names so that they are visible during decl
// processing. Conflicting global names are hidden, so that they are not
// found.
void templ_inst::expose_parameter_names() {

  if (hidden_globals)
    error ('i', "an expose without a hide of global names") ;
  
  for (Plist formal = inst_formals ; formal  ; formal = formal->l)
    if (formal->f->n_template_arg == template_expr_formal) {
      // Hide any visible globals
      Pname gname = gtbl->look(formal->f->string, 0) ;
      if (gname) {
	// an existing global name, hide it
	gname->n_key = HIDDEN ;
	// note them for future restoration
	hidden_globals = new name_list(gname,hidden_globals);
      }
      formal->f->n_key = 0 ;	// bring it out of hiding
      if (formal->f != gtbl->look(formal->f->string,0))
	error('i', "parameter could not be located in the global table") ;
    }
}


// Hide the non-type parameter names after an instantiation, and restore any
// globals that may have been hidden during the process.
void templ_inst::hide_parameter_names() {
  
  for (Plist formal = inst_formals ; formal  ; formal = formal->l)
    if (formal->f->n_template_arg == template_expr_formal) {
      formal->f->n_key = HIDDEN ;
    }
  for (; hidden_globals; hidden_globals= hidden_globals->l)
    hidden_globals->f->n_key= 0 ;
  hidden_globals = 0 ;
}



// Primitives for saving and restoring the compilation state around a template
// instantiation. It also maintains the stack of template instantiations.
void templ_inst::save_state(Pname p)  {
  if (next_active) error ('i', "circular instantiation of a template") ;
  context.save() ;
  if (templ_inst::head)
    templ_inst::head->hide_parameter_names() ;
  next_active = templ_inst::head ; templ_inst::head = this ;
  context.init() ;
  Cdcl = p ; Cstmt = NULL ;
  curr_file = (Cdcl) ? Cdcl->where.file : 0;
  expose_parameter_names() ;
} 


void templ_inst::restore_state() {
  context.restore() ;
  hide_parameter_names() ;
  templ_inst::head = next_active ; next_active = NULL ;
  if (templ_inst::head)
    templ_inst::head->expose_parameter_names() ;
} 


// Copy over the class definition subtree starting from COBJ down to the
// CLASSDEF node. This minimal subtree has to exist during syntax analysis,
// and already contains pointers into it.
void templ_inst::kludge_copy(Pbase pbc)
{
  // copy just the COBJ ->b_name NAME ->tp CLASS path for now, note that the
  // preceding path of the tree is pre-allocated, since syntax analysis needs
  // to generate pointers to these objects.
  Pbase pb = Pbase(tname->tp) ;
  Pname save_b_name = pb->b_name ;
  Ptype save_tp = pb->b_name->tp ;

  if ((pb->base != COBJ) || (pbc->base != COBJ))
    error ('i', "cobj nodes were expected here") ;
  
  *pb = *pbc ;
  pb->b_name = save_b_name ;
  *pb->b_name = *pbc->b_name ;
  pb->b_name->tp = save_tp ;
  *Pclass(pb->b_name->tp) = *Pclass(pbc->b_name->tp) ;
  Pclass(pb->b_name->tp)->class_base = instantiated_template_class ;
  
}


// these statics probably belong in templ_inst and shouldn't be dangling
// around

static Pbase cobj_node ;
static Pname  cname_node ;
static Pclass class_node ;
	     
static void syntax_tree_copy_hook(void *,
			     Pnode &,
			     node_class,
			     tree_node_action &action,
			     int& never_see_again)
{
  never_see_again = 1;
  action = tna_continue;
  return;
}


// create a copy of the expression tree
static Pnode copy_syntax_tree(Pnode n, int no_types = 0) {
  pointer_hash       cht(default_copy_hash_size) ;
    
  tree_copy_info  info ;

  if(no_types) info.node_hook = syntax_tree_copy_hook;

  copy_tree (n, info, &cht);

  return n ;
}
 


// hook to perform the copying of the pre-allocated class subtree
bool templ_inst::copy_hook(Pnode &node)
{
  switch (node->base) {
  case COBJ:
    if (node == cobj_node) return false ;
    
    if (node == def->namep->tp) {
      *cobj_node =  *Pbase(node) ;
      node = cobj_node ;
    }
    break ;
  case NAME:
    if (node == cname_node) return false ;
    if (node == sta_name) return false ;

    if (node == Pbase(def->namep->tp)->b_name) {
      *cname_node= *Pname(node) ;
      node = cname_node ;		  
    }else { // check for tree expression formals
      char *s = Pname(node)->string ;
      Pname f =  0 ;
      if (s && (*s == '$') && (f = get_parameter(s+1)))
	{
	  if(Pname(node)->n_list) 
	    error ('i', "n_list set in tree template formal.");
	  node = copy_syntax_tree(Pname(f)->n_initializer) ;
	  return false ;
	}
    }
    break ;
  case CLASS:
    if (node == class_node) return false ;
    
    if (node == Pbase(def->namep->tp)->b_name->tp) {
      *class_node = *Pclass(node) ;
      node = class_node ;
    }
    break ;
  }
  return true ;
}


/*

This hook function used during a class copy.
		       
*/
static void copy_hook(void /* Ptempl_inst */ *p, Pnode &node,
		      node_class, tree_node_action &action,
		      int& never_see_again)
{
  action = (Ptempl_inst(p)->copy_hook(node) ? tna_continue : tna_stop ) ;
  never_see_again = (action != tna_stop);
  return ;
}      

    
    
void establish_class_subtree_correspondence(pointer_hash &h, Pname key_tname,
					    Pname value_tname) 
{
  h[int(key_tname)] = int(value_tname) ;
  h[int(key_tname->tp)] = int(value_tname->tp) ;
  h[int(Pbase(key_tname->tp)->b_name)] =
    int(Pbase(value_tname->tp)->b_name) ;
  h[int(Pbase(key_tname->tp)->b_name->tp)] =
    int(Pbase(value_tname->tp)->b_name->tp) ;
}




Pcons make_ref_copy(pointer_hash &h, tree_copy_info &info, Pcons old_templ_refs)
{
  cons dummy(0,0), *last = &dummy ;
  
  for (Pcons pc = old_templ_refs ; pc ; pc = pc->cdr) {
    
    Ptempl_inst t = Ptempl_inst(pc->car) ;
// +**** this doesn't work without class instances of new and delete
// +**** dtor places this onto free_list: ugh
// +**** want to restore this once new/delete isntances are restored
//    expr   dummy(ELIST, 0, 0) ;
//    elist  list(&dummy) ;
    Pexpr   dummy = new expr(ELIST, 0, 0);
    elist  list(dummy);

    // copy the trees corresponding to the actuals
    for (Pexpr actual = t->actuals ; actual ; actual = actual->e2) {
      Pnode root = actual->e1 ;
      copy_tree (root, info, &h);
      // make sure that references to enclosing formals are resolved
      root = Pexpr(root)->typ(gtbl);
      list.add(new expr(ELIST, Pexpr(root), 0)) ;
    }
    Pexpr new_actuals = list.head->e2 ;
    
    // get one if it exists, create one otherwise.
    Ptempl_inst  treal = t->def->get_inst(new_actuals, t) ;
    Pname new_tname = treal->tname ;
    
    last = last->cdr = new cons(treal,0);

    establish_class_subtree_correspondence(h, t->tname, new_tname) ;
  }

  return dummy.cdr ;
}




/*
   Remap the template references from within the body of the template. This
action is similar to the normal tree copy operation; it would normally have
been done during the syntax phase, that produced the tree, but since there
isn't one, for the instantiated body, it must be done here.

*/					     
Pcons templ_inst::ref_copy(pointer_hash &h, tree_copy_info &info, Pcons old_templ_refs)
{
  expose_parameter_names() ;
  Pcons new_refs = make_ref_copy(h,info,old_templ_refs) ;
  hide_parameter_names() ;
  return new_refs ;
}

static bool is_forward_instantiation(Pbase b_base, Pbase f_base)
{
  return bool(b_base->b_name->tp->defined && f_base->b_name->tp->defined) ;
}


/*****************************************************************************
* 									     *
* If the template instantiation is found to be unique after the decl	     *
* processing of the actuals, create a copy of the post syntax graph for the  *
* class. The edges of the graph are determined by "type nodes" that have     *
* already been defined, and TNAME nodes that are in the global keyword	     *
* table. Special care is also taken to avoid copying nodes whose identity    *
* must be maintained, since cfront uses them for fast type checks, these     *
* nodes always have the "defined" flag turned on and so are never copied.    *
* 									     *
* Copying of the pre-allocated class sub-tree for the template: COBJ	     *
* ->b_name NAME ->tp CLASS						     *
* 									     *
* is handled by the class_copy hook above, that is invoked during the course *
* of the copy.								     *
* 									     *
* 									     *
* Template references from within the class need special handling, since     *
* each instantiation of the class, results in a potentially new template     *
* instantiation.							     *
* 									     *
*****************************************************************************/
Ptempl_inst  templ_inst::class_copy(Pcons &templ_refs, bool recopy) 
{
  bool forward = false ; // a forward class is instantiated twice
		
  // associate the formals with their types, and their expressions
  if (recopy) {
    // remove the class def node from the table, so that it's attributes are
    // copied. 
    corr->del(int(Pbase(def->namep->tp)->b_name->tp)) ;
    corr->del(int(Pbase(def->namep->tp)->b_name)) ;
    corr->del(int(def->namep->tp)) ;
    
    corr->del(int(tname->tp)) ;
    corr->del(int(Pbase(tname->tp)->b_name)) ;
    corr->del(int(Pbase(tname->tp)->b_name->tp)) ;
  }else corr = new pointer_hash(default_copy_hash_size) ;
  
  { // copy the formals & install them in the correspondence table
    name_list dummy_formal(0,0) ; 
    Plist last = &dummy_formal ;
      
    for (Plist formal = def->formals ; formal ; formal = formal->l) {
      Pname copy_name = new name("") ;
      *copy_name = *formal->f ;
      copy_name->n_tbl_list = 0 ;
      last = last->l = new name_list(copy_name, 0) ;
      (*corr)[int(formal->f)] = (int)copy_name ;
    }
    inst_formals = dummy_formal.l ;
  }
  
  bind_formals() ;
  if ( ! recopy && ktbl->look(tname->string, 0)) {    
    // formal binding may result in detecting identical instantiations
    Ptempl_inst ti = def->get_match(actuals, this, true) ;
    if (ti) return ti ;
    error('i', "Generated template instantiation name %swas not unique",
	  tname->string) ;
  }
  
  { 
    tree_copy_info  info ;
    info.node_hook = ::copy_hook ;
    info.hook_info = this ;
    
    (*corr)[int(def->namep)] = int(tname) ; // make the tnames correspond
    
    templ_refs = ref_copy(*corr, info, templ_refs) ;
    Pnode root = def->basep ;	// start the copy at the cobj node

    // deal with these nodes differently during the copy, ie. the nodes
    // themselves are not copied, but their attributes are.
    cobj_node = (Pbase)tname->tp ;
    cname_node = Pbase( tname->tp)->b_name ;
    class_node = Pclass(Pbase( tname->tp)->b_name->tp) ;
    
    copy_tree (root, info, corr);

    {  // dump the tree if the flag is set
       extern int dump_tree ;
       extern dcn_arg dump_tree_arg;

       if (dump_tree) display_cfront_node (dump_tree_arg, root);
     }
  }
  // Perform name modifications for the class, so that it is an
  // instantiation-specific name.
  cname_node->string = tname->string ;
  if (!recopy)
    namep =  ktbl->insert(tname, 0) ;
  else class_node->defined &= ~(DEFINED|SIMPLIFIED) ;
  namep->tp = cobj_node;
    
  class_node->modify_inst_names(cname_node->string) ;
  return 0 ;
}


/*
This hook function is responsible for the replacement of references to
expression when copying function bodies
*/
static void function_copy_hook(void *current_templ_inst,
			     Pnode &node,
			     node_class,
			     tree_node_action &action,
			       int& never_see_again)
{
  never_see_again = 1;

  switch (node->base) {
  case SM_PARAM:
    error ('i', "statement parameters not permitted for member functions") ;
    break ;
    
  case NAME:
    { 
      if(node == sta_name) {
	  action = tna_stop;
	  return;
      }
      char *s = Pname(node)->string ;
      Pname f =  0 ;
      if (s && (*s == '$') &&
	  (f = Ptempl_inst(current_templ_inst)->get_parameter(s+1))) {
	      if(Pname(node)->n_list) 
		  error ('i', "n_list set in tree template formal.");
	      node = copy_syntax_tree(Pname(f)->n_initializer) ;
	      action = tna_stop ;
	      never_see_again = 0;
	  }else action = tna_continue ;
      return ;
    }
  default:
    action = tna_continue ;
    return ;
  }
}



/* 

Create a copy of a function member, as part of the instantiation of a function
body. The correspondence table is first initialized with the contents of the
correspondence table used to instantiate the class. Copying is initiated
in this context.

*/

Pname templ_inst::function_copy(Pfunt fnt, Pcons &templ_refs)
{
  pointer_hash fcorr(*corr) ; // initialize it with the old hash table
  
  {     
    tree_copy_info  info ;
    Pnode           root = fnt->fn ; 

    // establish a correspondence between the formals used for the class
    // template, andthe formals used for the function template, all references
    // to the function template formals will be replaced by references to the
    // instantiated class template formals after the copy has been completed.
    
    for (Plist fformal = fnt->formals, cformal = inst_formals ;
	 fformal ; fformal = fformal->l, cformal = cformal->l)
      {
	fcorr[int(fformal->f)] = int(cformal->f) ;
	if (fcorr[int(fformal->f)] != int(cformal->f))
	  error ('i', "hash table bug") ;
      }

    info.node_hook = ::function_copy_hook ;
    info.hook_info = this ;

    templ_refs = ref_copy(fcorr, info,  templ_refs) ;
    if (fcorr[int(def->namep)] != int(tname))
      error ('i', "template to instantiation typename correspondence is missing") ;
    
    copy_tree (root, info, &fcorr);

    {  // dump the tree if the flag is set
      extern int dump_tree ;
      extern dcn_arg dump_tree_arg;

      if (dump_tree)
	display_cfront_node (dump_tree_arg, root);
    }
    return Pname(root) ;
  }
}
  
     
/*****************************************************************************
* 		       							     *
* A matching template was found at instantiation time, which was not	     *
* detected at syntax analysis time. This can happen, when an instantiation   *
* has as its arguments not real types but template arguments, so that	     *
* matches cannot be detected until the templates are bound. Note that it is  *
* also possible to match a template that is in the process of being	     *
* instantiated further up the instantiation call chain. In such cases, the   *
* kludge_copy operation will copy over an incomplete class subtree, which    *
* will be recopied with the completed one after the instantiation is	     *
* completed, in templ_inst::instantiate.				     *
* 									     *
*****************************************************************************/
void templ_inst::instantiate_match(Ptempl_inst match)
{ Pbase pb = Pbase(match->tname->tp) ;
  kludge_copy(pb) ;
  forward = match ;		// Note the fact that this template was matched
}


Pclass current_instantiation = 0 ;

// Do the class declaration instantiation.
void templ_inst::instantiate(bool reinstantiate)
{
  Pcons templ_refs = def->templ_refs  ;
  if (! reinstantiate) {
    switch (Ptclass(Pbase(tname->tp)->b_name->tp)->class_base) {
    case instantiated_template_class: 
      return ;
    case uninstantiated_template_class: 
      break ;
    case vanilla_class:
    case template_class:		// the canonical template class
    default: 
      error ('i', "attempt to instantiate a non-template class") ;
    }
    status = class_instantiated ;
    // Check whether, the template has already been instantiated, if so use it.
    forward_template_arg_types(def->formals, actuals) ;
    Ptempl_inst match = def->get_match(actuals, this, true) ;
    
    if (match || (match = class_copy(templ_refs, false))){
      instantiate_match(match) ;
      return ;
    }
  }else class_copy(templ_refs, true) ;

  Pbase pb = Pbase(tname->tp) ;
  
  // Save the state around decl processing
  { save_state(def->namep) ;
    
    if (def->open_instantiations++ > 1) {
      error ("an infinite instantiation sequence was initiated") ;
      def->open_instantiations-- ;
      return ;
    }
    // Mark the class as instantiated so that there are no circular
    // instantiations. 
    Pclass(pb->b_name->tp)->class_base = instantiated_template_class ;

    // if it is a forward reference, rely on the usual compilation to
    // provide an error message, if indeed it is an error, and not a
    // benign forward reference such as: friend class foo<X,Y> 
	  
    if (def->basep->b_name->tp->defined) {

      // Put out the typedefs for the template parameters do this before the
      // call to name::dcl below, since dcl processing will emit c declarations
      // that make use of the type
      for (Plist formal = inst_formals; formal ; formal = formal->l)
	switch(formal->f->n_template_arg) {
	case template_expr_tree_formal:
	case template_stmt_tree_formal:
	  break ;
	default:
	  formal->f->dcl_print(0) ;
	}
      // Instantiate the parametrized types referenced by this template
      for (Pcons pc = templ_refs ; pc ; pc = pc->cdr)
	Ptempl_inst(pc->car)->instantiate() ;
      
      if (!((pb->b_name->dcl(gtbl, EXTERN) == 0 ) || error_count)) {
	pb->b_name->simpl() ;
	
	if (pb->b_name->tp->base != CLASS)
	  error('i', "a classdef was expected in templ_inst::instantiate") ;
	
	current_instantiation =  Pclass(pb->b_name->tp) ;
	pb->b_name->dcl_print(0) ;
	if (! (pb->b_name->tp->defined & DEFINED))
	  error ('i', "dcl class is not yet defined") ;
	current_instantiation = 0 ;
      }
    }

    // bash every template instantiation class that has been forwarded to
    // it, with the decl processed version.
    for (Ptempl_inst clone = def->insts ; clone ; clone = clone->next)
      if (clone != this) {
	if (clone->forward == this)
	  clone->kludge_copy(Pbase(tname->tp)) ;
	else {
	  // resolve references to forward declarations
	  if (this == def->get_match(clone->actuals, clone, true)) {
	    clone->kludge_copy(Pbase(tname->tp)) ;
	    clone->forward = this ;
	  }
	}
      }
    Pclass result = Pclass(pb->b_name->tp);
      
    // dcl_print the member functions, so that they can be referenced
    int i = 0 ;
    for (Pname fn= Pclass(pb->b_name->tp)->memtbl->get_mem(i=1); fn;
	 fn=Pclass(pb->b_name->tp)->memtbl->get_mem(++i))
      if ((fn->base == NAME) && (fn->tp->base == FCT))
	fn->dcl_print(0) ;
    
    restore_state() ;
    def->open_instantiations-- ;
  }
}

/* Template Constructors  */


templ::templ(Plist parms, Pname p) {
  namep   = p ;
  formals = parms ;

  if (!formals) error ("a parametrized type must have parameters !") ;

  basep   = Pbase(namep->tp) ;

  Pclass(basep->b_name->tp)->class_base = template_class ;
  defined = ((basep->b_name->tp->defined & DEF_SEEN) ? true : false) ;
  if (defined)
    members = Pclass(basep->b_name->tp)->mem_list ;
  
  PERM(namep) ; PERM(namep->tp) ;
  // Chain on to the list of templates for the compilation.
  next = templp->list ;
  templp->list = this ;
}


templ_inst::templ_inst (Pexpr act, Ptempl owner)
{
  // Set up the basetype for the class, so that nodes that need to point to it
  // during syntax processing can do so. Theese objects are merely
  // place-holders during syntax analysis, and are actually filled in during
  // the copy phase of instantiation.
  Pclass c ;
  
  def = owner ;
  tname = new name(def->namep->string) ;
  tname->base = TNAME ;
  tname->tp = new basetype(COBJ, new name(def->namep->string)) ;
  Pbase(tname->tp)->b_name->tp = c = new templ_classdef(this) ;
  PERM(tname) ; PERM(tname->tp) ; PERM(Pbase(tname->tp)->b_name) ;
  PERM(Pbase(tname->tp)->b_name->tp) ;

  // initialize the member list so that set_scope can do the right thing
  c->mem_list = Pclass(def->basetype()->b_name->tp)->mem_list ;
  
  actuals = act ;
  next = owner->insts ;
  owner->insts = this ;
}


templ_classdef::templ_classdef(Ptempl_inst i): classdef(CLASS) {
  inst = i ;
  class_base = uninstantiated_template_class ;
  string = unparametrized_tname()->string ;
}


// Create a new function template.
function_template::function_template (templ &owner, Plist params, Pname n)
{
  definition_number = ++definition_tick ;
		      
  if (owner.fns_end)
    owner.fns_end->next = this ;
  else owner.fns = this ;
  owner.fns_end = this ;
  formals   = params ;
  fn        = n ;
  PERM(n) ; PERM(n->tp) ;
}


// create the tree template
tree_template::tree_template(TOK tree_kind, char *s, Plist params, Pnode tree,
			     Pcons references) 
{
  string = s ;
  formals = params;
  e = tree ;
  if (!e)
    error('w', "the internal template %s does not have an associated body", s);
  templ_refs = references ;
  kind = tree_kind ;

  // add the expression template too the list of known templates
  if (get(s)) {
      error ("duplicate definition of the internal template %s", s) ;
      return ;
    }
  // link it in
  next = templ_compilation::tree_templates ;
  templ_compilation::tree_templates = this ;

  // check that formals weren't misspelt
  for (Plist formal = formals ; formal ; formal = formal->l)
    if (! formal->f->n_used)
      error('w', "the formal parameter %n was not referenced within the template body",formal->f) ;
}


// lookup an internal expression template
Ptreet tree_template::get(char *s) {
  for (Ptreet o = templ_compilation::tree_templates ; o ; o = o->next)
    if (strcmp(o->string, s) == 0) return o ;
  return 0 ;
}
 
 
Pname tree_template::get_parameter(char *s) {
  for (Plist formal = formals ; formal ; formal = formal->l) {
    if (strcmp(formal->f->string, s)== 0)
      return formal->f ;
  }
  return 0 ;
}



// Sam: some remodularization seems to be in order here, so that this method
// can be shared
Pname templ_inst::get_parameter(char *s) {
  for (Plist formal = inst_formals ; formal ; formal = formal->l) {
    if (strcmp(formal->f->string, s)== 0)
      return formal->f ;
  }
  return 0 ;
}

Pexpr tree_template::expand(Pexpr)  
{
  error('i', "no support for tree templates") ;
  return 0 ;
}

  
// Instantiate each function member body. It assumes that the class
// declaration has been instantiated. The return value indicates whether an
// instantiation of bodies actually took place. This function is only invoked
// at the end of a file compilation, after all source text has been processed. 
bool templ::instantiate_bodies(){
  bool change = false ;
  // Perform the instantiation of the member function bodies.
  if (!fns) return change ;
  
  for (Ptempl_inst inst = insts ;  inst ; inst = inst->next)
    if (!inst->forward && (inst->status == class_instantiated)) {
      // Set up the environment for the declaration, and subsequent compilation
      // of the function bodies.
      inst->status = body_instantiated ; change = true ;

      {  Pclass ic = inst->get_class() ; int i ;
	// note all the overriding definitions explicitly provided by the user
	for (Pname fn= ic->memtbl->get_mem(i=1); fn; fn=ic->memtbl->get_mem(++i))
	     if ((fn->base == NAME) && (fn->tp->base == FCT) && Pfct(fn->tp)->body)
	  fn->n_redefined = 1 ;
       }

      for (Pfunt fnt = fns;  fnt ; fnt = fnt->next) {
	Pcons templ_ref_copy = fnt->templ_refs ;
	Pname fn = inst->function_copy(fnt, templ_ref_copy) ;
	
	// Change the qualifier to be the name of the instantiated, rather than
	// the parametrized class name
	fn->n_qualifier = inst->namep ;
if (fn->n_oper != TYPE ) // cond contains type information
	fn->n_table = 0; 
	fn->n_tbl_list = 0 ;
	
	// Note that the formals were bound to the actuals when the class decl
	// was instantiated, so the binding is not redone.
	
	// Modify constructor and destructor names.
	if (!strcmp(fn->string, namep->string))
	  fn->string = inst->namep->string ;	
	{ inst->save_state(fn) ;
	  // Instantiate the parametrized types referenced by this template
	  for (Pcons pc = templ_ref_copy ; pc ; pc = pc->cdr)
	    Ptempl_inst(pc->car)->instantiate() ;

	  // ensure that "type type" formals constrained to be class definitions are
	  if (!fnt->check_constraints(inst->actuals))continue ;

	  if ( ((fn = fn->dcl(gtbl, EXTERN)) == 0) || error_count) {
	    inst->restore_state() ;
	    continue ;
	  }
	  fn->simpl() ;
	  fn->dcl_print(0) ;
	  inst->restore_state() ;
	}
      }
    }
  return change ;
}
0707071010112046121004440001630000160000010212600466055421700001300000040045template.h/* ident "@(#)ctrans:src/template.h	1.2" */
/* -*- Mode:C++ -*- */
/*
	$Source: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v $ $RCSfile: cfront.cpio,v $
	$Revision: 1.1.1.1 $		$Date: 2018/04/24 17:21:35 $
	$Author: root $		$Locker:  $
	$State: Exp $
*/
/*
    $Header: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v 1.1.1.1 2018/04/24 17:21:35 root Exp $

    Copyright 1989 by Object Design, Inc., Burlington, Mass.
    All rights reserved.

*/


/*****************************************************************************
* 									     *
* This file contains types pertinent to the implementation of the	     *
* parametrized type facility.						     *
* 									     *
*****************************************************************************/

enum bool { true = 1, false = 0 } ;

typedef class templ *Ptempl ;

typedef class templ_inst *Ptempl_inst ;

typedef class function_template *Pfunt ;

typedef class templ_classdef *Ptclass ;

typedef class tree_template *Ptreet ;


// A Lisp style cons cell to help build lists. The parametrized type facility,
// should obviate the need for this type-unsafe nonsense.
class cons {
public:
  void *car ;
  cons *cdr ;
  cons (void *pcar, cons *pcdr) { car = pcar ; cdr = pcdr ; } ;
} ;

typedef cons *Pcons ;



/*****************************************************************************
* 									     *
* The class template_compilation holds the state, and the associated methods *
* used during template compilation. There is exactly one instance of the     *
* type, it is mainly a device used to enforce modularity.  In reality, it    *
* would never need to be instantiated since all it's members are static.     *
* However, since the type::mem for of reference is not supported as	     *
* yet(cfront 1.2), we need an instantiation to get to the members via	     *
* pointer syntax instead.						     *
* 									     *
* A templ_compilation holds the state relevant to the syntax analysis of a   *
* class or member function template definition.				     *
* 									     *
*****************************************************************************/

class templ_compilation {
  static  Plist param_end,   // make append easier
                param_tn ;   // The type names introduced by the parameters

public:
  static Ptempl  list ;      // The list of templates for the compilation
  static Plist   params ;    // The list of parameters to the template
  static Ptempl  owner  ;    // The template when compiling a member
                             //     function.
  static table   *templates ; // The templates defined during this compilation
  
  static Ptreet  tree_templates; // The list of tree templates

  static bool    in_progress; // a template compilation is in progress
  // instantiation parameter parsing in progress. Used in the lexer to ensure
  // that name string are consed in the heap, rather than being retained as
  // pointers into the lex buffer.
  static int     parameters_in_progress ;

  // the list of templates referenced by the top level definition being compiled.
  static Pcons   templ_refs ;
  static Pcons   last_cons ;
  static Ptype   any_type ;  // canonical "ANY" type for formal parms
  
  // true, if currently compiling an expression tree template
  static TOK   curr_tree_template ;

  void append_ref(Ptempl_inst ref) ;
  void start() ;
  
  void collect(TOK parm_type, Pname namep) ;
  void collect(Pname namep) ;

  void enter_parameters() ;
  void introduce_class_templ(Pname cnamep) ;
  void end(Pname class_name) ;
  Pname forward_declaration(Pname class_name) ;
  void instantiate_ref_templ() ;
  void clear_ref_templ() ;

  Pname check_tname(Pname p) ;
  bool  current_template(Pname p, Pexpr actuals) ;
  Ptempl is_template(Pname p) ;
  Ptempl is_template(char *s);
  void end_of_compilation() ;   // Done with compilation, instantiate bodies
  templ_compilation()  ;

  static Pname tree_parameter(char *s) ; // return true if the name is a tree parameter

private:
  void append_parameter(Pname p) ;
  
} ;



// The canonical template_compilation instance. templ_compilation exists as a
// class simply to provide a code and data packaging mechanism. There is
// exactly one generated instance of it.

extern templ_compilation *templp ;

// should actually be static member functions of templ_compilation
Pname parametrized_typename (Pname p, Pexpr actuals) ;
Pbase parametrized_basetype (Pname p, Pexpr actuals) ;




// the basis for class and member function templates
class basic_template {
  friend templ_compilation ;
protected:
  Plist       formals ;        // The formal arguments to the template
  Pcons       templ_refs ;     // The templates referenced by this template

  // check class constraints placed on formals while processing member
  // function bodies. 
  bool check_constraints(Pexpr actuals) ;
  
  // ensure that use of formals is consistent across, class, member and
  // forward declarations
  void check_formals(Plist formals) ;

public:
  // used to order template class definitions for instantiations. Not being
  // used as yet.
  int        definition_number ;

  // used to generate the definition numbers, used by the above member.
  static int definition_tick ;
	 
  Plist get_formals() {return formals ;}
} ;



// the template for a class
class templ  : public basic_template { 
  Pbase       basep ;          // COBJ basetype for the template
  Ptempl_inst insts  ;         // instantiations of the template
  Pfunt       fns  ;           // member function declarations
  Pfunt       fns_end ;        // last fun in the above list
  
  // Use these state variables to set up the correct state for error
  // processing. They are used by the "error" routines for statement numbers.
  Pname       Cdcl ;
  Pstmt       Cstmt ;
  
  friend templ_inst ;
  friend function_template ;

  // used to detect loops during instantiation; a count greater than two is
  // indicative of a non-terminating instantiation sequence
  int         open_instantiations ;
  
  Ptempl_inst get_match(Pexpr actuals,
			Ptempl_inst exclude,
			bool match_instantiated_only) ;
  bool check_actual_args (Pexpr actuals) ;

public:
  Ptempl      next ;           // connects all the class templates in the comp
  Pname       namep ;          // the TNAME for the template class
  bool        defined ;        // the actual definition, not just a forward
  			       // declaration has been seen.

  Pname       members ;        // note the members to catch redefinition errors

  Ptempl_inst get_inst(Pexpr actuals, Ptempl_inst exclude = 0) ;
  templ(Plist parms, Pname p) ;
  void resolve_forward_decl(Plist parms, Pclass c) ;
  void instantiate_forward_decl() ;
  
  // The uninstantiated base type
  Pbase basetype() {return basep; }
  // The basetype for a specific instantiation
  Pbase inst_basetype(Pexpr actuals) ;

  Pname typename(Pexpr actuals) ;
  
  Pfunt collect_function_member(Pname fname) ;
  bool  has_tree_expr_formals() ;
  bool instantiate_bodies() ;
} ;



// Member function templates
class function_template : public basic_template {
  Pname       fn ;             // The name of the member function
  Pfunt       next ;           // connects the list of member functions

  friend templ ;
  friend templ_inst ;

public:
  function_template (templ & owner, Plist params, Pname n) ;
} ;



// compiler internal expression templates, used to implement Objectstore constructs
class tree_template : public basic_template {
  TOK         kind ;          // STATEMENT or EXPRESSION
  Pnode       e ;             // the post-syntax tree representing the
			      // expression or statement constituting the
                              // template.
  Ptreet      next ;          // the next expression template
  static      int count ;     // the number of instantiations
				 
public:
  char        *string ;       // the name used for template lookup
  tree_template(TOK tree_kind, char *s, Plist params, Pnode tree,
		Pcons references) ;
  static  Ptreet get(char *s) ;
  Pname   get_parameter(char *s) ;
  static  void test() ;
  Pexpr expand(Pexpr actuals) ;
} ;




// Global state variables that must be saved around an instantiation. The
// saving of state was required in the implementstion that interspersed decl
// processing and instantiation, rather than the current strategy, which only
// forces instantiations at the top level outside of any dcl-processing
// context. It is retained in case we ever go back to the "interspersed" style
// of instantiation. 
class state {

public:
  Pname       Cdcl ;      // the global variables used by the error routines
  Pstmt       Cstmt ;
  Pname       dcl_list ;  // Holds the list of typedef names that are hidden
  Loc         curloc ;
  
  int         curr_file ;
  Pexpr       curr_expr ;
  Pin         curr_icall ;
  Pstmt       curr_loop;
  Pblock      curr_block;
  Pstmt       curr_switch;

  int         bound  ;   
  int         inline_restr ;
  Loc         last_line ;

  int         no_of_badcall;
  int         no_of_undcl ;
  
  Pname       badcall ;
  Pname       undcl ;

  state() {} ; // prevent used before set warnings.
  void save() ;
  
  void init() ; 
  void restore() ; 
} ;


class pointer_hash ; 
class tree_copy_info ;


// A template starts out being uninstantiated, and is class_instantiated when
// there is a refrence to it with actual arguments. It is body_instantiated at
// the end of compilation, when all its function members are instantiated.
enum inst_status { uninstantiated, class_instantiated, body_instantiated };

// templ_inst captures the arguments used in the instantiation of a template.
// These instantiations are rooted in the templ object. 
class templ_inst {
  
  friend class template_instantiation ;

  Pname      tname ;         // The instantiation name, it is the TNAME that
                             // leads up to an actual instantiation of the class
  Pname      namep ;         // The version of TNAME in the ktbl
  Pexpr      actuals ;       // instantiation arguments, chained using ELIST
			     // as an expression "cons" node, e1 is the car
			     // and e2 the cdr. The car points to a name node.
  Ptempl_inst next ;         // The linked list of instantiations for this
                             // template.
  Ptempl_inst next_active ;  // The list of currently active instantiations.
  state       context ;      // the context of this instantiation
  Ptempl_inst forward ;      // This instantiation is the same as the one
                             // pointed to.

  // Contains the list of global names that are hidden during an
  // instantiation.
  Plist hidden_globals ;

  // The class correspondence table. This table is initialized 
  // when the class definition is instantiated. Subsequently, it is used to
  // initial member correspondence tables before the copy process is
  // initiated.
  pointer_hash        *corr ;

  // the instantiation's copy of the formals
  Plist  inst_formals ;
       
  inst_status status ;
  
  friend class templ ;
  friend class templ_classdef ;
  friend class tree_template ;
  friend Pcons make_ref_copy(pointer_hash &h, tree_copy_info &info,
			     Pcons old_templ_refs);
  
  templ_inst (Pexpr act,  Ptempl owner) ;
  bool actuals_match(Pexpr check_actuals) ;
  void instantiate_match(Ptempl_inst match) ;
  void kludge_copy(Pbase source_base) ;
  // create a copy of the class type subtree preparatory to the ensuing
  // instantiation. Return a non-zero value, only if there was no need to
  // create a copy, ie. an identical instantiation already existed.
  Ptempl_inst class_copy(Pcons &templ_refs, bool recopy) ;
  Pcons ref_copy(pointer_hash &h, tree_copy_info &info, Pcons old_templ_refs) ;
    
  // save and restore state around the template instantiation
  void save_state(Pname p) ;
  void restore_state() ;
  
  // Used to collect references to this template by a definition
  Ptempl_inst note_ref() ;
  char *instantiation_string() ;
  
  void expose_parameter_names() ;
  void hide_parameter_names() ;
  
public:
  Ptempl        def ;           // The template definition, for which this is an
			     // instantiation.
  bool         refp ;        // A flag used to note template references during
			     // a C++ definition
  void print_error_loc() ;   // Wants to be a static function
  // Bind the formals before an instantiation
  void bind_formals() ;

  Ptempl_inst canonical_instantiation() {
    return ( forward ? forward : this ) ;
  }

  // get the class associated with this instantiation
  Pclass get_class() { return Pclass(Pbase(tname->tp)->b_name->tp) ;}
			      
  void instantiate(bool reinstantiate = false) ;
  static Ptempl_inst head ;  // Head of the list of active instantiations.
  void print_pretty_name() ;
  char *mangled_name(char *buffer) ;
  // The uninstantiated basetype
  Pbase def_basetype() { return def->basep ; } ;
  // A general way of determining whether two template instantiations are
  // the same
  bool  same(Ptempl_inst t) ;
  bool copy_hook(Pnode&) ;
  // return a copy of the function tree starting with it's name
  Pname function_copy(Pfunt fnt, Pcons &templ_refs) ;

  // special check for instantiations used in qualifiers for template function
  // member declarations. 
  bool check_qualifier(Plist formals) ;
  Pname get_parameter(char *s) ;
} ;



// Experimental debugging toggle
extern int zdebug  ;


// The class node used for template classes.
// Rep invariant:
// class_base == uninstantiated_template_class ||
// class_base  == instantiated_template_class

class templ_classdef : public classdef {
public:
  Ptempl_inst inst ;              // a pointer to the instantiation; the
				  // instantiation also points back to it via
                                  // the tname ->cobj->name->class path
  templ_classdef(Ptempl_inst i) ;
  Pname unparametrized_tname() { return inst->def->namep ; } 
  void instantiate() { inst->instantiate() ; }

} ;


// Safe accessor functions for navigating through COBJ base classes

extern class_type_enum get_class_base (Pbase b) ;

extern Ptclass get_template_class (Pbase b) ;

extern Ptempl_inst get_templ_inst(Pbase b) ;
 

/*
   $Log: cfront.cpio,v $
   Revision 1.1.1.1  2018/04/24 17:21:35  root
   researchv10 Norman

 * Revision 1.4  90/04/02  11:31:35  sam
 * Made comments current.
 * 
 * Revision 1.3  90/03/30  18:50:55  sam
 * 1) Added the introduce_class_templ member function to the templ_compilation 
 * class.
 * 2) Rationalized the definition of class templ. Made basic_template be it's
 * base class, instead of type. The latter was the base type, simply so that
 * it could be stored in a table associating strings with types. Don't have
 * to resolve to such kludgery in the PT world.
 * 3) Added the member open_instantiations to detect non-terminating
 * instantiations
 * 
 * Revision 1.2  90/03/27  10:16:27  sam
 * > Merged in revision 1.13 from the main line of development 
 * 
 * Revision 1.1  89/11/20  08:50:58  benson
 * Initial revision
 * 
 * Revision 1.11  89/10/16  15:25:00  sam
 * use pointer_hash rather than Hash as the type of the correspondence table.
 * 
 * Revision 1.10  89/09/26  16:44:34  sam
 * fix the forward declaration of template classes
 * 
 * Revision 1.9  89/09/18  16:37:37  sam
 * provide for error recovery upon argument mismatch in a template instantiation
 * 
 * 
 * Revision 1.8  89/09/15  09:31:50  benson
 * move tree_template.string into the public section.
 * 
 * Revision 1.7  89/08/30  13:02:12  sam
 * added support for dealing with __expressions in class formal templates
 * 
 * Revision 1.6  89/08/28  09:42:05  sam
 * Support for nested references in internal templates. These nested 
 * references are instantiated whenever an expansion takes place.
 * 
 * Revision 1.5  89/08/23  10:26:00  sam
 * support for BS style formal syntax. refer to 1.5 templates.c for more 
 * detailed comments.
 * 
 * Revision 1.4  89/08/11  14:57:09  sam
 *  implementation of multiple instantiation templates.
 * 
 * Revision 1.3  89/07/27  11:33:40  sam
 * the comments in template.c 1.3 describe the modifications.
 * 
 * Revision 1.2  89/07/07  14:34:11  sam
 * Added the templ_classdef::unparametrized_type_name() function member, as part
 * of the base init fix.
 * 
 * Revision 1.1  89/06/29  09:21:32  benson
 * Initial revision
 * 
 * Revision 1.1  89/06/22  16:29:29  sam
 * Initial revision
 * 


   end_log
*/



/*
   $Log $


   end_log
*/
0707071010112045701004440001630000160000010210100466055411600001000000012452token.h/*ident	"@(#)ctrans:src/token.h	1.4" */
/**************************************************************************

	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.

token.h:

*****************************************************************************/
/*
#ifndef PRESAFE
extern "C" {
#endif

extern void free(char*);			// alloc.h
extern char* malloc(unsigned);
extern char* calloc(unsigned, unsigned);

extern strncmp(const char*, const char*, const);	// string.h
extern strcmp(const char*, const char*);
extern int strlen(const char*);
extern char* strcpy(char*, const char*);

#ifdef apollo
	extern void set_sbrk_size(int);
#endif

#ifndef PRESAFE
}
#endif
*/

#include <malloc.h>
#include <string.h>
#include <stdio.h>

extern void lex_clear();
extern void otbl_init();

//#define yylex()	lalex()

#define putstring(s)	fputs(s,out_file)
#define putst(s)	(fputs(s,out_file),putc(' ',out_file))
#define putch(c)	putc(c,out_file)
#define putcat(c,s)	(putc(c,out_file),fputs(s,out_file))

			/* token numbers for C parser	*/

#define MAXTOK 255
extern char* keys[MAXTOK+1];

#define EOFTOK	0	/* 	EOF	*/
			/* keywords in alphabetical order */
#define ASM		1
#define AUTO		2
#define BREAK		3
#define CASE		4
#define CHAR		5
#define CLASS		6
#define CONTINUE	7
#define DEFAULT		8
#define DELETE		9
#define DO		10
#define DOUBLE		11
#define ELSE		12
#define ENUM		13
#define EXTERN		14
#define FLOAT		15
#define FOR		16
#define FORTRAN		17
#define FRIEND		18
#define GOTO		19
#define IF		20
#define INT		21
#define LONG		22
#define NEW		23
#define OPERATOR	24
#define PUBLIC		25
#define CONST		26
#define REGISTER	27
#define RETURN		28
#define SHORT		29
#define SIZEOF		30
#define STATIC		31
#define STRUCT		32
#define SWITCH		33
#define THIS		34
#define TYPEDEF		35
#define UNION		36
#define UNSIGNED	37
#define VOID		38
#define WHILE		39

			/* operators in priority order (sort of) */
#define LP		40
#define RP		41
#define LB		42
#define RB		43
#define REF		44
#define DOT		45
#define NOT		46
#define COMPL		47
#define INCR		48
#define DECR		49
#define MUL		50
#define DIV		51
#define AND		52
#define MOD		53
#define PLUS		54
#define MINUS		55
#define LS		56
#define RS		57
#define LT		58
#define LE		59
#define GT		60
#define GE		61
#define EQ		62
#define NE		63
#define ER		64
#define OR		65
#define ANDAND		66
#define OROR		67
#define QUEST		68
#define COLON		69
#define ASSIGN		70
#define CM		71
#define SM		72
#define LC		73
#define RC		74

#define INLINE		75
#define OVERLOAD	76
#define VIRTUAL		77
#define COERCE		78
#define PROTECTED	79

			/* constants etc. */
#define ID		80
#define STRING		81
#define ICON		82
#define FCON		83
#define CCON		84
#define NAME		85
#define ZERO		86

			/* groups of tokens */
#define ASOP		90	/* op= */
#define RELOP		91	/* LE GE LT GT */
#define EQUOP		92	/* EQ NE */
#define DIVOP		93	/* DIV MOD */
#define SHIFTOP		94	/* LS RS */
#define ICOP		95	/* INCR DECR */
#define UNOP		96	/* NOT COMPL */
#define TYPE		97
	/* TYPE =	INT FLOAT CHAR DOUBLE REGISTER STATIC EXTERN AUTO
			LONG SHORT UNSIGNED INLINE FRIEND VIRTUAL */

			/* new tokens generated by syn() */
#define UMINUS		107
#define FCT		108
#define CALL		109
#define VEC		110
#define DEREF		111
#define ADDROF		112
#define CAST		113
//#define ENDCAST		122
#define FIELD		114
#define LABEL		115
#define BLOCK		116
//#define QUA		117
#define DCL		118	/* local declaration statement */
#define COBJ		119
#define EOBJ		121
#define TNAME		123
#define ILIST		124
#define PTR		125

#define ASPLUS		126
#define ASMINUS		127
#define ASMUL		128
#define ASDIV		129
#define ASMOD		130
#define ASAND		131
#define ASOR		132
#define ASER		133
#define ASLS		134
#define ASRS		135

#define ARG		136
#define ARGS		137
#define ZTYPE		138
#define ARGT		139
#define ELIST		140
#define ANY		141
#define TABLE		142
#define LOC		143
#define DUMMY		144
#define G_ADDROF	145
#define G_CALL		146
#define G_CM		147
#define IVAL		150
//#define FVAL		151
//#define LVAL		152
#define ELLIPSIS	155
#define AGGR		156
#define VALUE		157	/* constructor call */
#define RPTR		158	/* reference */
#define HIDDEN		159
#define MEM		160
#define CTOR		161
#define DTOR		162
#define CONST_PTR	163
#define CONST_RPTR	164
#define TEXT		165
#define PAIR		166
#define ANON		167
#define ICALL		168
#define ANAME		169
#define VOLATILE	170
#define SIGNED		171
#define UPLUS		172
#define MEMPTR		173
#define PRIVATE		174
#define PR		175	/* PUBLIC PRIVATE or PROTECTED */
#define MDOT		177
#define TSCOPE		178
#define DECL_MARKER	179
#define REFMUL		180
#define LDOUBLE		181
#define LINKAGE         182
#define LOCAL		183
#define GNEW		184
#define TEMPLATE	185
#define STAT_INIT	186
#define CATCH		187
#define GDELETE		188
//#define CONVERT	189
#define NESTED		190
#define TRY		191

// class parameterized types constants
#define XVIRT	         200 /* class virt */
#define XNLIST		 201 /* struct name_list */
#define XILINE		 202
#define XIA		 203
#define STATEMENT        205
#define EXPRESSION       206
#define SM_PARAM         207 
#define TEMPLATE_TEST    208
#define PTNAME           209
#define NEW_INIT_KLUDGE  210
#define XDELETED_NODE    211
#define DUMMY_LAST_NODE  212

//#define SYN	1
//#define TYP	2
//#define SIMPL	3
//#define ERROR	4

//#define ICTOR 88
//#define IDTOR 89
0707071010112046131004440001630000160000010212340466055422200001600000006724token_names.h/* ident "@(#)ctrans:src/token_names.h	1.2" */
struct _token_name { char * string; int val; } token_names [] = {
	{ "EOFTOK",	0 },
	{ "ASM",	1 },
	{ "AUTO",	2 },
	{ "BREAK",	3 },
	{ "CASE",	4 },
	{ "CHAR",	5 },
	{ "CLASS",	6 },
	{ "CONTINUE",	7 },
	{ "DEFAULT",	8 },
	{ "DELETE",	9 },
	{ "DO",	10 },
	{ "DOUBLE",	11 },
	{ "ELSE",	12 },
	{ "ENUM",	13 },
	{ "EXTERN",	14 },
	{ "FLOAT",	15 },
	{ "FOR",	16 },
	{ "FORTRAN",	17 },
	{ "FRIEND",	18 },
	{ "GOTO",	19 },
	{ "IF",	20 },
	{ "INT",	21 },
	{ "LONG",	22 },
	{ "NEW",	23 },
	{ "OPERATOR",	24 },
	{ "RETURN",	28 },
	{ "PUBLIC",	25 },
	{ "CONST",	26 },
	{ "REGISTER",	27 },
	{ "RETURN",	28 },
	{ "SHORT",	29 },
	{ "SIZEOF",	30 },
	{ "STATIC",	31 },
	{ "STRUCT",	32 },
	{ "SWITCH",	33 },
	{ "THIS",	34 },
	{ "TYPEDEF",	35 },
	{ "UNION",	36 },
	{ "UNSIGNED",	37 },
	{ "VOID",	38 },
	{ "WHILE",	39 },
	{ "LP",	40 },
	{ "RP",	41 },
	{ "LB",	42 },
	{ "RB",	43 },
	{ "REF",	44 },
	{ "DOT",	45 },
	{ "NOT",	46 },
	{ "COMPL",	47 },
	{ "INCR",	48 },
	{ "DECR",	49 },
	{ "MUL",	50 },
	{ "DIV",	51 },
	{ "AND",	52 },
	{ "MOD",	53 },
	{ "PLUS",	54 },
	{ "MINUS",	55 },
	{ "LS",	56 },
	{ "RS",	57 },
	{ "LT",	58 },
	{ "LE",	59 },
	{ "GT",	60 },
	{ "GE",	61 },
	{ "EQ",	62 },
	{ "NE",	63 },
	{ "ER",	64 },
	{ "OR",	65 },
	{ "ANDAND",	66 },
	{ "OROR",	67 },
	{ "QUEST",	68 },
	{ "COLON",	69 },
	{ "ASSIGN",	70 },
	{ "CM",	71 },
	{ "SM",	72 },
	{ "LC",	73 },
	{ "RC",	74 },
	{ "INLINE",	75 },
	{ "OVERLOAD",	76 },
	{ "VIRTUAL",	77 },
	{ "COERCE",	78 },
	{ "PROTECTED",	79 },
	{ "ID",	80 },
	{ "STRING",	81 },
	{ "ICON",	82 },
	{ "FCON",	83 },
	{ "CCON",	84 },
	{ "NAME",	85 },
	{ "ZERO",	86 },
	{ "ICTOR",	88 },
	{ "IDTOR",	89 },
	{ "ASOP",	90 },
	{ "RELOP",	91 },
	{ "EQUOP",	92 },
	{ "DIVOP",	93 },
	{ "SHIFTOP",	94 },
	{ "ICOP",	95 },
	{ "UNOP",	96 },
	{ "TYPE",	97 },
	{ "UMINUS",	107 },
	{ "FCT",	108 },
	{ "CALL",	109 },
	{ "VEC",	110 },
	{ "DEREF",	111 },
	{ "ADDROF",	112 },
	{ "CAST",	113 },
	{ "FIELD",	114 },
	{ "LABEL",	115 },
	{ "BLOCK",	116 },
	{ "QUA",	117 },
	{ "DCL",	118 },
	{ "COBJ",	119 },
	{ "EOBJ",	121 },
	{ "TNAME",	123 },
	{ "ILIST",	124 },
	{ "PTR",	125 },
	{ "ASPLUS",	126 },
	{ "ASMINUS",	127 },
	{ "ASMUL",	128 },
	{ "ASDIV",	129 },
	{ "ASMOD",	130 },
	{ "ASAND",	131 },
	{ "ASOR",	132 },
	{ "ASER",	133 },
	{ "ASLS",	134 },
	{ "ASRS",	135 },
	{ "ARG",	136 },
	{ "KNOWN",	137 },
	{ "ZTYPE",	138 },
	{ "ARGT",	139 },
	{ "ELIST",	140 },
	{ "ANY",	141 },
	{ "TABLE",	142 },
	{ "LOC",	143 },
	{ "DUMMY",	144 },
	{ "G_ADDROF",	145 },
	{ "G_CALL",	146 },
	{ "G_CM",	147 },
	{ "IVAL",	150 },
	{ "FVAL",	151 },
	{ "LVAL",	152 },
	{ "ELLIPSIS",	155 },
	{ "AGGR",	156 },
	{ "VALUE",	157 },
	{ "RPTR",	158 },
	{ "HIDDEN",	159 },
	{ "MEM",	160 },
	{ "CTOR",	161 },
	{ "DTOR",	162 },
	{ "CONST_PTR",	163 },
	{ "CONST_RPTR",	164 },
	{ "TEXT",	165 },
	{ "PAIR",	166 },
	{ "ANON",	167 },
	{ "ICALL",	168 },
	{ "ANAME",	169 },
	{ "VOLATILE",	170 },
	{ "SIGNED",	171 },
	{ "UPLUS",	172 },
	{ "MEMPTR",	173 },
	{ "PRIVATE",	174 },
	{ "PR",	175 },
	{ "MDOT",	177 },
	{ "TSCOPE",	178 },
	{ "DECL_MARKER",	179 },
	{ "REFMUL",	180 },
	{ "LDOUBLE",	181 },
	{ "LINKAGE",	182 },
	{ "LOCAL",	183 },
	{ "GNEW",	184 },
	{ "TEMPLATE",	185 },
	{ "STAT_INIT",	186 },
	{ "CATCH",	187 },
	{ "GDELETE",	188 },
	{ "CONVERT",	189 },
	{ "XVIRT",	200 },
	{ "XNLIST",	201 },
	{ "XILINE",	202 },
	{ "XIA",	203 },
	{ "STATEMENT",	205 },
	{ "EXPRESSION",	206 },
	{ "SM_PARAM",	207 },
	{ "TEMPLATE_TEST",	208 },
	{ "PTNAME",	209 },
	{ "NEW_INIT_KLUDGE", 210 },
	{ "XDELETED_NODE",	211 },
	{ "DUMMY_LAST_TOKEN",	212 },
};
0707071010112045711004440001630000160000010156650466055412200001100000002515tqueue.h/*ident	"@(#)ctrans:src/tqueue.h	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.

tqueue.h:

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

#ifndef EOF
#include <stdio.h>
#endif

struct toknode {
	TOK      tok;			/* token for parser */
	bit      used;			/* token has been processed by lalex() */
	YYSTYPE  retval;			/* $arg */
	loc      place;
	toknode* next;
	toknode* last;
	static toknode* free_toks;
	void*   operator new(size_t);
	void    operator delete(void*,size_t);
		toknode(TOK,YYSTYPE,loc);
};
extern toknode* front;
extern toknode* rear;

extern void addtok(TOK,YYSTYPE,loc);	/* add tok to rear of Q */
extern TOK deltok(int);			/* take tok from front of Q */
extern TOK tlex();

// interface to parser
extern TOK lalex();
extern int yychar;
extern YYSTYPE yylval;
extern TOK	la_look();
extern void	la_backup( TOK, YYSTYPE );
extern int	la_cast();
extern void	check_decl();
extern void	check_cast();
extern TOK	lalex();

// save / restore implicit inline functions
extern toknode*	save_text();
extern void	restore_text();
0707071010112046041004440001630000160000010211700466055416700001400000014274tree_copy.c/* ident "@(#)ctrans:src/tree_copy.c	1.3" */
/*
	$Source: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v $ $RCSfile: cfront.cpio,v $
	$Revision: 1.1.1.1 $		$Date: 2018/04/24 17:21:35 $
	$Author: root $		$Locker:  $
	$State: Exp $
*/
 
/* utilities to copy pieces of cfront trees. 
   what we have here is a somewhat parameterizable
   action procedure for the tree walker.

   We may make more versions of this for template expansion
   and saving things in files, or we may just make it possible
   for this to swing more ways. 
*/

#include "cfront.h"
#include "tree_walk.h"
#include "tree_copy.h"
#include <memory.h>

/* determine whether "n" is a an already defined type */
static unsigned int type_is_defined(Pnode n) {
  return (Ptype(n)->defined & DEFINED) ;
}

void
copy_walker (Pnode& node, node_class cl, void * info, 
	     tree_node_action& action, int, Pnode, tree_walk_tree&,
	     int& register_in_hash)
{
    union {
	Pnode node;
	Pvirt vr;
	Plist list;
	Pgen g;
	Pvec vc;
	Pfct f;
	Ptable t;
	Pbase  bt;
	Pexpr  x;
	Pstmt  s;
	Penum  e;
	Pclass c;
	Pbcl   bcl;
	Pin    iline;
	ia   * ia;
	Pname  n;
	Pptr p;
      } n;
    Pnode original_node = node;

    tree_copy_info * tci = (tree_copy_info *)info;
    action = tna_continue;

    /* first, give an application-specific hook a shot at the node. */

    tci->check_node(node, cl, action, register_in_hash);
    if(action != tna_continue) return;    

    if(node != original_node) { /* a replacement */
      n.node = node;
    } else /* ok, nothing funny, we just go ahead and copy */
      switch (cl) {
      default:
	break;	
      case nc_eof:
	n.node = Pnode(tci->malloc(sizeof (node)));
	*n.node = *node;
	goto Replace;

      case nc_virt:
	n.vr = Pvirt(tci->malloc(sizeof(virt)));
	*n.vr = *Pvirt(node);
	goto Replace;

      case nc_nlist:
	n.list = Plist(tci->malloc(sizeof(name_list)));
	*n.list = *Plist(node);
	goto Replace;

      case nc_gen:
	n.g = Pgen(tci->malloc(sizeof(gen)));
	*n.g = *Pgen(node);
	goto Replace;

      case nc_vec: 
	n.vc = Pvec(tci->malloc(sizeof(vec)));
	*n.vc = *Pvec(node);
	goto Replace;

      case nc_ptr:
	n.p = Pptr(tci->malloc(sizeof(ptr)));
	*n.p = *Pptr(node);
	goto Replace;

      case nc_fct:
	n.f = Pfct(tci->malloc(sizeof(fct)));
	*n.f = *Pfct(node);
	if(n.f->f_signature) {
	    n.f->f_signature =
		(char *)tci->malloc(strlen(Pfct(node)->f_signature)+1);
	    strcpy(n.f->f_signature, Pfct(node)->f_signature);
	};
	goto Replace;

      case nc_table:
	n.t = Ptable(tci->malloc(sizeof(table)));
	*n.t = *Ptable(node);
	n.t->entries = (Pname *)tci->malloc(sizeof(Pname) * n.t->size);
	memcpy((char *)n.t->entries, (char *)Ptable(node)->entries, n.t->size * sizeof(Pname));
	n.t->hashtbl = (short *)tci->malloc(sizeof(short) * n.t->hashsize);
	memcpy((char *)n.t->hashtbl, (char *)Ptable(node)->hashtbl, n.t->hashsize * sizeof (short));
	goto Replace;

      case nc_basetype:
	// Don't copy types that have already been dealt with
	if (type_is_defined(node)) {
	  action = tna_stop ;
	  return ;
	}
	n.bt = Pbase(tci->malloc(sizeof(basetype)));
	*n.bt = *Pbase(node);
	if(n.bt->discriminator(0) == 2 && n.bt->b_linkage) {
	    n.bt->b_linkage = tci->malloc(strlen(n.bt->b_linkage) + 1);
	    strcpy(n.bt->b_linkage, Pbase(node)->b_linkage);
	}
	goto Replace;

      case nc_expr:
	// cfront needs identity maintaied for these nodes
	if ((node == dummy) || (node == zero)) {
	  action = tna_stop ;
	  return ;
	}
	n.x = Pexpr(tci->malloc(sizeof(expr)));
	*n.x = *Pexpr(node);
	if(n.x->discriminator(1) == 3 && n.x->string) {
	    n.x->string = tci->malloc(strlen(n.x->string) + 1);
	    strcpy(n.x->string, Pexpr(node)->string);
	}
	if(n.x->discriminator(2) == 3 && n.x->string2) {
	    n.x->string2 = tci->malloc(strlen(n.x->string2) + 1);
	    strcpy(n.x->string2, Pexpr(node)->string2);
	}
	goto Replace;

      case nc_stmt:
	n.s = Pstmt(tci->malloc(sizeof(stmt)));
	*n.s = *Pstmt(node);
	goto Replace;

      case nc_enumdef:
	if (type_is_defined(node)) {
	  action = tna_stop ;
	  return ;
	}
	n.e = Penum(tci->malloc(sizeof(enumdef)));
	*n.e = *Penum(node);
	if(n.e->string) {
	    n.e->string = tci->malloc(n.e->strlen+1);
	    strcpy(n.e->string, Penum(node)->string);
	}
	goto Replace;

      case nc_classdef:
	// Don't copy types that have already been dealt with
	if (type_is_defined(node)) {
	  action = tna_stop ;
	  return ;
	}
	n.c = Pclass(tci->malloc(sizeof(classdef)));
	*n.c = *Pclass(node);
	if(n.c->string) {
	    n.c->string = tci->malloc(strlen(n.c->string)+1);
	    strcpy(n.c->string, Pclass(node)->string);
	}
	goto Replace;

      case nc_baseclass:
	n.bcl = Pbcl(tci->malloc(sizeof(struct basecl)));
	*n.bcl = *Pbcl(node);
	goto Replace;

      case nc_iline:
	n.iline = Pin(tci->malloc(sizeof(iline)));
	*n.iline = *Pin(node);
	goto Replace;

      case nc_ia:
	n.ia = (ia *)tci->malloc(sizeof(ia));
	*n.ia = *(ia *)node;
	goto Replace;

      case nc_name:
	/* check for globalosity */
	if(Pname(node)->string && (node == (node->base == TNAME ? ktbl : gtbl)->look(Pname(node)->string, 0))) {
	    action = tna_stop;
	    return;
	}
	n.n = Pname(tci->malloc(sizeof(name)));
	*n.n = *Pname(node);
/* First, hack exprosity */
	if(n.x->discriminator(1) == 3 && n.n->string) {
	    n.n->string = tci->malloc(strlen(n.n->string) + 1);
	    strcpy(n.n->string, Pexpr(node)->string);
	}
	if(n.x->discriminator(2) == 3 && n.n->string2) {
	    n.n->string2 = tci->malloc(strlen(n.n->string2) + 1);
	    strcpy(n.n->string2, Pexpr(node)->string2);
/* ok, name stuff */
	}
	if(n.n->n_anon) {
	    n.n->n_anon = tci->malloc(strlen(n.n->n_anon)+1);
	    strcpy(n.n->n_anon, Pname(node)->n_anon);
	}
	if(n.n->n_template_arg_string) {
	    n.n->n_template_arg_string =
		tci->malloc(strlen(n.n->n_template_arg_string)+1);
	    strcpy(n.n->n_template_arg_string, Pname(node)->n_template_arg_string);
	}
    }
  Replace:
    node = n.node;
    action = tna_continue;
    return;
}

static int call_error (int i, const char * s)
{
    return error (i, s);
}

void
copy_tree (Pnode& node, tree_copy_info& tci, Hash * cht)
{
    tree_walk_control twc;

    twc.call_i_error = 1;
    twc.i_error = call_error; /* ... in type of error confuses compiler */
    twc.action_proc = copy_walker;
    twc.nodes_seen_hash = cht;
    twc.callback_info = (void *)&tci;

    walk_tree (twc, node);
}

0707071010112046141004440001630000160000010210160466055422600001400000003011tree_copy.h/* ident "@(#)ctrans:src/tree_copy.h	1.2" */
/* -*- Mode: C -*- begin include file tree_copy.H 
   argument class for copying trees. */

#include "hash.h"
#include "tree_walk.h"

/* The copier procedure expects one of these as its 
    info pointer */

class tree_copy_info {
  public:
/* If non-zero, this procedure is called at each node.
   it returns an action. It cannot currently return
   a node of a different class and also return an
   action other than tna_stop, since the walker won't
   notice that the rug has been removed from beneath its feet. 
   The procedure must set the last argument to indicate whether
   or not to register the node in the hash table and use the
   replacement every future time it is encountered.
*/

    void (* node_hook) (void * info, Pnode&, node_class, tree_node_action&,
			int&);

    /* if this is nonzero it is used to allocate space for
       the copies. We don't run constructors since we always
       bit copy over the new copy. */
    char * (* malloc_hook) (void * info, size_t);
    void * hook_info;
    tree_copy_info ()
	{
	    hook_info = 0;
	    node_hook = 0;
	    malloc_hook = 0;
	}; 
    char * malloc (size_t s) {
	return malloc_hook ? malloc_hook(hook_info, s) : ::malloc (s);
    };
    void check_node (Pnode& n,
		     node_class cl, 
		     tree_node_action& action, 
		     int& never_see_again) {
	if(node_hook)
	    node_hook(hook_info, n, cl, action, never_see_again);
    };
};

void copy_tree (Pnode& n, tree_copy_info& tci, Hash * cht = 0);

/* End tree_copy.H */

0707071010112046161004440001630000160000010213300466055423500001400000061200tree_dump.c/* ident "@(#)ctrans:src/tree_dump.c	1.2" */
/* -*- Mode:C++ -*- */
/* tree_dump.C -- utilities for displaying the cfront tree. */
/* BIM 890530 */
/* rewritten 890712 to use the tree-walking facilities */

/*
	$Source: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v $ $RCSfile: cfront.cpio,v $
	$Revision: 1.1.1.1 $		$Date: 2018/04/24 17:21:35 $
	$Author: root $		$Locker:  $
	$State: Exp $


*/

#include "tree_dump.h"
#include <stdio.h>
#include <malloc.h>
#include "template.h"
#include "token_names.h"

const int Indent_Increment = 4;
static char badnamebuf[100];

char *
token_name(TOK t)
{
    char * bnb = badnamebuf;

    if((int) t == -1) return "-1";
    if(t > DUMMY_LAST_NODE) {
bad:
	printf_to_string(bnb, sizeof(badnamebuf), 
			 "<unknown token %d>", (int) t);
	return bnb;
    } 
    int x;
    for (x = 0; x < DUMMY_LAST_NODE; x++) {
	if(token_names[x].val == t) return token_names[x].string;
    }
    goto bad;
}

class displayer{
  public:
    dcn_arg * arg;
    Pnode node;
    Pnode node_address;
    displayer (dcn_arg& d) { arg = &d; indent = 0; print_null_values = 0; };
    void do_node (Pnode& node, node_class cl, tree_node_action& action, int depth, Pnode);
  private:
    enum ppc {print_ptr_copy = 0, print_ptr_copied = 1};
    int indent;
    int err;
    int print_null_values;
    void printf (const char *, ...);
    void catprintf (const char *, ...);
    void print_ptr (const char *, Pnode);
    void print_ptr (Pnode, ppc = print_ptr_copy);
    void minimal ();
    void a_basetype ();
    void a_basecl() ;
    void a_type() ;
    void a_node() ;
    void a_name ();
    void a_expr (int from_name = 0);
    void a_fct ();
    void a_stmt ();
    void a_enumdef ();
    void a_table();
    void a_classdef ();
    void a_gen ();
    void a_vec ();
    void a_ptr ();
    void a_virt ();
    void a_nlist ();
    void a_iline ();
    void a_elist ();
    void a_ia ();
    void a_by_name ();
    void print_loc(loc&);
    void * display_address () { return node_address; }
    void fetch (void * addr, unsigned long length, void *& taddr);
    void fetch_string (void * addr, unsigned long length, void *& taddr);
    void free_fetched(void *);
    void flag (int, const char *);
    void print_string (const char *, void *);
    void print_string_brief (void *);
    void null_field (const char *);
    void nz_printf(const char *format, const int i) ;
    void nz_printf(const char *format, const char *p) ;
    void nz_printf(const char *format, const long l) ;
    void ind();
};

const char many_spaces[] = "                                                                                                                                                                                                        ";

inline void
displayer::ind()
{
    arg->output_stream->write(many_spaces, indent);
}

/* call me for full lines */

void
displayer::printf (const char * format, ...)
{
    va_list args;
    va_start(args, format);

    ind();
    vostream_printf (format, args, *arg->output_stream);
    arg->output_stream->write("\n", 1);
    va_end (args);
}

void
displayer::catprintf (const char * format, ...)
{
    va_list args;
    va_start(args, format);

    vostream_printf (format, args, *arg->output_stream);
    va_end (args);
}

void
displayer::minimal ()
{
    print_ptr(node, print_ptr_copied);
}    

void
displayer::print_ptr(const char * label, Pnode node)
{
    if(node || print_null_values) {
	ind();
	catprintf("%s:\t", label);
	print_ptr(node);
	catprintf("\n");
    }
}


void
displayer::print_ptr(Pnode node, ppc copy_ptr)
{
    void * string = 0;
    void * ncopy;
    void * na = (void *)node;

    if(node) {

	if(copy_ptr == print_ptr_copy) {
	    fetch(na, sizeof(node), ncopy);
	    node = Pnode(ncopy);
	} else ncopy = node;

	switch(node->base) {
	case CLASS:
	    free_fetched(ncopy);
	    fetch(na, sizeof(classdef),ncopy);
	    node = Pnode(ncopy);
	    string = Pclass(node)->string;
	    break;
	case ENUM:
	    free_fetched(ncopy);
	    fetch(na, sizeof(enumdef),ncopy);
	    node = Pnode(ncopy);
	    string = Penum(node)->string;
	    break;
	case NAME:
	case TNAME:
	case PUBLIC:
	case PROTECTED:
	    if(!node->baseclass) {
		free_fetched(ncopy);
		fetch(na, sizeof(name),ncopy);
		node = Pnode(ncopy);
		string = Pname(node)->string;
	    }
	    break;
	}
	if(string) {
	    catprintf("<%s |0x%p ", token_name(node->base), na);
	    print_string_brief(string);
	    catprintf(">");
	}
	else catprintf("<%s |0x%p>", token_name(node->base), na);
	free_fetched (ncopy);
    }
    else catprintf("Null");
}

void
displayer::do_node (Pnode& n, node_class cl, tree_node_action& action,
	 int depth, Pnode na)
{
    int forced_min = 0;
    int printed_min = 0;
    int prune = 0;

    switch(cl) {
      case nc_table:
	if(depth > 0 && !arg->walk_tables)prune = 1;
      case nc_fct:
      case nc_classdef:
      case nc_enumdef:
	if(arg->stop_at_top && depth > 1) prune = 1;
	break;
    }

    if((arg->max_depth > 0) && (depth >= arg->max_depth))
	prune = 1;

    if(prune || arg->max_depth == 0)
	action = tna_stop;
    else action = tna_continue;

    node = n;
    node_address = na;

    if(arg->verbose == dt_brief || prune) {
	printed_min = 1;
	minimal();
    }
    else {
	switch(cl)
	    {
	      default:
	    case nc_unused:
		ostream_printf(*arg->error_stream, "Unknown node %d\n", node->base);
		forced_min = 1;

	    case nc_eof:
		minimal();
		printed_min = 1;
		break;

	    case nc_virt:
		a_virt ();
		break;

	    case nc_nlist:
		a_nlist();
		break;

	    case nc_gen:
		a_gen();
		break;

	    case nc_vec:
		a_vec();
		break;

	    case nc_ptr:
		a_ptr();
		break;

	    case nc_fct:
		a_fct();
		break;

	    case nc_table:
		a_table();
		break;

	    case nc_basetype:
		a_basetype();
		break;

	    case nc_name:
		a_name();
		break;

	    case nc_expr:
		a_expr();
		break;

	    case nc_stmt:
		a_stmt();
		break;

	    case nc_enumdef:
		a_enumdef();
		break;

	    case nc_classdef:
		a_classdef();
		break;

	    case nc_baseclass:
		a_basecl ();
		break;

	    case nc_iline:
		a_iline();
		break;

	    case nc_ia:
		a_ia();
		break;

	    }
	if(printed_min) catprintf(">");
    }
}


void
displayer::flag(int f, const char * n)
{
    if(f)catprintf("%s", n);
}

void
displayer::free_fetched (void * addr)
{
    if (arg->fetcher != null_tfp) /* not in the same address space. */
	free ((char *)addr);
}    


void
displayer::fetch (void * addr, unsigned long length, void *& taddr)
{
    if (arg->fetcher == null_tfp) {	/* in the same address space. */
	taddr = addr;
	err = 0;
    } else {
	taddr = (void *)malloc ((unsigned int)length);
	err = arg->fetcher (arg->fetcher_info,
			    addr,
			    length,
			    0,
			    taddr);
    }
}

void
displayer::fetch_string (void * addr, unsigned long length, void *& taddr)
{
    if (arg->fetcher == null_tfp) {	/* in the same address space. */
	taddr = addr;
	err = 0;
    } else {
	taddr = (void *)malloc ((unsigned int)length);
	err = arg->fetcher (arg->fetcher_info,
			    addr,
			    length,
			    1,
			    taddr);
    }
}

/* Print the field, only if it has a non_zero value, or requested to print */
/* always */
void
displayer::nz_printf(const char *format, const int i)
{
    if (i || print_null_values) {
	printf(format, i) ;
    }
} 

void
displayer::nz_printf(const char *format, const char *p)
{
    if (p || print_null_values) {
	printf(format, (p ? p : "0")) ;
    }
} 


void 
displayer::nz_printf(const char *format, const long i)
{
    if (i || print_null_values) {
	printf(format, i) ;
    }
} 

void 
displayer::a_node() 
{
    struct node &n = *node ;

    nz_printf("$node", n.permanent);
//    nz_printf("n_key:\t%d", (int)n.n_key) ;
    nz_printf("permanent:\t%d", n.permanent) ;
    nz_printf("baseclass:\t%d", n.baseclass) ;
}
  
  

void 
displayer::a_type()
{
    struct type& t = *Ptype(node);
    int show_up =  t.defined  /* || t.inline_temp_index != 0 */;

    if(show_up) {
	printf("$type") ;
	nz_printf("defined:\t%d", t.defined) ;
	// nz_printf("inline_temp_index:\t%d", t.inline_temp_index);
	indent += Indent_Increment;
    }
    a_node();
    if(show_up) indent -= Indent_Increment;
} 
  

  
  

void
displayer::null_field(const char * name)
{
  nz_printf( "%s:\t0", name);
}


void 
displayer::a_basecl()
{
    struct basecl& bc = *Pbcl(node);

    printf("$basecl %s |0x%p",
	   token_name(node->base),
	   node_address);
    
    nz_printf ("ppp:\t%s", token_name(bc.ppp)) ;
    nz_printf ("allocated:\t%d", bc.allocated) ;
    nz_printf ("promoted:\t%d", bc.promoted) ;
    print_ptr("bclass", bc.bclass);
    nz_printf ("ptr_offset:\t%d", bc.ptr_offset) ;
    nz_printf ("obj_offset:\t%d", bc.obj_offset) ;
    indent += Indent_Increment;
    a_node();			/* do the supertype. */
    indent -= Indent_Increment;
}




void
displayer::a_basetype ()
{
    struct basetype& bt = *Pbase(node);
  
    printf("$basetype %s |0x%p",
	   token_name(node->base),
	   node_address);

    ind();
    catprintf("Flags:\t");
    flag(bt.b_unsigned, "unsigned ");
    flag(bt.b_signed, "signed ");
    flag(bt.b_volatile, "volatile ");
    flag(bt.b_const, "const ");
    flag(bt.b_typedef, "typedef ");
    flag(bt.b_virtual, "virtual ");
    flag(bt.b_short, "short ");
    flag(bt.b_long, "long ");
    catprintf("\n");
    nz_printf( "b_bits:\t%d", bt.b_bits);
    nz_printf( "b_offset:\t%d", bt.b_offset);
    nz_printf( "b_sto:\t%s", bt.b_sto ? token_name(bt.b_sto) : 0);
    switch(bt.discriminator(0)) {
      case 1:
	print_ptr("b_fieldtype", bt.b_fieldtype);
	break;
      case 2:
	nz_printf( "b_linkage:\t%s", bt.b_linkage ? "C" : "0(C++)");
    }

    print_ptr("b_name", bt.b_name);
    print_ptr("b_table", bt.b_table);
    // print_ptr("b_field", bt.b_field);
    print_ptr("b_xname", bt.b_xname);

    indent += Indent_Increment;
    a_type();			/* do the supertype. */
    indent -= Indent_Increment;
    
}

void
displayer::print_loc(loc& loc)
{
  catprintf("file %d line %d", (int)loc.file, (int)loc.line);
}


void
displayer::print_string_brief(void * addr)
{
  void * tmp;
  
  fetch_string (addr, 1000, tmp);
  *arg->output_stream << (char *)tmp;
  free_fetched (tmp);
}

void
displayer::print_string(const char * label, void * addr)
{
  ind();
  catprintf("%s:\t", label);
  print_string_brief(addr);
  *arg->output_stream << "\n";
}

void
displayer::a_expr(int from_name)
{
    struct expr& e = *Pexpr(node);
  
    if(from_name) printf("$expr");
    else printf("$expr %s |0x%p",
		token_name(node->base),
		node_address);
  
    print_ptr("tp", e.tp);
  
    switch(e.discriminator(1)) {
      case 0: break;
      case 1:
	print_ptr("e1", e.e1);
	break;
      case 2:
	printf("i1:\t%ld", e.i1);
	break;
      case 3:
	print_string("string", (void *)e.string);
    }

    switch(e.discriminator(2)) {
      case 0: break;
      case 1:
	print_ptr("e2", e.e2);
	break;
      case 2:
	printf("i2:\t%ld", e.i2);
	break;
      case 3:
	print_string("string2", (void *)e.string2);
	break;
      case 4:
	print_ptr("n_initializer", e.n_initializer);
    }

    switch(e.discriminator(3)) {
      case 0:
	break;
      case 1: print_ptr ("tp2", e.tp2); break;
      case 2: print_ptr ("fct_name", e.fct_name); break;
      case 3: print_ptr ("cond", e.cond); break;
      case 4: print_ptr ("mem", e.mem); break;
      case 5: print_ptr ("as_type", e.as_type); break;
      case 6: print_ptr ("n_table", e.n_table); break;
      case 7: print_ptr ("il", e.il); break;
      case 8: print_ptr ("query_this", e.query_this); break;
    }

  indent += Indent_Increment;
  a_node();
  indent -= Indent_Increment;

}

void
displayer::a_name()
{
    struct name& n = *Pname(node);


    ind();
    catprintf("$name %s |0x%p ",
	      token_name(node->base),
	      node_address);
    print_string_brief((void *)n.string);
    *arg->output_stream << "\n";

    nz_printf("n_key:\t%d", (int)n.n_key) ;
    nz_printf( "n_oper:\t\t%s", n.n_oper ?
	      token_name(n.n_oper) : 0);
    nz_printf( "n_sto:\t\t%s", n.n_sto ?
	      token_name(n.n_sto) : 0);
    nz_printf( "n_stclass:\t%s", n.n_stclass ?
	      token_name(n.n_stclass) : 0);
    nz_printf( "n_scope:\t%s", n.n_scope ?
	      token_name(n.n_scope) : 0);
    nz_printf( "n_union:\t%d", n.n_union);
    nz_printf( "n_evaluated:\t%d", n.n_evaluated);
    nz_printf( "n_xref:\t\t%d", n.n_xref);
    nz_printf( "lex_level:\t%d", n.lex_level);
    nz_printf( "n_protect:\t%s", n.n_protect ?
	      token_name(n.n_protect) : 0);
    if (n.n_dcl_printed || print_null_values) {
	ind();
	catprintf("n_dcl_printed:\t%d", n.n_dcl_printed);

	switch(n.n_dcl_printed)
	    {
	    case 0:
		catprintf("(not)\n");
		break;
	    case 1:
		printf("(declaration)\n");
		break;
	    case 2:
		printf("(definition)\n");
		break;
	    }
	
    }
    if(n.n_template_arg) {
	ind();
	catprintf( "n_template_arg:\t");
	switch(n.n_template_arg) 
	    { 
	    case template_type_formal:
		catprintf("template_type_formal\n");
		break;
	    case template_expr_formal:
		catprintf("template_expr_formal\n");
		break;
	    case template_stmt_tree_formal:
		catprintf("template_stmt_formal\n");
		break;
	    case template_expr_tree_formal:
		catprintf("template_expr_tree_formal\n");
		break;
	    case template_actual_arg_dummy:
		catprintf("template_actual_arg_dummy\n");
		break;
	    } ;
    }
    nz_printf( "n_addr_taken:\t%d", n.n_addr_taken);
    nz_printf( "n_used:\t\t%d", n.n_used);
    nz_printf( "n_assigned_to:\t%d", n.n_assigned_to);
    ind();
    catprintf("loc:\t\t");
    print_loc(n.where);
    catprintf("\n");
    nz_printf( "n_offset:\t%d", n.n_offset);
    // if(n.output_string) { print_string("output_string", (void *)n.output_string); }
    nz_printf( "n_val:\t\t%ld", n.n_val);

    print_ptr("n_list", n.n_list);
    print_ptr("n_tbl_list", n.n_tbl_list);
    if(n.n_gen_fct_name)
	print_string("n_gen_fct_name", n.n_gen_fct_name);
    if(n.n_template_arg_string) {
	print_string("n_template_arg_string",
		     n.n_template_arg_string);
    }
    switch(n.discriminator(0)) {
    case 2: print_ptr("n_realscope", n.n_realscope); break;
    case 1: print_ptr("n_qualifier", n.n_qualifier); break;
    }
    nz_printf("n_val:\t%ld", n.n_val);

    indent += Indent_Increment;
    a_expr(1);			/* do the supertype. */
    indent -= Indent_Increment;
}

void
displayer::a_fct()
{
    struct fct& f = *Pfct(node);

    printf("$fct %s |0x%p",
	   token_name(node->base),
	   node_address);


    printf("nargs:\t\t%d", f.nargs);
    printf("nargs_known:\t%d%s", f.nargs_known,
	   f.nargs_known == 0 ? " UNKNOWN" :
	   (f.nargs_known == 1 ? " KNOWN" :
	    (f.nargs_known == ELLIPSIS ? "ELLIPSIS" : "" )));
    nz_printf( "f_vdef:\t\t%d", f.f_vdef);
    printf("f_inline:\t%d%s", f.f_inline,
	   f.f_inline == 0 ? "" :
	   f.f_inline == 1 ? " inline" :
	   f.f_inline == 2 ? " inline in expansion" : "");
    nz_printf( "f_const:\t\t%d", f.f_const);
    nz_printf( "f_static:\t\t%d", f.f_static);
    nz_printf( "f_virtual:\t%d", f.f_virtual);
    nz_printf( "f_imeasure:\t%d", f.f_imeasure);
    print_string("f_signature", (void *)f.f_signature);

    print_ptr("returns", f.returns);
    print_ptr("argtype", f.argtype);
    print_ptr("s_returns", f.s_returns);
    print_ptr("f_this", f.f_this);
    print_ptr("memof", f.memof);
    print_ptr("body", f.body);
    print_ptr("f_init", f.f_init);
    print_ptr("f_expr", f.f_expr);
    print_ptr("last_expanded", f.last_expanded);
    print_ptr("f_result", f.f_result);
    print_ptr("f_args", f.f_args);
    print_ptr("local_classes", f.local_class);
    
    indent += Indent_Increment;
    a_type();			/* do the supertype. */
    indent -= Indent_Increment;
}

void
displayer::a_stmt ()
{
    struct stmt& s = *Pstmt(node);

    ind();
    catprintf("$stmt %s |0x%p ",
	      token_name(node->base),
	      node_address);
    print_loc(s.where);
    *arg->output_stream << "\n";

    ind();
    *arg->output_stream << "where:\t";
    print_loc(s.where);
    *arg->output_stream << "\n";

    print_ptr("s", s.s);
    print_ptr("s_list", s.s_list);
    print_ptr("memtbl", s.memtbl);
    switch(s.discriminator(0)) {
      case 1: print_ptr("d", s.d); break;
      case 2: print_ptr("e2", s.e2); break;
      case 3: print_ptr("has_default", s.has_default); break;
      case 4: nz_printf("case_value:\t0x%x", s.case_value);
      case 5: print_ptr("ret_tp", s.ret_tp); break;
    }
    switch(s.discriminator(1)) {
      case 1: print_ptr("e", s.e); break;
      case 2: nz_printf("own_tbl:\t%d", s.own_tbl); break;
      case 3: print_ptr("s2", s.s2); break;
    }

    switch(s.discriminator(2)) {
	case 1: print_ptr("for_init", s.for_init); break;
	case 2:	print_ptr("else_stmt",s.for_init); break;
	case 3: print_ptr("case_list", s.case_list); break;
    }
}

void
displayer::a_enumdef ()
{
   struct enumdef& e = *Penum(node);

   printf("$enumdef %s |0x%p",
	  token_name(node->base),
	  node_address);

   nz_printf( "e_body:\t\t%d", e.e_body);
   nz_printf( "no_of_enumerators: %d", 
	     e.no_of_enumerators);
   nz_printf( "strlen:\t%d", e.strlen);
   print_string ("string", (void *)e.string);

   print_ptr("mem", e.mem);
   print_ptr("e_type", e.e_type);
   indent += Indent_Increment;
   a_type();			/* do the supertype. */
   indent -= Indent_Increment;
}

void
displayer::a_classdef ()
{
    struct classdef& c = *Pclass(node);

    ind();
    catprintf("$classdef %s |0x%p ",
	      token_name(node->base),
	      node_address);
    print_string_brief(c.string);
    *arg->output_stream << "\n";
    ind();
    catprintf("class_base:\t");
    switch(c.class_base) 
	{ 
	  case vanilla_class:
	    *arg->output_stream << "vanilla_class\n";
	    break;
	  case template_class:
	    *arg->output_stream << "template_class\n";
Template_Class:	    
	    nz_printf("inst:\t\t%p", (int)Ptclass(&c)->inst);
	    break;
	  case instantiated_template_class:
	    *arg->output_stream << "instantiated_template_class\n";
	    goto Template_Class;
	  case uninstantiated_template_class:
	    *arg->output_stream << "uninstantiated_template_class\n";
	    goto Template_Class;
	  case relationship_class:
	    *arg->output_stream << "relationship_class\n";
	    break;
	  case defining_class:
	    *arg->output_stream << "defining_class\n";
	    break;
	}

    nz_printf( "c_body:\t\t%d", c.c_body);
    printf("csu:\t\t%s", 
	   token_name(c.csu));
    nz_printf( "obj_align:\t%d", c.obj_align);
    if(c.c_xref) {
	ind();
	catprintf( "c_xref:\t%x", c.c_xref);
	flag(c.c_xref & 1, "has-vptr ");
	flag(c.c_xref & 2, "X(X&)-defined ");
	flag(c.c_xref & 4, "operator=(X&)-defined ");
	flag(c.c_xref & 8, "has-vbaseptr(s) ");
	*arg->output_stream << "\n";
    }
    nz_printf( "virt_count:\t%d", c.virt_count);
    nz_printf( "virt_merge:\t%d", c.virt_merge);
    nz_printf( "c_abstract:\t%d", c.c_abstract);
    nz_printf( "has_vvtab:\t%d", c.has_vvtab);
    nz_printf( "strlen:\t%d", c.strlen);
    print_string ("string", (void *)c.string);
    nz_printf( "obj_size:\t%d", c.obj_size);
    nz_printf( "real_size:\t%d", c.real_size);
    nz_printf("lex_level:\t%d", c.lex_level);
    if(c.lcl)print_string("lcl", c.lcl);

    print_ptr("baselist", c.baselist);
    print_ptr("mem_list", c.mem_list);
    print_ptr("memtbl", c.memtbl);
    print_ptr("friend_list", c.friend_list);
    print_ptr("pubdef", c.pubdef);
    print_ptr("tn_list", c.tn_list); /* not brief */
    print_ptr("in_class", c.in_class);
    print_ptr("in_fct", c.in_fct);
    print_ptr("this_type", c.this_type);
    print_ptr("virt_list", c.virt_list); 
    print_ptr("c_ctor", c.c_ctor);
    print_ptr("c_dtor", c.c_dtor);
    print_ptr("c_itor", c.c_itor);
    print_ptr("conv", c.conv);
    indent += Indent_Increment;
    a_type();			/* do the supertype. */
    indent -= Indent_Increment;
}


void
displayer::a_virt()
{
    virt& v = *Pvirt(node);
    void * vna;
    void * vna_e;
    int vx;

    printf("$virt %s |0x%p ",
	   token_name(node->base),
	   node_address);
    
    print_ptr("next", v.next);
    if(v.n_init) {
	printf("n_init:\t%d", v.n_init);
	printf("virt_init:");
	for (vna = v.virt_init, vx = 0; vx < (v.n_init - 1);
	     vna = (char *)vna + sizeof (velem), vx++)
	    {
		fetch(vna, sizeof (velem), vna_e);
		struct velem * ve = (struct velem *) vna_e;
		ind();
		catprintf("%d offset %d\t", vx, ve->offset);
		print_ptr(ve->n);
		free_fetched(vna_e);
	    }
    }
    print_ptr("vclass", v.vclass);
    nz_printf( "\nis_vbase:\t %d", v.is_vbase);
    nz_printf( "\nprinted:\t %d", v.printed);
}

void
displayer::a_table ()
{
   struct table& t = *Ptable(node);
   int x;
   int y;
   void * nlist;
   void * slist;

   printf("$table %s |0x%p",
	  token_name(node->base),
	  node_address);

    printf("init_stat:\t%d%s", t.init_stat,
	   t.init_stat == 0 ? " not simplified" :
	   t.init_stat == 1 ? " simplified, no inits" :
	   t.init_stat == 2 ? " simplified, inits" :
	   "");
   printf("size:\t%d", t.size);
   printf("hashsize:\t%d", t.hashsize);
   printf("free_slot:\t%d", t.free_slot);

   /* it looks like there is an array of Pnames here ... */
   *arg->output_stream << "\n";
   ind();
   *arg->output_stream << "entries:\n";
   fetch((void *)t.entries, t.size * sizeof(Pname), nlist);
   Pname * tmp_nlist = (Pname *)nlist;
   for(x = 0; x < t.size; x ++) {
       if(tmp_nlist[x]) {
	   ind();
	   *arg->output_stream << x;
	   *arg->output_stream << "\t";
	   print_ptr(tmp_nlist[x]);
	   unsigned char tmp_name_s[sizeof(name)];
	   void * tmp_name;
	   tmp_name = (void *)&tmp_name_s[0];
	   fetch(tmp_nlist[x], sizeof(name), tmp_name);
	   catprintf(" key %d\n", Pname(tmp_name)->n_key);
       }
   }
   free_fetched(nlist);
   /* and then an array of shorts for the hash table. */
   /* we really need a tabular format here, alright. */
   ind();
   *arg->output_stream << "hashtbl:\n";
   fetch(t.hashtbl, t.hashsize * sizeof(short), slist);
   short * tmp_slist = (short *)slist;
   for(x = 0;; x++ ) {
       for (y = 0; y < 11; y ++) {
       if(((x * 12) + y) > t.hashsize) break;
	   catprintf("%6d ", tmp_slist[(x*12)+y]);
       }
       *arg->output_stream << "\n";
       if(((x * 12) + y) > t.hashsize) break;
   }

   free_fetched (slist);

   print_ptr("t_name", t.t_name);
   print_ptr("real_block", t.real_block);
   print_ptr("name", t.t_name);
   print_ptr("next", t.next);
}

void
displayer::a_gen ()
{
    struct gen& g = *Pgen(node);

    printf("$gen %s |0x%p",
	   token_name(node->base),
	   node_address);

    print_ptr ("fct_list", g.fct_list);
    indent += Indent_Increment;
    a_type();			/* do the supertype. */
    indent -= Indent_Increment;
}

void
displayer::a_vec ()
{
   struct vec& v = *Pvec(node);

   printf("$vec %s |0x%p",
	  token_name(node->base),
	  node_address);
   printf("size:\t\t%d", v.size);
   print_ptr ("typ", v.typ);
   print_ptr ("dim", v.dim);
}

void
displayer::a_ptr ()
{
    struct ptr& p = *Pptr(node);

    printf("$ptr %s |0x%p",
	   token_name(node->base),
	   node_address);
    ind();
    printf("rdo:\t\t%d", p.rdo);
    ind();

    print_ptr ("typ", p.typ);
    print_ptr ("memof", p.memof);
}


void
displayer::a_nlist()
{
    name_list& n = *Plist(node);

    printf("$name_list %s |0x%p ",
	   token_name(node->base),
	   node_address);
    
    print_ptr("f", n.f);
    print_ptr("l", n.l);
}

void
displayer::a_iline()
{
    struct iline& i = *(struct iline *)node;

    printf("$iline %s |0x%p ",
	   token_name(node->base),
	   node_address);
    
    print_ptr("fct_name", i.fct_name);
    print_ptr("i_next", i.i_next);
    print_ptr("i_table", i.i_table);
    nz_printf("i_slots:\t%d", i.i_slots);
    print_ptr("i_args", i.i_args);
}

void
displayer::a_ia()
{
    struct ia& i = *(struct ia *)node;

    printf("$ia %s |0x%p ",
	   token_name(node->base),
	   node_address);
    
    print_ptr("local", i.local);
    print_ptr("arg", i.arg);
    print_ptr("tp", i.tp);
}

static int fetcher (void * info,
		    void * pointer,
		    unsigned long length,
		    int zero_stop,  /* for character strings.*/
		    void * target)
{
    displayer * d = (displayer *)info;
    if(d->arg->fetcher)
	return d->arg->fetcher(d->arg->fetcher_info, pointer, length,
			       zero_stop, target);
}

static void 
do_node (Pnode& node, node_class cl, void * info, tree_node_action& action,
	 int depth, Pnode na, tree_walk_tree&, int&)
{
    displayer * d = (displayer *)info;
    d->do_node(node, cl, action, depth, na);
    d->arg->output_stream->write("\n", 1);
}


/* Note -- declared extern "C" in tree_dump.h. */

void
display_cfront_node (dcn_arg& arg, Pnode n)
{
    tree_walk_control twc;
    displayer d (arg);
    
    if(arg.verbose == dt_normal)arg.max_depth = 0;
    twc.callback_info = (void *)&d;
    if(arg.fetcher) twc.fetcher = fetcher;
    twc.action_proc = do_node;
    twc.error_stream = arg.error_stream;
    twc.nodes_seen_hash = arg.nodes_seen_hash;
    twc.resolve_by_name = 0;	/* we want to display the by_name nodes */
    twc.dont_chase_lists_top = 1; /* don't display n_list or s_list peers
			             at the top level. */

    walk_tree(twc, n);

    arg.error_stream->flush();
    arg.output_stream->flush();
}


extern "C" void _fcout();
void _fcout () { cout.flush(); }
0707071010112046001004440001630000160000010207660466055415100001400000003407tree_dump.h/* ident "@(#)ctrans:src/tree_dump.h	1.2" */
/* -*- Mode: C -*- Begin tree_dump.h */

#ifndef _DUMP_TREE
#define _DUMP_TREE

#include "tree_walk.h"
#include <iostream.h>
#include "hash.h"

enum dump_tree_verbosity {
    dt_brief = 1,		/* minimal identification */
    dt_normal = 2,	  	/* all data, outpointers Brief (one level) */
    dt_recursive_0 = 3,		/* minimal, but recurse down.
				   (outpointers Recursive_0) */
    dt_recursive_1 = 4,		/* all data, outpointers Recursive_2. */
};

class dcn_arg {
  public:
    int version;
    dump_tree_verbosity verbose;
    tree_fetch_proc fetcher;
    void * fetcher_info;
    ostream* output_stream;
    ostream* error_stream;
    int max_depth;
    Hash * nodes_seen_hash;
    /* end of version 1 */
    int walk_tables;
    /* end of version 2 */
    int stop_at_top;
    dcn_arg () { version = 2; 
		 nodes_seen_hash = 0;
		 fetcher = null_tfp; 
		 output_stream = &cout;
		 error_stream = &cerr; 
		 max_depth = -1;
		 walk_tables = 1;
		 stop_at_top = 0;
	     };
};


extern "C" {
    void display_cfront_node (dcn_arg&, Pnode);
}
#else

typedef enum dump_tree_verbosity {
    dt_brief = 1,		/* minimal identification */
    dt_normal = 2,	  	/* all data, outpointers Brief (one level) */
    dt_recursive_0 = 3,		/* minimal, but recurse down.
				   (outpointers Recursive_0) */
    dt_recursive_1 = 4,		/* all data, outpointers Recursive_2. */
} dump_tree_verbosity;

struct dcn_arg {
    int version;		/* must be 1 for now. */
    dump_tree_verbosity verbose;
    int (*fetcher) ();
    void * fetcher_info;
    void * output_stream;	/* these are c++ streams */
    void * error_stream;
    int max_depth;
    void * nodes_seen_hash;
    int walk_tables;
    int stop_at_top;
};

void display_cfront_node ();
#endif

/* End tree_dump.h */
0707071010112046051004440001630000160000010212000466055417300001400000066517tree_walk.c/* ident "@(#)ctrans:src/tree_walk.c	1.2" */
/* 
	tree_walk.c
	Utilities for tree-walking 
*/

#include "cfront.h"
#include "tree_walk.h"
#include <stdarg.h>
#include "hash.h"
// #include <alloca.h>
// ************ need to add an explicit call of free
// ************ make it an ifdef
// ??? #include <streamdefs.h>
#include <malloc.h>

class walker {
    tree_walk_control control;
    Pnode orig_addr;
    Hash *nodes_seen_hash;
    int depth;
    int made_ht;
    tree_walk_tree * cur_tree;
  public:
    walker(tree_walk_control& c) ;
 
    ~walker () {
	if(made_ht) delete nodes_seen_hash;
    }
    tree_node_action walk (Pnode&);
    tree_node_action walk_ (Pnode& n) 
    {
	if(n) {
	    int save_depth = depth;
	    tree_walk_tree * save_cur_tree = cur_tree;

	    depth ++;
	    if(control.alloc_stack_bytes) {
		cur_tree = (tree_walk_tree *)
		    // alloca (control.alloc_stack_bytes + sizeof (tree_walk_tree));
		    malloc(control.alloc_stack_bytes + sizeof (tree_walk_tree));
		cur_tree->parent = save_cur_tree;
	    }
	    tree_node_action r = walk(n);
	    depth = save_depth;
	    return r;
	} else return tna_continue;
    }
	
    tree_node_action walk(Pgen& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pvec& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pptr& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Ptype& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pfct& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Ptable& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pbase& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pname& n) 
    { return walk_ ((struct node * &)n); };
     tree_node_action walk(Pexpr& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pstmt& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pblock& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Penum& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pclass& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pvirt& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Plist& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pin& n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(struct ia * & n) 
    { return walk_ ((struct node * &)n); };
    tree_node_action walk(Pbcl& n) 
    { return walk_ ((struct node * &)n); };
  private:
    int fetching () {  return (control.fetcher != null_tfp); } ;
    void free_fetched (void *);
    int fetch (void *, unsigned long, void *&);
    int fetch (void * a, unsigned long l, Pnode& p) 
    {
	int ret;
	void * t;		/* this is an output argument */
	ret = fetch(a,l,t);
	if(!ret) {
	    p = Pnode(t);
	}
	return ret;
    };
    // void error (const char *,...); ?? at&t -- to get it up quick, line 155
    void error ( char *, unsigned long=0 );
    tree_node_action pre_act_on_node (Pnode node, node_class nc,
				      Pnode node_copy, Pnode& replacement);
				       
    tree_node_action a_gen (Pnode, Pgen, Pnode&);
    tree_node_action a_vec (Pnode, Pvec, Pnode&);
    tree_node_action a_ptr (Pnode, Pptr, Pnode&);
    tree_node_action a_fct (Pnode, Pfct, Pnode&);
    tree_node_action a_table (Pnode, Ptable, Pnode&);
    tree_node_action a_basetype (Pnode, Pbase, Pnode&);
    tree_node_action a_name(Pnode, Pname, Pnode&);
    tree_node_action a_expr (Pnode, Pexpr, Pnode&);
    tree_node_action a_stmt (Pnode, Pstmt, Pnode&);
    tree_node_action a_enumdef (Pnode, Penum, Pnode&);
    tree_node_action a_classdef (Pnode, Pclass, Pnode&);
    tree_node_action a_virt (Pnode, Pvirt, Pnode&);
    tree_node_action a_name_list (Pnode, Plist, Pnode&);
    tree_node_action a_iline (Pnode, Pin, Pnode&);
    tree_node_action a_ia (Pnode, struct ia *, Pnode&);
    tree_node_action a_baseclass (Pnode, Pbcl, Pnode&);
    tree_node_action a_expr_guts (Pexpr);
};


walker::walker(tree_walk_control& c) 
{ control = c;
  made_ht = 0;
  if (c.nodes_seen_hash)
    nodes_seen_hash = c.nodes_seen_hash;
  else {
    nodes_seen_hash = new pointer_hash (100);
    made_ht = 1;
  }
  depth = 0;
  cur_tree = 0;
}


tree_node_action
walk_tree (tree_walk_control& c, Pnode& n)
{
    walker w (c);
    return w.walk(n);
}


/* error messages are of finite length, so no need to run
   around mallocing strings */

// void walker::error (const char * format, ...)
void walker::error (char *format, unsigned long v)
{
    va_list args;
    va_start(args, format);
    if(control.call_i_error) {
	char buf[1000];
	// vsprintf(buf, format, args);
        // vsprintf not universal: by inspection
        // all calls are currently of 1 or 0 arguments
	sprintf(buf, format, v);
	(*control.i_error)('i', buf);
    } else {
	vostream_printf (format, args, *control.error_stream);
	*control.error_stream << "\n";
	control.error_stream->flush();
    }
    va_end (args);
}


void
walker::free_fetched (void * addr)
{
    if (control.fetcher != null_tfp)	/* null indicates no cross-address-space */
       free ((char *)addr);	
}    

int
walker::fetch (void * addr, unsigned long length, void*& taddr)
{
    int err;

    if (control.fetcher == null_tfp) { 
	taddr = addr;
	return 0;
    } else {
       taddr = (void *)malloc ((unsigned int)length);
       if(taddr == 0) {
	   error ("walker::fetch: failed to malloc %d bytes.", length);
	   return 1;
       }

       err = (*control.fetcher) (control.callback_info, addr, length, 0, taddr);
       if(err) {
	   error("walker::fetch: fetcher returned %d.", err);
	   return 1;
       }
   }
}

/* ::walk is called with a node pointer and a reference to
   a replacement node pointer. When it returns,
   replacement will be set if the action procedure
   called on the node decided to copy it or replace it.
   There are two possible modularities. 
   In case there is cross-address-space action,
   ::walk can't call the action procedure until it has
   entered the case on node bases. Once it has,
   it calls the per-structure-type procedure,
   which calls the action proc. If the action 
   proc supplies a replacement, then that replacement
   will be returned up via the reference parameters to 
   the per-structure procedures.

   It the action procedure returns tna_continue,
   then the walk continues against the new copy of the node
   so that further replacements are reflected in the new copies.
   This prevents replacement from being meaningful cross-address-space,
   since the new copy will presumably be in the current 
   (and not the cross) address space. That is, if the node
   is replaced by the action proc, the pointers in the new 
   node will drive the subsequent tree walk. Usually one
   would just bitcopy, and then they would be replaced in turn.
*/

tree_node_action
walker::walk (Pnode& top)
{
    Pnode replacement = 0;
    tree_node_action err;
    int class_err;
    node_class nclass;
    Pnode node = 0; /* assign to shut up compiler,
		       which dosen't recognize pass-by-reference as a set */

    orig_addr = top;

    if(fetching ()) {
	if(fetch((void *)top, sizeof (struct node), node))
	    return tna_error;
    } else node = top;

/* This has a complete catalog of bases, rather than just a list
   of those associated with data structures. Its important
   to detect the errs.
*/   

    nclass = classify_node (node, class_err);

    if(class_err) {
	error("walker::walk: unknown node type %d.", node->base);
	free_fetched ((void *)node);
	err = tna_error;
	goto Return;
    }
    
    switch(nclass)
    {
      default:
      case nc_unused:
	error("walker::walk: unused node type %d.", node->base);
	err = tna_error;
	goto Return;

      case nc_eof:
	break;

      case nc_virt:
	fetch((void *)top, sizeof (struct virt), node);
	err = a_virt(top, Pvirt (node), replacement);
	break;

      case nc_nlist:
	fetch((void *)top, sizeof (struct name_list), node);
	err = a_name_list(top, (struct name_list *)node, replacement);
	break;

      case nc_iline:
	fetch((void *)top, sizeof (struct iline), node);
	err = a_iline(top, (struct iline *)node, replacement);
	break;

      case nc_gen:
	fetch((void *)top, sizeof (struct gen), node);
	err = a_gen(top, Pgen (node), replacement);
	break;

      case nc_vec:
	fetch((void *)top, sizeof (struct vec), node);
	err = a_vec(top, Pvec(node), replacement);
	break;

      case nc_ptr:
	fetch((void *)top, sizeof (struct ptr), node);
	err = a_ptr(top, Pptr(node), replacement);
	break;

      case nc_fct:
	fetch((void *)top, sizeof (struct fct), node);
	err = a_fct(top, Pfct(node), replacement);
	break;

      case nc_table:
	fetch((void *)top, sizeof (struct table), node);
	err = a_table(top, Ptable(node), replacement);
	break;

      case nc_basetype:
	fetch((void *)top, sizeof (struct basetype), node);
	err = a_basetype(top, Pbase(node), replacement);
	break;

      case nc_name:
	fetch((void *)top, sizeof (struct name), node);
	err = a_name(top, Pname(node), replacement);
	break;

      case nc_expr:
	fetch((void *)top, sizeof (struct expr), node);
	err = a_expr(top, Pexpr(node), replacement);
	break;

      case nc_stmt:
	fetch((void *)top, sizeof (struct stmt), node);
	err = a_stmt(top, Pstmt(node), replacement);
	break;

      case nc_enumdef:
	fetch((void *)top, sizeof (struct enumdef), node);
	err = a_enumdef(top, Penum(node), replacement);
	break;

      case nc_classdef:
	fetch((void *)top, sizeof (struct classdef), node);
	err = a_classdef(top, Pclass(node), replacement);
	break;

      case nc_ia:
	fetch((void *)top, sizeof (struct ia), node);
	err = a_ia(top, (struct ia *)node, replacement);
	break;

      case nc_baseclass:
	fetch((void *)top, sizeof (struct basecl), node);
	err = a_baseclass(top, Pbcl(node), replacement);
	break;

    }

    if(replacement) {
	if (fetching ()) {
	    error
		("walker::walk: Attempt to replace tree in cross-address space mode.");
	    err = tna_error;
	} 
	else top = replacement;
    }
	
    if (control.post_action_proc && err != tna_error) {
	tree_node_action post_err;
	Pnode& post_repl = node;

	(*control.post_action_proc) (post_repl, nclass, control.callback_info, post_err,
				     depth, orig_addr, *cur_tree);
	if(post_err != tna_continue) err = post_err;
	if(post_repl != node) {
	    if (fetching ()) {
		error
		    ("walker::walk: Attempt to replace tree in cross-address space mode.");
		err = tna_error;
	    } 
	    else top = post_repl;
	}
    }

    free_fetched((void *) node);

Return:
    return err;
}

/* This is called in pre-order for each node. Then
   post_act_on_node is called after whatever recursive
   processing ensues.
   
   This is called from each of the structure-specific procedures
   to give the action procedure an opportunity to act.
   It can return a replacement pointer and control
   whether to examine the insides of the node.
   */

tree_node_action 
walker::pre_act_on_node (Pnode node, node_class nc,
		       Pnode node_copy, Pnode& replacement)
{
/* If we have been here before, then we never proceed */
/* node_copy is != node when a fetcher is in use */

    int found;
    int old_node;
    tree_node_action action;
    Pnode new_node;
    int register_in_hash = 1;

    nodes_seen_hash->action((int)node, 0, Hash::probe, found, old_node);

    if(found) {
	new_node = Pnode(old_node);
	if(new_node != node) replacement = new_node;
	return tna_stop; /* no need to proceed */
    }

    /* OK, we don't know from a previous pass. Call our actor */

    new_node = fetching () && node_copy ? node_copy : node;

    (*control.action_proc)(new_node, nc, control.callback_info, action, 
			   depth, orig_addr, *cur_tree,
			   register_in_hash);

    if(action != tna_error && !fetching () && new_node != node) {
	replacement = new_node;
	if(register_in_hash)
	    nodes_seen_hash->action((int)node, 
				    (int)new_node, 
				    Hash::insert, 0, 0);
    }
    else {
	if(register_in_hash)
	    nodes_seen_hash->action((int)node, (int) node, Hash::insert, 0, 0);
    }
    return action;
}			   

tree_node_action walker::a_table(Pnode ta, Ptable t, Pnode& replacement) 
{
    /* no unions */

    tree_node_action action;
    action = pre_act_on_node(ta, nc_table, Pnode(t), replacement);
    if(action != tna_continue) return action;

/* -----------------------------*/
/* For Now, Never Walk a Table. */

    action = tna_stop; return action;

/* An array of pointers. 
 * The action procedure is responsible for allocating a new one
 * of those if it replaced and continued. 
 * *** end of comment

    if(!fetching () && replacement)
	t = Ptable(replacement);

    Pname * t_entries;

    if(fetching ()) {
	void * temp;
	fetch((void *)t->entries, t->size * sizeof(Pname), temp);
	t_entries = (Pname *)temp;
    }
    else t_entries = t->entries;

    for(int nx = 0; nx < t->size; nx ++) {
	action = walk(t_entries[nx]);
	if(action == tna_error) return action;
    }

    if(fetching ()) free_fetched ((void *)t_entries);
    
    Pnode n = Pnode(t->real_block);

    action = walk(t->real_block);
    if(action == tna_error) return action;
    
    action = walk(t->next);
    action = walk(t->t_name);
    return tna_continue;
*/ // don't walk table
}

tree_node_action walker::a_enumdef (Pnode ta, Penum e, Pnode& replacement) 
{
    tree_node_action action = pre_act_on_node(ta, nc_enumdef, Pnode(e), replacement);

    action = walk(e->mem);
    if(action == tna_error) return action;

    action = walk(e->e_type);

    return tna_continue;
}    

tree_node_action walker::a_virt(Pnode ta, Pvirt v, Pnode& replacement) 
{
    /* no unions */

    int nx;
    tree_node_action action = pre_act_on_node(ta, nc_enumdef, Pnode(v), replacement);

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	v = Pvirt(replacement);

/* an array of velem structures. */

    velem * v_virt_init;

    if(fetching ()) {
	void * t;
	fetch((void *)v->virt_init, v->n_init * sizeof(velem), t);
	v_virt_init = (velem *)t;
    }
    else v_virt_init = v->virt_init;

    for(nx = 0; nx < v->n_init; nx ++) {
	action = walk(v_virt_init[nx].n);
	if(action == tna_error) return action;
    }

    if(fetching ()) free_fetched ((void *)v_virt_init);
    
    action = walk(v->vclass);
    
    return tna_continue;
}

tree_node_action walker::a_classdef(Pnode ta, Pclass c, Pnode& replacement) 
{

    tree_node_action action = pre_act_on_node(ta, nc_classdef, Pnode(c), replacement);

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	c = Pclass(replacement);

    action = walk(c->baselist);
    if(action == tna_error) return action;

    action=walk(c->mem_list);
    if(action == tna_error) return action;
    
    action=walk(c->memtbl);
    if(action == tna_error) return action;

    action=walk(c->friend_list);
    if(action == tna_error) return action;

    action=walk(c->pubdef);
    if(action == tna_error) return action;
    
    action=walk(c->tn_list);
    if(action == tna_error) return action;

    action=walk(c->in_class);
    if(action == tna_error) return action;

    action=walk(c->in_fct);
    if(action == tna_error) return action;

    action=walk(c->this_type);
    if(action == tna_error) return action;

    action=walk(c->virt_list);
    if(action == tna_error) return action;

    action=walk(c->c_ctor);
    if(action == tna_error) return action;
    action=walk(c->c_dtor);
    if(action == tna_error) return action;
    action=walk(c->c_itor);
    if(action == tna_error) return action;

    action=walk(c->conv);
    if(action == tna_error) return action;

    return tna_continue;
}

tree_node_action walker::a_basetype(Pnode ta, Pbase b, Pnode& replacement) 
{

    tree_node_action action = pre_act_on_node(ta, nc_basetype, Pnode(b), replacement);
    int derr;

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	b = Pbase(replacement);

    action = walk(b->b_name);
    if(action == tna_error) return action;

    action = walk(b->b_table);
    if(action == tna_error) return action;

    // action = walk(b->b_field);
    // if(action == tna_error) return action;

    action = walk(b->b_xname);
    if(action == tna_error) return action;

    switch(derr = b->discriminator(0)) {
      case 0: break;
      case 1:
	action = walk(b->b_fieldtype);
	if(action == tna_error) return action;
	break;
      case 2: break;
      default:
	error ("a_basetype: discrim error %d.", derr);
	return tna_error;
    }

    return tna_continue;
}

tree_node_action walker::a_fct(Pnode ta, Pfct f, Pnode& replacement) 
{

    tree_node_action action = pre_act_on_node(ta, nc_fct, Pnode(f), replacement);

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	f = Pfct(replacement);

    action = walk(f->returns);
    if(action == tna_error) return action;

    action = walk(f->argtype);
    if(action == tna_error) return action;

    action = walk(f->s_returns);
    if(action == tna_error) return action;

    action = walk(f->f_this);
    if(action == tna_error) return action;

    action = walk(f->memof);
    if(action == tna_error) return action;

    action = walk(f->body);
    if(action == tna_error) return action;

    action = walk(f->f_init);
    if(action == tna_error) return action;

    action = walk(f->f_expr);
    if(action == tna_error) return action;

    action = walk(f->last_expanded);
    if(action == tna_error) return action;

    action = walk(f->f_result);
    if(action == tna_error) return action;

    action = walk(f->f_args);
    if(action == tna_error) return action;

    return tna_continue;
}

tree_node_action walker::a_name_list(Pnode ta, Plist l, Pnode& replacement) 
{

    int cl_error;
    tree_node_action action = pre_act_on_node(ta, nc_nlist, Pnode(l), replacement);

    if(action == tna_stop) {
	if(!fetching () && replacement)
	    l = Plist(replacement);
	cl_error = 0;
	if((classify_node(Pnode(l), cl_error) == nc_nlist) && !cl_error) {
	    action = walk(l->l);
	    if(action == tna_error) return action;
	}
    }

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	l = Plist(replacement);

    action = walk(l->f);
    if(action == tna_error) return action;

    action = walk(l->l);
    if(action == tna_error) return action;

    return tna_continue;
}

tree_node_action walker::a_gen(Pnode ta, Pgen g, Pnode& replacement) 
{

    tree_node_action action = pre_act_on_node(ta, nc_gen, Pnode(g), replacement);

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	g = Pgen(replacement);

    action = walk(g->fct_list);
    if(action == tna_error) return action;

    return tna_continue;
}

tree_node_action walker::a_vec(Pnode ta, Pvec v, Pnode& replacement) 
{

    tree_node_action action = pre_act_on_node(ta, nc_vec, Pnode(v), replacement);

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	v = Pvec(replacement);

    action = walk(v->typ);
    if(action == tna_error) return action;

    action = walk(v->dim);
    if(action == tna_error) return action;

    return tna_continue;
}

tree_node_action walker::a_ptr(Pnode ta, Pptr p, Pnode& replacement) 
{

    tree_node_action action = pre_act_on_node(ta, nc_ptr, Pnode(p), replacement);

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	p = Pptr(replacement);

    action = walk(p->typ);
    if(action == tna_error) return action;

    action = walk(p->memof);
    if(action == tna_error) return action;

    return tna_continue;
}


tree_node_action walker::a_expr_guts(Pexpr e)
{
    int derr;
    tree_node_action action;

    switch(derr = e->discriminator (0)) {
      case 1:
	action = walk(e->tp);
	if(action == tna_error) return action;
	break;
      case 0:
	break;
      default:
	error ("a_expr: discrim error %d on union 0.", derr);
	return tna_error;
    }

    switch(derr = e->discriminator (1)) {
      case 0:
	break;
      default:
	error ("a_expr: discrim error %d on union 1.", derr);
	return tna_error;
      case 1:
	action = walk(e->e1);
	if(action == tna_error) return action;
	break;
      case 2:
	break;
      case 3:
	break;
    }

    switch(derr = e->discriminator (2)) {
      case 0:
	break;
      default:
	error ("a_expr: discrim error %d on union 2.", derr);
	return tna_error;
      case 1:
	/* elists are special. e2 for an elist is a peer, not
	   a child. */
	if(e->base != ELIST) {
	    action = walk(e->e2);
	    if(action == tna_error) return action;
	}
	break;
      case 2:
	break;
      case 3:
	break;
      case 4:
	action = walk(e->n_initializer);
	if(action == tna_error) return action;
	break;
    }
    
    switch(derr = e->discriminator (3)) {
      case 0:
	break;
      default:
	error ("a_expr: discrim error %d on union 3.", derr);
	return tna_error;
      case 1:
	action = walk(e->tp2);
	if(action == tna_error) return action;
	break;
      case 2:
	action = walk(e->fct_name);
	if(action == tna_error) return action;
	break;
      case 3:
	action = walk(e->cond);
	if(action == tna_error) return action;
	break;
      case 4:
	action = walk(e->mem);
	if(action == tna_error) return action;
	break;
      case 5:
	action = walk(e->as_type);
	if(action == tna_error) return action;
	break;
      case 6:
	action = walk(e->n_table);
	if(action == tna_error) return action;
	break;
      case 7:
	action = walk(e->il);
	if(action == tna_error) return action;
	break;
      case 8:
	action = walk(e->query_this);
	if(action == tna_error) return action;
	break;
    }
    return tna_continue;
}


tree_node_action walker::a_expr(Pnode ta, Pexpr e, Pnode& replacement) 
{
    tree_node_action action = pre_act_on_node(ta, nc_expr, Pnode(e), replacement);

    if(action == tna_stop) {
	if(!fetching () && replacement)
	    e = Pexpr(replacement);
	/* ELIST implies that e2 is a peer, not a child */
	if(e->base == ELIST) {
	    action = walk(e->e2);
	    return action;
	}
    }
	
    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	e = Pexpr(replacement);

    action = a_expr_guts(e);
    if (action == tna_error) return action;
    if(e->base == ELIST)
	action = walk(e->e2);
    return action;
}

tree_node_action walker::a_baseclass(Pnode ta, Pbcl b, Pnode& replacement) 
{
    tree_node_action action = pre_act_on_node(ta, nc_baseclass, Pnode(b), replacement);

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	b = Pbcl(replacement);

    action = walk(b->bclass);
    if(action == tna_error) return action;

    action = walk(b->init);
    if(action == tna_error) return action;

    action = walk(b->next);
    if(action == tna_error) return action;

    return tna_continue;
}


/* a name is also an expr. */
   

tree_node_action walker::a_name(Pnode ta, Pname n, Pnode& replacement) 
{
    int derr;
    int cl_error;
    tree_node_action action = pre_act_on_node(ta, nc_name, Pnode(n), replacement);

    /* n_list is a sibling, not a child. We always process it
       except in case of an error. */
    if(action == tna_stop) {
	cl_error = 0;
	if(!fetching () && replacement)
	    n = Pname(replacement);
	if((classify_node(Pnode(n), cl_error) == nc_name) && !cl_error) {
	    if(depth > 0 || !control.dont_chase_lists_top) {
		action = walk(n->n_list); 
		if(action == tna_error) return action;
	    }
	}
	return tna_stop;
    }	

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	n = Pname(replacement);

/* We don't walk n_tbl_list. Its not part of the graph.
   */

    switch(derr = n->discriminator(0)) {
      case 0:
	break;
      case 1:
	action = walk(n->n_qualifier);
	if(action == tna_error) return action;
	break;
      case 2:
	action = walk(n->n_realscope);
	if(action == tna_error) return action;
	break;
      default:
	error ("a_name: discrim error %d on union 0.", derr);
	return tna_error;
    }

    action = a_expr_guts(Pexpr(n));
    if(action == tna_error) return action;

    if(depth > 0 || !control.dont_chase_lists_top) {
	action = walk(n->n_list);
	if(action == tna_error) return action;
    }
    
    return action;
}
    
/* --- NOTE: s_list should be deferred until AFTER the post-action
   procedure is called, if there is one. Since no one uses
   post-actions yet I haven't bothered to make this fix.
   --benson */

tree_node_action walker::a_stmt(Pnode ta, Pstmt s, Pnode& replacement) 
{
    int cl_error;
    int derr;
    tree_node_action action = pre_act_on_node(ta, nc_stmt, Pnode(s), replacement);

    if(action == tna_stop) {
	if(!fetching () && replacement)
	    s = Pstmt(replacement);
	cl_error = 0;
	if((classify_node(Pnode(s), cl_error) == nc_stmt) && !cl_error) {
	    /* s_list is not our subordinate, it is our peer */
	    if(depth > 0 || !control.dont_chase_lists_top) {
		action = walk(s->s_list); /* continue walk of sibs */
		if (action == tna_error) return tna_error;
	    }
	}
	return tna_stop;
    }

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	s = Pstmt(replacement);

    action = walk(s->s);
    if(action == tna_error) return action;

    action = walk(s->memtbl);
    if(action == tna_error) return action;

    switch(derr = s->discriminator(0)) {
      default:
	error ("a_stmt: discrim error %d on union 0.", derr);
	return tna_error;
      case 4:
      case 0: break;
      case 1:
	action = walk(s->d);
	if(action == tna_error) return action;
	break;
      case 2:
	action = walk(s->e2);
	if(action == tna_error) return action;
	break;
      case 3:
	action = walk(s->has_default);
	if(action == tna_error) return action;
	break;
      case 5:
	action = walk(s->ret_tp);
	if(action == tna_error) return action;
	break;
    }

    switch(derr = s->discriminator(1)) {
      default:
	error ("a_stmt: discrim error %d on union 1.", derr);
	return tna_error;
      case 2:
      case 0: break;
      case 1:
	action = walk(s->e);
	if(action == tna_error) return action;
	break;
      case 3:
	action = walk(s->s2);
	if(action == tna_error) return action;
	break;
    }

    switch(derr = s->discriminator(2)) {
      default:
	error ("a_stmt: discrim error %d on union 2.", derr);
	return tna_error;
      case 0: break;
      case 1:
	action = walk(s->for_init);
	if(action == tna_error) return action;
	break;
      case 2:
	action = walk(s->else_stmt);
	if(action == tna_error) return action;
	break;
      case 3:
	action = walk(s->case_list);
	if(action == tna_error) return action;
	break;
    }

    if(depth > 0 || !control.dont_chase_lists_top) {
	action = walk(s->s_list);
	if(action == tna_error) return action;
    }

    return tna_continue;
}

tree_node_action walker::a_ia(Pnode ta, struct ia * ia, Pnode& replacement) 
{
    tree_node_action action = pre_act_on_node(ta, nc_ia, Pnode(ia), replacement);

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	ia = (struct ia *)&replacement;

    action = walk(ia->local);
    if(action == tna_error) return action;

    action = walk(ia->arg);
    if(action == tna_error) return action;
    
    action = walk(ia->tp);
    if(action == tna_error) return action;

    return tna_continue;
}

tree_node_action walker::a_iline(Pnode ta, Pin iline, Pnode& replacement) 
{
    tree_node_action action = pre_act_on_node(ta, nc_iline, Pnode(iline), replacement);

    if(action != tna_continue) return action;

    if(!fetching () && replacement)
	iline = Pin(replacement);

    action = walk(iline->fct_name);
    if(action == tna_error) return action;

    action = walk(iline->i_next);
    if(action == tna_error) return action;
    
    action = walk(iline->i_table);
    if(action == tna_error) return action;

    action = walk(iline->i_args);
    if(action == tna_error) return action;

    return tna_continue;
}
0707071010112046151004440001630000160000010107200466055423100001400000004551tree_walk.h/* ident "@(#)ctrans:src/tree_walk.h	1.2" */
/* -*- Mode: C -*- Begin include file tree_walk.H */
/*
	$Source: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/xptcfront/cfront.cpio,v $ $RCSfile: cfront.cpio,v $
	$Revision: 1.1.1.1 $		$Date: 2018/04/24 17:21:35 $
	$Author: root $		$Locker:  $
	$State: Exp $
*/

#ifndef _TREE_WALK
#define _TREE_WALK

#include "cfront.h"
#include "node_classes.h"
#include <iostream.h>
#include "ios_printf.h"
#include "hash.h"

enum tree_node_action {
    tna_continue = 0,		/* plain vanilla */
    tna_stop = 1,		/* don't proceed */
    tna_error = 2,		/* stop entire walk now. */
};

/* procedural interface to indirect via a pointer. */
typedef int (*tree_fetch_proc) (void * info,
				void * pointer,
				unsigned long length,
				int zero_stop,  /* for character strings.*/
				void * target);


const tree_fetch_proc null_tfp = (tree_fetch_proc) 0;

class tree_walk_tree {
  public:
    tree_walk_tree * parent;
    char storage[1];		/* variable amt, specified by caller. */
};

/* The trailing int here controls whether to remember the
   node in the hash table to short-circuit meeting it again */

typedef void (*tree_pre_action)
    (Pnode&, node_class, void *, tree_node_action&, int, Pnode, 
     tree_walk_tree&, int&);


typedef void (*tree_post_action)
    (Pnode&, node_class, void *, tree_node_action&, int, Pnode, 
     tree_walk_tree&);

typedef void (*errorp) (char, const char *);

class tree_walk_control {
  public:
    int version;
    void * callback_info;
    tree_fetch_proc fetcher;
    tree_pre_action action_proc;
    tree_post_action post_action_proc;
    int (*i_error) (int, const char *); /* usually part of cfront */
    int call_i_error;		/* if 0, just use the following */
    ostream * error_stream;
    Hash * nodes_seen_hash;	/* allows this to be global over
				 more than one call to the walker. */
    int resolve_by_name;
    int alloc_stack_bytes;
    /* if on, n_list and s_list are ignored for the very top node. 
       this is for the benefit of the printer. */
    int dont_chase_lists_top;
    tree_walk_control () {
	version = 1;
	callback_info = 0;
	fetcher = null_tfp;
	call_i_error = 0;
	error_stream = &cerr;
	nodes_seen_hash = 0;
	resolve_by_name = 1;	/* the dumper turns this off */
	alloc_stack_bytes = 0;
	post_action_proc = 0;
	dont_chase_lists_top = 0;
    }
};

tree_node_action walk_tree (tree_walk_control& c, Pnode& n);

#endif
0707071010112045721004440001630000160000010210200466055412600000600000054504typ.c/*ident	"@(#)ctrans:src/typ.c	1.4" */
/**************************************************************************

	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.

typ.c:


***************************************************************************/
 
#include "cfront.h"
#include "size.h"

Pbase short_type;
Pbase int_type;
Pbase char_type;
Pbase long_type;

Pbase uchar_type;
Pbase ushort_type;
Pbase uint_type;
Pbase ulong_type;

Pbase zero_type;
Pbase float_type;
Pbase double_type;
Pbase ldouble_type;
Pbase void_type;
Pbase any_type;

Ptype Pint_type;
Ptype Pchar_type;
Ptype Pvoid_type;
Ptype Pfctvec_type;

Ptable gtbl;
Ptable ptbl;

Pname Cdcl;
Pstmt Cstmt;

bit new_type;

void echeck(Ptype t1, Ptype t2)
/*
	t1 is an enum, t2 is assigned to it
*/
{
	if (t1 == t2) return;

//error('d',"echeck(%t,%t) %d %d",t1,t2,t1->base,t2->base);
//error('d',"se %d promote: %d",suppress_error, enum_promote);
	if (t1->base==EOBJ
	&& t2->base==EOBJ
	&& Pbase(t1)->b_name->tp == Pbase(t2)->b_name->tp) return;

	if (enum_promote) return;
	error(strict_opt?0:'w',"%t assigned to %t (anachronism)",t2,t1);
}


Ptype np_promote(TOK oper, TOK r1, TOK r2, Ptype t1, Ptype t2, TOK p)
/*
	an arithmetic operator "oper" is applied to "t1" and "t2",
	types t1 and t2 has been checked and belongs to catagories
	"r1" and "r2", respectively:
		A	ANY
		Z	ZERO
		I	CHAR, SHORT, INT, LONG, FIELD, or EOBJ
		F	FLOAT DOUBLE LDOUBLE
		P	PTR (to something) or VEC (of something)
	test for compatability of the operands,
	if (p) return the promoted result type
*/
{
	if (r2 == 'A') return t1;

//error('d',"promote(%t,%t,%k)",t1,t2,oper);

	switch (r1) {
	case 'A':	return t2;
	case 'Z':
		switch (r2) {
		case 'Z':		return int_type;
		case 'I':
		case 'F':
			if(oper==DEREF) return any_type;
			return (p) ? Pbase(t2)->arit_conv(0) : 0;
		case 'P': switch (oper) {
			case PLUS:
			case ASPLUS:	if(t2!=Pvoid_type) break;
			default:	return any_type;
			}
			return t2;
		case FCT:	error("zero%kF",oper); return any_type;
		default:	error('i',"zero(%d)",r2);
		}
	case 'I':
		switch (r2) {
		case 'Z': t2 = 0;
		case 'I':
		case 'F': 
			if(oper==DEREF) return any_type;
			return (p) ? Pbase(t1)->arit_conv(Pbase(t2)) : 0;
		case 'P': switch (oper) {
			case PLUS:
			case ASPLUS:	if(t2!=Pvoid_type) break;
			default:	error("int%kP",oper); return any_type;
			}
			return t2;
		case FCT: error("int%kF",oper); return any_type;
		default: error('i',"int(%d)",r2); return any_type;
		}
	case 'F':
		switch (r2) {
		case 'Z': t2 = 0;
		case 'I':
		case 'F': 
			if(oper==DEREF) return any_type;
			return (p) ? Pbase(t1)->arit_conv(Pbase(t2)) : 0;
		case 'P': error("float%kP",oper); return any_type;
		case FCT: error("float%kF",oper); return any_type;
		default: error('i',"float(%d)",r2); return any_type;
		}
	case 'P':
		switch (r2) {
		case 'Z': return t1;
		case 'I':
			switch (oper) {
			case PLUS:
			case MINUS:
			case ASPLUS:
			case ASMINUS:
				if (t1->check(Pvoid_type,0)==0) {
					return any_type;
				}
				break;
			default: error("P%k int",oper); return any_type;
			}
			return t1;
		case 'F': error("P%k float",oper); return any_type;
		case 'P':
			if (t1->check(t2,ASSIGN)) {
				switch (oper) {
				case EQ:
				case NE:
				case LE:
				case GE:
				case GT:
				case LT:
				case QUEST:
					if (t2->check(t1,ASSIGN) == 0) goto zz;
				}
				error("T mismatch:%t %k%t",t1,oper,t2);
				return any_type;
			}
			zz:
			switch (oper) {
			case MINUS:	
				return (t2!=Pvoid_type) ? int_type : any_type;
			case ASMINUS:	error("P -=P"); return any_type;
			case PLUS:	error("P +P"); return any_type;
			case ASPLUS:	error("P +=P"); return any_type;
			case LS:
			case RS:	return any_type;
			default:	return (t1!=Pvoid_type) ? t1 : any_type;
			}
		case FCT:	return t1;
		default:	error('i',"P(%d)",r2);
		}
	case FCT:
		if(oper == QUEST) {
			switch (r2) {
			case 'Z':
				return any_type;
			case 'P':
				return t2;
			case 'I':
			case 'F':
				error("F%k%t",oper,t2);
			default:
				return t1;
			}
		}
		error("F%k%t",oper,t2);
		return any_type;
	default:
		error('i',"np_promote(%d,%d)",r1,r2);
	}
}

TOK type::kind(TOK oper, TOK v)
/*	v ==	'I'	integral
		'N'	numeric
		'P'	numeric or pointer
*/
{
	Ptype t = this;
	if (this == 0) error('i',"type::kind(): this==0");
xx:
	switch (t->base) {
	case ANY:	return 'A';
	case ZTYPE:	return 'Z';
	case FIELD:
	case CHAR:
	case SHORT:
	case INT:
	case LONG:
	case EOBJ:	return 'I';
	case FLOAT:
	case LDOUBLE:
	case DOUBLE:	if (v == 'I') error("float operand for %k",oper);	return 'F';
	case VEC:
	case PTR:	if (v != 'P') error("P operand for %k",oper);
			switch (oper) {
			case INCR:
			case DECR:
			case MINUS:
			case PLUS:
			case ASMINUS:
			case ASPLUS:
				if (t->base==PTR
				&& (Pptr(t)->memof || Pptr(t)->typ->base==FCT))
					error("%t operand of%k",this,oper);
				else
					Pptr(t)->typ->tsizeof(); // get increment
				break;
			default:
				if (t->base==PTR
				&& (Pptr(t)->memof || Pptr(t)->typ->base==FCT))
					error("%t operand of%k",this,oper);
			case ANDAND:
			case OROR:
			case ASSIGN:
			case NE:
			case EQ:
			case IF:
			case WHILE:
			case DO:
			case FOR:
			case QUEST:
			case NOT:
					break;
			}
			return 'P';
	case RPTR:	error("R operand for %k",oper);			return 'A';
	case TYPE:	t = Pbase(t)->b_name->tp;			goto xx;
	case FCT:	if (v != 'P') error("F operand for %k",oper);	return FCT;
	case OVERLOAD:	error("overloaded operand for %k",oper);	return 'A';
	case CLASS:
	case ENUM:	error("%k operand for %k",base,oper);		return 'A';
	default:	error("%t operand for %k",this,oper);		return 'A';
	}
}

void type::dcl(Ptable tbl)
/*
	go through the type (list) and
	(1) evaluate vector dimensions
	(2) evaluate field sizes
	(3) lookup struct tags, etc.
	(4) handle implicit tag declarations
*/
{
static arg_fudge;

	Ptype t = this;

	if (this == 0) error('i',"T::dcl(this==0)");
	if (tbl->base != TABLE) error('i',"T::dcl(%d)",tbl->base);

xx:
//error('d',"type::dcl %k",t->base);
	switch (t->base) {
	case TYPE:
		t = Pbase(t)->b_name->tp;
		goto xx;
	case PTR:
	case RPTR:
	{	Pptr p = Pptr(t);
		t = p->typ;
		if (t->base == TYPE) {
			Ptype tt = Pbase(t)->b_name->tp;
			if (tt->base == FCT) p->typ = tt;
			return;
		}
		goto xx;
	}

	case VEC:
	{	Pvec v = Pvec(t);
		Pexpr e = v->dim;
		if (e) {
			Ptype et;
			v->dim = e = e->typ(tbl);
			et = e->tp;
			if (et->integral(0) == 'A') {
				error("UN in array dimension");
			}
			else {
				long i;
				Neval = 0;
				i = e->eval();
				if (Neval == 0) {
					if (largest_int<i)
						error("array dimension too large");
					v->size = int(i);

				if ( lcl_tbl == 0 )

					DEL(v->dim);
					v->dim = 0;
				}

				if (new_type) {
					if (Neval)
						;
					else if (i == 0)
						v->dim = zero;
					else if (i < 0) {
						error("negative array dimension");
						i = 1;
					}
				}
				else {
					if (Neval)
						error("%s",Neval);
					else if (i == 0)
						error('w',"array dimension == 0");
					else if (i < 0) {
						error("negative array dimension");
						i = 1;
					}
				}
			}
		}
		t = v->typ;
	llx:
		switch (t->base) {
		case TYPE:
			t = Pbase(t)->b_name->tp;
			goto llx;
		case FCT:
			v->typ = t;
			break;
		case VEC:				
			if (Pvec(t)->dim==0 && Pvec(t)->size==0) error("null dimension (something like [][] seen)");
			if (arg_fudge) {
				v->base = PTR;	// X[12][10] ==> X(*)[10]
				Pptr(v)->rdo = 0;
				Pptr(v)->memof = 0;
			}
		}
		goto xx;
	}

	case FCT:
	{	Pfct f = Pfct(t);
void dargs(Pname, Pfct, Ptable);
		if (f->argtype) dargs(0,f,tbl);
		for (Pname n=f->argtype; n; n = n->n_list) {
			arg_fudge++;
			n->tp->dcl(tbl);
			arg_fudge--;
		}
		Pname cn = f->returns->is_cl_obj();
		if (cn && Pclass(cn->tp)->has_itor())
			make_res(f);
		else if (f->f_this == 0)
			f->f_args = f->argtype;
		t = f->returns;
		goto xx;
	}

	case FIELD:
	{	Pbase f = Pbase(t);
		Pexpr e = Pexpr(f->b_name);
		long i;
		Ptype et;
		e = e->typ(tbl);
		f->b_name = Pname(e);
		et = e->tp;
		if (et->integral(0) == 'A') {
			error("UN in field size");
			i = 1;
		}
		else {
			Neval = 0;
			i = e->eval();
			if (Neval)
				error("%s",Neval);
			else if (i < 0) {
				error("negative field size");
				i = 1;
			}
			else if (f->b_fieldtype->tsizeof()*BI_IN_BYTE < i)
				error("field size > sizeof(%t)",f->b_fieldtype);
			DEL(e);
		}
		f->b_bits = int(i);
		f->b_name = 0;
		break;
	}
	}
}

bit vrp_equiv;		// vector == pointer equivalence used in check()
bit const_problem;	// types differs only in const
int Vcheckerror;

bit type::check(Ptype t, TOK oper)
/*
	check if "this" can be combined with "t" by the operator "oper"

	used for check of
			assignment types		(oper==ASSIGN)
			declaration compatability	(oper==0)
                        parameterized type formals      (oper==255)
                          as for (oper==0) but
                          special checking for ANY types
			argument types			(oper==ARG)
			return types			(oper==RETURN)
			overloaded function name match	(oper==OVERLOAD)
			overloaded function coercion	(oper==COERCE)
			virtual function match		(oper==VIRTUAL)

	NOT for arithmetic operators

	return 1 if the check failed

	checking of const const* and *const is a mess
*/
{
        const unsigned int strict_any_check = (oper == 255);

	Ptype t1 = this;
	Ptype t2 = t;
	Ptype tt1 = this;
	Ptype tt2 = t;
	int cnst1 = 0;
	int cnst2 = 0;
	TOK b1, b2;
	bit first = 1;
	TOK r;
	int vv;
	int ptr_count = 0;
	int fct_seen = 0;
	int over;
	Pptr p1 = 0;
	Pptr p2 = 0;
	int p_count = 0;

        if (strict_any_check) oper = 0;

//error('d',"check %k %t %t",oper,t1,t2);
	if (t1==0 || t2==0) error('i',"check(%p,%p,%d)",t1,t2,oper);

	if (oper==VIRTUAL) {
		vv = 1;
		Vcheckerror = 0;
		oper = 0;
	}
	else
		vv = 0;

	if (oper == OVERLOAD) {
		over = 1;
		oper = 0;
	}
	else
		over = 0;

	const_problem = 0;

	while (t1 && t2) {
	top:
//error('d',"top: %t (%d) %t (%d)",t1,t1->base,t2,t2->base);
		if (t1 == t2) {
			if (cnst1==cnst2) return 0;
			if (oper) {
//error('d',"oper %d cnst1 %d cnst2 %d ptr %d",oper,cnst1,cnst2,tt1->is_ptr());
				if (tt1 = tt1->is_ptr()) {

					// const* = int*
					if (cnst2<cnst1) return 0;

					// int* = int *const
					if (cnst2==1 && tt2->tconst()) {
						// check for int* = const *const
						tt2 = tt2->is_ptr();
						if (tt2->tconst()) return 1;
						return 0;
					}
				}
				else {	// int = const allowed
					if (oper==ARG || cnst1<cnst2) return 0;
				}
			}
			else {
				if (p_count) {
					int pr1 = p1->rdo ? 1 : 0;
					int pr2 = p2->rdo ? 1 : 0;
					if (pr1+cnst1==pr2+cnst2)
						return 0;
				}
			//	const_problem = 1;
			}

			const_problem = 1;
			return 1;
		}

                if  ((t1->base == ANY || t2->base == ANY)) {
                          if (! strict_any_check) return 0;
                          // Perform the check for strict_any, ie. the
                          return ((t1 == t2) ? 0 : 1) ;
                }

		b1 = t1->base;
		switch (b1) {
		case TYPE:
			if (Pbase(t1)->b_const) cnst1++;
			t1 = Pbase(t1)->b_name->tp;
			goto top;
		}

		b2 = t2->base;
		switch (b2) {
		case TYPE:
			if (Pbase(t2)->b_const) cnst2++;
			t2 = Pbase(t2)->b_name->tp;
			goto top;
		}

//error('d',"oper %k b1 %k b2 %k",oper,b1,b2);
		if (b1 != b2) {
			switch (b1) {
			case PTR:
				switch (b2) {
				case VEC:
					if (ptr_count) return 1;
                                	// ptr/vec equivalence does not
                                	// apply to declaration matching
					t1 = Pptr(t1)->typ;
					t2 = Pvec(t2)->typ;
					if (oper == 0 && over==0) return 1;
					ptr_count++;
					first = 0;
					goto top;
				case FCT:
					t1 = Pptr(t1)->typ;
					if (t1->base!=VOID) 
						if (first==0 || t1->base!=b2) return 1;
					first = 0;
					goto top;
				}
				first = 0;
				break;

                        case FCT:
                                switch( b2 ) {
                                case PTR:
                                        t2 = Pptr(t2)->typ;
                                        if (t1->base!=VOID
					&& (first==0||t2->base!=b1)) return 1;
                                        first = 0;
                                        goto top;
                                }
                                first = 0;
                                break;

			case VEC:
				switch (b2) {
				case PTR:
					if (ptr_count) return 1;
					t1 = Pvec(t1)->typ;
					t2 = Pptr(t2)->typ;
					switch (oper) {
					case ARG:
					case ASSIGN:
					case COERCE:
						break;
					case 0:
						if (over) break;
					default:
						return 1;
					}
					ptr_count++;
					first = 0;
					goto top;
				}
				first = 0;
				break;
			}
			goto base_check; 
		}

		switch (b1) {
		case VEC:
//error('d',"vec %k %d %d",oper,Pvec(t1)->size,Pvec(t2)->size);
			if (first==0 && Pvec(t1)->size!=Pvec(t2)->size) return 1;
			first = 0;
			t1 = Pvec(t1)->typ;
			t2 = Pvec(t2)->typ;
			ptr_count++;
			break;

		case PTR:
		case RPTR:
			first = 0;
			p1 = Pptr(t1);
			p2 = Pptr(t2);
			p_count++;

			if (p1->memof != p2->memof) {

				if(p1->memof!=0 && p2->memof!=0
				    && p1->memof->baseof(p2->memof)==0)
					return 1;

				int flag1=0,flag2=0;
				t1 = p1->typ;
				t2 = p2->typ;
				while (t1->base == TYPE) {
					flag1++;
					t1 = Pbase(t1)->b_name->tp;
				}
				while (t2->base == TYPE) {
					flag2++;
					t2 = Pbase(t2)->b_name->tp;
				}
				if (t1 != t2 || (!flag1 && !flag2)) {
					if (p1->memof==0
					|| p2->memof==0
					|| p1->memof->baseof(p2->memof)==0)
						return 1;
			    		Nstd++;
				}
			}

			t1 = p1->typ;
			t2 = p2->typ;
			ptr_count++;

			if (oper==0) {
				int pr1 = p1->rdo ? 1 : 0;
				int pr2 = p2->rdo ? 1 : 0;
				if (pr1+cnst1!=pr2+cnst2
				&& cnst1+Pbase(t1)->b_const!=cnst2+Pbase(t2)->b_const) {
					// const_problem only if nothing
					// more serious is wrong
					if (t1->check(t2,0) == 0) const_problem = 1;
					return 1;
				}

				if (b1==RPTR && t1->tconst()!=t2->tconst())
					const_problem = 1;
			}
			break;

		case FCT:
			first = 0;
		{	Pfct f1 = Pfct(t1);
			Pfct f2 = Pfct(t2);
			Pname a1 = f1->argtype;
			Pname a2 = f2->argtype;
			TOK k1 = f1->nargs_known;
			TOK k2 = f2->nargs_known;
			int n1 = f1->nargs;
			int n2 = f2->nargs;
//error('d',"f1%t f2%t",f1,f2);
			if (f1->memof != f2->memof) {
				if (f1->memof==0 && f2->f_this==0)	//SSS
					goto sss;
				if (vv == 0)	// match even if private base class
					if (f1->memof==0
					|| f2->memof==0
					|| f1->memof->baseof(f2->memof)==0) return 1;
				Nstd++;
				sss:;	//SSS
			}

			if (k1 != k2) return 1;

			if (n1!=n2 && k1 && k2) {
				goto aaa;
			}
			else if (a1 && a2) {
				int i = 0;
				while (a1 && a2) {
					i++;
					if (a1->tp->check(a2->tp,over?OVERLOAD:0)) return 1;
					a1 = a1->n_list;
					a2 = a2->n_list;
				}
				if (a1 || a2) goto aaa;
			}
			else if (a1 || a2) {
			aaa:
//error('d',"aaa k1 %d k2 %d",k1,k2);
				if (k1 == ELLIPSIS) {
					switch (oper) {
					case 0:
						if (a2 && k2==0) break;
						return 1;
					case ASSIGN:
						if (a2 && k2==0) break;
						return 1;
					case ARG:
						if (a1) return 1;
						break;
				//	case OVERLOAD:
					case COERCE:
						return 1;
					}
				}
				else if (k2 == ELLIPSIS) {
					return 1;
				}
				else if (k1 || k2) {
					return 1;
				}
			}

			t1 = f1->returns;
			t2 = f2->returns;
			fct_seen = 1;

			switch (oper) {	//CCC
			case 0:
				if (f1->f_const!=f2->f_const) {
					if (t1->check(t2,0)==0) const_problem = 1;
					return 1;
				//	if (vv == 0) return 1;
				//	Vcheckerror = 1;
				}
				break;
			default:	// really pointer to function
				if (f1->f_const && f2->f_const==0) return 1;
			}


			if (vv && t1->check(t2,0)) { Vcheckerror = 1; return 1; }
		}
			break;

		case FIELD:
			goto field_check;
		case CHAR:
		case SHORT:
		case INT:
		case LONG:
			goto int_check;
		case FLOAT:
		case DOUBLE:
		case LDOUBLE:
			goto float_check;
		case EOBJ:
			goto enum_check;
		case COBJ:
			goto cla_check;
		case ZTYPE:
		case VOID:
			return 0;
		default:
			error('i',"T::check(o=%d %d %d)",oper,b1,b2);
		}
	}

	if (t1 || t2) {
		const_problem = 0;	// not a problem: the type itself is bad
		return 1;
	}
	return 0;

field_check:
	switch (oper) {
	case 0:
	case ARG:
		error('i',"check field?");
	}
	return 0;

enum_check:
//error('d',"enum check %t %t",t1,t2);
	if (Pbase(t1)->b_name->tp != Pbase(t2)->b_name->tp) goto base_check;
	goto const_check;

float_check:
	if (first==0 && b1!=b2 && b2!=ZTYPE) return 1;
	// no break

int_check:
//error('d',"int_check");
	if (Pbase(t1)->b_unsigned != Pbase(t2)->b_unsigned) {
		if (first == 0) return 1;
		if (oper /*&& oper!=OVERLOAD*/)
			Nstd++;
		else
			return 1;
	}
	// no break

const_check:
//error('d',"const_check %t (%d) %t (%d)",t1,t1->tconst(),t2,t2->tconst());
	if (oper==0) {
//error('d',"oper==0: t1 %t t2 %t cnst1 %d cnst2 %d",t1,t2,cnst1,cnst2);
		if (t1->tconst()+cnst1!=t2->tconst()+cnst2) {
			const_problem = 1;
			return 1;
		}
	}
	else if (first==0) {
		if (t1->tconst()+cnst1==0 && t2->tconst()+cnst2) {
//error('d',"t1 %t t2 %t cnst1 %d cnst2 %d",t1,t2,cnst1,cnst2);
//error('d',"tt1 %t %d cnst1 %d cnst2 %d",tt1,tt1->is_ptr(),cnst1,cnst2);
//error('d',"tt2 %t",tt2);
			if (tt1->is_ptr()) {
				if (fct_const || vec_const) cnst2--;

				// const* = int*
				if (cnst2-tt2->tconst()<cnst1-tt1->tconst()) return 0;

				// int* = *const
				//if (cnst2==1 && tt2->tconst()) return 0;

				// const T* = const T*
				if (t2->tconst()+cnst2==t1->tconst()+cnst1) return 0;
			}
			else {	// int = const allowed
				if (cnst1<cnst2) return 0;
			}
			const_problem = 1;
			return 1;
		}
		else {	// const* vs int *const
/*
 //error('d',"t1 %t cnst1 %d t2 %t cnst2 %d",t1,cnst1,t2,cnst2);
			if (tt1->is_ptr()) {
				int tt1c = tt1->tconst();
				int tt2c = tt2->tconst() - fct_const - vec_const;
 //error('d',"tt1c %d tt2c %d",tt1c,tt2c);
				if (tt1c<tt2c) return 1;
				int t1c = t1->tconst();
				int t2c = t2->tconst() - fct_const - vec_const;
 //error('d',"t1c %d t2c %d",t1c,t2c);
				if (cnst1+t1c<cnst2+t2c) return 1;
				if (tt2c<tt1c	// *const = *
				&& cnst1+t1c>cnst2+t2c)	// T = constT
					return 1;
			}
*/
			
		}
	}
	else {
//error('d',"first t1 %t t2 %t cnst1 %d cnst2 %d",t1,t2,cnst1,cnst2);
	}
//error('d',"return 0");
	return 0;

cla_check:
	{	Pname n1 = Pbase(t1)->b_name;
		Pname n2 = Pbase(t2)->b_name;
//error('d',"cla_check %n %n ptr_count %d",n1,n2,ptr_count);
		if (n1 == n2) goto const_check;

                // once again, a more comprehensive check for classes,
                // since they may be parametrized.
                if ((t1->base == COBJ) && (t2->base == COBJ) &&
                   ((Pclass(n1->tp)->same_class(Pclass(n2->tp)))))
                        goto const_check;

		if (/*first || */1<ptr_count || fct_seen) return 1;

		switch (oper) {
		case ARG:
		case ASSIGN:
		case RETURN:
		case COERCE:
		{
			ppbase = PUBLIC;
			if (Pclass(n2->tp)->is_base(n1->string)) {
				if (ppbase!=PUBLIC) {
					const_problem = 0;
				//	vrp_equiv = 0;
					return 1;	// private or protected base
				}
				Nstd++;
				goto const_check;
			}
		}
			// no break
		case 0:
		case OVERLOAD:
			const_problem = 0;
		//	vrp_equiv = 0;
			return 1;
		}

		goto const_check;
	}

base_check:
//error('d',"base_check t1=%t t2=%t oper=%d %s",t1,t2,oper,first?"first":"");
//error('d',"ptr_count %d",ptr_count);
	if (oper)
	if (first || 1!=ptr_count) {
		if (b1==VOID || b2==VOID) return 1;
	}
	else {
		if (b1 == VOID) {		// check for void* = T*
			register Ptype tpx = this;
		tpxloop:
			switch (tpx->base) {	// t1 == void*
			default:
					const_problem = 0;
					return 1;
			case VOID:	break;
			case PTR:
			case VEC:	tpx = Pvec(tpx)->typ;
					goto tpxloop;
			case TYPE:	tpx = Pbase(tpx)->b_name->tp;
					goto tpxloop;
			}

			tpx = t;
		bloop:
			switch (tpx->base) {	// t2 == T*
			default:
					const_problem = 0;
					return 1;
			case VEC:
			case PTR:
			case FCT:	Nstd++;
				//	return 0;
					goto const_check; // prevent void* = const*
			case TYPE:	tpx = Pbase(tpx)->b_name->tp;
					goto bloop;
			}
		}

		if (b2 != ZTYPE) {
			const_problem = 0;
			return 1;
		}
	}
//error('d',"oper %d b1 %d b2 %d cp %d",oper,b1,b2,const_problem);
	switch (oper) {
	case 0:
		if (b1 != b2) {
			const_problem = 0; // we have a bigger problem
		//	vrp_equiv = 0;
		}
		return 1;
	case COERCE:	// could probably be merged with the cases below
		switch (b1) {
		case EOBJ:
		case ZTYPE:
		case CHAR:
		case SHORT:
		case INT:
			switch (b2) {
				case LONG:
				case FLOAT:
				case DOUBLE:
				case LDOUBLE:
				case EOBJ:
				case ZTYPE:
				case CHAR:
				case SHORT:
				case INT:
				case FIELD:
					Nstd++;
					suppress_error++;
					if (b1 == EOBJ) echeck(t1,t2);
					suppress_error--;
					goto const_check;
			}
			return 1;
		case LONG:	// char, short, and int promotes to long
			switch (b2) {
				case FLOAT:
				case DOUBLE:
				case LDOUBLE:
			case ZTYPE:
			case EOBJ:
			case CHAR:
			case SHORT:
			case INT:
			case FIELD:
				Nstd++;
				goto const_check;
			}
			return 1;
		case FLOAT:
		//	switch (b2) {
		//	case ZTYPE:
		//		Nstd++;
		//	case FLOAT:
		//	case DOUBLE:
		//		goto const_check;
		//	}
		//	return 1;
		case DOUBLE:	// char, short, int, and float promotes to double
		case LDOUBLE:
			switch (b2) {
			case LONG:
			case ZTYPE:
			case EOBJ:
			case CHAR:
			case SHORT:
			case INT:
		//		Nstd++;
			case FLOAT:
			case DOUBLE:
			case LDOUBLE:
Nstd++;
				goto const_check;
			}
			return 1;
		case PTR:
			switch (b2) {
			case ZTYPE:
				Nstd++;
				goto const_check;
			}
		case RPTR:
		case VEC:
		case COBJ:
		case FCT:
			return 1;
		}
	case ARG:
	case ASSIGN:
	case RETURN:
		switch (b1) {
		case COBJ:
			return 1;
		case EOBJ:
		case ZTYPE:
		case CHAR:
		case SHORT:
		case INT:
		case LONG:
			suppress_error++;
			r = t2->num_ptr(ASSIGN);
			suppress_error--;
			switch (r) {
			case 'F':
			//	if (oper!=ARG) error('w',"%t assigned to%t",t2,t1);
				break;
			case 'A':
			case 'P':
			case FCT:	return 1;
			}
			if (b1 == EOBJ) echeck(t1,t2);	
			break;
		case FLOAT:
		case DOUBLE:
		case LDOUBLE:
			suppress_error++;
			r = t2->numeric(ASSIGN);
			suppress_error--;
			switch (r) {	
			case 'A':
			case 'P':
			case FCT:	return 1;
			}
			break;
		case VEC:
			if(oper==ARG && b2==ZTYPE) goto const_check;
			return 1;
		case PTR:
			suppress_error++;
			r = t2->num_ptr(ASSIGN);
			suppress_error--;
			switch (r) {
			case 'A':
			case 'I':
			case 'F':	return 1;
			case FCT:	if (Pptr(t1)->typ->base != FCT) return 1;
			}
			break;
		case RPTR:
			return 1;
		case FCT:
			switch (oper) {
			case ARG:
			case ASSIGN:
				return 1;
			}
		}	
		break;
	}
	goto const_check;
}

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

typ2.c:

***************************************************************************/
 
#include "cfront.h"
#include "size.h"

extern int chars_in_largest;
int largest_int;

void typ_init()
{	
	chars_in_largest = strlen(LARGEST_INT);
	largest_int = int(str_to_long(LARGEST_INT));

	defa_type = new basetype(INT,0);	// note defa_type!=int_type
	int_type = new basetype(INT,0);		// but they both represent `int'

	PERM(int_type); int_type->defined = DEFINED ;
	PERM(defa_type); defa_type->defined = DEFINED ;

	moe_type = new basetype(INT,0);
	PERM(moe_type); moe_type->defined = DEFINED ;
	moe_type->b_const = 1;
	moe_type->check(0);

	uint_type = new basetype(INT,0);
	PERM(uint_type); uint_type->defined = DEFINED ;
	uint_type->type_adj(UNSIGNED);
	uint_type->check(0);

	long_type = new basetype(LONG,0);
	PERM(long_type); long_type->defined = DEFINED ;
	long_type->check(0);

	ulong_type = new basetype(LONG,0);
	PERM(ulong_type); ulong_type->defined = DEFINED ;
	ulong_type->type_adj(UNSIGNED);
	ulong_type->check(0);

	short_type = new basetype(SHORT,0);
	PERM(short_type); short_type->defined = DEFINED ;
	short_type->check(0);

	ushort_type = new basetype(SHORT,0);
	PERM(ushort_type); ushort_type->defined = DEFINED ;
	ushort_type->type_adj(UNSIGNED);
	ushort_type->check(0);

	float_type = new basetype(FLOAT,0);
	PERM(float_type); float_type->defined = DEFINED ;

	double_type = new basetype(DOUBLE,0);
	PERM(double_type); double_type->defined = DEFINED ;

	ldouble_type = new basetype(LDOUBLE,0);
	PERM(ldouble_type); ldouble_type->defined = DEFINED ;

	zero_type = new basetype(ZTYPE,0);
	PERM(zero_type); zero_type->defined = DEFINED ;
	zero->tp = zero_type;

	void_type = new basetype(VOID,0);
	PERM(void_type); void_type->defined = DEFINED ;

	char_type = new basetype(CHAR,0);
	PERM(char_type); char_type->defined = DEFINED ;

	uchar_type = new basetype(CHAR,0);
	PERM(uchar_type); uchar_type->defined = DEFINED ;
	uchar_type->type_adj(UNSIGNED);
	uchar_type->check(0);

	Pchar_type = char_type->addrof();
	PERM(Pchar_type); Pchar_type->defined = DEFINED ;

	Pint_type = int_type->addrof();
	PERM(Pint_type); Pint_type->defined = DEFINED ;

	Pvoid_type = void_type->addrof();
	PERM(Pvoid_type); Pvoid_type->defined = DEFINED ;

	Pfctvec_type = new fct(int_type,0,0);	// must be last, see basetype::normalize()
	Pfctvec_type = Pfctvec_type->addrof();
	Pfctvec_type = Pfctvec_type->addrof();
	PERM(Pfctvec_type); Pfctvec_type->defined = DEFINED ;

	gtbl = new table(GTBLSIZE,0,0);
	gtbl->t_name = new name("global");
	ptbl = new table(CTBLSIZE,0,0);
	ptbl->t_name = new name("ptbl");
}

bit enum_promote;

Pbase basetype::arit_conv(Pbase t)
/*
	perform the "usual arithmetic conversions" C ref Manual 6.6
	on "this" op "t"
	"this" and "t" are integral or floating
	"t" may be 0
*/
{
	while (base == TYPE) this = Pbase(Pbase(this)->b_name->tp);
// error('d', "arit_conv: this: %k %d %t %d", base, base, this, this );

	bit l;
	bit u;
	bit f;
	bit l1 = (base == LONG);
	bit u1 = b_unsigned;
	bit f1 = (base==FLOAT || base==DOUBLE || base==LDOUBLE);
	if (t) {
		while (t->base == TYPE) t = Pbase(Pbase(t)->b_name->tp);
// error('d', "arit_conv: t: %k %d %t %d", t->base, t->base, t, t );

		bit l2 = (t->base == LONG);
		bit u2 = t->b_unsigned;
		bit f2 = (t->base==FLOAT || t->base==DOUBLE || base==LDOUBLE);
		l = l1 || l2;
		u = u1 || u2;
		f = f1 || f2;
	}
	else {
		l = l1;
		u = u1;
		f = f1;
	}

	if (f) {
		if (base==LDOUBLE || (t && t->base==LDOUBLE)) return ldouble_type;
		if (base==DOUBLE || (t && t->base==DOUBLE)) return double_type;
		return float_type;
	}
	if (l & u) return ulong_type;
	if (l & !u) return long_type;
	if (u) {
		if (base==INT || (t && t->base==INT)) return uint_type;
		if (SZ_SHORT==SZ_INT) // ANSIism
			if (base==SHORT || (t && t->base==SHORT)) return uint_type;
		return int_type;
	}

	if (t && t->base == EOBJ && base == EOBJ) enum_promote = 1;
	return int_type;
}

bit vec_const = 0;
bit fct_const = 0;

bit type::tconst()
/*
	is this type a constant
*/
{
	Ptype t = this;
	vec_const = 0;
	fct_const = 0;
//error('d',"tconst %t",t);
xxx:
	switch (t->base) {
	case TYPE:
		if (Pbase(t)->b_const) return 1;
		t = Pbase(t)->b_name->tp;
		goto xxx;
	case VEC:
		vec_const = 1;
		return 1;
	case PTR:
	case RPTR:
		return Pptr(t)->rdo;
	case FCT:
	case OVERLOAD:
		fct_const = 1;
		return 1;
	default:
		return Pbase(t)->b_const;
	}
}

TOK type::set_const(bit mode)
/*
	make someting a constant or variable, return old status
*/
{
	Ptype t = this;
	int m;
xxx:
	switch (t->base) {
	case TYPE:
		m = Pbase(t)->b_const;
		Pbase(t)->b_const = mode;
		t = Pbase(t)->b_name->tp;
		goto xxx;
	case ANY:
	case RPTR:
	case VEC:
		return t->base;		// constant by definition
	case PTR:
		m = Pptr(t)->rdo;
		Pptr(t)->rdo = mode;
		return m;
	default:
		m = Pbase(t)->b_const;
		Pbase(t)->b_const = mode;
		return m;
	}
}

Pptr type::is_ref()
{
	Ptype t = this;
xxx:
	switch (t->base) {
	case TYPE:	t = Pbase(t)->b_name->tp; goto xxx;
	case RPTR:	return Pptr(t);
	default:	return 0;
	}
}

Pclass Mptr;

Pptr type::is_ptr()
{
	Ptype t = this;
xxx:
	switch (t->base) {
	case TYPE:	t = Pbase(t)->b_name->tp; goto xxx;
	case PTR:
	case VEC:	Mptr = Pptr(t)->memof;
			return Pptr(t);
	default:	return 0;
	}
}

Pptr type::is_ptr_or_ref()
{
	Ptype t = this;
xxx:
	switch (t->base) {
	case TYPE:	t = Pbase(t)->b_name->tp; goto xxx;
	case PTR:
	case RPTR:
	case VEC:	Mptr = Pptr(t)->memof;
			return Pptr(t);
	default:	return 0;
	}
}

int type::align()
{
	Ptype t = this;
xx:
/*fprintf(stderr,"align %d %d\n",t,t->base);*/
	switch (t->base) {
	case TYPE:	t = Pbase(t)->b_name->tp; goto xx;
	case COBJ:	t = Pbase(t)->b_name->tp; goto xx;
	case VEC:	t = Pvec(t)->typ; goto xx;
	case ANY:	return 1;
	case CHAR:	return AL_CHAR;
	case SHORT:	return AL_SHORT;
	case INT:	return AL_INT;
	case LONG:	return AL_LONG;
	case FLOAT:	return AL_FLOAT;
	case DOUBLE:	return AL_DOUBLE;
	case LDOUBLE:	return AL_LDOUBLE;
	case PTR:
	case RPTR:	return AL_WPTR;
	case CLASS:	return Pclass(t)->obj_align;
	case ENUM:
	case EOBJ:	return AL_INT;
	case VOID:	error("illegal use of void"); return AL_INT;
	default:	error('i',"(%d,%k)->type::align",t,t->base);
	}
}

bit fake_sizeof;

int type::tsizeof(int ptmc)
/*
	the sizeof type operator
	return the size in bytes of the types representation
*/
{
	Ptype t = this;
zx:
//error('d',"zx %t %d",t,t->base);
	if (t == 0) error('i',"typ.tsizeof(t==0)");
	switch (t->base) {
	case TYPE:
		t = Pbase(t)->b_name->tp;
		goto zx;
	case COBJ:
		t = Pbase(t)->b_name->tp;
		if (t == 0) return 0;	// ``fake'' generated classes: _Sdd
		goto zx;

	case ANY:	return 1;
	case VOID:	return 0;
	case ZTYPE:	return SZ_WPTR;	/* assume pointer */
	case CHAR:	return SZ_CHAR;
	case SHORT:	return SZ_SHORT;
	case INT:	return SZ_INT;
	case LONG:	return SZ_LONG;
	case FLOAT:	return SZ_FLOAT;
	case DOUBLE:	return SZ_DOUBLE;
	case LDOUBLE:	return SZ_LDOUBLE;

	case VEC:
		{	Pvec v = Pvec(t);
			if (v->size == 0) {
				if (fake_sizeof == 0) error('w',"sizeof array with undeclared dimension");
				return SZ_WPTR;	// vector argument has sizeof ptr
			}
			return v->size * v->typ->tsizeof();
		}
	case RPTR:	
	case PTR:
	{	
		int k = (Pptr(t)->memof && !ptmc)?sizeof(short)+sizeof(short):0;
		t = Pptr(t)->typ;
	xxx:
		switch (t->base) {
		default:	return SZ_WPTR;
		case CHAR:	return SZ_BPTR;
		case FCT:	return SZ_WPTR+k;
		case TYPE:	t = Pbase(t)->b_name->tp; goto xxx;
		}
	}
	case FIELD:
		error("sizeof(field)");
		return Pbase(t)->b_bits/BI_IN_BYTE+1;
	case FCT:
		error("sizeof(function)");
		return 0;

	case CLASS:	
	{
                Pclass cl = Pclass(t);
		if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) {
			error("%tU, size not known",cl);
			return SZ_INT;
		}
	 	if (cl->c_body == 1)	// detect first allocation or sizeof
	 		cl->dcl_print(0);
		return cl->obj_size;
	}

	case EOBJ:
	case ENUM:	return SZ_INT;

	default:	return 0;	// deref can be called for any type
			//error('i',"sizeof(%d)",t->base);
	}
}

bit type::vec_type()
{
	Ptype t = this;
xx:
	switch (t->base) {
	case ANY:
	case VEC:
	case PTR:
	case RPTR:	return 1;
	case TYPE:	t = Pbase(t)->b_name->tp; goto xx;
	default:	return 0;
	}
}

int ref_initializer;

Ptype type::deref()
/*	index==1:	*p
	index==0:	p[expr]
*/
{
//error('d',"%t -> deref() refd %d",this,ref_initializer);
	Ptype t = this;
xx:
	switch (t->base) {
	case TYPE:
		t = Pbase(t)->b_name->tp;
		goto xx;
	case PTR:
	case RPTR:
	case VEC:
	{	if (t == Pvoid_type) error("void* dereferenced");
		Ptype tt = t = Pvec(t)->typ;
		if (ref_initializer == 0) {
			while (tt->base == TYPE) tt = Pbase(tt)->b_name->tp;
			if (tt->base == COBJ) { 
                        	tt = Pbase(tt)->b_name->tp;
                        	if (tt && Pclass(tt)->defined&(DEFINED|SIMPLIFIED))
                                	(void) t->tsizeof();
                        }
		}
		// no break
	}
	case ANY:
		return t;
	default:
		error("nonP dereferenced");
		return any_type;
	}
}

Pfct type::memptr()
// is ``this'' a pointer to member function
{
	Ptype t = this;
	while (t->base == TYPE) t = Pbase(t)->b_name->tp;
	if (t->base != PTR || Pptr(t)->memof==0) return 0;

	t = Pptr(t)->typ;
	while (t->base == TYPE) t = Pbase(t)->b_name->tp;
	return (t->base == FCT) ? Pfct(t) : 0;
}
0707071010112045741004440001630000160000010177160466055413400001200000002731typedef.h/*ident	"@(#)ctrans:src/typedef.h	1.2" */
/**************************************************************************

        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.

typedef.h:

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

typedef unsigned char TOK;
typedef unsigned char bit;	// sometimes used as bits
typedef class node * PP;
typedef int (*PFI)();
typedef void (*PFV)();
typedef class node * Pnode;
typedef struct key * Pkey;
typedef class name * Pname;
typedef class basetype * Pbase;
typedef class basecl* Pbcl;
typedef class type * Ptype;
typedef class fct  * Pfct;
typedef class field * Pfield;
typedef class expr * Pexpr;
typedef class qexpr * Pqexpr;
typedef class texpr * Ptexpr;
typedef class classdef * Pclass;
typedef class enumdef * Penum;
typedef class stmt * Pstmt;
typedef class estmt * Pestmt;
typedef class tstmt * Ptstmt;
typedef class vec * Pvec;
typedef class ptr * Pptr;
typedef class block * Pblock;
typedef class table * Ptable;
typedef struct loc Loc;
typedef class call * Pcall;
typedef class gen* Pgen;
typedef class ref * Pref;
typedef class name_list * Plist;
typedef class iline * Pin;
typedef class nlist * Pnlist;
typedef class slist * Pslist;
typedef class elist * Pelist;
typedef class virt * Pvirt;
typedef char* Pchar;

0707071010112045751004440001630000160000010201670466055413700001200000001374yystype.h/*ident	"@(#)ctrans:src/yystype.h	1.2" */
/**************************************************************************

        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.

yystype:

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

typedef union {
	char*	s;
	TOK	t;
	int	i;
	loc	l;
	Pname	pn;
	Ptype	pt;
	Pexpr	pe;
	Pstmt	ps;
	Pbase	pb;
	Pnlist	nl;
	Pslist	sl;
	Pelist	el;
	Pbcl	pbc;
	Pptr	pp;
	PP	p;	// fudge: pointer to all class node objects
	Plist	pl;	// fudge: pointer to all class node objects
} YYSTYPE;
extern YYSTYPE yylval;
0707071010112045751004440001630000160000010201670466055413700001300000000000TRAILER!!!ss node objects
} YYSTYPE;
extern YYSTYPE yylval;
0707071010112045751004440001630000160000010201670466055413700001300000000000TRAILER!!!ss node objects
} YYSTYPE;
extern YYSTYPE yylval;
0707071010112045751004440001630000160000010201670466055413700001300000000000TRAILER!!!ss node objects
} YYSTYPE;
extern YYSTYPE yylval;
070707101011204575100444000163000016000001020167046

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.