sourcepawn/compiler/sc6.c
changeset 1952 b7aa2b626807
child 2289 44045ead61cd
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/sourcepawn/compiler/sc6.c	Sun Mar 30 07:00:22 2008 +0000
     1.3 @@ -0,0 +1,1308 @@
     1.4 +/*  Pawn compiler - Binary code generation (the "assembler")
     1.5 + *
     1.6 + *  Copyright (c) ITB CompuPhase, 1997-2006
     1.7 + *
     1.8 + *  This software is provided "as-is", without any express or implied warranty.
     1.9 + *  In no event will the authors be held liable for any damages arising from
    1.10 + *  the use of this software.
    1.11 + *
    1.12 + *  Permission is granted to anyone to use this software for any purpose,
    1.13 + *  including commercial applications, and to alter it and redistribute it
    1.14 + *  freely, subject to the following restrictions:
    1.15 + *
    1.16 + *  1.  The origin of this software must not be misrepresented; you must not
    1.17 + *      claim that you wrote the original software. If you use this software in
    1.18 + *      a product, an acknowledgment in the product documentation would be
    1.19 + *      appreciated but is not required.
    1.20 + *  2.  Altered source versions must be plainly marked as such, and must not be
    1.21 + *      misrepresented as being the original software.
    1.22 + *  3.  This notice may not be removed or altered from any source distribution.
    1.23 + *
    1.24 + *  Version: $Id$
    1.25 + */
    1.26 +#include <assert.h>
    1.27 +#include <stdio.h>
    1.28 +#include <stdlib.h>     /* for macro max() */
    1.29 +#include <stddef.h>     /* for macro offsetof() */
    1.30 +#include <string.h>
    1.31 +#include <ctype.h>
    1.32 +#if defined FORTIFY
    1.33 +  #include <alloc/fortify.h>
    1.34 +#endif
    1.35 +#include "lstring.h"
    1.36 +#include "sc.h"
    1.37 +#include "amxdbg.h"
    1.38 +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
    1.39 +  #include <sclinux.h>
    1.40 +#endif
    1.41 +
    1.42 +
    1.43 +static void append_dbginfo(FILE *fout);
    1.44 +
    1.45 +
    1.46 +typedef cell (*OPCODE_PROC)(FILE *fbin,char *params,cell opcode);
    1.47 +
    1.48 +typedef struct {
    1.49 +  cell opcode;
    1.50 +  char *name;
    1.51 +  int segment;          /* sIN_CSEG=parse in cseg, sIN_DSEG=parse in dseg */
    1.52 +  OPCODE_PROC func;
    1.53 +} OPCODEC;
    1.54 +
    1.55 +static cell codeindex;  /* similar to "code_idx" */
    1.56 +static cell *lbltab;    /* label table */
    1.57 +static int writeerror;
    1.58 +static int bytes_in, bytes_out;
    1.59 +static jmp_buf compact_err;
    1.60 +
    1.61 +/* apparently, strtol() does not work correctly on very large (unsigned)
    1.62 + * hexadecimal values */
    1.63 +static ucell hex2long(const char *s,char **n)
    1.64 +{
    1.65 +  ucell result=0L;
    1.66 +  int negate=FALSE;
    1.67 +  int digit;
    1.68 +
    1.69 +  /* ignore leading whitespace */
    1.70 +  while (*s==' ' || *s=='\t')
    1.71 +    s++;
    1.72 +
    1.73 +  /* allow a negation sign to create the two's complement of numbers */
    1.74 +  if (*s=='-') {
    1.75 +    negate=TRUE;
    1.76 +    s++;
    1.77 +  } /* if */
    1.78 +
    1.79 +  assert((*s>='0' && *s<='9') || (*s>='a' && *s<='f') || (*s>='a' && *s<='f'));
    1.80 +  for ( ;; ) {
    1.81 +    if (*s>='0' && *s<='9')
    1.82 +      digit=*s-'0';
    1.83 +    else if (*s>='a' && *s<='f')
    1.84 +      digit=*s-'a' + 10;
    1.85 +    else if (*s>='A' && *s<='F')
    1.86 +      digit=*s-'A' + 10;
    1.87 +    else
    1.88 +      break;    /* probably whitespace */
    1.89 +    result=(result<<4) | digit;
    1.90 +    s++;
    1.91 +  } /* for */
    1.92 +  if (n!=NULL)
    1.93 +    *n=(char*)s;
    1.94 +  if (negate)
    1.95 +    result=(~result)+1; /* take two's complement of the result */
    1.96 +  return (ucell)result;
    1.97 +}
    1.98 +
    1.99 +static ucell getparam(const char *s,char **n)
   1.100 +{
   1.101 +  ucell result=0;
   1.102 +  for ( ;; ) {
   1.103 +    result+=hex2long(s,(char**)&s);
   1.104 +    if (*s!='+')
   1.105 +      break;
   1.106 +    s++;
   1.107 +  } /* for */
   1.108 +  if (n!=NULL)
   1.109 +    *n=(char*)s;
   1.110 +  return result;
   1.111 +}
   1.112 +
   1.113 +#if BYTE_ORDER==BIG_ENDIAN
   1.114 +static uint16_t *align16(uint16_t *v)
   1.115 +{
   1.116 +  unsigned char *s = (unsigned char *)v;
   1.117 +  unsigned char t;
   1.118 +
   1.119 +  /* swap two bytes */
   1.120 +  t=s[0];
   1.121 +  s[0]=s[1];
   1.122 +  s[1]=t;
   1.123 +  return v;
   1.124 +}
   1.125 +
   1.126 +static uint32_t *align32(uint32_t *v)
   1.127 +{
   1.128 +  unsigned char *s = (unsigned char *)v;
   1.129 +  unsigned char t;
   1.130 +
   1.131 +  /* swap outer two bytes */
   1.132 +  t=s[0];
   1.133 +  s[0]=s[3];
   1.134 +  s[3]=t;
   1.135 +  /* swap inner two bytes */
   1.136 +  t=s[1];
   1.137 +  s[1]=s[2];
   1.138 +  s[2]=t;
   1.139 +  return v;
   1.140 +}
   1.141 +
   1.142 +#if PAWN_CELL_SIZE>=64
   1.143 +static uint64_t *align64(uint64_t *v)
   1.144 +{
   1.145 +	unsigned char *s = (unsigned char *)v;
   1.146 +	unsigned char t;
   1.147 +
   1.148 +	t=s[0];
   1.149 +	s[0]=s[7];
   1.150 +	s[7]=t;
   1.151 +
   1.152 +	t=s[1];
   1.153 +	s[1]=s[6];
   1.154 +	s[6]=t;
   1.155 +
   1.156 +	t=s[2];
   1.157 +	s[2]=s[5];
   1.158 +	s[5]=t;
   1.159 +
   1.160 +	t=s[3];
   1.161 +	s[3]=s[4];
   1.162 +	s[4]=t;
   1.163 +
   1.164 +	return v;
   1.165 +}
   1.166 +#endif
   1.167 +
   1.168 +  #if PAWN_CELL_SIZE==16
   1.169 +    #define aligncell(v)  align16(v)
   1.170 +  #elif PAWN_CELL_SIZE==32
   1.171 +    #define aligncell(v)  align32(v)
   1.172 +  #elif PAWN_CELL_SIZE==64
   1.173 +    #define aligncell(v)  align64(v)
   1.174 +  #endif
   1.175 +#else
   1.176 +  #define align16(v)    (v)
   1.177 +  #define align32(v)    (v)
   1.178 +  #define aligncell(v)  (v)
   1.179 +#endif
   1.180 +
   1.181 +static char *skipwhitespace(char *str)
   1.182 +{
   1.183 +  while (isspace(*str))
   1.184 +    str++;
   1.185 +  return str;
   1.186 +}
   1.187 +
   1.188 +static char *stripcomment(char *str)
   1.189 +{
   1.190 +  char *ptr=strchr(str,';');
   1.191 +  if (ptr!=NULL) {
   1.192 +    *ptr++='\n';        /* terminate the line, but leave the '\n' */
   1.193 +    *ptr='\0';
   1.194 +  } /* if */
   1.195 +  return str;
   1.196 +}
   1.197 +
   1.198 +static void write_encoded(FILE *fbin,ucell *c,int num)
   1.199 +{
   1.200 +  #if PAWN_CELL_SIZE == 16
   1.201 +    #define ENC_MAX   3     /* a 16-bit cell is encoded in max. 3 bytes */
   1.202 +    #define ENC_MASK  0x03  /* after 2x7 bits, 2 bits remain to make 16 bits */
   1.203 +  #elif PAWN_CELL_SIZE == 32
   1.204 +    #define ENC_MAX   5     /* a 32-bit cell is encoded in max. 5 bytes */
   1.205 +    #define ENC_MASK  0x0f  /* after 4x7 bits, 4 bits remain to make 32 bits */
   1.206 +  #elif PAWN_CELL_SIZE == 64
   1.207 +    #define ENC_MAX   10    /* a 32-bit cell is encoded in max. 10 bytes */
   1.208 +    #define ENC_MASK  0x01  /* after 9x7 bits, 1 bit remains to make 64 bits */
   1.209 +  #endif
   1.210 +
   1.211 +  assert(fbin!=NULL);
   1.212 +  while (num-->0) {
   1.213 +    if (sc_compress) {
   1.214 +      ucell p=(ucell)*c;
   1.215 +      unsigned char t[ENC_MAX];
   1.216 +      unsigned char code;
   1.217 +      int index;
   1.218 +      for (index=0; index<ENC_MAX; index++) {
   1.219 +        t[index]=(unsigned char)(p & 0x7f);     /* store 7 bits */
   1.220 +        p>>=7;
   1.221 +      } /* for */
   1.222 +      /* skip leading zeros */
   1.223 +      while (index>1 && t[index-1]==0 && (t[index-2] & 0x40)==0)
   1.224 +        index--;
   1.225 +      /* skip leading -1s */
   1.226 +      if (index==ENC_MAX && t[index-1]==ENC_MASK && (t[index-2] & 0x40)!=0)
   1.227 +        index--;
   1.228 +      while (index>1 && t[index-1]==0x7f && (t[index-2] & 0x40)!=0)
   1.229 +        index--;
   1.230 +      /* write high byte first, write continuation bits */
   1.231 +      assert(index>0);
   1.232 +      while (index-->0) {
   1.233 +        code=(unsigned char)((index==0) ? t[index] : (t[index]|0x80));
   1.234 +        writeerror |= !pc_writebin(fbin,&code,1);
   1.235 +        bytes_out++;
   1.236 +      } /* while */
   1.237 +      bytes_in+=sizeof *c;
   1.238 +      assert(AMX_COMPACTMARGIN>2);
   1.239 +      if (bytes_out-bytes_in>=AMX_COMPACTMARGIN-2)
   1.240 +        longjmp(compact_err,1);
   1.241 +    } else {
   1.242 +      assert((pc_lengthbin(fbin) % sizeof(cell)) == 0);
   1.243 +      writeerror |= !pc_writebin(fbin,aligncell(c),sizeof *c);
   1.244 +    } /* if */
   1.245 +    c++;
   1.246 +  } /* while */
   1.247 +}
   1.248 +
   1.249 +#if defined __BORLANDC__ || defined __WATCOMC__
   1.250 +  #pragma argsused
   1.251 +#endif
   1.252 +static cell noop(FILE *fbin,char *params,cell opcode)
   1.253 +{
   1.254 +  return 0;
   1.255 +}
   1.256 +
   1.257 +#if defined __BORLANDC__ || defined __WATCOMC__
   1.258 +  #pragma argsused
   1.259 +#endif
   1.260 +static cell set_currentfile(FILE *fbin,char *params,cell opcode)
   1.261 +{
   1.262 +  fcurrent=(short)getparam(params,NULL);
   1.263 +  return 0;
   1.264 +}
   1.265 +
   1.266 +#if defined __BORLANDC__ || defined __WATCOMC__
   1.267 +  #pragma argsused
   1.268 +#endif
   1.269 +static cell parm0(FILE *fbin,char *params,cell opcode)
   1.270 +{
   1.271 +  if (fbin!=NULL)
   1.272 +    write_encoded(fbin,(ucell*)&opcode,1);
   1.273 +  return opcodes(1);
   1.274 +}
   1.275 +
   1.276 +static cell parm1(FILE *fbin,char *params,cell opcode)
   1.277 +{
   1.278 +  ucell p=getparam(params,NULL);
   1.279 +  if (fbin!=NULL) {
   1.280 +    write_encoded(fbin,(ucell*)&opcode,1);
   1.281 +    write_encoded(fbin,&p,1);
   1.282 +  } /* if */
   1.283 +  return opcodes(1)+opargs(1);
   1.284 +}
   1.285 +
   1.286 +static cell parm2(FILE *fbin,char *params,cell opcode)
   1.287 +{
   1.288 +  ucell p1=getparam(params,&params);
   1.289 +  ucell p2=getparam(params,NULL);
   1.290 +  if (fbin!=NULL) {
   1.291 +    write_encoded(fbin,(ucell*)&opcode,1);
   1.292 +    write_encoded(fbin,&p1,1);
   1.293 +    write_encoded(fbin,&p2,1);
   1.294 +  } /* if */
   1.295 +  return opcodes(1)+opargs(2);
   1.296 +}
   1.297 +
   1.298 +static cell parm3(FILE *fbin,char *params,cell opcode)
   1.299 +{
   1.300 +  ucell p1=getparam(params,&params);
   1.301 +  ucell p2=getparam(params,&params);
   1.302 +  ucell p3=getparam(params,NULL);
   1.303 +  if (fbin!=NULL) {
   1.304 +    write_encoded(fbin,(ucell*)&opcode,1);
   1.305 +    write_encoded(fbin,&p1,1);
   1.306 +    write_encoded(fbin,&p2,1);
   1.307 +    write_encoded(fbin,&p3,1);
   1.308 +  } /* if */
   1.309 +  return opcodes(1)+opargs(3);
   1.310 +}
   1.311 +
   1.312 +static cell parm4(FILE *fbin,char *params,cell opcode)
   1.313 +{
   1.314 +  ucell p1=getparam(params,&params);
   1.315 +  ucell p2=getparam(params,&params);
   1.316 +  ucell p3=getparam(params,&params);
   1.317 +  ucell p4=getparam(params,NULL);
   1.318 +  if (fbin!=NULL) {
   1.319 +    write_encoded(fbin,(ucell*)&opcode,1);
   1.320 +    write_encoded(fbin,&p1,1);
   1.321 +    write_encoded(fbin,&p2,1);
   1.322 +    write_encoded(fbin,&p3,1);
   1.323 +    write_encoded(fbin,&p4,1);
   1.324 +  } /* if */
   1.325 +  return opcodes(1)+opargs(4);
   1.326 +}
   1.327 +
   1.328 +static cell parm5(FILE *fbin,char *params,cell opcode)
   1.329 +{
   1.330 +  ucell p1=getparam(params,&params);
   1.331 +  ucell p2=getparam(params,&params);
   1.332 +  ucell p3=getparam(params,&params);
   1.333 +  ucell p4=getparam(params,&params);
   1.334 +  ucell p5=getparam(params,NULL);
   1.335 +  if (fbin!=NULL) {
   1.336 +    write_encoded(fbin,(ucell*)&opcode,1);
   1.337 +    write_encoded(fbin,&p1,1);
   1.338 +    write_encoded(fbin,&p2,1);
   1.339 +    write_encoded(fbin,&p3,1);
   1.340 +    write_encoded(fbin,&p4,1);
   1.341 +    write_encoded(fbin,&p5,1);
   1.342 +  } /* if */
   1.343 +  return opcodes(1)+opargs(5);
   1.344 +}
   1.345 +
   1.346 +#if defined __BORLANDC__ || defined __WATCOMC__
   1.347 +  #pragma argsused
   1.348 +#endif
   1.349 +static cell do_dump(FILE *fbin,char *params,cell opcode)
   1.350 +{
   1.351 +  ucell p;
   1.352 +  int num = 0;
   1.353 +
   1.354 +  while (*params!='\0') {
   1.355 +    p=getparam(params,&params);
   1.356 +    if (fbin!=NULL)
   1.357 +      write_encoded(fbin,&p,1);
   1.358 +    num++;
   1.359 +    while (isspace(*params))
   1.360 +      params++;
   1.361 +  } /* while */
   1.362 +  return num*sizeof(cell);
   1.363 +}
   1.364 +
   1.365 +static cell do_call(FILE *fbin,char *params,cell opcode)
   1.366 +{
   1.367 +  char name[sNAMEMAX+1];
   1.368 +  int i;
   1.369 +  symbol *sym;
   1.370 +  ucell p;
   1.371 +
   1.372 +  for (i=0; !isspace(*params); i++,params++) {
   1.373 +    assert(*params!='\0');
   1.374 +    assert(i<sNAMEMAX);
   1.375 +    name[i]=*params;
   1.376 +  } /* for */
   1.377 +  name[i]='\0';
   1.378 +
   1.379 +  if (name[0]=='l' && name[1]=='.') {
   1.380 +    /* this is a label, not a function symbol */
   1.381 +    i=(int)hex2long(name+2,NULL);
   1.382 +    assert(i>=0 && i<sc_labnum);
   1.383 +    if (fbin!=NULL) {
   1.384 +      assert(lbltab!=NULL);
   1.385 +      p=lbltab[i];
   1.386 +    } /* if */
   1.387 +  } else {
   1.388 +    /* look up the function address; note that the correct file number must
   1.389 +     * already have been set (in order for static globals to be found).
   1.390 +     */
   1.391 +    sym=findglb(name,sGLOBAL);
   1.392 +    assert(sym!=NULL);
   1.393 +    assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
   1.394 +    assert(sym->vclass==sGLOBAL);
   1.395 +    p=sym->addr;
   1.396 +  } /* if */
   1.397 +
   1.398 +  if (fbin!=NULL) {
   1.399 +    write_encoded(fbin,(ucell*)&opcode,1);
   1.400 +    write_encoded(fbin,&p,1);
   1.401 +  } /* if */
   1.402 +  return opcodes(1)+opargs(1);
   1.403 +}
   1.404 +
   1.405 +static cell do_jump(FILE *fbin,char *params,cell opcode)
   1.406 +{
   1.407 +  int i;
   1.408 +  ucell p;
   1.409 +
   1.410 +  i=(int)hex2long(params,NULL);
   1.411 +  assert(i>=0 && i<sc_labnum);
   1.412 +
   1.413 +  if (fbin!=NULL) {
   1.414 +    assert(lbltab!=NULL);
   1.415 +    p=lbltab[i];
   1.416 +    write_encoded(fbin,(ucell*)&opcode,1);
   1.417 +    write_encoded(fbin,&p,1);
   1.418 +  } /* if */
   1.419 +  return opcodes(1)+opargs(1);
   1.420 +}
   1.421 +
   1.422 +static cell do_switch(FILE *fbin,char *params,cell opcode)
   1.423 +{
   1.424 +  int i;
   1.425 +  ucell p;
   1.426 +
   1.427 +  i=(int)hex2long(params,NULL);
   1.428 +  assert(i>=0 && i<sc_labnum);
   1.429 +
   1.430 +  if (fbin!=NULL) {
   1.431 +    assert(lbltab!=NULL);
   1.432 +    p=lbltab[i];
   1.433 +    write_encoded(fbin,(ucell*)&opcode,1);
   1.434 +    write_encoded(fbin,&p,1);
   1.435 +  } /* if */
   1.436 +  return opcodes(1)+opargs(1);
   1.437 +}
   1.438 +
   1.439 +#if defined __BORLANDC__ || defined __WATCOMC__
   1.440 +  #pragma argsused
   1.441 +#endif
   1.442 +static cell do_case(FILE *fbin,char *params,cell opcode)
   1.443 +{
   1.444 +  int i;
   1.445 +  ucell p,v;
   1.446 +
   1.447 +  v=hex2long(params,&params);
   1.448 +  i=(int)hex2long(params,NULL);
   1.449 +  assert(i>=0 && i<sc_labnum);
   1.450 +
   1.451 +  if (fbin!=NULL) {
   1.452 +    assert(lbltab!=NULL);
   1.453 +    p=lbltab[i];
   1.454 +    write_encoded(fbin,&v,1);
   1.455 +    write_encoded(fbin,&p,1);
   1.456 +  } /* if */
   1.457 +  return opcodes(0)+opargs(2);
   1.458 +}
   1.459 +
   1.460 +static OPCODEC opcodelist[] = {
   1.461 +  /* node for "invalid instruction" */
   1.462 +  {  0, NULL,         0,        noop },
   1.463 +  /* opcodes in sorted order */
   1.464 +  { 78, "add",        sIN_CSEG, parm0 },
   1.465 +  { 87, "add.c",      sIN_CSEG, parm1 },
   1.466 +  { 14, "addr.alt",   sIN_CSEG, parm1 },
   1.467 +  { 13, "addr.pri",   sIN_CSEG, parm1 },
   1.468 +  { 30, "align.alt",  sIN_CSEG, parm1 },
   1.469 +  { 29, "align.pri",  sIN_CSEG, parm1 },
   1.470 +  { 81, "and",        sIN_CSEG, parm0 },
   1.471 +  {121, "bounds",     sIN_CSEG, parm1 },
   1.472 +  {137, "break",      sIN_CSEG, parm0 },  /* version 8 */
   1.473 +  { 49, "call",       sIN_CSEG, do_call },
   1.474 +  { 50, "call.pri",   sIN_CSEG, parm0 },
   1.475 +  {  0, "case",       sIN_CSEG, do_case },
   1.476 +  {130, "casetbl",    sIN_CSEG, parm0 },  /* version 1 */
   1.477 +  {118, "cmps",       sIN_CSEG, parm1 },
   1.478 +  {  0, "code",       sIN_CSEG, set_currentfile },
   1.479 +  {156, "const",      sIN_CSEG, parm2 },  /* version 9 */
   1.480 +  { 12, "const.alt",  sIN_CSEG, parm1 },
   1.481 +  { 11, "const.pri",  sIN_CSEG, parm1 },
   1.482 +  {157, "const.s",    sIN_CSEG, parm2 },  /* version 9 */
   1.483 +  {  0, "data",       sIN_DSEG, set_currentfile },
   1.484 +  {114, "dec",        sIN_CSEG, parm1 },
   1.485 +  {113, "dec.alt",    sIN_CSEG, parm0 },
   1.486 +  {116, "dec.i",      sIN_CSEG, parm0 },
   1.487 +  {112, "dec.pri",    sIN_CSEG, parm0 },
   1.488 +  {115, "dec.s",      sIN_CSEG, parm1 },
   1.489 +  {  0, "dump",       sIN_DSEG, do_dump },
   1.490 +  { 95, "eq",         sIN_CSEG, parm0 },
   1.491 +  {106, "eq.c.alt",   sIN_CSEG, parm1 },
   1.492 +  {105, "eq.c.pri",   sIN_CSEG, parm1 },
   1.493 +/*{124, "file",       sIN_CSEG, do_file }, */
   1.494 +  {119, "fill",       sIN_CSEG, parm1 },
   1.495 +  {162, "genarray",   sIN_CSEG, parm1 },
   1.496 +  {163, "genarray.z", sIN_CSEG, parm1 },
   1.497 +  {100, "geq",        sIN_CSEG, parm0 },
   1.498 +  { 99, "grtr",       sIN_CSEG, parm0 },
   1.499 +  {120, "halt",       sIN_CSEG, parm1 },
   1.500 +  { 45, "heap",       sIN_CSEG, parm1 },
   1.501 +  { 27, "idxaddr",    sIN_CSEG, parm0 },
   1.502 +  { 28, "idxaddr.b",  sIN_CSEG, parm1 },
   1.503 +  {109, "inc",        sIN_CSEG, parm1 },
   1.504 +  {108, "inc.alt",    sIN_CSEG, parm0 },
   1.505 +  {111, "inc.i",      sIN_CSEG, parm0 },
   1.506 +  {107, "inc.pri",    sIN_CSEG, parm0 },
   1.507 +  {110, "inc.s",      sIN_CSEG, parm1 },
   1.508 +  { 86, "invert",     sIN_CSEG, parm0 },
   1.509 +  { 55, "jeq",        sIN_CSEG, do_jump },
   1.510 +  { 60, "jgeq",       sIN_CSEG, do_jump },
   1.511 +  { 59, "jgrtr",      sIN_CSEG, do_jump },
   1.512 +  { 58, "jleq",       sIN_CSEG, do_jump },
   1.513 +  { 57, "jless",      sIN_CSEG, do_jump },
   1.514 +  { 56, "jneq",       sIN_CSEG, do_jump },
   1.515 +  { 54, "jnz",        sIN_CSEG, do_jump },
   1.516 +  { 52, "jrel",       sIN_CSEG, parm1 },  /* always a number */
   1.517 +  { 64, "jsgeq",      sIN_CSEG, do_jump },
   1.518 +  { 63, "jsgrtr",     sIN_CSEG, do_jump },
   1.519 +  { 62, "jsleq",      sIN_CSEG, do_jump },
   1.520 +  { 61, "jsless",     sIN_CSEG, do_jump },
   1.521 +  { 51, "jump",       sIN_CSEG, do_jump },
   1.522 +  {128, "jump.pri",   sIN_CSEG, parm0 },  /* version 1 */
   1.523 +  { 53, "jzer",       sIN_CSEG, do_jump },
   1.524 +  { 31, "lctrl",      sIN_CSEG, parm1 },
   1.525 +  { 98, "leq",        sIN_CSEG, parm0 },
   1.526 +  { 97, "less",       sIN_CSEG, parm0 },
   1.527 +  { 25, "lidx",       sIN_CSEG, parm0 },
   1.528 +  { 26, "lidx.b",     sIN_CSEG, parm1 },
   1.529 +/*{125, "line",       sIN_CSEG, parm2 }, */
   1.530 +  {  2, "load.alt",   sIN_CSEG, parm1 },
   1.531 +  {154, "load.both",  sIN_CSEG, parm2 },  /* version 9 */
   1.532 +  {  9, "load.i",     sIN_CSEG, parm0 },
   1.533 +  {  1, "load.pri",   sIN_CSEG, parm1 },
   1.534 +  {  4, "load.s.alt", sIN_CSEG, parm1 },
   1.535 +  {155, "load.s.both",sIN_CSEG, parm2 },  /* version 9 */
   1.536 +  {  3, "load.s.pri", sIN_CSEG, parm1 },
   1.537 +  { 10, "lodb.i",     sIN_CSEG, parm1 },
   1.538 +  {  6, "lref.alt",   sIN_CSEG, parm1 },
   1.539 +  {  5, "lref.pri",   sIN_CSEG, parm1 },
   1.540 +  {  8, "lref.s.alt", sIN_CSEG, parm1 },
   1.541 +  {  7, "lref.s.pri", sIN_CSEG, parm1 },
   1.542 +  { 34, "move.alt",   sIN_CSEG, parm0 },
   1.543 +  { 33, "move.pri",   sIN_CSEG, parm0 },
   1.544 +  {117, "movs",       sIN_CSEG, parm1 },
   1.545 +  { 85, "neg",        sIN_CSEG, parm0 },
   1.546 +  { 96, "neq",        sIN_CSEG, parm0 },
   1.547 +  {134, "nop",        sIN_CSEG, parm0 },  /* version 6 */
   1.548 +  { 84, "not",        sIN_CSEG, parm0 },
   1.549 +  { 82, "or",         sIN_CSEG, parm0 },
   1.550 +  { 43, "pop.alt",    sIN_CSEG, parm0 },
   1.551 +  { 42, "pop.pri",    sIN_CSEG, parm0 },
   1.552 +  { 46, "proc",       sIN_CSEG, parm0 },
   1.553 +  { 40, "push",       sIN_CSEG, parm1 },
   1.554 +  {133, "push.adr",   sIN_CSEG, parm1 },  /* version 4 */
   1.555 +  { 37, "push.alt",   sIN_CSEG, parm0 },
   1.556 +  { 39, "push.c",     sIN_CSEG, parm1 },
   1.557 +  { 36, "push.pri",   sIN_CSEG, parm0 },
   1.558 +  { 38, "push.r",     sIN_CSEG, parm1 },  /* obsolete (never generated) */
   1.559 +  { 41, "push.s",     sIN_CSEG, parm1 },
   1.560 +  {139, "push2",      sIN_CSEG, parm2 },  /* version 9 */
   1.561 +  {141, "push2.adr",  sIN_CSEG, parm2 },  /* version 9 */
   1.562 +  {138, "push2.c",    sIN_CSEG, parm2 },  /* version 9 */
   1.563 +  {140, "push2.s",    sIN_CSEG, parm2 },  /* version 9 */
   1.564 +  {143, "push3",      sIN_CSEG, parm3 },  /* version 9 */
   1.565 +  {145, "push3.adr",  sIN_CSEG, parm3 },  /* version 9 */
   1.566 +  {142, "push3.c",    sIN_CSEG, parm3 },  /* version 9 */
   1.567 +  {144, "push3.s",    sIN_CSEG, parm3 },  /* version 9 */
   1.568 +  {147, "push4",      sIN_CSEG, parm4 },  /* version 9 */
   1.569 +  {149, "push4.adr",  sIN_CSEG, parm4 },  /* version 9 */
   1.570 +  {146, "push4.c",    sIN_CSEG, parm4 },  /* version 9 */
   1.571 +  {148, "push4.s",    sIN_CSEG, parm4 },  /* version 9 */
   1.572 +  {151, "push5",      sIN_CSEG, parm5 },  /* version 9 */
   1.573 +  {153, "push5.adr",  sIN_CSEG, parm5 },  /* version 9 */
   1.574 +  {150, "push5.c",    sIN_CSEG, parm5 },  /* version 9 */
   1.575 +  {152, "push5.s",    sIN_CSEG, parm5 },  /* version 9 */
   1.576 +  { 47, "ret",        sIN_CSEG, parm0 },
   1.577 +  { 48, "retn",       sIN_CSEG, parm0 },
   1.578 +  { 32, "sctrl",      sIN_CSEG, parm1 },
   1.579 +  { 73, "sdiv",       sIN_CSEG, parm0 },
   1.580 +  { 74, "sdiv.alt",   sIN_CSEG, parm0 },
   1.581 +  {104, "sgeq",       sIN_CSEG, parm0 },
   1.582 +  {103, "sgrtr",      sIN_CSEG, parm0 },
   1.583 +  { 65, "shl",        sIN_CSEG, parm0 },
   1.584 +  { 69, "shl.c.alt",  sIN_CSEG, parm1 },
   1.585 +  { 68, "shl.c.pri",  sIN_CSEG, parm1 },
   1.586 +  { 66, "shr",        sIN_CSEG, parm0 },
   1.587 +  { 71, "shr.c.alt",  sIN_CSEG, parm1 },
   1.588 +  { 70, "shr.c.pri",  sIN_CSEG, parm1 },
   1.589 +  { 94, "sign.alt",   sIN_CSEG, parm0 },
   1.590 +  { 93, "sign.pri",   sIN_CSEG, parm0 },
   1.591 +  {102, "sleq",       sIN_CSEG, parm0 },
   1.592 +  {101, "sless",      sIN_CSEG, parm0 },
   1.593 +  { 72, "smul",       sIN_CSEG, parm0 },
   1.594 +  { 88, "smul.c",     sIN_CSEG, parm1 },
   1.595 +/*{127, "srange",     sIN_CSEG, parm2 }, -- version 1 */
   1.596 +  { 20, "sref.alt",   sIN_CSEG, parm1 },
   1.597 +  { 19, "sref.pri",   sIN_CSEG, parm1 },
   1.598 +  { 22, "sref.s.alt", sIN_CSEG, parm1 },
   1.599 +  { 21, "sref.s.pri", sIN_CSEG, parm1 },
   1.600 +  { 67, "sshr",       sIN_CSEG, parm0 },
   1.601 +  { 44, "stack",      sIN_CSEG, parm1 },
   1.602 +  {165, "stackadjust",sIN_CSEG, parm1 },
   1.603 +  {  0, "stksize",    0,        noop },
   1.604 +  { 16, "stor.alt",   sIN_CSEG, parm1 },
   1.605 +  { 23, "stor.i",     sIN_CSEG, parm0 },
   1.606 +  { 15, "stor.pri",   sIN_CSEG, parm1 },
   1.607 +  { 18, "stor.s.alt", sIN_CSEG, parm1 },
   1.608 +  { 17, "stor.s.pri", sIN_CSEG, parm1 },
   1.609 +  {164, "stradjust.pri", sIN_CSEG, parm0 },
   1.610 +  { 24, "strb.i",     sIN_CSEG, parm1 },
   1.611 +  { 79, "sub",        sIN_CSEG, parm0 },
   1.612 +  { 80, "sub.alt",    sIN_CSEG, parm0 },
   1.613 +  {132, "swap.alt",   sIN_CSEG, parm0 },  /* version 4 */
   1.614 +  {131, "swap.pri",   sIN_CSEG, parm0 },  /* version 4 */
   1.615 +  {129, "switch",     sIN_CSEG, do_switch }, /* version 1 */
   1.616 +/*{126, "symbol",     sIN_CSEG, do_symbol }, */
   1.617 +/*{136, "symtag",     sIN_CSEG, parm1 },  -- version 7 */
   1.618 +  {123, "sysreq.c",   sIN_CSEG, parm1 },
   1.619 +  {135, "sysreq.n",   sIN_CSEG, parm2 },  /* version 9 (replaces SYSREQ.d from earlier version) */
   1.620 +  {122, "sysreq.pri", sIN_CSEG, parm0 },
   1.621 +  {161, "tracker.pop.setheap", sIN_CSEG, parm0 },
   1.622 +  {160, "tracker.push.c", sIN_CSEG, parm1 },
   1.623 +  { 76, "udiv",       sIN_CSEG, parm0 },
   1.624 +  { 77, "udiv.alt",   sIN_CSEG, parm0 },
   1.625 +  { 75, "umul",       sIN_CSEG, parm0 },
   1.626 +  { 35, "xchg",       sIN_CSEG, parm0 },
   1.627 +  { 83, "xor",        sIN_CSEG, parm0 },
   1.628 +  { 91, "zero",       sIN_CSEG, parm1 },
   1.629 +  { 90, "zero.alt",   sIN_CSEG, parm0 },
   1.630 +  { 89, "zero.pri",   sIN_CSEG, parm0 },
   1.631 +  { 92, "zero.s",     sIN_CSEG, parm1 },
   1.632 +};
   1.633 +
   1.634 +#define MAX_INSTR_LEN   30
   1.635 +static int findopcode(char *instr,int maxlen)
   1.636 +{
   1.637 +  int low,high,mid,cmp;
   1.638 +  char str[MAX_INSTR_LEN];
   1.639 +
   1.640 +  if (maxlen>=MAX_INSTR_LEN)
   1.641 +    return 0;
   1.642 +  strlcpy(str,instr,maxlen+1);
   1.643 +  /* look up the instruction with a binary search
   1.644 +   * the assembler is case insensitive to instructions (but case sensitive
   1.645 +   * to symbols)
   1.646 +   */
   1.647 +  low=1;                /* entry 0 is reserved (for "not found") */
   1.648 +  high=(sizeof opcodelist / sizeof opcodelist[0])-1;
   1.649 +  while (low<high) {
   1.650 +    mid=(low+high)/2;
   1.651 +    assert(opcodelist[mid].name!=NULL);
   1.652 +    cmp=stricmp(str,opcodelist[mid].name);
   1.653 +    if (cmp>0)
   1.654 +      low=mid+1;
   1.655 +    else
   1.656 +      high=mid;
   1.657 +  } /* while */
   1.658 +
   1.659 +  assert(low==high);
   1.660 +  if (stricmp(str,opcodelist[low].name)==0)
   1.661 +    return low;         /* found */
   1.662 +  return 0;             /* not found, return special index */
   1.663 +}
   1.664 +
   1.665 +SC_FUNC int assemble(FILE *fout,FILE *fin)
   1.666 +{
   1.667 +  AMX_HEADER hdr;
   1.668 +  AMX_FUNCSTUBNT func;
   1.669 +  int numpublics,numnatives,numlibraries,numpubvars,numtags,padding;
   1.670 +  long nametablesize,nameofs;
   1.671 +  #if PAWN_CELL_SIZE > 32
   1.672 +    char line[512];
   1.673 +  #else
   1.674 +    char line[256];
   1.675 +  #endif
   1.676 +  char *instr,*params;
   1.677 +  int i,pass,size;
   1.678 +  int16_t count;
   1.679 +  symbol *sym, **nativelist;
   1.680 +  constvalue *constptr;
   1.681 +  cell mainaddr;
   1.682 +  char nullchar;
   1.683 +  char testalias[sNAMEMAX+1];
   1.684 +
   1.685 +  /* if compression failed, restart the assembly with compaction switched off */
   1.686 +  if (setjmp(compact_err)!=0) {
   1.687 +    assert(sc_compress);  /* cannot arrive here if compact encoding was disabled */
   1.688 +    sc_compress=FALSE;
   1.689 +    pc_resetbin(fout,0);
   1.690 +    error(232);           /* disabled compact encoding */
   1.691 +  } /* if */
   1.692 +
   1.693 +  #if !defined NDEBUG
   1.694 +    /* verify that the opcode list is sorted (skip entry 1; it is reserved
   1.695 +     * for a non-existant opcode)
   1.696 +     */
   1.697 +    assert(opcodelist[1].name!=NULL);
   1.698 +    for (i=2; i<(sizeof opcodelist / sizeof opcodelist[0]); i++) {
   1.699 +      assert(opcodelist[i].name!=NULL);
   1.700 +      assert(stricmp(opcodelist[i].name,opcodelist[i-1].name)>0);
   1.701 +    } /* for */
   1.702 +  #endif
   1.703 +
   1.704 +  writeerror=FALSE;
   1.705 +  nametablesize=sizeof(int16_t);
   1.706 +  numpublics=0;
   1.707 +  numnatives=0;
   1.708 +  numpubvars=0;
   1.709 +  mainaddr=-1;
   1.710 +  /* count number of public and native functions and public variables */
   1.711 +  for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
   1.712 +    int match=0;
   1.713 +    if (sym->ident==iFUNCTN) {
   1.714 +      if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
   1.715 +        match=++numnatives;
   1.716 +      }
   1.717 +      if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
   1.718 +        match=++numpublics;
   1.719 +      if (strcmp(sym->name,uMAINFUNC)==0) {
   1.720 +        assert(sym->vclass==sGLOBAL);
   1.721 +        mainaddr=sym->addr;
   1.722 +      } /* if */
   1.723 +    } else if (sym->ident==iVARIABLE || sym->ident == iARRAY || sym->ident == iREFARRAY) {
   1.724 +      if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0)
   1.725 +        match=++numpubvars;
   1.726 +    } /* if */
   1.727 +    if (match) {
   1.728 +      const char *aliasptr = sym->name;
   1.729 +      assert(sym!=NULL);
   1.730 +      if (((sym->usage & uNATIVE)!=0) && lookup_alias(testalias,sym->name)) {
   1.731 +        aliasptr = "@";
   1.732 +      } /* if */
   1.733 +      nametablesize+=strlen(aliasptr)+1;
   1.734 +    } /* if */
   1.735 +  } /* for */
   1.736 +  assert(numnatives==ntv_funcid);
   1.737 +
   1.738 +  /* count number of libraries */
   1.739 +  numlibraries=0;
   1.740 +  if (pc_addlibtable) {
   1.741 +    for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
   1.742 +      if (constptr->value>0) {
   1.743 +        assert(strlen(constptr->name)>0);
   1.744 +        numlibraries++;
   1.745 +        nametablesize+=strlen(constptr->name)+1;
   1.746 +      } /* if */
   1.747 +    } /* for */
   1.748 +  } /* if */
   1.749 +
   1.750 +  /* count number of public tags */
   1.751 +  numtags=0;
   1.752 +  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
   1.753 +    /*if ((constptr->value & PUBLICTAG)!=0) {*/
   1.754 +      assert(strlen(constptr->name)>0);
   1.755 +      numtags++;
   1.756 +      nametablesize+=strlen(constptr->name)+1;
   1.757 +    /*} if */
   1.758 +  } /* for */
   1.759 +
   1.760 +  /* pad the header to sc_dataalign
   1.761 +   * => thereby the code segment is aligned
   1.762 +   * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned
   1.763 +   * => and thereby the stack top is aligned too
   1.764 +   */
   1.765 +  assert(sc_dataalign!=0);
   1.766 +  padding= (int)(sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign);
   1.767 +  if (padding==sc_dataalign)
   1.768 +    padding=0;
   1.769 +
   1.770 +  /* write the abstract machine header */
   1.771 +  memset(&hdr, 0, sizeof hdr);
   1.772 +  hdr.magic=(unsigned short)AMX_MAGIC;
   1.773 +  hdr.file_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MAX_FILE_VER_JIT : CUR_FILE_VERSION);
   1.774 +  hdr.amx_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MIN_AMX_VER_JIT : MIN_AMX_VERSION);
   1.775 +  hdr.flags=(short)(sc_debug & sSYMBOLIC);
   1.776 +  if (sc_compress)
   1.777 +    hdr.flags|=AMX_FLAG_COMPACT;
   1.778 +  if (sc_debug==0)
   1.779 +    hdr.flags|=AMX_FLAG_NOCHECKS;
   1.780 +  if (pc_memflags & suSLEEP_INSTR)
   1.781 +    hdr.flags|=AMX_FLAG_SLEEP;
   1.782 +  hdr.defsize=sizeof(AMX_FUNCSTUBNT);
   1.783 +  hdr.publics=sizeof hdr; /* public table starts right after the header */
   1.784 +  hdr.natives=hdr.publics + numpublics*sizeof(AMX_FUNCSTUBNT);
   1.785 +  hdr.libraries=hdr.natives + numnatives*sizeof(AMX_FUNCSTUBNT);
   1.786 +  hdr.pubvars=hdr.libraries + numlibraries*sizeof(AMX_FUNCSTUBNT);
   1.787 +  hdr.tags=hdr.pubvars + numpubvars*sizeof(AMX_FUNCSTUBNT);
   1.788 +  hdr.nametable=hdr.tags + numtags*sizeof(AMX_FUNCSTUBNT);
   1.789 +  hdr.cod=hdr.nametable + nametablesize + padding;
   1.790 +  hdr.dat=hdr.cod + code_idx;
   1.791 +  hdr.hea=hdr.dat + glb_declared*sizeof(cell);
   1.792 +  hdr.stp=hdr.hea + pc_stksize*sizeof(cell);
   1.793 +  hdr.cip=mainaddr;
   1.794 +  hdr.size=hdr.hea; /* preset, this is incorrect in case of compressed output */
   1.795 +  pc_writebin(fout,&hdr,sizeof hdr);
   1.796 +
   1.797 +  /* dump zeros up to the rest of the header, so that we can easily "seek" */
   1.798 +  nullchar='\0';
   1.799 +  for (nameofs=sizeof hdr; nameofs<hdr.cod; nameofs++)
   1.800 +    pc_writebin(fout,&nullchar,1);
   1.801 +  nameofs=hdr.nametable+sizeof(int16_t);
   1.802 +
   1.803 +  /* write the public functions table */
   1.804 +  count=0;
   1.805 +  for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
   1.806 +    if (sym->ident==iFUNCTN
   1.807 +        && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
   1.808 +    {
   1.809 +      assert(sym->vclass==sGLOBAL);
   1.810 +      func.address=sym->addr;
   1.811 +      func.nameofs=nameofs;
   1.812 +      #if BYTE_ORDER==BIG_ENDIAN
   1.813 +        align32(&func.address);
   1.814 +        align32(&func.nameofs);
   1.815 +      #endif
   1.816 +      pc_resetbin(fout,hdr.publics+count*sizeof(AMX_FUNCSTUBNT));
   1.817 +      pc_writebin(fout,&func,sizeof func);
   1.818 +      pc_resetbin(fout,nameofs);
   1.819 +      pc_writebin(fout,sym->name,strlen(sym->name)+1);
   1.820 +      nameofs+=strlen(sym->name)+1;
   1.821 +      count++;
   1.822 +    } /* if */
   1.823 +  } /* for */
   1.824 +
   1.825 +  /* write the natives table */
   1.826 +  /* The native functions must be written in sorted order. (They are
   1.827 +   * sorted on their "id", not on their name). A nested loop to find
   1.828 +   * each successive function would be an O(n^2) operation. But we
   1.829 +   * do not really need to sort, because the native function id's
   1.830 +   * are sequential and there are no duplicates. So we first walk
   1.831 +   * through the complete symbol list and store a pointer to every
   1.832 +   * native function of interest in a temporary table, where its id
   1.833 +   * serves as the index in the table. Now we can walk the table and
   1.834 +   * have all native functions in sorted order.
   1.835 +   */
   1.836 +  if (numnatives>0) {
   1.837 +    nativelist=(symbol **)malloc(numnatives*sizeof(symbol *));
   1.838 +    if (nativelist==NULL)
   1.839 +      error(103);               /* insufficient memory */
   1.840 +    #if !defined NDEBUG
   1.841 +      memset(nativelist,0,numnatives*sizeof(symbol *)); /* for NULL checking */
   1.842 +    #endif
   1.843 +    for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
   1.844 +      if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
   1.845 +        assert(sym->addr < numnatives);
   1.846 +        nativelist[(int)sym->addr]=sym;
   1.847 +      } /* if */
   1.848 +    } /* for */
   1.849 +    count=0;
   1.850 +    for (i=0; i<numnatives; i++) {
   1.851 +      const char *aliasptr;
   1.852 +      sym=nativelist[i];
   1.853 +      assert(sym!=NULL);
   1.854 +      aliasptr = sym->name;
   1.855 +      if (lookup_alias(testalias,sym->name)) {
   1.856 +        aliasptr = "@";
   1.857 +      }
   1.858 +      assert(sym->vclass==sGLOBAL);
   1.859 +      func.address=0;
   1.860 +      func.nameofs=nameofs;
   1.861 +      #if BYTE_ORDER==BIG_ENDIAN
   1.862 +        align32(&func.address);
   1.863 +        align32(&func.nameofs);
   1.864 +      #endif
   1.865 +      pc_resetbin(fout,hdr.natives+count*sizeof(AMX_FUNCSTUBNT));
   1.866 +      pc_writebin(fout,&func,sizeof func);
   1.867 +      pc_resetbin(fout,nameofs);
   1.868 +      pc_writebin(fout,(void *)aliasptr,strlen(aliasptr)+1);
   1.869 +      nameofs+=strlen(aliasptr)+1;
   1.870 +      count++;
   1.871 +    } /* for */
   1.872 +    free(nativelist);
   1.873 +  } /* if */
   1.874 +
   1.875 +  /* write the libraries table */
   1.876 +  if (pc_addlibtable) {
   1.877 +    count=0;
   1.878 +    for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
   1.879 +      if (constptr->value>0) {
   1.880 +        assert(strlen(constptr->name)>0);
   1.881 +        func.address=0;
   1.882 +        func.nameofs=nameofs;
   1.883 +        #if BYTE_ORDER==BIG_ENDIAN
   1.884 +          align32(&func.address);
   1.885 +          align32(&func.nameofs);
   1.886 +        #endif
   1.887 +        pc_resetbin(fout,hdr.libraries+count*sizeof(AMX_FUNCSTUBNT));
   1.888 +        pc_writebin(fout,&func,sizeof func);
   1.889 +        pc_resetbin(fout,nameofs);
   1.890 +        pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
   1.891 +        nameofs+=strlen(constptr->name)+1;
   1.892 +        count++;
   1.893 +      } /* if */
   1.894 +    } /* for */
   1.895 +  } /* if */
   1.896 +
   1.897 +  /* write the public variables table */
   1.898 +  count=0;
   1.899 +  for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
   1.900 +    if ((sym->ident==iVARIABLE || sym->ident==iARRAY || sym->ident==iREFARRAY)
   1.901 +        && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) {
   1.902 +      //removed until structs don't seem to mess this up
   1.903 +      //assert((sym->usage & uDEFINE)!=0);
   1.904 +      assert(sym->vclass==sGLOBAL);
   1.905 +      func.address=sym->addr;
   1.906 +      func.nameofs=nameofs;
   1.907 +      #if BYTE_ORDER==BIG_ENDIAN
   1.908 +        align32(&func.address);
   1.909 +        align32(&func.nameofs);
   1.910 +      #endif
   1.911 +      pc_resetbin(fout,hdr.pubvars+count*sizeof(AMX_FUNCSTUBNT));
   1.912 +      pc_writebin(fout,&func,sizeof func);
   1.913 +      pc_resetbin(fout,nameofs);
   1.914 +      pc_writebin(fout,sym->name,strlen(sym->name)+1);
   1.915 +      nameofs+=strlen(sym->name)+1;
   1.916 +      count++;
   1.917 +    } /* if */
   1.918 +  } /* for */
   1.919 +
   1.920 +  /* write the public tagnames table */
   1.921 +  count=0;
   1.922 +  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
   1.923 +    /*if ((constptr->value & PUBLICTAG)!=0) {*/
   1.924 +      assert(strlen(constptr->name)>0);
   1.925 +      func.address=constptr->value & TAGMASK;
   1.926 +      func.nameofs=nameofs;
   1.927 +      #if BYTE_ORDER==BIG_ENDIAN
   1.928 +        align32(&func.address);
   1.929 +        align32(&func.nameofs);
   1.930 +      #endif
   1.931 +      pc_resetbin(fout,hdr.tags+count*sizeof(AMX_FUNCSTUBNT));
   1.932 +      pc_writebin(fout,&func,sizeof func);
   1.933 +      pc_resetbin(fout,nameofs);
   1.934 +      pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
   1.935 +      nameofs+=strlen(constptr->name)+1;
   1.936 +      count++;
   1.937 +    /*} if */
   1.938 +  } /* for */
   1.939 +
   1.940 +  /* write the "maximum name length" field in the name table */
   1.941 +  assert(nameofs==hdr.nametable+nametablesize);
   1.942 +  pc_resetbin(fout,hdr.nametable);
   1.943 +  count=sNAMEMAX;
   1.944 +  #if BYTE_ORDER==BIG_ENDIAN
   1.945 +    align16(&count);
   1.946 +  #endif
   1.947 +  pc_writebin(fout,&count,sizeof count);
   1.948 +  pc_resetbin(fout,hdr.cod);
   1.949 +
   1.950 +  /* First pass: relocate all labels */
   1.951 +  /* This pass is necessary because the code addresses of labels is only known
   1.952 +   * after the peephole optimization flag. Labels can occur inside expressions
   1.953 +   * (e.g. the conditional operator), which are optimized.
   1.954 +   */
   1.955 +  lbltab=NULL;
   1.956 +  if (sc_labnum>0) {
   1.957 +    /* only very short programs have zero labels; no first pass is needed
   1.958 +     * if there are no labels */
   1.959 +    lbltab=(cell *)malloc(sc_labnum*sizeof(cell));
   1.960 +    if (lbltab==NULL)
   1.961 +      error(103);               /* insufficient memory */
   1.962 +    codeindex=0;
   1.963 +    pc_resetasm(fin);
   1.964 +    while (pc_readasm(fin,line,sizeof line)!=NULL) {
   1.965 +      stripcomment(line);
   1.966 +      instr=skipwhitespace(line);
   1.967 +      /* ignore empty lines */
   1.968 +      if (*instr=='\0')
   1.969 +        continue;
   1.970 +      if (tolower(*instr)=='l' && *(instr+1)=='.') {
   1.971 +        int lindex=(int)hex2long(instr+2,NULL);
   1.972 +        assert(lindex>=0 && lindex<sc_labnum);
   1.973 +        lbltab[lindex]=codeindex;
   1.974 +      } else {
   1.975 +        /* get to the end of the instruction (make use of the '\n' that fgets()
   1.976 +         * added at the end of the line; this way we will *always* drop on a
   1.977 +         * whitespace character) */
   1.978 +        for (params=instr; *params!='\0' && !isspace(*params); params++)
   1.979 +          /* nothing */;
   1.980 +        assert(params>instr);
   1.981 +        i=findopcode(instr,(int)(params-instr));
   1.982 +        if (opcodelist[i].name==NULL) {
   1.983 +          *params='\0';
   1.984 +          error(104,instr);     /* invalid assembler instruction */
   1.985 +        } /* if */
   1.986 +        if (opcodelist[i].segment==sIN_CSEG)
   1.987 +          codeindex+=opcodelist[i].func(NULL,skipwhitespace(params),opcodelist[i].opcode);
   1.988 +      } /* if */
   1.989 +    } /* while */
   1.990 +  } /* if */
   1.991 +
   1.992 +  /* Second pass (actually 2 more passes, one for all code and one for all data) */
   1.993 +  bytes_in=0;
   1.994 +  bytes_out=0;
   1.995 +  for (pass=sIN_CSEG; pass<=sIN_DSEG; pass++) {
   1.996 +    pc_resetasm(fin);
   1.997 +    while (pc_readasm(fin,line,sizeof line)!=NULL) {
   1.998 +      stripcomment(line);
   1.999 +      instr=skipwhitespace(line);
  1.1000 +      /* ignore empty lines and labels (labels have a special syntax, so these
  1.1001 +       * must be parsed separately) */
  1.1002 +      if (*instr=='\0' || tolower(*instr)=='l' && *(instr+1)=='.')
  1.1003 +        continue;
  1.1004 +      /* get to the end of the instruction (make use of the '\n' that fgets()
  1.1005 +       * added at the end of the line; this way we will *always* drop on a
  1.1006 +       * whitespace character) */
  1.1007 +      for (params=instr; *params!='\0' && !isspace(*params); params++)
  1.1008 +        /* nothing */;
  1.1009 +      assert(params>instr);
  1.1010 +      i=findopcode(instr,(int)(params-instr));
  1.1011 +      assert(opcodelist[i].name!=NULL);
  1.1012 +      if (opcodelist[i].segment==pass)
  1.1013 +        opcodelist[i].func(fout,skipwhitespace(params),opcodelist[i].opcode);
  1.1014 +    } /* while */
  1.1015 +  } /* for */
  1.1016 +  if (bytes_out-bytes_in>0)
  1.1017 +    error(106);         /* compression buffer overflow */
  1.1018 +
  1.1019 +  if (lbltab!=NULL) {
  1.1020 +    free(lbltab);
  1.1021 +    #if !defined NDEBUG
  1.1022 +      lbltab=NULL;
  1.1023 +    #endif
  1.1024 +  } /* if */
  1.1025 +
  1.1026 +  if (sc_compress)
  1.1027 +    hdr.size=pc_lengthbin(fout);/* get this value before appending debug info */
  1.1028 +  if (!writeerror && (sc_debug & sSYMBOLIC)!=0)
  1.1029 +    append_dbginfo(fout);       /* optionally append debug file */
  1.1030 +
  1.1031 +  if (writeerror)
  1.1032 +    error(101,"disk full");
  1.1033 +
  1.1034 +  /* adjust the header */
  1.1035 +  size=(int)hdr.cod;    /* save, the value in the header may be swapped */
  1.1036 +  #if BYTE_ORDER==BIG_ENDIAN
  1.1037 +    align32(&hdr.size);
  1.1038 +    align16(&hdr.magic);
  1.1039 +    align16(&hdr.flags);
  1.1040 +    align16(&hdr.defsize);
  1.1041 +    align32(&hdr.publics);
  1.1042 +    align32(&hdr.natives);
  1.1043 +    align32(&hdr.libraries);
  1.1044 +    align32(&hdr.pubvars);
  1.1045 +    align32(&hdr.tags);
  1.1046 +    align32(&hdr.nametable);
  1.1047 +    align32(&hdr.cod);
  1.1048 +    align32(&hdr.dat);
  1.1049 +    align32(&hdr.hea);
  1.1050 +    align32(&hdr.stp);
  1.1051 +    align32(&hdr.cip);
  1.1052 +  #endif
  1.1053 +  pc_resetbin(fout,0);
  1.1054 +  pc_writebin(fout,&hdr,sizeof hdr);
  1.1055 +
  1.1056 +  /* return the size of the header (including name tables, but excluding code
  1.1057 +   * or data sections)
  1.1058 +   */
  1.1059 +  return size;
  1.1060 +}
  1.1061 +
  1.1062 +static void append_dbginfo(FILE *fout)
  1.1063 +{
  1.1064 +  AMX_DBG_HDR dbghdr;
  1.1065 +  AMX_DBG_LINE dbgline;
  1.1066 +  AMX_DBG_SYMBOL dbgsym;
  1.1067 +  AMX_DBG_SYMDIM dbgidxtag[sDIMEN_MAX];
  1.1068 +  int index,dim,dbgsymdim;
  1.1069 +  char *str,*prevstr,*name,*prevname;
  1.1070 +  ucell codeidx,previdx;
  1.1071 +  constvalue *constptr;
  1.1072 +  char symname[2*sNAMEMAX+16];
  1.1073 +  int16_t id1,id2;
  1.1074 +  ucell address;
  1.1075 +
  1.1076 +  /* header with general information */
  1.1077 +  memset(&dbghdr, 0, sizeof dbghdr);
  1.1078 +  dbghdr.size=sizeof dbghdr;
  1.1079 +  dbghdr.magic=AMX_DBG_MAGIC;
  1.1080 +  dbghdr.file_version=CUR_FILE_VERSION;
  1.1081 +  dbghdr.amx_version=MIN_AMX_VERSION;
  1.1082 +
  1.1083 +  /* first pass: collect the number of items in various tables */
  1.1084 +
  1.1085 +  /* file table */
  1.1086 +  previdx=0;
  1.1087 +  prevstr=NULL;
  1.1088 +  prevname=NULL;
  1.1089 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1.1090 +    assert(str!=NULL);
  1.1091 +    assert(str[0]!='\0' && str[1]==':');
  1.1092 +    if (str[0]=='F') {
  1.1093 +      codeidx=hex2long(str+2,&name);
  1.1094 +      if (codeidx!=previdx) {
  1.1095 +        if (prevstr!=NULL) {
  1.1096 +          assert(prevname!=NULL);
  1.1097 +          dbghdr.files++;
  1.1098 +          dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
  1.1099 +        } /* if */
  1.1100 +        previdx=codeidx;
  1.1101 +      } /* if */
  1.1102 +      prevstr=str;
  1.1103 +      prevname=skipwhitespace(name);
  1.1104 +    } /* if */
  1.1105 +  } /* for */
  1.1106 +  if (prevstr!=NULL) {
  1.1107 +    assert(prevname!=NULL);
  1.1108 +    dbghdr.files++;
  1.1109 +    dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
  1.1110 +  } /* if */
  1.1111 +
  1.1112 +  /* line number table */
  1.1113 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1.1114 +    assert(str!=NULL);
  1.1115 +    assert(str[0]!='\0' && str[1]==':');
  1.1116 +    if (str[0]=='L') {
  1.1117 +      dbghdr.lines++;
  1.1118 +      dbghdr.size+=sizeof(AMX_DBG_LINE);
  1.1119 +    } /* if */
  1.1120 +  } /* for */
  1.1121 +
  1.1122 +  /* symbol table */
  1.1123 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1.1124 +    assert(str!=NULL);
  1.1125 +    assert(str[0]!='\0' && str[1]==':');
  1.1126 +    if (str[0]=='S') {
  1.1127 +      dbghdr.symbols++;
  1.1128 +      name=strchr(str+2,':');
  1.1129 +      assert(name!=NULL);
  1.1130 +      dbghdr.size+=sizeof(AMX_DBG_SYMBOL)+strlen(skipwhitespace(name+1));
  1.1131 +      if ((prevstr=strchr(name,'['))!=NULL)
  1.1132 +        while ((prevstr=strchr(prevstr+1,':'))!=NULL)
  1.1133 +          dbghdr.size+=sizeof(AMX_DBG_SYMDIM);
  1.1134 +    } /* if */
  1.1135 +  } /* for */
  1.1136 +
  1.1137 +  /* tag table */
  1.1138 +  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
  1.1139 +    assert(strlen(constptr->name)>0);
  1.1140 +    dbghdr.tags++;
  1.1141 +    dbghdr.size+=sizeof(AMX_DBG_TAG)+strlen(constptr->name);
  1.1142 +  } /* for */
  1.1143 +
  1.1144 +  /* automaton table */
  1.1145 +  for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
  1.1146 +    assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
  1.1147 +    dbghdr.automatons++;
  1.1148 +    dbghdr.size+=sizeof(AMX_DBG_MACHINE)+strlen(constptr->name);
  1.1149 +  } /* for */
  1.1150 +
  1.1151 +  /* state table */
  1.1152 +  for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
  1.1153 +    assert(strlen(constptr->name)>0);
  1.1154 +    dbghdr.states++;
  1.1155 +    dbghdr.size+=sizeof(AMX_DBG_STATE)+strlen(constptr->name);
  1.1156 +  } /* for */
  1.1157 +
  1.1158 +
  1.1159 +  /* pass 2: generate the tables */
  1.1160 +  #if BYTE_ORDER==BIG_ENDIAN
  1.1161 +    align32((uint32_t*)&dbghdr.size);
  1.1162 +    align16(&dbghdr.magic);
  1.1163 +    align16(&dbghdr.flags);
  1.1164 +    align16(&dbghdr.files);
  1.1165 +    align16(&dbghdr.lines);
  1.1166 +    align16(&dbghdr.symbols);
  1.1167 +    align16(&dbghdr.tags);
  1.1168 +    align16(&dbghdr.automatons);
  1.1169 +    align16(&dbghdr.states);
  1.1170 +  #endif
  1.1171 +  writeerror |= !pc_writebin(fout,&dbghdr,sizeof dbghdr);
  1.1172 +
  1.1173 +  /* file table */
  1.1174 +  previdx=0;
  1.1175 +  prevstr=NULL;
  1.1176 +  prevname=NULL;
  1.1177 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1.1178 +    assert(str!=NULL);
  1.1179 +    assert(str[0]!='\0' && str[1]==':');
  1.1180 +    if (str[0]=='F') {
  1.1181 +      codeidx=hex2long(str+2,&name);
  1.1182 +      if (codeidx!=previdx) {
  1.1183 +        if (prevstr!=NULL) {
  1.1184 +          assert(prevname!=NULL);
  1.1185 +          #if BYTE_ORDER==BIG_ENDIAN
  1.1186 +            aligncell(&previdx);
  1.1187 +          #endif
  1.1188 +          writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
  1.1189 +          writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
  1.1190 +        } /* if */
  1.1191 +        previdx=codeidx;
  1.1192 +      } /* if */
  1.1193 +      prevstr=str;
  1.1194 +      prevname=skipwhitespace(name);
  1.1195 +    } /* if */
  1.1196 +  } /* for */
  1.1197 +  if (prevstr!=NULL) {
  1.1198 +    assert(prevname!=NULL);
  1.1199 +    #if BYTE_ORDER==BIG_ENDIAN
  1.1200 +      aligncell(&previdx);
  1.1201 +    #endif
  1.1202 +    writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
  1.1203 +    writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
  1.1204 +  } /* if */
  1.1205 +
  1.1206 +  /* line number table */
  1.1207 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1.1208 +    assert(str!=NULL);
  1.1209 +    assert(str[0]!='\0' && str[1]==':');
  1.1210 +    if (str[0]=='L') {
  1.1211 +      dbgline.address=hex2long(str+2,&str);
  1.1212 +      dbgline.line=(int32_t)hex2long(str,NULL);
  1.1213 +      #if BYTE_ORDER==BIG_ENDIAN
  1.1214 +        aligncell(&dbgline.address);
  1.1215 +        align32(&dbgline.line);
  1.1216 +      #endif
  1.1217 +      writeerror |= !pc_writebin(fout,&dbgline,sizeof dbgline);
  1.1218 +    } /* if */
  1.1219 +  } /* for */
  1.1220 +
  1.1221 +  /* symbol table */
  1.1222 +  for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
  1.1223 +    assert(str!=NULL);
  1.1224 +    assert(str[0]!='\0' && str[1]==':');
  1.1225 +    if (str[0]=='S') {
  1.1226 +      dbgsym.address=hex2long(str+2,&str);
  1.1227 +      dbgsym.tag=(int16_t)hex2long(str,&str);
  1.1228 +      str=skipwhitespace(str);
  1.1229 +      assert(*str==':');
  1.1230 +      name=skipwhitespace(str+1);
  1.1231 +      str=strchr(name,' ');
  1.1232 +      assert(str!=NULL);
  1.1233 +      assert((int)(str-name)<sizeof symname);
  1.1234 +      strlcpy(symname,name,(int)(str-name)+1);
  1.1235 +      dbgsym.codestart=hex2long(str,&str);
  1.1236 +      dbgsym.codeend=hex2long(str,&str);
  1.1237 +      dbgsym.ident=(char)hex2long(str,&str);
  1.1238 +      dbgsym.vclass=(char)hex2long(str,&str);
  1.1239 +      dbgsym.dim=0;
  1.1240 +      str=skipwhitespace(str);
  1.1241 +      if (*str=='[') {
  1.1242 +        while (*(str=skipwhitespace(str+1))!=']') {
  1.1243 +          dbgidxtag[dbgsym.dim].tag=(int16_t)hex2long(str,&str);
  1.1244 +          str=skipwhitespace(str);
  1.1245 +          assert(*str==':');
  1.1246 +          dbgidxtag[dbgsym.dim].size=hex2long(str+1,&str);
  1.1247 +          dbgsym.dim++;
  1.1248 +        } /* while */
  1.1249 +      } /* if */
  1.1250 +      dbgsymdim = dbgsym.dim;
  1.1251 +      #if BYTE_ORDER==BIG_ENDIAN
  1.1252 +        aligncell(&dbgsym.address);
  1.1253 +        align16(&dbgsym.tag);
  1.1254 +        aligncell(&dbgsym.codestart);
  1.1255 +        aligncell(&dbgsym.codeend);
  1.1256 +        align16(&dbgsym.dim);
  1.1257 +      #endif
  1.1258 +      writeerror |= !pc_writebin(fout,&dbgsym,offsetof(AMX_DBG_SYMBOL, name));
  1.1259 +      writeerror |= !pc_writebin(fout,symname,strlen(symname)+1);
  1.1260 +      for (dim=0; dim<dbgsymdim; dim++) {
  1.1261 +        #if BYTE_ORDER==BIG_ENDIAN
  1.1262 +          align16(&dbgidxtag[dim].tag);
  1.1263 +          aligncell(&dbgidxtag[dim].size);
  1.1264 +        #endif
  1.1265 +        writeerror |= !pc_writebin(fout,&dbgidxtag[dim],sizeof dbgidxtag[dim]);
  1.1266 +      } /* for */
  1.1267 +    } /* if */
  1.1268 +  } /* for */
  1.1269 +
  1.1270 +  /* tag table */
  1.1271 +  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
  1.1272 +    assert(strlen(constptr->name)>0);
  1.1273 +    id1=(int16_t)(constptr->value & TAGMASK);
  1.1274 +    #if BYTE_ORDER==BIG_ENDIAN
  1.1275 +      align16(&id1);
  1.1276 +    #endif
  1.1277 +    writeerror |= !pc_writebin(fout,&id1,sizeof id1);
  1.1278 +    writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
  1.1279 +  } /* for */
  1.1280 +
  1.1281 +  /* automaton table */
  1.1282 +  for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
  1.1283 +    assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
  1.1284 +    id1=(int16_t)constptr->index;
  1.1285 +    address=(ucell)constptr->value;
  1.1286 +    #if BYTE_ORDER==BIG_ENDIAN
  1.1287 +      align16(&id1);
  1.1288 +      aligncell(&address);
  1.1289 +    #endif
  1.1290 +    writeerror |= !pc_writebin(fout,&id1,sizeof id1);
  1.1291 +    writeerror |= !pc_writebin(fout,&address,sizeof address);
  1.1292 +    writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
  1.1293 +  } /* for */
  1.1294 +
  1.1295 +  /* state table */
  1.1296 +  for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
  1.1297 +    assert(strlen(constptr->name)>0);
  1.1298 +    id1=(int16_t)constptr->value;
  1.1299 +    id2=(int16_t)constptr->index;
  1.1300 +    address=(ucell)constptr->value;
  1.1301 +    #if BYTE_ORDER==BIG_ENDIAN
  1.1302 +      align16(&id1);
  1.1303 +      align16(&id2);
  1.1304 +    #endif
  1.1305 +    writeerror |= !pc_writebin(fout,&id1,sizeof id1);
  1.1306 +    writeerror |= !pc_writebin(fout,&id2,sizeof id2);
  1.1307 +    writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
  1.1308 +  } /* for */
  1.1309 +
  1.1310 +  delete_dbgstringtable();
  1.1311 +}