aboutsummaryrefslogtreecommitdiffstats
path: root/src/bin/embryo/embryo_cc_sc6.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/embryo/embryo_cc_sc6.c')
-rw-r--r--src/bin/embryo/embryo_cc_sc6.c1080
1 files changed, 1080 insertions, 0 deletions
diff --git a/src/bin/embryo/embryo_cc_sc6.c b/src/bin/embryo/embryo_cc_sc6.c
new file mode 100644
index 000000000..20c4122fa
--- /dev/null
+++ b/src/bin/embryo/embryo_cc_sc6.c
@@ -0,0 +1,1080 @@
+/* Small compiler - Binary code generation (the "assembler")
+ *
+ * Copyright (c) ITB CompuPhase, 1997-2003
+ *
+ * This software is provided "as-is", without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * Version: $Id$
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h> /* for macro max() */
+#include <string.h>
+#include <ctype.h>
+
+#include <Eina.h>
+
+#include "embryo_cc_sc.h"
+
+typedef cell(*OPCODE_PROC) (FILE * fbin, char *params, cell opcode);
+
+typedef struct
+{
+ cell opcode;
+ char *name;
+ int segment; /* sIN_CSEG=parse in cseg, sIN_DSEG=parse in dseg */
+ OPCODE_PROC func;
+} OPCODE;
+
+static cell codeindex; /* similar to "code_idx" */
+static cell *lbltab; /* label table */
+static int writeerror;
+static int bytes_in, bytes_out;
+
+/* apparently, strtol() does not work correctly on very large (unsigned)
+ * hexadecimal values */
+static ucell
+hex2long(char *s, char **n)
+{
+ unsigned long result = 0L;
+ int negate = FALSE;
+ int digit;
+
+ /* ignore leading whitespace */
+ while (*s == ' ' || *s == '\t')
+ s++;
+
+ /* allow a negation sign to create the two's complement of numbers */
+ if (*s == '-')
+ {
+ negate = TRUE;
+ s++;
+ } /* if */
+
+ assert((*s >= '0' && *s <= '9') || (*s >= 'a' && *s <= 'f')
+ || (*s >= 'a' && *s <= 'f'));
+ for (;;)
+ {
+ if (*s >= '0' && *s <= '9')
+ digit = *s - '0';
+ else if (*s >= 'a' && *s <= 'f')
+ digit = *s - 'a' + 10;
+ else if (*s >= 'A' && *s <= 'F')
+ digit = *s - 'A' + 10;
+ else
+ break; /* probably whitespace */
+ result = (result << 4) | digit;
+ s++;
+ } /* for */
+ if (n)
+ *n = s;
+ if (negate)
+ result = (~result) + 1; /* take two's complement of the result */
+ return (ucell) result;
+}
+
+#ifdef WORDS_BIGENDIAN
+static short *
+align16(short *v)
+{
+ unsigned char *s = (unsigned char *)v;
+ unsigned char t;
+
+ /* swap two bytes */
+ t = s[0];
+ s[0] = s[1];
+ s[1] = t;
+ return v;
+}
+
+static long *
+align32(long *v)
+{
+ unsigned char *s = (unsigned char *)v;
+ unsigned char t;
+
+ /* swap outer two bytes */
+ t = s[0];
+ s[0] = s[3];
+ s[3] = t;
+ /* swap inner two bytes */
+ t = s[1];
+ s[1] = s[2];
+ s[2] = t;
+ return v;
+}
+#if defined BIT16
+#define aligncell(v) align16(v)
+#else
+#define aligncell(v) align32(v)
+#endif
+#else
+#define align16(v) (v)
+#define align32(v) (v)
+#define aligncell(v) (v)
+#endif
+
+static char *
+skipwhitespace(char *str)
+{
+ while (sc_isspace(*str))
+ str++;
+ return str;
+}
+
+static char *
+stripcomment(char *str)
+{
+ char *ptr = strchr(str, ';');
+
+ if (ptr)
+ {
+ *ptr++ = '\n'; /* terminate the line, but leave the '\n' */
+ *ptr = '\0';
+ } /* if */
+ return str;
+}
+
+static void
+write_encoded(FILE * fbin, ucell * c, int num)
+{
+ assert(sizeof(cell) <= 4); /* code must be adjusted for larger cells */
+ assert(fbin != NULL);
+ while (num-- > 0)
+ {
+ if (sc_compress)
+ {
+ ucell p = (ucell) * c;
+ unsigned char t[5]; /* a 32-bit cell is encoded in max. 5 bytes (3 bytes for a 16-bit cell) */
+ unsigned char code;
+ int idx;
+
+ for (idx = 0; idx < 5; idx++)
+ {
+ t[idx] = (unsigned char)(p & 0x7f); /* store 7 bits */
+ p >>= 7;
+ } /* for */
+ /* skip leading zeros */
+ while (idx > 1 && t[idx - 1] == 0
+ && (t[idx - 2] & 0x40) == 0)
+ idx--;
+ /* skip leading -1s *//* ??? for BIT16, check for idx==3 && t[idx-1]==0x03 */
+ if (idx == 5 && t[idx - 1] == 0x0f
+ && (t[idx - 2] & 0x40) != 0)
+ idx--;
+ while (idx > 1 && t[idx - 1] == 0x7f
+ && (t[idx - 2] & 0x40) != 0)
+ idx--;
+ /* write high byte first, write continuation bits */
+ assert(idx > 0);
+ while (idx-- > 0)
+ {
+ code =
+ (unsigned char)((idx == 0) ? t[idx]
+ : (t[idx] | 0x80));
+ writeerror |= !sc_writebin(fbin, &code, 1);
+ bytes_out++;
+ } /* while */
+ bytes_in += sizeof *c;
+ assert(AMX_EXPANDMARGIN > 2);
+ if (bytes_out - bytes_in >= AMX_EXPANDMARGIN - 2)
+ error(106); /* compression buffer overflow */
+ }
+ else
+ {
+ assert((sc_lengthbin(fbin) % sizeof(cell)) == 0);
+ writeerror |= !sc_writebin(fbin, aligncell(c), sizeof *c);
+ } /* if */
+ c++;
+ } /* while */
+}
+
+#if defined __BORLANDC__ || defined __WATCOMC__
+#pragma argsused
+#endif
+
+static cell
+noop(FILE * fbin EINA_UNUSED, char *params EINA_UNUSED, cell opcode EINA_UNUSED)
+{
+ return 0;
+}
+
+#if defined __BORLANDC__ || defined __WATCOMC__
+#pragma argsused
+#endif
+
+static cell
+parm0(FILE * fbin, char *params EINA_UNUSED, cell opcode)
+{
+ if (fbin)
+ write_encoded(fbin, (ucell *) & opcode, 1);
+ return opcodes(1);
+}
+
+static cell
+parm1(FILE * fbin, char *params, cell opcode)
+{
+ ucell p = hex2long(params, NULL);
+
+ if (fbin)
+ {
+ write_encoded(fbin, (ucell *) & opcode, 1);
+ write_encoded(fbin, &p, 1);
+ } /* if */
+ return opcodes(1) + opargs(1);
+}
+
+static cell
+parm2(FILE * fbin, char *params, cell opcode)
+{
+ ucell p[2];
+
+ p[0] = hex2long(params, &params);
+ p[1] = hex2long(params, NULL);
+ if (fbin)
+ {
+ write_encoded(fbin, (ucell *) & opcode, 1);
+ write_encoded(fbin, p, 2);
+ } /* if */
+ return opcodes(1) + opargs(2);
+}
+
+#if defined __BORLANDC__ || defined __WATCOMC__
+#pragma argsused
+#endif
+
+static cell
+do_dump(FILE * fbin, char *params, cell opcode EINA_UNUSED)
+{
+ ucell p;
+ int num = 0;
+
+ while (*params != '\0')
+ {
+ p = hex2long(params, &params);
+ if (fbin)
+ write_encoded(fbin, &p, 1);
+ num++;
+ while (sc_isspace(*params))
+ params++;
+ } /* while */
+ return num * sizeof(cell);
+}
+
+static cell
+do_call(FILE * fbin, char *params, cell opcode)
+{
+ char name[sNAMEMAX + 1];
+ int i;
+ symbol *sym;
+ ucell p;
+
+ for (i = 0; !sc_isspace(*params); i++, params++)
+ {
+ assert(*params != '\0');
+ assert(i < sNAMEMAX);
+ name[i] = *params;
+ } /* for */
+ name[i] = '\0';
+
+ /* look up the function address; note that the correct file number must
+ * already have been set (in order for static globals to be found).
+ */
+ sym = findglb(name);
+ assert(sym != NULL);
+ assert(sym->ident == iFUNCTN || sym->ident == iREFFUNC);
+ assert(sym->vclass == sGLOBAL);
+
+ p = sym->addr;
+ if (fbin)
+ {
+ write_encoded(fbin, (ucell *) & opcode, 1);
+ write_encoded(fbin, &p, 1);
+ } /* if */
+ return opcodes(1) + opargs(1);
+}
+
+static cell
+do_jump(FILE * fbin, char *params, cell opcode)
+{
+ int i;
+ ucell p;
+
+ i = (int)hex2long(params, NULL);
+ assert(i >= 0 && i < labnum);
+
+ if (fbin)
+ {
+ assert(lbltab != NULL);
+ p = lbltab[i];
+ write_encoded(fbin, (ucell *) & opcode, 1);
+ write_encoded(fbin, &p, 1);
+ } /* if */
+ return opcodes(1) + opargs(1);
+}
+
+static cell
+do_file(FILE * fbin, char *params, cell opcode)
+{
+ ucell p, clen;
+ int len;
+
+ p = hex2long(params, &params);
+
+ /* remove leading and trailing white space from the filename */
+ while (sc_isspace(*params))
+ params++;
+ len = strlen(params);
+ while (len > 0 && sc_isspace(params[len - 1]))
+ len--;
+ params[len++] = '\0'; /* zero-terminate */
+ while (len % sizeof(cell) != 0)
+ params[len++] = '\0'; /* pad with zeros up to full cell */
+ assert(len > 0 && len < 256);
+ clen = len + sizeof(cell); /* add size of file ordinal */
+
+ if (fbin)
+ {
+ write_encoded(fbin, (ucell *) & opcode, 1);
+ write_encoded(fbin, &clen, 1);
+ write_encoded(fbin, &p, 1);
+ write_encoded(fbin, (ucell *) params, len / sizeof(cell));
+ } /* if */
+ return opcodes(1) + opargs(1) + clen; /* other argument is in clen */
+}
+
+static cell
+do_symbol(FILE * fbin, char *params, cell opcode)
+{
+ char *endptr;
+ ucell offset, clen, flags;
+ int len;
+ unsigned char mclass, type;
+
+ for (endptr = params; !sc_isspace(*endptr) && endptr != '\0'; endptr++)
+ /* nothing */ ;
+ assert(*endptr == ' ');
+
+ len = (int)(endptr - params);
+ assert(len > 0 && len < sNAMEMAX);
+ /* first get the other parameters from the line */
+ offset = hex2long(endptr, &endptr);
+ mclass = (unsigned char)hex2long(endptr, &endptr);
+ type = (unsigned char)hex2long(endptr, NULL);
+ flags = type + 256 * mclass;
+ /* now finish up the name (overwriting the input line) */
+ params[len++] = '\0'; /* zero-terminate */
+ while (len % sizeof(cell) != 0)
+ params[len++] = '\0'; /* pad with zeros up to full cell */
+ clen = len + 2 * sizeof(cell); /* add size of symbol address and flags */
+
+ if (fbin)
+ {
+ write_encoded(fbin, (ucell *) & opcode, 1);
+ write_encoded(fbin, &clen, 1);
+ write_encoded(fbin, &offset, 1);
+ write_encoded(fbin, &flags, 1);
+ write_encoded(fbin, (ucell *) params, len / sizeof(cell));
+ } /* if */
+
+#if !defined NDEBUG
+ /* function should start right after the symbolic information */
+ if (!fbin && mclass == 0 && type == iFUNCTN)
+ assert(offset == codeindex + opcodes(1) + opargs(1) + clen);
+#endif
+
+ return opcodes(1) + opargs(1) + clen; /* other 2 arguments are in clen */
+}
+
+static cell
+do_switch(FILE * fbin, char *params, cell opcode)
+{
+ int i;
+ ucell p;
+
+ i = (int)hex2long(params, NULL);
+ assert(i >= 0 && i < labnum);
+
+ if (fbin)
+ {
+ assert(lbltab != NULL);
+ p = lbltab[i];
+ write_encoded(fbin, (ucell *) & opcode, 1);
+ write_encoded(fbin, &p, 1);
+ } /* if */
+ return opcodes(1) + opargs(1);
+}
+
+#if defined __BORLANDC__ || defined __WATCOMC__
+#pragma argsused
+#endif
+
+static cell
+do_case(FILE * fbin, char *params, cell opcode EINA_UNUSED)
+{
+ int i;
+ ucell p, v;
+
+ v = hex2long(params, &params);
+ i = (int)hex2long(params, NULL);
+ assert(i >= 0 && i < labnum);
+
+ if (fbin)
+ {
+ assert(lbltab != NULL);
+ p = lbltab[i];
+ write_encoded(fbin, &v, 1);
+ write_encoded(fbin, &p, 1);
+ } /* if */
+ return opcodes(0) + opargs(2);
+}
+
+#if defined __BORLANDC__ || defined __WATCOMC__
+#pragma argsused
+#endif
+
+static cell
+curfile(FILE * fbin EINA_UNUSED, char *params, cell opcode EINA_UNUSED)
+{
+ fcurrent = (int)hex2long(params, NULL);
+ return 0;
+}
+
+static OPCODE opcodelist[] = {
+ /* node for "invalid instruction" */
+ {0, NULL, 0, noop},
+ /* opcodes in sorted order */
+ {78, "add", sIN_CSEG, parm0},
+ {87, "add.c", sIN_CSEG, parm1},
+ {14, "addr.alt", sIN_CSEG, parm1},
+ {13, "addr.pri", sIN_CSEG, parm1},
+ {30, "align.alt", sIN_CSEG, parm1},
+ {29, "align.pri", sIN_CSEG, parm1},
+ {81, "and", sIN_CSEG, parm0},
+ {121, "bounds", sIN_CSEG, parm1},
+ {49, "call", sIN_CSEG, do_call},
+ {50, "call.pri", sIN_CSEG, parm0},
+ {0, "case", sIN_CSEG, do_case},
+ {130, "casetbl", sIN_CSEG, parm0}, /* version 1 */
+ {118, "cmps", sIN_CSEG, parm1},
+ {0, "code", 0, noop},
+ {12, "const.alt", sIN_CSEG, parm1},
+ {11, "const.pri", sIN_CSEG, parm1},
+ {0, "curfile", sIN_CSEG, curfile},
+ {0, "data", 0, noop},
+ {114, "dec", sIN_CSEG, parm1},
+ {113, "dec.alt", sIN_CSEG, parm0},
+ {116, "dec.i", sIN_CSEG, parm0},
+ {112, "dec.pri", sIN_CSEG, parm0},
+ {115, "dec.s", sIN_CSEG, parm1},
+ {0, "dump", sIN_DSEG, do_dump},
+ {95, "eq", sIN_CSEG, parm0},
+ {106, "eq.c.alt", sIN_CSEG, parm1},
+ {105, "eq.c.pri", sIN_CSEG, parm1},
+ {124, "file", sIN_CSEG, do_file},
+ {119, "fill", sIN_CSEG, parm1},
+ {100, "geq", sIN_CSEG, parm0},
+ {99, "grtr", sIN_CSEG, parm0},
+ {120, "halt", sIN_CSEG, parm1},
+ {45, "heap", sIN_CSEG, parm1},
+ {27, "idxaddr", sIN_CSEG, parm0},
+ {28, "idxaddr.b", sIN_CSEG, parm1},
+ {109, "inc", sIN_CSEG, parm1},
+ {108, "inc.alt", sIN_CSEG, parm0},
+ {111, "inc.i", sIN_CSEG, parm0},
+ {107, "inc.pri", sIN_CSEG, parm0},
+ {110, "inc.s", sIN_CSEG, parm1},
+ {86, "invert", sIN_CSEG, parm0},
+ {55, "jeq", sIN_CSEG, do_jump},
+ {60, "jgeq", sIN_CSEG, do_jump},
+ {59, "jgrtr", sIN_CSEG, do_jump},
+ {58, "jleq", sIN_CSEG, do_jump},
+ {57, "jless", sIN_CSEG, do_jump},
+ {56, "jneq", sIN_CSEG, do_jump},
+ {54, "jnz", sIN_CSEG, do_jump},
+ {52, "jrel", sIN_CSEG, parm1}, /* always a number */
+ {64, "jsgeq", sIN_CSEG, do_jump},
+ {63, "jsgrtr", sIN_CSEG, do_jump},
+ {62, "jsleq", sIN_CSEG, do_jump},
+ {61, "jsless", sIN_CSEG, do_jump},
+ {51, "jump", sIN_CSEG, do_jump},
+ {128, "jump.pri", sIN_CSEG, parm0}, /* version 1 */
+ {53, "jzer", sIN_CSEG, do_jump},
+ {31, "lctrl", sIN_CSEG, parm1},
+ {98, "leq", sIN_CSEG, parm0},
+ {97, "less", sIN_CSEG, parm0},
+ {25, "lidx", sIN_CSEG, parm0},
+ {26, "lidx.b", sIN_CSEG, parm1},
+ {125, "line", sIN_CSEG, parm2},
+ {2, "load.alt", sIN_CSEG, parm1},
+ {9, "load.i", sIN_CSEG, parm0},
+ {1, "load.pri", sIN_CSEG, parm1},
+ {4, "load.s.alt", sIN_CSEG, parm1},
+ {3, "load.s.pri", sIN_CSEG, parm1},
+ {10, "lodb.i", sIN_CSEG, parm1},
+ {6, "lref.alt", sIN_CSEG, parm1},
+ {5, "lref.pri", sIN_CSEG, parm1},
+ {8, "lref.s.alt", sIN_CSEG, parm1},
+ {7, "lref.s.pri", sIN_CSEG, parm1},
+ {34, "move.alt", sIN_CSEG, parm0},
+ {33, "move.pri", sIN_CSEG, parm0},
+ {117, "movs", sIN_CSEG, parm1},
+ {85, "neg", sIN_CSEG, parm0},
+ {96, "neq", sIN_CSEG, parm0},
+ {134, "nop", sIN_CSEG, parm0}, /* version 6 */
+ {84, "not", sIN_CSEG, parm0},
+ {82, "or", sIN_CSEG, parm0},
+ {43, "pop.alt", sIN_CSEG, parm0},
+ {42, "pop.pri", sIN_CSEG, parm0},
+ {46, "proc", sIN_CSEG, parm0},
+ {40, "push", sIN_CSEG, parm1},
+ {37, "push.alt", sIN_CSEG, parm0},
+ {39, "push.c", sIN_CSEG, parm1},
+ {36, "push.pri", sIN_CSEG, parm0},
+ {38, "push.r", sIN_CSEG, parm1},
+ {41, "push.s", sIN_CSEG, parm1},
+ {133, "pushaddr", sIN_CSEG, parm1}, /* version 4 */
+ {47, "ret", sIN_CSEG, parm0},
+ {48, "retn", sIN_CSEG, parm0},
+ {32, "sctrl", sIN_CSEG, parm1},
+ {73, "sdiv", sIN_CSEG, parm0},
+ {74, "sdiv.alt", sIN_CSEG, parm0},
+ {104, "sgeq", sIN_CSEG, parm0},
+ {103, "sgrtr", sIN_CSEG, parm0},
+ {65, "shl", sIN_CSEG, parm0},
+ {69, "shl.c.alt", sIN_CSEG, parm1},
+ {68, "shl.c.pri", sIN_CSEG, parm1},
+ {66, "shr", sIN_CSEG, parm0},
+ {71, "shr.c.alt", sIN_CSEG, parm1},
+ {70, "shr.c.pri", sIN_CSEG, parm1},
+ {94, "sign.alt", sIN_CSEG, parm0},
+ {93, "sign.pri", sIN_CSEG, parm0},
+ {102, "sleq", sIN_CSEG, parm0},
+ {101, "sless", sIN_CSEG, parm0},
+ {72, "smul", sIN_CSEG, parm0},
+ {88, "smul.c", sIN_CSEG, parm1},
+ {127, "srange", sIN_CSEG, parm2}, /* version 1 */
+ {20, "sref.alt", sIN_CSEG, parm1},
+ {19, "sref.pri", sIN_CSEG, parm1},
+ {22, "sref.s.alt", sIN_CSEG, parm1},
+ {21, "sref.s.pri", sIN_CSEG, parm1},
+ {67, "sshr", sIN_CSEG, parm0},
+ {44, "stack", sIN_CSEG, parm1},
+ {0, "stksize", 0, noop},
+ {16, "stor.alt", sIN_CSEG, parm1},
+ {23, "stor.i", sIN_CSEG, parm0},
+ {15, "stor.pri", sIN_CSEG, parm1},
+ {18, "stor.s.alt", sIN_CSEG, parm1},
+ {17, "stor.s.pri", sIN_CSEG, parm1},
+ {24, "strb.i", sIN_CSEG, parm1},
+ {79, "sub", sIN_CSEG, parm0},
+ {80, "sub.alt", sIN_CSEG, parm0},
+ {132, "swap.alt", sIN_CSEG, parm0}, /* version 4 */
+ {131, "swap.pri", sIN_CSEG, parm0}, /* version 4 */
+ {129, "switch", sIN_CSEG, do_switch}, /* version 1 */
+ {126, "symbol", sIN_CSEG, do_symbol},
+ {136, "symtag", sIN_CSEG, parm1}, /* version 7 */
+ {123, "sysreq.c", sIN_CSEG, parm1},
+ {135, "sysreq.d", sIN_CSEG, parm1}, /* version 7, not generated directly */
+ {122, "sysreq.pri", sIN_CSEG, parm0},
+ {76, "udiv", sIN_CSEG, parm0},
+ {77, "udiv.alt", sIN_CSEG, parm0},
+ {75, "umul", sIN_CSEG, parm0},
+ {35, "xchg", sIN_CSEG, parm0},
+ {83, "xor", sIN_CSEG, parm0},
+ {91, "zero", sIN_CSEG, parm1},
+ {90, "zero.alt", sIN_CSEG, parm0},
+ {89, "zero.pri", sIN_CSEG, parm0},
+ {92, "zero.s", sIN_CSEG, parm1},
+};
+
+#define MAX_INSTR_LEN 30
+static int
+findopcode(char *instr, int maxlen)
+{
+ int low, high, mid, cmp;
+ char str[MAX_INSTR_LEN];
+
+ if (maxlen >= MAX_INSTR_LEN)
+ return 0;
+ strncpy(str, instr, maxlen);
+ str[maxlen] = '\0'; /* make sure the string is zero terminated */
+ /* look up the instruction with a binary search
+ * the assembler is case insensitive to instructions (but case sensitive
+ * to symbols)
+ */
+ low = 1; /* entry 0 is reserved (for "not found") */
+ high = (sizeof opcodelist / sizeof opcodelist[0]) - 1;
+ while (low < high)
+ {
+ mid = (low + high) / 2;
+ assert(opcodelist[mid].name != NULL);
+ cmp = strcasecmp(str, opcodelist[mid].name);
+ if (cmp > 0)
+ low = mid + 1;
+ else
+ high = mid;
+ } /* while */
+
+ assert(low == high);
+ if (strcasecmp(str, opcodelist[low].name) == 0)
+ return low; /* found */
+ return 0; /* not found, return special index */
+}
+
+void
+assemble(FILE * fout, FILE * fin)
+{
+ typedef struct tagFUNCSTUB
+ {
+ unsigned int address, nameofs;
+ } FUNCSTUB;
+ AMX_HEADER hdr;
+ FUNCSTUB func;
+ int numpublics, numnatives, numlibraries, numpubvars,
+ numtags, padding;
+ long nametablesize, nameofs;
+ char line[256], *instr, *params;
+ int i, pass;
+ short count;
+ symbol *sym, **nativelist;
+ constvalue *constptr;
+ cell mainaddr;
+ int nametable, tags, libraries, publics, natives, pubvars;
+ int cod, defsize;
+
+#if !defined NDEBUG
+ /* verify that the opcode list is sorted (skip entry 1; it is reserved
+ * for a non-existent opcode)
+ */
+ assert(opcodelist[1].name != NULL);
+ for (i = 2; i < (int)(sizeof(opcodelist) / sizeof(opcodelist[0])); i++)
+ {
+ assert(opcodelist[i].name != NULL);
+ assert(strcasecmp(opcodelist[i].name, opcodelist[i - 1].name) > 0);
+ } /* for */
+#endif
+
+ writeerror = FALSE;
+ nametablesize = sizeof(short);
+ numpublics = 0;
+ numnatives = 0;
+ numpubvars = 0;
+ mainaddr = -1;
+ /* count number of public and native functions and public variables */
+ for (sym = glbtab.next; sym; sym = sym->next)
+ {
+ char alias[sNAMEMAX + 1] = "";
+ int match = 0;
+
+ if (sym->ident == iFUNCTN)
+ {
+ assert(strlen(sym->name) <= sNAMEMAX);
+ if ((sym->usage & uNATIVE) != 0 && (sym->usage & uREAD) != 0
+ && sym->addr >= 0)
+ {
+ match = ++numnatives;
+ if (!lookup_alias(alias, sym->name))
+ strcpy(alias, sym->name);
+ } /* if */
+ if ((sym->usage & uPUBLIC) != 0 && (sym->usage & uDEFINE) != 0)
+ {
+ match = ++numpublics;
+ strcpy(alias, sym->name);
+ } /* if */
+ if (strcmp(sym->name, uMAINFUNC) == 0)
+ {
+ assert(sym->vclass == sGLOBAL);
+ mainaddr = sym->addr;
+ } /* if */
+ }
+ else if (sym->ident == iVARIABLE)
+ {
+ if ((sym->usage & uPUBLIC) != 0)
+ {
+ match = ++numpubvars;
+ strcpy(alias, sym->name);
+ } /* if */
+ } /* if */
+ if (match)
+ {
+ assert(alias[0] != '\0');
+ nametablesize += strlen(alias) + 1;
+ } /* if */
+ } /* for */
+ assert(numnatives == ntv_funcid);
+
+ /* count number of libraries */
+ numlibraries = 0;
+ for (constptr = libname_tab.next; constptr;
+ constptr = constptr->next)
+ {
+ if (constptr->value > 0)
+ {
+ assert(constptr->name[0] != '\0');
+ numlibraries++;
+ nametablesize += strlen(constptr->name) + 1;
+ } /* if */
+ } /* for */
+
+ /* count number of public tags */
+ numtags = 0;
+ for (constptr = tagname_tab.next; constptr;
+ constptr = constptr->next)
+ {
+ if ((constptr->value & PUBLICTAG) != 0)
+ {
+ assert(constptr->name[0] != '\0');
+ numtags++;
+ nametablesize += strlen(constptr->name) + 1;
+ } /* if */
+ } /* for */
+
+ /* pad the header to sc_dataalign
+ * => thereby the code segment is aligned
+ * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned
+ * => and thereby the stack top is aligned too
+ */
+ assert(sc_dataalign != 0);
+ padding = sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign;
+ if (padding == sc_dataalign)
+ padding = 0;
+
+ /* write the abstract machine header */
+ memset(&hdr, 0, sizeof hdr);
+ hdr.magic = (unsigned short)0xF1E0;
+ hdr.file_version = CUR_FILE_VERSION;
+ hdr.amx_version = MIN_AMX_VERSION;
+ hdr.flags = (short)(sc_debug & sSYMBOLIC);
+ if (charbits == 16)
+ hdr.flags |= AMX_FLAG_CHAR16;
+ if (sc_compress)
+ hdr.flags |= AMX_FLAG_COMPACT;
+ if (sc_debug == 0)
+ hdr.flags |= AMX_FLAG_NOCHECKS;
+// #ifdef WORDS_BIGENDIAN
+// hdr.flags|=AMX_FLAG_BIGENDIAN;
+// #endif
+ defsize = hdr.defsize = sizeof(FUNCSTUB);
+ assert((hdr.defsize % sizeof(cell)) == 0);
+ publics = hdr.publics = sizeof hdr; /* public table starts right after the header */
+ natives = hdr.natives = hdr.publics + numpublics * sizeof(FUNCSTUB);
+ libraries = hdr.libraries = hdr.natives + numnatives * sizeof(FUNCSTUB);
+ pubvars = hdr.pubvars = hdr.libraries + numlibraries * sizeof(FUNCSTUB);
+ tags = hdr.tags = hdr.pubvars + numpubvars * sizeof(FUNCSTUB);
+ nametable = hdr.nametable = hdr.tags + numtags * sizeof(FUNCSTUB);
+ cod = hdr.cod = hdr.nametable + nametablesize + padding;
+ hdr.dat = hdr.cod + code_idx;
+ hdr.hea = hdr.dat + glb_declared * sizeof(cell);
+ hdr.stp = hdr.hea + sc_stksize * sizeof(cell);
+ hdr.cip = mainaddr;
+ hdr.size = hdr.hea; /* preset, this is incorrect in case of compressed output */
+#ifdef WORDS_BIGENDIAN
+ align32(&hdr.size);
+ align16(&hdr.magic);
+ align16(&hdr.flags);
+ align16(&hdr.defsize);
+ align32(&hdr.cod);
+ align32(&hdr.dat);
+ align32(&hdr.hea);
+ align32(&hdr.stp);
+ align32(&hdr.cip);
+ align32(&hdr.publics);
+ align32(&hdr.natives);
+ align32(&hdr.libraries);
+ align32(&hdr.pubvars);
+ align32(&hdr.tags);
+ align32(&hdr.nametable);
+#endif
+ sc_writebin(fout, &hdr, sizeof hdr);
+
+ /* dump zeros up to the rest of the header, so that we can easily "seek" */
+ for (nameofs = sizeof hdr; nameofs < cod; nameofs++)
+ putc(0, fout);
+ nameofs = nametable + sizeof(short);
+
+ /* write the public functions table */
+ count = 0;
+ for (sym = glbtab.next; sym; sym = sym->next)
+ {
+ if (sym->ident == iFUNCTN
+ && (sym->usage & uPUBLIC) != 0 && (sym->usage & uDEFINE) != 0)
+ {
+ assert(sym->vclass == sGLOBAL);
+ func.address = sym->addr;
+ func.nameofs = nameofs;
+#ifdef WORDS_BIGENDIAN
+ align32(&func.address);
+ align32(&func.nameofs);
+#endif
+ fseek(fout, publics + count * sizeof(FUNCSTUB), SEEK_SET);
+ sc_writebin(fout, &func, sizeof func);
+ fseek(fout, nameofs, SEEK_SET);
+ sc_writebin(fout, sym->name, strlen(sym->name) + 1);
+ nameofs += strlen(sym->name) + 1;
+ count++;
+ } /* if */
+ } /* for */
+
+ /* write the natives table */
+ /* The native functions must be written in sorted order. (They are
+ * sorted on their "id", not on their name). A nested loop to find
+ * each successive function would be an O(n^2) operation. But we
+ * do not really need to sort, because the native function id's
+ * are sequential and there are no duplicates. So we first walk
+ * through the complete symbol list and store a pointer to every
+ * native function of interest in a temporary table, where its id
+ * serves as the index in the table. Now we can walk the table and
+ * have all native functions in sorted order.
+ */
+ if (numnatives > 0)
+ {
+ nativelist = (symbol **) malloc(numnatives * sizeof(symbol *));
+ if (!nativelist)
+ error(103); /* insufficient memory */
+#if !defined NDEBUG
+ memset(nativelist, 0, numnatives * sizeof(symbol *)); /* for NULL checking */
+#endif
+ for (sym = glbtab.next; sym; sym = sym->next)
+ {
+ if (sym->ident == iFUNCTN && (sym->usage & uNATIVE) != 0
+ && (sym->usage & uREAD) != 0 && sym->addr >= 0)
+ {
+ assert(sym->addr < numnatives);
+ nativelist[(int)sym->addr] = sym;
+ } /* if */
+ } /* for */
+ count = 0;
+ for (i = 0; i < numnatives; i++)
+ {
+ char alias[sNAMEMAX + 1];
+
+ sym = nativelist[i];
+ assert(sym != NULL);
+ if (!lookup_alias(alias, sym->name))
+ {
+ assert(strlen(sym->name) <= sNAMEMAX);
+ strcpy(alias, sym->name);
+ } /* if */
+ assert(sym->vclass == sGLOBAL);
+ func.address = 0;
+ func.nameofs = nameofs;
+#ifdef WORDS_BIGENDIAN
+ align32(&func.address);
+ align32(&func.nameofs);
+#endif
+ fseek(fout, natives + count * sizeof(FUNCSTUB), SEEK_SET);
+ sc_writebin(fout, &func, sizeof func);
+ fseek(fout, nameofs, SEEK_SET);
+ sc_writebin(fout, alias, strlen(alias) + 1);
+ nameofs += strlen(alias) + 1;
+ count++;
+ } /* for */
+ free(nativelist);
+ } /* if */
+
+ /* write the libraries table */
+ count = 0;
+ for (constptr = libname_tab.next; constptr;
+ constptr = constptr->next)
+ {
+ if (constptr->value > 0)
+ {
+ assert(constptr->name[0] != '\0');
+ func.address = 0;
+ func.nameofs = nameofs;
+#ifdef WORDS_BIGENDIAN
+ align32(&func.address);
+ align32(&func.nameofs);
+#endif
+ fseek(fout, libraries + count * sizeof(FUNCSTUB), SEEK_SET);
+ sc_writebin(fout, &func, sizeof func);
+ fseek(fout, nameofs, SEEK_SET);
+ sc_writebin(fout, constptr->name, strlen(constptr->name) + 1);
+ nameofs += strlen(constptr->name) + 1;
+ count++;
+ } /* if */
+ } /* for */
+
+ /* write the public variables table */
+ count = 0;
+ for (sym = glbtab.next; sym; sym = sym->next)
+ {
+ if (sym->ident == iVARIABLE && (sym->usage & uPUBLIC) != 0)
+ {
+ assert((sym->usage & uDEFINE) != 0);
+ assert(sym->vclass == sGLOBAL);
+ func.address = sym->addr;
+ func.nameofs = nameofs;
+#ifdef WORDS_BIGENDIAN
+ align32(&func.address);
+ align32(&func.nameofs);
+#endif
+ fseek(fout, pubvars + count * sizeof(FUNCSTUB), SEEK_SET);
+ sc_writebin(fout, &func, sizeof func);
+ fseek(fout, nameofs, SEEK_SET);
+ sc_writebin(fout, sym->name, strlen(sym->name) + 1);
+ nameofs += strlen(sym->name) + 1;
+ count++;
+ } /* if */
+ } /* for */
+
+ /* write the public tagnames table */
+ count = 0;
+ for (constptr = tagname_tab.next; constptr;
+ constptr = constptr->next)
+ {
+ if ((constptr->value & PUBLICTAG) != 0)
+ {
+ assert(constptr->name[0] != '\0');
+ func.address = constptr->value & TAGMASK;
+ func.nameofs = nameofs;
+#ifdef WORDS_BIGENDIAN
+ align32(&func.address);
+ align32(&func.nameofs);
+#endif
+ fseek(fout, tags + count * sizeof(FUNCSTUB), SEEK_SET);
+ sc_writebin(fout, &func, sizeof func);
+ fseek(fout, nameofs, SEEK_SET);
+ sc_writebin(fout, constptr->name, strlen(constptr->name) + 1);
+ nameofs += strlen(constptr->name) + 1;
+ count++;
+ } /* if */
+ } /* for */
+
+ /* write the "maximum name length" field in the name table */
+ assert(nameofs == nametable + nametablesize);
+ fseek(fout, nametable, SEEK_SET);
+ count = sNAMEMAX;
+#ifdef WORDS_BIGENDIAN
+ align16(&count);
+#endif
+ sc_writebin(fout, &count, sizeof count);
+ fseek(fout, cod, SEEK_SET);
+
+ /* First pass: relocate all labels */
+ /* This pass is necessary because the code addresses of labels is only known
+ * after the peephole optimization flag. Labels can occur inside expressions
+ * (e.g. the conditional operator), which are optimized.
+ */
+ lbltab = NULL;
+ if (labnum > 0)
+ {
+ /* only very short programs have zero labels; no first pass is needed
+ * if there are no labels */
+ lbltab = (cell *) malloc(labnum * sizeof(cell));
+ if (!lbltab)
+ error(103); /* insufficient memory */
+ codeindex = 0;
+ sc_resetasm(fin);
+ while (sc_readasm(fin, line, sizeof line))
+ {
+ stripcomment(line);
+ instr = skipwhitespace(line);
+ /* ignore empty lines */
+ if (*instr == '\0')
+ continue;
+ if (tolower(*instr) == 'l' && *(instr + 1) == '.')
+ {
+ int lindex = (int)hex2long(instr + 2, NULL);
+
+ assert(lindex < labnum);
+ lbltab[lindex] = codeindex;
+ }
+ else
+ {
+ /* get to the end of the instruction (make use of the '\n' that fgets()
+ * added at the end of the line; this way we will *always* drop on a
+ * whitespace character) */
+ for (params = instr; *params != '\0' && !sc_isspace(*params);
+ params++)
+ /* nothing */ ;
+ assert(params > instr);
+ i = findopcode(instr, (int)(params - instr));
+ if (!opcodelist[i].name)
+ {
+ *params = '\0';
+ error(104, instr); /* invalid assembler instruction */
+ } /* if */
+ if (opcodelist[i].segment == sIN_CSEG)
+ codeindex +=
+ opcodelist[i].func(NULL, skipwhitespace(params),
+ opcodelist[i].opcode);
+ } /* if */
+ } /* while */
+ } /* if */
+
+ /* Second pass (actually 2 more passes, one for all code and one for all data) */
+ bytes_in = 0;
+ bytes_out = 0;
+ for (pass = sIN_CSEG; pass <= sIN_DSEG; pass++)
+ {
+ sc_resetasm(fin);
+ while (sc_readasm(fin, line, sizeof line))
+ {
+ stripcomment(line);
+ instr = skipwhitespace(line);
+ /* ignore empty lines and labels (labels have a special syntax, so these
+ * must be parsed separately) */
+ if (*instr == '\0' || (tolower(*instr) == 'l'
+ && *(instr + 1) == '.'))
+ continue;
+ /* get to the end of the instruction (make use of the '\n' that fgets()
+ * added at the end of the line; this way we will *always* drop on a
+ * whitespace character) */
+ for (params = instr; *params != '\0' && !sc_isspace(*params);
+ params++)
+ /* nothing */ ;
+ assert(params > instr);
+ i = findopcode(instr, (int)(params - instr));
+ assert(opcodelist[i].name != NULL);
+ if (opcodelist[i].segment == pass)
+ opcodelist[i].func(fout, skipwhitespace(params),
+ opcodelist[i].opcode);
+ } /* while */
+ } /* for */
+ if (bytes_out - bytes_in > 0)
+ error(106); /* compression buffer overflow */
+
+ if (lbltab)
+ {
+ free(lbltab);
+#if !defined NDEBUG
+ lbltab = NULL;
+#endif
+ } /* if */
+
+ if (writeerror)
+ error(101, "disk full");
+
+ /* adjust the header */
+ if (sc_compress)
+ {
+ hdr.size = sc_lengthbin(fout);
+#ifdef WORDS_BIGENDIAN
+ align32(&hdr.size);
+#endif
+ sc_resetbin(fout); /* "size" is the very first field */
+ sc_writebin(fout, &hdr.size, sizeof hdr.size);
+ } /* if */
+}