blob: 942bed7936f496e8e998ac9ce59986ac2ac45cf2 [file] [log] [blame]
/* $VER: vbcc (declaration.c) $Revision: 1.90 $ */
#include <string.h>
#include <stdio.h>
#include "vbcc_cpp.h"
#include "vbc.h"
static char FILE_[]=__FILE__;
#define PLAIN_STORAGE_CLASS 7
#define PARAMETER 8
#define OLDSTYLE 16
void dynamic_init(Var *v,type *t,const_list *cl,zmax of,int noconst);
int test_assignment(type *,np);
int return_sc,return_reg,has_return,return_inline;
char *return_vattr;
static int did_return_label;
#ifdef HAVE_TARGET_ATTRIBUTES
unsigned long return_tattr;
#endif
zumax return_mask;
zmax init_dyn_sz,init_const_sz;
int init_dyn_cnt,init_const_cnt;
void init_sl(struct_list *sl);
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
extern np gen_libcall(char *,np,type *,np,type *);
extern int float_used;
extern void optimize(long,Var *);
extern type uct;
void needs(char *s)
{
Var *v;
if(!(v=find_ext_var(s))||!strcmp(v->identifier,s)){
Var *needs=add_var(s,clone_typ(&uct),EXTERN,0);
needs->flags|=(USEDASSOURCE|REFERENCED|NEEDS);
}
}
static void clear_main_ret(void)
{
if(c99&&!strcmp(cur_func,"main")&&return_typ&&ISSCALAR(return_typ->flags)){
/* in c99, main returns 0 if it falls from back */
IC *new=new_IC();
new->code=SETRETURN;
new->q1.val.vmax=l2zm(0L);
eval_const(&new->q1.val,MAXINT);
insert_const(&new->q1.val,return_typ->flags&NU);
new->q1.flags=KONST;
new->typf=return_typ->flags;
new->q2.val.vmax=szof(return_typ);
new->q2.flags=new->z.flags=0;
new->z.reg=freturn(return_typ);
add_IC(new);
}
}
static char *get_string(void)
/* Liest Stringkonstante und liefert Wert als String (malloced) */
{
np tree;int l;char *p;
const_list *cl;
killsp();
if(ctok->type!=T_STRING) {error(74);return 0;}
tree=string_expression();
if(!tree||tree->flags!=STRING){
error(229);
return 0;
}
cl=tree->cl;l=0;
while(cl){
l++;
cl=cl->next;
}
p=mymalloc(l);
cl=tree->cl;l=0;
while(cl){
p[l]=CHARBACK(zm2l(zc2zm(cl->other->val.vchar)));
l++;
cl=cl->next;
}
if(tree) free_expression(tree);
killsp();
return p;
}
/* checks whether string is a valid vector type */
/* returns the dimension */
static int check_vect(char *s,char *base)
{
int i=strlen(base),dim;
if(strncmp(s,base,i)) return 0;
dim=s[i];
if(dim=='2'||dim=='3'||dim=='4'||dim=='8'){
if(s[i+1]==0)
return dim-'0';
else
return 0;
}
if(s[i]=='1'&&s[i+1]=='6'&&s[i+2]==0)
return 16;
return 0;
}
int settyp(int typnew, int typold)
/* Unterroutine fuer declaration_specifiers(). */
{
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) return LDOUBLE;
if(c99&&typold==LONG&&typnew==LONG) return LLONG;
if(typold==INT&&(typnew==SHORT||typnew==LONG)) return typnew;
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||typold==LLONG) return(typold);
error(48);
return(typnew);
}
#define dsc if(storage_class) error(49); if(typ||type_qualifiers) error(50)
#define XSIGNED 16384
#ifdef HAVE_MISRA
/* removed */
#endif
type *declaration_specifiers(void)
/* Erzeugt neuen Typ und gibt Zeiger darauf zurueck, */
/* parst z.B. unsigned int, bla etc. */
{
int typ=0,type_qualifiers=0,notdone,storage_class,hard_reg,have_inline;
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
#endif
char *imerk,sident[MAXI],sbuff[MAXI],*attr=0,*vattr=0;
zumax mask=ul2zum(0UL);
type *new=new_typ(),*t,*ts;
struct_declaration *ssd;
struct_list (*sl)[];
size_t slsz;
Var *v;
int dim;
#ifdef HAVE_TARGET_ATTRIBUTES
unsigned long tattr=0;
#endif
storage_class=hard_reg=have_inline=0;
do{
killsp();notdone=0;
if(ctok->type==NAME){
if(!strcmp("struct",ctok->name)||!strcmp("union",ctok->name)||(ecpp&&!strcmp("class",ctok->name))){
if(!strcmp("struct",ctok->name)) notdone=STRUCT;
if(!strcmp("union",ctok->name)) {
notdone=UNION;
#ifdef HAVE_MISRA
/* removed */
#endif
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
next_token();
killsp();
if(ctok->type!=LBRA){
cpbez(sident,1);
next_token();
killsp();
ssd=find_struct(sident,0);
#ifdef HAVE_MISRA
/* removed */
#endif
if(ssd&&ctok->type==LBRA&&find_struct(sident,nesting)&&ssd->count>0) error(13,sident);
if(!ssd||((ctok->type==LBRA||ctok->type==SEMIC)&&!find_struct(sident,nesting))){
typ=settyp(notdone,typ);
ssd=mymalloc(sizeof(*ssd));
ssd->count=0;
new->exact=ssd=add_sd(ssd,notdone);
if(!ecpp)add_struct_identifier(sident,ssd);
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}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,notdone);
}
if(ssd->typ!=notdone) error(230,sident);
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
if(ctok->type==LBRA){
int bfoffset,bfsize,flex_array=0,cbfo=0;
int scount;
zmax off=l2zm(0L);
next_token();
killsp();
slsz=SLSIZE;
imerk=ident;
sl=mymalloc(slsz*sizeof(struct_list));
ssd->count=0;
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
scount=ssd->count;
ts=declaration_specifiers();
while(ctok->type!=RBRA&&ts){
if(flex_array) error(231);
ident=sbuff;
t=declarator(clone_typ(ts));
killsp();
bfsize=bfoffset=-1;
if(ctok->type==T_COLON){
np tree;
if((ts->flags&NQ)!=INT) {
error(51);
#ifdef HAVE_MISRA
/* removed */
#endif
}
next_token();killsp();tree=assignment_expression();
if(type_expression(tree,0)){
int tsize;
if(tree->flags!=CEXPR) error(52);
if(!ISINT(tree->ntyp->flags)) error(52);
eval_const(&tree->val,tree->ntyp->flags);
bfsize=(int)zm2l(vmax);
tsize=(int)zm2l(zmmult(sizetab[t->flags&NQ],char_bit));
if(bfsize<0||bfsize>tsize||(bfsize==0&&*ident)){
error(332);bfsize=1;
}
if(bfsize+cbfo>tsize){
bfoffset=cbfo=0;
}else{
bfoffset=cbfo;
}
if(bfsize!=0)
cbfo+=bfsize;
else
cbfo=0;
}
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
#endif
if(tree) free_expression(tree);
}else{
if(!ecpp&&*ident==0) error(53);
cbfo=0;
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
if(type_uncomplete(t)){
if(!c99||notdone!=STRUCT||flex_array||(t->flags&NQ)!=ARRAY||type_uncomplete(t->next)){
error(14,sbuff);
freetyp(t);
break;
}else{
flex_array=1;
}
}
if(ISARRAY(t->flags)&&t->dsize){
error(352,sbuff);
}
if(ISFUNC(t->flags)){
if(!ecpp){
error(15,sbuff);
}
}
if(*ident!=0){
int i=scount;
while(--i>=0)
if(!strcmp((*sl)[i].identifier,ident))
error(16,ident);
}
#ifdef HAVE_MISRA
/* removed */
#endif
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
(*sl)[scount].bfoffset=bfoffset;
(*sl)[scount].bfsize=bfsize;
(*sl)[scount].styp=t;
if(!ecpp) (*sl)[scount].identifier=add_identifier(ident,strlen(ident));
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
#endif
if(pack_align>0&&pack_align<falign(t))
(*sl)[scount].align=pack_align;
else
(*sl)[scount].align=falign(t);
{
zmax m,al=(*sl)[scount].align;
zmax sz=szof(t);
m=off;
if((zmeqto(al,l2zm(0L))||zmeqto(sz,l2zm(0L)))&&!flex_array){
if (!ecpp){
error(316,ident);
}
}else{
off=zmmult(zmdiv(zmadd(off,zmsub(al,l2zm(1L))),al),al);
if(!zmeqto(m,off)) error(306,ident);
if(!flex_array){
m=zmmult(zmdiv(zmadd(off,zmsub(sz,l2zm(1L))),sz),sz);
if(!zmeqto(m,off)) error(307,ident);
off=zmadd(off,sz);
}
}
}
scount++;
if(scount>=slsz-1){
slsz+=SLSIZE;
sl=myrealloc(sl,slsz*sizeof(struct_list));
}
killsp();
if(ctok->type==COMMA) {next_token();killsp();continue;}
if(ctok->type!=SEMIC) error(54); else next_token();
killsp();
#ifdef HAVE_ECPP
/* removed */
#endif
if(ctok->type!=RBRA){
if(ts) freetyp(ts);
ts=declaration_specifiers();killsp();
}
}
if(ts) freetyp(ts);
ssd->count=scount;
if(ssd->count==0) error(55);
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
ident=imerk;
add_sl(ssd,sl);
free(sl);
if(ctok->type!=RBRA) error(56); else next_token();
new->flags=notdone|type_qualifiers;
}
#ifdef HAVE_ECPP
/* removed */
#endif
notdone=1;
}else if(!strcmp("enum",ctok->name)){
/* enumerations; die Namen werden leider noch ignoriert */
next_token();killsp();notdone=1;
if(ctok->type!=LBRA){cpbez(buff,1);next_token();killsp();}
if(ctok->type==LBRA){
/* mode: 0=start 1=first was not init 2=first was init 3=more init */
zmax val; Var *v; type *t;int mode=0;
val=l2zm(0L);
next_token();killsp();
while(ctok->type!=RBRA){
cpbez(sident,1);next_token();killsp();
if(*sident==0) {error(56);break;}
t=new_typ();
t->flags=CONST|INT;
if(find_var(sident,nesting)) error(17,sident);
v=add_var(sident,t,AUTO,0); /* AUTO hier klug? */
if(ctok->type==ASGN){
if(mode==2) mode=3;
if(mode==0) mode=2;
#ifdef HAVE_MISRA /* MISRA Rule 9.3 checking */
/* removed */
#endif
next_token();killsp();
v->clist=initialization(v->vtyp,0,0,0,0,0);
val=zi2zm(v->clist->val.vint);killsp();
}else{
if(mode==0) mode=1;
#ifdef HAVE_MISRA /* MISRA Rule 9.3 checking */
/* removed */
#endif
v->clist=mymalloc(CLS);
v->clist->val.vint=zm2zi(val);
v->clist->next=v->clist->other=0;
v->clist->tree=0;
v->clist->idx=l2zm(0L);
}
vmax=l2zm(1L);val=zmadd(val,vmax);
v->vtyp->flags=CONST|ENUM;
if(ctok->type!=RBRA&&ctok->type!=COMMA) {error(56);break;}
if(ctok->type==COMMA) next_token();
killsp();
if(ctok->type==RBRA) {next_token(); break;}
}
}
killsp();
typ=settyp(INT,typ);
}else if(!strcmp("__readsmem",ctok->name)||!strcmp("__writesmem",ctok->name)){
enum {READS,WRITES} op;
char *imerk,tbuf[MAXI];
type *tmp;
if(!strcmp("__readsmem",ctok->name))
op=READS;
else
op=WRITES;
next_token();killsp();
if(ctok->type==LPAR) next_token(); else error(151);
imerk=ident;ident=tbuf;
tmp=declarator(declaration_specifiers());
ident=imerk;
if(tmp){
if(vattr)
vattr=myrealloc(vattr,strlen(vattr)+25);
else{
vattr=mymalloc(25);
vattr[0]=0;
}
sprintf(vattr+strlen(vattr),";%s(%d)",op==READS?"readmem":"writemem",tmp->flags);
}
killsp();
if(ctok->type==RPAR) next_token(); else error(59);
killsp();
notdone=1;
}else if(!strcmp("void",ctok->name)){
next_token();
typ=settyp(VOID,typ);notdone=1;
}else if(!strcmp("char",ctok->name)){
#ifdef HAVE_MISRA
/* removed */
/* removed */
#endif
next_token();
typ=settyp(CHAR,typ);
notdone=1;
if(default_unsigned&&!(type_qualifiers&XSIGNED))
type_qualifiers|=UNSIGNED;
}else if(!strcmp("short",ctok->name)){
#ifdef HAVE_MISRA
/* removed */
#endif
next_token();
typ=settyp(SHORT,typ);notdone=1;
}else if(!strcmp("int",ctok->name)){
#ifdef HAVE_MISRA
/* removed */
#endif
next_token();
typ=settyp(INT,typ);notdone=1;
}else if(!strcmp("long",ctok->name)){
#ifdef HAVE_MISRA
/* removed */
#endif
next_token();
typ=settyp(LONG,typ);notdone=1;
}else if(!strcmp("float",ctok->name)){
#ifdef HAVE_MISRA
/* removed */
#endif
next_token();
typ=settyp(FLOAT,typ);notdone=1;
}else if(!strcmp("double",ctok->name)){
#ifdef HAVE_MISRA
/* removed */
#endif
next_token();
typ=settyp(DOUBLE,typ);notdone=1;
}else if(!strcmp("const",ctok->name)){
next_token();
if(type_qualifiers&CONST) error(58);
type_qualifiers|=CONST;notdone=1;
}else if(!strcmp("volatile",ctok->name)){
next_token();
if(type_qualifiers&VOLATILE) error(58);
type_qualifiers|=VOLATILE;notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"bool"))){
next_token();
typ=settyp(VECBOOL+dim-1,typ);
notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"char"))){
next_token();
typ=settyp(VECCHAR+dim-1,typ);
notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"uchar"))){
next_token();
typ=settyp((VECCHAR+dim-1)|UNSIGNED,typ);
notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"short"))){
next_token();
typ=settyp(VECSHORT+dim-1,typ);
notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"ushort"))){
next_token();
typ=settyp((VECSHORT+dim-1)|UNSIGNED,typ);
notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"int"))){
next_token();
typ=settyp(VECINT+dim-1,typ);
notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"uint"))){
next_token();
typ=settyp((VECINT+dim-1)|UNSIGNED,typ);
notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"long"))){
next_token();
typ=settyp(VECLONG+dim-1,typ);
notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"ulong"))){
next_token();
typ=settyp((VECLONG+dim-1)|UNSIGNED,typ);
notdone=1;
}else if(opencl&&(dim=check_vect(ctok->name,"float"))){
next_token();
typ=settyp(VECFLOAT+dim-1,typ);
notdone=1;
#if 0
}else if(c99&&!strcmp("restrict",ctok->name)){
next_token();
if(type_qualifiers&RESTRICT) error(58);
type_qualifiers|=RESTRICT;notdone=1;
#endif
}else if(!strcmp("unsigned",ctok->name)){
next_token();
if(type_qualifiers&(XSIGNED|UNSIGNED)) error(58);
notdone=1;type_qualifiers|=UNSIGNED;
}else if(!strcmp("signed",ctok->name)){
next_token();
if(type_qualifiers&(XSIGNED|UNSIGNED)) error(58);
notdone=1;type_qualifiers|=XSIGNED;
}else if(!strcmp("auto",ctok->name)){
next_token();
dsc;storage_class=AUTO;notdone=1;
}else if(!strcmp("register",ctok->name)){
#ifdef HAVE_MISRA
/* removed */
#endif
next_token();
dsc;storage_class=REGISTER;notdone=1;
}else if(!strcmp("static",ctok->name)){
next_token();
dsc;storage_class=STATIC;notdone=1;
#ifdef HAVE_ECPP
/* removed */
#endif
}else if(!strcmp("extern",ctok->name)){
next_token();
dsc;storage_class=EXTERN;notdone=1;
}else if(!strcmp("typedef",ctok->name)){
next_token();
dsc;storage_class=TYPEDEF;notdone=1;
}else if(c99&&!strcmp("inline",ctok->name)){
next_token();
have_inline=1;notdone=1;
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__reg",ctok->name)){
char *d;
next_token();killsp();
if(ctok->type==LPAR) next_token(); else error(151);
killsp();
if(d=get_string()){
for(hard_reg=1;hard_reg<=MAXR;hard_reg++){
if(!strcmp(d,regnames[hard_reg])) break;
}
if(hard_reg>MAXR){ hard_reg=0;error(220,d);}
notdone=1;
free(d);
}
killsp();
if(ctok->type==RPAR) next_token(); else error(59);
killsp();
}else if(!strcmp("__mask",ctok->name)){
np tree;
next_token();killsp();
if(ctok->type==LPAR) next_token(); else error(151);
tree=expression();
if(tree&&type_expression(tree,0)){
if(tree->flags==CEXPR&&ISINT(tree->ntyp->flags)){
eval_const(&tree->val,tree->ntyp->flags);
mask=vumax;
}else
error(18);
free_expression(tree);
}else
error(18);
killsp();
if(ctok->type==RPAR) next_token(); else error(59);
killsp();
notdone=1;
}else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__attr",ctok->name)){
char *d;
next_token();killsp();
if(ctok->type==LPAR) next_token(); else error(151);
killsp();
if(d=get_string()){
if(!attr){
attr=d;
}else{
attr=myrealloc(attr,strlen(attr)+strlen(d)+2);
strcat(attr,";");
strcat(attr,d);
free(d);
}
notdone=1;
}
killsp();
if(ctok->type==RPAR) next_token(); else error(59);
killsp();
}else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__vattr",ctok->name)){
char *d;
next_token();killsp();
if(ctok->type==LPAR) next_token(); else error(151);
killsp();
if(d=get_string()){
if(!vattr){
vattr=d;
}else{
vattr=myrealloc(vattr,strlen(vattr)+strlen(d)+2);
strcat(vattr,";");
strcat(vattr,d);
free(d);
}
notdone=1;
}
killsp();
if(ctok->type==RPAR) next_token(); else error(59);
killsp();
}else{
#ifdef HAVE_TARGET_ATTRIBUTES
int i;
for(i=0;g_attr_name[i];i++){
if(!strcmp(g_attr_name[i],ctok->name)){
if(tattr&(1L<<i)) error(227,ctok->name);
tattr|=(1L<<i);
next_token();
notdone=1;break;
}
}
#endif
if(!notdone&&typ==0&&!(type_qualifiers&(XSIGNED|UNSIGNED))){
v=find_var(ctok->name,0);
if(v&&v->storage_class==TYPEDEF){
free(new);
new=clone_typ(v->vtyp);
typ=settyp(new->flags,typ);
notdone=1;
next_token();
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}
}
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
if(DEBUG&2) printf("typ:%d\n",typ);
}while(notdone);
killsp();
return_sc=storage_class;
return_reg=hard_reg;
return_vattr=vattr;
return_mask=mask;
return_inline=have_inline;
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
#endif
#ifdef HAVE_TARGET_ATTRIBUTES
return_tattr=tattr;
#endif
if(typ==0){
if(storage_class==0&&type_qualifiers==0&&!hard_reg){
free(new);
return 0;
}
#ifdef HAVE_MISRA
/* removed */
#endif
typ=INT;
}
if(type_qualifiers&(XSIGNED|UNSIGNED))
if(!ISINT(typ))
error(58);
new->flags=typ|type_qualifiers;
new->attr=attr;
return new;
}
type *declarator(type *a)
/* Erzeugt einen neuen Typ, auf Basis des Typs a. */
/* a wird hiermit verkettet. */
{
type *t;
killsp();*ident=0;
t=direct_declarator(pointer(a));
if(!a)
{if(t) freetyp(t);return 0;}
#ifdef HAVE_ECPP
/* removed */
#endif
#ifdef HAVE_EXT_TYPES
conv_typ(t);
#endif
return t;
}
type *pointer(type *a)
/* Unterroutine fuer declarator(), behandelt Zeiger auf Typ. */
{
type *t;char *attr;int notdone;
if(!a) return(0);
killsp();
while(ctok->type==STAR){
next_token();
t=new_typ();
t->flags=POINTER_TYPE(a);
t->next=a;
attr=0;
a=t;
do{
killsp();
notdone=0;
if(ctok->type==NAME&&!strcmp("const",ctok->name)){
a->flags|=CONST;
notdone=1;
next_token();
}else if(ctok->type==NAME&&!strcmp("volatile",ctok->name)){
a->flags|=VOLATILE;
notdone=1;
next_token();
}else if(c99&&ctok->type==NAME&&!strcmp("restrict",ctok->name)){
a->flags|=RESTRICT;
notdone=1;
next_token();
}else if(ctok->type==NAME&&!strcmp("__attr",ctok->name)){
char *d;
next_token();
killsp();
if(ctok->type==LPAR) next_token(); else error(151);
killsp();
if(d=get_string()){
if(!attr){
attr=d;
}else{
attr=myrealloc(attr,strlen(attr)+strlen(d)+2);
strcat(attr,";");
strcat(attr,d);
free(d);
}
notdone=1;
}
killsp();
if(ctok->type==RPAR) next_token(); else error(59);
killsp();
}
}while(notdone);
a->attr=attr;
}
return a;
}
type *direct_declarator(type *a)
/* Unterroutine zu declarator() */
/* behandelt [],(funkt),(dekl). */
{
type *rek=0,*merk,*p,*t=0,*first,*last=0;
struct_declaration *fsd;
struct_list (*sl)[];
size_t slsz;char *imerk;
char fbuff[MAXI];
killsp();
if(ctok->type!=NAME&&ctok->type!=LPAR&&ctok->type!=LBRK)
return a;
if(ctok->type==NAME){
cpbez(ident,1);
next_token();
if(!a) return(0);
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}
else if(ctok->type==LPAR&&a){
/* Rekursion */
token mtok;
copy_token(&mtok,ctok);
next_token(); killsp();
if(ctok->type!=RPAR&&*ident==0&&!declaration(0)){
merk=a;
rek=declarator(a);
if(ctok->type!=RPAR) error(59); else next_token();
}else
push_token(&mtok);
free(mtok.name);
}
if(!a)return(0);
killsp();
while(ctok->type==LBRK||ctok->type==LPAR){
if(ctok->type==LBRK){
next_token();
killsp();
p=new_typ();
p->flags=ARRAY;
p->next=0;
if(ctok->type==RBRK){
p->size=l2zm(0L);
}else{
np tree;
tree=expression();
if(!type_expression(tree,0)){
/* error("incorrect constant expression");*/
}else{
if(tree->sidefx&&!c99) error(60);
if(tree->flags!=CEXPR||!ISINT(tree->ntyp->flags)){
if(!c99||!ALLOCVLA_INLINEASM)
error(19);
else{
type *st;IC *new;
st=new_typ();
st->flags=HAVE_INT_SIZET?(UNSIGNED|INT):(UNSIGNED|LONG);
p->dsize=add_tmp_var(st);
gen_IC(tree,0,0);
convert(tree,st->flags);
new=new_IC();
new->code=ASSIGN;
new->typf=st->flags;
new->q1=tree->o;
new->z.flags=VAR;
new->z.v=p->dsize;
new->z.val.vmax=l2zm(0L);
new->q2.val.vmax=szof(st);
add_IC(new);
}
}else{
eval_constn(tree);
p->size=vmax;
if(zmleq(p->size,l2zm(0L))) {error(61);p->size=l2zm(1L);}
}
}
free_expression(tree);
}
if(ctok->type!=RBRK) error(62); else next_token();
if(last){
last->next=p;
last=p;
}else{
first=last=p;
}
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
#endif
if(ctok->type==LPAR){
int komma,firstparm,oldstyle=0;
#if 0 /*#ifdef HAVE_REGPARMS*/
treg_handle reg_handle=empty_reg_handle;
type rpointer={0};
if(!ffreturn(a)&&(a->flags&NQ)!=VOID){
rpointer.flags=POINTER_TYPE(a);
rpointer.next=a;
reg_parm(&reg_handle,&rpointer,0,a); /*TODO: a might be incomplete */
}
#endif
#ifdef HAVE_MISRA
/* removed */
/* removed */
#endif
next_token();
killsp();
#ifdef HAVE_MISRA
/* removed */
#endif
fsd=mymalloc(sizeof(*fsd));
slsz=SLSIZE;
sl=mymalloc(sizeof(struct_list)*slsz);
fsd->count=0;
imerk=ident;komma=0;
enter_block();
firstparm=1;
while(ctok->type!=RPAR&&ctok->type!=MDOTS){
int hard_reg;
#ifdef HAVE_ECPP
/* removed */
#endif
if(!firstparm&&!komma) error(57);
komma=firstparm=0;
ident=fbuff;*fbuff=0;
t=declaration_specifiers();
hard_reg=return_reg;
t=declarator(t);
if(!t){
oldstyle=1;
if(*ident==0) {error(20);freetyp(t);continue;}
}
if(fsd->count){
if((t&&!(*sl)[fsd->count-1].styp)||
(!t&&(*sl)[fsd->count-1].styp))
error(63);
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
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;
{
int m=nesting;
nesting=0;
(*sl)[fsd->count].identifier=add_identifier(ident,strlen(ident));
nesting=m;
}
if(t){
if(((*sl)[fsd->count].styp->flags&NQ)==VOID&&fsd->count!=0)
error(22);
/* Arrays in Zeiger umwandeln */
if(ISARRAY((*sl)[fsd->count].styp->flags))
(*sl)[fsd->count].styp->flags=POINTER_TYPE((*sl)[fsd->count].styp->next);
/* Funktionen in Zeiger auf Funktionen umwandeln */
if(ISFUNC((*sl)[fsd->count].styp->flags)){
type *new;
new=new_typ();
new->next=(*sl)[fsd->count].styp;
new->flags=POINTER_TYPE(new->next);
(*sl)[fsd->count].styp=new;
}
}
if(hard_reg&&regok(hard_reg,t->flags,-1)<=0) error(217,regnames[hard_reg]);
#if 0 /*#ifdef HAVE_REGPARMS*/
if(t) (*sl)[fsd->count].reg=reg_parm(&reg_handle,t,0,a); /*TODO: a might be incomplete */
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=myrealloc(sl,slsz*sizeof(struct_list));
}
killsp(); /* Hier Syntaxpruefung strenger machen */
if(ctok->type==COMMA) {next_token();komma=1; killsp();}
}
ident=imerk;
#ifdef HAVE_MISRA
/* removed */
#endif
if(ctok->type!=MDOTS||!komma){
int ecpp_addvoid=0;
#ifdef HAVE_ECPP
/* removed */
#endif
if(ecpp_addvoid||(!ecpp&&fsd->count>0&&(!(*sl)[fsd->count-1].styp||((*sl)[fsd->count-1].styp->flags&NQ)!=VOID))){
(*sl)[fsd->count].styp=new_typ();
(*sl)[fsd->count].styp->flags=VOID;
(*sl)[fsd->count].styp->next=0;
(*sl)[fsd->count].reg=0;
(*sl)[fsd->count].identifier=empty;
#ifdef HAVE_ECPP
/* removed */
#endif
fsd->count++;
}
if(ecpp&&ctok->type==MDOTS){next_token();killsp();}
}else if(komma){
next_token();komma=0;
if(oldstyle) error(221);
}
p=new_typ();
p->flags=FUNKT;
{
int m=nesting;
nesting=0;
p->exact=add_sd(fsd,FUNKT);
add_sl(fsd,sl);
free(sl);
nesting=m;
}
#ifdef HAVE_REGPARMS
{
treg_handle reg_handle=empty_reg_handle;
int i,r;
p->next=a;
if(!ffreturn(a)&&(a->flags&NQ)!=VOID){
type rpointer={0};
rpointer.flags=POINTER_TYPE(a);
rpointer.next=a;
reg_parm(&reg_handle,&rpointer,0,p);
}
for(i=0;i<p->exact->count;i++){
if((*p->exact->sl)[i].styp)
r=reg_parm(&reg_handle,(*p->exact->sl)[i].styp,0,p);
else
r=0;
if((*p->exact->sl)[i].reg==0) (*p->exact->sl)[i].reg=r;
}
}
#endif
killsp();
if(komma) error(59);
if(ctok->type!=RPAR) error(59); else next_token();
killsp();
if(ctok->type==COMMA||ctok->type==SEMIC||ctok->type==RPAR||ctok->type==ASGN)
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. */
{
Var *v;token mtok;
int fl=0;
if(offset){
copy_token(&mtok,ctok);
next_token();
killsp();
}
if(ctok->type==NAME){
if(!strcmp("auto",ctok->name)) fl=1;
else if(!strcmp("char",ctok->name)) fl=1;
else if(!strcmp("const",ctok->name)) fl=1;
else if(!strcmp("double",ctok->name)) fl=1;
else if(!strcmp("enum",ctok->name)) fl=1;
else if(!strcmp("extern",ctok->name)) fl=1;
else if(!strcmp("float",ctok->name)) fl=1;
else if(!strcmp("int",ctok->name)) fl=1;
else if(!strcmp("long",ctok->name)) fl=1;
else if(!strcmp("register",ctok->name)) fl=1;
else if(c99&&!strcmp("restrict",ctok->name)) fl=1;
else if(!strcmp("short",ctok->name)) fl=1;
else if(!strcmp("signed",ctok->name)) fl=1;
else if(!strcmp("static",ctok->name)) fl=1;
else if(!strcmp("struct",ctok->name)) fl=1;
else if(!strcmp("typedef",ctok->name)) fl=1;
else if(!strcmp("union",ctok->name)) fl=1;
else if(!strcmp("unsigned",ctok->name)) fl=1;
else if(!strcmp("void",ctok->name)) fl=1;
else if(!strcmp("volatile",ctok->name)) fl=1;
else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__reg",ctok->name)) fl=1;
else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__attr",ctok->name)) fl=1;
else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__vattr",ctok->name)) fl=1;
else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__mask",ctok->name)) fl=1;
else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__readsmem",ctok->name)) fl=1;
else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__writesmem",ctok->name)) fl=1;
else{
v=find_var(ctok->name,0);
if(v&&v->storage_class==TYPEDEF) fl=1;
}
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
if(offset){
push_token(&mtok);
free(mtok.name);
}
return fl;
}
void init_sl(struct_list *sl){
if(!sl){ierror(0);return;}
sl->identifier=0;
sl->styp=0;
sl->align=0;
sl->bfoffset=-1;
sl->bfsize=-1;
sl->reg=0;
sl->storage_class=0;
#ifdef HAVE_ECPP
/* removed */
#endif
}
void add_sl(struct_declaration *sd,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_list)*sd->count;
sd->sl=mymalloc(sz);
memcpy(sd->sl,sl,sz);
}
struct_declaration *add_sd(struct_declaration *new,int typ)
/* Fuegt eine Declaration in Liste ein. */
{
new->next=0;
new->label=0;
new->typ=typ;
new->identifier=0;
new->tunit=last_tunit;
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
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_declaration *p)
/* Gibt eine struct_declaration-List inkl. struct_lists und */
/* allen Typen jeder struct_list frei, nicht aber identifier. */
{
int i;struct_declaration *merk;
while(p){
merk=p->next;
if(p->sl){
for(i=0;i<p->count;i++){
if((*p->sl)[i].styp) freetyp((*p->sl)[i].styp);
}
if(p->count>0) free(p->sl);
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
#endif
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. */
{
identifier_list *new;
if((*identifier==0&&length==0)||identifier==empty) return(empty);
new=mymalloc(sizeof(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(identifier_list *p)
/* Gibt eine verkettete identifier_liste und saemtliche darin */
/* gespeicherten Identifier frei. */
{
identifier_list *merk;
while(p){
merk=p->next;
if(p->identifier) free(p->identifier);
free(p);
p=merk;
}
}
int type_uncomplete(type *p)
/* Testet, ob Typ unvollstaendig ist. Momentan gelten nur */
/* unvollstaendige Strukturen und Arrays von solchen als */
/* unvollstaendig, aber keine Zeiger oder Funktionen darauf. */
{
struct_declaration *sd;
if(!p){ierror(0);return(0);}
if(ISSTRUCT(p->flags)||ISUNION(p->flags))
if(p->exact->count<=0) return 1;
if(ISARRAY(p->flags)){
if(!p->dsize&&zmleq(p->size,l2zm(0L))) return 1;
if(!p->next) ierror(0);
if(type_uncomplete(p->next)) return 1;
}
return 0;
}
void add_struct_identifier(char *identifier,struct_declaration *sd)
/* Erzeugt neuen struct_identifier, fuegt ihn in Liste an und */
/* vervollstaendigt unvollstaendige Typen dieser Struktur. */
{
struct_identifier *new;
/* type *t;*/
if(DEBUG&1) printf("add_si %s (nesting=%d)->%p\n",identifier,nesting,(void *)sd);
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
new=mymalloc(sizeof(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;
}
sd->identifier=new->identifier;
}
void free_si(struct_identifier *p)
/* Gibt eine struct_identifier-Liste frei, aber nicht die */
/* identifiers und struct_declarations. */
{
struct_identifier *merk;
while(p){
merk=p->next;
p->sd->identifier="<prototype-only>";
free(p);
p=merk;
}
}
struct_declaration *find_struct(char *identifier,int endnesting)
/* Sucht angegebene Strukturdefinition und liefert */
/* entsprechende struct_declaration. */
{
struct_identifier *si; int i,l;
if(misracheck) l=strlen(identifier);
for(i=nesting;i>=endnesting;i--){
si=first_si[i];
while(si){
if(!strcmp(si->identifier,identifier)){
if(DEBUG&1) printf("found tag <%s> at nesting %d->%p\n",identifier,i,(void *)si->sd);
return(si->sd);
}
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
#endif
si=si->next;
}
}
if(DEBUG&1) printf("didn't find tag <%s>\n",identifier);
return(0);
}
/* generate code to create a variable-lenght-array */
static void create_allocvl(Var *v)
{
np tree,ds;
IC *new;Var *fv;
/* check if we got a frame-pointer */
if(FPVLA_REG&&!regsa[FPVLA_REG]){
if(regused[FPVLA_REG])
ierror(0);
else
regsa[FPVLA_REG]=regscratch[FPVLA_REG]=regused[FPVLA_REG]=1;
}
/* if this is the first vla in this block, save old sp */
if(!block_vla[nesting]){
/* declare function - may be done by the backend, if necessary */
if(!(fv=find_ext_var("__oldvlasp"))){
type *t;
static type voidt={VOID};
struct_declaration *sd=mymalloc(sizeof(*sd));
t=new_typ();
t->flags=FUNKT;
t->next=new_typ();
t->next->flags=POINTER_TYPE(&voidt);
t->next->next=clone_typ(&voidt);
sd->count=0;
t->exact=add_sd(sd,FUNKT);
fv=add_var("__oldvlasp",t,EXTERN,0);
fv->fi=new_fi();
fv->fi->flags|=(ALL_USES|ALL_MODS);
fv->fi->inline_asm=mystrdup(OLDSPVLA_INLINEASM);
}
block_vla[nesting]=add_tmp_var(clone_typ(fv->vtyp->next));
tree=gen_libcall("__oldvlasp",0,0,0,0);
new=new_IC();
new->code=ASSIGN;
new->z.flags=VAR;
new->z.v=block_vla[nesting];
new->z.val.vmax=l2zm(0L);
new->q1=tree->o;
new->q2.flags=0;
new->typf=block_vla[nesting]->vtyp->flags;
new->q2.val.vmax=sizetab[new->typf];
add_IC(new);
free_expression(tree);
}
/* make room on the stack */
ds=new_node();
ds->flags=IDENTIFIER;
ds->identifier=empty;
ds->dsize=vlength_szof(v->vtyp);
ds->val.vmax=l2zm(0L);
ds->ntyp=clone_typ(ds->dsize->vtyp);
ds->o.flags=VAR;
ds->o.v=ds->dsize;
ds->o.val.vmax=l2zm(0L);
ds->left=ds->right=0;
if(!find_ext_var("__allocvla")){
/* declare function */
struct_declaration *sd=mymalloc(sizeof(*sd));
type *t=new_typ();
sd->count=1;
sd->sl=mymalloc(sizeof(struct_list));
(*sd->sl)[0].storage_class=AUTO;
(*sd->sl)[0].styp=clone_typ(ds->dsize->vtyp);
(*sd->sl)[0].reg=ALLOCVLA_REG;
t->flags=FUNKT;
t->exact=add_sd(sd,FUNKT);
t->next=new_typ();
t->next->flags=POINTER_TYPE(v->vtyp);
t->next->next=new_typ();
t->next->next->flags=v->vtyp->flags;
fv=add_var("__allocvla",t,EXTERN,0);
fv->fi=new_fi();
fv->fi->flags|=(ALL_USES|ALL_MODS);
fv->fi->inline_asm=mystrdup(ALLOCVLA_INLINEASM);
}
if(!type_expression(ds,0)) ierror(0);
tree=gen_libcall("__allocvla",ds,0,0,0);
new=new_IC();
new->code=ASSIGN;
new->z.flags=VAR;
new->z.v=v;
new->z.val.vmax=l2zm(0L);
new->q1=tree->o;
new->q2.flags=0;
new->typf=POINTER_TYPE(v->vtyp);
new->q2.val.vmax=sizetab[new->typf];
add_IC(new);
free_expression(tree);
vlas=1;
}
/* reset sp to remove variable-length-arrays */
void freevl(void)
{
np tree,ds;
Var *fv;
dontdelete=1; /* never remove them, otherwise, fix_vla_jump get confused */
if(!find_ext_var("__resetvlasp")){
struct_declaration *sd=mymalloc(sizeof(*sd));
type *t=new_typ();
sd->count=1;
sd->sl=mymalloc(sizeof(struct_list));
(*sd->sl)[0].storage_class=AUTO;
(*sd->sl)[0].styp=clone_typ(block_vla[nesting]->vtyp);
(*sd->sl)[0].reg=FREEVLA_REG;
t->flags=FUNKT;
t->exact=add_sd(sd,FUNKT);
t->next=new_typ();
t->next->flags=VOID;
fv=add_var("__resetvlasp",t,EXTERN,0);
fv->fi=new_fi();
fv->fi->flags|=(ALL_USES|ALL_MODS);
fv->fi->inline_asm=mystrdup(FREEVLA_INLINEASM);
}
if(nesting==1){
clear_main_ret();
gen_label(return_label);
did_return_label=1;
}
ds=new_node();
ds->flags=IDENTIFIER;
ds->identifier=empty;
ds->dsize=block_vla[nesting];
ds->val.vmax=l2zm(0L);
ds->ntyp=clone_typ(ds->dsize->vtyp);
ds->left=ds->right=0;
ds->o.flags=VAR;
ds->o.v=ds->dsize;
ds->o.val.vmax=l2zm(0L);
if(!type_expression(ds,0)) ierror(0);
tree=gen_libcall("__resetvlasp",ds,0,0,0);
free_expression(tree);
dontdelete=0;
}
void clearvl(void)
{
llist *p,*n;
vlaadjust_list *vl,*vn;
/* look for stack-adjusts that have to be removed */
vl=vlaadjusts[nesting];
while(vl){
int ln;
IC *ic=vl->branch;
if(ic){
ln=ic->typf;
if(ic->code!=BRA) ierror(0);
p=vladeflabels[nesting];
while(p){
if(p->label==ln) break;
p=p->next;
}
if(!p){
ic=ic->prev;
while(ic!=vl->first->prev){
if(!ic) ierror(0);
ic->code=NOP;
ic->q1.flags=ic->q2.flags=ic->z.flags=0;
ic=ic->prev;
}
}
}
vn=vl->next;
free(vl);
vl=vn;
}
freevl();
block_vla[nesting]=0;
p=vladeflabels[nesting];
while(p){
n=p->next;
free(p);
p=n;
}
p=vlajmplabels[nesting];
while(p){
n=p->next;
free(p);
p=n;
}
vladeflabels[nesting]=vlajmplabels[nesting]=0;
vlaadjusts[nesting]=0;
}
/* Handle a stack of stored sp variables when traversing an IC list; */
void vla_nesting(IC *p,Var **vn,int *nest)
{
if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"__oldvlasp")){
IC *p2=p->next;
while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next;
if(!p2||p2->code!=GETRETURN||(p2->z.flags&(VAR|DREFOBJ))!=VAR) ierror(0);
/*printf("found save sp to %p\n",p2->z.v);*/
vn[*nest]=p2->z.v;
(*nest)++;
vn[*nest]=0;
if(*nest>=MAXN) ierror(0);
return;
}
if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"__resetvlasp")){
/*printf("found reset\n");*/
if(*nest<=0) ierror(0);
(*nest)--;
return;
}
}
static int return_vla_nest;
static Var *return_last_vlasp;
/* Find the stack pointer that is needed when jumping to label lab */
Var *vla_find_sp(int lab)
{
IC *p;int nest=0;
static Var *vn[MAXN];
for(p=first_ic;p;p=p->next){
if(p->code==LABEL&&p->typf==lab){
return_vla_nest=nest;
return_last_vlasp=vn[nest];
if(nest<=0)
return 0;
else
return vn[nest-1];
}
vla_nesting(p,vn,&nest);
}
ierror(0);
}
void vla_jump_fix(void)
{
IC *p;int nest=0;
static Var *vn[MAXN],*savedsp;
if(DEBUG&1) printf("searching for vla-jump-fixes\n");
for(p=first_ic;p;p=p->next){
/*pric2(stdout,p);*/
if(p->code>=BEQ&&p->code<=BRA){
/*printf("jump found\n");*/
p->savedsp=0;
if(1/*nest>0*/){
/*printf("is in vla context!\n");*/
savedsp=vla_find_sp(p->typf);
if(return_vla_nest>nest||(nest>0&&return_vla_nest==nest&&savedsp!=vn[nest-1])){
err_ic=p;
error(351);
}else if(nest==0||savedsp==vn[nest-1]){
/*printf("jump within the same context\n");*/
}else{
if(vn[nest]){
if(DEBUG&1) printf("have to set sp to %p\n",return_last_vlasp);
p->savedsp=return_last_vlasp;
}else{
int ndiff=nest-return_vla_nest-1;
IC *p2;
/*printf("have to search oldsp ndiff=%d\n",ndiff);*/
for(p2=p->prev;p2;p2=p2->prev){
if(p2->code==CALL&&(p2->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p2->q1.v->identifier,"__oldvlasp")){
if(ndiff==0){
/*printf("found savesp\n");*/
p2=p2->next;
while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next;
if(!p2||p2->code!=GETRETURN) ierror(0);
if((p2->z.flags&(VAR|DREFOBJ))!=VAR) ierror(0);
/*printf("found oldsp %p\n",p2->z.v);*/
p->savedsp=p2->z.v;
break;
}
ndiff--;
}
if(p2->code==CALL&&(p2->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p2->q1.v->identifier,"__resetvlasp")){
ndiff++;
}
}
if(!p2) ierror(0);
}
}
}else{
/*printf("not in vla context\n");*/
}
}
vla_nesting(p,vn,&nest);
}
for(p=first_ic;p;p=p->next){
if(p->code>=BEQ&&p->code<=BRA){
if(p->savedsp){
IC *merkfic,*merklic,*newcode,*m,*new,*setr=0;
np ds,tree;
if(DEBUG&1) printf("generating sp-adjust\n");
merkfic=first_ic;merklic=last_ic;
first_ic=0;last_ic=0;
ds=new_node();
ds->flags=IDENTIFIER;
ds->identifier=empty;
ds->dsize=p->savedsp;
ds->val.vmax=l2zm(0L);
ds->ntyp=clone_typ(ds->dsize->vtyp);
ds->left=ds->right=0;
ds->o.flags=VAR;
ds->o.v=ds->dsize;
ds->o.val.vmax=l2zm(0L);
if(!type_expression(ds,0)) ierror(0);
tree=gen_libcall("__resetvlasp",ds,0,0,0);
free_expression(tree);
newcode=first_ic;
first_ic=merkfic;last_ic=merklic;
if(p->code==BRA){
/* check if the branch was preceded by a SETRETURN */
IC *p2=p->prev;
while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG))
p2=p2->prev;
if(p2->code==SETRETURN&&p2->z.reg)
setr=p2;
}else{
new=new_IC();
new->typf=++label;
if(p->code==BEQ) new->code=BRA;
else if(p->code==BNE) new->code=BEQ;
else if(p->code==BLT) new->code=BGE;
else if(p->code==BGT) new->code=BLE;
else if(p->code==BLE) new->code=BGT;
else if(p->code==BGE) new->code=BLT;
insert_IC(p->prev,new);
}
while(newcode){
m=newcode->next;
insert_IC(p->prev,newcode);
newcode=m;
}
if(p->code!=BRA){
p->code=BRA;
new=new_IC();
new->code=LABEL;
new->typf=label;
insert_IC(p,new);
}
if(setr){
/* save the return value to save it from being overwritten */
/* could be optimized further */
Var *v;
if(ISSCALAR(setr->typf)){
static type t={0};
t.flags=setr->typf;
v=add_tmp_var(clone_typ(&t));
}else ierror(0);
new=new_IC();
*new=*setr;
new->q1.flags=VAR;
new->q1.v=v;
new->q1.val.vmax=l2zm(0L);
setr->z=new->q1;
setr->code=ASSIGN;
insert_IC(p->prev,new);
}
}
}
}
}
Var *add_tmp_var(type *t)
{
t->flags&=NU;
return add_var(empty,t,AUTO,0);
}
Var *add_var(char *identifier, type *t, int storage_class,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. */
{
Var *new;int f;
struct_declaration *sd;
static zmax paroffset;
zmax al;
/*if(*identifier==0) return;*/ /* sollte woanders bemaekelt werden */
if(DEBUG&2) printf("add_var(): %s\n",identifier);
#ifdef HAVE_TARGET_VARHOOK_PRE
add_var_hook_pre(identifier,t,storage_class,clist);
#endif
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
if(ISFUNC(t->flags&NQ)&&(ISARRAY(t->next->flags)||ISFUNC(t->next->flags)))
error(25);
new=mymalloc(sizeof(Var));
if(!*identifier&&identifier!=empty) ierror(0);
new->clist=clist;
new->vtyp=t;
new->storage_class=storage_class&PLAIN_STORAGE_CLASS;
new->reg=0;
new->vattr=0;
new->next=0;
new->flags=0;
new->inr=0;
new->fi=0;
new->nesting=nesting;
new->filename=filename;
new->line=line;
new->dfilename=0;
new->dline=0;
new->description=0;
new->tunit=last_tunit;
new->inline_copy=0;
new->index=-1;
#ifdef HAVE_TARGET_ATTRIBUTES
new->tattr=0;
#endif
/* if((storage_class&PLAIN_STORAGE_CLASS)==STATIC||(storage_class&PLAIN_STORAGE_CLASS)==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;
if(!(storage_class&DBLPUSH)){
if((storage_class&OLDSTYLE)&&(t->flags&NQ)==FLOAT)
new->flags|=CONVPARAMETER;
storage_class&=~PARAMETER;
}
}
if(DEBUG&2) printf("storage_class=%d\n",storage_class);
if(DEBUG&2) printf("max_offset=%ld\n",zm2l(max_offset));
if(is_vlength(t)&&storage_class!=AUTO&&storage_class!=REGISTER)
error(315);
if((storage_class&PLAIN_STORAGE_CLASS)==REGISTER) new->priority=registerpri; else new->priority=0;
if(/*nesting==0&&*/new->storage_class==EXTERN){
int m=nesting;
nesting=0;
new->identifier=add_identifier(identifier,strlen(identifier));
nesting=m;
if(last_ext){
last_ext->next=new;
last_ext=new;
}else{
first_ext=last_ext=new;
vl0=first_ext;
}
if(hash_ext) add_hashentry(hash_ext,new->identifier,new);
}else{
new->identifier=add_identifier(identifier,strlen(identifier));
if(last_var[nesting]){
new->offset=zmadd(last_var[nesting]->offset,szof(last_var[nesting]->vtyp));
last_var[nesting]->next=new;
last_var[nesting]=new;
}else{
new->offset=l2zm(0L);
paroffset=l2zm(0L);;
first_var[nesting]=last_var[nesting]=new;
if(nesting==0) vl1=new;
if(nesting==1) vl2=new;
}
}
f=t->flags&NQ;
if((storage_class&PLAIN_STORAGE_CLASS)==AUTO||(storage_class&PLAIN_STORAGE_CLASS)==REGISTER){
if(DEBUG&2) printf("auto\n");
al=falign(t);
if((c_flags_val[0].l&2)&&nesting==1&&!(storage_class&PARAMETER)){
new->offset=max_offset;
}else{
if(storage_class&PARAMETER){
new->offset=paroffset;
if(align_arguments)
new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(al,l2zm(1L))),al),al);
}else{
new->offset=local_offset[nesting];
new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(al,l2zm(1L))),al),al);
}
}
if(storage_class&PARAMETER){
new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(stackalign,l2zm(1L))),stackalign),stackalign);
if(ISINT(f)&&f<INT&&!short_push){
/* Integer-Erweiterungen fuer alle Funktionsparameter */
paroffset=zmadd(new->offset,sizetab[INT]);
}else{
if(f==FLOAT&&(storage_class&OLDSTYLE)){
/* Bei alten Funktionen werden FLOAT als DOUBLE uebergeben */
new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(align[DOUBLE],l2zm(1L))),align[DOUBLE]),align[DOUBLE]);
paroffset=zmadd(new->offset,sizetab[DOUBLE]);
}else{
paroffset=zmadd(new->offset,szof(new->vtyp));
}
}
}else{
local_offset[nesting]=zmadd(new->offset,szof(new->vtyp));
}
if(!(storage_class&PARAMETER))
if(zmleq(max_offset,local_offset[nesting])) max_offset=local_offset[nesting];
if(DEBUG&2) printf("max_offset=%ld\n",zm2l(max_offset));
}
if((storage_class&PLAIN_STORAGE_CLASS)==STATIC) new->offset=l2zm((long)++label);
if(storage_class&PARAMETER){
if(DEBUG&2) printf("parameter\n");
if(ISINT(f)&&f<INT&&!zmleq(sizetab[INT],sizetab[f])){
if(BIGENDIAN){
new->offset=zmadd(new->offset,zmsub(sizetab[INT],sizetab[f]));
}else{
if(!LITTLEENDIAN)
ierror(0);
}
}
if((storage_class&OLDSTYLE)&&f==FLOAT){
/* Bei alten Funktionen werden DOUBLE nach FLOAT konvertiert */
if(!(storage_class&REGPARM)){
#if HAVE_LIBCALLS
static type dt={DOUBLE},ft={FLOAT};
static node n,nn;
IC *conv=new_IC();
n.flags=REINTERPRET;
n.left=&nn;
n.ntyp=&dt;
nn.flags=IDENTIFIER;
nn.identifier=identifier;
nn.ntyp=&ft;
nn.o.flags=VAR|DONTREGISTERIZE;
nn.o.v=new;
nn.o.val.vmax=l2zm(0L);
n.o=nn.o;
convert(&n,FLOAT);
conv->code=ASSIGN;
conv->typf=FLOAT;
conv->q1=n.o;
conv->z.v=new;
conv->z.flags=VAR;
conv->z.val.vmax=l2zm(0L);
conv->q2.val.vmax=sizetab[FLOAT];
conv->z.v=new;
add_IC(conv);
#else
IC *conv=new_IC();
conv->code=CONVERT;
conv->typf=FLOAT;
conv->typf2=DOUBLE;
conv->q1.flags=VAR|DONTREGISTERIZE;
conv->z.flags=VAR;
conv->q2.flags=0;
conv->q1.v=conv->z.v=new;
conv->q1.val.vmax=conv->z.val.vmax=l2zm(0);
add_IC(conv);
#endif
}
new->flags|=CONVPARAMETER;
}
new->offset=zmsub(l2zm(0L),zmadd(maxalign,new->offset));
}
if((storage_class&PLAIN_STORAGE_CLASS)==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;
}
if(is_vlength(new->vtyp))
create_allocvl(new);
#ifdef HAVE_TARGET_VARHOOK_POST
add_var_hook_post(new);
#endif
return(new);
}
void free_var(Var *p)
/* Gibt Variablenliste inkl. Typ, aber ohne Identifier frei. */
{
Var *merk;
while(p){
if(!*p->identifier&&p->identifier!=empty) ierror(0);
free(p->description);
free(p->vattr);
merk=p->next;
if(!(p->flags&USEDASADR)&&(p->storage_class==AUTO||p->storage_class==REGISTER)){
if(*p->identifier&&!(p->flags&USEDASDEST)&&ISSCALAR(p->vtyp->flags)) error(64,p->identifier);
if(*p->identifier&&!(p->flags&USEDASSOURCE)&&ISSCALAR(p->vtyp->flags)) 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;
}
}
Var *find_ext_var(char *identifier)
{
Var *v;int l;
if(misracheck) l=strlen(identifier);
if(hash_ext) return find_name(hash_ext,identifier);
for(v=first_ext;v;v=v->next){
if(!strcmp(v->identifier,identifier)) return v;
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}
return 0;
}
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,l;Var *v;
if(identifier==0||*identifier==0) return 0;
if(misracheck) l=strlen(identifier);
for(i=nesting;i>=endnesting;i--){
for(v=first_var[i];v;v=v->next){
if(!strcmp(v->identifier,identifier))
return v;
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}
}
if(endnesting==0){
v=find_ext_var(identifier);
if(v&&!(v->flags&NOTINTU))
return v;
else
return 0;
}else
return 0;
}
#ifdef HAVE_MISRA
/* removed */
/* removed */
#endif
int check_zero_initialisation(const_list* cl, int typ)
{
if (cl->next) return 0;
if (cl->tree) return 0;
if (cl->other) {
return check_zero_initialisation(cl->other,typ);
} else {
eval_const(&cl->val,typ);
if ( (zmeqto(vmax,l2zm(0L))) && (zumeqto(vumax,ul2zum(0UL))) && (zldeqto(vldouble,d2zld(0.0))) ) {
return 1;
}
}
return 0;
}
/* decide whether a initialization shall be performed only be generated code
or if a table copy should be used first */
int use_only_dyn_init(zmax sz,zmax dyn_sz,zmax const_sz,int dyn_cnt,int const_cnt)
{
if(zmleq(sz,l2zm(clist_copy_stack)))
return 1;
if(zmeqto(dyn_sz,l2zm(0L)))
return 0;
if(!zmleq(zmdiv(sz,dyn_sz),l2zm(2L)))
return 0;
else
return 1;
}
void init_local_compound(Var *v)
{
if(v->storage_class==AUTO||v->storage_class==REGISTER){
IC *new;
/* Initialisierung von auto-Variablen */
new=new_IC();
new->code=ASSIGN;
new->typf=v->vtyp->flags;
new->q2.flags=0;
new->q2.val.vmax=szof(v->vtyp);
new->z.flags=VAR;
new->z.v=v;
new->z.val.vmax=l2zm(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;
add_IC(new);
/* v->clist=0;*/
}else{
/* Array etc. */
Var *nv;
if(!ISSCALAR(v->vtyp->flags)&&!use_only_dyn_init(szof(v->vtyp),init_dyn_sz,init_const_sz,init_dyn_cnt,init_const_cnt)){
nv=add_var(empty,clone_typ(v->vtyp),STATIC,v->clist);
nv->flags|=DEFINED;
nv->dfilename=filename;
nv->dline=line;
nv->vtyp->flags|=CONST;
/* v->clist=0;*/
new->q1.flags=VAR;
new->q1.v=nv;
new->q1.val.vmax=l2zm(0L);
add_IC(new);
dynamic_init(v,v->vtyp,v->clist,0,1);
}else{
dynamic_init(v,v->vtyp,v->clist,0,0);
}
}
}
}
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
#endif
void var_declaration(void)
/* Bearbeitet eine Variablendeklaration und erzeugt alle */
/* noetigen Strukturen. */
{
type *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,diffunit=0,inline_flag;
Var *v;
char *vattr;
zumax mask;
int base_type;
#ifdef HAVE_TARGET_ATTRIBUTES
unsigned long tattr;
#endif
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
#endif
ts=declaration_specifiers();notdone=1;
storage_class=return_sc;hard_reg=return_reg;vattr=return_vattr;mask=return_mask;
inline_flag=return_inline;
#ifdef HAVE_ECPP
/* removed */
#endif
if(for_decl&&storage_class!=0&&storage_class!=AUTO&&storage_class!=REGISTER){
error(299);
storage_class=AUTO;
}
#ifdef HAVE_TARGET_ATTRIBUTES
tattr=return_tattr;
#endif
if(storage_class==EXTERN) extern_flag=1; else extern_flag=0;
killsp();
if(ctok->type==SEMIC){
if(!ts) error(0);
if(storage_class||(!ISSTRUCT(ts->flags)&&!ISUNION(ts->flags)&&(ts->flags&NQ)!=INT))
error(36);
freetyp(ts);
next_token();killsp();
return;
}
if(nesting==0&&(storage_class==AUTO||storage_class==REGISTER))
{error(66);storage_class=EXTERN;}
if(!ts){
if(nesting<=1){
ts=new_typ();
ts->flags=INT;ts->next=0;
makeint=1;
if(!storage_class) storage_class=EXTERN;
#ifdef HAVE_MISRA
/* removed */
#endif
error(67);
}else{
error(365);
}
}
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));
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
#ifdef HAVE_EXT_TYPES
conv_typ(t);
#endif
if(!ISFUNC(t->flags)){
isfunc=0;
if(inline_flag) error(301);
}else{
isfunc=1;
#ifdef HAVE_MISRA
/* removed */
#endif
if(storage_class!=STATIC&&storage_class!=TYPEDEF) storage_class=EXTERN;
}
ident=imerk; /* nicht unbedingt noetig ? */
if(!*vident){
free(ts);free(t);
error(36);return;
}
v=find_var(vident,oldnesting);
if(!v&&/*oldnesting==0&&*/storage_class==EXTERN&&cross_module&&(v=find_ext_var(vident))){
v->flags&=~NOTINTU;
diffunit=1;
/*FIXME: check auf doppelte Def. */
}
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
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&&!compatible_types(v->vtyp,t,NU|CONST|VOLATILE)){
if(ISFUNC(t->flags)&&!ISFUNC(v->vtyp->flags))
error(361,vident);
else
error(68,vident);
#ifdef HAVE_MISRA
/* removed */
#endif
}
if((storage_class!=v->storage_class&&!extern_flag)||hard_reg!=v->reg)
error(28,v->identifier);
if(!isfunc&&!extern_flag) v->flags|=TENTATIVE;
}
#ifdef HAVE_TARGET_ATTRIBUTES
{
int i;
for(i=0;g_attr_name[i];i++){
if((v->tattr&(1L<<i))!=(tattr&(1L<<i))) error(228,vident,g_attr_name[i]);
}
v->tattr=tattr;
}
#endif
if(vattr){
if(!v->vattr||!strstr(v->vattr,vattr)){
error(370,v->identifier,vattr,v->vattr?v->vattr:empty);
add_attr(&v->vattr,vattr);
}
if(ISFUNC(v->vtyp->flags)) fi_from_attr(v);
}
if(!isfunc){
if(!ISARRAY(t->flags)||!zmeqto(t->size,l2zm(0L))){
free(v->vtyp);
v->vtyp=t;
}
}else{
om=v->vtyp;
if(t->exact->count>0){
old=v->vtyp;v->vtyp=t;
}
}
}
#ifdef HAVE_TARGET_VARHOOK_POST
add_attr_haddecl=v;
add_var_hook_post(v);
add_attr_haddecl=0;
#endif
}else{
had_decl=0;
#ifdef HAVE_MISRA
/* removed */
#endif
if(isfunc&&ctok->type!=COMMA&&ctok->type!=SEMIC&&ctok->type!=RPAR&&ctok->type!=ASGN&&nesting>0) nesting--;
if(!zumeqto(mask,ul2zum(0UL))){
sprintf(vident+strlen(vident),".%lu",zum2ul(mask));
}
v=add_var(vident,t,storage_class,0);
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
v->reg=hard_reg;
if(vattr)
add_attr(&v->vattr,vattr);
if(ISFUNC(v->vtyp->flags))
fi_from_attr(v);
#ifdef HAVE_TARGET_ATTRIBUTES
v->tattr=tattr;
#endif
if(isfunc&&ctok->type!=COMMA&&ctok->type!=SEMIC&&ctok->type!=RPAR&&ctok->type!=ASGN&&nesting>=0) nesting++;
if(!v) ierror(0);
else{
if(!isfunc&&!extern_flag){
v->flags|=TENTATIVE;
if(nesting>0){
v->flags|=DEFINED;
v->dfilename=filename;
v->dline=line;
}
}
}
om=0;
}
if(isfunc&&inline_flag){
v->flags|=INLINEFUNC;
if(extern_flag) v->flags|=INLINEEXT;
}
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
if(disallow_statics&&v->storage_class==STATIC&&*v->identifier&&!is_const(v->vtyp))
error(302,v->identifier);
killsp();
/* Inline-Assembler-Code in Funktionsdeklarationen */
if(ctok->type==ASGN&&ISFUNC(v->vtyp->flags)&&(header_cnt>0||!(c_flags[7]&USEDFLAG))){
np tree;
next_token();killsp();
if(v->fi){free(v->fi->inline_asm);v->fi->inline_asm=0;}
if(!v->fi) v->fi=new_fi();
v->fi->inline_asm=get_string();
/*STRBACK(v->fi->inline_asm);*/
mdef=1;
}else{
/*if(v->fi){free(v->fi->inline_asm);v->fi->inline_asm=0;}*/
}
/* Initialisierung von Variablen bei Deklaration */
if(ctok->type==ASGN){
next_token();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;
v->dfilename=filename;
v->dline=line;
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}
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;}
}
#ifdef HAVE_MISRA
/* removed */
/* removed */
#endif
init_dyn_sz=l2zm(0L);
init_dyn_cnt=0;
init_const_sz=l2zm(0L);
init_const_cnt=0;
v->clist=initialization(v->vtyp,v->storage_class==AUTO||v->storage_class==REGISTER,0,0,0,0);
/* MISRA Rule 9.2 violation checking and error reporting */
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
if(v->clist){
if(ISARRAY(v->vtyp->flags)&&zmeqto(v->vtyp->size,l2zm(0L))){
const_list *p=v->clist;
while(p){v->vtyp->size=zmadd(p->idx,l2zm(1L));p=p->next;}
if(v->storage_class==AUTO||v->storage_class==REGISTER){
local_offset[nesting]=zmadd(local_offset[nesting],szof(v->vtyp));
if(zmleq(max_offset,local_offset[nesting])) max_offset=local_offset[nesting];
}
}
if(v->storage_class==AUTO||v->storage_class==REGISTER){
init_local_compound(v);
}else if(c_flags[19]&USEDFLAG){
/* Ohne Optimierung gleich erzeugen; das ist noch */
/* etwas von der genauen Implementierung der Liste */
/* der Variablen abhaengig. */
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(ctok->type==COMMA) {next_token();killsp();mdef=1;} else notdone=0;
}
freetyp(ts);
if(ISFUNC(t->flags)&&v->reg)
t->next->reg=v->reg;
if(!mdef&&t&&(t->flags&NQ)==FUNKT&&ctok->type!=SEMIC){
/* Funktionsdefinition*/
int i,oldstyle=0;
#ifdef HAVE_MISRA
/* removed */
/* removed */
#endif
#ifdef HAVE_REGPARMS
treg_handle reg_handle;
#endif
if(DEBUG&1) printf("Funktionsdefinition! %s %p\n",v->identifier,(void *)v);
{
int i;
for(i=1;i<=MAXR;i++) {regs[i]=regused[i]=regsa[i];regsbuf[i]=0;}
}
cur_func=v->identifier;
cur_funcv=v;
if(only_inline==2) only_inline=0;
if(nesting<1) enter_block();
if(nesting>1) error(32);
if(v->flags&DEFINED){
if(!inline_flag||!cross_module){
error(33,v->identifier);
}else{
if(v->fi->first_ic){
free_IC(v->fi->first_ic);
v->fi->first_ic=0;
}
}
}else{
v->flags|=DEFINED;
v->dfilename=filename;
v->dline=line;
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}
if(storage_class!=EXTERN&&storage_class!=STATIC) error(34);
if(extern_flag&&!inline_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(!ecpp&&ctok->type!=LBRA){
/* alter Stil */
type *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(ISARRAY(ts->flags)) ts->flags=POINTER_TYPE(ts);
/* typ() in *typ() */
if(ISFUNC(ts->flags)){
type *new=new_typ();
new->flags=POINTER_TYPE(ts);
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(ctok->type==COMMA) {next_token();killsp();} else notdone=0;
}
if(nt) freetyp(nt);
if(ctok->type==SEMIC){
next_token();killsp();
}else{
error(54);
while(ctok->type!=LBRA&&ctok->type!=SEMIC){next_token();killsp();}
}
}
if(!ecpp&&t->exact->count==0){
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=new_typ();
sl[0].styp->flags=VOID;
sl[0].styp->next=0;
sl[0].reg=0;
nesting--;
add_sl(t->exact,&sl);
nesting++;
}
if(om&&om->exact&&!compare_sd(om->exact,t->exact)) {
error(123);
#ifdef HAVE_MISRA
/* removed */
#endif
}
nocode=0;currentpri=1;
/* enter_block();*/
local_offset[1]=l2zm(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(!ffreturn(return_typ)&&(return_typ->flags&NQ)!=VOID){
/* Parameter fuer die Rueckgabe von Werten, die nicht in einem */
/* Register sind. */
type *rt=new_typ();int reg;
rt->flags=POINTER_TYPE(return_typ);rt->next=return_typ;
#ifdef HAVE_REGPARMS
reg=reg_parm(&reg_handle,rt,0,v->vtyp);
if(!reg){
return_var=add_var(empty,clone_typ(rt),AUTO|PARAMETER|oldstyle,0);
}else{
return_var=add_var(empty,clone_typ(rt),reg<0?(AUTO|PARAMETER|REGPARM|DBLPUSH|oldstyle):(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;
return_var->dfilename=filename;
return_var->dline=line;
free(rt);
}
}
first_ic=last_ic=0;ic_count=0;max_offset=l2zm(0L);
if(!zmleq(local_offset[1],Z0)) max_offset=local_offset[1];
for(i=0;i<t->exact->count;i++){
/* TODO: missing pointer for struct return */
#ifdef HAVE_REGPARMS
int didrp=0;
if((*t->exact->sl)[i].styp){
int tr;
tr=reg_parm(&reg_handle,(*t->exact->sl)[i].styp,0,t);
didrp=1;
if(!(*t->exact->sl)[i].reg) (*t->exact->sl)[i].reg=tr;
}
#endif
if(!(*t->exact->sl)[i].styp&&*(*t->exact->sl)[i].identifier){
type *nt;
#ifdef HAVE_MISRA
/* removed */
#endif
nt=new_typ();
nt->flags=INT;
(*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){
Var *tmp;int sc,tr;
sc=((*t->exact->sl)[i].storage_class|PARAMETER|oldstyle);
#ifdef HAVE_REGPARMS
if(!didrp){
if(!t->exact->sl) ierror(0);
if(!(*t->exact->sl)[i].styp) ierror(0);
tr=reg_parm(&reg_handle,(*t->exact->sl)[i].styp,0,t);
if(!(*t->exact->sl)[i].reg) (*t->exact->sl)[i].reg=tr;
}
#endif
if((*t->exact->sl)[i].reg>0) sc|=REGPARM;
if((*t->exact->sl)[i].reg<0) sc|=(REGPARM|DBLPUSH);
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;
tmp->dfilename=filename;
tmp->dline=line;
if(oldstyle){
#ifdef HAVE_MISRA
/* removed */
#endif
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]=l2zm(0L);*/
return_label=++label;
function_calls=0;float_used=0;has_return=0;goto_used=0;vlas=0;
did_return_label=0;
for(i=1;i<=MAXR;i++) simple_scratch[i]=0;
if(v->storage_class==EXTERN&&(v->flags&INLINEFUNC))
disallow_statics=1;
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
#ifdef HAVE_MISRA
/* removed */
/* removed */
#endif
if(c99){
/* c99 predefined __func__ */
type *ft=new_typ();
Var *fnc;
/* create type */
ft->flags=ARRAY;
ft->size=l2zm((long)strlen(cur_func)+1);
ft->next=new_typ();
ft->next->flags=CONST|CHAR;
/* use string_expression() to create const_list */
fnc=add_var("__func__",ft,STATIC,cl_from_string(cur_func,cur_func+strlen(cur_func)));
fnc->flags|=DEFINED;
}
/* Generate intermediate code for function */
compound_statement();
#ifdef HAVE_MISRA
/* removed */
#endif
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
cur_funcv=0;
disallow_statics=0;
if(block_vla[nesting]) clearvl();
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
if(!did_return_label){
clear_main_ret();
gen_label(return_label);
}
/* backpatch code for jumps out of vla-scope if necessary */
if(vlas)
vla_jump_fix();
if(cross_module){
if(!v->fi) v->fi=new_fi();
v->fi->statics=first_var[0];
}else 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(optflags,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)){
memset(regs_modified,0,RSIZE);
gen_code(out,first_ic,v,max_offset);
static_stack_check(v);
v->flags|=GENERATED;
#ifdef HAVE_REGS_MODIFIED
if(!v->fi) v->fi=new_fi();
if(v->fi->flags&ALL_REGS)
{
int i;
for(i=1;i<=MAXR;i++){
if(reg_pair(i,&rp)){
if(BTST(regs_modified,i)){
BSET(regs_modified,rp.r1);
BSET(regs_modified,rp.r2);
}else{
if(BTST(regs_modified,rp.r1)||BTST(regs_modified,rp.r2))
BSET(regs_modified,i);
}
}
}
memcpy(v->fi->regs_modified,regs_modified,RSIZE);
v->fi->flags|=ALL_REGS;
}
#endif
}
/*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(cross_module){
if(!v->fi) v->fi=new_fi();
v->fi->first_ic=first_ic;
v->fi->last_ic=last_ic;
first_ic=last_ic=0;
}
if(v->fi&&v->fi->first_ic){
Var *vp;
if(DEBUG&1) printf("leave block %d (inline-version)\n",nesting);
if(block_vla[nesting]) clearvl();
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&&!cross_module) gen_vars(merk_varf);
if(first_llist) free_llist(first_llist);
first_llist=0;
if(first_clist) free_clist(first_clist);
first_clist=0;
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];*/
if(!cross_module){
vp=merk_varf;
while(vp){
if(vp->storage_class==AUTO||vp->storage_class==REGISTER){
/*if(DEBUG&1024) printf("handling variable %s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp);*/
if(!zmleq(l2zm(0L),vp->offset)){
vp->offset=l2zm(0L);
if(DEBUG&1024) printf("converted parameter <%s>(%ld) for inlining\n",vp->identifier,(long)zm2l(vp->offset));
}else vp->offset=l2zm(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(ctok->type==SEMIC) next_token(); else error(54);
if(ISFUNC(t->flags)&&t->exact){
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 compatible_types(type *a,type *b,int qual)
/* Vergleicht, ob Typ beider Typen gleich ist, const/volatile */
/* werden laut ANSI nicht beruecksichtigt. */
{
struct_declaration *sd;
int af=a->flags&qual,bf=b->flags&qual;
if(af!=bf) return(0);
af&=NQ;bf&=NQ;
if(ISFUNC(af)){
if(a->exact->count&&!compare_sd(a->exact,b->exact)) return(0);
}
if(ISSTRUCT(af)||ISUNION(af)){
if(cross_module&&a->exact->tunit!=b->exact->tunit) return 1;
if(a->exact!=b->exact) return(0);
}
if(ISARRAY(af)){
if(!zmeqto(a->size,l2zm(0L))&&!zmeqto(b->size,l2zm(0L))&&!zmeqto(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);
if(qual!=NQ) qual=(NU|CONST|VOLATILE);
return(compatible_types(a->next,b->next,qual));
}
int compare_sd(struct_declaration *a,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&&!compatible_types((*a->sl)[i].styp,(*b->sl)[i].styp,NU)) return(0);
if((*a->sl)[i].reg!=(*b->sl)[i].reg) {error(368);return 0;}
#ifdef HAVE_MISRA
/* removed */
/* removed */
#endif
}
return(1);
}
void free_clist(const_list *p)
/* Gibt clist frei. */
{
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 *,type *,const_list *);
void gen_vars(Var *v)
/* Generiert Variablen. */
{
int mode,al,first_pass=1;Var *p;
if(errors!=0||(c_flags[5]&USEDFLAG)) return;
if(optsize)
al=zm2l(maxalign);
else
al=0;
for(;al>=0;al--){
for(mode=0;mode<3;mode++){
int i,flag;
for(p=v;p;p=p->next){
if(p->flags&NEEDS) continue;
if(optsize&&zm2l(falign(p->vtyp))!=al)
continue;
if(cross_module&&!(p->flags&REFERENCED)) continue;
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;
if(p->storage_class==STATIC&&p->nesting>0&&!(p->flags&(USEDASSOURCE|USEDASDEST))) continue;
/* erst konstante initialisierte Daten */
if(mode==0){
if(!p->clist) continue;
if(!(p->vtyp->flags&(CONST|STRINGCONST))){
type *t=p->vtyp;int f=0;
do{
if(t->flags&(CONST|STRINGCONST)) break;
if(!ISARRAY(t->flags)){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))){
if(!((p->vtyp->flags&NQ)==FUNKT)||!p->fi||!p->fi->inline_asm){
if(mask_opt){
if((p->flags&PRINTFLIKE)&&!strstr(p->identifier,".")) needs("vfprintf");
if((p->flags&SCANFLIKE)&&!strstr(p->identifier,".")) needs("vfscanf");
}
gen_var_head(out,p);
}
if(p->storage_class==STATIC&&(!p->fi||!p->fi->inline_asm)) error(127,p->identifier);
continue;
}else{
/*gen_align(out,falign(p->vtyp));*/
}
if(!((p->vtyp->flags&NQ)==FUNKT)||!p->fi||!p->fi->inline_asm){
if(mask_opt){
if((p->flags&PRINTFLIKE)&&!strstr(p->identifier,".")) needs("vfprintf");
if((p->flags&SCANFLIKE)&&!strstr(p->identifier,".")) needs("vfscanf");
}
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;
}else if(p->flags&INLINEEXT){
/* a function was declared extern inline and defined;
we have to create external linkage */
int m=p->flags;
/* pretend, it was only declared, but not defined and remove
INLINEEXT */
p->flags&=~(DEFINED|INLINEEXT);
gen_var_head(out,p);
p->flags|=DEFINED;
}
}
}
first_pass=0;
}
}
if(mask_opt){
for(p=v;p;p=p->next)
if(p->flags&NEEDS) gen_var_head(out,p);
}
}
/* creates code that dynamically initializes a variable */
void dynamic_init(Var *v,type *t,const_list *cl,zmax of,int noconst)
{
int f=t->flags;
if(ISARRAY(f)){
zmax i;
for(i=l2zm(0L);!zmleq(t->size,i);i=zmadd(i,l2zm(1L))){
if(cl&&zmeqto(cl->idx,i)){
dynamic_init(v,t->next,cl->other,of,noconst);
cl=cl->next;
}else{
dynamic_init(v,t->next,0,of,noconst);
}
of=zmadd(of,szof(t->next));
}
}else if(ISUNION(f)&&(!cl||!cl->tree)){
dynamic_init(v,(*t->exact->sl)[cl?zm2l(cl->idx):0].styp,cl?cl->other:0,of,noconst);
}else if(ISSTRUCT(f)&&(!cl||!cl->tree)){
zmax al;int fl;type *st;
int bfo,i;
for(i=0;i<t->exact->count&&cl;i++){
if(!cl->other){
if(errors==0)
ierror(0);
return;
}
st=(*t->exact->sl)[i].styp;
al=(*t->exact->sl)[i].align;
if(!(*t->exact->sl)[i].identifier) ierror(0);
bfo=(*t->exact->sl)[i].bfoffset;
if(!zmeqto(zmmod(of,al),l2zm(0L))){
of=zmadd(of,zmsub(al,zmmod(of,al)));
}
if(bfo>=0){
int bfs=(*t->exact->sl)[i].bfsize;
static obj dest = {0};
dest.flags=VAR;
dest.v=v;
dest.val.vmax=of;
if(bfo==0){
/* first clear entire bitfield */
IC *new=new_IC();
new->code=ASSIGN;
new->z=dest;
new->typf=st->flags;
new->q2.val.vmax=sizetab[st->flags&NQ];
new->q1.flags=KONST;
new->q1.val.vmax=l2zm(0L);
eval_const(&new->q1.val,MAXINT);
insert_const(&new->q1.val,st->flags&NU);
add_IC(new);
}
/* bitfield */
if(!zmeqto(cl->idx,l2zm(i))||!cl->other){
/* nothing to do, initialized before */
}else if(cl->other->tree){
obj dummy;
gen_IC(cl->other->tree,0,0);
convert(cl->other->tree,st->flags);
insert_bitfield(&dest,&cl->other->tree->o,&cl->other->tree->o,bfs,bfo,st->flags,1);
cl=cl->next;
}else{
static obj val = {0};
val.flags=KONST;
val.val=cl->other->val;
insert_bitfield(&dest,&val,&val,bfs,bfo,st->flags,1);
cl=cl->next;
}
if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){
of=zmadd(of,szof(st));
}
}else{
if(zmeqto(l2zm((long)i),cl->idx)){
dynamic_init(v,st,cl->other,of,noconst);
cl=cl->next;
}else
dynamic_init(v,st,0,of,noconst);
of=zmadd(of,szof(st));
}
}
for(;i<t->exact->count;i++){
st=(*t->exact->sl)[i].styp;
al=(*t->exact->sl)[i].align;
bfo=(*t->exact->sl)[i].bfoffset;
if(bfo>0) continue;
if(!zmeqto(zmmod(of,al),l2zm(0L))){
of=zmadd(of,zmsub(al,zmmod(of,al)));
}
dynamic_init(v,st,0,of,noconst);
of=zmadd(of,szof(st));
}
}else{
IC *new;
if(noconst&&(!cl||!cl->tree))
return;
new=new_IC();
new->code=ASSIGN;
new->z.flags=VAR;
new->z.v=v;
new->z.val.vmax=of;
new->typf=t->flags;
new->q2.val.vmax=szof(t);
if(!cl){
new->q1.flags=KONST;
gval.vmax=l2zm(0L);
eval_const(&gval,MAXINT);
insert_const(&new->q1.val,t->flags&NU);
}else if(cl->tree){
gen_IC(cl->tree,0,0);
if(ISSCALAR(t->flags))
convert(cl->tree,t->flags);
new->q1=cl->tree->o;
}else{
new->q1.flags=KONST;
new->q1.val=cl->val;
}
add_IC(new);
}
}
void gen_clist(FILE *f,type *t,const_list *cl)
/* Generiert dc fuer const_list. */
{
int i,bfo,bfs;zmax sz;zumax bfval=ul2zum(0UL);
#if 0
for(i=0;i<(int)szof(t);i++){
zuchar c;int s;
s=get_clist_byte(t,cl,i,&c);
printf("%03d: 0x%02x (%d)\n",i,(int)c,s);
}
#endif
if(ISARRAY(t->flags)){
for(sz=l2zm(0L);!zmleq(t->size,sz)&&cl;cl=cl->next){
if(!cl->other){ierror(0);return;}
if(!zmeqto(sz,cl->idx))
gen_ds(f,zmmult(zmsub(cl->idx,sz),szof(t->next)),t->next);
gen_clist(f,t->next,cl->other);
sz=zmadd(cl->idx,l2zm(1L));
}
if(!zmleq(t->size,sz)) gen_ds(f,zmmult(zmsub(t->size,sz),szof(t->next)),t->next);
return;
}
if(ISUNION(t->flags)){
int i=zm2l(cl->idx);
if(cl&&cl->tree){
/* union initialized by another union */
gen_ds(f,szof(t),t);
}else{
gen_clist(f,(*t->exact->sl)[i].styp,cl->other);
sz=zmsub(szof(t),szof((*t->exact->sl)[i].styp));
if(!zmeqto(sz,l2zm(0L))) gen_ds(f,sz,0);
}
return;
}
if(ISSTRUCT(t->flags)){
zmax al;int fl;type *st;
sz=l2zm(0L);
if(cl&&cl->tree){
/* initialized by another */
gen_ds(f,szof(t),t);
sz=zmadd(sz,szof(t));
}else{
for(i=0;i<t->exact->count&&cl;i++){
if(!cl->other){ierror(0);return;}
st=(*t->exact->sl)[i].styp;
al=(*t->exact->sl)[i].align;
if(!(*t->exact->sl)[i].identifier) ierror(0);
bfo=(*t->exact->sl)[i].bfoffset;
if(!zmeqto(zmmod(sz,al),l2zm(0L))){
gen_ds(f,zmsub(al,zmmod(sz,al)),0);
sz=zmadd(sz,zmsub(al,zmmod(sz,al)));
}
if(bfo>=0){
/* bitfield */
if((*t->exact->sl)[i].identifier[0]){
bfs=(*t->exact->sl)[i].bfsize;
if(zmeqto(l2zm((long)i),cl->idx)){
eval_const(&cl->other->val,st->flags);
cl=cl->next;
}else{
vumax=ul2zum(0UL);
}
vumax=zumand(vumax,zumsub(zumlshift(ul2zum(1UL),ul2zum((unsigned long)bfs)),ul2zum(1UL)));
bfval=zumor(bfval,zumlshift(vumax,ul2zum((unsigned long)bflayout(bfo,bfs,st->flags))));
}
if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){
/* last bitfield in integer */
const_list bfcl;
gval.vumax=bfval;
eval_const(&gval,UNSIGNED|MAXINT);
insert_const(&bfcl.val,st->flags&NU);
bfcl.tree=0;
gen_dc(f,st->flags&NU,&bfcl);
bfval=ul2zum(0L);
sz=zmadd(sz,szof(st));
}
}else{
if(zmeqto(l2zm((long)i),cl->idx)){
gen_clist(f,st,cl->other);
cl=cl->next;
}else
gen_ds(f,szof(st),st);
sz=zmadd(sz,szof(st));
}
}
for(;i<t->exact->count;i++){
st=(*t->exact->sl)[i].styp;
al=(*t->exact->sl)[i].align;
bfo=(*t->exact->sl)[i].bfoffset;
if(bfo>0) continue;
if(!zmeqto(zmmod(sz,al),l2zm(0L))){
gen_ds(f,zmsub(al,zmmod(sz,al)),0);
sz=zmadd(sz,zmsub(al,zmmod(sz,al)));
}
gen_ds(f,szof((*t->exact->sl)[i].styp),(*t->exact->sl)[i].styp);
sz=zmadd(sz,szof(st));
}
}
al=falign(t);
if(!zmeqto(zmmod(sz,al),l2zm(0L)))
gen_ds(f,zmsub(al,zmmod(sz,al)),0);
return;
}
if(cl->tree) cl->tree->o.am=0;
if(zmeqto(cl->idx,l2zm(-1L)))
gen_ds(f,szof(t),t);
else
gen_dc(f,t->flags&NU,cl);
}
/* finds the correct place in a const list to insert new initializer */
const_list *insert_cl(const_list *old,zmax idx)
{
const_list *p,*cl=0;
if(old&&zmleq(old->idx,idx)){
p=old;
do{
if(zmeqto(p->idx,idx)){
/* found existing entry */
cl=p;
break;
}
if(!p->next||!zmleq(p->next->idx,idx))
break;
p=p->next;
}while(p);
}else
p=0;
/* we need a new entry */
if(!cl){
cl=mymalloc(CLS);
cl->tree=0;
cl->other=0;
cl->idx=idx;
if(p){
cl->next=p->next;
p->next=cl;
}else
cl->next=old;
}
return cl;
}
const_list *designator(type *t,const_list *cl)
{
int f=t->flags&NQ;
np tree;
if(!c99) return 0;
if(ISARRAY(f)&&ctok->type==LBRK){
next_token();
killsp();
tree=expression();
if(ctok->type!=RBRK)
error(62);
else
{next_token();killsp();}
if(!type_expression(tree,0)){
/* error("incorrect constant expression");*/
}else{
if(tree->sidefx) error(60);
if(tree->flags!=CEXPR||!ISINT(tree->ntyp->flags)){
error(19);
}else{
/* check index for valid range */
eval_constn(tree);
if(!zmleq(l2zm(0L),vmax)) {error(354);vmax=l2zm(0L);}
if(!zmeqto(t->size,l2zm(0L))&&zmleq(t->size,vmax)) {error(354);vmax=l2zm(0L);}
cl=insert_cl(cl,vmax);
return cl;
}
}
}else if((ISSTRUCT(f)||ISUNION(f))&&ctok->type==DOT){
next_token();
killsp();
if(ctok->type!=NAME){
error(53);
}else{
int i,n=-1;
for(i=0;i<t->exact->count;i++)
if(!strcmp((*t->exact->sl)[i].identifier,ctok->name)) n=i;
if(n<0){
error(23,ctok->name);
return 0;
}
next_token();
killsp();
if(!ISUNION(f)||!cl)
cl=insert_cl(cl,l2zm((long)n));
return cl;
}
}
return 0;
}
/* declare a builtin function with up to two scalar arguments */
Var *declare_builtin(char *name,int ztyp,int q1typ,int q1reg,int q2typ,int q2reg,int nosidefx,char *asm)
{
struct_declaration *sd;
type *t;
Var *v;
int args;
if(!(v=find_ext_var(name))){
sd=mymalloc(sizeof(*sd));
if(q1typ==0) args=1;
else if(q2typ!=0) args=3;
else args=2;
sd->sl=mymalloc(args*sizeof(struct_list));
memset(sd->sl,0,args*sizeof(struct_list));
sd->count=args;
if(q1typ){
(*sd->sl)[0].styp=new_typ();
(*sd->sl)[0].styp->flags=q1typ;
(*sd->sl)[0].reg=q1reg;
}
if(q2typ){
(*sd->sl)[1].styp=new_typ();
(*sd->sl)[1].styp->flags=q2typ;
(*sd->sl)[1].reg=q2reg;
}
(*sd->sl)[args-1].styp=new_typ();
(*sd->sl)[args-1].styp->flags=VOID;
(*sd->sl)[args-1].reg=0;
t=new_typ();
t->flags=FUNKT;
t->exact=add_sd(sd,FUNKT);
t->next=new_typ();
t->next->flags=ztyp;
v=add_var(name,t,EXTERN,0);
v->flags|=BUILTIN;
if(asm||nosidefx){
v->fi=new_fi();
if(asm) v->fi->inline_asm=asm;
if(nosidefx){
v->fi->call_cnt=v->fi->use_cnt=v->fi->change_cnt=0;
v->fi->flags=ALL_CALLS|ALL_USES|ALL_MODS|ALWAYS_RETURNS|NOSIDEFX;
}
}
}
return v;
}
const_list *initialization(type *t,int noconst,int level,int desi,struct_declaration *fstruct,const_list *first)
/* Traegt eine Initialisierung in eine const_list ein. */
{
const_list *cl,**prev;
np tree,tree2;
int bracket,desi_follows=0;
zmax i;
token mtok;
int f=t->flags&NQ;
if(ISFUNC(f)){error(42);return(0);}
if(ctok->type==LBRA){next_token();killsp();bracket=1;} else bracket=0;
if(ISARRAY(f)){
#ifdef HAVE_MISRA
/* removed */
#endif
if(t->dsize){
error(358);
}else if(zmeqto(t->size,l2zm(0L))&&level!=0){
error(359);
}else if(ctok->type==T_STRING&&t->next&&(t->next->flags&NQ)==CHAR){
killsp();
tree=string_expression();
first=tree->cl;
free_expression(tree);
}else{
const_list *last=first;
if(level==0&&!bracket) error(157);
for(i=l2zm(0L);desi_follows||((zmeqto(t->size,l2zm(0L))||!zmleq(t->size,i)||ctok->type==LBRK)&&ctok->type!=RBRA);i=zmadd(i,l2zm(1L))){
if(!zmleq(i,0)){
if(ctok->type==COMMA){next_token();killsp();} else break;
if(ctok->type==RBRA) break;
}
/* check for first designated initializer */
cl=designator(t,first);
if(!cl){
/* no designator */
cl=insert_cl(last,i);
cl->other=initialization(t->next,c99?noconst:0,level+1,0,fstruct,cl->other);
if(cl->other&&zmeqto(cl->other->idx,l2zm(-2L))){
first=cl->other;
first->other=0;
break;
}
}else{
/* designator: store current object and handle remaining designators */
i=cl->idx;
if(ctok->type!=ASGN){
if(ctok->type!=LBRK&&ctok->type!=DOT)
error(355);
}else{
cl->other=0;
next_token();killsp();
}
cl->other=initialization(t->next,c99?noconst:0,level+1,1,fstruct,cl->other);
}
if(cl->next==first) first=cl;
last=cl;
killsp();
if(desi&&!bracket)
break;
desi_follows=0;
if(ctok->type==COMMA){
copy_token(&mtok,ctok);
next_token();killsp();
if(ctok->type==LBRK)
desi_follows=1;
push_token(&mtok);
}
}
if(bracket&&zmeqto(i,l2zm(0L))) error(360);
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}
}else if(ISSTRUCT(f)&&(bracket||!noconst||c99)){
if(t->exact->count<=0)
{error(43);return(0);}
#ifdef HAVE_ECPP
/* removed */
#endif
prev=0;
if(level==0&&!bracket&&!c99) error(157);
for(i=l2zm(0L);desi_follows||(!zmleq(t->exact->count,i)&&ctok->type!=RBRA);i=zmadd(i,l2zm(1L))){
if(!desi_follows&&(*t->exact->sl)[zm2l(i)].identifier[0]==0) continue; /* unnamed bitfield */
if(!zmleq(i,0)){
if(ctok->type==COMMA){next_token();killsp();} else break;
if(ctok->type==RBRA) break;
}
cl=designator(t,first);
if(!cl){
cl=insert_cl(first,l2zm((long)i));
cl->other=initialization((*t->exact->sl)[zm2l(i)].styp,c99?noconst:0,level+1,0,!fstruct&&!bracket&&zmeqto(i,l2zm(0L))?t->exact:fstruct,cl->other);
if(cl->other&&zmeqto(cl->other->idx,l2zm(-2L))){
if(fstruct){
first=cl->other;
first->other=0;
}else{
*cl=*cl->other;
cl->idx=l2zm(-1L);
cl->other=0;
first=cl;
}
break;
}
}else{
i=zm2l(cl->idx);
if(ctok->type!=ASGN){
if(ctok->type!=LBRK&&ctok->type!=DOT)
error(355);
}else{
next_token();killsp();
cl->other=0;
}
cl->other=initialization((*t->exact->sl)[zm2l(i)].styp,c99?noconst:0,level+1,1,fstruct,cl->other);
}
if(cl->next==first) first=cl;
if(desi&&!bracket)
break;
desi_follows=0;
if(ctok->type==COMMA){
copy_token(&mtok,ctok);
next_token();killsp();
if(ctok->type==DOT)
desi_follows=1;
push_token(&mtok);
}
}
if(bracket&&zmeqto(i,l2zm(0L))) error(360);
#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
#endif
}else if(ISUNION(f)&&(c99||bracket||!noconst)){
if(t->exact->count<=0)
{error(44);return(0);}
if(level==0&&!bracket&&!c99) error(157);
desi_follows=1;
while(desi_follows){
cl=designator(t,first);
if(!cl){
cl=insert_cl(first,l2zm((long)0));
cl->other=initialization((*t->exact->sl)[0].styp,c99?noconst:0,level+1,0,!fstruct&&!bracket?t->exact:fstruct,cl->other);
if(cl->other&&zmeqto(cl->other->idx,l2zm(-2L))){
if(fstruct){
first=cl->other;
first->other=0;
}else{
*cl=*cl->other;
cl->other=0;
cl->idx=l2zm(-1L);
first=cl;
}
break;
}
}else{
i=zm2l(cl->idx);
if(ctok->type!=ASGN){
if(ctok->type!=LBRK&&ctok->type!=DOT)
error(355);
}else{
next_token();killsp();
cl->other=0;
}
cl->other=initialization((*t->exact->sl)[zm2l(i)].styp,c99?noconst:0,level+1,1,fstruct,cl->other);
}
first=cl;
if(desi&&!bracket)
break;
desi_follows=0;
if(ctok->type==COMMA){
copy_token(&mtok,ctok);
next_token();killsp();
if(ctok->type==DOT)
desi_follows=1;
else
push_token(&mtok);
}
}
}else{
int oldconst=const_expr;
tree2=tree=assignment_expression();
if(!tree){error(45);return(0);}
if(!noconst) const_expr=1;
if(!type_expression(tree,t)){free_expression(tree); const_expr=oldconst;return 0;}
const_expr=oldconst;
tree=makepointer(tree);
/* check for complete assignment in dynamic initialization */
if(noconst&&(ISSTRUCT(tree->ntyp->flags)||ISUNION(tree->ntyp->flags))&&fstruct==tree->ntyp->exact){
first=mymalloc(CLS);
first->tree=tree;
first->next=first->other=0;
first->idx=l2zm(-2L);
return first;
}
if(!test_assignment(t,tree)){free_expression(tree); return 0;}
if(!noconst){
/* nur Konstanten erlaubt (bei Arrays/Strukturen etc. oder static) */
if(tree->flags!=CEXPR){
/*while(tree->flags==CAST) tree=tree->left;*/
if(!tree->sidefx/*tree->flags==ADDRESS||tree->flags==ADDRESSS||tree->flags==ADDRESSA*/){
const_expr=1;
gen_IC(tree,0,0);
const_expr=oldconst;
if(!(tree->o.flags&VARADR)){
/* hier fehlen noch viele Pruefungen */
free_expression(tree);error(46);
return(0);
}
tree->o.v->flags|=USEDASADR;
first=mymalloc(CLS);
first->next=first->other=0;
first->tree=tree;
first->idx=l2zm(0L);
killsp();
}else{
free_expression(tree);error(46);
return(0);
}
}else{
first=mymalloc(CLS);
first->idx=l2zm(0L);
first->next=first->other=0;
first->tree=0;
eval_constn(tree);
tree->ntyp->flags=t->flags;
insert_constn(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(!tree->sidefx){
if(tree->flags==CEXPR){
eval_constn(tree);
tree->ntyp->flags=t->flags;
insert_constn(tree);
first->val=tree->val;
first->tree=0;
first->idx=l2zm(0L);
init_const_sz=zmadd(init_const_sz,szof(tree->ntyp));
init_const_cnt++;
free_expression(tree2);
}else{
first->idx=l2zm(-1L);
init_dyn_sz=zmadd(init_dyn_sz,szof(tree->ntyp));
init_dyn_cnt++;
}
}else{
first->idx=l2zm(-1L);
init_dyn_sz=zmadd(init_dyn_sz,szof(tree->ntyp));
init_dyn_cnt++;
}
}
}
if(bracket){
if(ctok->type==COMMA){next_token();killsp();}
if(ctok->type==RBRA){next_token();killsp();} else error(128);
}
return(first);
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif