/* writetrailer * Not much left of this once important function. * * Global references: pc_stksize (referred to only) * sc_dataalign (referred to only) * code_idx (altered) * glb_declared (altered) */ SC_FUNC void writetrailer(void) { assert(sc_dataalign % opcodes(1) == 0); /* alignment must be a multiple of * the opcode size */ assert(sc_dataalign!=0); /* pad code to align data segment */ if ((code_idx % sc_dataalign)!=0) { begcseg(); while ((code_idx % sc_dataalign)!=0) nooperation(); } /* if */ /* pad data segment to align the stack and the heap */ assert(litidx==0); /* literal queue should have been emptied */ assert(sc_dataalign % sizeof(cell) == 0); if (((glb_declared*sizeof(cell)) % sc_dataalign)!=0) { begdseg(); defstorage(); while (((glb_declared*sizeof(cell)) % sc_dataalign)!=0) { stgwrite("0 "); glb_declared++; } /* while */ } /* if */ stgwrite("\nSTKSIZE "); /* write stack size (align stack top) */ outval(pc_stksize - (pc_stksize % sc_dataalign),TRUE,TRUE); }
/* * dump zeroes for default initial value * (or rather, get loader to do it for us) */ int dumpzero(int size, int count) { if (count <= 0) return (0); defstorage() ; outdec(size*count) ; /* outstr("dumpzero"); */ nl(); return(size*count); }
void #endif dumpvars() { int ident,type,storage; SYMBOL *ptr; if (!glbcnt) return; /* Start at the start! */ glbptr=STARTGLB; outstr("; --- Start of Static Variables ---\n\n"); /* Two different handlings, if an application then use defvars construct * if not, then just drop em using defs! * * Even more handlings...if asz80 used we dump into data sectio */ output_section("bss_compiler"); // output_section("bss"); ptr=STARTGLB; while (ptr < ENDGLB) { if (ptr->name[0] != 0 && ptr->name[0] != '0' ) { ident=ptr->ident; type =ptr->type; storage=ptr->storage; if (ident !=ENUM && type !=ENUM && ident != MACRO && ident != FUNCTION && storage != EXTERNAL && storage != DECLEXTN && storage != EXTERNP && storage != LSTKEXT && storage!=TYPDEF ) { prefix(); outname(ptr->name,1); col(); defstorage(); outdec(ptr->size); nl(); } } ++ptr; } /* Switch back to standard section */ output_section("code_compiler"); // output_section("code"); }
dumpglbs() { int j; if(glbflag==0)return; /* don't if user said no */ cptr=startglb; while(cptr < glbptr) {if(cptr[ident]!=function) /* do if anything but function */ {outstr(cptr);col(); /* output name as label... */ defstorage(); /* define storage */ j=((cptr[offset]&255)+ ((cptr[offset+1]&255)<<8)); /* calc # bytes */ if((cptr[type]==cint)| (cptr[ident]==pointer)) j=j+1; outdec(j); /* need that many */ nl(); } cptr=cptr+symsiz; } }
/* writestatetables * Creates and dumps the state tables. Every function with states has a state * table that contains jump addresses (or overlay indices) the branch to the * appropriate function using the (hidden) state variable as the criterion. * Technically, this happens in a "switch" (or an "iswitch") instruction. * This function also creates the hidden state variables (one for each * automaton) in the data segment. */ SC_FUNC void writestatetables(symbol *root,int lbl_nostate,int lbl_ignorestate) { int lbl_default,lbl_table,lbl_defnostate; int statecount; symbol *sym; constvalue *fsa, *state; statelist *stlist; int fsa_id,listid; assert(code_idx>0); /* leader must already have been written */ /* check whether there are any functions that have states */ for (sym=root->next; sym!=NULL; sym=sym->next) if (sym->ident==iFUNCTN && (sym->usage & (uPUBLIC | uREAD))!=0 && sym->states!=NULL) break; if (sym==NULL) return; /* no function has states, nothing to do next */ assert(pc_ovl0size[ovlNO_STATE][0]>0); /* state exit point must already have been created */ assert(pc_ovl0size[ovlNO_STATE][1]>0); /* write the "state-selectors" table with all automatons (update the * automatons structure too, as we are now assigning the address to * each automaton state-selector variable) */ assert(glb_declared==0); begdseg(); for (fsa=sc_automaton_tab.next; fsa!=NULL; fsa=fsa->next) { defstorage(); stgwrite("0\t; automaton "); if (strlen(fsa->name)==0) stgwrite("(anonymous)"); else stgwrite(fsa->name); stgwrite("\n"); fsa->value=glb_declared*sizeof(cell); glb_declared++; } /* for */ /* write stubs and jump tables for all state functions */ begcseg(); for (sym=root->next; sym!=NULL; sym=sym->next) { if (sym->ident==iFUNCTN && (sym->usage & (uPUBLIC | uREAD))!=0 && sym->states!=NULL) { stlist=sym->states->next; assert(stlist!=NULL); /* there should be at least one state item */ listid=stlist->id; assert(listid==-1 || listid>0); if (listid==-1 && stlist->next!=NULL) { /* first index is the "fallback", take the next one (if available) */ stlist=stlist->next; listid=stlist->id; } /* if */ if (listid==-1) { /* first index is the fallback, there is no second... */ stlist->label=0; /* insert dummy label number */ /* this is an error, but we postpone adding the error message until the * function definition */ continue; } /* if */ /* generate label numbers for all statelist ids */ for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) { if (pc_overlays>0) { /* code overlay indices should already be set, see gen_ovlinfo() */ assert(stlist->label>0); } else { assert(stlist->label==0); stlist->label=getlabel(); } /* if */ } /* for */ if (strcmp(sym->name,uENTRYFUNC)==0) continue; /* do not generate stubs for this special function */ sym->addr=code_idx; /* fix the function address now */ /* get automaton id for this function */ assert(listid>0); fsa_id=state_getfsa(listid); assert(fsa_id>=0); /* automaton 0 exists */ fsa=automaton_findid(fsa_id); /* count the number of states actually used; at the same time, check * whether there is a default (i.e. "fallback") state function */ statecount=0; if (strcmp(sym->name,uEXITFUNC)==0) { lbl_default= (pc_overlays>0) ? ovlEXITSTATE : lbl_ignorestate; } else { lbl_defnostate= (pc_overlays>0) ? ovlNO_STATE : lbl_nostate; lbl_default=lbl_defnostate; } /* if */ for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) { if (stlist->id==-1) { lbl_default=stlist->label; } else { statecount+=state_count(stlist->id); } /* if */ } /* for */ /* generate a stub entry for the functions */ stgwrite("\tload.pri "); outval(fsa->value,TRUE,FALSE); stgwrite("\t; "); stgwrite(sym->name); if (pc_overlays>0) { /* add overlay index */ stgwrite("/"); outval(sym->index,FALSE,FALSE); } /* if */ stgwrite("\n"); code_idx+=opcodes(1)+opargs(1); /* calculate code length */ lbl_table=getlabel(); ffswitch(lbl_table,(pc_overlays>0)); /* generate the jump table */ setlabel(lbl_table); ffcase(statecount,lbl_default,TRUE,(pc_overlays>0)); for (state=sc_state_tab.next; state!=NULL; state=state->next) { if (state->index==fsa_id) { /* find the label for this list id */ for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) { if (stlist->id!=-1 && state_inlist(stlist->id,(int)state->value)) { /* when overlays are used, the jump-label for the case statement * are overlay indices instead of code labels */ ffcase(state->value,stlist->label,FALSE,(pc_overlays>0)); break; } /* if */ } /* for */ if (stlist==NULL && lbl_default==lbl_defnostate) error(230,state->name,sym->name); /* unimplemented state, no fallback */ } /* if (state belongs to automaton of function) */ } /* for (state) */ stgwrite("\n"); /* the jump table gets its own overlay index, and the size of the jump * table must therefore be known (i.e. update the codeaddr field of the * function with the address where the jump table ends) */ sym->codeaddr=code_idx; } /* if (is function, used & having states) */ } /* for (sym) */ }
/* * dump all static variables */ void dumpglbs (void) { long i = 1; int dim, list_size, line_count; int j; FILE *save = output; if (!data) data = fmemopen(data_buf, DATABUFSIZE, "w"); if (!rodata) rodata = fmemopen(rodata_buf, DATABUFSIZE, "w"); /* This is done in several passes: Pass 0: Dump initialization data into const bank. Pass 1: Define space for uninitialized data. Pass 2: Define space for initialized data. */ if (glbflag) { int pass = 0; next: i = 1; for (cptr = rglbptr; cptr < glbptr; cptr++) { if (cptr->ident != FUNCTION) { // ppubext(cptr); if ((cptr->storage & WRITTEN) == 0 && /* Not yet written to file */ cptr->storage != EXTERN) { dim = cptr->offset; if (find_symbol_initials(cptr->name)) { // has initials /* dump initialization data */ if (pass == 1) /* initialized data not handled in pass 1 */ continue; else if (pass == 2) { /* define space for initialized data */ output = data; if (cptr->storage != LSTATIC) prefix(); outstr(cptr->name); outstr(":\t"); defstorage(); outdec(cptr->size); nl(); cptr->storage |= WRITTEN; output = save; continue; } /* output initialization data into const bank */ output = rodata; have_init_data = 1; list_size = 0; line_count = 0; list_size = get_size(cptr->name); if (cptr->type == CSTRUCT) list_size /= tag_table[cptr->tagidx].number_of_members; if (dim == -1) dim = list_size; int item; /* dim is an item count for non-compound types and a byte size for compound types; dump_struct() wants an item number, so we have to count both to get the right members out. */ for (j = item = 0; j < dim; j++, item++) { if (cptr->type == CSTRUCT) j += dump_struct(cptr, item) - 1; else { if (line_count % 10 == 0) { nl(); if (cptr->type == CCHAR || cptr->type == CUCHAR) defbyte(); else defword(); } if (j < list_size) { // dump data int value = get_item_at(cptr->name, j, &tag_table[cptr->tagidx]); outdec(value); } else { // dump zero, no more data available outdec(0); } line_count++; if (line_count % 10 == 0) line_count = 0; else { if (j < dim - 1) outbyte(','); } } } nl(); output = save; } else { if (pass == 0) continue; /* define space in bss */ if (i) { i = 0; nl(); gdata(); } if (cptr->storage != LSTATIC) prefix(); outstr(cptr->name); outstr(":\t"); defstorage(); outdec(cptr->size); nl(); cptr->storage |= WRITTEN; } } } else { // fpubext(cptr); } } if (++pass < 3) goto next; } if (i) { nl(); gdata(); } output = save; }
/* When a subroutine returns to address 0, the AMX must halt. In earlier * releases, the RET and RETN opcodes checked for the special case 0 address. * Today, the compiler simply generates a HALT instruction at address 0. So * a subroutine can savely return to 0, and then encounter a HALT. */ SC_FUNC void writeleader(symbol *root) { int lbl_nostate,lbl_table; int statecount; symbol *sym; constvalue *fsa, *state, *stlist; int fsa_id,listid; char lbl_default[sNAMEMAX+1]; assert(code_idx==0); begcseg(); stgwrite(";program exit point\n"); stgwrite("\thalt 0\n\n"); code_idx+=opcodes(1)+opargs(1); /* calculate code length */ /* check whether there are any functions that have states */ for (sym=root->next; sym!=NULL; sym=sym->next) if (sym->ident==iFUNCTN && (sym->usage & (uPUBLIC | uREAD))!=0 && sym->states!=NULL) break; if (sym==NULL) return; /* no function has states, nothing to do next */ /* generate an error function that is called for an undefined state */ stgwrite("\n;exit point for functions called from the wrong state\n"); lbl_nostate=getlabel(); setlabel(lbl_nostate); stgwrite("\thalt "); outval(AMX_ERR_INVSTATE,TRUE); code_idx+=opcodes(1)+opargs(1); /* calculate code length */ /* write the "state-selectors" table with all automatons (update the * automatons structure too, as we are now assigning the address to * each automaton state-selector variable) */ assert(glb_declared==0); begdseg(); for (fsa=sc_automaton_tab.next; fsa!=NULL; fsa=fsa->next) { defstorage(); stgwrite("0\t; automaton "); if (strlen(fsa->name)==0) stgwrite("(anonymous)"); else stgwrite(fsa->name); stgwrite("\n"); fsa->value=glb_declared*sizeof(cell); glb_declared++; } /* for */ /* write stubs and jump tables for all state functions */ begcseg(); for (sym=root->next; sym!=NULL; sym=sym->next) { if (sym->ident==iFUNCTN && (sym->usage & (uPUBLIC | uREAD))!=0 && sym->states!=NULL) { stlist=sym->states->next; assert(stlist!=NULL); /* there should be at least one state item */ listid=stlist->index; assert(listid==-1 || listid>0); if (listid==-1 && stlist->next!=NULL) { /* first index is the "fallback", take the next one (if available) */ stlist=stlist->next; listid=stlist->index; } /* if */ if (listid==-1) { /* first index is the fallback, there is no second... */ strcpy(stlist->name,"0"); /* insert dummy label number */ /* this is an error, but we postpone adding the error message until the * function definition */ continue; } /* if */ /* generate label numbers for all statelist ids */ for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) { assert(strlen(stlist->name)==0); strcpy(stlist->name,itoh(getlabel())); } /* for */ if (strcmp(sym->name,uENTRYFUNC)==0) continue; /* do not generate stubs for this special function */ sym->addr=code_idx; /* fix the function address now */ /* get automaton id for this function */ assert(listid>0); fsa_id=state_getfsa(listid); assert(fsa_id>=0); /* automaton 0 exists */ fsa=automaton_findid(fsa_id); /* count the number of states actually used; at the sane time, check * whether there is a default state function */ statecount=0; strcpy(lbl_default,itoh(lbl_nostate)); for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) { if (stlist->index==-1) { assert(strlen(stlist->name)<sizeof lbl_default); strcpy(lbl_default,stlist->name); } else { statecount+=state_count(stlist->index); } /* if */ } /* for */ /* generate a stub entry for the functions */ stgwrite("\tload.pri "); outval(fsa->value,FALSE); stgwrite("\t; "); stgwrite(sym->name); stgwrite("\n"); code_idx+=opcodes(1)+opargs(1); /* calculate code length */ lbl_table=getlabel(); ffswitch(lbl_table); /* generate the jump table */ setlabel(lbl_table); ffcase(statecount,lbl_default,TRUE); for (state=sc_state_tab.next; state!=NULL; state=state->next) { if (state->index==fsa_id) { /* find the label for this list id */ for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) { if (stlist->index!=-1 && state_inlist(stlist->index,(int)state->value)) { ffcase(state->value,stlist->name,FALSE); break; } /* if */ } /* for */ if (stlist==NULL && strtol(lbl_default,NULL,16)==lbl_nostate) error(230,state->name,sym->name); /* unimplemented state, no fallback */ } /* if (state belongs to automaton of function) */ } /* for (state) */ stgwrite("\n"); } /* if (is function, used & having states) */ } /* for (sym) */ }
/* * initialise structure */ int str_init(TAG_SYMBOL *tag) { int dim, flag; int sz, usz, numelements = 0; SYMBOL *ptr; int nodata = NO; ptr = tag->ptr; while (ptr < tag->end) { numelements++; dim = ptr->size; sz = getstsize(ptr,NO); if ( nodata == NO ) { if ( rcmatch('{') ) { needchar('{'); while (dim) { if ( ptr->type == STRUCT ) { if ( ptr->ident == ARRAY ) /* array of struct */ needchar('{'); str_init(tag); if ( ptr->ident == ARRAY ) { --dim; needchar('}'); } } else { init(sz, ptr->ident, &dim, 1, 1,1); } if (cmatch(',') == 0) break; blanks(); } needchar('}'); dumpzero(sz,dim); } else { init(sz, ptr->ident, &dim, ptr->more, 1, 1); } /* Pad out afterwards */ } else { /* Run out of data for this initialisation, set blank */ defstorage(); outdec(dim * getstsize(ptr,YES)); nl(); } usz = (ptr->size ? ptr->size : 1 ) * getstsize(ptr,YES); ++ptr; flag = NO; while (ptr->offset.i == 0 && ptr < tag->end) { if (getstsize(ptr,YES) * (ptr->size ? ptr->size : 1 ) > usz) { usz = getstsize(ptr,YES) * (ptr->size ? ptr->size : 1 ) ; flag = YES; } ++ptr; } /* Pad out the union */ if (usz != sz && flag) { defstorage(); outdec(usz - sz); nl(); } if (cmatch(',') == 0 && ptr != tag->end) { nodata = YES; } } return numelements; }