update docs
[xorcyst.git] / unit.c
blobab21a8156caedb2734777d2a381930c46dad21e8
1 /*
2 * $Id: unit.c,v 1.4 2007/07/22 13:33:26 khansen Exp $
3 * $Log: unit.c,v $
4 * Revision 1.4 2007/07/22 13:33:26 khansen
5 * convert tabs to whitespaces
7 * Revision 1.3 2004/12/18 17:00:35 kenth
8 * improved error reporting slightly
10 * Revision 1.2 2004/12/16 13:20:07 kenth
11 * xorcyst 1.3.5
13 * Revision 1.1 2004/06/30 07:56:00 kenth
14 * Initial revision
18 /**
19 * (C) 2004 Kent Hansen
21 * The XORcyst is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 * The XORcyst is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with The XORcyst; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include "unit.h"
39 #include "objdef.h"
41 #define SAFE_FREE(m) if ((m) != NULL) { free(m); m = NULL; }
43 /*---------------------------------------------------------------------------*/
45 /* Reads a byte */
46 #define get_1(f) (unsigned char)fgetc(fp)
47 /* Reads a short (big-endian) */
48 static unsigned short get_2(FILE *fp)
50 unsigned short result;
51 result = get_1(fp) << 8; /* High byte */
52 result |= get_1(fp); /* Low byte */
53 return result;
55 /* Reads a 24-bit integer (big-endian) */
56 static unsigned int get_3(FILE *fp)
58 unsigned int result;
59 result = get_2(fp) << 8; /* High 16 bits */
60 result |= get_1(fp); /* Low byte */
61 return result;
63 /* Reads an int (big-endian) */
64 static unsigned int get_4(FILE *fp)
66 unsigned int result;
67 /* Assumes little-endian machine!! */
68 result = get_2(fp) << 16; /* High 16 bits */
69 result |= get_2(fp); /* Low 16 bits */
70 return result;
72 /* Reads a string prepended by 8-bit length */
73 static char *get_str_8(FILE *fp)
75 char *s;
76 /* Read length */
77 int len = get_1(fp) + 1;
78 /* Allocate space for string */
79 s = (char *)malloc(len + 1);
80 if (s != NULL) {
81 /* Read string from file */
82 fread(s, 1, len, fp);
83 /* 0-terminate string */
84 s[len] = '\0';
86 /* Return the new string */
87 return s;
89 /* Reads a string prepended by 16-bit length */
90 static char *get_str_16(FILE *fp)
92 char *s;
93 /* Read length */
94 int len = get_2(fp) + 1;
95 /* Allocate space for string */
96 s = (char *)malloc(len + 1);
97 if (s != NULL) {
98 /* Read string from file */
99 fread(s, 1, len, fp);
101 /* Return the new string */
102 return s;
104 #define get_bytes_8(f) (unsigned char *)get_str_8(f)
105 #define get_bytes_16(f) (unsigned char *)get_str_16(f)
107 /*--------------------------------------------------------------------------*/
110 * Reads a constant from file.
111 * @param fp File handle
112 * @param u Unit in which constant is loaded
113 * @param i Index of constant in unit's constant array
115 static void get_const(FILE *fp, unit *u, int i)
117 constant *cnst = &u->constants[i];
118 /* Read name */
119 cnst->name = get_str_8(fp);
120 /* Read type */
121 cnst->type = get_1(fp);
122 /* Read value */
123 switch (cnst->type) {
124 case INT_8: cnst->integer = get_1(fp); cnst->type = INTEGER_CONSTANT; break;
125 case INT_16: cnst->integer = get_2(fp); cnst->type = INTEGER_CONSTANT; break;
126 case INT_24: cnst->integer = get_3(fp); cnst->type = INTEGER_CONSTANT; break;
127 case INT_32: cnst->integer = get_4(fp); cnst->type = INTEGER_CONSTANT; break;
128 case STR_8: cnst->string = get_str_8(fp); cnst->type = STRING_CONSTANT; break;
129 case STR_16: cnst->string = get_str_16(fp); cnst->type = STRING_CONSTANT; break;
131 default:
132 /* Error, invalid type */
133 fprintf(stderr, "%s(0x%lx): get_const(): bad constant type (%.2X)\n", u->name, ftell(fp), cnst->type);
134 break;
136 /* Set owner */
137 cnst->unit = u;
141 * Reads constant array from file.
142 * @param fp File handle
143 * @param u Unit whose constants array will be populated
145 static void get_constants(FILE *fp, unit *u)
147 int i;
148 /* Read the number of constants */
149 int count = get_2(fp);
150 /* Allocate the list */
151 if (count > 0) {
152 u->constants = (constant *)malloc(sizeof(constant) * count);
154 else {
155 u->constants = NULL;
157 /* Read constants */
158 for (i=0; i<count; i++) {
159 get_const(fp, u, i);
161 /* Set count field */
162 u->const_count = count;
166 * Reads imported symbol from file.
167 * @param fp File handle
168 * @param u Unit
169 * @param i External index
171 static void get_ext(FILE *fp, unit *u, int i)
173 external *ext = &u->externals[i];
174 /* Read unit # */
175 ext->unit = get_1(fp);
176 /* Read name */
177 ext->name = get_str_8(fp);
178 /* Set owner */
179 ext->from = u;
183 * Reads imported symbol array from file.
184 * @param fp File handle
185 * @param u Unit whose externals array will be populated
187 static void get_externals(FILE *fp, unit *u)
189 int i;
190 int count;
191 /* Read the number of imported symbols */
192 count = get_2(fp);
193 /* Allocate the list */
194 if (count > 0) {
195 u->externals = (external *)malloc(sizeof(external) * count);
197 else {
198 u->externals = NULL;
200 /* Read imported symbols */
201 for (i=0; i<count; i++) {
202 get_ext(fp, u, i);
204 /* Set count field */
205 u->ext_count = count;
209 * Reads an expression from file.
210 * @param fp File handle
211 * @param dest Pointer to pointer where expression should be stored
212 * @param u Owner unit
214 static void get_expr_recursive(FILE *fp, expression **dest, unit *u)
216 unsigned char type;
217 /* Allocate space for expression */
218 expression *exp = (expression *)malloc( sizeof(expression) );
219 if (exp != NULL) {
220 /* Read expression type */
221 type = get_1(fp);
222 /* Read the value */
223 switch (type) {
224 /* Literals */
225 case INT_8: exp->integer = get_1(fp); exp->type = INTEGER_EXPRESSION; break;
226 case INT_16: exp->integer = get_2(fp); exp->type = INTEGER_EXPRESSION; break;
227 case INT_24: exp->integer = get_3(fp); exp->type = INTEGER_EXPRESSION; break;
228 case INT_32: exp->integer = get_4(fp); exp->type = INTEGER_EXPRESSION; break;
229 case STR_8: exp->string = get_str_8(fp); exp->type = STRING_EXPRESSION; break;
230 case STR_16: exp->string = get_str_16(fp); exp->type = STRING_EXPRESSION; break;
232 /* Identifiers */
233 case LOCAL: exp->local_id = get_2(fp); exp->type = LOCAL_EXPRESSION; break;
234 case EXTRN: exp->extrn_id = get_2(fp); exp->type = EXTERNAL_EXPRESSION;break;
236 /* Current address */
237 case PC: ; exp->type = PC_EXPRESSION; break;
239 /* Arithmetic, binary */
240 case OP_PLUS:
241 case OP_MINUS:
242 case OP_MUL:
243 case OP_DIV:
244 case OP_MOD:
245 case OP_SHL:
246 case OP_SHR:
247 case OP_AND:
248 case OP_OR:
249 case OP_XOR:
250 case OP_EQ:
251 case OP_NE:
252 case OP_LT:
253 case OP_GT:
254 case OP_LE:
255 case OP_GE:
256 get_expr_recursive(fp, &exp->op_expr.lhs, u);
257 get_expr_recursive(fp, &exp->op_expr.rhs, u);
258 exp->op_expr.operator = type;
259 exp->type = OPERATOR_EXPRESSION;
260 break;
262 /* Arithmetic, unary */
263 case OP_NOT:
264 case OP_NEG:
265 case OP_LO:
266 case OP_HI:
267 case OP_UMINUS:
268 case OP_BANK:
269 get_expr_recursive(fp, &exp->op_expr.lhs, u);
270 exp->op_expr.rhs = NULL;
271 exp->op_expr.operator = type;
272 exp->type = OPERATOR_EXPRESSION;
273 break;
275 default:
276 fprintf(stderr, "%s(0x%lx): get_expr(): invalid expression type (%.2X)\n", u->name, ftell(fp), type);
277 exp->integer = 0;
278 exp->type = INTEGER_EXPRESSION;
279 break;
282 /* Set owner */
283 exp->unit = u;
284 /* Set result pointer */
285 *dest = exp;
289 * Reads expressions from file.
290 * @param fp File handle
291 * @param u Unit whose expressions array to populate
293 static void get_expressions(FILE *fp, unit *u)
295 int i;
296 int count;
297 /* Read the number of expressions */
298 count = get_2(fp);
299 /* Allocate the list */
300 if (count > 0) {
301 u->expressions = (expression **)malloc(sizeof(expression *) * count);
303 else {
304 u->expressions = NULL;
306 /* Read expressions */
307 for (i=0; i<count; i++) {
308 get_expr_recursive(fp, &u->expressions[i], u);
310 /* Store count */
311 u->expr_count = count;
315 * Reads a segment from file.
316 * @param fp File handle
317 * @param seg Where to store segment
319 static void get_segment(FILE *fp, segment *seg)
321 /* Read size */
322 seg->size = get_3(fp);
323 /* Allocate space */
324 if (seg->size > 0) {
325 /* Allocate mem for bytecodes */
326 seg->bytes = (unsigned char *)malloc(seg->size);
327 if (seg->bytes != NULL) {
328 /* Read contents */
329 fread(seg->bytes, 1, seg->size, fp);
332 else {
333 seg->bytes = NULL;
337 /*--------------------------------------------------------------------------*/
340 * Reads a unit from file.
341 * @param filename Name of the unit
342 * @param u Pointer to struct to fill in
344 int unit_read(char *filename, unit *u)
346 FILE *fp;
347 int count, i;
348 unsigned short magic;
349 unsigned char version;
351 /* Store name */
352 u->name = filename;
353 /* Attempt to open file */
354 fp = fopen(filename, "rb");
355 if (fp == NULL) {
356 /* Error, couldn't open it */
357 u->const_count = 0;
358 u->ext_count = 0;
359 u->expr_count = 0;
360 u->dataseg.size = 0;
361 u->dataseg.bytes = NULL;
362 u->codeseg.size = 0;
363 u->codeseg.bytes = NULL;
364 return 0;
366 /* Read magic number */
367 magic = get_2(fp);
368 /* Verify magic number */
369 if (magic != A_MAGIC) {
370 /* Error, bad magic number */
371 return 0;
373 /* Read version */
374 version = get_1(fp);
375 /* Verify version: should be 1.0 */
376 if (version != A_VERSION) {
377 /* Error, bad version */
378 return 0;
380 /* Read exported constants */
381 get_constants(fp, u);
382 /* Read # of units explicitly imported from */
383 count = get_1(fp);
384 /* Read unit names */
385 for (i=0; i<count; i++) {
386 get_str_8(fp);
388 /* Read imported symbols */
389 get_externals(fp, u);
390 /* Read dataseg */
391 get_segment(fp, &u->dataseg);
392 /* Read codeseg */
393 get_segment(fp, &u->codeseg);
394 /* Read expressions */
395 get_expressions(fp, u);
397 /* Close the file */
398 fclose(fp);
400 /* Success */
401 return 1;
404 /*--------------------------------------------------------------------------*/
407 * Finalizes a constant.
408 * @param c Constant to finalize
410 static void finalize_constant(constant *c)
412 if (c->type == STRING_CONSTANT) {
413 SAFE_FREE(c->string);
415 SAFE_FREE(c->name);
419 * Finalizes an external.
420 * @param e External to finalize
422 static void finalize_external(external *e)
424 SAFE_FREE(e->name);
428 * Finalizes an expression.
429 * @param e Expression to finalize
431 static void finalize_expression(expression *e)
433 if (e == NULL) { return; }
434 switch (e->type) {
435 case STRING_EXPRESSION:
436 SAFE_FREE(e->string);
437 break;
439 case OPERATOR_EXPRESSION:
440 finalize_expression(e->op_expr.lhs);
441 finalize_expression(e->op_expr.rhs);
442 break;
444 default:
445 /* Nada */
446 break;
448 SAFE_FREE(e);
452 * Finalizes a bytecode segment.
453 * @param s Segment to finalize
455 static void finalize_segment(segment *s)
457 SAFE_FREE(s->bytes);
460 /*--------------------------------------------------------------------------*/
463 * Finalizes a unit.
464 * @param u Unit to finalize
466 void unit_finalize(unit *u)
468 int i;
469 /* Finalize the constants */
470 for (i=0; i<u->const_count; i++) {
471 finalize_constant(&u->constants[i]);
473 SAFE_FREE(u->constants);
474 /* Finalize the externals */
475 for (i=0; i<u->ext_count; i++) {
476 finalize_external(&u->externals[i]);
478 SAFE_FREE(u->externals);
479 /* Finalize expressions */
480 for (i=0; i<u->expr_count; i++) {
481 finalize_expression(u->expressions[i]);
483 SAFE_FREE(u->expressions);
484 /* Finalize bytecode segments */
485 finalize_segment(&u->dataseg);
486 finalize_segment(&u->codeseg);