/*  $VER: vbcc (declaration.c) V0.4     */

#include "vbc.h"

static char FILE_[]=__FILE__;

#define PARAMETER 8
#define OLDSTYLE 16

struct const_list *initialization(struct Typ *,int,int);
int test_assignment(struct Typ *,np);
int return_sc,return_reg,has_return;

extern int float_used;
extern void optimize(long,struct Var *);

int settyp(int typnew, int typold)
/* Unterroutine fuer declaration_specifiers().              */
{
  static int warned_long_double;
  if(DEBUG&2) printf("settyp: new=%d old=%d\n",typnew,typold);
  if(typold==LONG&&typnew==FLOAT){ error(203); return(DOUBLE);}
  if(typold==LONG&&typnew==DOUBLE){
    if(!warned_long_double){error(204);warned_long_double=1;}
    return(DOUBLE);
  }
  if(typold!=0&&typnew!=INT){error(47);return(typnew);}
  if(typold==0&&typnew==INT) return(INT);
  if(typold==0) return(typnew);
  if(typold==SHORT||typold==LONG) return(typold);
  error(48);
  return(typnew);
}

#define dsc if(storage_class) error(49); if(typ||type_qualifiers) error(50)
#define XSIGNED 16384

struct Typ *declaration_specifiers(void)
/* Erzeugt neuen Typ und gibt Zeiger darauf zurueck,      */
/* parst z.B. unsigned int, struct bla etc.               */
{
  int typ=0,type_qualifiers=0,notdone,storage_class,hard_reg;
  char *merk,*imerk,sident[MAXI],sbuff[MAXI];
  struct Typ *new=mymalloc(TYPS),*t,*ts;
  struct struct_declaration *ssd;
  struct struct_list (*sl)[];
  size_t slsz;
  struct Var *v;
  storage_class=hard_reg=0;
  new->next=0; new->exact=0;
  do{
    killsp();merk=s;cpbez(buff,0);notdone=0;
    if(DEBUG&2) printf("ts: %s\n",buff);
    if(!strcmp("struct",buff)) notdone=STRUCT;
    if(!strcmp("union",buff)) notdone=UNION;
    if(notdone!=0){
      killsp();
      if(*s!='{'){
	cpbez(sident,1);
	killsp();
	ssd=find_struct(sident,0);
	if(ssd&&*s=='{'&&find_struct(sident,nesting)&&ssd->count>0) error(13,sident);
	if(!ssd||((*s=='{'||*s==';')&&!find_struct(sident,nesting))){
	  typ=settyp(notdone,typ);
	  ssd=mymalloc(sizeof(*ssd));
	  ssd->count=0;
	  new->exact=ssd=add_sd(ssd);
	  add_struct_identifier(sident,ssd);
	}else{
	  new->exact=ssd;
	  typ=settyp(new->flags=notdone,typ);
	}
      }else{
	*sident=0;
	typ=settyp(notdone,typ);
	ssd=mymalloc(sizeof(*ssd));
	ssd->count=0;
	new->exact=ssd=add_sd(ssd);
      }
      if(*s=='{'){
	s++;
	killsp();
	slsz=SLSIZE;
	sl=mymalloc(slsz*sizeof(struct struct_list));
	ssd->count=0;
	imerk=ident;
	ts=declaration_specifiers();
	while(*s!='}'&&ts){
	  ident=sbuff;
	  t=declarator(clone_typ(ts));
	  killsp();
	  if(*s==':'){
	    /*  bitfields werden hier noch ignoriert    */
	    np tree;
	    if((ts->flags&NQ)!=INT) error(51);
	    s++;killsp();tree=assignment_expression();
	    if(type_expression(tree)){
	      if(tree->flags!=CEXPR) error(52);
	      if((tree->ntyp->flags&NQ)<CHAR||(tree->ntyp->flags&NQ)>LONG) error(52);
	    }
	    if(tree) free_expression(tree);
	  }else{
	    if(*ident==0) error(53);
	  }
	  if(type_uncomplete(t)){
	    error(14,sbuff);
	    freetyp(t);
	    break;
	  }
	  if((t->flags&NQ)==FUNKT)
	    error(15,sbuff);
	  
	  if(*ident!=0){
	    int i=ssd->count;
	    while(--i>=0)
	      if(!strcmp((*sl)[i].identifier,ident))
		error(16,ident);
	  }
	  (*sl)[ssd->count].styp=t;
	  (*sl)[ssd->count].identifier=add_identifier(ident,strlen(ident));
	  ssd->count++;
	  if(ssd->count>=slsz-1){
	    slsz+=SLSIZE;
	    sl=realloc(sl,slsz*sizeof(struct struct_list));
	    if(!sl){error(12);raus();}
	  }
	  killsp();
	  if(*s==',') {s++;killsp();continue;}
	  if(*s!=';') error(54); else s++;
	  killsp();
	  if(*s!='}'){
	    if(ts) freetyp(ts);
	    ts=declaration_specifiers();killsp();
	  }
	}
	if(ts) freetyp(ts);
	if(ssd->count==0) error(55);
	ident=imerk;
	add_sl(ssd,sl);
	free(sl);
	if(*s!='}') error(56); else s++;
	new->flags=notdone|type_qualifiers;
      }
      notdone=1;
    }
    if(!strcmp("enum",buff)){
      /*  enumerations; die Namen werden leider noch ignoriert    */
      killsp();notdone=1;
      if(*s!='{'){cpbez(buff,1);killsp();}
      if(*s=='{'){
	zlong val; struct Var *v; struct Typ *t;
	val=l2zl(0L);
	s++;killsp();
	while(*s!='}'){
	  cpbez(sident,1);killsp();
	  if(*sident==0) {error(56);break;}
	  t=mymalloc(TYPS);
	  t->flags=CONST|INT;
	  t->next=0;
	  if(find_var(sident,nesting)) error(17,sident);
	  v=add_var(sident,t,AUTO,0); /*  AUTO hier klug? */
	  if(*s=='='){
	    s++;killsp();
	    v->clist=initialization(v->vtyp,0,0);
	    val=zi2zl(v->clist->val.vint);killsp();
	  }else{
	    v->clist=mymalloc(CLS);
	    v->clist->val.vint=val;
	    v->clist->next=v->clist->other=0;
	    v->clist->tree=0;
	  }
	  vlong=l2zl(1L);val=zladd(val,vlong);
	  v->vtyp->flags=CONST|ENUM;
	  if(*s!='}'&&*s!=',') {error(56);break;}
	  if(*s==',') s++;
	  killsp();
	  if(*s=='}') {s++; break;}
	}
      }
      killsp();
      typ=settyp(INT,typ);*buff=0;
    }
    if(!strcmp("void",buff)) {typ=settyp(VOID,typ);notdone=1;}
    if(!strcmp("char",buff)) {typ=settyp(CHAR,typ);notdone=1;}
    if(!strcmp("short",buff)) {typ=settyp(SHORT,typ);notdone=1;}
    if(!strcmp("int",buff)) {typ=settyp(INT,typ);notdone=1;}
    if(!strcmp("long",buff)) {typ=settyp(LONG,typ);notdone=1;}
    if(!strcmp("float",buff)) {typ=settyp(FLOAT,typ);notdone=1;}
    if(!strcmp("double",buff)) {typ=settyp(DOUBLE,typ);notdone=1;}
    if(!strcmp("const",buff)){
      if(type_qualifiers&CONST) error(58);
      type_qualifiers|=CONST;notdone=1;
    }
    if(!strcmp("volatile",buff)){
      if(type_qualifiers&VOLATILE) error(58);
      type_qualifiers|=VOLATILE;notdone=1;
    }
    if(!strcmp("unsigned",buff)){
      if(type_qualifiers&(XSIGNED|UNSIGNED)) error(58);
      notdone=1;type_qualifiers|=UNSIGNED;
    }
    if(!strcmp("signed",buff)){
      if(type_qualifiers&(XSIGNED|UNSIGNED)) error(58);
      notdone=1;type_qualifiers|=XSIGNED;
    }
    if(!strcmp("auto",buff)) {dsc;storage_class=AUTO;notdone=1;}
    if(!strcmp("register",buff)){dsc;storage_class=REGISTER;notdone=1;}
    if(!strcmp("static",buff)) {dsc;storage_class=STATIC;notdone=1;}
    if(!strcmp("extern",buff)) {dsc;storage_class=EXTERN;notdone=1;}
    if(!strcmp("typedef",buff)) {dsc;storage_class=TYPEDEF;notdone=1;}
    if(!(c_flags[7]&USEDFLAG)&&!strcmp("__reg",buff)){
      char *d;int f=0;
      killsp(); if(*s=='(') s++; else error(151);
      killsp(); if(*s=='\"') s++; else error(74);
      d=buff;
      while(*s&&*s!='\"'){
	if(d-buff-2>MAXI){
	  if(!f){ error(206,MAXI);f=1;}
	}else *d++=*s;
	s++;
      }
      *d=0;
      if(*s=='\"') s++; else error(74);
      killsp(); if(*s==')') s++; else error(59);
      for(hard_reg=1;hard_reg<=MAXR;hard_reg++){
	if(!strcmp(buff,regnames[hard_reg])) break;
      }
      if(hard_reg>MAXR){ hard_reg=0;error(220,buff);}
      notdone=1;
    }
    
    if(!notdone&&*buff&&typ==0&&!(type_qualifiers&(XSIGNED|UNSIGNED))){
      v=find_var(buff,0);
      if(v&&v->storage_class==TYPEDEF){
	free(new);
	new=clone_typ(v->vtyp);
	typ=settyp(new->flags,typ);
	notdone=1;
      }
    }
    if(DEBUG&2) printf("typ:%d\n",typ);
  }while(notdone);
  s=merk;killsp();
  return_sc=storage_class;
  return_reg=hard_reg;
  if(typ==0){
    if(storage_class==0&&type_qualifiers==0) {free(new);return(0);}
    typ=INT;
  }
  if(type_qualifiers&(XSIGNED|UNSIGNED))
    if(typ!=INT&&typ!=CHAR&&typ!=LONG&&typ!=SHORT)
      error(58);
  if(DEBUG&2) printf("ts finish:%s\n",s);
  new->flags=typ|type_qualifiers;
  return(new);
}

