/*
 * 68K/386 32-bit C compiler.
 *
 * copyright (c) 1997, David Lindauer
 * 
 * This compiler is intended for educational use.  It may not be used
 * for profit without the express written consent of the author.
 *
 * It may be freely redistributed, as long as this notice remains intact
 * and either the original sources or derived sources 
 * are distributed along with any executables derived from the originals.
 *
 * The author is not responsible for any damages that may arise from use
 * of this software, either idirect or consequential.
 *
 * V1.85 July 2000
 * David Lindauer, camille@bluegrass.net
 *
 * Credits to Mathew Brandt for original K&R C compiler
 *
 */
/*
 * handle ALL declarative statements
 */
#include        <stdio.h>
#include				<limits.h>
#include 				<string.h>
#include        "lists.h"
#include        "expr.h"
#include        "c.h"
#include        "errors.h"

extern int stdinttype,stdunstype,stdintsize, stdldoublesize,stdaddrsize;
extern int strucadd,strucmod;
extern TYP stdint;

extern int prm_cmangle;
extern char laststr[];
extern int global_flag;
extern HASHREC **gsyms;
extern TABLE lsyms;
extern	SNODE *cbautoinithead;
extern int prm_packing;
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;

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

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_register, kw_typedef, id, kw_void, 0 };

int							sizeoflastbit;
TYP             *head = 0, **headptr;
TYP             *tail = 0;
char            declid[100];
TABLE           tagtable = {0,0};
int ispascal,isstdcall,iscdecl;

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;

void declini(void)
/*
 * init
 */
{
	bittype = -1;
	head = tail = 0;
	declid[0] = 0;
	tagtable.head = tagtable.tail = 0;
	pcount = 0;
	mangleflag = TRUE;
	declclass = 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;
	return tp;
}
TYP *copytype(TYP *itp, int flags)
/*
 * copy a type tree
 */
{
	TYP *head, *tail,*x=itp;
	while (x->type == bt_pointer)
		x = x->btp;
	if (isstructured(x)) 
		if (!x->lst.head) {
			itp->cflags = flags;
			return head = tail = itp;
		}
	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;
	}
	return head;
}
int istype(void)
{
	SYM *sp;
	switch (lastst) {
		case kw_void:
    case kw_char:
		case kw_bool:
    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)
															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;
				while (lastst == kw_const || lastst == kw_volatile || lastst == kw__intrinsic ||
						(prm_cplusplus &&(lastst == kw_virtual || lastst == kw_inline || lastst == kw_static))) {
					switch (lastst) {
						case kw_const:
							flags |= DF_CONST;
							break;
						case kw_volatile:
							flags |= DF_VOL;
							break;
						case kw__intrinsic:
							flags |= DF_INTRINS;
							break;
#ifdef CPLUSPLUS
						case kw_virtual:
							cppflags |= PF_VIRTUAL;
							break;
						case kw_static:
							cppflags |= PF_STATIC;
							break;
						case kw_inline:
							cppflags |= PF_INLINE;
							break;
						case kw_friend:
							cppflags |= PF_FRIEND;
							break;
#endif
					}
					getsym();
				}
        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_int: 
                        getsym();
								default:
                        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();
															generror(ERR_LONGLONG,0,0);
														}
														if (lastst == kw_int)
															getsym();
                        		head = tail = maketype(bt_unsigned,4);
														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();
															generror(ERR_LONGLONG,0,0);
														}
														if (lastst == kw_int)
															getsym();
                        		head = tail = maketype(bt_long,4);
														break;
													case kw_int:
														getsym();
													default:
                        		head = tail = maketype(stdinttype,stdintsize);
														break;
												}
                        break;
								case kw_class:
												if (prm_cplusplus) {
													getsym();
													declstruct(table, bt_class, flags | DF_PRIVATE,cppflags);
													break;
												}
                case id:                /* no type declarator */
												if ((typesp = gsearch(lastid)) && typesp->storage_class == sc_type) {	
													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_long,4);
                          }
