/* 
   Copyright 1994-2003 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
/*
 * handle ALL declarative statements
 */
#include        <stdio.h>
#include 				<string.h>
#include        "lists.h"
#include        "expr.h"
#include        "c.h"
#include        "errors.h"

#define LONGS /* enable 64 bit support */
extern NAMESPACE *thisnamespace ;

extern int prm_debug ;
extern int stdinttype,stdunstype,stdintsize, stdldoublesize,stdaddrsize;
extern int strucadd,strucmod;
extern TYP stdint;
extern LIST *instantiated_inlines ;
extern int classhead, vtabhead ;
extern int lineno ;
extern int packdata[], packlevel ;
extern int prm_cmangle, prm_microlink, prm_asmfile;
extern char laststr[];
extern int global_flag;
extern HASHREC **gsyms;
extern TABLE lsyms;
extern	SNODE *cbautoinithead,*cbautoinittail;
extern int prm_revbits;
extern int prm_68020;
extern int prm_ansi;
extern SYM *currentfunc;
extern int prm_cplusplus;
extern char * tn_unnamed;
extern TYP stdconst;
extern enum e_sym lastst;
extern char lastid[];
extern int block_nesting;
extern long nextlabel;
extern char *cpp_funcname_tab[];
extern int stdmemberptrsize;
extern ENODE *block_rundown ;

int friendclass, friendfunc ;

char *Cstr = "C";
SYM *declclass;
SYM *typequal;

int unnamedstructcount ;
int nullnamecount ;
int mangleflag;
int skm_declopenpa[] = { semicolon, comma,openpa, eq,0 };
int skm_declclosepa[] = { semicolon, comma,closepa, eq,0 };
int skm_declcomma[] = { semicolon, comma,begin, eq,0 };
int skm_declbegin[] = { begin,semicolon, begin,0 };
int skm_declclosebr[] = { comma,closebr, eq,0 };
int skm_declend[] = { semicolon, comma, end, eq,0 };
int skm_decl[] = {semicolon,kw_int, kw_long, kw_short, kw_char, kw_float, kw_bool,
		kw_double, kw_struct, kw_union, kw_enum, kw_unsigned, kw_signed, kw_auto,
      kw_extern, kw_static, kw_restrict, kw_register, kw_typedef, id, kw_void, kw_wchar_t, 0 };

int            mainfunc ;
int							sizeoflastbit;
TYP             *head = 0, **headptr;
TYP             *tail = 0;
char            declid[100];
TABLE           tagtable = {0,0};
int ispascal,isstdcall,iscdecl,isindirect,isexport,isimport;
char *importname ;
LIST *localfuncs ; /* 68k */

static int inprototype ;
static int memberptr;
static					SYM *lastdecl;
static 					int pcount=0;
static int bittype = -1;
static int curbit = 0;
static int curofs = 0;
static int manglelevel;
static int intflag, farflag;
static int cppflags;
static int defaulttype ;
static int decl3size ;
void declini(void)
/*
 * init
 */
{
	bittype = -1;
	head = tail = 0;
	declid[0] = 0;
	tagtable.head = tagtable.tail = 0;
	pcount = 0;
	mangleflag = TRUE;
	declclass = 0;
	localfuncs = 0;
   unnamedstructcount = 0 ;
}
	
int     imax(int i,int j)
{       return (i > j) ? i : j;
}

char    *litlate(char *s)
{       char    *p;
        p = xalloc(strlen(s) + 1);
        strcpy(p,s);
        return p;
}

TYP     *maketype(int bt,int siz)
/*
 * Create a type list entry
 */
{       TYP     *tp;
				
        tp = xalloc(sizeof(TYP));
        tp->val_flag = 0;
				tp->bits = tp->startbit = -1;
        tp->size = siz;
        tp->type = bt;
        tp->sp = 0;
				tp->cflags = 0;
				tp->uflags = 0;
        tp->lst.head = tp->lst.tail = 0;
				tp->tdef = 0;
        return tp;
}
TYP *cponetype(TYP *t)
/*
 * Copy a entry
 */
{				TYP *tp;
	tp = xalloc(sizeof(TYP));
	tp->type = t->type;
	tp->val_flag = t->val_flag;
	tp->cflags = t->cflags;
	tp->bits = t->bits;
	tp->startbit = t->startbit;
	tp->size = t->size;
	tp->lst = t->lst;
	tp->btp = t->btp;
	tp->sp = t->sp;
	tp->uflags = t->uflags;
	tp->tdef = t->tdef;
   tp->typeindex = t->typeindex ;
   tp->enumlist = t->enumlist ;
   tp->alignment = t->alignment ;
	return tp;
}
TYP *copytype(TYP *itp, int flags)
/*
 * copy a type tree
 */
{
   TYP *head, *tail,*x=itp,*reclone = 0;
	while (x->type == bt_pointer)
		x = x->btp;
	if (isstructured(x)) 
		if (!x->lst.head) {
         reclone = x ;
		}
   if (!itp->typeindex)
      itp->typeindex = xalloc(sizeof(int)) ;
	head = tail = cponetype(itp);
	while (itp->type == bt_pointer) {
		tail = tail->btp = cponetype(itp->btp);
		itp = itp->btp;
	}
	if (itp->type == bt_func || itp->type == bt_ifunc) {
			tail->btp = cponetype(itp->btp);
	}
	else {
		tail->cflags |= flags;
	}
   if (reclone) {
      x = head ;
      while (x->type == bt_pointer)
         x = x->btp;
      x->reclone = reclone->reclone ;
      reclone->reclone = x ;
   }
	return head;
}
int istype(void)
{
	SYM *sp;
	switch (lastst) {
		case kw_void:
    case kw_char:
		case kw_bool:
    case kw_wchar_t:
    case kw_short:
    case kw_int: 
    case kw_unsigned:
    case kw_signed:
		case kw_class:
    case kw_float:
		case kw_long:
    case kw_double:
    case kw_enum:
    case kw_struct:
    case kw_union:
			return TRUE;
    case id:                /* no type declarator */
			if ((sp = gsearch(lastid)) && sp->storage_class == sc_type)
			 	return TRUE;	
		default:
			return FALSE;
	}
}
SYM *parsetype(SYM *typesp)
{
                          while (prm_cplusplus && lastst == classsel) {
                            typequal = typesp;
                            getsym();
														if (lastst == kw_operator || lastst == compl)
															break ;
                            if (lastst != id) {
                              generror(ERR_IDEXPECT,0,0); 
                              break;
                            } else if (!(typesp = tcsearch(lastid,TRUE)))
                              break;
														else if (typesp->storage_class != sc_type)
															break;
														else getsym();
                          }
	if (lastst == classselstar) {
		typequal = typesp;
		typesp = 0;
	}
	return typesp;
}
int     decl(TABLE *table,int cppflags)
/*
 * parse the declare keywords and create a basic type
 */
{
				int tp;
				int flags = 0;
				SYM *typesp = 0;
				defaulttype = FALSE ;
            while (lastst == kw_const || lastst == kw_volatile || lastst == kw_inline || lastst == kw__intrinsic || lastst == kw_restrict || 
                  (prm_cplusplus &&(lastst == kw_virtual || lastst == kw_static || lastst == kw_friend))) {
					switch (lastst) {
						case kw_const:
							flags |= DF_CONST;
                     getsym();
							break;
                  case kw_restrict:
                     flags |= DF_RESTRICT;
                     getsym();
							break;
						case kw_volatile:
							flags |= DF_VOL;
                     getsym();
							break;
						case kw__intrinsic:
							flags |= DF_INTRINS;
                     getsym();
							break;
						case kw_inline:
							cppflags |= PF_INLINE;
                     getsym();
							break;
#ifdef CPLUSPLUS
						case kw_virtual:
                     cppflags |= PF_VIRTUAL;
                     getsym();
							break;
						case kw_static:
							cppflags |= PF_STATIC;
                     getsym();
							break;
						case kw_friend:
                     getsym () ;
                     if (lastst == kw_class) {
                        getsym() ;
                        friendclass = TRUE ;
                     } else
                        friendfunc = TRUE ;
							break;
#endif
					}
				}
        switch (lastst) {
								case kw_void:
                        head = tail = maketype(bt_void,0);
												getsym();
												break;
								case kw_bool:
                        head = tail = maketype(bt_bool,1);
                        getsym();
                        break;
                case kw_char:
                        head = tail = maketype(bt_char,1);
                        getsym();
                        break;
                case kw_short:
												getsym();
												tp = bt_short;
												if (lastst == kw_unsigned) {
													tp = bt_unsignedshort;
                                       getsym();
												}
												if (lastst == kw_int)
													getsym();
                        head = tail = maketype(tp,2);
                        break;
                case kw_wchar_t:
                        getsym() ;
                        head = tail = maketype(bt_unsignedshort,2);
                        break;
                case kw_int: 
                        getsym();
                default:
                        defaulttype = TRUE ;
                        head = tail = maketype(stdinttype,stdintsize);
                        break;
                case kw_unsigned:
												getsym();
												switch (lastst) {
													case kw_char:
														getsym();
                        		head = tail = maketype(bt_unsignedchar,1);
														break;
													case kw_short:
														getsym();
														if (lastst == kw_int)
															getsym();
                                        head = tail = maketype(bt_unsignedshort,2);
														break;
													case kw_long:
														getsym();
                                          if (lastst == kw_long) {
                                             getsym();
#ifdef LONGS
                                             head = tail = maketype(bt_unsignedlong,8) ;
#else
                                             generror(ERR_LONGLONG,0,0);
#endif
                                          } else
                                             head = tail = maketype(bt_unsigned,4) ;
														if (lastst == kw_int)
															getsym();
														break;
													case kw_int:
														getsym();
													default:
                        		head = tail = maketype(stdunstype,stdintsize);
														break;
												}
                        break;
                case kw_signed:
												getsym();
												switch (lastst) {
													case kw_char:
														getsym();
                        		head = tail = maketype(bt_char,1);
														break;
													case kw_short:
														getsym();
														if (lastst == kw_int)
															getsym();
                        		head = tail = maketype(bt_short,2);
														break;
													case kw_long:
														getsym();
                                          if (lastst == kw_long) {
                                             getsym();
#ifdef LONGS
                                             head = tail = maketype(bt_long,8);
#else
                                             generror(ERR_LONGLONG,0,0);
#endif
                                          } else
                                             head = tail = maketype(bt_int,4);
														if (lastst == kw_int)
															getsym();
														break;
													case kw_int:
														getsym();
													default:
                        		head = tail = maketype(bt_int,stdintsize);
														break;
												}
                        break;
								case kw_class:
												if (prm_cplusplus) {
													getsym();
													declstruct(table, bt_class, flags | DF_PRIVATE,cppflags);
													break;
												}
                case id:                /* no type declarator */
                          defaulttype = TRUE ;
												if ((typesp = gsearch(lastid)) && typesp->storage_class == sc_type && typesp != declclass) {	
													getsym();
#ifdef CPLUSPLUS
													typesp = parsetype(typesp);
                          if (typesp && typesp->storage_class == sc_type) {
#endif
                            head = tail = copytype(typesp->tp,flags);
														
#ifdef CPLUSPLUS
                          } else {
                            head = tail = maketype(bt_int,4);
                          }
#endif
												}
												else {
                           head = tail = maketype(bt_int,4);
												}
                        break;
								case kw_operator:
                           head = tail = maketype(bt_int,4);
													break ;
                case kw_float:
                        getsym() ;
                        if (lastst == kw__Complex) {
                           getsym() ;
                           head = tail = maketype(bt_fcomplex,8) ;
                        }else if (lastst == kw__Imaginary) {
                           getsym() ;
                           head = tail = maketype(bt_fimaginary,8) ;
                        }else
                          head = tail = maketype(bt_float,4);
                        break;
								case kw_long:
												getsym();
												if (lastst==kw_double) {
													getsym();
                                       if (lastst == kw__Complex) {
                                          getsym() ;
                                          head = tail = maketype(bt_lrcomplex,stdldoublesize*2);
                                       }else if (lastst == kw__Imaginary) {
                                          getsym() ;
                                          head = tail = maketype(bt_lrimaginary,stdldoublesize*2);
                                       } else
                                          head = tail = maketype(bt_longdouble,stdldoublesize);
													break;
												}
												if (lastst==kw_float) {
													getsym();
                                       if (lastst == kw__Complex) {
                                          getsym() ;
                                          head = tail = maketype(bt_rcomplex,16);
                                       }else if (lastst == kw__Imaginary) {
                                          getsym() ;
                                          head = tail = maketype(bt_rimaginary,16);
                                       } else
                                          head = tail = maketype(bt_double,8);
													break;
												}
												if (lastst == kw_long) {
													getsym();
#ifdef LONGS
                                       tp = bt_long;
#else
													generror(ERR_LONGLONG,0,0);
                                       tp = bt_int ;
#endif
                                    } else
                                       tp = bt_int ;

												if (lastst == kw_unsigned) {
#ifdef LONGS
                                       if (tp == bt_long)
                                          tp = bt_unsignedlong;
                                       else
#endif
                                          tp = bt_unsigned ;
													getsym();
												}
												if (lastst == kw_int)
													getsym();
#ifdef LONGS
                        if (tp == bt_long || tp == bt_unsignedlong)
                           head = tail = maketype(tp,8);
                        else
#endif
                           head = tail = maketype(tp,4) ;
                        break;
                case kw_double:
                        getsym() ;
                        if (lastst == kw__Complex) {
                           getsym() ;
                           head = tail = maketype(bt_rcomplex,16);
                        } else if (lastst == kw__Imaginary) {
                           getsym() ;
                           head = tail = maketype(bt_rimaginary,16);
                        } else
                           head = tail = maketype(bt_double,8);
                        break;
                case kw_enum:
                        getsym();
                        declenum(table,cppflags);
                        break;
                case kw_struct:
                        getsym();
                        declstruct(table, bt_struct,flags | DF_PUBLIC,cppflags);
                        break;
                case kw_union:
                        getsym();
                        declstruct(table, bt_union,flags,cppflags);
                        break;
                }
exit:
	head->cflags |= flags;
	head->uflags |= UF_CANASSIGN;
	return cppflags;
}

