1 /* Small compiler - Binary code generation (the "assembler")
3 * Copyright (c) ITB CompuPhase, 1997-2003
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.
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:
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.
25 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
34 #include <stdlib.h> /* for macro max() */
37 #include "embryo_cc_osdefs.h"
38 #include "embryo_cc_sc.h"
40 typedef cell(*OPCODE_PROC) (FILE * fbin, char *params, cell opcode);
46 int segment; /* sIN_CSEG=parse in cseg, sIN_DSEG=parse in dseg */
50 static cell codeindex; /* similar to "code_idx" */
51 static cell *lbltab; /* label table */
52 static int writeerror;
53 static int bytes_in, bytes_out;
55 /* apparently, strtol() does not work correctly on very large (unsigned)
56 * hexadecimal values */
58 hex2long(char *s, char **n)
60 unsigned long result = 0L;
64 /* ignore leading whitespace */
65 while (*s == ' ' || *s == '\t')
68 /* allow a negation sign to create the two's complement of numbers */
75 assert((*s >= '0' && *s <= '9') || (*s >= 'a' && *s <= 'f')
76 || (*s >= 'a' && *s <= 'f'));
79 if (*s >= '0' && *s <= '9')
81 else if (*s >= 'a' && *s <= 'f')
82 digit = *s - 'a' + 10;
83 else if (*s >= 'A' && *s <= 'F')
84 digit = *s - 'A' + 10;
86 break; /* probably whitespace */
87 result = (result << 4) | digit;
93 result = (~result) + 1; /* take two's complement of the result */
94 return (ucell) result;
97 #ifdef WORDS_BIGENDIAN
101 unsigned char *s = (unsigned char *)v;
114 unsigned char *s = (unsigned char *)v;
117 /* swap outer two bytes */
121 /* swap inner two bytes */
128 #define aligncell(v) align16(v)
130 #define aligncell(v) align32(v)
133 #define align16(v) (v)
134 #define align32(v) (v)
135 #define aligncell(v) (v)
139 skipwhitespace(char *str)
141 while (isspace(*str))
147 stripcomment(char *str)
149 char *ptr = strchr(str, ';');
153 *ptr++ = '\n'; /* terminate the line, but leave the '\n' */
160 write_encoded(FILE * fbin, ucell * c, int num)
162 assert(sizeof(cell) <= 4); /* code must be adjusted for larger cells */
163 assert(fbin != NULL);
168 ucell p = (ucell) * c;
169 unsigned char t[5]; /* a 32-bit cell is encoded in max. 5 bytes (3 bytes for a 16-bit cell) */
173 for (index = 0; index < 5; index++)
175 t[index] = (unsigned char)(p & 0x7f); /* store 7 bits */
178 /* skip leading zeros */
179 while (index > 1 && t[index - 1] == 0
180 && (t[index - 2] & 0x40) == 0)
182 /* skip leading -1s *//* ??? for BIT16, check for index==3 && t[index-1]==0x03 */
183 if (index == 5 && t[index - 1] == 0x0f
184 && (t[index - 2] & 0x40) != 0)
186 while (index > 1 && t[index - 1] == 0x7f
187 && (t[index - 2] & 0x40) != 0)
189 /* write high byte first, write continuation bits */
194 (unsigned char)((index == 0) ? t[index]
195 : (t[index] | 0x80));
196 writeerror |= !sc_writebin(fbin, &code, 1);
199 bytes_in += sizeof *c;
200 assert(AMX_EXPANDMARGIN > 2);
201 if (bytes_out - bytes_in >= AMX_EXPANDMARGIN - 2)
202 error(106); /* compression buffer overflow */
206 assert((sc_lengthbin(fbin) % sizeof(cell)) == 0);
207 writeerror |= !sc_writebin(fbin, aligncell(c), sizeof *c);
213 #if defined __BORLANDC__ || defined __WATCOMC__
218 noop(FILE * fbin __UNUSED__, char *params __UNUSED__, cell opcode __UNUSED__)
223 #if defined __BORLANDC__ || defined __WATCOMC__
228 parm0(FILE * fbin, char *params __UNUSED__, cell opcode)
231 write_encoded(fbin, (ucell *) & opcode, 1);
236 parm1(FILE * fbin, char *params, cell opcode)
238 ucell p = hex2long(params, NULL);
242 write_encoded(fbin, (ucell *) & opcode, 1);
243 write_encoded(fbin, &p, 1);
245 return opcodes(1) + opargs(1);
249 parm2(FILE * fbin, char *params, cell opcode)
253 p[0] = hex2long(params, ¶ms);
254 p[1] = hex2long(params, NULL);
257 write_encoded(fbin, (ucell *) & opcode, 1);
258 write_encoded(fbin, p, 2);
260 return opcodes(1) + opargs(2);
263 #if defined __BORLANDC__ || defined __WATCOMC__
268 do_dump(FILE * fbin, char *params, cell opcode __UNUSED__)
273 while (*params != '\0')
275 p = hex2long(params, ¶ms);
277 write_encoded(fbin, &p, 1);
279 while (isspace(*params))
282 return num * sizeof(cell);
286 do_call(FILE * fbin, char *params, cell opcode)
288 char name[sNAMEMAX + 1];
293 for (i = 0; !isspace(*params); i++, params++)
295 assert(*params != '\0');
296 assert(i < sNAMEMAX);
301 /* look up the function address; note that the correct file number must
302 * already have been set (in order for static globals to be found).
306 assert(sym->ident == iFUNCTN || sym->ident == iREFFUNC);
307 assert(sym->vclass == sGLOBAL);
312 write_encoded(fbin, (ucell *) & opcode, 1);
313 write_encoded(fbin, &p, 1);
315 return opcodes(1) + opargs(1);
319 do_jump(FILE * fbin, char *params, cell opcode)
324 i = (int)hex2long(params, NULL);
325 assert(i >= 0 && i < labnum);
329 assert(lbltab != NULL);
331 write_encoded(fbin, (ucell *) & opcode, 1);
332 write_encoded(fbin, &p, 1);
334 return opcodes(1) + opargs(1);
338 do_file(FILE * fbin, char *params, cell opcode)
343 p = hex2long(params, ¶ms);
345 /* remove leading and trailing white space from the filename */
346 while (isspace(*params))
348 len = strlen(params);
349 while (len > 0 && isspace(params[len - 1]))
351 params[len++] = '\0'; /* zero-terminate */
352 while (len % sizeof(cell) != 0)
353 params[len++] = '\0'; /* pad with zeros up to full cell */
354 assert(len > 0 && len < 256);
355 clen = len + sizeof(cell); /* add size of file ordinal */
359 write_encoded(fbin, (ucell *) & opcode, 1);
360 write_encoded(fbin, &clen, 1);
361 write_encoded(fbin, &p, 1);
362 write_encoded(fbin, (ucell *) params, len / sizeof(cell));
364 return opcodes(1) + opargs(1) + clen; /* other argument is in clen */
368 do_symbol(FILE * fbin, char *params, cell opcode)
371 ucell offset, clen, flags;
373 unsigned char mclass, type;
375 for (endptr = params; !isspace(*endptr) && endptr != '\0'; endptr++)
377 assert(*endptr == ' ');
379 len = (int)(endptr - params);
380 assert(len > 0 && len < sNAMEMAX);
381 /* first get the other parameters from the line */
382 offset = hex2long(endptr, &endptr);
383 mclass = (unsigned char)hex2long(endptr, &endptr);
384 type = (unsigned char)hex2long(endptr, NULL);
385 flags = type + 256 * mclass;
386 /* now finish up the name (overwriting the input line) */
387 params[len++] = '\0'; /* zero-terminate */
388 while (len % sizeof(cell) != 0)
389 params[len++] = '\0'; /* pad with zeros up to full cell */
390 clen = len + 2 * sizeof(cell); /* add size of symbol address and flags */
394 write_encoded(fbin, (ucell *) & opcode, 1);
395 write_encoded(fbin, &clen, 1);
396 write_encoded(fbin, &offset, 1);
397 write_encoded(fbin, &flags, 1);
398 write_encoded(fbin, (ucell *) params, len / sizeof(cell));
402 /* function should start right after the symbolic information */
403 if (fbin == NULL && mclass == 0 && type == iFUNCTN)
404 assert(offset == codeindex + opcodes(1) + opargs(1) + clen);
407 return opcodes(1) + opargs(1) + clen; /* other 2 arguments are in clen */
411 do_switch(FILE * fbin, char *params, cell opcode)
416 i = (int)hex2long(params, NULL);
417 assert(i >= 0 && i < labnum);
421 assert(lbltab != NULL);
423 write_encoded(fbin, (ucell *) & opcode, 1);
424 write_encoded(fbin, &p, 1);
426 return opcodes(1) + opargs(1);
429 #if defined __BORLANDC__ || defined __WATCOMC__
434 do_case(FILE * fbin, char *params, cell opcode __UNUSED__)
439 v = hex2long(params, ¶ms);
440 i = (int)hex2long(params, NULL);
441 assert(i >= 0 && i < labnum);
445 assert(lbltab != NULL);
447 write_encoded(fbin, &v, 1);
448 write_encoded(fbin, &p, 1);
450 return opcodes(0) + opargs(2);
453 #if defined __BORLANDC__ || defined __WATCOMC__
458 curfile(FILE * fbin __UNUSED__, char *params, cell opcode __UNUSED__)
460 fcurrent = (int)hex2long(params, NULL);
464 static OPCODE opcodelist[] = {
465 /* node for "invalid instruction" */
467 /* opcodes in sorted order */
468 {78, "add", sIN_CSEG, parm0},
469 {87, "add.c", sIN_CSEG, parm1},
470 {14, "addr.alt", sIN_CSEG, parm1},
471 {13, "addr.pri", sIN_CSEG, parm1},
472 {30, "align.alt", sIN_CSEG, parm1},
473 {29, "align.pri", sIN_CSEG, parm1},
474 {81, "and", sIN_CSEG, parm0},
475 {121, "bounds", sIN_CSEG, parm1},
476 {49, "call", sIN_CSEG, do_call},
477 {50, "call.pri", sIN_CSEG, parm0},
478 {0, "case", sIN_CSEG, do_case},
479 {130, "casetbl", sIN_CSEG, parm0}, /* version 1 */
480 {118, "cmps", sIN_CSEG, parm1},
481 {0, "code", 0, noop},
482 {12, "const.alt", sIN_CSEG, parm1},
483 {11, "const.pri", sIN_CSEG, parm1},
484 {0, "curfile", sIN_CSEG, curfile},
485 {0, "data", 0, noop},
486 {114, "dec", sIN_CSEG, parm1},
487 {113, "dec.alt", sIN_CSEG, parm0},
488 {116, "dec.i", sIN_CSEG, parm0},
489 {112, "dec.pri", sIN_CSEG, parm0},
490 {115, "dec.s", sIN_CSEG, parm1},
491 {0, "dump", sIN_DSEG, do_dump},
492 {95, "eq", sIN_CSEG, parm0},
493 {106, "eq.c.alt", sIN_CSEG, parm1},
494 {105, "eq.c.pri", sIN_CSEG, parm1},
495 {124, "file", sIN_CSEG, do_file},
496 {119, "fill", sIN_CSEG, parm1},
497 {100, "geq", sIN_CSEG, parm0},
498 {99, "grtr", sIN_CSEG, parm0},
499 {120, "halt", sIN_CSEG, parm1},
500 {45, "heap", sIN_CSEG, parm1},
501 {27, "idxaddr", sIN_CSEG, parm0},
502 {28, "idxaddr.b", sIN_CSEG, parm1},
503 {109, "inc", sIN_CSEG, parm1},
504 {108, "inc.alt", sIN_CSEG, parm0},
505 {111, "inc.i", sIN_CSEG, parm0},
506 {107, "inc.pri", sIN_CSEG, parm0},
507 {110, "inc.s", sIN_CSEG, parm1},
508 {86, "invert", sIN_CSEG, parm0},
509 {55, "jeq", sIN_CSEG, do_jump},
510 {60, "jgeq", sIN_CSEG, do_jump},
511 {59, "jgrtr", sIN_CSEG, do_jump},
512 {58, "jleq", sIN_CSEG, do_jump},
513 {57, "jless", sIN_CSEG, do_jump},
514 {56, "jneq", sIN_CSEG, do_jump},
515 {54, "jnz", sIN_CSEG, do_jump},
516 {52, "jrel", sIN_CSEG, parm1}, /* always a number */
517 {64, "jsgeq", sIN_CSEG, do_jump},
518 {63, "jsgrtr", sIN_CSEG, do_jump},
519 {62, "jsleq", sIN_CSEG, do_jump},
520 {61, "jsless", sIN_CSEG, do_jump},
521 {51, "jump", sIN_CSEG, do_jump},
522 {128, "jump.pri", sIN_CSEG, parm0}, /* version 1 */
523 {53, "jzer", sIN_CSEG, do_jump},
524 {31, "lctrl", sIN_CSEG, parm1},
525 {98, "leq", sIN_CSEG, parm0},
526 {97, "less", sIN_CSEG, parm0},
527 {25, "lidx", sIN_CSEG, parm0},
528 {26, "lidx.b", sIN_CSEG, parm1},
529 {125, "line", sIN_CSEG, parm2},
530 {2, "load.alt", sIN_CSEG, parm1},
531 {9, "load.i", sIN_CSEG, parm0},
532 {1, "load.pri", sIN_CSEG, parm1},
533 {4, "load.s.alt", sIN_CSEG, parm1},
534 {3, "load.s.pri", sIN_CSEG, parm1},
535 {10, "lodb.i", sIN_CSEG, parm1},
536 {6, "lref.alt", sIN_CSEG, parm1},
537 {5, "lref.pri", sIN_CSEG, parm1},
538 {8, "lref.s.alt", sIN_CSEG, parm1},
539 {7, "lref.s.pri", sIN_CSEG, parm1},
540 {34, "move.alt", sIN_CSEG, parm0},
541 {33, "move.pri", sIN_CSEG, parm0},
542 {117, "movs", sIN_CSEG, parm1},
543 {85, "neg", sIN_CSEG, parm0},
544 {96, "neq", sIN_CSEG, parm0},
545 {134, "nop", sIN_CSEG, parm0}, /* version 6 */
546 {84, "not", sIN_CSEG, parm0},
547 {82, "or", sIN_CSEG, parm0},
548 {43, "pop.alt", sIN_CSEG, parm0},
549 {42, "pop.pri", sIN_CSEG, parm0},
550 {46, "proc", sIN_CSEG, parm0},
551 {40, "push", sIN_CSEG, parm1},
552 {37, "push.alt", sIN_CSEG, parm0},
553 {39, "push.c", sIN_CSEG, parm1},
554 {36, "push.pri", sIN_CSEG, parm0},
555 {38, "push.r", sIN_CSEG, parm1},
556 {41, "push.s", sIN_CSEG, parm1},
557 {133, "pushaddr", sIN_CSEG, parm1}, /* version 4 */
558 {47, "ret", sIN_CSEG, parm0},
559 {48, "retn", sIN_CSEG, parm0},
560 {32, "sctrl", sIN_CSEG, parm1},
561 {73, "sdiv", sIN_CSEG, parm0},
562 {74, "sdiv.alt", sIN_CSEG, parm0},
563 {104, "sgeq", sIN_CSEG, parm0},
564 {103, "sgrtr", sIN_CSEG, parm0},
565 {65, "shl", sIN_CSEG, parm0},
566 {69, "shl.c.alt", sIN_CSEG, parm1},
567 {68, "shl.c.pri", sIN_CSEG, parm1},
568 {66, "shr", sIN_CSEG, parm0},
569 {71, "shr.c.alt", sIN_CSEG, parm1},
570 {70, "shr.c.pri", sIN_CSEG, parm1},
571 {94, "sign.alt", sIN_CSEG, parm0},
572 {93, "sign.pri", sIN_CSEG, parm0},
573 {102, "sleq", sIN_CSEG, parm0},
574 {101, "sless", sIN_CSEG, parm0},
575 {72, "smul", sIN_CSEG, parm0},
576 {88, "smul.c", sIN_CSEG, parm1},
577 {127, "srange", sIN_CSEG, parm2}, /* version 1 */
578 {20, "sref.alt", sIN_CSEG, parm1},
579 {19, "sref.pri", sIN_CSEG, parm1},
580 {22, "sref.s.alt", sIN_CSEG, parm1},
581 {21, "sref.s.pri", sIN_CSEG, parm1},
582 {67, "sshr", sIN_CSEG, parm0},
583 {44, "stack", sIN_CSEG, parm1},
584 {0, "stksize", 0, noop},
585 {16, "stor.alt", sIN_CSEG, parm1},
586 {23, "stor.i", sIN_CSEG, parm0},
587 {15, "stor.pri", sIN_CSEG, parm1},
588 {18, "stor.s.alt", sIN_CSEG, parm1},
589 {17, "stor.s.pri", sIN_CSEG, parm1},
590 {24, "strb.i", sIN_CSEG, parm1},
591 {79, "sub", sIN_CSEG, parm0},
592 {80, "sub.alt", sIN_CSEG, parm0},
593 {132, "swap.alt", sIN_CSEG, parm0}, /* version 4 */
594 {131, "swap.pri", sIN_CSEG, parm0}, /* version 4 */
595 {129, "switch", sIN_CSEG, do_switch}, /* version 1 */
596 {126, "symbol", sIN_CSEG, do_symbol},
597 {136, "symtag", sIN_CSEG, parm1}, /* version 7 */
598 {123, "sysreq.c", sIN_CSEG, parm1},
599 {135, "sysreq.d", sIN_CSEG, parm1}, /* version 7, not generated directly */
600 {122, "sysreq.pri", sIN_CSEG, parm0},
601 {76, "udiv", sIN_CSEG, parm0},
602 {77, "udiv.alt", sIN_CSEG, parm0},
603 {75, "umul", sIN_CSEG, parm0},
604 {35, "xchg", sIN_CSEG, parm0},
605 {83, "xor", sIN_CSEG, parm0},
606 {91, "zero", sIN_CSEG, parm1},
607 {90, "zero.alt", sIN_CSEG, parm0},
608 {89, "zero.pri", sIN_CSEG, parm0},
609 {92, "zero.s", sIN_CSEG, parm1},
612 #define MAX_INSTR_LEN 30
614 findopcode(char *instr, int maxlen)
616 int low, high, mid, cmp;
617 char str[MAX_INSTR_LEN];
619 if (maxlen >= MAX_INSTR_LEN)
621 strncpy(str, instr, maxlen);
622 str[maxlen] = '\0'; /* make sure the string is zero terminated */
623 /* look up the instruction with a binary search
624 * the assembler is case insensitive to instructions (but case sensitive
627 low = 1; /* entry 0 is reserved (for "not found") */
628 high = (sizeof opcodelist / sizeof opcodelist[0]) - 1;
631 mid = (low + high) / 2;
632 assert(opcodelist[mid].name != NULL);
633 cmp = strcasecmp(str, opcodelist[mid].name);
641 if (strcasecmp(str, opcodelist[low].name) == 0)
642 return low; /* found */
643 return 0; /* not found, return special index */
647 assemble(FILE * fout, FILE * fin)
649 typedef struct tagFUNCSTUB
651 unsigned int address, nameofs;
655 int numpublics, numnatives, numlibraries, numpubvars,
657 long nametablesize, nameofs;
658 char line[256], *instr, *params;
661 symbol *sym, **nativelist;
662 constvalue *constptr;
664 int nametable, tags, libraries, publics, natives, pubvars;
665 int cod, dat, hea, stp, cip, size, defsize;
668 /* verify that the opcode list is sorted (skip entry 1; it is reserved
669 * for a non-existant opcode)
671 assert(opcodelist[1].name != NULL);
672 for (i = 2; i < (sizeof opcodelist / sizeof opcodelist[0]); i++)
674 assert(opcodelist[i].name != NULL);
675 assert(strcasecmp(opcodelist[i].name, opcodelist[i - 1].name) > 0);
680 nametablesize = sizeof(short);
685 /* count number of public and native functions and public variables */
686 for (sym = glbtab.next; sym != NULL; sym = sym->next)
688 char alias[sNAMEMAX + 1] = "";
691 if (sym->ident == iFUNCTN)
693 assert(strlen(sym->name) <= sNAMEMAX);
694 if ((sym->usage & uNATIVE) != 0 && (sym->usage & uREAD) != 0
697 match = ++numnatives;
698 if (!lookup_alias(alias, sym->name))
699 strcpy(alias, sym->name);
701 if ((sym->usage & uPUBLIC) != 0 && (sym->usage & uDEFINE) != 0)
703 match = ++numpublics;
704 strcpy(alias, sym->name);
706 if (strcmp(sym->name, uMAINFUNC) == 0)
708 assert(sym->vclass == sGLOBAL);
709 mainaddr = sym->addr;
712 else if (sym->ident == iVARIABLE)
714 if ((sym->usage & uPUBLIC) != 0)
716 match = ++numpubvars;
717 strcpy(alias, sym->name);
722 assert(alias[0] != '\0');
723 nametablesize += strlen(alias) + 1;
726 assert(numnatives == ntv_funcid);
728 /* count number of libraries */
730 for (constptr = libname_tab.next; constptr != NULL;
731 constptr = constptr->next)
733 if (constptr->value > 0)
735 assert(constptr->name[0] != '\0');
737 nametablesize += strlen(constptr->name) + 1;
741 /* count number of public tags */
743 for (constptr = tagname_tab.next; constptr != NULL;
744 constptr = constptr->next)
746 if ((constptr->value & PUBLICTAG) != 0)
748 assert(constptr->name[0] != '\0');
750 nametablesize += strlen(constptr->name) + 1;
754 /* pad the header to sc_dataalign
755 * => thereby the code segment is aligned
756 * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned
757 * => and thereby the stack top is aligned too
759 assert(sc_dataalign != 0);
760 padding = sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign;
761 if (padding == sc_dataalign)
764 /* write the abstract machine header */
765 memset(&hdr, 0, sizeof hdr);
766 hdr.magic = (unsigned short)0xF1E0;
767 hdr.file_version = CUR_FILE_VERSION;
768 hdr.amx_version = MIN_AMX_VERSION;
769 hdr.flags = (short)(sc_debug & sSYMBOLIC);
771 hdr.flags |= AMX_FLAG_CHAR16;
773 hdr.flags |= AMX_FLAG_COMPACT;
775 hdr.flags |= AMX_FLAG_NOCHECKS;
776 // #ifdef WORDS_BIGENDIAN
777 // hdr.flags|=AMX_FLAG_BIGENDIAN;
779 defsize = hdr.defsize = sizeof(FUNCSTUB);
780 assert((hdr.defsize % sizeof(cell)) == 0);
781 publics = hdr.publics = sizeof hdr; /* public table starts right after the header */
782 natives = hdr.natives = hdr.publics + numpublics * sizeof(FUNCSTUB);
783 libraries = hdr.libraries = hdr.natives + numnatives * sizeof(FUNCSTUB);
784 pubvars = hdr.pubvars = hdr.libraries + numlibraries * sizeof(FUNCSTUB);
785 tags = hdr.tags = hdr.pubvars + numpubvars * sizeof(FUNCSTUB);
786 nametable = hdr.nametable = hdr.tags + numtags * sizeof(FUNCSTUB);
787 cod = hdr.cod = hdr.nametable + nametablesize + padding;
788 dat = hdr.dat = hdr.cod + code_idx;
789 hea = hdr.hea = hdr.dat + glb_declared * sizeof(cell);
790 stp = hdr.stp = hdr.hea + sc_stksize * sizeof(cell);
791 cip = hdr.cip = mainaddr;
792 size = hdr.size = hdr.hea; /* preset, this is incorrect in case of compressed output */
793 #ifdef WORDS_BIGENDIAN
797 align16(&hdr.defsize);
803 align32(&hdr.publics);
804 align32(&hdr.natives);
805 align32(&hdr.libraries);
806 align32(&hdr.pubvars);
808 align32(&hdr.nametable);
810 sc_writebin(fout, &hdr, sizeof hdr);
812 /* dump zeros up to the rest of the header, so that we can easily "seek" */
813 for (nameofs = sizeof hdr; nameofs < cod; nameofs++)
815 nameofs = nametable + sizeof(short);
817 /* write the public functions table */
819 for (sym = glbtab.next; sym != NULL; sym = sym->next)
821 if (sym->ident == iFUNCTN
822 && (sym->usage & uPUBLIC) != 0 && (sym->usage & uDEFINE) != 0)
824 assert(sym->vclass == sGLOBAL);
825 func.address = sym->addr;
826 func.nameofs = nameofs;
827 #ifdef WORDS_BIGENDIAN
828 align32(&func.address);
829 align32(&func.nameofs);
831 fseek(fout, publics + count * sizeof(FUNCSTUB), SEEK_SET);
832 sc_writebin(fout, &func, sizeof func);
833 fseek(fout, nameofs, SEEK_SET);
834 sc_writebin(fout, sym->name, strlen(sym->name) + 1);
835 nameofs += strlen(sym->name) + 1;
840 /* write the natives table */
841 /* The native functions must be written in sorted order. (They are
842 * sorted on their "id", not on their name). A nested loop to find
843 * each successive function would be an O(n^2) operation. But we
844 * do not really need to sort, because the native function id's
845 * are sequential and there are no duplicates. So we first walk
846 * through the complete symbol list and store a pointer to every
847 * native function of interest in a temporary table, where its id
848 * serves as the index in the table. Now we can walk the table and
849 * have all native functions in sorted order.
853 nativelist = (symbol **) malloc(numnatives * sizeof(symbol *));
854 if (nativelist == NULL)
855 error(103); /* insufficient memory */
857 memset(nativelist, 0, numnatives * sizeof(symbol *)); /* for NULL checking */
859 for (sym = glbtab.next; sym != NULL; sym = sym->next)
861 if (sym->ident == iFUNCTN && (sym->usage & uNATIVE) != 0
862 && (sym->usage & uREAD) != 0 && sym->addr >= 0)
864 assert(sym->addr < numnatives);
865 nativelist[(int)sym->addr] = sym;
869 for (i = 0; i < numnatives; i++)
871 char alias[sNAMEMAX + 1];
875 if (!lookup_alias(alias, sym->name))
877 assert(strlen(sym->name) <= sNAMEMAX);
878 strcpy(alias, sym->name);
880 assert(sym->vclass == sGLOBAL);
882 func.nameofs = nameofs;
883 #ifdef WORDS_BIGENDIAN
884 align32(&func.address);
885 align32(&func.nameofs);
887 fseek(fout, natives + count * sizeof(FUNCSTUB), SEEK_SET);
888 sc_writebin(fout, &func, sizeof func);
889 fseek(fout, nameofs, SEEK_SET);
890 sc_writebin(fout, alias, strlen(alias) + 1);
891 nameofs += strlen(alias) + 1;
897 /* write the libraries table */
899 for (constptr = libname_tab.next; constptr != NULL;
900 constptr = constptr->next)
902 if (constptr->value > 0)
904 assert(constptr->name[0] != '\0');
906 func.nameofs = nameofs;
907 #ifdef WORDS_BIGENDIAN
908 align32(&func.address);
909 align32(&func.nameofs);
911 fseek(fout, libraries + count * sizeof(FUNCSTUB), SEEK_SET);
912 sc_writebin(fout, &func, sizeof func);
913 fseek(fout, nameofs, SEEK_SET);
914 sc_writebin(fout, constptr->name, strlen(constptr->name) + 1);
915 nameofs += strlen(constptr->name) + 1;
920 /* write the public variables table */
922 for (sym = glbtab.next; sym != NULL; sym = sym->next)
924 if (sym->ident == iVARIABLE && (sym->usage & uPUBLIC) != 0)
926 assert((sym->usage & uDEFINE) != 0);
927 assert(sym->vclass == sGLOBAL);
928 func.address = sym->addr;
929 func.nameofs = nameofs;
930 #ifdef WORDS_BIGENDIAN
931 align32(&func.address);
932 align32(&func.nameofs);
934 fseek(fout, pubvars + count * sizeof(FUNCSTUB), SEEK_SET);
935 sc_writebin(fout, &func, sizeof func);
936 fseek(fout, nameofs, SEEK_SET);
937 sc_writebin(fout, sym->name, strlen(sym->name) + 1);
938 nameofs += strlen(sym->name) + 1;
943 /* write the public tagnames table */
945 for (constptr = tagname_tab.next; constptr != NULL;
946 constptr = constptr->next)
948 if ((constptr->value & PUBLICTAG) != 0)
950 assert(constptr->name[0] != '\0');
951 func.address = constptr->value & TAGMASK;
952 func.nameofs = nameofs;
953 #ifdef WORDS_BIGENDIAN
954 align32(&func.address);
955 align32(&func.nameofs);
957 fseek(fout, tags + count * sizeof(FUNCSTUB), SEEK_SET);
958 sc_writebin(fout, &func, sizeof func);
959 fseek(fout, nameofs, SEEK_SET);
960 sc_writebin(fout, constptr->name, strlen(constptr->name) + 1);
961 nameofs += strlen(constptr->name) + 1;
966 /* write the "maximum name length" field in the name table */
967 assert(nameofs == nametable + nametablesize);
968 fseek(fout, nametable, SEEK_SET);
970 #ifdef WORDS_BIGENDIAN
973 sc_writebin(fout, &count, sizeof count);
974 fseek(fout, cod, SEEK_SET);
976 /* First pass: relocate all labels */
977 /* This pass is necessary because the code addresses of labels is only known
978 * after the peephole optimization flag. Labels can occur inside expressions
979 * (e.g. the conditional operator), which are optimized.
984 /* only very short programs have zero labels; no first pass is needed
985 * if there are no labels */
986 lbltab = (cell *) malloc(labnum * sizeof(cell));
988 error(103); /* insufficient memory */
991 while (sc_readasm(fin, line, sizeof line) != NULL)
994 instr = skipwhitespace(line);
995 /* ignore empty lines */
998 if (tolower(*instr) == 'l' && *(instr + 1) == '.')
1000 int lindex = (int)hex2long(instr + 2, NULL);
1002 assert(lindex < labnum);
1003 lbltab[lindex] = codeindex;
1007 /* get to the end of the instruction (make use of the '\n' that fgets()
1008 * added at the end of the line; this way we will *always* drop on a
1009 * whitespace character) */
1010 for (params = instr; *params != '\0' && !isspace(*params);
1013 assert(params > instr);
1014 i = findopcode(instr, (int)(params - instr));
1015 if (opcodelist[i].name == NULL)
1018 error(104, instr); /* invalid assembler instruction */
1020 if (opcodelist[i].segment == sIN_CSEG)
1022 opcodelist[i].func(NULL, skipwhitespace(params),
1023 opcodelist[i].opcode);
1028 /* Second pass (actually 2 more passes, one for all code and one for all data) */
1031 for (pass = sIN_CSEG; pass <= sIN_DSEG; pass++)
1034 while (sc_readasm(fin, line, sizeof line) != NULL)
1037 instr = skipwhitespace(line);
1038 /* ignore empty lines and labels (labels have a special syntax, so these
1039 * must be parsed separately) */
1040 if (*instr == '\0' || (tolower(*instr) == 'l'
1041 && *(instr + 1) == '.'))
1043 /* get to the end of the instruction (make use of the '\n' that fgets()
1044 * added at the end of the line; this way we will *always* drop on a
1045 * whitespace character) */
1046 for (params = instr; *params != '\0' && !isspace(*params);
1049 assert(params > instr);
1050 i = findopcode(instr, (int)(params - instr));
1051 assert(opcodelist[i].name != NULL);
1052 if (opcodelist[i].segment == pass)
1053 opcodelist[i].func(fout, skipwhitespace(params),
1054 opcodelist[i].opcode);
1057 if (bytes_out - bytes_in > 0)
1058 error(106); /* compression buffer overflow */
1069 error(101, "disk full");
1071 /* adjust the header */
1074 hdr.size = sc_lengthbin(fout);
1075 #ifdef WORDS_BIGENDIAN
1078 sc_resetbin(fout); /* "size" is the very first field */
1079 sc_writebin(fout, &hdr.size, sizeof hdr.size);