#endif
												}
												else {
                       		head = tail = maketype(bt_long,4);
												}
                        break;
								case kw_operator:
                       		head = tail = maketype(bt_long,4);
													break ;
                case kw_float:
                        head = tail = maketype(bt_float,4);
                        getsym();
                        break;
								case kw_long:
												getsym();
												if (lastst==kw_double) {
													getsym();
                        	head = tail = maketype(bt_longdouble,stdldoublesize);
													break;
												}
												if (lastst==kw_float) {
													getsym();
                        	head = tail = maketype(bt_double,8);
													break;
												}
												if (lastst == kw_long) {
													getsym();
													generror(ERR_LONGLONG,0,0);
												}
												tp = bt_long;
												if (lastst == kw_unsigned) {
													tp = bt_unsigned;
													getsym();
												}
												if (lastst == kw_long) {
													getsym();
													generror(ERR_LONGLONG,0,0);
												}
												if (lastst == kw_int)
													getsym();
                        head = tail = maketype(tp,4);
                        break;
                case kw_double:
                        head = tail = maketype(bt_double,8);
                        getsym();
                        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;
}

#ifdef CPLUSPLUS
void checkclasstype(void)
{
	if (prm_cplusplus) {
 		if (declclass && typequal && (declclass != typequal || currentfunc))
 			gensymerror(ERR_CANTHAVETYPE,typequal->name);
		if (lastst == compl) {
			getsym();
			strcpy(declid,cpp_funcname_tab[CI_DESTRUCTOR]);
			if (!strcmp(typequal->name,lastid))
				gensymerror(ERR_BADESTRUCT,typequal->name);
			cppflags |= PF_DESTRUCTOR;
		}
		else if (typequal && !strcmp(typequal->name,lastid)) {
			strcpy(declid,cpp_funcname_tab[CI_CONSTRUCTOR]);
			cppflags |= PF_CONSTRUCTOR;
		}
		else
			strcpy(declid,lastid);
	}
	else
		strcpy(declid,lastid);
	
}
#endif
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;
		}
		/* 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) {
#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_inline:
									if (!prm_cplusplus) {
										lastst = id;
										goto getid;
									}
									cppflags |= PF_INLINE;
									getsym();
									goto lp;
								case kw_friend:
									if (!prm_cplusplus) {
										lastst = id;
										goto getid;
									}
									cppflags |= PF_FRIEND;
									getsym();
									goto lp;
#endif
								case kw_const:
									head1->cflags |= DF_CONST;
									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__pascal:
									ispascal = TRUE;
									getsym();
									goto lp;
								case kw__cdecl:
									iscdecl = TRUE;
									getsym();
									goto lp;
#ifdef CPLUSPLUS
								case compl:
									checkclasstype();
									decl2(sp);
									break;
								case kw_operator:
									overloadoperator(sp);
									decl2(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 (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(sp);
                            break;
                          } else
                            if (typesp && typesp->storage_class == sc_type)
                              generror(ERR_IDEXPECT,0,0);
                        else 
                          if (lastst != id)
                            generror(ERR_IDEXPECT,0,0);
												
		
												if (typequal)
													checkclasstype();
											}
#endif
                        getsym();
                        strcpy(declid,lastid);
                        decl2(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(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(sp);
                        break;
                default:
                        decl2(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: 
      if (argcount != 1)
				gensymerror(ERR_DECL1ARG,sp->name);
			else
				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:
      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;
	}
}
#endif
void decl2(SYM *sp)
/*
 * type modifiers that come AFTER the name of the variable
 */
{       TYP     *temp1, *head1 = *headptr;
				int ocppf;
				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__intrinsic:
									head1->cflags |= DF_INTRINS;
									getsym();
									goto lp;
								case kw_volatile:
									head1->cflags |= DF_VOL;
									getsym();
									goto lp;
                case openbr:
												decl3();
												decl2(sp);
                        break;
                case openpa:
                        getsym();
	                      temp1 = maketype(bt_func,0);
												if (head1->cflags & DF_INTRINS)
													temp1->cflags |= DF_INTRINS;
#ifdef CPLUSPLUS
												if (cppflags & PF_DESTRUCTOR) {
													head1->uflags |= UF_DEFINED;
    	                  	temp1->val_flag = 1;
      	                	temp1->btp = head1;
        	              	*headptr = temp1;
													temp1->uflags |= UF_DEFINED;
						            	if (lastst != closepa)
														generror(ERR_NODESTRUCTARG,0,skm_declclosepa);
													else
														getsym();
												}
#endif
												{
													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
													declfuncarg(intflag,farflag,sp);
													sp->name = 0;
													cppflags = ocppf;
#ifdef CPLUSPLUS
													if (prm_cplusplus) {
														while (lastst == kw_const || lastst == kw_volatile) {
															if (lastst == kw_const)
																temp1->cflags |= DF_CONST;
															else
																temp1->cflags |= DF_VOL;
															getsym();
														}
														if (!declclass && !typequal && (temp1->cflags & (DF_CONST | DF_VOL)))
															generror(ERR_CONSTNOMEMBER,0,0);
													}
										
#endif
													if (lastst == begin) {
														if (head->type == bt_func)
															head->type = bt_ifunc;
														else
															temp1->type = bt_ifunc;
#ifdef CPLUSPLUS
														if (cppflags & PF_CONSTRUCTOR)
															if (lastst == colon) {
																getsym();
																classbaseasn(sp);
															}
															else consreferr(sp,0,0,0);
#endif	
														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) {
											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;
                }
}

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;
	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 {
                                temp1->size = intexpr(0);
                                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:
			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,mainfunc;
        nbytes = 0;
        dhead = head;
				ufsave = head->uflags;
        for(;;) {
								sp1 = 0;
                declid[0] = 0;
								memberptr = FALSE;
								headptr = &head;
                sp = decl1(al,0);
								mainfunc = FALSE;
#ifdef CPLUSPLUS
								sp->value.classdata.cppflags |= xcppflags;
#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... */
										if (!isstructured(head) &&
												head->type != bt_memberptr)
											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)
													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)
												sp->name = fullcppmangle(0,declid,head);
#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
										sp->parentclass = declclass;
                    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->isstdcall = isstdcall;
										sp->init = 0;
										sp->indecltable = 0;
										sp->funcparm = 0;
										sp->inreg = 0;
										sp->staticlabel = FALSE;
										if ((sp->tp->type == bt_func || sp->tp->type == bt_ifunc) && flags & DF_FAR) {
											sp->farproc = TRUE;
										}
										if (al != sc_type && (sp->tp->type == bt_func || sp->tp->type == bt_ifunc)) {
											setalias(sp);
										}
										if (al == sc_external && lastst == assign)
											sp->storage_class = sc_global;
										if (sp->intflag && (ispascal || isstdcall))
											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 (!prm_packing && (!noadj || !curbit)) {
															val = (ilc + nbytes) %align;
															if (val)  val = align - val;
															nbytes += val;
														}
														if (ztype == bt_union)
															sp->value.i = ilc;
														else
															sp->value.i = nbytes + ilc;
														if (!noadj)  {
															int size;
															if (curbit < 100)
																size = (curbit -1)/8 + 1;
															else
																size = sp->tp->size;
	                        		if(ztype == bt_union)
  	                            nbytes = imax(nbytes,size);
    	                    		else if(al != sc_external)
      	                        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))
													&& (sp->tp->cflags & (PF_VIRTUAL | PF_STATIC | PF_FRIEND)))
												generror(ERR_NODESTRUCTQUAL,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(sp->name, &typequal->value.classdata.memberptrs,FALSE);
											else
#endif
  											sp1 = basesearch(sp->name,table,FALSE);
											if (sp->name[0] == '@' && !sp1) {
												if (typequal) {
													genclasserror(ERR_NOCLASSMEMBERFUNC,sp->name);
												}
												funcrefinsert(declid,sp,table,declclass);
											}
                     	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
                         		insert(sp,table);
#ifndef ICODE
													if (sp->tp->cflags & DF_INTRINS)
														SearchIntrins(sp);
#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;
													}
												}
											}
											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)
													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;
														 }