SYM* makesym(enum e_sc sc)
{
	SYM *sp = xalloc(sizeof(SYM));
	sp->storage_class = sc;
	return sp;
}
#ifdef CPLUSPLUS
void overloadoperator(SYM *sp)
{
	char *q = lastid;
	getsym(); /* past the operator keyword */
	if (lastst >= id) {
error:
		generror(ERR_OPERATOREXPECTED,0,skm_declend);
		return;
	}
	else {
		sp->value.i = lastst + IT_OV_THRESHOLD;
    sp->value.classdata.cppflags |= PF_OPERATOR;
		getsym(); /* past the operator */
		/* special case operator () and [] since they are two symbols */
		switch(sp->value.i) {
			case ov_ind:
				if (lastst != closebr)
					goto error;
				getsym();
				break;
			case ov_arg:
				if (lastst != closepa)
					goto error;
				getsym();
				break;
         case ov_new:
            sp->value.classdata.cppflags |= PF_STATIC ;
            if (lastst == openbr) {
               sp->value.i = ov_newa ;
               getsym() ;
               needpunc(closebr,0) ;
            }
            break ;
         case ov_delete:              
            sp->value.classdata.cppflags |= PF_STATIC ;
            if (lastst == openbr) {
               sp->value.i = ov_deletea ;
               getsym() ;
               needpunc(closebr,0) ;
            }
            break ;
		}
		/* construct the function name */
/*		if (prm_cmangle)
			*q++ = '_';
*/		strcpy(q,cpp_funcname_tab[sp->value.i]);
		strcpy(declid,lastid);
	}

	return;
}
#endif
SYM *decl1(enum e_sc sc, SYM *sp)
/*
 * Modifiers that could occur BEFORE the name of the var
 */
{       TYP     *temp1, *temp2, *temp3, *temp4,*head1 = *headptr;
				TYP			**tempptr;
				SYM *typesp;
				int ocppf;
				if (!sp)
						sp = makesym(sc);

lp:
        switch (lastst) {
								case kw_inline:
									if (!prm_cplusplus) {
										lastst = id;
										goto getid;
									}
									cppflags |= PF_INLINE;
									getsym();
									goto lp;
#ifdef CPLUSPLUS
								case kw_virtual:
									if (!prm_cplusplus) {
										lastst = id;
										goto getid;
									}
									cppflags |= PF_VIRTUAL;
									getsym();
									goto lp;
								case kw_static:
									cppflags |= PF_STATIC;
									getsym();
									goto lp;
								case kw_friend:
									if (!prm_cplusplus) {
										lastst = id;
										goto getid;
									}
									getsym();
                           if (lastst == kw_class) {
                              friendclass = TRUE ;
                              getsym() ;
                           } else friendfunc = TRUE ;
									goto lp;
#endif
								case kw_const:
									head1->cflags |= DF_CONST;
									getsym();
									goto lp;
                        case kw_restrict:
                           head1->cflags |= DF_RESTRICT;
									getsym();
									goto lp;
								case kw__intrinsic:
									head1->cflags |= DF_INTRINS;
									getsym();
									goto lp;
								case kw_volatile:
									head1->cflags |= DF_VOL;
									getsym();
									goto lp;
								case kw__stdcall:
									isstdcall = TRUE;
									getsym();
									goto lp;
								case kw__indirect:
									if (prm_microlink)
										isindirect = TRUE ;
									getsym();
									goto lp ;
								case kw__pascal:
									ispascal = TRUE;
									getsym();
									goto lp;
								case kw__export:
									isexport = TRUE ;
									getsym() ;
									goto lp ;
								case kw__import:
									isimport = TRUE ;
                           importname = 0 ;
									getsym() ;
                           if (lastst == openpa) {
                              getsym() ;
										if (lastst == sconst) {
											importname = litlate(laststr) ;
											getsym() ;
											needpunc(closepa,0) ;
										} else
										  generror(ERR_NEEDCHAR,'"',0);
									}
									goto lp ;
								case kw__cdecl:
									iscdecl = TRUE;
									getsym();
									goto lp;
#ifdef CPLUSPLUS
								case compl:
									getsym() ;
									if ((typesp = gsearch(lastid)) && typesp->storage_class == sc_type) {
										getsym();
										typesp = parsetype(typesp);
									}
									if (lastst == id)
										getsym() ;
									if ((!typequal || typequal == declclass) && declclass && !strcmp(declclass->name,lastid)) {
                              if (!defaulttype || currentfunc)
                                gensymerror(ERR_CANTHAVETYPE,declclass->name);
										strcpy(declid,cpp_funcname_tab[CI_DESTRUCTOR]);
										cppflags |= PF_DESTRUCTOR;
                              declclass->value.classdata.cppflags |= PF_HASDEST ;
									} else
                    if (typesp && typesp->storage_class == sc_type)
											if (!strcmp(typesp->name,lastid)) {
                                    if (!defaulttype || currentfunc)
                                       gensymerror(ERR_CANTHAVETYPE,typesp->name);
												strcpy(declid,cpp_funcname_tab[CI_DESTRUCTOR]) ;
												head = tail = maketype(bt_void,0) ;
												decl2(sc,sp) ;
												break ;
											} else
                                    gensymerror(ERR_BADESTRUCT,typesp->name) ;
                     else 
                                  gensymerror(ERR_BADESTRUCT,lastid) ;
                  head = tail = maketype(bt_void,0);
									if (lastst == id)
										getsym() ;
									decl2(sc,sp);
									break;
								case kw_operator:
									overloadoperator(sp);
									decl2(sc,sp);
									break;
                case classsel: /* shouldn't get here */
								case classselstar:
                  break;
#endif
                case id:
getid:
#ifdef CPLUSPLUS	
											if (prm_cplusplus) {
												if ((typesp = gsearch(lastid)) && typesp->storage_class == sc_type) {
													getsym();
													typesp = parsetype(typesp);
												}
												if ((!typequal || typequal == declclass) && declclass && !strcmp(declclass->name,lastid)) {
                                       if (!defaulttype || currentfunc)
                                          gensymerror(ERR_CANTHAVETYPE,declclass->name);
													strcpy(declid,cpp_funcname_tab[CI_CONSTRUCTOR]);
													cppflags |= PF_CONSTRUCTOR;
                                       declclass->value.classdata.cppflags |= PF_HASCONS ;
                  				head = tail = maketype(bt_void,0);
													if (lastst == id)
														getsym() ;
													decl2(sc,sp) ;
													break ;
												}
												if (lastst == classselstar) {
													getsym();
													if (!typequal || typequal->tp->type != bt_class && typequal->tp->type != bt_struct) {
														generror(ERR_TYPEQUALEXP,0,0);
													} else {
														if (lastst != id)
																generror(ERR_IDEXPECT,0,0);
														else {
															memberptr = TRUE;
															temp1 = maketype(bt_memberptr,stdmemberptrsize);
															temp1->btp = head;
															temp1->sp = typequal;
															*headptr = temp1;
															typequal = 0;
															/* if pointer to member function */
														}
													}
                        } else 
                          if (lastst == kw_operator) {
                            overloadoperator(sp);
                            decl2(sc,sp);
                            break;
                          } else
                            if (typesp && typesp->storage_class == sc_type)
															if (!strcmp(typesp->name,lastid)) {
                                                if (!defaulttype || currentfunc)
                                                   gensymerror(ERR_CANTHAVETYPE,typesp->name);
																strcpy(declid,cpp_funcname_tab[CI_CONSTRUCTOR]) ;
																decl2(sc,sp) ;
																break ;
															} else
                                generror(ERR_IDEXPECT,0,0);
                        		else 
                          		if (lastst != id)
                            		generror(ERR_IDEXPECT,0,0);
												
											}
#endif
                        getsym();
                        strcpy(declid,lastid);

                        decl2(sc,sp);
                        break;
                  case colon:  
                        sprintf(declid,"_$$NULLNAME%d",nullnamecount++) ;  
                        decl2(sc,sp) ;
                        break ;
								case and:
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
													getsym();
													temp1 = maketype(bt_ref,4);
													temp1->btp = head1;
													*headptr = temp1;
													if (tail == NULL)
														tail = head1;
										 			decl1(sc,sp);
												} else
#endif
												{
													decl2(sc,sp);
												}
												break;
                case star:
												head1->uflags &= ~UF_CANASSIGN;
                        temp1 = maketype(bt_pointer,4);
                        temp1->btp = head1;
                        *headptr = temp1;
												head1->uflags |= UF_CANASSIGN;
                        if(tail == NULL)
                                tail = head1;
                        getsym();
                        decl1(sc,sp);
                        break;
                case openpa:
                        getsym();
	                      temp1 = head1;
  	                    temp2 = tail;
      	                decl1(sc,sp);
												if ((*headptr)->btp) {
													for (temp1 = *headptr; temp1->btp && temp1->btp != head1; temp1 = temp1->btp);
													headptr = &temp1->btp;
												}
												else
													if (head->type == bt_memberptr)
														headptr = &head->btp;
													else
														headptr = &head;
	        	            needpunc(closepa,0);
												decl2(sc,sp);
                        break;
                default:
                        if (inprototype)
                           decl2(sc,sp);
                        break;
                }
	return sp;
}
#ifdef CPLUSPLUS
/* Some overloaded functions require a member of type class */
int isclassarg(SYM *sp)
{
	SYM *head = sp->tp->lst.head;
	while (head && head != (SYM *)-1) {
		TYP *tp = head->tp;
		while (tp->type == bt_ref)
			tp = tp->btp;
		if (isstructured(tp))
			return TRUE;
		head = head->next;
	}
	return FALSE;
}
/* Depending on the type of function being overloaded, there are
 * different error checks to be performed
 */
