| #include "minicomp.h" |
| |
| #define clone_type clone_typ |
| #define free_type freetyp |
| #define new_icode new_IC |
| #define add_icode add_IC |
| #define free_all_icode() free_IC(first_ic) |
| #define get_first_icode() first_ic |
| typedef struct IC icode; |
| |
| static int errors; |
| var *store_locals; |
| |
| struct rpair rp; |
| |
| char *copyright="minicomp/vbcc (c) in 2002 Volker Barthelmann"; |
| char *inname,*outname; |
| struct struct_declaration *first_sd; |
| struct Var *first_ext,*merk_varf; |
| char **target_macros; |
| |
| FILE *out; |
| |
| void raus(void) |
| { |
| var *v; |
| for(v=first_var[0];v;v=v->next) |
| if(v->type->flags!=FUNCTION){ |
| gen_align(out,falign(v->type)); |
| gen_var_head(out,v->vbccvar); |
| gen_ds(out,szof(v->type),v->type); |
| } |
| |
| cleanup_cg(out); |
| |
| if(errors>0) |
| exit(EXIT_FAILURE); |
| else |
| exit(EXIT_SUCCESS); |
| } |
| |
| main(int argc,char **argv) |
| { |
| int i,j,flag; |
| type *nt; |
| |
| for(i=1;i<argc;i++){ |
| if(*argv[i]!='-'){ |
| if(inname) |
| error(18,"multiple input files"); |
| inname=argv[i]; |
| }else{ |
| flag=0; |
| if((!strcmp("-o",argv[i]))&&i<argc-1){ |
| flag=1; |
| outname=argv[++i]; |
| continue; |
| } |
| if(!strncmp("-debug=",argv[i],7)){ |
| flag=1; |
| sscanf(argv[i]+7,"%d",&j); |
| DEBUG=j; |
| continue; |
| } |
| if(!strncmp("-unroll-size=",argv[i],13)){ |
| flag=1; |
| sscanf(argv[i]+13,"%d",&j); |
| unroll_size=j; |
| continue; |
| } |
| if(!strncmp("-inline-size=",argv[i],13)){ |
| flag=1; |
| sscanf(argv[i]+13,"%d",&j); |
| inline_size=j; |
| continue; |
| } |
| if(!strncmp("-maxoptpasses=",argv[i],14)){ |
| flag=1; |
| sscanf(argv[i]+14,"%d",&j); |
| maxoptpasses=j; |
| continue; |
| } |
| for(j=0;j<MAXGF&&flag==0;j++){ |
| size_t l; |
| if(!g_flags_name[j]) continue; |
| l=strlen(g_flags_name[j]); |
| if(l>0&&!strncmp(argv[i]+1,g_flags_name[j],l)){ |
| flag=1; |
| if((g_flags[j]&(USEDFLAG|FUNCFLAG))==USEDFLAG){error(19,"multiple option");break;} |
| g_flags[j]|=USEDFLAG; |
| if(g_flags[j]&STRINGFLAG){ |
| if(argv[i][l+1]!='='){error(21,"string expected");} |
| if(argv[i][l+2]||i>=argc-1) |
| g_flags_val[j].p=&argv[i][l+2]; |
| else |
| g_flags_val[j].p=&argv[++i][0]; |
| } |
| if(g_flags[j]&VALFLAG){ |
| if(argv[i][l+1]!='='){error(20,"value expected");} |
| if(argv[i][l+2]||i>=argc-1) |
| g_flags_val[j].l=atol(&argv[i][l+2]); |
| else |
| g_flags_val[j].l=atol(&argv[++i][0]); |
| } |
| if(g_flags[j]&FUNCFLAG) g_flags_val[j].f(&argv[i][l+1]); |
| } |
| } |
| if(!flag) error(23,"unknown option"); |
| } |
| } |
| |
| if(!inname) |
| error(22,"no input file"); |
| infile=fopen(inname,"r"); |
| if(!infile) |
| error(18,"could not open output file"); |
| if(!outname) |
| error(23,"no output file"); |
| out=fopen(outname,"w"); |
| if(!out){ |
| error(24,"could not open input file"); |
| } |
| nt=new_type(FUNCTION); |
| nt->next=new_type(INT); |
| add_var("readInt",clone_type(nt)); |
| add_var("writeInt",clone_type(nt)); |
| add_var("writeChar",clone_type(nt)); |
| add_var("readChar",clone_type(nt)); |
| add_var("writeReal",nt); |
| nt=new_type(FUNCTION); |
| nt->next=new_type(REAL); |
| add_var("readReal",nt); |
| |
| stackalign=l2zm(0L); |
| if(!init_cg()) exit(EXIT_FAILURE); |
| if(zmeqto(stackalign,l2zm(0L))) |
| stackalign=maxalign; |
| for(i=0;i<EMIT_BUF_DEPTH;i++) |
| emit_buffer[i]=mymalloc(EMIT_BUF_LEN); |
| emit_p=emit_buffer[0]; |
| |
| multiple_ccs=0; |
| optflags=-1; |
| maxoptpasses=100; |
| |
| yyparse(); |
| |
| raus(); |
| } |
| |
| yyerror(char *s) |
| { |
| error(1,s); |
| } |
| |
| void error(int n,...) |
| { |
| if(n==170||n==172) return; |
| errors++; |
| fprintf(stderr,"error %d\n",n); |
| raus(); |
| } |
| |
| void *getmem(size_t s) |
| { |
| void *p=malloc(s); |
| if(!p){ |
| error(2,"out of memory"); |
| } |
| return p; |
| } |
| |
| #define LABELNESTING 1024 |
| static int labelstack[LABELNESTING],labelidx; |
| |
| void push_int(int l) |
| { |
| labelstack[labelidx++]=l; |
| } |
| |
| int pop_int() |
| { |
| return labelstack[--labelidx]; |
| } |
| |
| #define NAMENESTING 1024 |
| static char *namestack[NAMENESTING],nameidx; |
| |
| void push_ptr(void *ptr) |
| { |
| namestack[nameidx++]=ptr; |
| } |
| |
| void *pop_ptr() |
| { |
| return namestack[--nameidx]; |
| } |
| |
| |
| char *typename[]={" ","int","real","array","function"}; |
| |
| |
| type *new_type(int t) |
| { |
| type *new=new_typ(); |
| new->flags=t; |
| new->next=0; |
| return new; |
| } |
| |
| type *new_array(type *t,node *p) |
| { |
| type *new=new_typ(); |
| simplify_tree(p); |
| if(p->flags!=NNUMBER) |
| error(3,"array size not a constant"); |
| if(p->type->flags!=INT) |
| error(4,"array size not an integer"); |
| new->flags=ARRAY; |
| new->next=t; |
| new->size=l2zm((long)p->ivalue); |
| free_tree(p); |
| return new; |
| } |
| |
| int nesting; |
| int local_offset,parm_offset,framesize; |
| |
| #define MAXNESTING 128 |
| var *first_var[128]; |
| |
| void free_varlist(var *v) |
| { |
| var *m; |
| while(v){ |
| free_var(v->vbccvar); |
| m=v->next; |
| free(v); |
| v=m; |
| } |
| } |
| |
| void enter_block() |
| { |
| nesting++; |
| first_var[nesting]=0; |
| push_int(local_offset); |
| } |
| |
| void leave_block() |
| { |
| if(first_var[nesting]){ |
| var *p=first_var[nesting]; |
| while(p->next) |
| p=p->next; |
| p->next=store_locals; |
| p->vbccvar->next=merk_varf; |
| store_locals=first_var[nesting]; |
| merk_varf=store_locals->vbccvar; |
| } |
| nesting--; |
| local_offset=pop_int(); |
| } |
| |
| void gen_func(var *v,icode *first,int framesize) |
| { |
| pric(stdout,get_first_icode()); |
| vl1=first_var[0]?first_var[0]->vbccvar:0; |
| vl2=first_var[1]?first_var[1]->vbccvar:0; |
| vl3=merk_varf; |
| optimize(optflags,v->vbccvar); |
| memset(regs_modified,0,RSIZE); |
| pric(stdout,get_first_icode()); |
| gen_code(out,get_first_icode(),v->vbccvar,max_offset); |
| } |
| |
| void enter_func(char *name,type *p) |
| { |
| type *t=new_type(FUNCTION); |
| var *v; |
| t->next=p; |
| t->exact=getmem(sizeof(*t->exact)); |
| t->exact->count=0; |
| v=add_var(name,t); |
| local_offset=parm_offset=framesize=0; |
| push_ptr(v); |
| enter_block(); |
| } |
| |
| void leave_func() |
| { |
| icode *p,*merk; |
| leave_block(); |
| gen_func(pop_ptr(),get_first_icode(),framesize); |
| free_all_icode(); |
| first_ic=last_ic=0; |
| free_varlist(store_locals); |
| merk_varf=0; |
| store_locals=0; |
| } |
| |
| var *find_var(char *p,int minnest) |
| { |
| var *v; |
| int i; |
| |
| for(i=nesting;i>=minnest;i--){ |
| for(v=first_var[i];v;v=v->next) |
| if(!strcmp(v->name,p)) |
| return v; |
| } |
| return 0; |
| } |
| |
| var *add_var(char *name,type *t) |
| { |
| var *new=getmem(sizeof(*new)); |
| struct Var *vv; |
| /*FIXME: add vbccvar */ |
| if(find_var(name,nesting)) |
| error(5,"var %s already defined",name); |
| new->nesting=nesting; |
| new->name=add_string(name); |
| new->type=t; |
| if(*name==0){ |
| new->next=store_locals; |
| }else{ |
| new->next=first_var[nesting]; |
| } |
| if(nesting==1){ |
| /* parameter */ |
| new->offset=parm_offset; |
| parm_offset+=szof(t); |
| } |
| if(nesting>1){ |
| /* local variable */ |
| new->offset=local_offset; |
| local_offset+=szof(t); |
| if(local_offset>framesize) |
| framesize=local_offset; |
| } |
| /* attach vbcc variable */ |
| vv=new_var(); |
| vv->vtyp=clone_typ(new->type); |
| vv->identifier=add_string(name); |
| vv->nesting=(*name!=0?nesting:2); |
| vv->storage_class=(vv->nesting==0?EXTERN:AUTO); |
| if(nesting==1) |
| vv->offset=zmsub(l2zm(0L),zmadd(maxalign,l2zm(new->offset))); |
| else |
| vv->offset=l2zm((long)local_offset); |
| new->vbccvar=vv; |
| |
| if(*name==0){ |
| store_locals=new; |
| vv->next=merk_varf; |
| merk_varf=vv; |
| }else{ |
| vv->next=first_var[nesting]?first_var[nesting]->vbccvar:0; |
| first_var[nesting]=new; |
| } |
| return new; |
| } |
| |
| var *new_temp(int tflags) |
| { |
| char tname[16]; |
| static int itmps,rtmps,ptmps; |
| if(tflags==INT) |
| sprintf(tname,"\0 itmp%d",++itmps); |
| else if(tflags==REAL) |
| sprintf(tname,"\0 rtmp%d",++rtmps); |
| else if(tflags==POINTER) |
| sprintf(tname,"\0 rtmp%d",++ptmps); |
| else |
| error(16,"internal"); |
| return add_var(tname,new_type(tflags)); |
| } |
| |
| struct Var *add_tmp_var(struct Typ *t) |
| { |
| |
| return new_temp(t->flags)->vbccvar; |
| } |
| |
| char *add_string(char *s) |
| { |
| char *new=getmem(strlen(s)+1); |
| strcpy(new,s); |
| return new; |
| } |
| |
| char *nodename[]={ |
| "var","number","add","mul","sub","div","index","equals", |
| "lt","gt","leq","geq","neq","and","or", |
| "int2real","real2int","assign","call","argument" |
| }; |
| |
| node *number_node(void) |
| { |
| node *new=getmem(sizeof(*new)); |
| new->flags=NNUMBER; |
| if(strstr(tkname,".")){ |
| double rval; |
| sscanf(tkname,"%lf",&rval); |
| new->rvalue=rval; |
| new->type=new_type(REAL); |
| new->left=new->right=0; |
| }else{ |
| new->ivalue=atoi(tkname); |
| new->type=new_type(INT); |
| new->left=new->right=0; |
| } |
| return new; |
| } |
| |
| node *var_node(void) |
| { |
| var *v=find_var(tkname,0); |
| node *new; |
| if(!v){ |
| error(6,"unknown identifier: %s",tkname); |
| } |
| new=getmem(sizeof(*new)); |
| new->flags=NVARIABLE; |
| new->var=v; |
| new->type=clone_type(v->type); |
| new->left=new->right=0; |
| return new; |
| } |
| |
| |
| node *binary_node(enum nodeflags flags,node *left,node *right) |
| { |
| node *new=getmem(sizeof(*new)); |
| new->flags=flags; |
| new->left=left; |
| new->right=right; |
| new->type=0; |
| if(!left||(flags!=NCALL&&!right)) |
| error(7,"internal error"); |
| if(flags==NINDEX){ |
| if(left->type->flags!=ARRAY) |
| error(8,"operand of [] must be array"); |
| new->type=clone_type(left->type->next); |
| }else if(flags==NARG){ |
| /* nothing to do? */ |
| }else if(flags==NCALL){ |
| if(left->type->flags!=FUNCTION) |
| error(9,"only functions can be called"); |
| new->type=clone_type(left->type->next); |
| }else{ |
| if(left->type->flags==ARRAY||right->type->flags==ARRAY) |
| error(10,"both operands must be real or int"); |
| if(left->type->flags==REAL||right->type->flags==REAL){ |
| new->type=new_type(REAL); |
| if(left->type->flags==INT){ |
| new->left=conv_tree(left,REAL); |
| } |
| if(right->type->flags==INT){ |
| new->right=conv_tree(right,REAL); |
| } |
| }else |
| new->type=new_type(INT); |
| } |
| return new; |
| } |
| |
| void print_tree(node *p) |
| { |
| printf("%s(",nodename[p->flags]); |
| if(p->left) |
| print_tree(p->left); |
| if(p->right){ |
| printf(","); |
| print_tree(p->right); |
| } |
| if(p->flags==NNUMBER){ |
| if(p->type->flags==INT) |
| printf("%d[int]",p->ivalue); |
| else |
| printf("%g[real]",p->rvalue); |
| } |
| if(p->flags==NVARIABLE) |
| printf("%s[%s]",p->var->name,typename[p->var->type->flags]); |
| printf(")"); |
| } |
| |
| node *conv_tree(node *p,int tflags) |
| { |
| node *new; |
| if(p->type->flags==tflags) |
| return p; |
| new=getmem(sizeof(*new)); |
| if(tflags==REAL) |
| new->flags=NI2R; |
| else |
| new->flags=NR2I; |
| new->type=new_type(p->type->flags); |
| new->left=p; |
| new->right=0; |
| return new; |
| } |
| |
| void free_tree(node *p) |
| { |
| if(p->left) |
| free_tree(p->left); |
| if(p->right) |
| free_tree(p->right); |
| if(p->type) |
| free_type(p->type); |
| free(p); |
| } |
| |
| |
| static void const_node(node *p,int val) |
| { |
| p->flags=NNUMBER; |
| p->ivalue=val; |
| if(p->left) |
| free_tree(p->left); |
| if(p->right) |
| free_tree(p->right); |
| p->left=p->right=0; |
| } |
| |
| void simplify_tree(node *p) |
| { |
| if(p->left) |
| simplify_tree(p->left); |
| if(p->right) |
| simplify_tree(p->right); |
| if(p->type&&p->type->flags==INT&&p->left&&p->left->flags==NNUMBER&&p->right&&p->right->flags==NNUMBER){ |
| switch(p->flags){ |
| case NADD: const_node(p,p->left->ivalue+p->right->ivalue); break; |
| case NMUL: const_node(p,p->left->ivalue*p->right->ivalue); break; |
| case NSUB: const_node(p,p->left->ivalue-p->right->ivalue); break; |
| case NDIV: |
| if(p->right->ivalue!=0) |
| const_node(p,p->left->ivalue/p->right->ivalue); break; |
| } |
| } |
| } |
| |
| void assign_statement(node *left,node *right) |
| { |
| if(left->type->flags==ARRAY||right->type->flags==ARRAY) |
| error(11,"array type in assignment"); |
| if(left->type->flags==FUNCTION||right->type->flags==FUNCTION) |
| error(12,"function type in assignment"); |
| |
| right=conv_tree(right,left->type->flags); |
| simplify_tree(left); |
| simplify_tree(right); |
| if(left->flags==NINDEX){ |
| icode *n1,*n2,*n3; |
| n1=new_icode(); |
| n1->code=MULT; |
| n1->typf=INT; |
| n1->q1=*gen_tree(left->right); |
| n1->q2.flags=KONST; |
| n1->q2.val.vint=zm2zi(sizetab[INT]); |
| n1->z.flags=VAR; |
| n1->z.v=new_temp(INT)->vbccvar; |
| n1->z.val.vmax=l2zm(0L); |
| n2=new_icode(); |
| n2->code=ADDI2P; |
| n2->typf=INT; |
| n2->typf2=POINTER; |
| n2->q1=*gen_tree(left->left); |
| n2->q2=n1->z; |
| n2->z.flags=VAR; |
| n2->z.v=new_temp(POINTER)->vbccvar; |
| n2->z.val.vmax=l2zm(0L); |
| n3=new_icode(); |
| n3->code=ASSIGN; |
| n3->typf=left->type->flags; |
| n3->q1=*gen_tree(right); |
| n3->z=n2->z; |
| n3->z.flags|=DREFOBJ; |
| n3->z.dtyp=POINTER; |
| n3->q2.val.vmax=szof(left->type); |
| add_icode(n1); |
| add_icode(n2); |
| add_icode(n3); |
| #if 0 |
| /* leicht anderes Format */ |
| new->flags=CSTORE; |
| new->op1=*gen_tree(right); |
| new->op2=*gen_tree(left->left); |
| new->dest=*gen_tree(left->right); |
| #endif |
| }else{ |
| icode *new=new_icode(); |
| new->code=ASSIGN; |
| new->q1=*gen_tree(right); |
| new->z=*gen_tree(left); |
| new->q2.val.vmax=szof(left->type); |
| new->typf=left->type->flags; |
| add_icode(new); |
| } |
| free_tree(left); |
| free_tree(right); |
| } |
| |
| void return_statement(node *p) |
| { |
| icode *new=new_icode(); |
| p=conv_tree(p,INT); /*FIXME*/ |
| simplify_tree(p); |
| new->code=SETRETURN; |
| new->typf=p->type->flags; |
| new->q1=*gen_tree(p); |
| new->z.reg=freturn(p->type); |
| add_icode(new); |
| free_tree(p); |
| } |
| |
| void while_statement(node *p) |
| { |
| int loop=++label,exit=++label; |
| simplify_tree(p); |
| gen_cond(p,loop,exit); |
| gen_label(loop); |
| last_ic->flags|=LOOP_COND_TRUE; |
| push_ptr(p); |
| push_int(loop); |
| push_int(exit); |
| #if 0 |
| gen_label(loop); |
| gen_cond(p,start,exit); |
| free_tree(p); |
| gen_label(start); |
| push_int(loop); |
| push_int(exit); |
| #endif |
| } |
| |
| void while_end() |
| { |
| int loop,exit; |
| node *p; |
| exit=pop_int(); |
| loop=pop_int(); |
| p=pop_ptr(); |
| gen_cond(p,loop,exit); |
| gen_label(exit); |
| #if 0 |
| new=new_icode(); |
| new->code=BRA; |
| new->typf=loop; |
| add_icode(new); |
| gen_label(exit); |
| #endif |
| } |
| |
| void if_statement(node *p) |
| { |
| int true=++label,false=++label; |
| simplify_tree(p); |
| gen_cond(p,true,false); |
| free_tree(p); |
| gen_label(true); |
| push_int(false); |
| } |
| |
| void if_end() |
| { |
| gen_label(pop_int()); |
| } |
| |
| void if_else() |
| { |
| int endlabel=++label; |
| icode *new=new_icode(); |
| new->code=BRA; |
| new->typf=++label; |
| add_icode(new); |
| gen_label(pop_int()); |
| push_int(label); |
| } |
| |
| int label; |
| |
| operand *gen_tree(node *p) |
| { |
| icode *new; |
| static operand op; |
| |
| if(p->flags==NVARIABLE){ |
| if(p->var->type->flags==ARRAY){ |
| if(p->var->nesting==0){ |
| op.flags=VAR|VARADR; |
| op.v=p->var->vbccvar; |
| op.val.vmax=l2zm(0L); |
| return &op; |
| }else{ |
| icode *new=new_icode(); |
| new->flags=ADDRESS; |
| new->q1.flags=VAR; |
| new->q1.v=p->var->vbccvar; |
| new->q1.val.vmax=l2zm(0L); |
| new->z.flags=VAR; |
| new->z.v=new_temp(POINTER)->vbccvar; |
| new->z.val.vmax=l2zm(0L); |
| add_icode(new); |
| return &new->z; |
| } |
| }else{ |
| op.flags=VAR; |
| op.v=p->var->vbccvar; |
| op.val.vmax=l2zm(0L); |
| return &op; |
| } |
| } |
| |
| if(p->flags==NNUMBER){ |
| op.flags=KONST; |
| if(p->type->flags==INT) |
| op.val.vint=p->ivalue; |
| else |
| op.val.vdouble=zld2zd(d2zld(p->rvalue)); |
| return &op; |
| } |
| |
| if(p->flags==NADD||p->flags==NMUL||p->flags==NSUB||p->flags==NDIV||p->flags==NI2R||p->flags==NR2I){ |
| int ttyp=p->type->flags; |
| new=new_icode(); |
| switch(p->flags){ |
| case NADD: new->code=ADD;break; |
| case NMUL: new->code=MULT;break; |
| case NSUB: new->code=SUB;break; |
| case NDIV: new->code=DIV;break; |
| case NI2R: new->code=CONVERT;ttyp=REAL;new->typf2=INT;break; |
| case NR2I: new->code=CONVERT;ttyp=INT;new->typf2=REAL;break; |
| } |
| new->q1=*gen_tree(p->left); |
| if(p->right) |
| new->q2=*gen_tree(p->right); |
| new->z.flags=VAR; |
| new->z.v=new_temp(ttyp)->vbccvar; |
| new->z.val.vmax=l2zm(0L); |
| new->typf=ttyp; |
| add_icode(new); |
| return &new->z; |
| } |
| |
| if(p->flags==NINDEX){ |
| if(p->type->flags==ARRAY){ |
| icode *merk,*new=new_icode(); |
| new->flags=MULT; |
| new->typf=INT; |
| new->q1=*gen_tree(p->right); |
| new->q2.flags=KONST; |
| new->q2.val.vint=szof(p->type); |
| new->z.flags=VAR; |
| new->z.v=new_temp(INT)->vbccvar; |
| new->z.val.vmax=l2zm(0L); |
| add_icode(new); |
| merk=new; |
| new=new_icode(); |
| new->flags=ADDI2P; |
| new->typf=INT; |
| new->typf2=POINTER; |
| new->q1=*gen_tree(p->left); |
| new->q2=merk->z; |
| new->z.flags=VAR; |
| new->z.v=new_temp(POINTER)->vbccvar; |
| new->z.val.vmax=l2zm(0L); |
| op=new->z; |
| add_icode(new); |
| return &new->z; |
| }else{ |
| icode *merk,*new=new_icode(); |
| new->code=MULT; |
| new->typf=INT; |
| new->q1=*gen_tree(p->right); |
| new->q2.flags=KONST; |
| new->q2.val.vint=zm2zi(sizetab[INT]); |
| new->z.flags=VAR; |
| new->z.v=new_temp(INT)->vbccvar; |
| new->z.val.vmax=l2zm(0L); |
| add_icode(new); |
| merk=new; |
| new=new_icode(); |
| new->code=ADDI2P; |
| new->q1=*gen_tree(p->left); |
| new->q2=merk->z; |
| new->typf=INT; |
| new->typf2=POINTER; |
| new->z.flags=VAR; |
| new->z.v=new_temp(POINTER)->vbccvar; |
| new->z.val.vmax=l2zm(0L); |
| op=new->z; |
| op.flags|=DREFOBJ; |
| op.dtyp=POINTER; |
| add_icode(new); |
| return &op; |
| } |
| } |
| |
| if(p->flags==NCALL){ |
| icode *new=new_icode(); |
| new->code=CALL; |
| new->typf=FUNKT; |
| if(p->right) |
| new->q2.val.vmax=l2zm(push_arg(p->right)); |
| else |
| new->q2.val.vmax=l2zm(0L); |
| new->q1=*gen_tree(p->left); |
| add_icode(new); |
| new=new_icode(); |
| new->code=GETRETURN; |
| new->z.flags=VAR; |
| new->typf=p->type->flags; |
| new->z.v=new_temp(p->type->flags)->vbccvar; |
| new->z.val.vmax=l2zm(0L); |
| new->q1.reg=freturn(p->type); |
| add_icode(new); |
| return &new->z; |
| } |
| |
| error(13,"operation not yet supported"); |
| } |
| |
| void gen_label(int l) |
| { |
| icode *new=new_icode(); |
| new->code=LABEL; |
| new->typf=l; |
| add_icode(new); |
| } |
| |
| void gen_cond(node *p,int true_label,int false_label) |
| { |
| icode *new; |
| if(p->flags==NAND){ |
| int tmp=++label; |
| gen_cond(p->left,tmp,false_label); |
| gen_label(tmp); |
| gen_cond(p->right,true_label,false_label); |
| return; |
| } |
| if(p->flags==NOR){ |
| int tmp=++label; |
| gen_cond(p->left,true_label,tmp); |
| gen_label(tmp); |
| gen_cond(p->right,true_label,false_label); |
| return; |
| } |
| new=new_icode(); |
| new->code=COMPARE; |
| new->typf=p->type->flags; |
| new->q1=*gen_tree(p->left); |
| new->q2=*gen_tree(p->right); |
| add_icode(new); |
| new=new_icode(); |
| switch(p->flags){ |
| case NEQUALS: new->code=BEQ;break; |
| case NNEQ: new->code=BNE;break; |
| case NLT: new->code=BLT;break; |
| case NGT: new->code=BGT;break; |
| case NLEQ: new->code=BLE;break; |
| case NGEQ: new->code=BGE;break; |
| default: error(14,"internal"); |
| } |
| new->typf=true_label; |
| add_icode(new); |
| |
| new=new_icode(); |
| new->code=BRA; |
| new->typf=false_label; |
| add_icode(new); |
| } |
| |
| int push_arg(node *p) |
| { |
| if(p->flags==NARG){ |
| int s; |
| s=push_arg(p->right); |
| return s+push_arg(p->left); |
| }else{ |
| icode *new=new_icode(); |
| if(p->type->flags==ARRAY) |
| error(15,"arrays cannot be passed"); |
| new->code=PUSH; |
| new->q2.val.vmax=szof(p->type); |
| new->z.val.vmax=new->q2.val.vmax; |
| new->typf=p->type->flags; |
| new->q1=*gen_tree(p); |
| add_icode(new); |
| return szof(p->type); |
| } |
| } |
| |
| void free_var(struct Var *v) |
| { |
| free(v); |
| /*FIXME*/ |
| } |
| |
| void add_IC(icode *new) |
| { |
| if(last_ic&&new->code==ASSIGN&&new->q1.flags==VAR&&last_ic->z.flags==VAR&& |
| new->q1.v==last_ic->z.v&&zmeqto(new->q1.val.vmax,last_ic->z.val.vmax)&& |
| *new->q1.v->identifier==0){ |
| last_ic->z=new->z; |
| free(new); |
| return; |
| } |
| insert_IC(last_ic,new); |
| } |