/* Pawn compiler - Binary code generation (the "assembler") * * Copyright (c) ITB CompuPhase, 1997-2005 * * This software is provided "as-is", without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in * a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * Version: $Id$ */ #include #include #include /* for macro max() */ #include #include #if defined FORTIFY #include "fortify.h" #endif #include "sc.h" #include "amxdbg.h" #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ #include #endif static void append_dbginfo(FILE *fout); typedef cell (*OPCODE_PROC)(FILE *fbin,char *params,cell opcode); typedef struct { cell opcode; char *name; int segment; /* sIN_CSEG=parse in cseg, sIN_DSEG=parse in dseg */ OPCODE_PROC func; } OPCODE; static cell codeindex; /* similar to "code_idx" */ static cell *lbltab; /* label table */ static int writeerror; static int bytes_in, bytes_out; static jmp_buf compact_err; /* apparently, strtol() does not work correctly on very large (unsigned) * hexadecimal values */ static ucell hex2long(char *s,char **n) { ucell result=0L; int negate=FALSE; int digit; /* ignore leading whitespace */ while (*s==' ' || *s=='\t') s++; /* allow a negation sign to create the two's complement of numbers */ if (*s=='-') { negate=TRUE; s++; } /* if */ assert((*s>='0' && *s<='9') || (*s>='a' && *s<='f') || (*s>='a' && *s<='f')); for ( ;; ) { if (*s>='0' && *s<='9') digit=*s-'0'; else if (*s>='a' && *s<='f') digit=*s-'a' + 10; else if (*s>='A' && *s<='F') digit=*s-'A' + 10; else break; /* probably whitespace */ result=(result<<4) | digit; s++; } /* for */ if (n!=NULL) *n=s; if (negate) result=(~result)+1; /* take two's complement of the result */ return (ucell)result; } static ucell getparam(char *s,char **n) { ucell result=0; for ( ;; ) { result+=hex2long(s,&s); if (*s!='+') break; s++; } /* for */ if (n!=NULL) *n=s; return result; } #if BYTE_ORDER==BIG_ENDIAN static uint16_t *align16(uint16_t *v) { unsigned char *s = (unsigned char *)v; unsigned char t; /* swap two bytes */ t=s[0]; s[0]=s[1]; s[1]=t; return v; } static uint32_t *align32(uint32_t *v) { unsigned char *s = (unsigned char *)v; unsigned char t; /* swap outer two bytes */ t=s[0]; s[0]=s[3]; s[3]=t; /* swap inner two bytes */ t=s[1]; s[1]=s[2]; s[2]=t; return v; } #if PAWN_CELL_SIZE>=64 static uint64_t *align64(uint64_t *v) { unsigned char *s = (unsigned char *)v; unsigned char t; t=s[0]; s[0]=s[7]; s[7]=t; t=s[1]; s[1]=s[6]; s[6]=t; t=s[2]; s[2]=s[5]; s[5]=t; t=s[3]; s[3]=s[4]; s[4]=t; return v; } #endif #if PAWN_CELL_SIZE==16 #define aligncell(v) align16(v) #elif PAWN_CELL_SIZE==32 #define aligncell(v) align32(v) #elif PAWN_CELL_SIZE==64 #define aligncell(v) align64(v) #endif #else #define align16(v) (v) #define align32(v) (v) #define aligncell(v) (v) #endif static char *skipwhitespace(char *str) { while (isspace(*str)) str++; return str; } static char *stripcomment(char *str) { char *ptr=strchr(str,';'); if (ptr!=NULL) { *ptr++='\n'; /* terminate the line, but leave the '\n' */ *ptr='\0'; } /* if */ return str; } static void write_encoded(FILE *fbin,ucell *c,int num) { #if PAWN_CELL_SIZE == 16 #define ENC_MAX 3 /* a 16-bit cell is encoded in max. 3 bytes */ #define ENC_MASK 0x03 /* after 2x7 bits, 2 bits remain to make 16 bits */ #elif PAWN_CELL_SIZE == 32 #define ENC_MAX 5 /* a 32-bit cell is encoded in max. 5 bytes */ #define ENC_MASK 0x0f /* after 4x7 bits, 4 bits remain to make 32 bits */ #elif PAWN_CELL_SIZE == 64 #define ENC_MAX 10 /* a 32-bit cell is encoded in max. 10 bytes */ #define ENC_MASK 0x01 /* after 9x7 bits, 1 bit remains to make 64 bits */ #endif assert(fbin!=NULL); while (num-->0) { if (sc_compress) { ucell p=(ucell)*c; unsigned char t[ENC_MAX]; unsigned char code; int index; for (index=0; index>=7; } /* for */ /* skip leading zeros */ while (index>1 && t[index-1]==0 && (t[index-2] & 0x40)==0) index--; /* skip leading -1s */ if (index==ENC_MAX && t[index-1]==ENC_MASK && (t[index-2] & 0x40)!=0) index--; while (index>1 && t[index-1]==0x7f && (t[index-2] & 0x40)!=0) index--; /* write high byte first, write continuation bits */ assert(index>0); while (index-->0) { code=(unsigned char)((index==0) ? t[index] : (t[index]|0x80)); writeerror |= !pc_writebin(fbin,&code,1); bytes_out++; } /* while */ bytes_in+=sizeof *c; assert(AMX_COMPACTMARGIN>2); if (bytes_out-bytes_in>=AMX_COMPACTMARGIN-2) longjmp(compact_err,1); } else { assert((pc_lengthbin(fbin) % sizeof(cell)) == 0); writeerror |= !pc_writebin(fbin,aligncell(c),sizeof *c); } /* if */ c++; } /* while */ } #if defined __BORLANDC__ || defined __WATCOMC__ #pragma argsused #endif static cell noop(FILE *fbin,char *params,cell opcode) { return 0; } #if defined __BORLANDC__ || defined __WATCOMC__ #pragma argsused #endif static cell parm0(FILE *fbin,char *params,cell opcode) { if (fbin!=NULL) write_encoded(fbin,(ucell*)&opcode,1); return opcodes(1); } static cell parm1(FILE *fbin,char *params,cell opcode) { ucell p=getparam(params,NULL); if (fbin!=NULL) { write_encoded(fbin,(ucell*)&opcode,1); write_encoded(fbin,&p,1); } /* if */ return opcodes(1)+opargs(1); } #if defined __BORLANDC__ || defined __WATCOMC__ #pragma argsused #endif static cell do_dump(FILE *fbin,char *params,cell opcode) { ucell p; int num = 0; while (*params!='\0') { p=getparam(params,¶ms); if (fbin!=NULL) write_encoded(fbin,&p,1); num++; while (isspace(*params)) params++; } /* while */ return num*sizeof(cell); } static cell do_call(FILE *fbin,char *params,cell opcode) { char name[sNAMEMAX+1]; int i; symbol *sym; ucell p; for (i=0; !isspace(*params); i++,params++) { assert(*params!='\0'); assert(i=0 && iident==iFUNCTN || sym->ident==iREFFUNC); assert(sym->vclass==sGLOBAL); p=sym->addr; } /* if */ if (fbin!=NULL) { write_encoded(fbin,(ucell*)&opcode,1); write_encoded(fbin,&p,1); } /* if */ return opcodes(1)+opargs(1); } static cell do_jump(FILE *fbin,char *params,cell opcode) { int i; ucell p; i=(int)hex2long(params,NULL); assert(i>=0 && i=0 && i=0 && i=MAX_INSTR_LEN) return 0; strncpy(str,instr,maxlen); str[maxlen]='\0'; /* make sure the string is zero terminated */ /* look up the instruction with a binary search * the assembler is case insensitive to instructions (but case sensitive * to symbols) */ low=1; /* entry 0 is reserved (for "not found") */ high=(sizeof opcodelist / sizeof opcodelist[0])-1; while (low0) low=mid+1; else high=mid; } /* while */ assert(low==high); if (stricmp(str,opcodelist[low].name)==0) return low; /* found */ return 0; /* not found, return special index */ } SC_FUNC int assemble(FILE *fout,FILE *fin) { AMX_HEADER hdr; AMX_FUNCSTUBNT func; int numpublics,numnatives,numlibraries,numpubvars,numtags,padding; long nametablesize,nameofs; #if PAWN_CELL_SIZE > 32 char line[512]; #else char line[256]; #endif char *instr,*params; int i,pass,size; int16_t count; symbol *sym, **nativelist; constvalue *constptr; cell mainaddr; /* if compression failed, restart the assembly with compaction switched off */ if (setjmp(compact_err)!=0) { assert(sc_compress); /* cannot arrive here if compact encoding was disabled */ sc_compress=FALSE; pc_resetbin(fout,0); error(232); /* disabled compact encoding */ } /* if */ #if !defined NDEBUG /* verify that the opcode list is sorted (skip entry 1; it is reserved * for a non-existant opcode) */ assert(opcodelist[1].name!=NULL); for (i=2; i<(sizeof opcodelist / sizeof opcodelist[0]); i++) { assert(opcodelist[i].name!=NULL); assert(stricmp(opcodelist[i].name,opcodelist[i-1].name)>0); } /* for */ #endif writeerror=FALSE; nametablesize=sizeof(int16_t); numpublics=0; numnatives=0; numpubvars=0; mainaddr=-1; /* count number of public and native functions and public variables */ for (sym=glbtab.next; sym!=NULL; sym=sym->next) { int match=0; if (sym->ident==iFUNCTN) { if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) match=++numnatives; if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0) match=++numpublics; if (strcmp(sym->name,uMAINFUNC)==0) { assert(sym->vclass==sGLOBAL); mainaddr=sym->addr; } /* if */ } else if (sym->ident==iVARIABLE) { if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) match=++numpubvars; } /* if */ if (match) { char alias[sNAMEMAX+1]; assert(sym!=NULL); if ((sym->usage & uNATIVE)==0 || !lookup_alias(alias,sym->name)) { assert(strlen(sym->name)<=sNAMEMAX); strcpy(alias,sym->name); } /* if */ nametablesize+=strlen(alias)+1; } /* if */ } /* for */ assert(numnatives==ntv_funcid); /* count number of libraries */ numlibraries=0; if (pc_addlibtable) { for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) { if (constptr->value>0) { assert(strlen(constptr->name)>0); numlibraries++; nametablesize+=strlen(constptr->name)+1; } /* if */ } /* for */ } /* if */ /* count number of public tags */ numtags=0; for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) { if ((constptr->value & PUBLICTAG)!=0) { assert(strlen(constptr->name)>0); numtags++; nametablesize+=strlen(constptr->name)+1; } /* if */ } /* for */ /* pad the header to sc_dataalign * => thereby the code segment is aligned * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned * => and thereby the stack top is aligned too */ assert(sc_dataalign!=0); padding= (int)(sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign); if (padding==sc_dataalign) padding=0; /* write the abstract machine header */ memset(&hdr, 0, sizeof hdr); hdr.magic=(unsigned short)AMX_MAGIC; hdr.file_version=CUR_FILE_VERSION; hdr.amx_version=MIN_AMX_VERSION; hdr.flags=(short)(sc_debug & sSYMBOLIC); if (sc_compress) hdr.flags|=AMX_FLAG_COMPACT; if (sc_debug==0) hdr.flags|=AMX_FLAG_NOCHECKS; hdr.defsize=sizeof(AMX_FUNCSTUBNT); hdr.publics=sizeof hdr; /* public table starts right after the header */ hdr.natives=hdr.publics + numpublics*sizeof(AMX_FUNCSTUBNT); hdr.libraries=hdr.natives + numnatives*sizeof(AMX_FUNCSTUBNT); hdr.pubvars=hdr.libraries + numlibraries*sizeof(AMX_FUNCSTUBNT); hdr.tags=hdr.pubvars + numpubvars*sizeof(AMX_FUNCSTUBNT); hdr.nametable=hdr.tags + numtags*sizeof(AMX_FUNCSTUBNT); hdr.cod=hdr.nametable + nametablesize + padding; hdr.dat=hdr.cod + code_idx; hdr.hea=hdr.dat + glb_declared*sizeof(cell); hdr.stp=hdr.hea + sc_stksize*sizeof(cell); hdr.cip=mainaddr; hdr.size=hdr.hea; /* preset, this is incorrect in case of compressed output */ pc_writebin(fout,&hdr,sizeof hdr); /* dump zeros up to the rest of the header, so that we can easily "seek" */ for (nameofs=sizeof hdr; nameofsnext) { if (sym->ident==iFUNCTN && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0) { assert(sym->vclass==sGLOBAL); func.address=sym->addr; func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.publics+count*sizeof(AMX_FUNCSTUBNT)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,sym->name,strlen(sym->name)+1); nameofs+=strlen(sym->name)+1; count++; } /* if */ } /* for */ /* write the natives table */ /* The native functions must be written in sorted order. (They are * sorted on their "id", not on their name). A nested loop to find * each successive function would be an O(n^2) operation. But we * do not really need to sort, because the native function id's * are sequential and there are no duplicates. So we first walk * through the complete symbol list and store a pointer to every * native function of interest in a temporary table, where its id * serves as the index in the table. Now we can walk the table and * have all native functions in sorted order. */ if (numnatives>0) { nativelist=(symbol **)malloc(numnatives*sizeof(symbol *)); if (nativelist==NULL) error(103); /* insufficient memory */ #if !defined NDEBUG memset(nativelist,0,numnatives*sizeof(symbol *)); /* for NULL checking */ #endif for (sym=glbtab.next; sym!=NULL; sym=sym->next) { if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) { assert(sym->addr < numnatives); nativelist[(int)sym->addr]=sym; } /* if */ } /* for */ count=0; for (i=0; iname)) { assert(strlen(sym->name)<=sNAMEMAX); strcpy(alias,sym->name); } /* if */ assert(sym->vclass==sGLOBAL); func.address=0; func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.natives+count*sizeof(AMX_FUNCSTUBNT)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,alias,strlen(alias)+1); nameofs+=strlen(alias)+1; count++; } /* for */ free(nativelist); } /* if */ /* write the libraries table */ if (pc_addlibtable) { count=0; for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) { if (constptr->value>0) { assert(strlen(constptr->name)>0); func.address=0; func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.libraries+count*sizeof(AMX_FUNCSTUBNT)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,constptr->name,strlen(constptr->name)+1); nameofs+=strlen(constptr->name)+1; count++; } /* if */ } /* for */ } /* if */ /* write the public variables table */ count=0; for (sym=glbtab.next; sym!=NULL; sym=sym->next) { if (sym->ident==iVARIABLE && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) { assert((sym->usage & uDEFINE)!=0); assert(sym->vclass==sGLOBAL); func.address=sym->addr; func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.pubvars+count*sizeof(AMX_FUNCSTUBNT)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,sym->name,strlen(sym->name)+1); nameofs+=strlen(sym->name)+1; count++; } /* if */ } /* for */ /* write the public tagnames table */ count=0; for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) { if ((constptr->value & PUBLICTAG)!=0) { assert(strlen(constptr->name)>0); func.address=constptr->value & TAGMASK; func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.tags+count*sizeof(AMX_FUNCSTUBNT)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,constptr->name,strlen(constptr->name)+1); nameofs+=strlen(constptr->name)+1; count++; } /* if */ } /* for */ /* write the "maximum name length" field in the name table */ assert(nameofs==hdr.nametable+nametablesize); pc_resetbin(fout,hdr.nametable); count=sNAMEMAX; #if BYTE_ORDER==BIG_ENDIAN align16(&count); #endif pc_writebin(fout,&count,sizeof count); pc_resetbin(fout,hdr.cod); /* First pass: relocate all labels */ /* This pass is necessary because the code addresses of labels is only known * after the peephole optimization flag. Labels can occur inside expressions * (e.g. the conditional operator), which are optimized. */ lbltab=NULL; if (sc_labnum>0) { /* only very short programs have zero labels; no first pass is needed * if there are no labels */ lbltab=(cell *)malloc(sc_labnum*sizeof(cell)); if (lbltab==NULL) error(103); /* insufficient memory */ codeindex=0; pc_resetasm(fin); while (pc_readasm(fin,line,sizeof line)!=NULL) { stripcomment(line); instr=skipwhitespace(line); /* ignore empty lines */ if (*instr=='\0') continue; if (tolower(*instr)=='l' && *(instr+1)=='.') { int lindex=(int)hex2long(instr+2,NULL); assert(lindex>=0 && lindexinstr); i=findopcode(instr,(int)(params-instr)); if (opcodelist[i].name==NULL) { *params='\0'; error(104,instr); /* invalid assembler instruction */ } /* if */ if (opcodelist[i].segment==sIN_CSEG) codeindex+=opcodelist[i].func(NULL,skipwhitespace(params),opcodelist[i].opcode); } /* if */ } /* while */ } /* if */ /* Second pass (actually 2 more passes, one for all code and one for all data) */ bytes_in=0; bytes_out=0; for (pass=sIN_CSEG; pass<=sIN_DSEG; pass++) { pc_resetasm(fin); while (pc_readasm(fin,line,sizeof line)!=NULL) { stripcomment(line); instr=skipwhitespace(line); /* ignore empty lines and labels (labels have a special syntax, so these * must be parsed separately) */ if (*instr=='\0' || tolower(*instr)=='l' && *(instr+1)=='.') continue; /* get to the end of the instruction (make use of the '\n' that fgets() * added at the end of the line; this way we will *always* drop on a * whitespace character) */ for (params=instr; *params!='\0' && !isspace(*params); params++) /* nothing */; assert(params>instr); i=findopcode(instr,(int)(params-instr)); assert(opcodelist[i].name!=NULL); if (opcodelist[i].segment==pass) opcodelist[i].func(fout,skipwhitespace(params),opcodelist[i].opcode); } /* while */ } /* for */ if (bytes_out-bytes_in>0) error(106); /* compression buffer overflow */ if (lbltab!=NULL) { free(lbltab); #if !defined NDEBUG lbltab=NULL; #endif } /* if */ if (sc_compress) hdr.size=pc_lengthbin(fout);/* get this value before appending debug info */ if (!writeerror && (sc_debug & sSYMBOLIC)!=0) append_dbginfo(fout); /* optionally append debug file */ if (writeerror) error(101,"disk full"); /* adjust the header */ size=(int)hdr.cod; /* save, the value in the header may be swapped */ #if BYTE_ORDER==BIG_ENDIAN align32(&hdr.size); align16(&hdr.magic); align16(&hdr.flags); align16(&hdr.defsize); align32(&hdr.publics); align32(&hdr.natives); align32(&hdr.libraries); align32(&hdr.pubvars); align32(&hdr.tags); align32(&hdr.nametable); align32(&hdr.cod); align32(&hdr.dat); align32(&hdr.hea); align32(&hdr.stp); align32(&hdr.cip); #endif pc_resetbin(fout,0); pc_writebin(fout,&hdr,sizeof hdr); /* return the size of the header (including name tables, but excluding code * or data sections) */ return size; } static void append_dbginfo(FILE *fout) { AMX_DBG_HDR dbghdr; AMX_DBG_LINE dbgline; AMX_DBG_SYMBOL dbgsym; AMX_DBG_SYMDIM dbgidxtag[sDIMEN_MAX]; int index,dim; char *str,*prevstr,*name,*prevname; ucell codeidx,previdx; constvalue *constptr; char symname[2*sNAMEMAX+16]; int16_t id1,id2; ucell address; /* header with general information */ memset(&dbghdr, 0, sizeof dbghdr); dbghdr.size=sizeof dbghdr; dbghdr.magic=AMX_DBG_MAGIC; dbghdr.file_version=CUR_FILE_VERSION; dbghdr.amx_version=MIN_AMX_VERSION; /* first pass: collect the number of items in various tables */ /* file table */ previdx=0; prevstr=NULL; prevname=NULL; for (index=0; (str=get_dbgstring(index))!=NULL; index++) { assert(str!=NULL); assert(str[0]!='\0' && str[1]==':'); if (str[0]=='F') { codeidx=hex2long(str+2,&name); if (codeidx!=previdx) { if (prevstr!=NULL) { assert(prevname!=NULL); dbghdr.files++; dbghdr.size+=sizeof(cell)+strlen(prevname)+1; } /* if */ previdx=codeidx; } /* if */ prevstr=str; prevname=skipwhitespace(name); } /* if */ } /* for */ if (prevstr!=NULL) { assert(prevname!=NULL); dbghdr.files++; dbghdr.size+=sizeof(cell)+strlen(prevname)+1; } /* if */ /* line number table */ for (index=0; (str=get_dbgstring(index))!=NULL; index++) { assert(str!=NULL); assert(str[0]!='\0' && str[1]==':'); if (str[0]=='L') { dbghdr.lines++; dbghdr.size+=sizeof(AMX_DBG_LINE); } /* if */ } /* for */ /* symbol table */ for (index=0; (str=get_dbgstring(index))!=NULL; index++) { assert(str!=NULL); assert(str[0]!='\0' && str[1]==':'); if (str[0]=='S') { dbghdr.symbols++; name=strchr(str+2,':'); assert(name!=NULL); dbghdr.size+=sizeof(AMX_DBG_SYMBOL)+strlen(skipwhitespace(name+1)); if ((prevstr=strchr(name,'['))!=NULL) while ((prevstr=strchr(prevstr+1,':'))!=NULL) dbghdr.size+=sizeof(AMX_DBG_SYMDIM); } /* if */ } /* for */ /* tag table */ for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) { assert(strlen(constptr->name)>0); dbghdr.tags++; dbghdr.size+=sizeof(AMX_DBG_TAG)+strlen(constptr->name); } /* for */ /* automaton table */ for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) { assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0); dbghdr.automatons++; dbghdr.size+=sizeof(AMX_DBG_MACHINE)+strlen(constptr->name); } /* for */ /* state table */ for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) { assert(strlen(constptr->name)>0); dbghdr.states++; dbghdr.size+=sizeof(AMX_DBG_STATE)+strlen(constptr->name); } /* for */ /* pass 2: generate the tables */ writeerror |= !pc_writebin(fout,&dbghdr,sizeof dbghdr); /* file table */ previdx=0; prevstr=NULL; prevname=NULL; for (index=0; (str=get_dbgstring(index))!=NULL; index++) { assert(str!=NULL); assert(str[0]!='\0' && str[1]==':'); if (str[0]=='F') { codeidx=hex2long(str+2,&name); if (codeidx!=previdx) { if (prevstr!=NULL) { assert(prevname!=NULL); writeerror |= !pc_writebin(fout,&previdx,sizeof previdx); writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1); } /* if */ previdx=codeidx; } /* if */ prevstr=str; prevname=skipwhitespace(name); } /* if */ } /* for */ if (prevstr!=NULL) { assert(prevname!=NULL); writeerror |= !pc_writebin(fout,&previdx,sizeof previdx); writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1); } /* if */ /* line number table */ for (index=0; (str=get_dbgstring(index))!=NULL; index++) { assert(str!=NULL); assert(str[0]!='\0' && str[1]==':'); if (str[0]=='L') { dbgline.address=hex2long(str+2,&str); dbgline.line=(int32_t)hex2long(str,NULL); writeerror |= !pc_writebin(fout,&dbgline,sizeof dbgline); } /* if */ } /* for */ /* symbol table */ for (index=0; (str=get_dbgstring(index))!=NULL; index++) { assert(str!=NULL); assert(str[0]!='\0' && str[1]==':'); if (str[0]=='S') { dbgsym.address=hex2long(str+2,&str); dbgsym.tag=(int16_t)hex2long(str,&str); str=skipwhitespace(str); assert(*str==':'); name=skipwhitespace(str+1); str=strchr(name,' '); assert(str!=NULL); assert((int)(str-name)next) { assert(strlen(constptr->name)>0); id1=(int16_t)(constptr->value & TAGMASK); writeerror |= !pc_writebin(fout,&id1,sizeof id1); writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1); } /* for */ /* automaton table */ for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) { assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0); id1=(int16_t)constptr->index; address=(ucell)constptr->value; writeerror |= !pc_writebin(fout,&id1,sizeof id1); writeerror |= !pc_writebin(fout,&address,sizeof address); writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1); } /* for */ /* state table */ for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) { assert(strlen(constptr->name)>0); id1=(int16_t)constptr->value; id2=(int16_t)constptr->index; address=(ucell)constptr->value; writeerror |= !pc_writebin(fout,&id1,sizeof id1); writeerror |= !pc_writebin(fout,&id2,sizeof id2); writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1); } /* for */ delete_dbgstringtable(); }