struct Typ *declarator(struct Typ *a)
/* Erzeugt einen neuen Typ, auf Basis des Typs a.           */
/* a wird hiermit verkettet.                                */
{
  struct Typ *t;
  killsp();*ident=0;
  t=direct_declarator(pointer(a));
  if(!a) {if(t) freetyp(t);return(0);} else return(t);
}
struct Typ *pointer(struct Typ *a)
/* Unterroutine fuer declaration(), behandelt Zeiger auf Typ.   */
{
  struct Typ *t;char *merk;int notdone;
  if(!a) return(0);
  killsp();
  while(*s=='*'){
    s++;
    t=mymalloc(TYPS);
    t->flags=POINTER;
    t->next=a;
    a=t;
    do{
      killsp();
      merk=s;cpbez(buff,0);
      notdone=0;
      if(!strcmp("const",buff)) {a->flags|=CONST;notdone=1;}
      if(!strcmp("volatile",buff)) {a->flags|=VOLATILE;notdone=1;}
    }while(notdone);
    s=merk;
  }
  return(a);
}

struct Typ *direct_declarator(struct Typ *a)
/*  Unterroutine zu declarator()                    */
/*  behandelt [],(funkt),(dekl).                     */
{
  struct Typ *rek=0,*merk,*p,*t,*first,*last=0;
  struct struct_declaration *fsd;
  struct struct_list (*sl)[];
  size_t slsz;
  char *imerk,fbuff[MAXI];
  killsp();
  if(!isalpha((unsigned char)*s)&&*s!='_'&&*s!='('&&*s!='[') return(a);
  if(isalpha((unsigned char)*s)||*s=='_'){
    cpbez(ident,1);
    if(!a) return(0);
  }else if(*s=='('&&a){
    /* Rekursion */
    imerk=s; s++; killsp();
    if(*s!=')'&&*ident==0&&!declaration(0)){
      merk=a;
      rek=declarator(a);
      if(*s!=')') error(59); else s++;
    }else s=imerk;
  }
  if(!a)return(0);
  killsp();
  while(*s=='['||*s=='('){
    if(*s=='['){
      s++;
      killsp();
      p=mymalloc(TYPS);
      p->flags=ARRAY;
      p->next=0;
      if(*s==']'){
	p->size=l2zl(0L);
      }else{
	np tree;
	tree=expression();
	if(!type_expression(tree)){
	  /*                    error("incorrect constant expression");*/
	}else{
	  if(tree->sidefx) error(60);
	  if(tree->flags!=CEXPR||(tree->ntyp->flags&NQ)<CHAR||(tree->ntyp->flags&NQ)>LONG){
	    error(19);
	  }else{
	    eval_constn(tree);
	    p->size=vlong;
	    if(zleqto(p->size,l2zl(0L))) {error(61);p->size=l2zl(1L);}
	  }
	}
	free_expression(tree);
      }
      if(*s!=']') error(62); else s++;
      if(last){
	last->next=p;
	last=p;
      }else{
	first=last=p;
      }
    }
    if(*s=='('){
      int komma,oldstyle=0;
#ifdef HAVE_REGPARMS
      struct reg_handle reg_handle=empty_reg_handle;
      struct Typ rpointer={POINTER};
      if(!freturn(a)){
	rpointer.next=a;
	if(!reg_parm(&reg_handle,&rpointer)) ierror(0);
      }
#endif
      s++;
      killsp();
      fsd=mymalloc(sizeof(*fsd));
      slsz=SLSIZE;
      sl=mymalloc(sizeof(struct struct_list)*slsz);
      fsd->count=0;
      imerk=ident;komma=0;
      enter_block();
      while(*s!=')'&&*s!='.'){
	int hard_reg;
	ident=fbuff;*fbuff=0;komma=0;
	t=declaration_specifiers();
	hard_reg=return_reg;
	t=declarator(t);
	if(!t){
	  oldstyle=1;
	  if(*ident==0) {error(20);break;}
	}
	if(fsd->count){
	  if((t&&!(*sl)[fsd->count-1].styp)||
	     (!t&&(*sl)[fsd->count-1].styp))
	    error(63);
	}
	if(!return_sc) return_sc=AUTO;
	if(return_sc!=AUTO&&return_sc!=REGISTER)
	  {error(21);return_sc=AUTO;}
	(*sl)[fsd->count].styp=t;
	(*sl)[fsd->count].storage_class=return_sc;
	if(hard_reg&&!regok(hard_reg,t->flags,0)) error(217,regnames[hard_reg]);
	(*sl)[fsd->count].identifier=add_identifier(ident,strlen(ident));
	if(t){
	  if(((*sl)[fsd->count].styp->flags&NQ)==VOID&&fsd->count!=0)
	    error(22);
	  /*  Arrays in Zeiger umwandeln  */
	  if(((*sl)[fsd->count].styp->flags&NQ)==ARRAY)
	    (*sl)[fsd->count].styp->flags=POINTER;
	  /*  Funktionen in Zeiger auf Funktionen umwandeln   */
	  if(((*sl)[fsd->count].styp->flags&NQ)==FUNKT){
	    struct Typ *new;
	    new=mymalloc(TYPS);
	    new->flags=POINTER;
	    new->next=(*sl)[fsd->count].styp;
	    (*sl)[fsd->count].styp=new;
	  }	  
	}
#ifdef HAVE_REGPARMS
	if(t) (*sl)[fsd->count].reg=reg_parm(&reg_handle,t);
	if(hard_reg) (*sl)[fsd->count].reg=hard_reg;
#else
	(*sl)[fsd->count].reg=hard_reg;
#endif
	fsd->count++;
	if(fsd->count>=slsz-2){     /*  eins Reserve fuer VOID  */
	  slsz+=SLSIZE;
	  sl=realloc(sl,slsz*sizeof(struct struct_list));
	  if(!sl){error(12);raus();}
	}
	killsp(); /* Hier Syntaxpruefung strenger machen */
	if(*s==',') {s++;komma=1; killsp();}
      }
      ident=imerk;
      if((*s!='.'||*(s+1)!='.'||*(s+2)!='.')||!komma){
	if(fsd->count>0&&(!(*sl)[fsd->count-1].styp||((*sl)[fsd->count-1].styp->flags&NQ)!=VOID)){
	  (*sl)[fsd->count].styp=mymalloc(TYPS);
	  (*sl)[fsd->count].styp->flags=VOID;
	  (*sl)[fsd->count].styp->next=0;
	  (*sl)[fsd->count].identifier=empty;
	  fsd->count++;
	}
      }else if(komma){
	s+=3;komma=0;
	if(oldstyle) error(221);
      }
      p=mymalloc(TYPS);
      p->flags=FUNKT;
      p->next=0;
      {
	int m=nesting;
	nesting=0;
	p->exact=add_sd(fsd);
	add_sl(fsd,sl);
	free(sl);
	nesting=m;
      }
      killsp();
      if(komma) error(59);
      if(*s!=')') error(59); else s++;
      killsp();
      if(*s==','||*s==';'||*s==')'||*s=='=') leave_block();
      if(last){
	last->next=p;
	last=p;
      }else{
	first=last=p;
      }
    }
    killsp();
  }
  if(last){last->next=a;last=a;a=first;}
  if(rek!=0&&rek!=merk){
    /* Zweite Liste anhaengen */
    p=rek;
    while(p->next!=merk) p=p->next;
    if(p) p->next=a; else ierror(0);
    return(rek);
  }
  return(a);
}
int declaration(int offset)
/*  Testet, ob eine Typangabe kommt. Wenn offset!=0 ist,    */
/*  muss s auf '(' zeigen und es wird getestet, ob nach der */
/*  Klammer eine Typangabe kommt.                           */
/*  In jedem Fall zeigt s danach wieder auf dieselbe Stelle */
/*  im Source.                                              */
{
  char *merk=s,buff[MAXI];
  struct Var *v;
  if(offset){
    s++;
    read_new_line=0;
    if(DEBUG&1) printf("cleared read_new_line\n");
    killsp();
    if(read_new_line){  /*  es kam eine neue Zeile  */
      memmove(s+1,s,MAXINPUT);
      *s='(';
      if(DEBUG&1) printf("look-ahead: %s|\n",s);
      merk=s;
      s++;
      cpbez(buff,0);
    }else{
      if(DEBUG&1) printf("read_new_line unchanged\n");
      cpbez(buff,0);
    }
  }else{
    cpbez(buff,0);
  }
  s=merk;
  if(!strcmp("auto",buff)) return(1);
  if(!strcmp("char",buff)) return(1);
  if(!strcmp("const",buff)) return(1);
  if(!strcmp("double",buff)) return(1);
  if(!strcmp("enum",buff)) return(1);
  if(!strcmp("extern",buff)) return(1);
  if(!strcmp("float",buff)) return(1);
  if(!strcmp("int",buff)) return(1);
  if(!strcmp("long",buff)) return(1);
  if(!strcmp("register",buff)) return(1);
  if(!strcmp("short",buff)) return(1);
  if(!strcmp("signed",buff)) return(1);
  if(!strcmp("static",buff)) return(1);
  if(!strcmp("struct",buff)) return(1);
  if(!strcmp("typedef",buff)) return(1);
  if(!strcmp("union",buff)) return(1);
  if(!strcmp("unsigned",buff)) return(1);
  if(!strcmp("void",buff)) return(1);
  if(!strcmp("volatile",buff)) return(1);
  if(!(c_flags[7]&USEDFLAG)&&!strcmp("__reg",buff)) return(1);
  v=find_var(buff,0);
  if(v&&v->storage_class==TYPEDEF) return(1);
  return(0);
}
void add_sl(struct struct_declaration *sd,struct struct_list (*sl)[])
/*  Fuegt ein struct_list-Array in eine struct_declaration ein.     */
/*  Das Array muss mind. sd->count Elements haben und wird kopiert. */
{
  size_t sz=sizeof(struct struct_list)*sd->count;
  sd->sl=mymalloc(sz);
  memcpy(sd->sl,sl,sz);
}
struct struct_declaration *add_sd(struct struct_declaration *new)
/*  Fuegt eine struct Declaration in Liste ein.     */
{
  new->next=0;
  if(first_sd[nesting]==0){
    first_sd[nesting]=last_sd[nesting]=new;
  }else{
    last_sd[nesting]->next=new;
    last_sd[nesting]=new;
  }
  return(new);
}
void free_sd(struct struct_declaration *p)
/*  Gibt eine struct_declaration-List inkl. struct_lists und    */
/*  allen Typen jeder struct_list frei, nicht aber identifier.  */
{
  int i;struct struct_declaration *merk;
  while(p){
    merk=p->next;
    for(i=0;i<p->count;i++) if((*p->sl)[i].styp) freetyp((*p->sl)[i].styp);
    if(p->count>0) free(p->sl);
    free(p);
    p=merk;
  }
}
char *add_identifier(char *identifier,int length)
/*  Kopiert identifier an sicheren Ort, der spaeter zentral     */
/*  freigegeben werden kann.                                    */
/*  Sollte noch einbauen, dass ueberprueft wird, ob schon       */
/*  vorhanden und dann nicht zweimal speichern.                 */
{
  struct identifier_list *new;
  if((*identifier==0&&length==0)||identifier==empty) return(empty);
  new=mymalloc(sizeof(struct identifier_list));
  new->identifier=mymalloc(length+1);
  memcpy(new->identifier,identifier,length+1);
  new->next=0;new->length=length;
  if(last_ilist[nesting]){
    last_ilist[nesting]->next=new;
    last_ilist[nesting]=new;
  }else{
    last_ilist[nesting]=first_ilist[nesting]=new;
  }
  return(new->identifier);
}
void free_ilist(struct identifier_list *p)
/*  Gibt eine verkettete identifier_liste und saemtliche darin  */
/*  gespeicherten Identifier frei.                              */
{
  struct identifier_list *merk;
  while(p){
    merk=p->next;
    if(p->identifier) free(p->identifier);
    free(p);
    p=merk;
  }
}
int type_uncomplete(struct Typ *p)
/*  Testet, ob Typ unvollstaendig ist. Momentan gelten nur      */
/*  unvollstaendige Strukturen und Arrays von solchen als       */
/*  unvollstaendig, aber keine Zeiger oder Funktionen darauf.   */
{
  struct struct_declaration *sd;
  if(!p){ierror(0);return(0);}
  if((p->flags&NQ)==STRUCT||(p->flags&NQ)==UNION)
    if(p->exact->count<=0) return(1);
  if((p->flags&NQ)==ARRAY){
    if(zlleq(p->size,l2zl(0L))) return(1);
    if(type_uncomplete(p->next)) return(1);
  }
  return(0);
}
void add_struct_identifier(char *identifier,struct struct_declaration *sd)
/*  Erzeugt neuen struct_identifier, fuegt ihn in Liste an und  */
/*  vervollstaendigt unvollstaendige Typen dieser Struktur.     */
{
  struct struct_identifier *new;
/*    struct Typ *t;*/
  if(DEBUG&1) printf("add_si %s (nesting=%d)->%p\n",identifier,nesting,(void *)sd);
  new=mymalloc(sizeof(struct struct_identifier));
  new->identifier=add_identifier(identifier,strlen(identifier));
  new->sd=sd; new->next=0;
  if(first_si[nesting]==0){
    first_si[nesting]=new;last_si[nesting]=new;
  }else{
    last_si[nesting]->next=new;last_si[nesting]=new;
  }
}
void free_si(struct struct_identifier *p)
/*  Gibt eine struct_identifier-Liste frei, aber nicht die      */
/*  identifiers und struct_declarations.                        */
{
  struct struct_identifier *merk;
  while(p){
    merk=p->next;
    free(p);
    p=merk;
  }
}
struct struct_declaration *find_struct(char *identifier,int endnesting)
/*  Sucht angegebene Strukturdefinition und liefert             */
/*  entsprechende struct_declaration.                           */
{
  struct struct_identifier *si; int i;
  for(i=nesting;i>=endnesting;i--){
    si=first_si[i];
    while(si){
      if(!strcmp(si->identifier,identifier)){
	if(DEBUG&1) printf("found struct tag <%s> at nesting %d->%p\n",identifier,i,(void *)si->sd);
	return(si->sd);
      }
      si=si->next;
    }
  }
  if(DEBUG&1) printf("didn't find struct tag <%s>\n",identifier);
  return(0);
}
struct Var *add_tmp_var(struct Typ *t)
{
  return add_var(empty,t,AUTO,0);
}
struct Var *add_var(char *identifier, struct Typ *t, int storage_class,struct const_list *clist)
/*  Fuegt eine Variable mit Typ in die var_list ein.            */
/*  In der storage_class werden die Flags PARAMETER und evtl.   */
/*  OLDSTYLE und REGPARM erkannt.                               */
{
  struct Var *new;int f;
  struct struct_declaration *sd;
  static zlong paroffset;
  zlong al;
  /*if(*identifier==0) return;*/ /* sollte woanders bemaekelt werden */
  if(DEBUG&2) printf("add_var(): %s\n",identifier);
  if((t->flags&NQ)==FUNKT&&((t->next->flags&NQ)==ARRAY||(t->next->flags&NQ)==FUNKT))
    error(25);
  new=mymalloc(sizeof(struct Var));
  new->identifier=add_identifier(identifier,strlen(identifier));
  new->clist=clist;
  new->vtyp=t;
  new->storage_class=storage_class&7;
  new->reg=0;
  new->next=0;
  new->flags=0;
  new->fi=0;
  new->nesting=nesting;
  /*    if((storage_class&7)==STATIC||(storage_class&7)==EXTERN) new->flags=USEDASSOURCE|USEDASDEST;*/
  if(DEBUG&2) printf("storage_class=%d\n",storage_class);
  if(storage_class&PARAMETER) new->flags|=USEDASDEST;
  if(storage_class&REGPARM) {new->flags|=REGPARM;storage_class&=~PARAMETER;}
  if(DEBUG&2) printf("storage_class=%d\n",storage_class);
  if(DEBUG&2) printf("max_offset=%ld\n",max_offset);
  if((storage_class&7)==REGISTER) new->priority=registerpri; else new->priority=0;
  if(last_var[nesting]){
    new->offset=zladd(last_var[nesting]->offset,szof(last_var[nesting]->vtyp));
    last_var[nesting]->next=new;
    last_var[nesting]=new;
  }else{
    new->offset=l2zl(0L);
    paroffset=l2zl(0L);;
    first_var[nesting]=last_var[nesting]=new;
  }
  f=t->flags&NQ;
  if((storage_class&7)==AUTO||(storage_class&7)==REGISTER){
    if(DEBUG&2) printf("auto\n");
    if(type_uncomplete(t)&&(t->flags&NQ)!=ARRAY) error(202,identifier);
    /*  das noch ueberpruefen   */
    if((c_flags_val[0].l&2)&&nesting==1&&!(storage_class&PARAMETER)){
      new->offset=max_offset;
    }else{
      if(storage_class&PARAMETER){
	new->offset=paroffset;
      }else{
	new->offset=local_offset[nesting];
      }
    }
    al=falign(t);
    new->offset=zlmult(zldiv(zladd(new->offset,zlsub(al,l2zl(1L))),al),al);
    if(storage_class&PARAMETER){
      new->offset=zlmult(zldiv(zladd(new->offset,zlsub(maxalign,l2zl(1L))),maxalign),maxalign);
      if(f>=CHAR&&f<=SHORT){
	/*  Integer-Erweiterungen fuer alle Funktionsparameter  */
	paroffset=zladd(new->offset,sizetab[INT]);
      }else{
	if(f==FLOAT&&(storage_class&OLDSTYLE)){
	  /*  Bei alten Funktionen werden FLOAT als DOUBLE uebergeben */
	  new->offset=zlmult(zldiv(zladd(new->offset,zlsub(align[DOUBLE],l2zl(1L))),align[DOUBLE]),align[DOUBLE]);
	  paroffset=zladd(new->offset,sizetab[DOUBLE]);
	}else{
	  paroffset=zladd(new->offset,szof(new->vtyp));
	}
      }
    }else{
      local_offset[nesting]=zladd(new->offset,szof(new->vtyp));
    }
    
    if(!(storage_class&PARAMETER))
      if(zlleq(max_offset,local_offset[nesting])) max_offset=local_offset[nesting];
    if(DEBUG&2) printf("max_offset=%ld\n",max_offset);
  }
  if((storage_class&7)==STATIC) new->offset=l2zl((long)++label);
  if(storage_class&PARAMETER){
    
    if(DEBUG&2) printf("parameter\n");
    
    if(f>=CHAR&&f<=SHORT&&!zlleq(sizetab[INT],sizetab[f])){
      if(BIGENDIAN){
	new->offset=zladd(new->offset,zlsub(sizetab[INT],sizetab[f]));
      }else{
	if(!LITTLEENDIAN)
	  ierror(0);
      }
    }
    if((storage_class&OLDSTYLE)&&f==FLOAT){
      /*  Bei alten Funktionen werden DOUBLE nach FLOAT konvertiert   */
      struct IC *conv=mymalloc(ICS);
      conv->code=CONVDOUBLE;
      conv->typf=FLOAT;
      conv->q1.flags=VAR|DONTREGISTERIZE;
      conv->z.flags=VAR;
      conv->q2.flags=0;
      conv->q1.v=conv->z.v=new;
      conv->q1.val.vlong=conv->z.val.vlong=l2zl(0);
      add_IC(conv);
      new->flags|=CONVPARAMETER;
    }
    new->offset=zlsub(l2zl(0L),zladd(maxalign,new->offset));
  }
  if((storage_class&7)==EXTERN){
    if(!strcmp("fprintf",identifier)) new->flags|=PRINTFLIKE;
    if(!strcmp("printf",identifier))  new->flags|=PRINTFLIKE;
    if(!strcmp("sprintf",identifier)) new->flags|=PRINTFLIKE;
    if(!strcmp("fscanf",identifier))  new->flags|=SCANFLIKE;
    if(!strcmp("scanf",identifier))   new->flags|=SCANFLIKE;
    if(!strcmp("sscanf",identifier))  new->flags|=SCANFLIKE;
  }
  return(new);
}
void free_var(struct Var *p)
/*  Gibt Variablenliste inkl. Typ, aber ohne Identifier frei.   */
{
  struct Var *merk;
  while(p){
    merk=p->next;
    if(!(p->flags&USEDASADR)&&(p->storage_class==AUTO||p->storage_class==REGISTER)){
      if(*p->identifier&&!(p->flags&USEDASDEST)&&(p->vtyp->flags&NQ)<=POINTER) error(64,p->identifier);
      if(*p->identifier&&!(p->flags&USEDASSOURCE)&&(p->vtyp->flags&NQ)<=POINTER) error(65,p->identifier);
    }
    if(DEBUG&2) printf("free_var %s, pri=%d\n",p->identifier,p->priority);
    if(p->vtyp) freetyp(p->vtyp);
    if(p->clist) free_clist(p->clist);
    if(p->fi){
      if(DEBUG&2) printf("free_fi of function %s\n",p->identifier);
      free_fi(p->fi);
      if(DEBUG&2) printf("end free_fi of function %s\n",p->identifier);
    }
    free(p);
    p=merk;
  }
}
struct Var *find_var(char *identifier,int endnesting)
/*  Sucht Variable mit Bezeichner und liefert Zeiger zurueck    */
/*  es werden nur Variablen der Bloecke endnesting-nesting      */
/*  durchsucht.                                                 */
{
  int i;struct Var *v;
  if(*identifier==0||identifier==0) return(0);
  for(i=nesting;i>=endnesting;i--){
    v=first_var[i];
    while(v){
      if(!strcmp(v->identifier,identifier)) return(v);
      v=v->next;
    }
  }
  return(0);
}
void var_declaration(void)
/*  Bearbeitet eine Variablendeklaration und erzeugt alle       */
/*  noetigen Strukturen.                                        */
{
  struct Typ *ts,*t,*old=0,*om=0;char *imerk,vident[MAXI];
  int mdef=0,makeint=0,notdone,storage_class,msc,extern_flag,isfunc,
    had_decl,hard_reg,mhr;
  struct Var *v;
  ts=declaration_specifiers();notdone=1;
  storage_class=return_sc;hard_reg=return_reg;
  if(storage_class==EXTERN) extern_flag=1; else extern_flag=0;
  killsp();
  if(*s==';'){
    if(storage_class||((ts->flags&NQ)!=STRUCT&&(ts->flags&NQ)!=UNION&&(ts->flags&NQ)!=INT))
      error(36);
    freetyp(ts);s++;killsp();
    return;
  }
  if(nesting==0&&(storage_class==AUTO||storage_class==REGISTER))
    {error(66);storage_class=EXTERN;}
  if(!ts){
    if(nesting<=1){
      ts=mymalloc(TYPS);
      ts->flags=INT;ts->next=0;
      makeint=1;
      if(!storage_class) storage_class=EXTERN;
      error(67);
    }else{
      ierror(0);return;
    }
  }
  if(storage_class==0){
    if(nesting==0) storage_class=EXTERN; else storage_class=AUTO;
  }
  msc=storage_class;mhr=hard_reg;
  while(notdone){
    int oldnesting=nesting;
    imerk=ident;ident=vident;*vident=0;  /* merken von ident hier vermutlich */
    storage_class=msc;hard_reg=mhr;
    if(old) {freetyp(old);old=0;}
    t=declarator(clone_typ(ts));
    if((t->flags&NQ)!=FUNKT) isfunc=0;
    else {isfunc=1;if(storage_class!=STATIC) storage_class=EXTERN;}
    ident=imerk;                    /* nicht unbedingt noetig ?         */
    if(!*vident){
      free(ts);free(t);
      error(36);return;
    }
    v=find_var(vident,oldnesting);
    if(v){
      had_decl=1;
      if(storage_class==TYPEDEF){
	error(226,v->identifier);
      }else{
	if(nesting>0&&(v->flags&DEFINED)&&!extern_flag&&!isfunc){
	  error(27,vident);
	}else{
	  if(t&&v->vtyp&&!compare_pointers(v->vtyp,t,255)){
	    error(68,vident);
	  }
	  if((storage_class!=v->storage_class&&!extern_flag)||hard_reg!=v->reg)
	    error(28,v->identifier);
	  if(!isfunc&&!extern_flag) v->flags|=TENTATIVE;
	}
	if(!isfunc){
	  v->vtyp=t;
	}else{
	  om=v->vtyp;
	  if(t->exact->count>0) {old=v->vtyp;v->vtyp=t;}
	}
      }
    }else{
      had_decl=0;
      if(isfunc&&*s!=','&&*s!=';'&&*s!=')'&&*s!='='&&nesting>0) nesting--;
      v=add_var(vident,t,storage_class,0);
      v->reg=hard_reg;
      if(isfunc&&*s!=','&&*s!=';'&&*s!=')'&&*s!='='&&nesting>=0) nesting++;
      if(!v) ierror(0);
      else{
	if(!isfunc&&!extern_flag){
	  v->flags|=TENTATIVE;
	  if(nesting>0) v->flags|=DEFINED;
	}
      }
      om=0;
    }
    killsp();
    /*  Inline-Assembler-Code in Funktionsdeklarationen */
    if(*s=='='&&(v->vtyp->flags&NQ)==FUNKT&&!(c_flags[7]&USEDFLAG)){
      np tree;
      s++;killsp();
      tree=string_expression();
      if(!tree||tree->flags!=STRING) error(42);
      else{
	int l;struct const_list *cl;
	if(!v->fi) v->fi=new_fi();
	cl=tree->cl;l=0;
	while(cl){
	  l++;
	  cl=cl->next;
	}
	v->fi->inline_asm=mymalloc(l);
	cl=tree->cl;l=0;
	while(cl){
	  v->fi->inline_asm[l]=zl2l(zc2zl(cl->other->val.vchar));
	  l++;
	  cl=cl->next;
	}
      }
      if(tree) free_expression(tree);
      killsp();
    }       	
    /*  Initialisierung von Variablen bei Deklaration   */
    if(*s=='='){
      s++;killsp();
      if(!had_decl&&v->nesting==0&&v->storage_class==EXTERN&&strcmp("main",v->identifier))
	error(168,v->identifier);
      if(v->flags&DEFINED) {if(nesting==0) error(30,v->identifier);}
      else v->flags|=DEFINED;
      if(v->storage_class==TYPEDEF) error(114,v->identifier);
      if(extern_flag){
	if(nesting==0)
	  error(118,v->identifier);
	else
	  error(207,v->identifier);
	if(v->storage_class!=EXTERN){ error(77);v->storage_class=EXTERN;}
      }
      v->clist=initialization(v->vtyp,v->storage_class==AUTO||v->storage_class==REGISTER,0);
      if(v->clist){
	if((v->vtyp->flags&NQ)==ARRAY&&zleqto(v->vtyp->size,l2zl(0L))){
	  struct const_list *p=v->clist;
	  while(p){v->vtyp->size=zladd(v->vtyp->size,l2zl(1L));p=p->next;}
	  if(v->storage_class==AUTO||v->storage_class==REGISTER){
	    local_offset[nesting]=zladd(local_offset[nesting],szof(v->vtyp));
	    if(zlleq(max_offset,local_offset[nesting])) max_offset=local_offset[nesting];
	  }
	}
	if(v->storage_class==AUTO||v->storage_class==REGISTER){
	  struct IC *new;
	  /*  Initialisierung von auto-Variablen  */
	  new=mymalloc(ICS);
	  new->code=ASSIGN;
	  new->typf=v->vtyp->flags;
	  new->q2.flags=0;
	  new->q2.val.vlong=szof(v->vtyp);
	  new->z.flags=VAR;
	  new->z.v=v;
	  new->z.val.vlong=l2zl(0L);
	  if(v->clist->tree){
	    /*  einzelner Ausdruck  */
	    gen_IC(v->clist->tree,0,0);
	    convert(v->clist->tree,v->vtyp->flags&NU);
	    new->q1=v->clist->tree->o;
	    /*                        v->clist=0;*/
	  }else{
	    /*  Array etc.  */
	    struct Var *nv;
	    nv=add_var(empty,clone_typ(v->vtyp),STATIC,v->clist);
	    nv->flags|=DEFINED;
	    nv->vtyp->flags|=CONST;
	    /*                        v->clist=0;*/
	    new->q1.flags=VAR;
	    new->q1.v=nv;
	    new->q1.val.vlong=l2zl(0L);
	  }
	  add_IC(new);
	  /*                    if(v->clist&&v->clist->tree){free_expression(v->clist->tree);v->clist->tree=0;}*/
	}else if(c_flags[19]&USEDFLAG){
	  /*  Ohne Optimierung gleich erzeugen; das ist noch  */
	  /*  etwas von der genauen Implementierung der Liste */
	  /*  der Variablen abhaengig.                        */
	  struct Var *merk=v->next;
	  v->next=0;
	  gen_vars(v);
	  v->next=merk;
	  v->clist=0;
	}
      }
    }else{
      if((v->flags&DEFINED)&&type_uncomplete(v->vtyp)) error(202,v->identifier);
      if((v->vtyp->flags&CONST)&&(v->storage_class==AUTO||v->storage_class==REGISTER))
	error(119,v->identifier);
    }
    if(*s==',') {s++;killsp();mdef=1;} else notdone=0;
  }
  freetyp(ts);
  if(!mdef&&t&&(t->flags&NQ)==FUNKT&&*s!=';'){
    /*  Funktionsdefinition                                     */
    int i,oldstyle=0;
#ifdef HAVE_REGPARMS
    struct reg_handle reg_handle;
#endif
    fline=line;
    if(DEBUG&1) printf("Funktionsdefinition!\n");
    {int i;
    for(i=1;i<=MAXR;i++) {regs[i]=regused[i]=regsa[i];regsbuf[i]=0;}
    }
    cur_func=v->identifier;
    if(only_inline==2) only_inline=0;
    if(nesting<1) ierror(0);
    if(nesting>1) error(32);
    if(v->flags&DEFINED) error(33,v->identifier);
    else v->flags|=DEFINED;
    if(storage_class!=EXTERN&&storage_class!=STATIC) error(34);
    if(extern_flag) error(120);
    if(storage_class==EXTERN&&!strcmp(v->identifier,"main")&&(!t->next||t->next->flags!=INT)) error(121);
    if(!had_decl&&v->nesting==0&&v->storage_class==EXTERN&&strcmp("main",v->identifier))
      error(168,v->identifier);
    while(*s!='{'){
      /*  alter Stil  */
      struct Typ *nt=declaration_specifiers();notdone=1;oldstyle=OLDSTYLE;
      if(!ts) {error(35);}
      while(notdone){
	int found=0;
	imerk=ident;ident=vident;*vident=0;
	ts=declarator(clone_typ(nt));
	ident=imerk;
	if(!ts) {error(36);}
	else{
	  for(i=0;i<t->exact->count;i++){
	    if(!strcmp((*t->exact->sl)[i].identifier,vident)){
	      found=1;
	      if((*t->exact->sl)[i].styp){
		error(69,vident);
		freetyp((*t->exact->sl)[i].styp);
	      }
	      /*  typ[] in *typ   */
	      if((ts->flags&NQ)==ARRAY) ts->flags=POINTER;
	      /*  typ() in *typ() */
	      if((ts->flags&NQ)==FUNKT){
		struct Typ *new=mymalloc(TYPS);
		new->flags=POINTER;
		new->next=ts;
		ts=new;
	      }
	      if(!return_sc) return_sc=AUTO;
	      if(return_sc!=AUTO&&return_sc!=REGISTER)
		{error(122);return_sc=AUTO;}
	      (*t->exact->sl)[i].storage_class=return_sc;
	      (*t->exact->sl)[i].reg=return_reg;
	      if(return_reg) error(219);
	      (*t->exact->sl)[i].styp=ts;
	    }
	  }
	}
	if(!found) {error(37,vident);}
	killsp();
	if(*s==',') {s++;killsp();} else notdone=0;
      }
      if(nt) freetyp(nt);
      if(*s==';'){s++;killsp();
      }else{
	error(54);
	while(*s!='{'&&*s!=';'){s++;killsp();}
      }
    }
    if(t->exact->count==0){
      struct struct_list sl[1];
      if(DEBUG&1) printf("prototype converted to (void)\n");
      t->exact->count=1;
      sl[0].identifier=empty;
      sl[0].storage_class=AUTO;
      sl[0].styp=mymalloc(TYPS);
      sl[0].styp->flags=VOID;
      sl[0].styp->next=0;
      nesting--;
      add_sl(t->exact,&sl);
      nesting++;
    }
    if(om&&!compare_sd(om->exact,t->exact))
      error(123);
    nocode=0;currentpri=1;
    /*        enter_block();*/
    local_offset[1]=l2zl(0L);
    return_var=0;
    if(!v->vtyp) ierror(0);
#ifdef HAVE_REGPARMS
    reg_handle=empty_reg_handle;
#endif
    if(v->vtyp->next->flags==VOID) return_typ=0;
    else{
      return_typ=v->vtyp->next;
      if(!freturn(return_typ)){
	/*  Parameter fuer die Rueckgabe von Werten, die nicht in einem */
	/*  Register sind.                                              */
	struct Typ *rt=mymalloc(TYPS);int reg;
	rt->flags=POINTER;rt->next=return_typ;
#ifdef HAVE_REGPARMS
	reg=reg_parm(&reg_handle,rt);
	if(!reg) ierror(0);
	return_var=add_var(empty,clone_typ(rt),AUTO|PARAMETER|REGPARM|oldstyle,0);
	return_var->reg=reg;
#else
	return_var=add_var(empty,clone_typ(rt),AUTO|PARAMETER|oldstyle,0);
#endif
	return_var->flags|=DEFINED;
	free(rt);
      }
    }
    first_ic=last_ic=0;ic_count=0;max_offset=l2zl(0L);
    for(i=0;i<t->exact->count;i++){
      if(!(*t->exact->sl)[i].styp&&*(*t->exact->sl)[i].identifier){
	struct Typ *nt;
	nt=mymalloc(TYPS);
	nt->flags=INT; nt->next=0;
	(*t->exact->sl)[i].styp=nt;
	(*t->exact->sl)[i].storage_class=AUTO;
	(*t->exact->sl)[i].reg=0;
	error(124);
      }
      if(*(*t->exact->sl)[i].identifier){
	struct Var *tmp;int sc;
	sc=((*t->exact->sl)[i].storage_class|PARAMETER|oldstyle);
#ifdef HAVE_REGPARMS
	if(!t->exact->sl) ierror(0);
	if(!(*t->exact->sl)[i].styp) ierror(0);
	(*t->exact->sl)[i].reg=reg_parm(&reg_handle,(*t->exact->sl)[i].styp);
#endif
	if((*t->exact->sl)[i].reg) sc|=REGPARM;
	tmp=add_var((*t->exact->sl)[i].identifier,clone_typ((*t->exact->sl)[i].styp),sc,0);
	tmp->reg=(*t->exact->sl)[i].reg;
	tmp->flags|=DEFINED;
	if(oldstyle){
	  freetyp((*t->exact->sl)[i].styp);
	  (*t->exact->sl)[i].styp=0; /*  Prototype entfernen */
	}
      }
    }
    if(oldstyle) t->exact->count=0; /*  Prototype entfernen */
    /*        local_offset[1]=l2zl(0L);*/
    return_label=++label;
    v->flags|=GENERATED;
    function_calls=0;float_used=0;has_return=0;goto_used=0;
    compound_statement();
    if((v->vtyp->next->flags&NQ)!=VOID&&!has_return){
      if(strcmp(v->identifier,"main")) error(173,v->identifier);
      else error(174,v->identifier);
    }
#if 0
    {int i;
    for(i=1;i<=MAXR;i++) if(regs[i]!=regsa[i]) {printf("Register %s:\n",regnames[i]);ierror(0);}
    }
#endif
        gen_label(return_label);
        if(first_ic&&errors==0){
	  if((c_flags[2]&USEDFLAG)&&ic1){fprintf(ic1,"function %s\n",v->identifier); pric(ic1,first_ic);}
	  vl1=first_var[0];
	  vl2=first_var[1];
	  vl3=merk_varf;
	  optimize(c_flags_val[0].l,v);
	  if((c_flags[3]&USEDFLAG)&&ic2){fprintf(ic2,"function %s\n",v->identifier); pric(ic2,first_ic);}
	  if(out&&!only_inline&&!(c_flags[5]&USEDFLAG)){
	    gen_code(out,first_ic,v,max_offset);
	  }
	  /*            if(DEBUG&8192){fprintf(ic2,"function %s, after gen_code\n",v->identifier); pric(ic2,first_ic);}*/
	  free_IC(first_ic);
	  first_ic=last_ic=0;
        }
        if(v->fi&&v->fi->first_ic){
	  struct Var *vp;
	  if(DEBUG&1) printf("leave block %d (inline-version)\n",nesting);
	  if(nesting!=1) ierror(0);
	  if(merk_varl) merk_varl->next=first_var[nesting]; else merk_varf=first_var[nesting];
	  if(last_var[nesting]) merk_varl=last_var[nesting];
	  if(merk_sil) merk_sil->next=first_si[nesting]; else merk_sif=first_si[nesting];
	  if(last_si[nesting]) merk_sil=last_si[nesting];
	  if(merk_sdl) merk_sdl->next=first_sd[nesting]; else merk_sdf=first_sd[nesting];
	  if(last_sd[nesting]) merk_sdl=last_sd[nesting];
	  if(merk_ilistl) merk_ilistl->next=first_ilist[nesting]; else merk_ilistf=first_ilist[nesting];
	  if(last_ilist[nesting]) merk_ilistl=last_ilist[nesting];
	  
	  if(merk_varf&&!only_inline) gen_vars(merk_varf);
	  if(first_llist) free_llist(first_llist);
	  if(first_clist) free_clist(first_clist);
	  if(merk_sif) free_si(merk_sif);
/*  struct-declarations erst ganz am Schluss loeschen. Um zu vermeiden,     */
/*  dass struct-declarations in Prototypen frei werden und dann eine        */
/*  spaetere struct, dieselbe Adresse bekommt und dadurch gleich wird.      */
/*  Nicht sehr schoen - wenn moeglich noch mal aendern.                     */
/*            if(merk_sdf) free_sd(merk_sdf);*/
            /*  hier noch was ueberlegen    */
/*            if(merk_ilistf) free_ilist(merk_ilistf);*/
	  nesting--;
	  v->fi->vars=merk_varf;
/*            v->fi->vars=first_var[1];*/
            /*  keine echten Parameter=>keine negativen Offsets */
/*            vp=first_var[1];*/
	  vp=merk_varf;
	  while(vp){
	    if(vp->storage_class==AUTO||vp->storage_class==REGISTER){
	      if(!zlleq(l2zl(0L),vp->offset)){
		vp->offset=l2zl(0L);
		if(DEBUG&1024) printf("converted parameter <%s>(%ld) for inlining\n",vp->identifier,(long)zl2l(vp->offset));
	      }else vp->offset=l2zl(4L);  /*  Dummy, da recalc_offsets?   */
	    }
	    vp=vp->next;
	  }
        }else{
	  leave_block();
        }
        if(only_inline==2) only_inline=0;
        cur_func="oops, I forgot it";
  }else{
    if(makeint) error(125);
    if(*s==';') s++; else error(54);
    if((t->flags&NQ)==FUNKT&&t->exact){
      struct struct_declaration *sd=t->exact;int i,f;
      for(f=0,i=0;i<sd->count;i++)
	if(!(*sd->sl)[i].styp){error(126);f=1;}
      if(f){
	for(i=0;i<sd->count;i++) if((*sd->sl)[i].styp) freetyp((*sd->sl)[i].styp);
	sd->count=0;
      }
    }
  }
  if(old) freetyp(old);
}
int compare_pointers(struct Typ *a,struct Typ *b,int qual)
/*  Vergleicht, ob Typ beider Typen gleich ist, const/volatile      */
/*  werden laut ANSI nicht beruecksichtigt.                         */
{
  struct struct_declaration *sd;
  int af=a->flags&qual,bf=b->flags&qual;
  if(af!=bf) return(0);
  af&=NQ;bf&=NQ;
  if(af==FUNKT){
    if(a->exact->count&&!compare_sd(a->exact,b->exact)) return(0);
  }
  if(af==STRUCT||af==UNION){
    if(a->exact!=b->exact) return(0);
  }
  if(af==ARRAY){
    if(!zleqto(a->size,l2zl(0L))&&!zleqto(b->size,l2zl(0L))&&!zleqto(a->size,b->size)) return(0);
  }
  if(a->next==0&&b->next!=0) return(0);
  if(a->next!=0&&b->next==0) return(0);
  if(a->next==0&&b->next==0) return(1);
  return(compare_pointers(a->next,b->next,qual));
}
int compare_sd(struct struct_declaration *a,struct struct_declaration *b)
/*  Vergleicht, ob zwei struct_declarations identisch sind          */
/*  Wird nur nur fuer Prototypen benutzt, leere Liste immer gleich. */
{
  int i;
  if(!a->count||!b->count) return(1);
  if(a->count!=b->count) return(0);
  for(i=0;i<a->count;i++)
    if((*a->sl)[i].styp&&(*b->sl)[i].styp&&!compare_pointers((*a->sl)[i].styp,(*b->sl)[i].styp,255)) return(0);
  return(1);
}
void free_clist(struct const_list *p)
/*  Gibt clist frei.                                        */
{
  struct const_list *merk;
  return;
  while(p){
    merk=p->next;
    if(p->other) free_clist(p->other);
    if(p->tree) free_expression(p->tree);
    free(p);
    p=merk;
  }
}
void gen_clist(FILE *,struct Typ *,struct const_list *);