void CheckOverloadedArgs(SYM *sp)
{
	int argcount = 0;
	SYM *head = sp->tp->lst.head;
	while (head && head != (SYM *)-1) {
      argcount++;
		head = head->next;
	}
	switch (sp->value.i ) {
    case ov_new: 
    case ov_newa:
				if (sp->tp->lst.head->tp->type!= bt_unsigned)
					generror(ERR_SIZE_T_NEW,0,0);
				else
					if (sp->tp->btp->type != bt_pointer || sp->tp->btp->btp->type != bt_void)
						generror(ERR_VOIDSTAR_NEW,0,0);
			break;
		case ov_delete:
      case ov_deletea:
      if (argcount != 1)
				gensymerror(ERR_DECL1ARG,sp->name);
			else
            if (sp->tp->lst.head->tp->type!= bt_pointer || sp->tp->lst.head->tp->btp->type != bt_void)
					generror(ERR_VOIDSTAR_DELETE,0,0);
				else
					if (sp->tp->btp->type != bt_void)
						generror(ERR_VOID_DELETE,0,0);
			break;
		case ov_div:  case ov_shl: case ov_shr: case ov_mod: 
		case ov_lor: case ov_land: case ov_or:  case ov_xor: 
		case ov_equ: case ov_neq: case ov_lt: case ov_le: 
		case ov_gt: case ov_ge:
		case ov_asn: case ov_aasadd: case ov_assub: 
		case ov_asmul: case ov_asdiv:
		case ov_asmod: case ov_asshl: case ov_asshr: 
		case ov_asand: case ov_asor:
		case ov_asxor: 
      if (typequal || declclass) {
				if  (argcount != 1)
					gensymerror(ERR_DECL1ARG,sp->name);
			}
			else
				if (argcount != 2)
					gensymerror(ERR_DECL2ARG,sp->name);
				else
					if (!isclassarg(sp))
            gensymerror(ERR_OPERATORMUSTCLASS,sp->name);
			break ; 

		case ov_and: case ov_mul: case ov_add: case ov_sub:
      if (typequal || declclass) {
				if (argcount > 1)
					gensymerror(ERR_DECL1ARG,sp->name);
			} else
				if (argcount != 1 && argcount != 2)
          gensymerror(ERR_DECL2ARG,sp->name);
				else
					if (!isclassarg(sp))
            gensymerror(ERR_OPERATORMUSTCLASS,sp->name);
			break;
		case ov_cpl: case ov_not: 
		case ov_autoinc: case ov_autodec: 
      if (typequal || declclass) {
				if  (argcount)
					gensymerror(ERR_DECL0ARG,sp->name);
			}
			else
				if (argcount != 1)
					gensymerror(ERR_DECL1ARG,sp->name);
				else
					if (!isclassarg(sp))
            gensymerror(ERR_OPERATORMUSTCLASS,sp->name);
			break ; 

		case ov_ind: 
      if (!typequal && !declclass)
				gensymerror(ERR_OPMUSTBEMEMBER,sp->name);
      else
				if (argcount != 1)
					gensymerror(ERR_DECL1ARG,sp->name);
			break;					
		case ov_arg: 
      if (!typequal && !declclass)
				gensymerror(ERR_OPMUSTBEMEMBER,sp->name);
			break ; 
		case ov_pstar: case ov_arr:
      if (!typequal && !declclass)
				gensymerror(ERR_OPMUSTBEMEMBER,sp->name);
			else
				if (argcount)
					gensymerror(ERR_DECL0ARG,sp->name);
        else {
          TYP *tp = sp->tp->btp;
				 	if (tp->type != bt_pointer || !isstructured(tp->btp))
						gensymerror(ERR_POINTTOCLASS,sp->name);
        }
			break;
	}
}
ENODE * do_constructor(SYM *sp_in, TYP *tp, TYP *head1 ,ENODE *node, int size, int offset)
{
	char buf[256] ;
	int voidfunc=FALSE ;
	SYM *sp ;
	ENODE *pnode, *rnode, *tcnode = 0 ;
	if (tp->lst.head == (SYM *) -1)
		voidfunc = TRUE ;
   {
		SYM *sp1 = search(cpp_funcname_tab[CI_CONSTRUCTOR],&head1->lst);
		if (!sp1) {
			if (!voidfunc)
				
            gensymerrorexp(ERR_NOFUNCMATCH,fullcppmangle(head1->sp,cpp_funcname_tab[CI_CONSTRUCTOR],tp));
			return 0 ;
		}
      sp = funcovermatch(sp1,tp,FALSE);
		if (!sp) {
         gensymerrorexp(ERR_NOFUNCMATCH,fullcppmangle(head1->sp,cpp_funcname_tab[CI_CONSTRUCTOR],tp));
			return 0 ;
		}		
		pnode = makenode(en_napccon,sp,0) ;
	}
	sp->extflag = TRUE ;
	parmlist(&node,tp,sp->tp);
	pnode = makenode(en_void,pnode,node);
   rnode = makeintnode(en_icon,sp->tp->btp->size);
				if (sp->pascaldefn)
          pnode = makenode(en_pfcall,rnode,pnode);
				else
					if (sp->isstdcall)
            pnode = makenode(en_sfcall,rnode,pnode);
          else
						pnode = makenode(en_fcall,rnode,pnode);
		if (!(sp->value.classdata.cppflags & PF_STATIC))
			if (sp_in->storage_class == sc_auto)
  			tcnode = makenode(en_autocon,sp_in,0);
			else if (sp_in->storage_class == sc_autoreg)
   			tcnode = makenode(en_autoreg,sp_in,0);
			else tcnode = makenode(en_nacon,sp_in,0) ;
      if (offset)
         tcnode = makenode(en_addstruc,(void *)tcnode,makeintnode(en_icon,offset)) ;
#ifdef CPLUSPLUS
		if (prm_cplusplus && tcnode && 
				(sp->value.classdata.cppflags & PF_MEMBER) &&
				!(sp->value.classdata.cppflags & PF_STATIC)) {
			pnode = makenode(en_thiscall, tcnode, pnode);
		}
		if (size == 1)
			pnode = doinline(pnode);
		else {
         ENODE *snode ;
         snode = makeintnode(en_icon,head1->size) ;
         snode = makenode(en_void,makeintnode(en_icon,size),(void *)snode) ;
         pnode = makenode(en_repcons,(void *)snode,(void *)pnode) ;
			if ((sp->value.classdata.cppflags & PF_INLINE) && !(sp->value.classdata.cppflags & PF_INSTANTIATED)) {
				LIST *l = xalloc(sizeof(LIST)) ;
				l->data = sp ;
				l->link = instantiated_inlines ;
				instantiated_inlines = l ;
				sp->value.classdata.cppflags |= PF_INSTANTIATED ;
			}
		}
			
#endif
		pnode->cflags = head1->cflags;
	return pnode ;

}
ENODE * do_destructor(SYM *sp_in, TYP *tp, TYP *head1, ENODE *xnode, int size)
{
	char buf[256] ;
	ENODE *node = 0 ;
	SYM *sp ;
	ENODE *pnode, *rnode, *tcnode = 0 ;
 {
		SYM *sp1 = search(cpp_funcname_tab[CI_DESTRUCTOR],&head1->lst);
		if (!sp1) {
			return 0 ;
		}
      sp = funcovermatch(sp1,tp,FALSE);
		if (!sp) {
         gensymerrorexp(ERR_NOFUNCMATCH,fullcppmangle(tp->sp,cpp_funcname_tab[CI_DESTRUCTOR],tp));
			return 0 ;
		}		
		pnode = makenode(en_napccon,sp,0) ;
	}
	sp->extflag = TRUE ;
	if (xnode)
		tcnode = xnode ;
	else {
		if (!(sp->value.classdata.cppflags & PF_STATIC))
			if (sp_in->storage_class == sc_auto)
  			tcnode = makenode(en_autocon,sp_in,0);
			else if (sp_in->storage_class == sc_autoreg)
   			tcnode = makenode(en_autoreg,sp_in,0);
			else tcnode = makenode(en_nacon,sp_in,0) ;
	}
   if (sp->value.classdata.cppflags & PF_VIRTUAL) {
      ENODE *inode,*nnode ;
      inode = makeintnode(en_icon,sp->value.classdata.vtabindex);
      if (sp->value.classdata.vtaboffs)
        tcnode = makenode(en_add,tcnode,makeintnode(en_icon,sp->value.classdata.vtaboffs)) ;
      nnode = makenode(en_l_ref,(void *)copy_enode(tcnode),0) ;
      pnode = makenode(en_add,inode,nnode);
      pnode = makenode(en_l_ref,pnode,0);
	}
	parmlist(&node,tp,sp->tp);
	pnode = makenode(en_void,pnode,node);
   rnode = makeintnode(en_icon,sp->tp->btp->size);
	if (sp->pascaldefn)
    pnode = makenode(en_pfcall,rnode,pnode);
	else
		if (sp->isstdcall)
      pnode = makenode(en_sfcall,rnode,pnode);
    else
			pnode = makenode(en_fcall,rnode,pnode);
#ifdef CPLUSPLUS
		if (prm_cplusplus && tcnode && 
				(sp->value.classdata.cppflags & PF_MEMBER) &&
				!(sp->value.classdata.cppflags & PF_STATIC)) {
			pnode = makenode(en_thiscall, tcnode, pnode);
		}
		if (size == 1)
			pnode = doinline(pnode);
		else {
         ENODE *snode ;
         snode = makeintnode(en_icon,head1->size) ;
         snode = makenode(en_void,makeintnode(en_icon,size),(void *)snode) ;
         pnode = makenode(en_repcons,(void *)snode,(void *)pnode) ;
			if ((sp->value.classdata.cppflags & PF_INLINE) && !(sp->value.classdata.cppflags & PF_INSTANTIATED)) {
				LIST *l = xalloc(sizeof(LIST)) ;
				l->data = sp ;
				l->link = instantiated_inlines ;
				instantiated_inlines = l ;
				sp->value.classdata.cppflags |= PF_INSTANTIATED ;
			}
		}
//      pnode = doinline(pnode);
#endif
		pnode->cflags = head1->cflags;
	return pnode ;

}
void conspair (SYM *sp, enum e_sc al,int flag)
{
													ENODE *qnode ;
													TYP *tp1 =gatherparms(&qnode,flag),tp2,*tp3=*headptr;
													int size = 1 ;                               	
													if (flag) {
														while (tp3->type == bt_pointer) {
															size = decl3size ;
															tp3 = tp3->btp ;
														}
													}
                                       qnode = do_constructor(sp,tp1,tp3,qnode,size,0) ;
													if (qnode) {
														if (al == sc_auto) {
															SNODE *snp = xalloc(sizeof(SNODE));
															snp->next = 0;
															snp->stype = st_expr;
															snp->exp = qnode ;
															if (cbautoinithead == 0)
																cbautoinithead = cbautoinittail = snp;
															else {
																cbautoinittail->next = snp;
																cbautoinittail= snp;
															}
														} else {
	            	              cppinitinsert(qnode) ;
														}
													}
													tp2.lst.head = -1 ;
													tp2.lst.tail = -1 ;
													tp2.type = bt_func ;
													qnode = do_destructor(sp,&tp2,tp3,0,size);
													if (qnode) {
														if (al == sc_auto) {
															if (block_rundown)
																block_rundown = makenode(en_void,qnode,block_rundown) ;
															else
																block_rundown = qnode ;
														} else {
															cpprundowninsert(qnode) ;
														}
													}
}
#endif
void decl2(enum e_sc sc,SYM *sp)
/*
 * type modifiers that come AFTER the name of the variable
 */
{       TYP     *temp1, *head1 = *headptr;
				int ocppf;
            int odflt ;
				char localid[128];
				if (prm_cplusplus) {
					temp1 = head;
					while (temp1->type == bt_ref || temp1->type == bt_pointer) {
						if (temp1->btp->type == bt_ref) {
							if (temp1->val_flag)
								generror(ERR_NOREFARRAY,0,0);
							else
								generror(ERR_CANTREF,0,0);
							break;
						}
						temp1 = temp1->btp;
					}
				}
lp:

        switch (lastst) {
								case kw_const:
									head1->cflags |= DF_CONST;
									getsym();
									goto lp;
                        case kw_restrict:
                           head1->cflags |= DF_RESTRICT;
									getsym();
									goto lp;
								case kw__intrinsic:
									head1->cflags |= DF_INTRINS;
									getsym();
									goto lp;
								case kw_volatile:
									head1->cflags |= DF_VOL;
									getsym();
									goto lp;
                case openbr:
											  decl3();
												decl2(sc,sp);
                        break;
                case openpa:
                     		getsym();
#ifdef CPLUSPLUS
												if (prm_cplusplus) {
                                       if (!declclass && isstructured(head) && !castbegin(lastst)) {
														conspair(sp,sc,FALSE) ;
														break ;
													}
													if (lastst != closepa && !castbegin(lastst)) {
														backup(openpa) ;
														break ;
													}
												}
#endif
	                      temp1 = maketype(bt_func,0);
												if (head1->cflags & DF_INTRINS)
													temp1->cflags |= DF_INTRINS;
												{
													temp1->uflags |= UF_DEFINED;
    	                  	temp1->val_flag = 1;
      	                	temp1->btp = head1;
        	              	*headptr = temp1;
													ocppf = cppflags;
													strcpy(localid,declid);
													sp->name = localid;
													temp1->sp = sp;
													sp->tp = temp1;
#ifdef CPLUSPLUS
                          sp->value.classdata.cppflags |= cppflags;
#endif
                                       odflt = defaulttype ;
													declfuncarg(intflag,farflag,sp);
                                       defaulttype = odflt ;
													sp->name = 0;
													cppflags = ocppf;
#ifdef CPLUSPLUS
													if (prm_cplusplus) {
                                          while (lastst == kw_const || lastst == kw_volatile || lastst == kw_restrict) {
															if (lastst == kw_const)
																temp1->cflags |= DF_CONST;
                                             else if (lastst == kw_restrict)
                                                temp1->cflags |= DF_RESTRICT ;
                                             else
																temp1->cflags |= DF_VOL;
															getsym();
														}
														if (!declclass && !typequal && (temp1->cflags & (DF_CONST | DF_VOL)))
															generror(ERR_CONSTNOMEMBER,0,0);
													}
										
#endif
                                       if (prm_cplusplus && lastst == colon || lastst == begin || castbegin(lastst) || lastst == kw_register || lastst == kw_const || lastst == kw_volatile || lastst == kw_restrict) {
														if (head->type == bt_func)
															head->type = bt_ifunc;
														else
															temp1->type = bt_ifunc;
														break;
													}
												}
                        break;
								case colon:
										getsym();
										head1->bits = intexpr(0);
										if (head1->type != bt_long && head1->type != bt_unsigned
												&& head1->type != bt_short && head1->type != bt_unsignedshort
												&& head1->type != bt_char && head1->type != bt_unsignedchar
												&& head1->type != bt_unsignedlong && head1->type != bt_int) {
											if (prm_ansi)
												generror(ERR_INTBITFIELDS,0,0);
											else
												generror(ERR_BFTYPE,0,0);
											head1->bits = -1;
										}
										else
											if (prm_ansi && head1->size != stdintsize) {
												generror(ERR_INTBITFIELDS,0,0);
												head1->bits = -1;
											}
										break;
									default:
											temp1 = head ;
											while (temp1->type == bt_pointer && temp1->val_flag)
												temp1 = temp1->btp ;
											if (prm_cplusplus && !declclass && isstructured(temp1))
											{
													conspair(sp,sc,TRUE) ;
											}
													break ;
                }
}

