sourcepawn/compiler/sc6.c
author David Anderson <dvander@alliedmods.net>
Tue May 15 04:59:24 2007 +0000 (2007-05-15)
changeset 798 3ae0debc74be
parent 689 1761955ca29d
child 1931 e0187c4811c5
permissions -rw-r--r--
core will now ignore missing natives starting with '@'
the compiler will now resolve aliased natives to single references and export '@' natives for each redundant entry
     1 /*  Pawn compiler - Binary code generation (the "assembler")
     2  *
     3  *  Copyright (c) ITB CompuPhase, 1997-2006
     4  *
     5  *  This software is provided "as-is", without any express or implied warranty.
     6  *  In no event will the authors be held liable for any damages arising from
     7  *  the use of this software.
     8  *
     9  *  Permission is granted to anyone to use this software for any purpose,
    10  *  including commercial applications, and to alter it and redistribute it
    11  *  freely, subject to the following restrictions:
    12  *
    13  *  1.  The origin of this software must not be misrepresented; you must not
    14  *      claim that you wrote the original software. If you use this software in
    15  *      a product, an acknowledgment in the product documentation would be
    16  *      appreciated but is not required.
    17  *  2.  Altered source versions must be plainly marked as such, and must not be
    18  *      misrepresented as being the original software.
    19  *  3.  This notice may not be removed or altered from any source distribution.
    20  *
    21  *  Version: $Id$
    22  */
    23 #include <assert.h>
    24 #include <stdio.h>
    25 #include <stdlib.h>     /* for macro max() */
    26 #include <stddef.h>     /* for macro offsetof() */
    27 #include <string.h>
    28 #include <ctype.h>
    29 #if defined FORTIFY
    30   #include <alloc/fortify.h>
    31 #endif
    32 #include "lstring.h"
    33 #include "sc.h"
    34 #include "amxdbg.h"
    35 #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
    36   #include <sclinux.h>
    37 #endif
    38 
    39 
    40 static void append_dbginfo(FILE *fout);
    41 
    42 
    43 typedef cell (*OPCODE_PROC)(FILE *fbin,char *params,cell opcode);
    44 
    45 typedef struct {
    46   cell opcode;
    47   char *name;
    48   int segment;          /* sIN_CSEG=parse in cseg, sIN_DSEG=parse in dseg */
    49   OPCODE_PROC func;
    50 } OPCODEC;
    51 
    52 static cell codeindex;  /* similar to "code_idx" */
    53 static cell *lbltab;    /* label table */
    54 static int writeerror;
    55 static int bytes_in, bytes_out;
    56 static jmp_buf compact_err;
    57 
    58 /* apparently, strtol() does not work correctly on very large (unsigned)
    59  * hexadecimal values */
    60 static ucell hex2long(const char *s,char **n)
    61 {
    62   ucell result=0L;
    63   int negate=FALSE;
    64   int digit;
    65 
    66   /* ignore leading whitespace */
    67   while (*s==' ' || *s=='\t')
    68     s++;
    69 
    70   /* allow a negation sign to create the two's complement of numbers */
    71   if (*s=='-') {
    72     negate=TRUE;
    73     s++;
    74   } /* if */
    75 
    76   assert((*s>='0' && *s<='9') || (*s>='a' && *s<='f') || (*s>='a' && *s<='f'));
    77   for ( ;; ) {
    78     if (*s>='0' && *s<='9')
    79       digit=*s-'0';
    80     else if (*s>='a' && *s<='f')
    81       digit=*s-'a' + 10;
    82     else if (*s>='A' && *s<='F')
    83       digit=*s-'A' + 10;
    84     else
    85       break;    /* probably whitespace */
    86     result=(result<<4) | digit;
    87     s++;
    88   } /* for */
    89   if (n!=NULL)
    90     *n=(char*)s;
    91   if (negate)
    92     result=(~result)+1; /* take two's complement of the result */
    93   return (ucell)result;
    94 }
    95 
    96 static ucell getparam(const char *s,char **n)
    97 {
    98   ucell result=0;
    99   for ( ;; ) {
   100     result+=hex2long(s,(char**)&s);
   101     if (*s!='+')
   102       break;
   103     s++;
   104   } /* for */
   105   if (n!=NULL)
   106     *n=(char*)s;
   107   return result;
   108 }
   109 
   110 #if BYTE_ORDER==BIG_ENDIAN
   111 static uint16_t *align16(uint16_t *v)
   112 {
   113   unsigned char *s = (unsigned char *)v;
   114   unsigned char t;
   115 
   116   /* swap two bytes */
   117   t=s[0];
   118   s[0]=s[1];
   119   s[1]=t;
   120   return v;
   121 }
   122 
   123 static uint32_t *align32(uint32_t *v)
   124 {
   125   unsigned char *s = (unsigned char *)v;
   126   unsigned char t;
   127 
   128   /* swap outer two bytes */
   129   t=s[0];
   130   s[0]=s[3];
   131   s[3]=t;
   132   /* swap inner two bytes */
   133   t=s[1];
   134   s[1]=s[2];
   135   s[2]=t;
   136   return v;
   137 }
   138 
   139 #if PAWN_CELL_SIZE>=64
   140 static uint64_t *align64(uint64_t *v)
   141 {
   142 	unsigned char *s = (unsigned char *)v;
   143 	unsigned char t;
   144 
   145 	t=s[0];
   146 	s[0]=s[7];
   147 	s[7]=t;
   148 
   149 	t=s[1];
   150 	s[1]=s[6];
   151 	s[6]=t;
   152 
   153 	t=s[2];
   154 	s[2]=s[5];
   155 	s[5]=t;
   156 
   157 	t=s[3];
   158 	s[3]=s[4];
   159 	s[4]=t;
   160 
   161 	return v;
   162 }
   163 #endif
   164 
   165   #if PAWN_CELL_SIZE==16
   166     #define aligncell(v)  align16(v)
   167   #elif PAWN_CELL_SIZE==32
   168     #define aligncell(v)  align32(v)
   169   #elif PAWN_CELL_SIZE==64
   170     #define aligncell(v)  align64(v)
   171   #endif
   172 #else
   173   #define align16(v)    (v)
   174   #define align32(v)    (v)
   175   #define aligncell(v)  (v)
   176 #endif
   177 
   178 static char *skipwhitespace(char *str)
   179 {
   180   while (isspace(*str))
   181     str++;
   182   return str;
   183 }
   184 
   185 static char *stripcomment(char *str)
   186 {
   187   char *ptr=strchr(str,';');
   188   if (ptr!=NULL) {
   189     *ptr++='\n';        /* terminate the line, but leave the '\n' */
   190     *ptr='\0';
   191   } /* if */
   192   return str;
   193 }
   194 
   195 static void write_encoded(FILE *fbin,ucell *c,int num)
   196 {
   197   #if PAWN_CELL_SIZE == 16
   198     #define ENC_MAX   3     /* a 16-bit cell is encoded in max. 3 bytes */
   199     #define ENC_MASK  0x03  /* after 2x7 bits, 2 bits remain to make 16 bits */
   200   #elif PAWN_CELL_SIZE == 32
   201     #define ENC_MAX   5     /* a 32-bit cell is encoded in max. 5 bytes */
   202     #define ENC_MASK  0x0f  /* after 4x7 bits, 4 bits remain to make 32 bits */
   203   #elif PAWN_CELL_SIZE == 64
   204     #define ENC_MAX   10    /* a 32-bit cell is encoded in max. 10 bytes */
   205     #define ENC_MASK  0x01  /* after 9x7 bits, 1 bit remains to make 64 bits */
   206   #endif
   207 
   208   assert(fbin!=NULL);
   209   while (num-->0) {
   210     if (sc_compress) {
   211       ucell p=(ucell)*c;
   212       unsigned char t[ENC_MAX];
   213       unsigned char code;
   214       int index;
   215       for (index=0; index<ENC_MAX; index++) {
   216         t[index]=(unsigned char)(p & 0x7f);     /* store 7 bits */
   217         p>>=7;
   218       } /* for */
   219       /* skip leading zeros */
   220       while (index>1 && t[index-1]==0 && (t[index-2] & 0x40)==0)
   221         index--;
   222       /* skip leading -1s */
   223       if (index==ENC_MAX && t[index-1]==ENC_MASK && (t[index-2] & 0x40)!=0)
   224         index--;
   225       while (index>1 && t[index-1]==0x7f && (t[index-2] & 0x40)!=0)
   226         index--;
   227       /* write high byte first, write continuation bits */
   228       assert(index>0);
   229       while (index-->0) {
   230         code=(unsigned char)((index==0) ? t[index] : (t[index]|0x80));
   231         writeerror |= !pc_writebin(fbin,&code,1);
   232         bytes_out++;
   233       } /* while */
   234       bytes_in+=sizeof *c;
   235       assert(AMX_COMPACTMARGIN>2);
   236       if (bytes_out-bytes_in>=AMX_COMPACTMARGIN-2)
   237         longjmp(compact_err,1);
   238     } else {
   239       assert((pc_lengthbin(fbin) % sizeof(cell)) == 0);
   240       writeerror |= !pc_writebin(fbin,aligncell(c),sizeof *c);
   241     } /* if */
   242     c++;
   243   } /* while */
   244 }
   245 
   246 #if defined __BORLANDC__ || defined __WATCOMC__
   247   #pragma argsused
   248 #endif
   249 static cell noop(FILE *fbin,char *params,cell opcode)
   250 {
   251   return 0;
   252 }
   253 
   254 #if defined __BORLANDC__ || defined __WATCOMC__
   255   #pragma argsused
   256 #endif
   257 static cell set_currentfile(FILE *fbin,char *params,cell opcode)
   258 {
   259   fcurrent=(short)getparam(params,NULL);
   260   return 0;
   261 }
   262 
   263 #if defined __BORLANDC__ || defined __WATCOMC__
   264   #pragma argsused
   265 #endif
   266 static cell parm0(FILE *fbin,char *params,cell opcode)
   267 {
   268   if (fbin!=NULL)
   269     write_encoded(fbin,(ucell*)&opcode,1);
   270   return opcodes(1);
   271 }
   272 
   273 static cell parm1(FILE *fbin,char *params,cell opcode)
   274 {
   275   ucell p=getparam(params,NULL);
   276   if (fbin!=NULL) {
   277     write_encoded(fbin,(ucell*)&opcode,1);
   278     write_encoded(fbin,&p,1);
   279   } /* if */
   280   return opcodes(1)+opargs(1);
   281 }
   282 
   283 static cell parm2(FILE *fbin,char *params,cell opcode)
   284 {
   285   ucell p1=getparam(params,&params);
   286   ucell p2=getparam(params,NULL);
   287   if (fbin!=NULL) {
   288     write_encoded(fbin,(ucell*)&opcode,1);
   289     write_encoded(fbin,&p1,1);
   290     write_encoded(fbin,&p2,1);
   291   } /* if */
   292   return opcodes(1)+opargs(2);
   293 }
   294 
   295 static cell parm3(FILE *fbin,char *params,cell opcode)
   296 {
   297   ucell p1=getparam(params,&params);
   298   ucell p2=getparam(params,&params);
   299   ucell p3=getparam(params,NULL);
   300   if (fbin!=NULL) {
   301     write_encoded(fbin,(ucell*)&opcode,1);
   302     write_encoded(fbin,&p1,1);
   303     write_encoded(fbin,&p2,1);
   304     write_encoded(fbin,&p3,1);
   305   } /* if */
   306   return opcodes(1)+opargs(3);
   307 }
   308 
   309 static cell parm4(FILE *fbin,char *params,cell opcode)
   310 {
   311   ucell p1=getparam(params,&params);
   312   ucell p2=getparam(params,&params);
   313   ucell p3=getparam(params,&params);
   314   ucell p4=getparam(params,NULL);
   315   if (fbin!=NULL) {
   316     write_encoded(fbin,(ucell*)&opcode,1);
   317     write_encoded(fbin,&p1,1);
   318     write_encoded(fbin,&p2,1);
   319     write_encoded(fbin,&p3,1);
   320     write_encoded(fbin,&p4,1);
   321   } /* if */
   322   return opcodes(1)+opargs(4);
   323 }
   324 
   325 static cell parm5(FILE *fbin,char *params,cell opcode)
   326 {
   327   ucell p1=getparam(params,&params);
   328   ucell p2=getparam(params,&params);
   329   ucell p3=getparam(params,&params);
   330   ucell p4=getparam(params,&params);
   331   ucell p5=getparam(params,NULL);
   332   if (fbin!=NULL) {
   333     write_encoded(fbin,(ucell*)&opcode,1);
   334     write_encoded(fbin,&p1,1);
   335     write_encoded(fbin,&p2,1);
   336     write_encoded(fbin,&p3,1);
   337     write_encoded(fbin,&p4,1);
   338     write_encoded(fbin,&p5,1);
   339   } /* if */
   340   return opcodes(1)+opargs(5);
   341 }
   342 
   343 #if defined __BORLANDC__ || defined __WATCOMC__
   344   #pragma argsused
   345 #endif
   346 static cell do_dump(FILE *fbin,char *params,cell opcode)
   347 {
   348   ucell p;
   349   int num = 0;
   350 
   351   while (*params!='\0') {
   352     p=getparam(params,&params);
   353     if (fbin!=NULL)
   354       write_encoded(fbin,&p,1);
   355     num++;
   356     while (isspace(*params))
   357       params++;
   358   } /* while */
   359   return num*sizeof(cell);
   360 }
   361 
   362 static cell do_call(FILE *fbin,char *params,cell opcode)
   363 {
   364   char name[sNAMEMAX+1];
   365   int i;
   366   symbol *sym;
   367   ucell p;
   368 
   369   for (i=0; !isspace(*params); i++,params++) {
   370     assert(*params!='\0');
   371     assert(i<sNAMEMAX);
   372     name[i]=*params;
   373   } /* for */
   374   name[i]='\0';
   375 
   376   if (name[0]=='l' && name[1]=='.') {
   377     /* this is a label, not a function symbol */
   378     i=(int)hex2long(name+2,NULL);
   379     assert(i>=0 && i<sc_labnum);
   380     if (fbin!=NULL) {
   381       assert(lbltab!=NULL);
   382       p=lbltab[i];
   383     } /* if */
   384   } else {
   385     /* look up the function address; note that the correct file number must
   386      * already have been set (in order for static globals to be found).
   387      */
   388     sym=findglb(name,sGLOBAL);
   389     assert(sym!=NULL);
   390     assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
   391     assert(sym->vclass==sGLOBAL);
   392     p=sym->addr;
   393   } /* if */
   394 
   395   if (fbin!=NULL) {
   396     write_encoded(fbin,(ucell*)&opcode,1);
   397     write_encoded(fbin,&p,1);
   398   } /* if */
   399   return opcodes(1)+opargs(1);
   400 }
   401 
   402 static cell do_jump(FILE *fbin,char *params,cell opcode)
   403 {
   404   int i;
   405   ucell p;
   406 
   407   i=(int)hex2long(params,NULL);
   408   assert(i>=0 && i<sc_labnum);
   409 
   410   if (fbin!=NULL) {
   411     assert(lbltab!=NULL);
   412     p=lbltab[i];
   413     write_encoded(fbin,(ucell*)&opcode,1);
   414     write_encoded(fbin,&p,1);
   415   } /* if */
   416   return opcodes(1)+opargs(1);
   417 }
   418 
   419 static cell do_switch(FILE *fbin,char *params,cell opcode)
   420 {
   421   int i;
   422   ucell p;
   423 
   424   i=(int)hex2long(params,NULL);
   425   assert(i>=0 && i<sc_labnum);
   426 
   427   if (fbin!=NULL) {
   428     assert(lbltab!=NULL);
   429     p=lbltab[i];
   430     write_encoded(fbin,(ucell*)&opcode,1);
   431     write_encoded(fbin,&p,1);
   432   } /* if */
   433   return opcodes(1)+opargs(1);
   434 }
   435 
   436 #if defined __BORLANDC__ || defined __WATCOMC__
   437   #pragma argsused
   438 #endif
   439 static cell do_case(FILE *fbin,char *params,cell opcode)
   440 {
   441   int i;
   442   ucell p,v;
   443 
   444   v=hex2long(params,&params);
   445   i=(int)hex2long(params,NULL);
   446   assert(i>=0 && i<sc_labnum);
   447 
   448   if (fbin!=NULL) {
   449     assert(lbltab!=NULL);
   450     p=lbltab[i];
   451     write_encoded(fbin,&v,1);
   452     write_encoded(fbin,&p,1);
   453   } /* if */
   454   return opcodes(0)+opargs(2);
   455 }
   456 
   457 static OPCODEC opcodelist[] = {
   458   /* node for "invalid instruction" */
   459   {  0, NULL,         0,        noop },
   460   /* opcodes in sorted order */
   461   { 78, "add",        sIN_CSEG, parm0 },
   462   { 87, "add.c",      sIN_CSEG, parm1 },
   463   { 14, "addr.alt",   sIN_CSEG, parm1 },
   464   { 13, "addr.pri",   sIN_CSEG, parm1 },
   465   { 30, "align.alt",  sIN_CSEG, parm1 },
   466   { 29, "align.pri",  sIN_CSEG, parm1 },
   467   { 81, "and",        sIN_CSEG, parm0 },
   468   {121, "bounds",     sIN_CSEG, parm1 },
   469   {137, "break",      sIN_CSEG, parm0 },  /* version 8 */
   470   { 49, "call",       sIN_CSEG, do_call },
   471   { 50, "call.pri",   sIN_CSEG, parm0 },
   472   {  0, "case",       sIN_CSEG, do_case },
   473   {130, "casetbl",    sIN_CSEG, parm0 },  /* version 1 */
   474   {118, "cmps",       sIN_CSEG, parm1 },
   475   {  0, "code",       sIN_CSEG, set_currentfile },
   476   {156, "const",      sIN_CSEG, parm2 },  /* version 9 */
   477   { 12, "const.alt",  sIN_CSEG, parm1 },
   478   { 11, "const.pri",  sIN_CSEG, parm1 },
   479   {157, "const.s",    sIN_CSEG, parm2 },  /* version 9 */
   480   {  0, "data",       sIN_DSEG, set_currentfile },
   481   {114, "dec",        sIN_CSEG, parm1 },
   482   {113, "dec.alt",    sIN_CSEG, parm0 },
   483   {116, "dec.i",      sIN_CSEG, parm0 },
   484   {112, "dec.pri",    sIN_CSEG, parm0 },
   485   {115, "dec.s",      sIN_CSEG, parm1 },
   486   {  0, "dump",       sIN_DSEG, do_dump },
   487   { 95, "eq",         sIN_CSEG, parm0 },
   488   {106, "eq.c.alt",   sIN_CSEG, parm1 },
   489   {105, "eq.c.pri",   sIN_CSEG, parm1 },
   490 /*{124, "file",       sIN_CSEG, do_file }, */
   491   {119, "fill",       sIN_CSEG, parm1 },
   492   {162, "genarray",   sIN_CSEG, parm1 },
   493   {163, "genarray.z", sIN_CSEG, parm1 },
   494   {100, "geq",        sIN_CSEG, parm0 },
   495   { 99, "grtr",       sIN_CSEG, parm0 },
   496   {120, "halt",       sIN_CSEG, parm1 },
   497   { 45, "heap",       sIN_CSEG, parm1 },
   498   { 27, "idxaddr",    sIN_CSEG, parm0 },
   499   { 28, "idxaddr.b",  sIN_CSEG, parm1 },
   500   {109, "inc",        sIN_CSEG, parm1 },
   501   {108, "inc.alt",    sIN_CSEG, parm0 },
   502   {111, "inc.i",      sIN_CSEG, parm0 },
   503   {107, "inc.pri",    sIN_CSEG, parm0 },
   504   {110, "inc.s",      sIN_CSEG, parm1 },
   505   { 86, "invert",     sIN_CSEG, parm0 },
   506   { 55, "jeq",        sIN_CSEG, do_jump },
   507   { 60, "jgeq",       sIN_CSEG, do_jump },
   508   { 59, "jgrtr",      sIN_CSEG, do_jump },
   509   { 58, "jleq",       sIN_CSEG, do_jump },
   510   { 57, "jless",      sIN_CSEG, do_jump },
   511   { 56, "jneq",       sIN_CSEG, do_jump },
   512   { 54, "jnz",        sIN_CSEG, do_jump },
   513   { 52, "jrel",       sIN_CSEG, parm1 },  /* always a number */
   514   { 64, "jsgeq",      sIN_CSEG, do_jump },
   515   { 63, "jsgrtr",     sIN_CSEG, do_jump },
   516   { 62, "jsleq",      sIN_CSEG, do_jump },
   517   { 61, "jsless",     sIN_CSEG, do_jump },
   518   { 51, "jump",       sIN_CSEG, do_jump },
   519   {128, "jump.pri",   sIN_CSEG, parm0 },  /* version 1 */
   520   { 53, "jzer",       sIN_CSEG, do_jump },
   521   { 31, "lctrl",      sIN_CSEG, parm1 },
   522   { 98, "leq",        sIN_CSEG, parm0 },
   523   { 97, "less",       sIN_CSEG, parm0 },
   524   { 25, "lidx",       sIN_CSEG, parm0 },
   525   { 26, "lidx.b",     sIN_CSEG, parm1 },
   526 /*{125, "line",       sIN_CSEG, parm2 }, */
   527   {  2, "load.alt",   sIN_CSEG, parm1 },
   528   {154, "load.both",  sIN_CSEG, parm2 },  /* version 9 */
   529   {  9, "load.i",     sIN_CSEG, parm0 },
   530   {  1, "load.pri",   sIN_CSEG, parm1 },
   531   {  4, "load.s.alt", sIN_CSEG, parm1 },
   532   {155, "load.s.both",sIN_CSEG, parm2 },  /* version 9 */
   533   {  3, "load.s.pri", sIN_CSEG, parm1 },
   534   { 10, "lodb.i",     sIN_CSEG, parm1 },
   535   {  6, "lref.alt",   sIN_CSEG, parm1 },
   536   {  5, "lref.pri",   sIN_CSEG, parm1 },
   537   {  8, "lref.s.alt", sIN_CSEG, parm1 },
   538   {  7, "lref.s.pri", sIN_CSEG, parm1 },
   539   { 34, "move.alt",   sIN_CSEG, parm0 },
   540   { 33, "move.pri",   sIN_CSEG, parm0 },
   541   {117, "movs",       sIN_CSEG, parm1 },
   542   { 85, "neg",        sIN_CSEG, parm0 },
   543   { 96, "neq",        sIN_CSEG, parm0 },
   544   {134, "nop",        sIN_CSEG, parm0 },  /* version 6 */
   545   { 84, "not",        sIN_CSEG, parm0 },
   546   { 82, "or",         sIN_CSEG, parm0 },
   547   { 43, "pop.alt",    sIN_CSEG, parm0 },
   548   { 42, "pop.pri",    sIN_CSEG, parm0 },
   549   { 46, "proc",       sIN_CSEG, parm0 },
   550   { 40, "push",       sIN_CSEG, parm1 },
   551   {133, "push.adr",   sIN_CSEG, parm1 },  /* version 4 */
   552   { 37, "push.alt",   sIN_CSEG, parm0 },
   553   { 39, "push.c",     sIN_CSEG, parm1 },
   554   { 36, "push.pri",   sIN_CSEG, parm0 },
   555   { 38, "push.r",     sIN_CSEG, parm1 },  /* obsolete (never generated) */
   556   { 41, "push.s",     sIN_CSEG, parm1 },
   557   {139, "push2",      sIN_CSEG, parm2 },  /* version 9 */
   558   {141, "push2.adr",  sIN_CSEG, parm2 },  /* version 9 */
   559   {138, "push2.c",    sIN_CSEG, parm2 },  /* version 9 */
   560   {140, "push2.s",    sIN_CSEG, parm2 },  /* version 9 */
   561   {143, "push3",      sIN_CSEG, parm3 },  /* version 9 */
   562   {145, "push3.adr",  sIN_CSEG, parm3 },  /* version 9 */
   563   {142, "push3.c",    sIN_CSEG, parm3 },  /* version 9 */
   564   {144, "push3.s",    sIN_CSEG, parm3 },  /* version 9 */
   565   {147, "push4",      sIN_CSEG, parm4 },  /* version 9 */
   566   {149, "push4.adr",  sIN_CSEG, parm4 },  /* version 9 */
   567   {146, "push4.c",    sIN_CSEG, parm4 },  /* version 9 */
   568   {148, "push4.s",    sIN_CSEG, parm4 },  /* version 9 */
   569   {151, "push5",      sIN_CSEG, parm5 },  /* version 9 */
   570   {153, "push5.adr",  sIN_CSEG, parm5 },  /* version 9 */
   571   {150, "push5.c",    sIN_CSEG, parm5 },  /* version 9 */
   572   {152, "push5.s",    sIN_CSEG, parm5 },  /* version 9 */
   573   { 47, "ret",        sIN_CSEG, parm0 },
   574   { 48, "retn",       sIN_CSEG, parm0 },
   575   { 32, "sctrl",      sIN_CSEG, parm1 },
   576   { 73, "sdiv",       sIN_CSEG, parm0 },
   577   { 74, "sdiv.alt",   sIN_CSEG, parm0 },
   578   {104, "sgeq",       sIN_CSEG, parm0 },
   579   {103, "sgrtr",      sIN_CSEG, parm0 },
   580   { 65, "shl",        sIN_CSEG, parm0 },
   581   { 69, "shl.c.alt",  sIN_CSEG, parm1 },
   582   { 68, "shl.c.pri",  sIN_CSEG, parm1 },
   583   { 66, "shr",        sIN_CSEG, parm0 },
   584   { 71, "shr.c.alt",  sIN_CSEG, parm1 },
   585   { 70, "shr.c.pri",  sIN_CSEG, parm1 },
   586   { 94, "sign.alt",   sIN_CSEG, parm0 },
   587   { 93, "sign.pri",   sIN_CSEG, parm0 },
   588   {102, "sleq",       sIN_CSEG, parm0 },
   589   {101, "sless",      sIN_CSEG, parm0 },
   590   { 72, "smul",       sIN_CSEG, parm0 },
   591   { 88, "smul.c",     sIN_CSEG, parm1 },
   592 /*{127, "srange",     sIN_CSEG, parm2 }, -- version 1 */
   593   { 20, "sref.alt",   sIN_CSEG, parm1 },
   594   { 19, "sref.pri",   sIN_CSEG, parm1 },
   595   { 22, "sref.s.alt", sIN_CSEG, parm1 },
   596   { 21, "sref.s.pri", sIN_CSEG, parm1 },
   597   { 67, "sshr",       sIN_CSEG, parm0 },
   598   { 44, "stack",      sIN_CSEG, parm1 },
   599   {  0, "stksize",    0,        noop },
   600   { 16, "stor.alt",   sIN_CSEG, parm1 },
   601   { 23, "stor.i",     sIN_CSEG, parm0 },
   602   { 15, "stor.pri",   sIN_CSEG, parm1 },
   603   { 18, "stor.s.alt", sIN_CSEG, parm1 },
   604   { 17, "stor.s.pri", sIN_CSEG, parm1 },
   605   {164, "stradjust.pri", sIN_CSEG, parm0 },
   606   { 24, "strb.i",     sIN_CSEG, parm1 },
   607   { 79, "sub",        sIN_CSEG, parm0 },
   608   { 80, "sub.alt",    sIN_CSEG, parm0 },
   609   {132, "swap.alt",   sIN_CSEG, parm0 },  /* version 4 */
   610   {131, "swap.pri",   sIN_CSEG, parm0 },  /* version 4 */
   611   {129, "switch",     sIN_CSEG, do_switch }, /* version 1 */
   612 /*{126, "symbol",     sIN_CSEG, do_symbol }, */
   613 /*{136, "symtag",     sIN_CSEG, parm1 },  -- version 7 */
   614   {123, "sysreq.c",   sIN_CSEG, parm1 },
   615   {135, "sysreq.n",   sIN_CSEG, parm2 },  /* version 9 (replaces SYSREQ.d from earlier version) */
   616   {122, "sysreq.pri", sIN_CSEG, parm0 },
   617   {161, "tracker.pop.setheap", sIN_CSEG, parm0 },
   618   {160, "tracker.push.c", sIN_CSEG, parm1 },
   619   { 76, "udiv",       sIN_CSEG, parm0 },
   620   { 77, "udiv.alt",   sIN_CSEG, parm0 },
   621   { 75, "umul",       sIN_CSEG, parm0 },
   622   { 35, "xchg",       sIN_CSEG, parm0 },
   623   { 83, "xor",        sIN_CSEG, parm0 },
   624   { 91, "zero",       sIN_CSEG, parm1 },
   625   { 90, "zero.alt",   sIN_CSEG, parm0 },
   626   { 89, "zero.pri",   sIN_CSEG, parm0 },
   627   { 92, "zero.s",     sIN_CSEG, parm1 },
   628 };
   629 
   630 #define MAX_INSTR_LEN   30
   631 static int findopcode(char *instr,int maxlen)
   632 {
   633   int low,high,mid,cmp;
   634   char str[MAX_INSTR_LEN];
   635 
   636   if (maxlen>=MAX_INSTR_LEN)
   637     return 0;
   638   strlcpy(str,instr,maxlen+1);
   639   /* look up the instruction with a binary search
   640    * the assembler is case insensitive to instructions (but case sensitive
   641    * to symbols)
   642    */
   643   low=1;                /* entry 0 is reserved (for "not found") */
   644   high=(sizeof opcodelist / sizeof opcodelist[0])-1;
   645   while (low<high) {
   646     mid=(low+high)/2;
   647     assert(opcodelist[mid].name!=NULL);
   648     cmp=stricmp(str,opcodelist[mid].name);
   649     if (cmp>0)
   650       low=mid+1;
   651     else
   652       high=mid;
   653   } /* while */
   654 
   655   assert(low==high);
   656   if (stricmp(str,opcodelist[low].name)==0)
   657     return low;         /* found */
   658   return 0;             /* not found, return special index */
   659 }
   660 
   661 SC_FUNC int assemble(FILE *fout,FILE *fin)
   662 {
   663   AMX_HEADER hdr;
   664   AMX_FUNCSTUBNT func;
   665   int numpublics,numnatives,numlibraries,numpubvars,numtags,padding;
   666   long nametablesize,nameofs;
   667   #if PAWN_CELL_SIZE > 32
   668     char line[512];
   669   #else
   670     char line[256];
   671   #endif
   672   char *instr,*params;
   673   int i,pass,size;
   674   int16_t count;
   675   symbol *sym, **nativelist;
   676   constvalue *constptr;
   677   cell mainaddr;
   678   char nullchar;
   679   char testalias[sNAMEMAX+1];
   680 
   681   /* if compression failed, restart the assembly with compaction switched off */
   682   if (setjmp(compact_err)!=0) {
   683     assert(sc_compress);  /* cannot arrive here if compact encoding was disabled */
   684     sc_compress=FALSE;
   685     pc_resetbin(fout,0);
   686     error(232);           /* disabled compact encoding */
   687   } /* if */
   688 
   689   #if !defined NDEBUG
   690     /* verify that the opcode list is sorted (skip entry 1; it is reserved
   691      * for a non-existant opcode)
   692      */
   693     assert(opcodelist[1].name!=NULL);
   694     for (i=2; i<(sizeof opcodelist / sizeof opcodelist[0]); i++) {
   695       assert(opcodelist[i].name!=NULL);
   696       assert(stricmp(opcodelist[i].name,opcodelist[i-1].name)>0);
   697     } /* for */
   698   #endif
   699 
   700   writeerror=FALSE;
   701   nametablesize=sizeof(int16_t);
   702   numpublics=0;
   703   numnatives=0;
   704   numpubvars=0;
   705   mainaddr=-1;
   706   /* count number of public and native functions and public variables */
   707   for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
   708     int match=0;
   709     if (sym->ident==iFUNCTN) {
   710       if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
   711         match=++numnatives;
   712       }
   713       if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
   714         match=++numpublics;
   715       if (strcmp(sym->name,uMAINFUNC)==0) {
   716         assert(sym->vclass==sGLOBAL);
   717         mainaddr=sym->addr;
   718       } /* if */
   719     } else if (sym->ident==iVARIABLE || sym->ident == iARRAY || sym->ident == iREFARRAY) {
   720       if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0)
   721         match=++numpubvars;
   722     } /* if */
   723     if (match) {
   724       const char *aliasptr = sym->name;
   725       assert(sym!=NULL);
   726       if (((sym->usage & uNATIVE)!=0) && lookup_alias(testalias,sym->name)) {
   727         aliasptr = "@";
   728       } /* if */
   729       nametablesize+=strlen(aliasptr)+1;
   730     } /* if */
   731   } /* for */
   732   assert(numnatives==ntv_funcid);
   733 
   734   /* count number of libraries */
   735   numlibraries=0;
   736   if (pc_addlibtable) {
   737     for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
   738       if (constptr->value>0) {
   739         assert(strlen(constptr->name)>0);
   740         numlibraries++;
   741         nametablesize+=strlen(constptr->name)+1;
   742       } /* if */
   743     } /* for */
   744   } /* if */
   745 
   746   /* count number of public tags */
   747   numtags=0;
   748   for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
   749     /*if ((constptr->value & PUBLICTAG)!=0) {*/
   750       assert(strlen(constptr->name)>0);
   751       numtags++;
   752       nametablesize+=strlen(constptr->name)+1;
   753     /*} if */
   754   } /* for */
   755 
   756   /* pad the header to sc_dataalign
   757    * => thereby the code segment is aligned
   758    * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned
   759    * => and thereby the stack top is aligned too
   760    */
   761   assert(sc_dataalign!=0);
   762   padding= (int)(sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign);
   763   if (padding==sc_dataalign)
   764     padding=0;
   765 
   766   /* write the abstract machine header */
   767   memset(&hdr, 0, sizeof hdr);
   768   hdr.magic=(unsigned short)AMX_MAGIC;
   769   hdr.file_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MAX_FILE_VER_JIT : CUR_FILE_VERSION);
   770   hdr.amx_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MIN_AMX_VER_JIT : MIN_AMX_VERSION);
   771   hdr.flags=(short)(sc_debug & sSYMBOLIC);
   772   if (sc_compress)
   773     hdr.flags|=AMX_FLAG_COMPACT;
   774   if (sc_debug==0)
   775     hdr.flags|=AMX_FLAG_NOCHECKS;
   776   if (pc_memflags & suSLEEP_INSTR)
   777     hdr.flags|=AMX_FLAG_SLEEP;
   778   hdr.defsize=sizeof(AMX_FUNCSTUBNT);
   779   hdr.publics=sizeof hdr; /* public table starts right after the header */
   780   hdr.natives=hdr.publics + numpublics*sizeof(AMX_FUNCSTUBNT);
   781   hdr.libraries=hdr.natives + numnatives*sizeof(AMX_FUNCSTUBNT);
   782   hdr.pubvars=hdr.libraries + numlibraries*sizeof(AMX_FUNCSTUBNT);
   783   hdr.tags=hdr.pubvars + numpubvars*sizeof(AMX_FUNCSTUBNT);
   784   hdr.nametable=hdr.tags + numtags*sizeof(AMX_FUNCSTUBNT);
   785   hdr.cod=hdr.nametable + nametablesize + padding;
   786   hdr.dat=hdr.cod + code_idx;
   787   hdr.hea=hdr.dat + glb_declared*sizeof(cell);
   788   hdr.stp=hdr.hea + pc_stksize*sizeof(cell);
   789   hdr.cip=mainaddr;
   790   hdr.size=hdr.hea; /* preset, this is incorrect in case of compressed output */
   791   pc_writebin(fout,&hdr,sizeof hdr);
   792 
   793   /* dump zeros up to the rest of the header, so that we can easily "seek" */
   794   nullchar='\0';
   795   for (nameofs=sizeof hdr; nameofs<hdr.cod; nameofs++)
   796     pc_writebin(fout,&nullchar,1);
   797   nameofs=hdr.nametable+sizeof(int16_t);
   798 
   799   /* write the public functions table */
   800   count=0;
   801   for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
   802     if (sym->ident==iFUNCTN
   803         && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
   804     {
   805       assert(sym->vclass==sGLOBAL);
   806       func.address=sym->addr;
   807       func.nameofs=nameofs;
   808       #if BYTE_ORDER==BIG_ENDIAN
   809         align32(&func.address);
   810         align32(&func.nameofs);
   811       #endif
   812       pc_resetbin(fout,hdr.publics+count*sizeof(AMX_FUNCSTUBNT));
   813       pc_writebin(fout,&func,sizeof func);
   814       pc_resetbin(fout,nameofs);
   815       pc_writebin(fout,sym->name,strlen(sym->name)+1);
   816       nameofs+=strlen(sym->name)+1;
   817       count++;
   818     } /* if */
   819   } /* for */
   820 
   821   /* write the natives table */
   822   /* The native functions must be written in sorted order. (They are
   823    * sorted on their "id", not on their name). A nested loop to find
   824    * each successive function would be an O(n^2) operation. But we
   825    * do not really need to sort, because the native function id's
   826    * are sequential and there are no duplicates. So we first walk
   827    * through the complete symbol list and store a pointer to every
   828    * native function of interest in a temporary table, where its id
   829    * serves as the index in the table. Now we can walk the table and
   830    * have all native functions in sorted order.
   831    */
   832   if (numnatives>0) {
   833     nativelist=(symbol **)malloc(numnatives*sizeof(symbol *));
   834     if (nativelist==NULL)
   835       error(103);               /* insufficient memory */
   836     #if !defined NDEBUG
   837       memset(nativelist,0,numnatives*sizeof(symbol *)); /* for NULL checking */
   838     #endif
   839     for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
   840       if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
   841         assert(sym->addr < numnatives);
   842         nativelist[(int)sym->addr]=sym;
   843       } /* if */
   844     } /* for */
   845     count=0;
   846     for (i=0; i<numnatives; i++) {
   847       const char *aliasptr;
   848       sym=nativelist[i];
   849       assert(sym!=NULL);
   850       aliasptr = sym->name;
   851       if (lookup_alias(testalias,sym->name)) {
   852         aliasptr = "@";
   853       }
   854       assert(sym->vclass==sGLOBAL);
   855       func.address=0;
   856       func.nameofs=nameofs;
   857       #if BYTE_ORDER==BIG_ENDIAN
   858         align32(&func.address);
   859         align32(&func.nameofs);
   860       #endif
   861       pc_resetbin(fout,hdr.natives+count*sizeof(AMX_FUNCSTUBNT));
   862       pc_writebin(fout,&func,sizeof func);
   863       pc_resetbin(fout,nameofs);
   864       pc_writebin(fout,(void *)aliasptr,strlen(aliasptr)+1);
   865       nameofs+=strlen(aliasptr)+1;
   866       count++;
   867     } /* for */
   868     free(nativelist);
   869   } /* if */
   870 
   871   /* write the libraries table */
   872   if (pc_addlibtable) {
   873     count=0;
   874     for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
   875       if (constptr->value>0) {
   876         assert(strlen(constptr->name)>0);
   877         func.address=0;
   878         func.nameofs=nameofs;
   879         #if BYTE_ORDER==BIG_ENDIAN
   880           align32(&func.address);
   881           align32(&func.nameofs);
   882         #endif
   883         pc_resetbin(fout,hdr.libraries+count*sizeof(AMX_FUNCSTUBNT));
   884         pc_writebin(fout,&func,sizeof func);
   885         pc_resetbin(fout,nameofs);
   886         pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
   887         nameofs+=strlen(constptr->name)+1;
   888         count++;
   889       } /* if */
   890     } /* for */
   891   } /* if */
   892 
   893   /* write the public variables table */
   894   count=0;
   895   for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
   896     if ((sym->ident==iVARIABLE || sym->ident==iARRAY || sym->ident==iREFARRAY)
   897         && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) {
   898       //removed until structs don't seem to mess this up
   899       //assert((sym->usage & uDEFINE)!=0);
   900       assert(sym->vclass==sGLOBAL);
   901       func.address=sym->addr;
   902       func.nameofs=nameofs;
   903       #if BYTE_ORDER==BIG_ENDIAN
   904         align32(&func.address);
   905         align32(&func.nameofs);
   906       #endif
   907       pc_resetbin(fout,hdr.pubvars+count*sizeof(AMX_FUNCSTUBNT));
   908       pc_writebin(fout,&func,sizeof func);
   909       pc_resetbin(fout,nameofs);
   910       pc_writebin(fout,sym->name,strlen(sym->name)+1);
   911       nameofs+=strlen(sym->name)+1;
   912       count++;
   913     } /* if */
   914   } /* for */
   915 
   916   /* write the public tagnames table */
   917   count=0;
   918   for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
   919     /*if ((constptr->value & PUBLICTAG)!=0) {*/
   920       assert(strlen(constptr->name)>0);
   921       func.address=constptr->value & TAGMASK;
   922       func.nameofs=nameofs;
   923       #if BYTE_ORDER==BIG_ENDIAN
   924         align32(&func.address);
   925         align32(&func.nameofs);
   926       #endif
   927       pc_resetbin(fout,hdr.tags+count*sizeof(AMX_FUNCSTUBNT));
   928       pc_writebin(fout,&func,sizeof func);
   929       pc_resetbin(fout,nameofs);
   930       pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
   931       nameofs+=strlen(constptr->name)+1;
   932       count++;
   933     /*} if */
   934   } /* for */
   935 
   936   /* write the "maximum name length" field in the name table */
   937   assert(nameofs==hdr.nametable+nametablesize);
   938   pc_resetbin(fout,hdr.nametable);
   939   count=sNAMEMAX;
   940   #if BYTE_ORDER==BIG_ENDIAN
   941     align16(&count);
   942   #endif
   943   pc_writebin(fout,&count,sizeof count);
   944   pc_resetbin(fout,hdr.cod);
   945 
   946   /* First pass: relocate all labels */
   947   /* This pass is necessary because the code addresses of labels is only known
   948    * after the peephole optimization flag. Labels can occur inside expressions
   949    * (e.g. the conditional operator), which are optimized.
   950    */
   951   lbltab=NULL;
   952   if (sc_labnum>0) {
   953     /* only very short programs have zero labels; no first pass is needed
   954      * if there are no labels */
   955     lbltab=(cell *)malloc(sc_labnum*sizeof(cell));
   956     if (lbltab==NULL)
   957       error(103);               /* insufficient memory */
   958     codeindex=0;
   959     pc_resetasm(fin);
   960     while (pc_readasm(fin,line,sizeof line)!=NULL) {
   961       stripcomment(line);
   962       instr=skipwhitespace(line);
   963       /* ignore empty lines */
   964       if (*instr=='\0')
   965         continue;
   966       if (tolower(*instr)=='l' && *(instr+1)=='.') {
   967         int lindex=(int)hex2long(instr+2,NULL);
   968         assert(lindex>=0 && lindex<sc_labnum);
   969         lbltab[lindex]=codeindex;
   970       } else {
   971         /* get to the end of the instruction (make use of the '\n' that fgets()
   972          * added at the end of the line; this way we will *always* drop on a
   973          * whitespace character) */
   974         for (params=instr; *params!='\0' && !isspace(*params); params++)
   975           /* nothing */;
   976         assert(params>instr);
   977         i=findopcode(instr,(int)(params-instr));
   978         if (opcodelist[i].name==NULL) {
   979           *params='\0';
   980           error(104,instr);     /* invalid assembler instruction */
   981         } /* if */
   982         if (opcodelist[i].segment==sIN_CSEG)
   983           codeindex+=opcodelist[i].func(NULL,skipwhitespace(params),opcodelist[i].opcode);
   984       } /* if */
   985     } /* while */
   986   } /* if */
   987 
   988   /* Second pass (actually 2 more passes, one for all code and one for all data) */
   989   bytes_in=0;
   990   bytes_out=0;
   991   for (pass=sIN_CSEG; pass<=sIN_DSEG; pass++) {
   992     pc_resetasm(fin);
   993     while (pc_readasm(fin,line,sizeof line)!=NULL) {
   994       stripcomment(line);
   995       instr=skipwhitespace(line);
   996       /* ignore empty lines and labels (labels have a special syntax, so these
   997        * must be parsed separately) */
   998       if (*instr=='\0' || tolower(*instr)=='l' && *(instr+1)=='.')
   999         continue;
  1000       /* get to the end of the instruction (make use of the '\n' that fgets()
  1001        * added at the end of the line; this way we will *always* drop on a
  1002        * whitespace character) */
  1003       for (params=instr; *params!='\0' && !isspace(*params); params++)
  1004         /* nothing */;
  1005       assert(params>instr);
  1006       i=findopcode(instr,(int)(params-instr));
  1007       assert(opcodelist[i].name!=NULL);
  1008       if (opcodelist[i].segment==pass)
  1009         opcodelist[i].func(fout,skipwhitespace(params),opcodelist[i].opcode);
  1010     } /* while */
  1011   } /* for */
  1012   if (bytes_out-bytes_in>0)
  1013     error(106);         /* compression buffer overflow */
  1014 
  1015   if (lbltab!=NULL) {
  1016     free(lbltab);
  1017     #if !defined NDEBUG
  1018       lbltab=NULL;
  1019     #endif
  1020   } /* if */
  1021 
  1022   if (sc_compress)
  1023     hdr.size=pc_lengthbin(fout);/* get this value before appending debug info */
  1024   if (!writeerror && (sc_debug & sSYMBOLIC)!=0)
  1025     append_dbginfo(fout);       /* optionally append debug file */
  1026 
  1027   if (writeerror)
  1028     error(101,"disk full");
  1029 
  1030   /* adjust the header */
  1031   size=(int)hdr.cod;    /* save, the value in the header may be swapped */
  1032   #if BYTE_ORDER==BIG_ENDIAN
  1033     align32(&hdr.size);
  1034     align16(&hdr.magic);
  1035     align16(&hdr.flags);
  1036     align16(&hdr.defsize);
  1037     align32(&hdr.publics);
  1038     align32(&hdr.natives);
  1039     align32(&hdr.libraries);
  1040     align32(&hdr.pubvars);
  1041     align32(&hdr.tags);
  1042     align32(&hdr.nametable);
  1043     align32(&hdr.cod);
  1044     align32(&hdr.dat);
  1045     align32(&hdr.hea);
  1046     align32(&hdr.stp);
  1047     align32(&hdr.cip);
  1048   #endif
  1049   pc_resetbin(fout,0);
  1050   pc_writebin(fout,&hdr,sizeof hdr);
  1051 
  1052   /* return the size of the header (including name tables, but excluding code
  1053    * or data sections)
  1054    */
  1055   return size;
  1056 }
  1057 
  1058 static void append_dbginfo(FILE *fout)
  1059 {
  1060   AMX_DBG_HDR dbghdr;
  1061   AMX_DBG_LINE dbgline;
  1062   AMX_DBG_SYMBOL dbgsym;
  1063   AMX_DBG_SYMDIM dbgidxtag[sDIMEN_MAX];
  1064   int index,dim,dbgsymdim;
  1065   char *str,*prevstr,*name,*prevname;
  1066   ucell codeidx,previdx;
  1067   constvalue *constptr;
  1068   char symname[2*sNAMEMAX+16];
  1069   int16_t id1,id2;
  1070   ucell address;
  1071 
  1072   /* header with general information */
  1073   memset(&dbghdr, 0, sizeof dbghdr);
  1074   dbghdr.size=sizeof dbghdr;
  1075   dbghdr.magic=AMX_DBG_MAGIC;
  1076   dbghdr.file_version=CUR_FILE_VERSION;
  1077   dbghdr.amx_version=MIN_AMX_VERSION;
  1078 
  1079   /* first pass: collect the number of items in various tables */
  1080 
  1081   /* file table */
  1082   previdx=0;
  1083   prevstr=NULL;
  1084   prevname=NULL;
  1085   for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1086     assert(str!=NULL);
  1087     assert(str[0]!='\0' && str[1]==':');
  1088     if (str[0]=='F') {
  1089       codeidx=hex2long(str+2,&name);
  1090       if (codeidx!=previdx) {
  1091         if (prevstr!=NULL) {
  1092           assert(prevname!=NULL);
  1093           dbghdr.files++;
  1094           dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
  1095         } /* if */
  1096         previdx=codeidx;
  1097       } /* if */
  1098       prevstr=str;
  1099       prevname=skipwhitespace(name);
  1100     } /* if */
  1101   } /* for */
  1102   if (prevstr!=NULL) {
  1103     assert(prevname!=NULL);
  1104     dbghdr.files++;
  1105     dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
  1106   } /* if */
  1107 
  1108   /* line number table */
  1109   for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1110     assert(str!=NULL);
  1111     assert(str[0]!='\0' && str[1]==':');
  1112     if (str[0]=='L') {
  1113       dbghdr.lines++;
  1114       dbghdr.size+=sizeof(AMX_DBG_LINE);
  1115     } /* if */
  1116   } /* for */
  1117 
  1118   /* symbol table */
  1119   for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1120     assert(str!=NULL);
  1121     assert(str[0]!='\0' && str[1]==':');
  1122     if (str[0]=='S') {
  1123       dbghdr.symbols++;
  1124       name=strchr(str+2,':');
  1125       assert(name!=NULL);
  1126       dbghdr.size+=sizeof(AMX_DBG_SYMBOL)+strlen(skipwhitespace(name+1));
  1127       if ((prevstr=strchr(name,'['))!=NULL)
  1128         while ((prevstr=strchr(prevstr+1,':'))!=NULL)
  1129           dbghdr.size+=sizeof(AMX_DBG_SYMDIM);
  1130     } /* if */
  1131   } /* for */
  1132 
  1133   /* tag table */
  1134   for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
  1135     assert(strlen(constptr->name)>0);
  1136     dbghdr.tags++;
  1137     dbghdr.size+=sizeof(AMX_DBG_TAG)+strlen(constptr->name);
  1138   } /* for */
  1139 
  1140   /* automaton table */
  1141   for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
  1142     assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
  1143     dbghdr.automatons++;
  1144     dbghdr.size+=sizeof(AMX_DBG_MACHINE)+strlen(constptr->name);
  1145   } /* for */
  1146 
  1147   /* state table */
  1148   for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
  1149     assert(strlen(constptr->name)>0);
  1150     dbghdr.states++;
  1151     dbghdr.size+=sizeof(AMX_DBG_STATE)+strlen(constptr->name);
  1152   } /* for */
  1153 
  1154 
  1155   /* pass 2: generate the tables */
  1156   #if BYTE_ORDER==BIG_ENDIAN
  1157     align32((uint32_t*)&dbghdr.size);
  1158     align16(&dbghdr.magic);
  1159     align16(&dbghdr.flags);
  1160     align16(&dbghdr.files);
  1161     align16(&dbghdr.lines);
  1162     align16(&dbghdr.symbols);
  1163     align16(&dbghdr.tags);
  1164     align16(&dbghdr.automatons);
  1165     align16(&dbghdr.states);
  1166   #endif
  1167   writeerror |= !pc_writebin(fout,&dbghdr,sizeof dbghdr);
  1168 
  1169   /* file table */
  1170   previdx=0;
  1171   prevstr=NULL;
  1172   prevname=NULL;
  1173   for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1174     assert(str!=NULL);
  1175     assert(str[0]!='\0' && str[1]==':');
  1176     if (str[0]=='F') {
  1177       codeidx=hex2long(str+2,&name);
  1178       if (codeidx!=previdx) {
  1179         if (prevstr!=NULL) {
  1180           assert(prevname!=NULL);
  1181           #if BYTE_ORDER==BIG_ENDIAN
  1182             aligncell(&previdx);
  1183           #endif
  1184           writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
  1185           writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
  1186         } /* if */
  1187         previdx=codeidx;
  1188       } /* if */
  1189       prevstr=str;
  1190       prevname=skipwhitespace(name);
  1191     } /* if */
  1192   } /* for */
  1193   if (prevstr!=NULL) {
  1194     assert(prevname!=NULL);
  1195     #if BYTE_ORDER==BIG_ENDIAN
  1196       aligncell(&previdx);
  1197     #endif
  1198     writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
  1199     writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
  1200   } /* if */
  1201 
  1202   /* line number table */
  1203   for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1204     assert(str!=NULL);
  1205     assert(str[0]!='\0' && str[1]==':');
  1206     if (str[0]=='L') {
  1207       dbgline.address=hex2long(str+2,&str);
  1208       dbgline.line=(int32_t)hex2long(str,NULL);
  1209       #if BYTE_ORDER==BIG_ENDIAN
  1210         aligncell(&dbgline.address);
  1211         align32(&dbgline.line);
  1212       #endif
  1213       writeerror |= !pc_writebin(fout,&dbgline,sizeof dbgline);
  1214     } /* if */
  1215   } /* for */
  1216 
  1217   /* symbol table */
  1218   for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1219     assert(str!=NULL);
  1220     assert(str[0]!='\0' && str[1]==':');
  1221     if (str[0]=='S') {
  1222       dbgsym.address=hex2long(str+2,&str);
  1223       dbgsym.tag=(int16_t)hex2long(str,&str);
  1224       str=skipwhitespace(str);
  1225       assert(*str==':');
  1226       name=skipwhitespace(str+1);
  1227       str=strchr(name,' ');
  1228       assert(str!=NULL);
  1229       assert((int)(str-name)<sizeof symname);
  1230       strlcpy(symname,name,(int)(str-name)+1);
  1231       dbgsym.codestart=hex2long(str,&str);
  1232       dbgsym.codeend=hex2long(str,&str);
  1233       dbgsym.ident=(char)hex2long(str,&str);
  1234       dbgsym.vclass=(char)hex2long(str,&str);
  1235       dbgsym.dim=0;
  1236       str=skipwhitespace(str);
  1237       if (*str=='[') {
  1238         while (*(str=skipwhitespace(str+1))!=']') {
  1239           dbgidxtag[dbgsym.dim].tag=(int16_t)hex2long(str,&str);
  1240           str=skipwhitespace(str);
  1241           assert(*str==':');
  1242           dbgidxtag[dbgsym.dim].size=hex2long(str+1,&str);
  1243           dbgsym.dim++;
  1244         } /* while */
  1245       } /* if */
  1246       dbgsymdim = dbgsym.dim;
  1247       #if BYTE_ORDER==BIG_ENDIAN
  1248         aligncell(&dbgsym.address);
  1249         align16(&dbgsym.tag);
  1250         aligncell(&dbgsym.codestart);
  1251         aligncell(&dbgsym.codeend);
  1252         align16(&dbgsym.dim);
  1253       #endif
  1254       writeerror |= !pc_writebin(fout,&dbgsym,offsetof(AMX_DBG_SYMBOL, name));
  1255       writeerror |= !pc_writebin(fout,symname,strlen(symname)+1);
  1256       for (dim=0; dim<dbgsymdim; dim++) {
  1257         #if BYTE_ORDER==BIG_ENDIAN
  1258           align16(&dbgidxtag[dim].tag);
  1259           aligncell(&dbgidxtag[dim].size);
  1260         #endif
  1261         writeerror |= !pc_writebin(fout,&dbgidxtag[dim],sizeof dbgidxtag[dim]);
  1262       } /* for */
  1263     } /* if */
  1264   } /* for */
  1265 
  1266   /* tag table */
  1267   for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
  1268     assert(strlen(constptr->name)>0);
  1269     id1=(int16_t)(constptr->value & TAGMASK);
  1270     #if BYTE_ORDER==BIG_ENDIAN
  1271       align16(&id1);
  1272     #endif
  1273     writeerror |= !pc_writebin(fout,&id1,sizeof id1);
  1274     writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
  1275   } /* for */
  1276 
  1277   /* automaton table */
  1278   for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
  1279     assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
  1280     id1=(int16_t)constptr->index;
  1281     address=(ucell)constptr->value;
  1282     #if BYTE_ORDER==BIG_ENDIAN
  1283       align16(&id1);
  1284       aligncell(&address);
  1285     #endif
  1286     writeerror |= !pc_writebin(fout,&id1,sizeof id1);
  1287     writeerror |= !pc_writebin(fout,&address,sizeof address);
  1288     writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
  1289   } /* for */
  1290 
  1291   /* state table */
  1292   for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
  1293     assert(strlen(constptr->name)>0);
  1294     id1=(int16_t)constptr->value;
  1295     id2=(int16_t)constptr->index;
  1296     address=(ucell)constptr->value;
  1297     #if BYTE_ORDER==BIG_ENDIAN
  1298       align16(&id1);
  1299       align16(&id2);
  1300     #endif
  1301     writeerror |= !pc_writebin(fout,&id1,sizeof id1);
  1302     writeerror |= !pc_writebin(fout,&id2,sizeof id2);
  1303     writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
  1304   } /* for */
  1305 
  1306   delete_dbgstringtable();
  1307 }