diff options
Diffstat (limited to 'libraries/embryo/src/bin/embryo_cc_sc6.c')
-rw-r--r-- | libraries/embryo/src/bin/embryo_cc_sc6.c | 1077 |
1 files changed, 0 insertions, 1077 deletions
diff --git a/libraries/embryo/src/bin/embryo_cc_sc6.c b/libraries/embryo/src/bin/embryo_cc_sc6.c deleted file mode 100644 index 7ec6098..0000000 --- a/libraries/embryo/src/bin/embryo_cc_sc6.c +++ /dev/null | |||
@@ -1,1077 +0,0 @@ | |||
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 | |||
36 | typedef cell(*OPCODE_PROC) (FILE * fbin, char *params, cell opcode); | ||
37 | |||
38 | typedef 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 | |||
46 | static cell codeindex; /* similar to "code_idx" */ | ||
47 | static cell *lbltab; /* label table */ | ||
48 | static int writeerror; | ||
49 | static int bytes_in, bytes_out; | ||
50 | |||
51 | /* apparently, strtol() does not work correctly on very large (unsigned) | ||
52 | * hexadecimal values */ | ||
53 | static ucell | ||
54 | hex2long(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 | ||
94 | static short * | ||
95 | align16(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 | |||
107 | static long * | ||
108 | align32(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 | |||
134 | static char * | ||
135 | skipwhitespace(char *str) | ||
136 | { | ||
137 | while (isspace(*str)) | ||
138 | str++; | ||
139 | return str; | ||
140 | } | ||
141 | |||
142 | static char * | ||
143 | stripcomment(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 | |||
155 | static void | ||
156 | write_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 | |||
213 | static cell | ||
214 | noop(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 | |||
223 | static cell | ||
224 | parm0(FILE * fbin, char *params __UNUSED__, cell opcode) | ||
225 | { | ||
226 | if (fbin) | ||
227 | write_encoded(fbin, (ucell *) & opcode, 1); | ||
228 | return opcodes(1); | ||
229 | } | ||
230 | |||
231 | static cell | ||
232 | parm1(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 | |||
244 | static cell | ||
245 | parm2(FILE * fbin, char *params, cell opcode) | ||
246 | { | ||
247 | ucell p[2]; | ||
248 | |||
249 | p[0] = hex2long(params, ¶ms); | ||
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 | |||
263 | static cell | ||
264 | do_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, ¶ms); | ||
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 | |||
281 | static cell | ||
282 | do_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 | |||
314 | static cell | ||
315 | do_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 | |||
333 | static cell | ||
334 | do_file(FILE * fbin, char *params, cell opcode) | ||
335 | { | ||
336 | ucell p, clen; | ||
337 | int len; | ||
338 | |||
339 | p = hex2long(params, ¶ms); | ||
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 | |||
363 | static cell | ||
364 | do_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 | |||
406 | static cell | ||
407 | do_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 | |||
429 | static cell | ||
430 | do_case(FILE * fbin, char *params, cell opcode __UNUSED__) | ||
431 | { | ||
432 | int i; | ||
433 | ucell p, v; | ||
434 | |||
435 | v = hex2long(params, ¶ms); | ||
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 | |||
453 | static cell | ||
454 | curfile(FILE * fbin __UNUSED__, char *params, cell opcode __UNUSED__) | ||
455 | { | ||
456 | fcurrent = (int)hex2long(params, NULL); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static 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 | ||
609 | static int | ||
610 | findopcode(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 | |||
642 | void | ||
643 | assemble(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 | } | ||