void decl3(void)
/*
 * Array index handling
 */
{
  TYP *temp1, *list[40], *head = *headptr;
	int count = 0,i;
	int mustsize = 0;
	head->uflags |= UF_DEFINED;
	head->uflags &= ~UF_CANASSIGN;
	decl3size = 1 ;
	while(lastst == openbr) {
                        getsym();
                        temp1 = maketype(bt_pointer,0);  
                        temp1->val_flag = 1;
                        if(lastst == closebr) {
														   	if (mustsize)
																	generror(ERR_SIZE,0,0);
    	                           temp1->size = 0;
                                getsym();
                                }
                        else {
                                ENODE *ep ;
                                int val= 0 ;
                                TYP *t1 = exprnc(&ep);
                                opt4(&ep) ;
                                 if (isintconst(ep->nodetype))
                                    val =  ep->v.i;
                                 else if (isfloatconst(ep->nodetype))
                                    val = ep->v.f;
                                 else generror(ERR_NEEDCONST,0,0) ;
                                decl3size *= temp1->size = val;
                                needpunc(closebr,skm_declclosebr);
                        }
												list[count++] = temp1;
												mustsize = 1;
	}
	if (head != NULL) {
		list[count-1]->size *= head->size;
		if (tail == NULL)
			tail = head;
	}
	for (i=count-1; i>0; i--) {
		list[i-1]->size *= list[i]->size;
		list[count-1]->uflags |= UF_DEFINED;
	}

	for (i=0; i < count-1; i++)
		list[i]->btp = list[i+1];
	list[count-1]->btp = head;

	*headptr = list[0];
	if (tail == NULL)
		tail = list[count-1];
}
int bitsize(int type)
/*
 * Max bit field depends on the type
 */
{
	switch (type) {
		case bt_char:
		case bt_unsignedchar:
			return 8;
		case bt_short:
		case bt_unsignedshort:
			return 16;
		case bt_long:
		case bt_unsigned:
		case bt_unsignedlong:
		case bt_int:
			return 32;
	}
	return 0;
}
int oksize(void)
/*
 * See if the size field is ok or if we should gen a message
 */
{
	TYP *q = head;
	while (q->type == bt_pointer) {
		if (q->val_flag)
			return 1;
		q = q->btp;
	}
	return head->size != 0;
}
int     basedeclare(TABLE *table,int al,long ilc,int ztype, int flags, int xcppflags)
/*
 *  Once a type declarator is found we come here to get the remainder of the
 * declaration and allocate spae
 *
 */
{       SYM     *sp=0, *sp1;
        TYP     *dhead;
        int     nbytes,ufsave,staticerror = 0;
        int declcount = 0 ;
        nbytes = 0;
        dhead = head;
				ufsave = head->uflags;
                              if ((friendfunc || friendclass) && (!declclass || al != sc_member))
                                    generror(ERR_FRIENDMUSTCLASS,0,0) ;
                              else if (friendclass) {
                                 if (isstructured(head)) {
                                    SYM *sp = copysym(head->sp) ;
                                    sp->parentclass = declclass ;
                                    sp->originalparentclass = declclass ;
                                    insertfriend(declclass,sp) ;
                                 } else
                                    generror(ERR_FRIENDCLASSNEEDSTRUC,0,0) ;
                                 needpunc(semicolon,0) ;
                                 return 0 ;
                              }
        for(;;) {
                int reffed = FALSE ;
                int varlineno = lineno ;
								sp1 = 0;
                declid[0] = 0;
								memberptr = FALSE;
								headptr = &head;
                sp = decl1(al,0);
								mainfunc = FALSE;
#ifdef CPLUSPLUS
								sp->value.classdata.cppflags |= xcppflags;
                        if (head->type != bt_func && head->type != bt_ifunc)
                           sp->value.classdata.cppflags &= ~(PF_CONSTRUCTOR | PF_DESTRUCTOR) ;
#endif
								/* stupid C standard uses a proper function name
								** as an alias for a pointer to a func when is a member...
								*/
								if (al == sc_member && !prm_cplusplus)
								  if (head->type == bt_func) {
										TYP *temp = maketype(bt_pointer,stdaddrsize);
										temp ->btp = head;
										head = temp;
									}
									else if (head->type == bt_ifunc)
										generror(ERR_NOFUNCSTRUCT,0,0);
								
								/* In case they put the extern tag on an ifunc */
								if (head->type == bt_ifunc && al == sc_external)
									al = sc_global;
		
								if (declid[0] == 0) {
									if ((flags & DF_FUNCPARMS)) {
										sprintf(declid,"**ARG%d**",pcount++);
									}
								}
								head->cflags |= flags;
                if(declid[0]) {      /* otherwise just struct tag... */
                              declcount++ ;
                              if (!isstructured(head))
											head->sp = sp;
#ifdef CPLUSPLUS
										if (head->type == bt_func || head->type == bt_ifunc)
											if (prm_cplusplus) {
												char *p = declid;
												if (prm_cmangle && *p == '_')
													p++;
												if (!strcmp(p,"main")) {
													SYM *sp1;
													mainfunc = TRUE;
													sp->name = litlate(declid);
													sp1 = search(sp->name,gsyms);
													if (sp1 && sp1->tp->type == bt_ifunc)
														generror(ERR_NOOVERMAIN,0,0);
												}
												else if (mangleflag && !ispascal && !isstdcall && !iscdecl && !isexport && !isimport)
                                       sp->name = fullcppmangle(0,declid,head);
												else
													sp->name = litlate(declid);
												if (typequal)
													table = &typequal->tp->lst;
											} else 
												sp->name = litlate(declid);
										else
#endif
										{
#ifdef CPLUSPLUS
											if (prm_cplusplus) {
												if (typequal)
													table = &typequal->tp->lst ;
											}
#endif
											sp->name = litlate(declid);

										}
#ifdef CPLUSPLUS
										sp->value.classdata.cppflags |= cppflags;
										if (al == sc_static)
											sp->value.classdata.cppflags |= PF_STATIC;
										sp->value.classdata.defalt = 0;
#endif
                              if (declclass)
                                 sp->parentclass = sp->originalparentclass = declclass;
                              else
                                 if (thisnamespace)
                                    sp->parentclass = sp->originalparentclass = thisnamespace->nsp;
                    sp->tp = head;
										sp->extflag = FALSE;
										sp->absflag = (al == sc_abs);
										sp->intflag = (flags &DF_INT) ? 1 : 0;
										sp->loadds = (flags & DF_LOADDS) ? 1 : 0;
										sp->pascaldefn = ispascal;
										sp->exportable = isexport ;
										sp->importable = isimport ;
										sp->importfile = importname ;
										sp->isstdcall = isstdcall;
										sp->indirect = isindirect ;
										sp->init = 0;
										sp->indecltable = 0;
										sp->funcparm = 0;
										sp->inreg = 0;
										sp->staticlabel = FALSE;
                              if (friendfunc) {
                                 if (sp->tp->type == bt_func)
                                    insertfriend(declclass,sp) ;
                                 else
                                    generror(ERR_FRIENDNEEDFUNC,0,0 ) ;
                                 needpunc(semicolon,0) ;
                                 return 0 ;
                              }
										if ((sp->tp->type == bt_func || sp->tp->type == bt_ifunc) && flags & DF_FAR) {
											sp->farproc = TRUE;
										}
										if (al != sc_type)
											if (sp->tp->type == bt_func || sp->tp->type == bt_ifunc) {
												setalias(sp);
										} else if (xcppflags & PF_STATIC)
											sp->alias = fullcppmangle(0,declid, 0) ; /* fake out static vars by using the alias field... */
						

										if (al == sc_external && (lastst == assign || lastst == openpa)) {
											sp->storage_class = sc_global;
										}
										

										if (sp->intflag && (ispascal || isstdcall || isexport || isimport))
											generror(ERR_PASCAL_NO_INT,0,0);

										if (al == sc_autoreg) {
											if (head->size > 4) {
												sp->storage_class = sc_auto;
												gensymerror(ERR_ILLREGISTER,sp->name);
											}
										}	
										if (al != sc_type && (oksize() || sp->tp->type == bt_func || sp->tp->type == bt_ifunc)) {
#ifdef CPLUSPLUS
											if (sp->value.classdata.cppflags & PF_VIRTUAL && declclass)
                        addvtabentry(declclass,sp);
#endif
											if (al == sc_abs)
												sp->value.i = ilc;
											else
												if (head->type != bt_func && head->type != bt_ifunc)
													if (sp->storage_class == sc_static && table == &lsyms) {
														sp->value.i = nextlabel++;
														sp->staticlabel = TRUE;
													}
													else
														sp->value.i = block_nesting;
												else
#ifdef CPLUSPLUS
                          if (!(sp->value.classdata.cppflags &PF_OPERATOR))
#endif
                            sp->value.i = 0;
											{
												int align = getalign(al,head);
												int noadj = FALSE;

												if (al != sc_member || head->bits == -1) {
													if (curbit < 100)
														nbytes +=sizeoflastbit;
													curbit=100;
													sizeoflastbit=0;
													bittype = -1;
												}
												else if (bittype != head->type || head->bits +curbit > bitsize(head->type)) {
													nbytes += sizeoflastbit;
													sizeoflastbit = sp->tp->size; 
													bittype = head->type;
													curbit = 0;
													noadj = TRUE;
												}
												else
													noadj = head->bits != -1;

                        if (al == sc_member && sp->tp->type !=bt_func && sp->tp->type != bt_ifunc) {
														int val;
                                          if (packdata[packlevel]!= 1 && (!noadj || !curbit)) {
															val = (ilc + nbytes) %align;
															if (val)  val = align - val;
															nbytes += val;
														}
                                          sp->value.i = nbytes + ilc;
														if (!noadj)  {
															int size;
															if (curbit < 100)
																size = (curbit -1)/8 + 1;
															else
																size = sp->tp->size;
                                             nbytes += size;
														}
												}
											}
											if (head->bits != -1) {
												if (al != sc_member) {
													generror(ERR_BFILLEGAL,0,0);
													head->bits = -1;
												}
												else if (head->bits > bitsize(head->type)) {
													generror(ERR_BFTOOBIG,0,0);
													head->bits = -1;
												}
												else {
													if (prm_revbits)
														head->startbit = head->size*8-curbit-head->bits;
													else
														head->startbit = curbit;
													curbit+=head->bits;
												}
											}
											
											if (sp->absflag &&( sp->tp->type == bt_func || sp->tp->type == bt_ifunc))
												gensymerror(ERR_ILLCLASS,lastid);
											if (sp->intflag &&( sp->tp->type != bt_func && sp->tp->type != bt_ifunc))
												gensymerror(ERR_ILLCLASS,lastid);
#ifdef CPLUSPLUS
											/* kill the inline flag for cases we can't handle */
											if (mainfunc || (sp->tp->type == bt_func) || (sp->parentclass && (sp->value.classdata.cppflags & (PF_DESTRUCTOR | PF_VIRTUAL))))
													sp->value.classdata.cppflags &= ~PF_INLINE;
											if (sp->tp->type == bt_union && (sp->tp->type == bt_func || sp->tp->type == bt_ifunc))
												gensymerror(ERR_UNIONNOVIRT,lastid);
											if (sp->tp->type != bt_func && sp->tp->type != bt_ifunc) {
												if ((sp->value.classdata.cppflags & (PF_VIRTUAL | PF_INLINE | PF_FRIEND)) && !declclass)
													generror(ERR_VIRTFUNC,0,0);
/*												if ((sp->value.classdata.cppflags & (PF_CONSTRUCTOR | PF_DESTRUCTOR)) && !declclass)
													generror(ERR_CONSFUNC,0,0);
*/
											}
                                 if (sp->value.classdata.cppflags & (PF_CONSTRUCTOR | PF_DESTRUCTOR)) {
                                    if (sp->value.classdata.cppflags  & (PF_STATIC | PF_FRIEND))
                                       generror(ERR_NODESTRUCTQUAL,0,0);
//                                    if (!defaulttype)
//                                       gensymerror(ERR_CANTHAVETYPE,declclass->name);
                                 }
                                 if (sp->value.classdata.cppflags & PF_DESTRUCTOR)
                                    if (sp->tp->lst.head != (void *)-1)
                                       generror(ERR_NODESTRUCTARG,0,0) ;
											if (sp->value.classdata.cppflags & PF_OPERATOR)
												CheckOverloadedArgs(sp);
#endif
                      if( sp->tp->type == bt_func  && al != sc_static)
                            sp->storage_class = sc_externalfunc;
#ifdef CPLUSPLUS											
											if (memberptr && typequal)
                                    sp1 = basesearch(declid, &typequal->value.classdata.memberptrs,FALSE);
											else
#endif
                                    sp1 = basesearch(declid,table,FALSE);
                                 if (sp1 && sp1->tp->type == bt_defunc) {
                                    sp1 = funcovermatch(sp1,sp->tp,TRUE) ;
                                 }
											if (sp->name[0] == '@' && !sp1) {
												if (typequal && typequal != declclass) {
													genclasserror(ERR_NOCLASSMEMBERFUNC,sp->name);
												}
												funcrefinsert(declid,sp,table,declclass);
                                    reffed = TRUE ;
											}
                                 if (!sp1 || (sp1->tp->type != bt_func && sp1->tp->type != bt_ifunc)) {
												if (!sp1 || al == sc_auto || al == sc_autoreg || al== sc_member) {
#ifdef CPLUSPLUS
													if (memberptr && typequal)
														insert(sp, &typequal->value.classdata.memberptrs);
													else
#endif
													{
                                          if (!reffed)
                                             insert(sp,table);
														if (table != gsyms && sp->tp->type == bt_func) {
															LIST *l = xalloc(sizeof(LIST)) ;
															l->data = sp ;
															l->link = localfuncs ;
															localfuncs = l ;
														}
													}
				
#ifdef CPLUSPLUS
                                       if (prm_cplusplus && al == sc_member && (xcppflags & PF_STATIC)) {
														SYM *sp2 = copysym(sp) ;
														sp2->storage_class = lastst == assign || lastst == openpa ? sc_global : sc_external ;
//                                          sp2->name = sp->alias;
														sp->value.classdata.gdeclare = sp2 ;
														insert(sp2,gsyms) ;
													}
#endif
#ifndef ICODE
													if (sp->tp->cflags & DF_INTRINS)
														SearchIntrins(sp);
#else
                                       sp->tp->cflags &= ~DF_INTRINS;
#endif
												}
												else {
													if (!exactype(sp->tp,sp1->tp))
														gensymerror(ERR_DECLMISMATCH,sp->name);
													if (sp1->tp->size == 0)
														sp1->tp = sp->tp;
													if (sp1->storage_class == sc_external || sp1->storage_class == sc_externalfunc) {
														sp1->storage_class = sp->storage_class;
														sp1->tp = sp->tp;
														sp1->value = sp->value;
													} 
#ifdef CPLUSPLUS
													else if (sp1->storage_class == sc_member) {
														if (sp->storage_class == sc_static && !staticerror++)
															generror(ERR_NOSTATIC,0,0) ;
														if (sp1->value.classdata.gdeclare)
															sp1->value.classdata.gdeclare->storage_class = sp->storage_class ;
													}
#endif													
												}
											}
											else 
join:
  											if (sp1->tp->type == bt_func && sp->tp->type == bt_ifunc){
	  											if (sp1->storage_class == sc_external || sp1->storage_class == sc_externalfunc || sp1->storage_class == sc_static)
                                       sp1->oldstyle = sp->oldstyle ;
		  											if (al == sc_static || sp1->storage_class == sc_static)
			  											sp->storage_class = sp1->storage_class = sc_static;
				  									else
					  									sp->storage_class = sp1->storage_class = sc_global;
						  					}
                     	if( sp->tp->type == bt_ifunc) { /* function body follows */
														 int pushed = FALSE;
														 SYM *dc;
														 if (sp1) {
															 if (sp1->tp->type == bt_ifunc)
															   gensymerror(ERR_MULTIPLEINIT,sp->name);
															 else
														     sp1->tp->type = bt_ifunc;
																sp1->tp->lst.head = sp->tp->lst.head;
															  sp1->tp->lst.tail = sp->tp->lst.tail;
														 } else
															 sp1 = sp;
#ifdef CPLUSPLUS
                             if (declclass) {
														 	 if  (!(sp1->value.classdata.cppflags & (PF_DESTRUCTOR | PF_VIRTUAL)))
															 	 if (!mainfunc)		
                                                     sp->value.classdata.cppflags |= PF_INLINE ;
                                                   sp1->value.classdata.cppflags |= PF_HEADERFUNC;
                             }
														 if (typequal) {
															 dc = declclass;
															 declclass = typequal;
															 pushed = TRUE;
														 }
                                           if (sp1->value.classdata.cppflags & PF_CONSTRUCTOR) {
                                             setRefFlags(declclass) ;
                                             setthunkflags(declclass,FALSE) ;
															if (lastst == colon) {
																getsym();
                                                classbaseasn(declclass);
                                                if (lastst != begin)
                                                   generror(ERR_NEEDCHAR,'{',0) ;
															}
                                           }
#endif
                              browse_startfunc(sp1,varlineno) ;
                             funcbody(sp1);
                              browse_endfunc(sp1,lineno) ;
#ifdef CPLUSPLUS
														 if (pushed)
															 declclass = dc;
#endif
														 lastdecl = sp1;
														 if (al == sc_member && (xcppflags & PF_STATIC))
															 return 0 ;
                             return nbytes;
                             }
                        if( (sp->storage_class == sc_global || sp->storage_class == sc_static) &&
                           	sp->tp->type != bt_func && sp->tp->type != bt_ifunc
														&& !(flags & DF_FUNCPARMS)) {
													int pushed = FALSE;
													SYM *dc;
													if (sp->tp->type == bt_ref && lastst != assign && lastst != openpa)
														gensymerror(ERR_REFMUSTINIT,declid);
													if (declclass && typequal)
														gensymerror(ERR_NOINIT,sp->name);
													if (!sp1)
														sp1 = sp;
#ifdef CPLUSPLUS
													if (typequal) {
													  dc = declclass;
														declclass = typequal;
														pushed = TRUE;
													}
													if (lastst == openpa)
                                          if (sp1->tp->type != bt_class && sp1->tp->type != bt_struct)
															generror(ERR_OLDFUNCSTYLE,0,skm_declcomma);
														else 
															doinit(sp1);
													else 
#endif
														doinit(sp1);
                                       browse_variable(sp1, varlineno) ;
#ifdef CPLUSPLUS
													if (pushed)
													 declclass =  dc;
#endif
											}
											else 
												if (al == sc_auto || al == sc_autoreg) {
													int pushed = FALSE;
#ifdef CPLUSPLUS
													SYM *dc;
													if (typequal) {
														dc = declclass;
														declclass = typequal;
														pushed = TRUE;
													}
													if (prm_cplusplus &&(flags & DF_FUNCPARMS))
														dodefaultinit(sp);
													else
														if (sp->tp->type == bt_ref && lastst != assign && lastst != openpa)
															gensymerror(ERR_REFMUSTINIT,lastid);
#endif
                                       if (!(flags & DF_FUNCPARMS))
                                          browse_variable(sp, varlineno) ;
												 	doautoinit(sp);
#ifdef CPLUSPLUS
													if (pushed)
													 declclass =  dc;
#endif
												}
                                    else if (sp->storage_class == sc_external||sp->storage_class == sc_externalfunc)
                                       browse_variable(sp,varlineno) ;
										}
										else if (al != sc_type) {
											gensymerror(ERR_SIZE,declid);
											expskim(skm_declclosepa);
										}
										else {
											SYM *sp1 ;
											if (sp->tp->size) {
                                    sp->tp = copytype(sp->tp,0);
											}
											sp1 = search(sp->name,table) ;
											if (sp1) {
												if (!exactype(sp->tp,sp1->tp))
													gensymerror(ERR_DUPSYM,sp->name);
											} else
                      	insert(sp,table);
                        browse_variable(sp,varlineno) ;
                                 if (prm_debug)
                                    debug_outputtypedef(sp) ;
										}
                }
								if (!(flags & DF_FUNCPARMS)) {
	                if(lastst == semicolon)
                        break;
									dhead = copytype(dhead,0);
  	              needpunc(comma,skm_declend);
								}
								else {
	                if(lastst == comma)
										break;
									if (sp1)
										lastdecl = sp1;
									else
										lastdecl = sp;
									if (al == sc_member && (xcppflags & PF_STATIC))
										return 0 ;
                  return(nbytes);
								}
                if(declbegin(lastst) == 0 && lastst != colon)
                        break;
                head = dhead;
								head->uflags = ufsave;
        }
        getsym();
				if (sp1)
					lastdecl = sp1;
				else
					lastdecl = sp;
            if (al == sc_member && declcount == 0) {
//               if (head->type != bt_union) 
//                  generror(ERR_DECLEXPECT,0,0) ;
//               else 
               {
                  /* handle anonymous unions here... */
                  char buf[40] ;
                  SYM * lst = head->lst.head,*lst1 ;
                  {
												int align = getalign(al,head);
														int val;
                                          if (packdata[packlevel]!= 1) {
															val = (ilc + nbytes) %align;
															if (val)  val = align - val;
															nbytes += val;
														}
                                          sp->value.i = nbytes + ilc;
                                          {
															int size;
                                             size = head->size;
                                             nbytes += size;
														}
												}
                  lastdecl->isunnamed = TRUE ;
                  sprintf(buf,"$$UNNAMEDSTRUCT%d",unnamedstructcount++) ;
                  lastdecl->name = litlate(buf) ;
                  lastdecl->tp = head ;
                  while (lst) {
                     if (strcmp(lst->name,cpp_funcname_tab[CI_CONSTRUCTOR]) && strcmp(lst->name,cpp_funcname_tab[CI_DESTRUCTOR])) {
                        if (search(lst->name,table)) {
                           gensymerror(ERR_DUPSYM,lst->name) ;
                        } else {
                           lst1 = table->head ;
                           while (lst1) { 
                              if (lst1->isunnamed)
                                if (search(lst->name,&lst1->tp->lst)) {
                                    gensymerror(ERR_DUPSYM,lst->name) ;
                                    break ;
                                }
                              lst1 = lst1->next ;
                           }
                        }
                     }
                     lst = lst->next ;
                  }

                  if (table->head)
                     table->tail = table->tail->next = lastdecl;
                  else
                     table->tail = table->head = lastdecl ;
                  nbytes = head->size ;
               }
            }
				if (al == sc_member && (xcppflags & PF_STATIC))
					return 0 ;
        return nbytes;
}
int     declare(TABLE *table,int al,int ztype, int flags,int cppflags)
/*
 * In this wrapper we do an ENTIRE declaration
 */
{
				int old_gf = global_flag,rv;
				if (al == sc_static)
					global_flag ++;
				typequal = 0;
        cppflags |= decl(table,cppflags);
				rv = basedeclare(table,al,0,ztype,flags,cppflags);
				global_flag = old_gf;
				return rv;
}
int     declare2(TABLE *table,int al,int ztype, int flags, int cppflags,long val)
/*
 * In this wrapper we do an ENTIRE declaration
 */
{
				int old_gf = global_flag,rv;
				if (al == sc_static)
					global_flag ++;
				typequal = 0;
        cppflags |= decl(table,cppflags);
				rv = basedeclare(table,al,val,ztype,flags,cppflags);
				global_flag = old_gf;
				return rv;
}

