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