aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/embryo/src/bin/embryo_cc_sc6.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/embryo/src/bin/embryo_cc_sc6.c')
-rw-r--r--libraries/embryo/src/bin/embryo_cc_sc6.c1077
1 files changed, 1077 insertions, 0 deletions
diff --git a/libraries/embryo/src/bin/embryo_cc_sc6.c b/libraries/embryo/src/bin/embryo_cc_sc6.c
new file mode 100644
index 0000000..7ec6098
--- /dev/null
+++ b/libraries/embryo/src/bin/embryo_cc_sc6.c
@@ -0,0 +1,1077 @@
1/* Small compiler - Binary code generation (the "assembler")
2 *
3 * Copyright (c) ITB CompuPhase, 1997-2003
4 *
5 * This software is provided "as-is", without any express or implied warranty.
6 * In no event will the authors be held liable for any damages arising from
7 * the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software in
15 * a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
20 *
21 * Version: $Id: embryo_cc_sc6.c 52451 2010-09-19 03:00:12Z raster $
22 */
23
24
25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
28
29#include <assert.h>
30#include <stdio.h>
31#include <stdlib.h> /* for macro max() */
32#include <string.h>
33#include <ctype.h>
34#include "embryo_cc_sc.h"
35
36typedef cell(*OPCODE_PROC) (FILE * fbin, char *params, cell opcode);
37
38typedef struct
39{
40 cell opcode;
41 char *name;
42 int segment; /* sIN_CSEG=parse in cseg, sIN_DSEG=parse in dseg */
43 OPCODE_PROC func;
44} OPCODE;
45
46static cell codeindex; /* similar to "code_idx" */
47static cell *lbltab; /* label table */
48static int writeerror;
49static int bytes_in, bytes_out;
50
51/* apparently, strtol() does not work correctly on very large (unsigned)
52 * hexadecimal values */
53static ucell
54hex2long(char *s, char **n)
55{
56 unsigned long result = 0L;
57 int negate = FALSE;
58 int digit;
59
60 /* ignore leading whitespace */
61 while (*s == ' ' || *s == '\t')
62 s++;
63
64 /* allow a negation sign to create the two's complement of numbers */
65 if (*s == '-')
66 {
67 negate = TRUE;
68 s++;
69 } /* if */
70
71 assert((*s >= '0' && *s <= '9') || (*s >= 'a' && *s <= 'f')
72 || (*s >= 'a' && *s <= 'f'));
73 for (;;)
74 {
75 if (*s >= '0' && *s <= '9')
76 digit = *s - '0';
77 else if (*s >= 'a' && *s <= 'f')
78 digit = *s - 'a' + 10;
79 else if (*s >= 'A' && *s <= 'F')
80 digit = *s - 'A' + 10;
81 else
82 break; /* probably whitespace */
83 result = (result << 4) | digit;
84 s++;
85 } /* for */
86 if (n)
87 *n = s;
88 if (negate)
89 result = (~result) + 1; /* take two's complement of the result */
90 return (ucell) result;
91}
92
93#ifdef WORDS_BIGENDIAN
94static short *
95align16(short *v)
96{
97 unsigned char *s = (unsigned char *)v;
98 unsigned char t;
99
100 /* swap two bytes */
101 t = s[0];
102 s[0] = s[1];
103 s[1] = t;
104 return v;
105}
106
107static long *
108align32(long *v)
109{
110 unsigned char *s = (unsigned char *)v;
111 unsigned char t;
112
113 /* swap outer two bytes */
114 t = s[0];
115 s[0] = s[3];
116 s[3] = t;
117 /* swap inner two bytes */
118 t = s[1];
119 s[1] = s[2];
120 s[2] = t;
121 return v;
122}
123#if defined BIT16
124#define aligncell(v) align16(v)
125#else
126#define aligncell(v) align32(v)
127#endif
128#else
129#define align16(v) (v)
130#define align32(v) (v)
131#define aligncell(v) (v)
132#endif
133
134static char *
135skipwhitespace(char *str)
136{
137 while (isspace(*str))
138 str++;
139 return str;
140}
141
142static char *
143stripcomment(char *str)
144{
145 char *ptr = strchr(str, ';');
146
147 if (ptr)
148 {
149 *ptr++ = '\n'; /* terminate the line, but leave the '\n' */
150 *ptr = '\0';
151 } /* if */
152 return str;
153}
154
155static void
156write_encoded(FILE * fbin, ucell * c, int num)
157{
158 assert(sizeof(cell) <= 4); /* code must be adjusted for larger cells */
159 assert(fbin != NULL);
160 while (num-- > 0)
161 {
162 if (sc_compress)
163 {
164 ucell p = (ucell) * c;
165 unsigned char t[5]; /* a 32-bit cell is encoded in max. 5 bytes (3 bytes for a 16-bit cell) */
166 unsigned char code;
167 int index;
168
169 for (index = 0; index < 5; index++)
170 {
171 t[index] = (unsigned char)(p & 0x7f); /* store 7 bits */
172 p >>= 7;
173 } /* for */
174 /* skip leading zeros */
175 while (index > 1 && t[index - 1] == 0
176 && (t[index - 2] & 0x40) == 0)
177 index--;
178 /* skip leading -1s *//* ??? for BIT16, check for index==3 && t[index-1]==0x03 */
179 if (index == 5 && t[index - 1] == 0x0f
180 && (t[index - 2] & 0x40) != 0)
181 index--;
182 while (index > 1 && t[index - 1] == 0x7f
183 && (t[index - 2] & 0x40) != 0)
184 index--;
185 /* write high byte first, write continuation bits */
186 assert(index > 0);
187 while (index-- > 0)
188 {
189 code =
190 (unsigned char)((index == 0) ? t[index]
191 : (t[index] | 0x80));
192 writeerror |= !sc_writebin(fbin, &code, 1);
193 bytes_out++;
194 } /* while */
195 bytes_in += sizeof *c;
196 assert(AMX_EXPANDMARGIN > 2);
197 if (bytes_out - bytes_in >= AMX_EXPANDMARGIN - 2)
198 error(106); /* compression buffer overflow */
199 }
200 else
201 {
202 assert((sc_lengthbin(fbin) % sizeof(cell)) == 0);
203 writeerror |= !sc_writebin(fbin, aligncell(c), sizeof *c);
204 } /* if */
205 c++;
206 } /* while */
207}
208
209#if defined __BORLANDC__ || defined __WATCOMC__
210#pragma argsused
211#endif
212
213static cell
214noop(FILE * fbin __UNUSED__, char *params __UNUSED__, cell opcode __UNUSED__)
215{
216 return 0;
217}
218
219#if defined __BORLANDC__ || defined __WATCOMC__
220#pragma argsused
221#endif
222
223static cell
224parm0(FILE * fbin, char *params __UNUSED__, cell opcode)
225{
226 if (fbin)
227 write_encoded(fbin, (ucell *) & opcode, 1);
228 return opcodes(1);
229}
230
231static cell
232parm1(FILE * fbin, char *params, cell opcode)
233{
234 ucell p = hex2long(params, NULL);
235
236 if (fbin)
237 {
238 write_encoded(fbin, (ucell *) & opcode, 1);
239 write_encoded(fbin, &p, 1);
240 } /* if */
241 return opcodes(1) + opargs(1);
242}
243
244static cell
245parm2(FILE * fbin, char *params, cell opcode)
246{
247 ucell p[2];
248
249 p[0] = hex2long(params, &params);
250 p[1] = hex2long(params, NULL);
251 if (fbin)
252 {
253 write_encoded(fbin, (ucell *) & opcode, 1);
254 write_encoded(fbin, p, 2);
255 } /* if */
256 return opcodes(1) + opargs(2);
257}
258
259#if defined __BORLANDC__ || defined __WATCOMC__
260#pragma argsused
261#endif
262
263static cell
264do_dump(FILE * fbin, char *params, cell opcode __UNUSED__)
265{
266 ucell p;
267 int num = 0;
268
269 while (*params != '\0')
270 {
271 p = hex2long(params, &params);
272 if (fbin)
273 write_encoded(fbin, &p, 1);
274 num++;
275 while (isspace(*params))
276 params++;
277 } /* while */
278 return num * sizeof(cell);
279}
280
281static cell
282do_call(FILE * fbin, char *params, cell opcode)
283{
284 char name[sNAMEMAX + 1];
285 int i;
286 symbol *sym;
287 ucell p;
288
289 for (i = 0; !isspace(*params); i++, params++)
290 {
291 assert(*params != '\0');
292 assert(i < sNAMEMAX);
293 name[i] = *params;
294 } /* for */
295 name[i] = '\0';
296
297 /* look up the function address; note that the correct file number must
298 * already have been set (in order for static globals to be found).
299 */
300 sym = findglb(name);
301 assert(sym != NULL);
302 assert(sym->ident == iFUNCTN || sym->ident == iREFFUNC);
303 assert(sym->vclass == sGLOBAL);
304
305 p = sym->addr;
306 if (fbin)
307 {
308 write_encoded(fbin, (ucell *) & opcode, 1);
309 write_encoded(fbin, &p, 1);
310 } /* if */
311 return opcodes(1) + opargs(1);
312}
313
314static cell
315do_jump(FILE * fbin, char *params, cell opcode)
316{
317 int i;
318 ucell p;
319
320 i = (int)hex2long(params, NULL);
321 assert(i >= 0 && i < labnum);
322
323 if (fbin)
324 {
325 assert(lbltab != NULL);
326 p = lbltab[i];
327 write_encoded(fbin, (ucell *) & opcode, 1);
328 write_encoded(fbin, &p, 1);
329 } /* if */
330 return opcodes(1) + opargs(1);
331}
332
333static cell
334do_file(FILE * fbin, char *params, cell opcode)
335{
336 ucell p, clen;
337 int len;
338
339 p = hex2long(params, &params);
340
341 /* remove leading and trailing white space from the filename */
342 while (isspace(*params))
343 params++;
344 len = strlen(params);
345 while (len > 0 && isspace(params[len - 1]))
346 len--;
347 params[len++] = '\0'; /* zero-terminate */
348 while (len % sizeof(cell) != 0)
349 params[len++] = '\0'; /* pad with zeros up to full cell */
350 assert(len > 0 && len < 256);
351 clen = len + sizeof(cell); /* add size of file ordinal */
352
353 if (fbin)
354 {
355 write_encoded(fbin, (ucell *) & opcode, 1);
356 write_encoded(fbin, &clen, 1);
357 write_encoded(fbin, &p, 1);
358 write_encoded(fbin, (ucell *) params, len / sizeof(cell));
359 } /* if */
360 return opcodes(1) + opargs(1) + clen; /* other argument is in clen */
361}
362
363static cell
364do_symbol(FILE * fbin, char *params, cell opcode)
365{
366 char *endptr;
367 ucell offset, clen, flags;
368 int len;
369 unsigned char mclass, type;
370
371 for (endptr = params; !isspace(*endptr) && endptr != '\0'; endptr++)
372 /* nothing */ ;
373 assert(*endptr == ' ');
374
375 len = (int)(endptr - params);
376 assert(len > 0 && len < sNAMEMAX);
377 /* first get the other parameters from the line */
378 offset = hex2long(endptr, &endptr);
379 mclass = (unsigned char)hex2long(endptr, &endptr);
380 type = (unsigned char)hex2long(endptr, NULL);
381 flags = type + 256 * mclass;
382 /* now finish up the name (overwriting the input line) */
383 params[len++] = '\0'; /* zero-terminate */
384 while (len % sizeof(cell) != 0)
385 params[len++] = '\0'; /* pad with zeros up to full cell */
386 clen = len + 2 * sizeof(cell); /* add size of symbol address and flags */
387
388 if (fbin)
389 {
390 write_encoded(fbin, (ucell *) & opcode, 1);
391 write_encoded(fbin, &clen, 1);
392 write_encoded(fbin, &offset, 1);
393 write_encoded(fbin, &flags, 1);
394 write_encoded(fbin, (ucell *) params, len / sizeof(cell));
395 } /* if */
396
397#if !defined NDEBUG
398 /* function should start right after the symbolic information */
399 if (!fbin && mclass == 0 && type == iFUNCTN)
400 assert(offset == codeindex + opcodes(1) + opargs(1) + clen);
401#endif
402
403 return opcodes(1) + opargs(1) + clen; /* other 2 arguments are in clen */
404}
405
406static cell
407do_switch(FILE * fbin, char *params, cell opcode)
408{
409 int i;
410 ucell p;
411
412 i = (int)hex2long(params, NULL);
413 assert(i >= 0 && i < labnum);
414
415 if (fbin)
416 {
417 assert(lbltab != NULL);
418 p = lbltab[i];
419 write_encoded(fbin, (ucell *) & opcode, 1);
420 write_encoded(fbin, &p, 1);
421 } /* if */
422 return opcodes(1) + opargs(1);
423}
424
425#if defined __BORLANDC__ || defined __WATCOMC__
426#pragma argsused
427#endif
428
429static cell
430do_case(FILE * fbin, char *params, cell opcode __UNUSED__)
431{
432 int i;
433 ucell p, v;
434
435 v = hex2long(params, &params);
436 i = (int)hex2long(params, NULL);
437 assert(i >= 0 && i < labnum);
438
439 if (fbin)
440 {
441 assert(lbltab != NULL);
442 p = lbltab[i];
443 write_encoded(fbin, &v, 1);
444 write_encoded(fbin, &p, 1);
445 } /* if */
446 return opcodes(0) + opargs(2);
447}
448
449#if defined __BORLANDC__ || defined __WATCOMC__
450#pragma argsused
451#endif
452
453static cell
454curfile(FILE * fbin __UNUSED__, char *params, cell opcode __UNUSED__)
455{
456 fcurrent = (int)hex2long(params, NULL);
457 return 0;
458}
459
460static OPCODE opcodelist[] = {
461 /* node for "invalid instruction" */
462 {0, NULL, 0, noop},
463 /* opcodes in sorted order */
464 {78, "add", sIN_CSEG, parm0},
465 {87, "add.c", sIN_CSEG, parm1},
466 {14, "addr.alt", sIN_CSEG, parm1},
467 {13, "addr.pri", sIN_CSEG, parm1},
468 {30, "align.alt", sIN_CSEG, parm1},
469 {29, "align.pri", sIN_CSEG, parm1},
470 {81, "and", sIN_CSEG, parm0},
471 {121, "bounds", sIN_CSEG, parm1},
472 {49, "call", sIN_CSEG, do_call},
473 {50, "call.pri", sIN_CSEG, parm0},
474 {0, "case", sIN_CSEG, do_case},
475 {130, "casetbl", sIN_CSEG, parm0}, /* version 1 */
476 {118, "cmps", sIN_CSEG, parm1},
477 {0, "code", 0, noop},
478 {12, "const.alt", sIN_CSEG, parm1},
479 {11, "const.pri", sIN_CSEG, parm1},
480 {0, "curfile", sIN_CSEG, curfile},
481 {0, "data", 0, noop},
482 {114, "dec", sIN_CSEG, parm1},
483 {113, "dec.alt", sIN_CSEG, parm0},
484 {116, "dec.i", sIN_CSEG, parm0},
485 {112, "dec.pri", sIN_CSEG, parm0},
486 {115, "dec.s", sIN_CSEG, parm1},
487 {0, "dump", sIN_DSEG, do_dump},
488 {95, "eq", sIN_CSEG, parm0},
489 {106, "eq.c.alt", sIN_CSEG, parm1},
490 {105, "eq.c.pri", sIN_CSEG, parm1},
491 {124, "file", sIN_CSEG, do_file},
492 {119, "fill", sIN_CSEG, parm1},
493 {100, "geq", sIN_CSEG, parm0},
494 {99, "grtr", sIN_CSEG, parm0},
495 {120, "halt", sIN_CSEG, parm1},
496 {45, "heap", sIN_CSEG, parm1},
497 {27, "idxaddr", sIN_CSEG, parm0},
498 {28, "idxaddr.b", sIN_CSEG, parm1},
499 {109, "inc", sIN_CSEG, parm1},
500 {108, "inc.alt", sIN_CSEG, parm0},
501 {111, "inc.i", sIN_CSEG, parm0},
502 {107, "inc.pri", sIN_CSEG, parm0},
503 {110, "inc.s", sIN_CSEG, parm1},
504 {86, "invert", sIN_CSEG, parm0},
505 {55, "jeq", sIN_CSEG, do_jump},
506 {60, "jgeq", sIN_CSEG, do_jump},
507 {59, "jgrtr", sIN_CSEG, do_jump},
508 {58, "jleq", sIN_CSEG, do_jump},
509 {57, "jless", sIN_CSEG, do_jump},
510 {56, "jneq", sIN_CSEG, do_jump},
511 {54, "jnz", sIN_CSEG, do_jump},
512 {52, "jrel", sIN_CSEG, parm1}, /* always a number */
513 {64, "jsgeq", sIN_CSEG, do_jump},
514 {63, "jsgrtr", sIN_CSEG, do_jump},
515 {62, "jsleq", sIN_CSEG, do_jump},
516 {61, "jsless", sIN_CSEG, do_jump},
517 {51, "jump", sIN_CSEG, do_jump},
518 {128, "jump.pri", sIN_CSEG, parm0}, /* version 1 */
519 {53, "jzer", sIN_CSEG, do_jump},
520 {31, "lctrl", sIN_CSEG, parm1},
521 {98, "leq", sIN_CSEG, parm0},
522 {97, "less", sIN_CSEG, parm0},
523 {25, "lidx", sIN_CSEG, parm0},
524 {26, "lidx.b", sIN_CSEG, parm1},
525 {125, "line", sIN_CSEG, parm2},
526 {2, "load.alt", sIN_CSEG, parm1},
527 {9, "load.i", sIN_CSEG, parm0},
528 {1, "load.pri", sIN_CSEG, parm1},
529 {4, "load.s.alt", sIN_CSEG, parm1},
530 {3, "load.s.pri", sIN_CSEG, parm1},
531 {10, "lodb.i", sIN_CSEG, parm1},
532 {6, "lref.alt", sIN_CSEG, parm1},
533 {5, "lref.pri", sIN_CSEG, parm1},
534 {8, "lref.s.alt", sIN_CSEG, parm1},
535 {7, "lref.s.pri", sIN_CSEG, parm1},
536 {34, "move.alt", sIN_CSEG, parm0},
537 {33, "move.pri", sIN_CSEG, parm0},
538 {117, "movs", sIN_CSEG, parm1},
539 {85, "neg", sIN_CSEG, parm0},
540 {96, "neq", sIN_CSEG, parm0},
541 {134, "nop", sIN_CSEG, parm0}, /* version 6 */
542 {84, "not", sIN_CSEG, parm0},
543 {82, "or", sIN_CSEG, parm0},
544 {43, "pop.alt", sIN_CSEG, parm0},
545 {42, "pop.pri", sIN_CSEG, parm0},
546 {46, "proc", sIN_CSEG, parm0},
547 {40, "push", sIN_CSEG, parm1},
548 {37, "push.alt", sIN_CSEG, parm0},
549 {39, "push.c", sIN_CSEG, parm1},
550 {36, "push.pri", sIN_CSEG, parm0},
551 {38, "push.r", sIN_CSEG, parm1},
552 {41, "push.s", sIN_CSEG, parm1},
553 {133, "pushaddr", sIN_CSEG, parm1}, /* version 4 */
554 {47, "ret", sIN_CSEG, parm0},
555 {48, "retn", sIN_CSEG, parm0},
556 {32, "sctrl", sIN_CSEG, parm1},
557 {73, "sdiv", sIN_CSEG, parm0},
558 {74, "sdiv.alt", sIN_CSEG, parm0},
559 {104, "sgeq", sIN_CSEG, parm0},
560 {103, "sgrtr", sIN_CSEG, parm0},
561 {65, "shl", sIN_CSEG, parm0},
562 {69, "shl.c.alt", sIN_CSEG, parm1},
563 {68, "shl.c.pri", sIN_CSEG, parm1},
564 {66, "shr", sIN_CSEG, parm0},
565 {71, "shr.c.alt", sIN_CSEG, parm1},
566 {70, "shr.c.pri", sIN_CSEG, parm1},
567 {94, "sign.alt", sIN_CSEG, parm0},
568 {93, "sign.pri", sIN_CSEG, parm0},
569 {102, "sleq", sIN_CSEG, parm0},
570 {101, "sless", sIN_CSEG, parm0},
571 {72, "smul", sIN_CSEG, parm0},
572 {88, "smul.c", sIN_CSEG, parm1},
573 {127, "srange", sIN_CSEG, parm2}, /* version 1 */
574 {20, "sref.alt", sIN_CSEG, parm1},
575 {19, "sref.pri", sIN_CSEG, parm1},
576 {22, "sref.s.alt", sIN_CSEG, parm1},
577 {21, "sref.s.pri", sIN_CSEG, parm1},
578 {67, "sshr", sIN_CSEG, parm0},
579 {44, "stack", sIN_CSEG, parm1},
580 {0, "stksize", 0, noop},
581 {16, "stor.alt", sIN_CSEG, parm1},
582 {23, "stor.i", sIN_CSEG, parm0},
583 {15, "stor.pri", sIN_CSEG, parm1},
584 {18, "stor.s.alt", sIN_CSEG, parm1},
585 {17, "stor.s.pri", sIN_CSEG, parm1},
586 {24, "strb.i", sIN_CSEG, parm1},
587 {79, "sub", sIN_CSEG, parm0},
588 {80, "sub.alt", sIN_CSEG, parm0},
589 {132, "swap.alt", sIN_CSEG, parm0}, /* version 4 */
590 {131, "swap.pri", sIN_CSEG, parm0}, /* version 4 */
591 {129, "switch", sIN_CSEG, do_switch}, /* version 1 */
592 {126, "symbol", sIN_CSEG, do_symbol},
593 {136, "symtag", sIN_CSEG, parm1}, /* version 7 */
594 {123, "sysreq.c", sIN_CSEG, parm1},
595 {135, "sysreq.d", sIN_CSEG, parm1}, /* version 7, not generated directly */
596 {122, "sysreq.pri", sIN_CSEG, parm0},
597 {76, "udiv", sIN_CSEG, parm0},
598 {77, "udiv.alt", sIN_CSEG, parm0},
599 {75, "umul", sIN_CSEG, parm0},
600 {35, "xchg", sIN_CSEG, parm0},
601 {83, "xor", sIN_CSEG, parm0},
602 {91, "zero", sIN_CSEG, parm1},
603 {90, "zero.alt", sIN_CSEG, parm0},
604 {89, "zero.pri", sIN_CSEG, parm0},
605 {92, "zero.s", sIN_CSEG, parm1},
606};
607
608#define MAX_INSTR_LEN 30
609static int
610findopcode(char *instr, int maxlen)
611{
612 int low, high, mid, cmp;
613 char str[MAX_INSTR_LEN];
614
615 if (maxlen >= MAX_INSTR_LEN)
616 return 0;
617 strncpy(str, instr, maxlen);
618 str[maxlen] = '\0'; /* make sure the string is zero terminated */
619 /* look up the instruction with a binary search
620 * the assembler is case insensitive to instructions (but case sensitive
621 * to symbols)
622 */
623 low = 1; /* entry 0 is reserved (for "not found") */
624 high = (sizeof opcodelist / sizeof opcodelist[0]) - 1;
625 while (low < high)
626 {
627 mid = (low + high) / 2;
628 assert(opcodelist[mid].name != NULL);
629 cmp = strcasecmp(str, opcodelist[mid].name);
630 if (cmp > 0)
631 low = mid + 1;
632 else
633 high = mid;
634 } /* while */
635
636 assert(low == high);
637 if (strcasecmp(str, opcodelist[low].name) == 0)
638 return low; /* found */
639 return 0; /* not found, return special index */
640}
641
642void
643assemble(FILE * fout, FILE * fin)
644{
645 typedef struct tagFUNCSTUB
646 {
647 unsigned int address, nameofs;
648 } FUNCSTUB;
649 AMX_HEADER hdr;
650 FUNCSTUB func;
651 int numpublics, numnatives, numlibraries, numpubvars,
652 numtags, padding;
653 long nametablesize, nameofs;
654 char line[256], *instr, *params;
655 int i, pass;
656 short count;
657 symbol *sym, **nativelist;
658 constvalue *constptr;
659 cell mainaddr;
660 int nametable, tags, libraries, publics, natives, pubvars;
661 int cod, defsize;
662
663#if !defined NDEBUG
664 /* verify that the opcode list is sorted (skip entry 1; it is reserved
665 * for a non-existent opcode)
666 */
667 assert(opcodelist[1].name != NULL);
668 for (i = 2; i < (int)(sizeof(opcodelist) / sizeof(opcodelist[0])); i++)
669 {
670 assert(opcodelist[i].name != NULL);
671 assert(strcasecmp(opcodelist[i].name, opcodelist[i - 1].name) > 0);
672 } /* for */
673#endif
674
675 writeerror = FALSE;
676 nametablesize = sizeof(short);
677 numpublics = 0;
678 numnatives = 0;
679 numpubvars = 0;
680 mainaddr = -1;
681 /* count number of public and native functions and public variables */
682 for (sym = glbtab.next; sym; sym = sym->next)
683 {
684 char alias[sNAMEMAX + 1] = "";
685 int match = 0;
686
687 if (sym->ident == iFUNCTN)
688 {
689 assert(strlen(sym->name) <= sNAMEMAX);
690 if ((sym->usage & uNATIVE) != 0 && (sym->usage & uREAD) != 0
691 && sym->addr >= 0)
692 {
693 match = ++numnatives;
694 if (!lookup_alias(alias, sym->name))
695 strcpy(alias, sym->name);
696 } /* if */
697 if ((sym->usage & uPUBLIC) != 0 && (sym->usage & uDEFINE) != 0)
698 {
699 match = ++numpublics;
700 strcpy(alias, sym->name);
701 } /* if */
702 if (strcmp(sym->name, uMAINFUNC) == 0)
703 {
704 assert(sym->vclass == sGLOBAL);
705 mainaddr = sym->addr;
706 } /* if */
707 }
708 else if (sym->ident == iVARIABLE)
709 {
710 if ((sym->usage & uPUBLIC) != 0)
711 {
712 match = ++numpubvars;
713 strcpy(alias, sym->name);
714 } /* if */
715 } /* if */
716 if (match)
717 {
718 assert(alias[0] != '\0');
719 nametablesize += strlen(alias) + 1;
720 } /* if */
721 } /* for */
722 assert(numnatives == ntv_funcid);
723
724 /* count number of libraries */
725 numlibraries = 0;
726 for (constptr = libname_tab.next; constptr;
727 constptr = constptr->next)
728 {
729 if (constptr->value > 0)
730 {
731 assert(constptr->name[0] != '\0');
732 numlibraries++;
733 nametablesize += strlen(constptr->name) + 1;
734 } /* if */
735 } /* for */
736
737 /* count number of public tags */
738 numtags = 0;
739 for (constptr = tagname_tab.next; constptr;
740 constptr = constptr->next)
741 {
742 if ((constptr->value & PUBLICTAG) != 0)
743 {
744 assert(constptr->name[0] != '\0');
745 numtags++;
746 nametablesize += strlen(constptr->name) + 1;
747 } /* if */
748 } /* for */
749
750 /* pad the header to sc_dataalign
751 * => thereby the code segment is aligned
752 * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned
753 * => and thereby the stack top is aligned too
754 */
755 assert(sc_dataalign != 0);
756 padding = sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign;
757 if (padding == sc_dataalign)
758 padding = 0;
759
760 /* write the abstract machine header */
761 memset(&hdr, 0, sizeof hdr);
762 hdr.magic = (unsigned short)0xF1E0;
763 hdr.file_version = CUR_FILE_VERSION;
764 hdr.amx_version = MIN_AMX_VERSION;
765 hdr.flags = (short)(sc_debug & sSYMBOLIC);
766 if (charbits == 16)
767 hdr.flags |= AMX_FLAG_CHAR16;
768 if (sc_compress)
769 hdr.flags |= AMX_FLAG_COMPACT;
770 if (sc_debug == 0)
771 hdr.flags |= AMX_FLAG_NOCHECKS;
772// #ifdef WORDS_BIGENDIAN
773// hdr.flags|=AMX_FLAG_BIGENDIAN;
774// #endif
775 defsize = hdr.defsize = sizeof(FUNCSTUB);
776 assert((hdr.defsize % sizeof(cell)) == 0);
777 publics = hdr.publics = sizeof hdr; /* public table starts right after the header */
778 natives = hdr.natives = hdr.publics + numpublics * sizeof(FUNCSTUB);
779 libraries = hdr.libraries = hdr.natives + numnatives * sizeof(FUNCSTUB);
780 pubvars = hdr.pubvars = hdr.libraries + numlibraries * sizeof(FUNCSTUB);
781 tags = hdr.tags = hdr.pubvars + numpubvars * sizeof(FUNCSTUB);
782 nametable = hdr.nametable = hdr.tags + numtags * sizeof(FUNCSTUB);
783 cod = hdr.cod = hdr.nametable + nametablesize + padding;
784 hdr.dat = hdr.cod + code_idx;
785 hdr.hea = hdr.dat + glb_declared * sizeof(cell);
786 hdr.stp = hdr.hea + sc_stksize * sizeof(cell);
787 hdr.cip = mainaddr;
788 hdr.size = hdr.hea; /* preset, this is incorrect in case of compressed output */
789#ifdef WORDS_BIGENDIAN
790 align32(&hdr.size);
791 align16(&hdr.magic);
792 align16(&hdr.flags);
793 align16(&hdr.defsize);
794 align32(&hdr.cod);
795 align32(&hdr.dat);
796 align32(&hdr.hea);
797 align32(&hdr.stp);
798 align32(&hdr.cip);
799 align32(&hdr.publics);
800 align32(&hdr.natives);
801 align32(&hdr.libraries);
802 align32(&hdr.pubvars);
803 align32(&hdr.tags);
804 align32(&hdr.nametable);
805#endif
806 sc_writebin(fout, &hdr, sizeof hdr);
807
808 /* dump zeros up to the rest of the header, so that we can easily "seek" */
809 for (nameofs = sizeof hdr; nameofs < cod; nameofs++)
810 putc(0, fout);
811 nameofs = nametable + sizeof(short);
812
813 /* write the public functions table */
814 count = 0;
815 for (sym = glbtab.next; sym; sym = sym->next)
816 {
817 if (sym->ident == iFUNCTN
818 && (sym->usage & uPUBLIC) != 0 && (sym->usage & uDEFINE) != 0)
819 {
820 assert(sym->vclass == sGLOBAL);
821 func.address = sym->addr;
822 func.nameofs = nameofs;
823#ifdef WORDS_BIGENDIAN
824 align32(&func.address);
825 align32(&func.nameofs);
826#endif
827 fseek(fout, publics + count * sizeof(FUNCSTUB), SEEK_SET);
828 sc_writebin(fout, &func, sizeof func);
829 fseek(fout, nameofs, SEEK_SET);
830 sc_writebin(fout, sym->name, strlen(sym->name) + 1);
831 nameofs += strlen(sym->name) + 1;
832 count++;
833 } /* if */
834 } /* for */
835
836 /* write the natives table */
837 /* The native functions must be written in sorted order. (They are
838 * sorted on their "id", not on their name). A nested loop to find
839 * each successive function would be an O(n^2) operation. But we
840 * do not really need to sort, because the native function id's
841 * are sequential and there are no duplicates. So we first walk
842 * through the complete symbol list and store a pointer to every
843 * native function of interest in a temporary table, where its id
844 * serves as the index in the table. Now we can walk the table and
845 * have all native functions in sorted order.
846 */
847 if (numnatives > 0)
848 {
849 nativelist = (symbol **) malloc(numnatives * sizeof(symbol *));
850 if (!nativelist)
851 error(103); /* insufficient memory */
852#if !defined NDEBUG
853 memset(nativelist, 0, numnatives * sizeof(symbol *)); /* for NULL checking */
854#endif
855 for (sym = glbtab.next; sym; sym = sym->next)
856 {
857 if (sym->ident == iFUNCTN && (sym->usage & uNATIVE) != 0
858 && (sym->usage & uREAD) != 0 && sym->addr >= 0)
859 {
860 assert(sym->addr < numnatives);
861 nativelist[(int)sym->addr] = sym;
862 } /* if */
863 } /* for */
864 count = 0;
865 for (i = 0; i < numnatives; i++)
866 {
867 char alias[sNAMEMAX + 1];
868
869 sym = nativelist[i];
870 assert(sym != NULL);
871 if (!lookup_alias(alias, sym->name))
872 {
873 assert(strlen(sym->name) <= sNAMEMAX);
874 strcpy(alias, sym->name);
875 } /* if */
876 assert(sym->vclass == sGLOBAL);
877 func.address = 0;
878 func.nameofs = nameofs;
879#ifdef WORDS_BIGENDIAN
880 align32(&func.address);
881 align32(&func.nameofs);
882#endif
883 fseek(fout, natives + count * sizeof(FUNCSTUB), SEEK_SET);
884 sc_writebin(fout, &func, sizeof func);
885 fseek(fout, nameofs, SEEK_SET);
886 sc_writebin(fout, alias, strlen(alias) + 1);
887 nameofs += strlen(alias) + 1;
888 count++;
889 } /* for */
890 free(nativelist);
891 } /* if */
892
893 /* write the libraries table */
894 count = 0;
895 for (constptr = libname_tab.next; constptr;
896 constptr = constptr->next)
897 {
898 if (constptr->value > 0)
899 {
900 assert(constptr->name[0] != '\0');
901 func.address = 0;
902 func.nameofs = nameofs;
903#ifdef WORDS_BIGENDIAN
904 align32(&func.address);
905 align32(&func.nameofs);
906#endif
907 fseek(fout, libraries + count * sizeof(FUNCSTUB), SEEK_SET);
908 sc_writebin(fout, &func, sizeof func);
909 fseek(fout, nameofs, SEEK_SET);
910 sc_writebin(fout, constptr->name, strlen(constptr->name) + 1);
911 nameofs += strlen(constptr->name) + 1;
912 count++;
913 } /* if */
914 } /* for */
915
916 /* write the public variables table */
917 count = 0;
918 for (sym = glbtab.next; sym; sym = sym->next)
919 {
920 if (sym->ident == iVARIABLE && (sym->usage & uPUBLIC) != 0)
921 {
922 assert((sym->usage & uDEFINE) != 0);
923 assert(sym->vclass == sGLOBAL);
924 func.address = sym->addr;
925 func.nameofs = nameofs;
926#ifdef WORDS_BIGENDIAN
927 align32(&func.address);
928 align32(&func.nameofs);
929#endif
930 fseek(fout, pubvars + count * sizeof(FUNCSTUB), SEEK_SET);
931 sc_writebin(fout, &func, sizeof func);
932 fseek(fout, nameofs, SEEK_SET);
933 sc_writebin(fout, sym->name, strlen(sym->name) + 1);
934 nameofs += strlen(sym->name) + 1;
935 count++;
936 } /* if */
937 } /* for */
938
939 /* write the public tagnames table */
940 count = 0;
941 for (constptr = tagname_tab.next; constptr;
942 constptr = constptr->next)
943 {
944 if ((constptr->value & PUBLICTAG) != 0)
945 {
946 assert(constptr->name[0] != '\0');
947 func.address = constptr->value & TAGMASK;
948 func.nameofs = nameofs;
949#ifdef WORDS_BIGENDIAN
950 align32(&func.address);
951 align32(&func.nameofs);
952#endif
953 fseek(fout, tags + count * sizeof(FUNCSTUB), SEEK_SET);
954 sc_writebin(fout, &func, sizeof func);
955 fseek(fout, nameofs, SEEK_SET);
956 sc_writebin(fout, constptr->name, strlen(constptr->name) + 1);
957 nameofs += strlen(constptr->name) + 1;
958 count++;
959 } /* if */
960 } /* for */
961
962 /* write the "maximum name length" field in the name table */
963 assert(nameofs == nametable + nametablesize);
964 fseek(fout, nametable, SEEK_SET);
965 count = sNAMEMAX;
966#ifdef WORDS_BIGENDIAN
967 align16(&count);
968#endif
969 sc_writebin(fout, &count, sizeof count);
970 fseek(fout, cod, SEEK_SET);
971
972 /* First pass: relocate all labels */
973 /* This pass is necessary because the code addresses of labels is only known
974 * after the peephole optimization flag. Labels can occur inside expressions
975 * (e.g. the conditional operator), which are optimized.
976 */
977 lbltab = NULL;
978 if (labnum > 0)
979 {
980 /* only very short programs have zero labels; no first pass is needed
981 * if there are no labels */
982 lbltab = (cell *) malloc(labnum * sizeof(cell));
983 if (!lbltab)
984 error(103); /* insufficient memory */
985 codeindex = 0;
986 sc_resetasm(fin);
987 while (sc_readasm(fin, line, sizeof line))
988 {
989 stripcomment(line);
990 instr = skipwhitespace(line);
991 /* ignore empty lines */
992 if (*instr == '\0')
993 continue;
994 if (tolower(*instr) == 'l' && *(instr + 1) == '.')
995 {
996 int lindex = (int)hex2long(instr + 2, NULL);
997
998 assert(lindex < labnum);
999 lbltab[lindex] = codeindex;
1000 }
1001 else
1002 {
1003 /* get to the end of the instruction (make use of the '\n' that fgets()
1004 * added at the end of the line; this way we will *always* drop on a
1005 * whitespace character) */
1006 for (params = instr; *params != '\0' && !isspace(*params);
1007 params++)
1008 /* nothing */ ;
1009 assert(params > instr);
1010 i = findopcode(instr, (int)(params - instr));
1011 if (!opcodelist[i].name)
1012 {
1013 *params = '\0';
1014 error(104, instr); /* invalid assembler instruction */
1015 } /* if */
1016 if (opcodelist[i].segment == sIN_CSEG)
1017 codeindex +=
1018 opcodelist[i].func(NULL, skipwhitespace(params),
1019 opcodelist[i].opcode);
1020 } /* if */
1021 } /* while */
1022 } /* if */
1023
1024 /* Second pass (actually 2 more passes, one for all code and one for all data) */
1025 bytes_in = 0;
1026 bytes_out = 0;
1027 for (pass = sIN_CSEG; pass <= sIN_DSEG; pass++)
1028 {
1029 sc_resetasm(fin);
1030 while (sc_readasm(fin, line, sizeof line))
1031 {
1032 stripcomment(line);
1033 instr = skipwhitespace(line);
1034 /* ignore empty lines and labels (labels have a special syntax, so these
1035 * must be parsed separately) */
1036 if (*instr == '\0' || (tolower(*instr) == 'l'
1037 && *(instr + 1) == '.'))
1038 continue;
1039 /* get to the end of the instruction (make use of the '\n' that fgets()
1040 * added at the end of the line; this way we will *always* drop on a
1041 * whitespace character) */
1042 for (params = instr; *params != '\0' && !isspace(*params);
1043 params++)
1044 /* nothing */ ;
1045 assert(params > instr);
1046 i = findopcode(instr, (int)(params - instr));
1047 assert(opcodelist[i].name != NULL);
1048 if (opcodelist[i].segment == pass)
1049 opcodelist[i].func(fout, skipwhitespace(params),
1050 opcodelist[i].opcode);
1051 } /* while */
1052 } /* for */
1053 if (bytes_out - bytes_in > 0)
1054 error(106); /* compression buffer overflow */
1055
1056 if (lbltab)
1057 {
1058 free(lbltab);
1059#if !defined NDEBUG
1060 lbltab = NULL;
1061#endif
1062 } /* if */
1063
1064 if (writeerror)
1065 error(101, "disk full");
1066
1067 /* adjust the header */
1068 if (sc_compress)
1069 {
1070 hdr.size = sc_lengthbin(fout);
1071#ifdef WORDS_BIGENDIAN
1072 align32(&hdr.size);
1073#endif
1074 sc_resetbin(fout); /* "size" is the very first field */
1075 sc_writebin(fout, &hdr.size, sizeof hdr.size);
1076 } /* if */
1077}