int     declbegin(int st)
/*
 * This determines if another variable is being declared of the same type
 */
{       return st == star || st == id || st == openpa ||
                st == openbr;
}

void declenum(TABLE *table,int cppflags)
/*
 * declare enums
 */
{       SYM     *sp;
        TYP     *tp;
				char *nm;
            int enumline = lineno ;
				int xglob = global_flag;
        if( lastst == id) {
/* tagged */
								global_flag++;
#ifdef CPLUSPLUS
								if (prm_cplusplus) {
                           nm = litlate(lastid) ;
                           if (table)
                              sp = search(nm,table);
                           else
                              sp = 0 ;
									if (!sp && declclass)
										sp = search(nm,declclass);
									if (!sp)
										sp = search(nm,gsyms);
									getsym();
									if (sp && sp->storage_class == sc_type) {
										sp = parsetype(sp);
										if (sp->storage_class != sc_type )
											generror(ERR_TYPENAMEEXP,0,0);
										else if (sp->tp->type != bt_enum)
											gensymerror(ERR_DECLMISMATCH,sp->name);
									}
								} else
#endif
								{
                	sp = search(nm = litlate(lastid),&tagtable);
									getsym();
								}
								if (sp == 0) {
                        sp = xalloc(sizeof(SYM));
                        sp->tp = xalloc(sizeof(TYP));
                        sp->tp->type = bt_enum;
                        sp->tp->size = 4;
                        sp->tp->lst.head = sp->tp->btp = 0;
                        sp->storage_class = sc_type;
                        sp->name = nm;
                        sp->tp->sp = sp;
												sp->tp->bits = sp->tp->startbit = -1;
#ifdef CPLUSPLUS
		 										sp->value.classdata.cppflags |= cppflags;
												/* tags are also typedefs in C++ */
                                    if (prm_cplusplus) {
													insert(sp,table);
                                    }
												else
#endif                  
                        	insert(sp,&tagtable);
                        browse_variable(sp,enumline) ;
                }

                if( lastst == begin) {
									
                  getsym();
                  sp->tp->enumlist = enumbody(table);
                }
                if (prm_debug && prm_cplusplus)
                  debug_outputtypedef(sp) ;
								global_flag--;
                head = sp->tp;
                }
        else    {
/* untagged */
                tp = xalloc(sizeof(TYP));
                tp->type = bt_enum;
                tp->lst.head = tp->btp = 0;
								tp->size = 4;
								tp->bits = tp->startbit = -1;
								tp->sp = 0;
                if( lastst != begin)
                        generror(ERR_PUNCT,begin,skm_declend);
                else    {
												global_flag++ ;
                        getsym();
                        tp->enumlist = enumbody(table); /* just ignore the enum list */
												global_flag--;
                        }
                head = tp;
                }
	global_flag = xglob;
}

