/* $VER: vbcc (declaration.c) V0.8 */ #include #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(struct Var *v,struct Typ *t,struct const_list *cl,zmax of,int noconst); int test_assignment(struct Typ *,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 zmax init_dyn_sz,init_const_sz; int init_dyn_cnt,init_const_cnt; void init_sl(struct 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,struct Typ *,np,struct Typ *); extern int float_used; extern void optimize(long,struct Var *); 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 */ struct 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; struct 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]=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!=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 struct Typ *declaration_specifiers(void) /* Erzeugt neuen Typ und gibt Zeiger darauf zurueck, */ /* parst z.B. unsigned int, struct bla etc. */ { int typ=0,type_qualifiers=0,notdone,storage_class,hard_reg,have_inline; #ifdef HAVE_ECPP /* removed */ /* removed */ /* removed */ #endif char *imerk,sident[MAXI],sbuff[MAXI],*attr=0,*vattr=0; struct Typ *new=new_typ(),*t,*ts; struct struct_declaration *ssd; struct struct_list (*sl)[]; size_t slsz; struct 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; zmax off=l2zm(0L); next_token(); killsp(); slsz=SLSIZE; imerk=ident; sl=mymalloc(slsz*sizeof(struct struct_list)); ssd->count=0; #ifdef HAVE_ECPP /* removed */ /* removed */ /* removed */ /* removed */ /* removed */ /* removed */ /* removed */ /* removed */ /* removed */ /* removed */ /* removed */ #endif 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)){ 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=ssd->count; 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 */ #endif (*sl)[ssd->count].bfoffset=bfoffset; (*sl)[ssd->count].bfsize=bfsize; (*sl)[ssd->count].styp=t; if(!ecpp) (*sl)[ssd->count].identifier=add_identifier(ident,strlen(ident)); #ifdef HAVE_ECPP /* removed */ /* removed */ /* removed */ #endif if(pack_align>0&&pack_aligncount].align=pack_align; else (*sl)[ssd->count].align=falign(t); { zmax m,al=(*sl)[ssd->count].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); } } } ssd->count++; if(ssd->count>=slsz-1){ slsz+=SLSIZE; sl=myrealloc(sl,slsz*sizeof(struct 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); 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; struct Var *v; struct Typ *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; } 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]; struct Typ *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(/*!(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<name); tattr|=(1L<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_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; } struct Typ *declarator(struct Typ *a) /* Erzeugt einen neuen Typ, auf Basis des Typs a. */ /* a wird hiermit verkettet. */ { struct Typ *t; killsp();*ident=0; t=direct_declarator(pointer(a)); if(!a) {if(t) freetyp(t);return 0;} #ifdef HAVE_ECPP /* removed */ #endif #ifdef HAVE_EXT_TYPES conv_typ(t); #endif return t; } struct Typ *pointer(struct Typ *a) /* Unterroutine fuer declarator(), behandelt Zeiger auf Typ. */ { struct Typ *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; } struct Typ *direct_declarator(struct Typ *a) /* Unterroutine zu declarator() */ /* behandelt [],(funkt),(dekl). */ { struct Typ *rek=0,*merk,*p,*t=0,*first,*last=0; struct struct_declaration *fsd; struct 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 */ struct 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)){ /* error("incorrect constant expression");*/ }else{ if(tree->sidefx&&!c99) error(60); if(tree->flags!=CEXPR||!ISINT(tree->ntyp->flags)){ if(!c99) error(19); else{ struct Typ *st;struct 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(zmeqto(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; #ifdef HAVE_REGPARMS struct reg_handle reg_handle=empty_reg_handle; struct Typ rpointer={0}; if(!ffreturn(a)&&(a->flags&NQ)!=VOID){ rpointer.flags=POINTER_TYPE(a); rpointer.next=a; reg_parm(®_handle,&rpointer,0,0); } #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 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)){ struct Typ *new; new=new_typ(); new->next=(*sl)[fsd->count].styp; new->flags=POINTER_TYPE(new->next); (*sl)[fsd->count].styp=new; } } if(hard_reg&®ok(hard_reg,t->flags,-1)<=0) error(217,regnames[hard_reg]); #ifdef HAVE_REGPARMS if(t) (*sl)[fsd->count].reg=reg_parm(®_handle,t,0,0); 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 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].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; } 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. */ { struct Var *v;struct 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("__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 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 struct_declaration *sd,struct struct_list (*sl)[]) /* Fuegt ein struct_list-Array in eine struct_declaration ein. */ /* Das Array muss mind. sd->count Elements haben und wird kopiert. */ { size_t sz=sizeof(struct struct_list)*sd->count; sd->sl=mymalloc(sz); memcpy(sd->sl,sl,sz); } struct struct_declaration *add_sd(struct struct_declaration *new,int typ) /* Fuegt eine struct 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 struct_declaration *p) /* Gibt eine struct_declaration-List inkl. struct_lists und */ /* allen Typen jeder struct_list frei, nicht aber identifier. */ { int i;struct struct_declaration *merk; while(p){ merk=p->next; if(p->sl){ for(i=0;icount;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. */ { struct identifier_list *new; if((*identifier==0&&length==0)||identifier==empty) return(empty); new=mymalloc(sizeof(struct identifier_list)); new->identifier=mymalloc(length+1); memcpy(new->identifier,identifier,length+1); new->next=0;new->length=length; if(last_ilist[nesting]){ last_ilist[nesting]->next=new; last_ilist[nesting]=new; }else{ last_ilist[nesting]=first_ilist[nesting]=new; } return(new->identifier); } void free_ilist(struct identifier_list *p) /* Gibt eine verkettete identifier_liste und saemtliche darin */ /* gespeicherten Identifier frei. */ { struct identifier_list *merk; while(p){ merk=p->next; if(p->identifier) free(p->identifier); free(p); p=merk; } } int type_uncomplete(struct Typ *p) /* Testet, ob Typ unvollstaendig ist. Momentan gelten nur */ /* unvollstaendige Strukturen und Arrays von solchen als */ /* unvollstaendig, aber keine Zeiger oder Funktionen darauf. */ { struct struct_declaration *sd; if(!p){ierror(0);return(0);} if(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 struct_declaration *sd) /* Erzeugt neuen struct_identifier, fuegt ihn in Liste an und */ /* vervollstaendigt unvollstaendige Typen dieser Struktur. */ { struct struct_identifier *new; /* struct Typ *t;*/ if(DEBUG&1) printf("add_si %s (nesting=%d)->%p\n",identifier,nesting,(void *)sd); #ifdef HAVE_MISRA /* removed */ /* removed */ /* removed */ /* removed */ /* removed */ #endif new=mymalloc(sizeof(struct struct_identifier)); new->identifier=add_identifier(identifier,strlen(identifier)); new->sd=sd; new->next=0; if(first_si[nesting]==0){ first_si[nesting]=new;last_si[nesting]=new; }else{ last_si[nesting]->next=new;last_si[nesting]=new; } sd->identifier=new->identifier; } void free_si(struct struct_identifier *p) /* Gibt eine struct_identifier-Liste frei, aber nicht die */ /* identifiers und struct_declarations. */ { struct struct_identifier *merk; while(p){ merk=p->next; p->sd->identifier=""; free(p); p=merk; } } struct struct_declaration *find_struct(char *identifier,int endnesting) /* Sucht angegebene Strukturdefinition und liefert */ /* entsprechende struct_declaration. */ { struct struct_identifier *si; int i,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 struct 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 struct tag <%s>\n",identifier); return(0); } /* generate code to create a variable-lenght-array */ static void create_allocvl(struct Var *v) { np tree,ds; struct IC *new;struct 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"))){ struct Typ *t; static struct Typ voidt={VOID}; struct 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 struct_declaration *sd=mymalloc(sizeof(*sd)); struct Typ *t=new_typ(); sd->count=1; sd->sl=mymalloc(sizeof(struct 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)) 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; struct Var *fv; dontdelete=1; /* never remove them, otherwise, fix_vla_jump get confused */ if(!find_ext_var("__resetvlasp")){ struct struct_declaration *sd=mymalloc(sizeof(*sd)); struct Typ *t=new_typ(); sd->count=1; sd->sl=mymalloc(sizeof(struct 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)) ierror(0); tree=gen_libcall("__resetvlasp",ds,0,0,0); free_expression(tree); dontdelete=0; } void clearvl(void) { struct llist *p,*n; struct vlaadjust_list *vl,*vn; /* look for stack-adjusts that have to be removed */ vl=vlaadjusts[nesting]; while(vl){ int ln; struct 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(struct IC *p,struct Var **vn,int *nest) { if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"__oldvlasp")){ struct 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 struct Var *return_last_vlasp; /* Find the stack pointer that is needed when jumping to label lab */ struct Var *vla_find_sp(int lab) { struct IC *p;int nest=0; static struct 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) { struct IC *p;int nest=0; static struct 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; struct 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){ struct 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)) 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 */ struct 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 */ struct Var *v; if(ISSCALAR(setr->typf)){ static struct Typ 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); } } } } } struct Var *add_tmp_var(struct Typ *t) { t->flags&=NU; return add_var(empty,t,AUTO,0); } struct Var *add_var(char *identifier, struct Typ *t, int storage_class,struct const_list *clist) /* Fuegt eine Variable mit Typ in die var_list ein. */ /* In der storage_class werden die Flags PARAMETER und evtl. */ /* OLDSTYLE und REGPARM erkannt. */ { struct Var *new;int f; struct struct_declaration *sd; static zmax paroffset; zmax al; /*if(*identifier==0) return;*/ /* sollte woanders bemaekelt werden */ if(DEBUG&2) printf("add_var(): %s\n",identifier); #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(struct 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; #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®PARM){ 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; } }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)&&foffset,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)&&foffset=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®PARM)){ #if HAVE_LIBCALLS static struct Typ dt={DOUBLE},ft={FLOAT}; static struct node n,nn; struct 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 struct 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); return(new); } void free_var(struct Var *p) /* Gibt Variablenliste inkl. Typ, aber ohne Identifier frei. */ { struct 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; } } struct Var *find_ext_var(char *identifier) { struct Var *v;int l; if(misracheck) l=strlen(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; } struct Var *find_var(char *identifier,int endnesting) /* Sucht Variable mit Bezeichner und liefert Zeiger zurueck */ /* es werden nur Variablen der Bloecke endnesting-nesting */ /* durchsucht. */ { int i,l;struct 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(struct 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(32L))) 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(struct Var *v) { if(v->storage_class==AUTO||v->storage_class==REGISTER){ struct 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. */ struct Var *nv; if(!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. */ { struct Typ *ts,*t,*old=0,*om=0;char *imerk,vident[MAXI]; int mdef=0,makeint=0,notdone,storage_class,msc,extern_flag,isfunc, had_decl,hard_reg,mhr,diffunit=0,inline_flag; struct Var *v; char *vattr; 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; 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{ ierror(0);return; } } if(storage_class==0){ if(nesting==0) storage_class=EXTERN; else storage_class=AUTO; } msc=storage_class;mhr=hard_reg; while(notdone){ int oldnesting=nesting; imerk=ident;ident=vident;*vident=0; /* merken von ident hier vermutlich */ storage_class=msc;hard_reg=mhr; if(old) {freetyp(old);old=0;} t=declarator(clone_typ(ts)); #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<tattr=tattr; } #endif if(vattr){ if(v->vattr){ v->vattr=myrealloc(v->vattr,strlen(v->vattr)+strlen(vattr)+2); strcat(v->vattr,";"); strcat(v->vattr,vattr); }else 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; } } } }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--; 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; 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(); 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))){ struct 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. */ struct Var *merk=v->next; v->next=0; gen_vars(v); v->next=merk; v->clist=0; } } }else{ if((v->flags&DEFINED)&&type_uncomplete(v->vtyp)) error(202,v->identifier); if((v->vtyp->flags&CONST)&&(v->storage_class==AUTO||v->storage_class==REGISTER)) error(119,v->identifier); } if(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 struct reg_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; 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 */ struct Typ *nt=declaration_specifiers();notdone=1;oldstyle=OLDSTYLE; if(!ts) {error(35);} while(notdone){ int found=0; imerk=ident;ident=vident;*vident=0; ts=declarator(clone_typ(nt)); ident=imerk; if(!ts) {error(36);} else{ for(i=0;iexact->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)){ struct Typ *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 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; 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. */ struct Typ *rt=new_typ();int reg; rt->flags=POINTER_TYPE(return_typ);rt->next=return_typ; #ifdef HAVE_REGPARMS reg=reg_parm(®_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); for(i=0;iexact->count;i++){ #ifdef HAVE_REGPARMS int didrp=0; if((*t->exact->sl)[i].styp){ int tr; tr=reg_parm(®_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){ struct Typ *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){ struct 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(®_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__ */ struct Typ *ft=new_typ(); struct 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 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){ struct 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 struct_declaration *sd=t->exact;int i,f; for(f=0,i=0;icount;i++) if(!(*sd->sl)[i].styp){error(126);f=1;} if(f){ for(i=0;icount;i++) if((*sd->sl)[i].styp) freetyp((*sd->sl)[i].styp); sd->count=0; } } } if(old) freetyp(old); } int compatible_types(struct Typ *a,struct Typ *b,int qual) /* Vergleicht, ob Typ beider Typen gleich ist, const/volatile */ /* werden laut ANSI nicht beruecksichtigt. */ { struct struct_declaration *sd; int af=a->flags&qual,bf=b->flags&qual; if(af!=bf) return(0); af&=NQ;bf&=NQ; if(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 struct_declaration *a,struct struct_declaration *b) /* Vergleicht, ob zwei struct_declarations identisch sind */ /* Wird nur nur fuer Prototypen benutzt, leere Liste immer gleich. */ { int i; if(!a->count||!b->count) return(1); if(a->count!=b->count) return(0); for(i=0;icount;i++){ if((*a->sl)[i].styp&&(*b->sl)[i].styp&&!compatible_types((*a->sl)[i].styp,(*b->sl)[i].styp,NU)) return(0); #ifdef HAVE_MISRA /* removed */ /* removed */ #endif } return(1); } void free_clist(struct const_list *p) /* Gibt clist frei. */ { struct const_list *merk; return; while(p){ merk=p->next; if(p->other) free_clist(p->other); if(p->tree) free_expression(p->tree); free(p); p=merk; } } void gen_clist(FILE *,struct Typ *,struct const_list *); void gen_vars(struct Var *v) /* Generiert Variablen. */ { int mode,al;struct Var *p; if(errors!=0||(c_flags[5]&USEDFLAG)) return; 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(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))){ struct Typ *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) 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) 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; } } } } } } /* creates code that dynamically initializes a variable */ void dynamic_init(struct Var *v,struct Typ *t,struct 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;struct Typ *st; int bfo,i; for(i=0;iexact->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(of,al),l2zm(0L))){ of=zmadd(of,zmsub(al,zmmod(of,al))); } if(bfo>=0){ int bfs=(*t->exact->sl)[i].bfsize; static struct obj dest = {0}; dest.flags=VAR; dest.v=v; dest.val.vmax=of; if(bfo==0){ /* first clear entire bitfield */ struct 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){ struct 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 struct 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(;iexact->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{ struct 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,struct Typ *t,struct const_list *cl) /* Generiert dc fuer const_list. */ { int i,bfo,bfs;zmax sz;zumax bfval=ul2zum(0UL); 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;struct Typ *st; sz=l2zm(0L); if(cl&&cl->tree){ /* struct initialized by another struct */ gen_ds(f,szof(t),t); sz=zmadd(sz,szof(t)); }else{ for(i=0;iexact->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 */ struct 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(;iexact->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 */ struct const_list *insert_cl(struct const_list *old,zmax idx) { struct 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; } struct const_list *designator(struct Typ *t,struct 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)){ /* 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;iexact->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 */ struct Var *declare_builtin(char *name,int ztyp,int q1typ,int q1reg,int q2typ,int q2reg,int nosidefx,char *asm) { struct struct_declaration *sd; struct Typ *t; struct 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 struct_list)); memset(sd->sl,0,args*sizeof(struct 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; 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; } struct const_list *initialization(struct Typ *t,int noconst,int level,int desi,struct struct_declaration *fstruct,struct const_list *first) /* Traegt eine Initialisierung in eine const_list ein. */ { struct const_list *cl,**prev; np tree,tree2; int bracket,desi_follows=0; zmax i; struct 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{ struct 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,0); 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)){free_expression(tree); const_expr=oldconst;return 0;} const_expr=oldconst; tree=makepointer(tree); /* check for complete struct 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{ 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