#endif
                             funcbody(sp1);
#ifdef CPLUSPLUS
														 if (pushed)
															 declclass = dc;
#endif
														 lastdecl = sp1;
                             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)
														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)
															generror(ERR_OLDFUNCSTYLE,0,skm_declcomma);
														else 
															doinit(sp1);
													else 
#endif
														doinit(sp1);
#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)
															gensymerror(ERR_REFMUSTINIT,lastid);
#endif
												 	doautoinit(sp);
#ifdef CPLUSPLUS
													if (pushed)
													 declclass =  dc;
#endif
												}
										}
										else if (al != sc_type) {
											gensymerror(ERR_SIZE,declid);
											expskim(skm_declclosepa);
										}
										else {
											if (sp->tp->size) {
												sp->tp = copytype(sp->tp,0);
												sp->tp->sp = sp;
											}
                      insert(sp,table);
										}
                }
								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;
                  return(nbytes);
								}
                if(declbegin(lastst) == 0)
                        break;
                head = dhead;
								head->uflags = ufsave;
        }
        getsym();
				if (sp1)
					lastdecl = sp1;
				else
					lastdecl = sp;
        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 xglob = global_flag;
        if( lastst == id) {
/* tagged */
								global_flag++;
#ifdef CPLUSPLUS
								if (prm_cplusplus) {
									sp = search(nm = litlate(lastid),table);
									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 = 2;
                        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);
                }
                if( lastst == begin) {
                  getsym();
                 	enumbody(table);
                }
								global_flag--;
                head = sp->tp;
                }
        else    {
/* untagged */
                tp = xalloc(sizeof(TYP));
                tp->type = bt_enum;
                tp->lst.head = tp->btp = 0;
								tp->size = 2;
								tp->bits = tp->startbit = -1;
								tp->sp = 0;
                if( lastst != begin)
                        generror(ERR_PUNCT,begin,skm_declend);
                else    {
												global_flag++ ;
                        getsym();
                        enumbody(table);
												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);
}
void enumbody(TABLE *table)
/*
 * read the enumeration constants in
 */
{       long     evalue;
        SYM     *sp;
        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;
								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 (sp->value.i < SHRT_MIN || sp->value.i >SHRT_MAX)
											generror(ERR_CONSTTOOLARGE,0,0);
								}
                if( lastst == comma)
                        getsym();
                else if(lastst != end)
                        break;
                }
        needpunc(end,skm_declend);
}
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;
        if(lastst == id) {
								global_flag++;
/* tagged */
#ifdef CPLUSPLUS
								if (prm_cplusplus) {
									sp = search(nm = litlate(lastid),table);
									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 && lastst == colon)) {
																if (lastst == begin)
                                	getsym();
                                structbody(sp,ztype);
												}
											}
                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 && lastst == colon) {
													if (lastst == begin)
														getsym();
													if (sp->tp->size == 0) 
														structbody(sp,ztype);
													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 flags=0;
				TYP *btp;
				SYM *dc;
				int pushed = FALSE;
        int decltype;

#ifdef CPLUSPLUS
				if (prm_cplusplus)
					global_flag++;
				sp->parentclass = declclass;
				if (ztype == bt_class) {
				  dc = declclass;
					declclass = sp;
					flags |= PF_PRIVATE;
					sp->value.classdata.basemode = BM_PRIVATE;
					pushed = TRUE;
				}
				else if (prm_cplusplus && (ztype == bt_struct || ztype == bt_union || ztype == bt_class)) {
				  dc = declclass;
					declclass = sp;
					if (ztype == bt_struct)
						ztype = bt_class;
					flags |= PF_PUBLIC;
					sp->value.classdata.basemode = BM_PUBLIC;
					pushed = TRUE;
				}
        if (sp->name) {
          SYM *sp1 = xalloc(sizeof(SYM));
          sp->value.classdata.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 (lastst == colon) {
					getsym();
					switch (lastst) {
						case kw_private:
							sp->value.classdata.basemode = BM_PRIVATE;
							getsym();
							break;
						case kw_protected:
							sp->value.classdata.basemode = BM_PROTECTED;
							getsym();
							break;
						case kw_public:
							sp->value.classdata.basemode = BM_PUBLIC;
							getsym();
							break;
					}
					if (lastst != id) {
						generror(ERR_IDEXPECT,0,0);
					}
					else {
						SYM *spx = gsearch(lastid);
						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();
							sp->value.classdata.baseclass = spx;
						}
						if (lastst != begin)
							generror(ERR_PUNCT,begin,0);
						else
							getsym();
					}
				}
				if (ztype == bt_class)
					loadclassdata(sp);	
#endif
				slc = sp->tp->size;
        while( lastst != end && lastst != eof) {
#ifdef CPLUSPLUS
								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;
                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 ((btp = sp->tp->lst.tail->tp)->type == bt_ref)
									genclasserror(ERR_REFNOCONS,sp->tp->lst.tail->name);
								sp->tp->lst.tail->tp->uflags |= UF_DEFINED;
								if (currentfunc && (btp->type == bt_ifunc || btp->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 (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;
				}
				/* had to change because of inheritance */
				sp->tp->size += slc;
#ifdef CPLUSPLUS
				if (pushed) {
					classerrs(sp);
					gen_vtab(sp);
					declclass = dc;
				}
				if (prm_cplusplus)
					global_flag--;
#endif
        getsym();
}
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();
				dump_muldivval();
#endif
				dumplits();
				initrundown();
				dumpstartups();
				check_used();
				putexterns();
}

void dodecl(int defclass)
/*
 * Declarations come here, ALWAYS
 */
{
				SYM *sp;
				int flags = 0;
				long val;
				char *nm;
				cbautoinithead = 0;
        for(;;) {
						ispascal = FALSE;
						isstdcall = FALSE;
						iscdecl = 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) {
											if (global_flag) {
												getsym();
												if (lastst != id)
													generror(ERR_NAMESPACEEXP,0,0);
												else {
													switchtonamespace(lastid);
													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_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:
                    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 thismangle = FALSE;
                        getsym();
#ifdef CPLUSPLUS
												if (prm_cplusplus && lastst == sconst) {
													if (!strcmp(laststr,Cstr)) {
														mangleflag = FALSE;
														manglelevel++;
														getsym();
														if (lastst == begin) {
															getsym();
														  thismangle = FALSE;
														}
														else thismangle = TRUE;
													}
												}
#endif
                        if( defclass == sc_member) {
                            gensymerror(ERR_ILLCLASS,lastid);
														break;
												}
                        ++global_flag;
                        declare(gsyms,sc_external,bt_struct,flags,0);
                        --global_flag;
												if (thismangle && !--manglelevel)
													mangleflag = TRUE;
												}
                        break;
								case end:
#ifdef CPLUSPLUS
												if (prm_cplusplus && manglelevel) {
													mangleflag = (!--manglelevel);
													getsym();
													continue;
												}
#endif
												return;
								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;
        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 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:
                    declare(table,sc_auto,bt_struct,flags,0);
                    break;
                case kw_static:
								case kw_auto:
								case kw_register:
                        gensymerror(ERR_ILLCLASS,lastid);
                        getsym();
												continue;
                default:
												goto exit;
                }
							if (isinline) {
								names[(*nparms)++] = litlate(declid);
							}
						
				flags &= ~DF_CONST;
				}
exit:
		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
		}
}