char *nexttagname(void)
{
	static int nexttag = 0;
	char buf[256];
	sprintf(buf,"$$UNNAMEDTAG%d",nexttag++);
	return litlate(buf);
}
SYM *enumbody(TABLE *table)
/*
 * read the enumeration constants in
 */
{       long     evalue;
        SYM     *sp, *list = 0, **next = &list;
        evalue = 0;
        while(lastst == id) {
                sp = xalloc(sizeof(SYM));
                sp->value.i = evalue++;
                sp->name = litlate(lastid);
                sp->storage_class = sc_const;
                sp->tp = &stdconst;
								(*next) = sp ;
								next = &(*next)->enumlist ; 
								if (prm_cplusplus || table == &lsyms)
									insert(sp,table);
								else
									insert(sp,gsyms);
                getsym();
								if (lastst == assign) {
										getsym();
										evalue = sp->value.i = intexpr(0);
										sp->value.i = evalue++;
								}
                if( lastst == comma)
                        getsym();
                else if(lastst != end)
                        break;
                }
        needpunc(end,skm_declend);
	return list ;
}
void doreclone(TYP *tp)
{
   struct stab lst = tp->lst ;
   int size = tp->size ;
   while (tp->reclone) {
      TYP *s = tp->reclone ;
      tp->reclone = 0 ;
      tp = s ;
      tp->lst = lst ;
      tp->size = size ;
      tp->val_flag = TRUE ;
   }
}
void declstruct(TABLE *table, int ztype, int flags, int cppflags)
/*
 * declare a structure or union type
 */
{       SYM     *sp;
        TYP     *tp;
				char *nm;
				int xglob = global_flag;
            int structline = lineno ;
        if(lastst == id) {
								global_flag++;
/* tagged */
#ifdef CPLUSPLUS
								if (prm_cplusplus) {
                           nm = litlate(lastid) ;
                           if (table)
                              sp = search(nm,table);
                           else
                              sp = 0 ;
									if (!sp && declclass)
										sp = search(nm,declclass);
									if (!sp)
										sp = search(nm,gsyms);
									getsym();
									if (sp && sp->storage_class == sc_type) {
										sp = parsetype(sp);
										if (sp->storage_class != sc_type )
											generror(ERR_TYPENAMEEXP,0,0);
										else if (sp->tp->type != ztype)
											gensymerror(ERR_DECLMISMATCH,sp->name);
									}
								} else
#endif
								{
                	sp = search(nm = litlate(lastid),&tagtable);
									getsym();
								}
								if (sp == 0) {
/* if tag was never defined */
                        sp = xalloc(sizeof(SYM));
                        sp->name = nm;
                        sp->tp = xalloc(sizeof(TYP));
                        sp->tp->type = ztype;
                        sp->tp->lst.head = 0;
                        sp->storage_class = sc_type;
                        sp->tp->sp = sp;
												sp->tp->cflags = flags;
												sp->tp->uflags = UF_DEFINED;
												sp->tp->size = 0;
#ifdef CPLUSPLUS
		 										sp->value.classdata.cppflags |= cppflags;
												/* tags are also typedefs in C++ */
												if (prm_cplusplus)
													insert(sp,table);
												else
#endif
                        	insert(sp,&tagtable);
												global_flag--;
                        if(lastst == begin || ((ztype == bt_class || ztype == bt_struct )&& lastst == colon)) {
																if (lastst == begin)
                                	getsym();
                                structbody(sp,ztype);
                                 browse_variable(sp,structline) ;
                                 if (prm_debug && prm_cplusplus)
                                    debug_outputtypedef(sp) ;
                                    } else
                                       sp->tp->reclone = sp->tp ;

											}
                else {
												if (ztype != sp->tp->type)
													generror(ERR_MISMATCH,0,0);

												global_flag--;
/* Allow redefinition if it was forward declared */
                        if(lastst == begin || ((ztype == bt_class || ztype == bt_struct )&& lastst == colon)) {
													if (lastst == begin)
														getsym();
                                       if (sp->tp->size == 0) { 
														structbody(sp,ztype);
                                          doreclone(sp->tp) ;
                                         browse_variable(sp,structline) ;
                                       } else {
														gensymerror(ERR_DUPSYM,sp->name);
														expskim(skm_declclosebr);
													}
												}
								}
								if (flags & (DF_CONST | DF_VOL))
									head = copytype(sp->tp,flags);
								else
                	head = sp->tp;
								head->bits = head->startbit = -1;
                }
        else    {
								global_flag++;
/* untagged */
                tp = xalloc(sizeof(TYP));
                tp->type = ztype;
								tp->cflags = flags;
								tp->uflags = UF_DEFINED;
                tp->sp = sp;
                tp->lst.head = 0;
								tp->bits = tp->startbit =-1;
								sp = xalloc(sizeof(SYM));
								sp->name = nexttagname();
								sp->tp = tp;
                tp->sp = sp;
                if( lastst != begin)
                       	generror(ERR_PUNCT,begin,skm_declend);
                else    {
                        getsym();
                        structbody(sp,ztype);
                        }
                head = tp;
                }
	global_flag = xglob;
}