void gen_vars(struct Var *v)
/*  Generiert Variablen.                                    */
{
  int mode,al;struct Var *p;
  if(errors!=0||(c_flags[5]&USEDFLAG)) return;
  for(mode=0;mode<3;mode++){
    int i,flag;
    for(p=v;p;p=p->next){
      if(DEBUG&2) printf("gen_var(): %s\n",p->identifier);
      if(p->storage_class==STATIC||p->storage_class==EXTERN){
	if(!(p->flags&GENERATED)){
	  if(p->storage_class==EXTERN&&!(p->flags&(USEDASSOURCE|USEDASDEST))&&!(p->flags&(TENTATIVE|DEFINED))) continue;
	  /*  erst konstante initialisierte Daten */
	  if(mode==0){
	    if(!p->clist) continue;
	    if(!(p->vtyp->flags&(CONST|STRINGCONST))){
	      struct Typ *t=p->vtyp;int f=0;
	      do{
		if(t->flags&(CONST|STRINGCONST)) break;
		if((t->flags&NQ)!=ARRAY){f=1;break;}
		t=t->next;
	      }while(1);
	      if(f) continue;
	    }
	  }
	  /*  dann initiolisierte */
	  if(mode==1&&!p->clist) continue;
	  /*  und dann der Rest   */
	  if(mode==2&&p->clist) continue;
	  if(!(p->flags&(TENTATIVE|DEFINED))){
	    gen_var_head(out,p);
	    if(p->storage_class==STATIC) error(127,p->identifier);
	    continue;
	  }else{
	    gen_align(out,falign(p->vtyp));
	  }
	  gen_var_head(out,p);
	  if(!p->clist){
	    if(type_uncomplete(p->vtyp)) error(202,p->identifier);
	    gen_ds(out,szof(p->vtyp),p->vtyp);
	  }else{
	    gen_clist(out,p->vtyp,p->clist);
	  }
	  p->flags|=GENERATED;
	}
      }
    }   
  }
}
void gen_clist(FILE *f,struct Typ *t,struct const_list *cl)
/*  Generiert dc fuer const_list.                           */
{
  int i;zlong sz;
  if((t->flags&NQ)==ARRAY){
    for(sz=l2zl(0L);!zlleq(t->size,sz)&&cl;sz=zladd(sz,l2zl(1L)),cl=cl->next){
      if(!cl->other){ierror(0);return;}
      gen_clist(f,t->next,cl->other);
    }
    if(!zlleq(t->size,sz)) gen_ds(f,zlmult(zlsub(t->size,sz),szof(t->next)),t->next);
    return;
  }
  if((t->flags&NQ)==UNION){
    gen_clist(f,(*t->exact->sl)[0].styp,cl);
    sz=zlsub(szof(t),szof((*t->exact->sl)[0].styp));
    if(!zleqto(sz,l2zl(0L))) gen_ds(f,sz,0);
    return;
  }
  if((t->flags&NQ)==STRUCT){
    zlong al;int fl;struct Typ *st;
    sz=l2zl(0L);
    for(i=0;i<t->exact->count&&cl;i++){
      if(!cl->other){ierror(0);return;}
      st=(*t->exact->sl)[i].styp;
      al=falign(st);
      if(!zleqto(zlmod(sz,al),l2zl(0L))){
	gen_ds(f,zlsub(al,zlmod(sz,al)),0);
	sz=zladd(sz,zlsub(al,zlmod(sz,al)));
      }
      if(!(*t->exact->sl)[i].identifier) ierror(0);
      if((*t->exact->sl)[i].identifier[0]){
	gen_clist(f,st,cl->other);
	cl=cl->next;
      }else{
	gen_ds(f,szof(st),0); /* sollte unnamed bitfield sein */
      }
      sz=zladd(sz,szof(st));
    }
    for(;i<t->exact->count;i++){
      st=(*t->exact->sl)[i].styp;
      al=falign(st);
      if(!zleqto(zlmod(sz,al),l2zl(0L))){
	gen_ds(f,zlsub(al,zlmod(sz,al)),0);
	sz+=zladd(sz,zlsub(al,zlmod(sz,al)));
      }
      gen_ds(f,szof((*t->exact->sl)[i].styp),(*t->exact->sl)[i].styp);
      sz=zladd(sz,szof(st));
    }
    al=falign(t);
    if(!zleqto(zlmod(sz,al),l2zl(0L)))
      gen_ds(f,zlsub(al,zlmod(sz,al)),0);
    return;
  }
  if(cl->tree) cl->tree->o.am=0;
  gen_dc(f,t->flags&NU,cl);
}
struct const_list *initialization(struct Typ *t,int noconst,int level)
/*  Traegt eine Initialisierung in eine const_list ein.         */
{
  struct const_list *first,*cl,**prev;np tree,tree2;int bracket;zlong i;
  int f=t->flags&NQ;
  if(f==FUNKT){error(42);return(0);}
  if(*s=='{'){s++;killsp();bracket=1;} else bracket=0;
  if(f==ARRAY){
    if(*s=='\"'&&t->next&&(t->next->flags&NQ)==CHAR){
      killsp();
      tree=string_expression();
      first=tree->cl;
      free_expression(tree);
    }else{
      prev=0;
      if(level==0&&!bracket) error(157);
      for(i=l2zl(0L);(zleqto(t->size,l2zl(0L))||!zlleq(t->size,i))&&*s!='}';i=zladd(i,l2zl(1L))){
	if(!zlleq(i,0)){
	  if(*s==','){s++;killsp();} else break;
	  if(*s=='}') break;
	}
	cl=mymalloc(CLS);
	cl->next=0;cl->tree=0;
	cl->other=initialization(t->next,0,level+1);
	killsp();
	if(prev) *prev=cl; else first=cl;
	prev=&cl->next;
      }
    }
  }else if(f==STRUCT&&(bracket||!noconst)){
    if(t->exact->count<=0)
      {error(43);return(0);}
    prev=0;
    if(level==0&&!bracket) error(157);
    for(i=l2zl(0L);!zlleq(t->exact->count,i)&&*s!='}';i=zladd(i,l2zl(1L))){
      if((*t->exact->sl)[zl2l(i)].identifier[0]==0) {continue;} /* unnamed bitfield */
      if(!zlleq(i,0)){
	if(*s==','){s++;killsp();} else break;
	if(*s=='}') break;
      }
      cl=mymalloc(CLS);
      cl->next=0;cl->tree=0;
      cl->other=initialization((*t->exact->sl)[zl2l(i)].styp,0,level+1);
      if(prev) *prev=cl; else first=cl;
      prev=&cl->next;
    }
  }else if(f==UNION&&(bracket||!noconst)){
    if(t->exact->count<=0)
      {error(44);return(0);}
    first=initialization((*t->exact->sl)[0].styp,0,level+1);
  }else{
    tree2=tree=assignment_expression();
    if(!tree){error(45);return(0);}
    if(!type_expression(tree)){free_expression(tree); return(0);}
    tree=makepointer(tree);
    test_assignment(t,tree);
    if(!noconst){
      /*  nur Konstanten erlaubt (bei Arrays/Strukturen etc. oder static) */
      if(tree->flags!=CEXPR){
	while(tree->flags==CAST) tree=tree->left;
	if(tree->flags==ADDRESS||tree->flags==ADDRESSS||tree->flags==ADDRESSA){
	  gen_IC(tree,0,0);
	  if(!(tree->o.flags&VARADR)){
	    /*  hier fehlen noch viele Pruefungen   */
	    free_expression(tree);error(46);
	    return(0);
	  }
	  first=mymalloc(CLS);
	  first->next=first->other=0;
	  first->tree=tree;
	  killsp();
	}else{
	  free_expression(tree);error(46);
	  return(0);
	}
      }else{
	first=mymalloc(CLS);
	first->next=first->other=0;
	first->tree=0;
	eval_constn(tree);
	tree->ntyp->flags=t->flags;
	insert_const(tree);
	first->val=tree->val;
	free_expression(tree2);
	killsp();
      }
    }else{
      /*  auch anderes erlaubt    */
      first=mymalloc(CLS);
      first->next=first->other=0;
      first->tree=tree;
      killsp();
    }
  }
  if(bracket){
    if(*s==','){s++;killsp();}
    if(*s=='}'){s++;killsp();} else error(128);
  }
  return(first);
}