void structbody(SYM *sp, int ztype)
/*
 * read in the structure/union elements and calculate the total size
 */
{       int     slc,vv;
        int mode,basemode ;
				int flags=0;
				SYM *dc;
				int pushed = FALSE;
        int decltype;
				int ocppflags = cppflags ;
				cppflags = 0 ;
#ifdef CPLUSPLUS
            if (prm_cplusplus) {
					global_flag++;
               sp->value.classdata.size += classhead ;
            }
				sp->parentclass = declclass;
				if (ztype == bt_class) {
               sp->value.classdata.baseclass = xalloc(sizeof(CLASSLIST)) ;
               sp->value.classdata.baseclass->data = sp ;
               sp->value.classdata.baseclass->vtabsize = vtabhead ;
               dc = declclass;
					declclass = sp;
					flags |= PF_PRIVATE;
               basemode = mode = BM_PRIVATE ;
					pushed = TRUE;
				}
				else if (prm_cplusplus && (ztype == bt_struct || ztype == bt_union || ztype == bt_class)) {
               sp->value.classdata.baseclass = xalloc(sizeof(CLASSLIST)) ;
               sp->value.classdata.baseclass->data = sp ;
               sp->value.classdata.baseclass->vtabsize = vtabhead ;
               dc = declclass;
					declclass = sp;
					if (ztype == bt_struct)
						ztype = bt_class;
					flags |= PF_PUBLIC;
               basemode = mode = BM_PUBLIC ;
					pushed = TRUE;
				}
        if (sp->name && prm_cplusplus) {
          SYM *sp1 = xalloc(sizeof(SYM));
          sp->value.classdata.baseclass->vtabsp = sp1;
          sp1->storage_class = sc_static;
          sp1->tp = &stdint;
          sp1->name = fullcppmangle(0,"$vtab",0);
        }
#endif
        sp->tp->size = 0;
        sp->tp->val_flag = 1;
				sp->tp->uflags &= ~UF_CANASSIGN;
            curbit=100;                       
				sizeoflastbit=0;
				bittype = -1;
#ifdef CPLUSPLUS
            if (prm_cplusplus && lastst == colon) {
               while (TRUE) {
                  getsym();
                  switch (lastst) {
                     case kw_private:
                        mode = BM_PRIVATE;
                        getsym();
                        break;
                     case kw_protected:
                        mode = BM_PROTECTED;
                        getsym();
                        break;
                     case kw_public:
                        mode = BM_PUBLIC;
                        getsym();
                        break;
                  }
                  if (lastst != id) {
                     generror(ERR_IDEXPECT,0,0);
                  }
                  else {
                     SYM *odc = declclass ;
                     SYM *spx ;
                     declclass = 0 ;
                     spx = gsearch(lastid);
                     declclass = odc ;

                     if (!spx || spx->storage_class != sc_type)
                           generror(ERR_TYPENAMEEXP,0,skm_declbegin);
                     else {
                        if (spx->tp->type == bt_union)
                           generror(ERR_UNIONNOBASE,0,0);
                        getsym();
                     }
                     loadclassdata(sp,spx,mode);   
                  }
                  if (lastst != comma)
                     break ;
                  mode = basemode ;
               }
               if (lastst != begin)
                  generror(ERR_PUNCT,begin,0);
               else
                  getsym();
				}
#endif
				slc = sp->value.classdata.size;
        while( lastst != end && lastst != eof) {
#ifdef CPLUSPLUS
								cppflags = 0;
								if (prm_cplusplus) {
									switch (lastst) {
										case kw_private:
											flags &= ~(PF_PRIVATE | PF_PUBLIC | PF_PROTECTED);
											flags |= PF_PRIVATE;
											getsym();
											needpunc(colon,0);
											continue;
										case kw_protected:
											flags &= ~(PF_PRIVATE | PF_PUBLIC | PF_PROTECTED);
											flags |= PF_PROTECTED;
											getsym();
											needpunc(colon,0);
											continue;
										case kw_public:
											flags &= ~(PF_PRIVATE | PF_PUBLIC | PF_PROTECTED);
											flags |= PF_PUBLIC;
											getsym();
											needpunc(colon,0);
											continue;
									}
								}
										
#endif						
#ifdef CPLUSPLUS
                if (lastst == kw_typedef) {
                  decltype = sc_type;
                  getsym();
                }
                else
                  decltype = sc_member;
								if (prm_cplusplus)
									flags |= PF_MEMBER;
                friendclass = friendfunc = FALSE ;
                if(ztype == bt_struct || ztype == bt_class)
                        slc += declare2(&sp->tp->lst,decltype,ztype,0,flags,slc);
                else
                        slc = imax(slc,vv=declare2(&sp->tp->lst,decltype,ztype,0,flags,0));
                if (sp->tp->lst.tail) {
                   sp->tp->lst.tail->tp->uflags |= UF_DEFINED;
                   if (sp->tp->lst.tail->tp->type == bt_struct || sp->tp->lst.tail->tp->type == bt_class) {
                     CLASSLIST **l = &sp->value.classdata.enclosedclass ;
                     while (*l)
                        l = &(*l)->link ;
                     *l = xalloc(sizeof(CLASSLIST)) ;
                     (*l)->data = sp->tp->lst.tail ;
                     (*l)->offset = sp->tp->lst.tail->value.i ;
                   }
                  if (currentfunc && (sp->tp->lst.tail->tp->type == bt_ifunc || sp->tp->lst.tail->tp->type == bt_func))
									generror(ERR_LOCALCLASSNOFUNC,0,0);
                }
#else
                if(ztype == bt_struct || ztype == bt_class)
                        slc += declare2(&sp->tp->lst,sc_member,ztype,0,flags,slc);
                else
                        slc = imax(slc,vv=declare2(&sp->tp->lst,sc_member,ztype,0,flags,0));
#endif
                if (sp->tp->lst.tail && sp->tp->lst.tail->isunnamed)
                  sp->hasunnamed = TRUE ;
              }
				if (curbit < 100) {
					int size = (curbit-1)/8 + 1;
					if (ztype == bt_struct || ztype == bt_class)
						slc+=size;
					else
						slc = imax(slc,vv+size);
					curbit = 100;
				}
            /* calculate the suggested alignment for this type */
            if (packdata[packlevel] != 1) {
               dc = sp->tp->lst.head ;
               vv = 1 ;
               while (dc) {
                  int vv1 = getalign(sc_member, dc->tp) ;
                  if (vv1 > vv)
                     vv = vv1 ;
                  dc = dc->next ;
               }
               sp->tp->alignment = vv ;
            } else
               sp->tp->alignment = 1 ;
#ifdef CPLUSPLUS
            if (prm_cplusplus) {
               int xx = FALSE ;
               CLASSLIST *l = sp->value.classdata.baseclass ;
               while (l) {
                  if (l->isvtab) {
                     xx = !l->offset ;
                     break ;
                  }
                  l = l->link ;
               }
               if (!xx) {
                  CLASSLIST* l ;
                  dc = sp->tp->lst.head ;
                  while (dc) {
                     if (dc->tp->type != bt_func && dc->tp->type != bt_ifunc &&
                           dc->tp->type != bt_defunc)
                        if (dc->value.i)
                           dc->value.i -= classhead ;
                     if (dc->tp->type == bt_defunc) {
                        SYM *dc1 = dc->tp->lst.head ;
                        while (dc1) {
                           if (dc1->value.classdata.vtaboffs)
                              dc1->value.classdata.vtaboffs -= classhead ;
                           dc1 = dc1->next ;
                        }
                     } else if (dc->tp->type == bt_ifunc || dc->tp->type == bt_func)
                        dc->value.classdata.vtaboffs -= classhead ;                     
                     dc = dc->next ;
                  }
                  l = sp->value.classdata.baseclass ;
                  while (l) {
                     if (l->offset)
                        l->offset -= classhead ;
                     l = l->link ;
                  }
                  slc -= classhead ;
               }
            }
            /* now if we aren't packing make the size of the structure
             * a multiple of the alignment size
             */
//            if (packdata[packlevel] != 1) {
//               slc = slc + packdata[packlevel] - 1 ;
//               slc = (slc / packdata[packlevel]) * packdata[packlevel] ;
//            }
				/* had to change because of inheritance */
				sp->tp->size = sp->value.classdata.size = slc;

				if (pushed) {
					classerrs(sp);
					gen_vtab(sp);
					declclass = dc;
				}
            if (prm_cplusplus) {
               CreateBaseConstructor(sp) ;
					global_flag--;
            }
#endif
        getsym();
				cppflags = ocppflags ;
                friendclass = friendfunc = FALSE ;
}
void check_used(void)
/*
 * At the end of compilition we check for some common cases where 
 * module-scoped variables are either missing or unused
 */
{
				int i;
				SYM *sp;
					for (i=0; i < HASHTABLESIZE; i++) {
						if ((sp=(SYM *) gsyms[i]) != 0) {
							while (sp) {
								if (sp->storage_class == sc_static)
									if (sp->tp->uflags & UF_USED) {
										if (sp->tp->type == bt_func)
											gensymerror(ERR_NOSTATICFUNC,sp->name);
									}
									else
										if (sp->tp->type == bt_ifunc || sp->tp->type == bt_func)
											gensymerror(ERR_FUNCUNUSED,sp->name);
										else
											gensymerror(ERR_STATICSYMUNUSED,sp->name);
								sp = sp->next;
							}
						}
					}
				sp = tagtable.head;
				while (sp) {
					if (sp->tp->size == 0) 
						gensymerror(ERR_NEVERSTRUCT,sp->name);
					sp = sp->next;
				}
}
void compile(void)
/*
 * Main compiler routine
 */
{       while(lastst != eof) {
                dodecl(sc_global);
								if (lastst != eof) {
									generror(ERR_DECLEXPECT,0,0);
									getsym();
								}
        }
#ifdef ICODE
				rewrite_icode();
#else
				flush_peep();
#endif
            dumplits();
				initrundown();
#ifndef ICODE
				dump_muldivval();
#endif
            dumpstartups();
				check_used();
				putexterns();
				if (!prm_asmfile)
					output_obj_file() ;
}

void dodecl(int defclass)
/*
 * Declarations come here, ALWAYS
 */
{
				SYM *sp;
				int flags = 0;
				long val;
				char *nm;
				cbautoinithead = 0;
        for(;;) {
						isexport = FALSE ;
						isimport = FALSE ;
						ispascal = FALSE;
						isstdcall = FALSE;
						isindirect = FALSE ;
						iscdecl = FALSE;
                  friendclass = friendfunc = FALSE ;
            switch(lastst) {
								case semicolon:
												getsym();
												break;
								case kw_typedef:
												getsym();
												if (defclass == sc_global)
													declare(gsyms,sc_type,bt_struct, 0,0);
												else
													declare(&lsyms,sc_type,bt_struct, 0,0);
												break;
                case kw_register:
                        if( defclass != sc_auto || flags & DF_VOL) {
                          gensymerror(ERR_ILLCLASS,lastid);
                        	getsym();
												}
												else  {
                        	getsym();
          	                  declare(&lsyms,sc_autoreg,bt_struct,flags | DF_AUTOREG,0);
												};
										break;
#ifdef CPLUSPLUS
								case kw_namespace:
										if (prm_cplusplus) {
                                 char *name = lastid ;
											if (global_flag) {
                                    getsym();
                                    if (lastst != id) {
                                       name = 0 ;
                                    }
                                    switchtonamespace(name);
                                    needpunc(begin,0);
                                    dodecl(defclass);
                                    needpunc(end,0);
                                    needpunc(semicolon,0);
                                    switchfromnamespace();
											}
                                 else 
                                    generror(ERR_NOLOCALNAMESPACE,0,0);
											break;
										}
										lastst = id;
#endif
                case id:
										if (defclass == sc_auto)
												if (!(((sp = search(nm = litlate(lastid),gsyms)) != 0 && sp->storage_class == sc_type)
												     || ((sp = search(nm,&lsyms)) != 0 && sp->storage_class == sc_type)))
													return;
                        case kw_restrict:
                        case kw_class: case kw_operator:
								case kw_volatile: case kw__intrinsic:
								case kw_const: case kw_virtual: case kw_inline: case kw_friend:
                case kw_char: case kw_int: case kw_short: case kw_unsigned:
                case kw_long: case kw_struct: case kw_union: case kw_signed:
                case kw_enum: case kw_void:  case kw_bool:
                case kw_float: case kw_double: case kw_wchar_t:
                    if( defclass == sc_global)
                            declare(gsyms,sc_global,bt_struct,flags | DF_GLOBAL,0);
                    else if( defclass == sc_auto)
                            declare(&lsyms,sc_auto,bt_struct,flags,0);
                    else
                        declare(&lsyms,sc_auto,bt_struct,flags,0);
                    break;
                case kw_static:
                        if( defclass == sc_member) {
                           gensymerror(ERR_ILLCLASS,lastid);
														getsym();
														break;
												}
												getsym();
												if( defclass == sc_auto)
														declare(&lsyms,sc_static,bt_struct,flags | DF_GLOBAL,0);
												else
														declare(gsyms,sc_static,bt_struct,flags | DF_GLOBAL,0);
                        break;
								case kw_auto:
												if (defclass != sc_auto) {
                           gensymerror(ERR_ILLCLASS,lastid);
														getsym();
														break;
												}
												getsym();
												declare(&lsyms,sc_auto,bt_struct,flags,0);
												break;
                case kw_extern: {
                        int cblock = FALSE ;
                        getsym();
                        if( defclass == sc_member)
                            gensymerror(ERR_ILLCLASS,lastid);
#ifdef CPLUSPLUS
												if (prm_cplusplus && lastst == sconst) {
													if (!strcmp(laststr,Cstr)) {
                                          mangleflag = !++manglelevel;
                                          cblock = TRUE ;
														getsym();
														if (lastst == begin) {
                                            getsym();
                                            dodecl(defclass) ;
                                            needpunc(end,0) ;
														}
                                          else {
                                             ++global_flag;
                                             declare(gsyms,sc_external,bt_struct,flags,0);
                                             --global_flag;
                                          }
                                          mangleflag = !--manglelevel ;
													}
												}
#endif
                        if (!cblock) {
                           ++global_flag;
                           declare(gsyms,sc_external,bt_struct,flags,0);
                           --global_flag;
                        }
                        }
                        break;
								case kw__interrupt:
												intflag = 1;
												flags |= DF_INT;
												getsym();
												continue;
								case kw__loadds:
												intflag = 1;
												flags |= DF_LOADDS;
												getsym();
												continue;
								case kw__far:
												farflag = 1;
												flags |= DF_FAR;
												getsym();
												continue;
								case kw__abs:
												++global_flag;
												getsym();
												if (lastst != openpa) {
													generror(ERR_PUNCT,openpa,skm_declend);
												}
												else {
													getsym();
													val = intexpr(0);
													if (lastst != closepa)
														generror(ERR_PUNCT,closepa,skm_declend);
													else {
														getsym();
														declare2(gsyms,sc_abs,bt_struct,flags,0,val);
													}
												}
												--global_flag;
												break;
                default:
                        return;
                }
						flags = 0;
						intflag = 0;
						farflag = 0;
            }
}
/*
 * in C++, a class/struct declarator can come first on a line but not
 * be a type specifier
 */
void blockdecl(void)
{
#ifdef CPLUSPLUS
	SYM *typesp;
	if (prm_cplusplus) {
		if (lastst == id) {
			typequal = 0;
			if ((typesp = gsearch(lastid)) && typesp->storage_class == sc_type) {	
				getsym();
				typesp = parsetype(typesp);
        if (typesp && typesp->storage_class == sc_type) {
          head = tail = copytype(typesp->tp,0);
					basedeclare(&lsyms,sc_auto,0,bt_struct,0,0);
					typequal = 0;
        } else 
					return;
			}
			else 
				dodecl(sc_auto);
		}
		else
			dodecl(sc_auto);
	} else
#endif
		dodecl(sc_auto);
}
void doargdecl(int defclass, char *names[], int *nparms, TABLE *table, int isinline)
/*
 * Function arguments are declared here
 */
{
				SYM *sp;
				int flags = isinline ? DF_FUNCPARMS : 0;
            int ocppf = cppflags, ofrcl = friendclass, ofrfu = friendfunc ;
            friendclass = friendfunc = FALSE ;
            cppflags = 0 ;
            inprototype = isinline ;
        for(;;) {
            switch(lastst) {
								case ellipse: {
									sprintf(declid,"**ELLIPSE%d**",pcount++);
									sp = xalloc(sizeof(SYM));
									sp->name = litlate(declid);
                  sp->storage_class = sc_auto;
									sp->tp = maketype(bt_ellipse,0);
									sp->tp->uflags |= UF_DEFINED | UF_USED;
									insert(sp,table);
									if (ispascal || isstdcall)
										generror(ERR_PASCAL_NO_ELLIPSE,0,0);
									getsym();
									goto exit;
								}
                        case kw_const: case kw_restrict:
								case id:
                case kw_char: case kw_int: case kw_short: case kw_unsigned:
                case kw_long: case kw_struct: case kw_union: case kw_signed:
                case kw_enum: case kw_void: case kw_bool:
                case kw_float: case kw_double: case kw_wchar_t:
                    declare(table,sc_auto,bt_struct,flags,0);
                    break;
								case kw_register:
										getsym() ;
#ifdef COLDFIRE
										if (lastst >= KW_D0 && lastst <= KW_A8) {
											flags |= DF_FORCEREG ;
											flags |= (lastst - KW_D0) << 24 ;
											getsym() ;
											declare(&lsyms,sc_autoreg,bt_struct,flags | DF_AUTOREG,0);
										} else 
#endif
										continue ;
                case kw_static:
								case kw_auto:
                        gensymerror(ERR_ILLCLASS,lastid);
                        getsym();
												continue;
                default:
												goto exit;
                }
							if (isinline) {
								names[(*nparms)++] = litlate(declid);
							}
						
				flags &= ~DF_CONST;
				}
exit:
      inprototype = FALSE ;
		if (prm_cplusplus) {
#ifdef CPLUSPLUS
			SYM *sp = table->head;
			int found = FALSE;
			while (sp) {
				if (sp->value.classdata.defalt)
					found = TRUE;
				else 
					if (found)
						gensymerror(ERR_MISSINGDEFAULT,sp->name);
				sp = sp->next;
			}
#endif
		}
      cppflags = ocppf ;
      friendclass = ofrcl ;
      friendfunc = ofrfu ;
}