use snprintf
[xorcyst.git] / astproc.c
blob3ceed4f480bc18d9e871493ad899b28cc2134cc0
1 /*
2 * $Id: astproc.c,v 1.21 2007/11/11 22:35:22 khansen Exp $
3 * $Log: astproc.c,v $
4 * Revision 1.21 2007/11/11 22:35:22 khansen
5 * compile on mac
7 * Revision 1.20 2007/08/19 10:17:39 khansen
8 * allow symbols to be used without having been declared
10 * Revision 1.19 2007/08/12 18:58:12 khansen
11 * ability to generate pure 6502 binary (--pure-binary switch)
13 * Revision 1.18 2007/08/12 02:42:46 khansen
14 * prettify, const
16 * Revision 1.17 2007/08/09 22:06:10 khansen
17 * ability to pass in reference to local label as argument to macro
19 * Revision 1.16 2007/08/09 20:48:46 khansen
20 * disable buggy code that can cause crash
22 * Revision 1.15 2007/08/09 20:33:40 khansen
23 * progress
25 * Revision 1.14 2007/08/08 22:40:01 khansen
26 * improved symbol lookup, definitions must precede usage
28 * Revision 1.13 2007/07/22 13:33:26 khansen
29 * convert tabs to whitespaces
31 * Revision 1.12 2005/01/09 11:17:57 kenth
32 * xorcyst 1.4.5
33 * fixed bug in process_data(), merge_data()
34 * no longer truncation warning when fits in signed byte/word
36 * Revision 1.11 2005/01/05 02:28:13 kenth
37 * xorcyst 1.4.3
38 * support for anonymous unions
39 * fixed sizeof bug
41 * Revision 1.10 2004/12/29 21:44:41 kenth
42 * xorcyst 1.4.2
43 * static indexing, sizeof improved
45 * Revision 1.9 2004/12/25 02:22:35 kenth
46 * fixed bug in reduce_user_storage()
48 * Revision 1.8 2004/12/19 19:58:29 kenth
49 * xorcyst 1.4.0
51 * Revision 1.7 2004/12/18 16:57:39 kenth
52 * STORAGE_NODE(WORD/DWORD_DATATYPE) converts to BYTE
54 * Revision 1.6 2004/12/16 13:19:47 kenth
55 * xorcyst 1.3.5
57 * Revision 1.5 2004/12/14 01:49:05 kenth
58 * xorcyst 1.3.0
60 * Revision 1.4 2004/12/11 02:01:25 kenth
61 * added forward/backward branching
63 * Revision 1.3 2004/12/09 11:18:13 kenth
64 * added: warning, error node processing
66 * Revision 1.2 2004/12/06 04:52:24 kenth
67 * Major updates (xorcyst 1.1.0)
69 * Revision 1.1 2004/06/30 07:55:31 kenth
70 * Initial revision
74 /**
75 * (C) 2004 Kent Hansen
77 * The XORcyst is free software; you can redistribute it and/or modify
78 * it under the terms of the GNU General Public License as published by
79 * the Free Software Foundation; either version 2 of the License, or
80 * (at your option) any later version.
82 * The XORcyst is distributed in the hope that it will be useful,
83 * but WITHOUT ANY WARRANTY; without even the implied warranty of
84 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85 * GNU General Public License for more details.
87 * You should have received a copy of the GNU General Public License
88 * along with The XORcyst; if not, write to the Free Software
89 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
92 /**
93 * This file contains functions that process the Abstract Syntax Tree (AST).
94 * After the assembly file has been parsed into an AST, a number of passes are
95 * made on it to process it and transform it. The functions here are
96 * concerned with things like
97 * - macro expansion
98 * - symbol table generation
99 * - equates substitution
100 * - constant folding
101 * - code and symbol validation
104 #include <stdlib.h>
105 #include <stdio.h>
106 #include <stdarg.h>
107 #include <string.h>
108 #include <assert.h>
109 #include "astproc.h"
110 #include "symtab.h"
111 #include "opcode.h"
112 #include "charmap.h"
113 #include "xasm.h"
115 #define IS_SIGNED_BYTE_VALUE(v) (((v) >= -128) && ((v) <= 127))
116 #define IS_UNSIGNED_BYTE_VALUE(v) (((v) >= 0) && ((v) <= 255))
117 #define IS_BYTE_VALUE(v) (IS_SIGNED_BYTE_VALUE(v) || IS_UNSIGNED_BYTE_VALUE(v))
119 #define IS_SIGNED_WORD_VALUE(v) (((v) >= -32768) && ((v) <= 32767))
120 #define IS_UNSIGNED_WORD_VALUE(v) (((v) >= 0) && ((v) <= 65535))
121 #define IS_WORD_VALUE(v) (IS_SIGNED_WORD_VALUE(v) || IS_UNSIGNED_WORD_VALUE(v))
123 /*---------------------------------------------------------------------------*/
125 /** Number of errors issued during processing. */
126 static int err_count = 0;
128 /** Number of warnings issued during processing. */
129 static int warn_count = 0;
131 /* Keeps track of number of global labels encountered. */
132 static int label_count = 0;
134 /* Keeps track of whether statement is in dataseg or codeseg. */
135 static int in_dataseg = 0;
137 /* Default symbol modifiers, i.e. ZEROPAGE_FLAG, PUBLIC_FLAG */
138 static int modifiers = 0;
140 /* Used when we are outputting pure 6502 binary */
141 static int dataseg_pc;
142 static int codeseg_pc;
144 /*---------------------------------------------------------------------------*/
146 /** Mapping from regular ASCII characters to custom character values.
147 * Used to transform .char arrays to regular .db arrays.
149 static unsigned char charmap[256];
152 * Resets the custom character map.
153 * Every ASCII character is mapped to itself.
155 static void reset_charmap()
157 int i;
158 for (i=0; i<256; i++) {
159 charmap[i] = (char)i;
163 /*---------------------------------------------------------------------------*/
164 /* Forward/backward branching stuff */
166 struct tag_forward_branch_info {
167 astnode *refs[128];
168 int index; /* Index into refs */
169 int counter;
172 typedef struct tag_forward_branch_info forward_branch_info;
174 struct tag_backward_branch_info {
175 astnode *decl;
176 int counter;
179 typedef struct tag_backward_branch_info backward_branch_info;
181 #define BRANCH_MAX 8
183 static forward_branch_info forward_branch[BRANCH_MAX];
185 static backward_branch_info backward_branch[BRANCH_MAX];
188 * Zaps forward/backward branch data.
190 static void branch_init()
192 int i, j;
193 for (i=0; i<BRANCH_MAX; i++) {
194 for (j=0; j<128; j++) {
195 forward_branch[i].refs[j] = NULL;
197 forward_branch[i].index = 0;
198 forward_branch[i].counter = 0;
199 backward_branch[i].decl = NULL;
200 backward_branch[i].counter = 0;
204 /*---------------------------------------------------------------------------*/
207 * Issues an error.
208 * @param loc File location of error
209 * @param fmt printf-style format string
211 static void err(location loc, const char *fmt, ...)
213 va_list ap;
214 va_start(ap, fmt);
216 /* Print error message w/ location info */
217 fprintf(stderr, "error: %s:", loc.file);
218 LOCATION_PRINT(stderr, loc);
219 fprintf(stderr, ": ");
220 vfprintf(stderr, fmt, ap);
221 fprintf(stderr, "\n");
223 va_end(ap);
225 /* Increase total error count */
226 err_count++;
230 * Issues a warning.
231 * @param loc File location of warning
232 * @param fmt printf-style format string
234 static void warn(location loc, const char *fmt, ...)
236 va_list ap;
237 if (!xasm_args.no_warn) {
238 va_start(ap, fmt);
239 /* Print warning message w/ location info */
240 fprintf(stderr, "warning: %s:", loc.file);
241 LOCATION_PRINT(stderr, loc);
242 fprintf(stderr, ": ");
243 vfprintf(stderr, fmt, ap);
244 fprintf(stderr, "\n");
245 va_end(ap);
248 /* Increase total warning count */
249 warn_count++;
253 * Gets the number of errors encountered during processing.
254 * @return Number of errors
256 int astproc_err_count()
258 return err_count;
261 /*---------------------------------------------------------------------------*/
264 * Gets the processor function for a node type from a map.
265 * Used by astproc_walk().
266 * @param type The node type
267 * @param map A mapping from node types to processor functions
269 static astnodeproc astproc_node_type_to_proc(astnode_type type, const astnodeprocmap *map)
271 /* Try all map entries */
272 for (; map->proc != NULL; map += 1) {
273 if (map->type == type) {
274 return map->proc; /* Match */
277 /* No match */
278 return NULL;
281 /*---------------------------------------------------------------------------*/
284 * Walks an abstract syntax tree recursively.
285 * @param n Node to walk
286 * @param arg Optional argument to pass to processor function
287 * @param map Mapping of node types to processor functions
289 static void astproc_walk_recursive(astnode *n, void *arg, const astnodeprocmap *map, astnode **next)
291 astnode *c;
292 astnode *t;
293 if (n == NULL) { return; }
294 /* Process this node if it has a processor function */
295 astnodeproc p = astproc_node_type_to_proc(astnode_get_type(n), map);
296 if (p != NULL) {
297 if (!p(n, arg, next)) return; /* Don't walk children */
299 /* Walk the node's children recursively */
300 for (c=n->first_child; c != NULL; c = t) {
301 t = c->next_sibling; /* default next node */
302 astproc_walk_recursive(c, arg, map, &t);
307 * Generic tree walker function.
308 * @param n Root
309 * @param arg General-purpose argument passed to each node handler function
310 * @param map Array of (nodetype, handler function) tuples
312 void astproc_walk(astnode *n, void *arg, const astnodeprocmap *map)
314 astnode *dummy;
315 astproc_walk_recursive(n, arg, map, &dummy);
318 /*---------------------------------------------------------------------------*/
321 * Don't do any processing of this node or its children on this pass.
323 static int noop(astnode *n, void *arg, astnode **next)
325 return 0;
329 * Substitutes an identifier node with subst_expr if the id is equal to subst_id.
330 * @param n A node of type IDENTIFIER_NODE
331 * @param arg Array of length 2, containing (expr, id) pair
333 static int substitute_id(astnode *n, void *arg, astnode **next)
335 /* arg is array containing expression and identifier */
336 astnode **array = (astnode **)arg;
337 astnode *subst_expr = array[0];
338 astnode *subst_id = array[1];
339 /* Test if this node and the identifier to replace are equal */
340 if (astnode_equal(n, subst_id)) {
341 /* They're equal, replace it by expression. */
342 astnode *cl = astnode_clone(subst_expr, n->loc);
343 /* ### Generalize: traverse all children, set the flag */
344 if (astnode_get_type(cl) == LOCAL_ID_NODE) {
345 cl->flags |= 0x80; /* don't globalize it */
347 astnode_replace(n, cl);
348 astnode_finalize(n);
349 *next = cl;
350 return 0;
351 } else {
352 return 1;
357 * Substitutes expr for id in list.
358 * Used by macro expander to substitute a macro body parameter name with the
359 * actual expression used in the macro expansion.
360 * @param expr An expression
361 * @param id An identifier
362 * @param list A list of statements (macro body)
364 static void substitute_expr_for_id(astnode *expr, astnode *id, astnode *list)
366 /* Prepare argument to astproc_walk */
367 astnode *array[2];
368 array[0] = expr;
369 array[1] = id;
370 /* Table of callback functions for our purpose. */
371 static astnodeprocmap map[] = {
372 { IDENTIFIER_NODE, substitute_id },
373 { 0, NULL }
375 /* Do the walk. */
376 astproc_walk(list, array, map);
379 /*---------------------------------------------------------------------------*/
382 * Globalizes a macro expanded local.
383 * This is done simply by concatenating the local label identifier with the
384 * global macro invocation counter.
385 * @param n A node of type LOCAL_LABEL_NODE or LOCAL_ID_NODE
386 * @param arg Namespace counter (int)
388 static int globalize_macro_expanded_local(astnode *n, void *arg, astnode **next)
390 /* Only globalize if it's a reference to a label defined in the macro */
391 if (!(n->flags & 0x80)) {
392 char str[16];
393 int count;
394 /* Make it global by appending the macro expansion counter to the id */
395 count = (int)arg;
396 snprintf(str, sizeof (str), "#%d", count);
397 if (astnode_is_type(n, LOCAL_LABEL_NODE)) {
398 /* LOCAL_LABEL_NODE, use label field */
399 n->label = realloc(n->label, strlen(n->label)+strlen(str)+1);
400 strcat(n->label, str);
401 } else {
402 /* LOCAL_ID_NODE, use ident field */
403 assert(astnode_is_type(n, LOCAL_ID_NODE));
404 n->ident = realloc(n->ident, strlen(n->ident)+strlen(str)+1);
405 strcat(n->ident, str);
408 /* */
409 return 1;
413 * Globalizes all locals in the body of a macro expansion.
414 * Used by the macro expander to ensure that local labels in macro expansions
415 * are unique.
416 * @param exp_body The expanded macro body
417 * @param count Unique macro namespace counter
419 static void globalize_macro_expanded_locals(astnode *exp_body, int count)
421 /* Table of callback functions for our purpose. */
422 static astnodeprocmap map[] = {
423 { LOCAL_ID_NODE, globalize_macro_expanded_local },
424 { LOCAL_LABEL_NODE, globalize_macro_expanded_local },
425 { 0, NULL }
427 /* Do the walk. */
428 astproc_walk(exp_body, (void *)count, map);
432 * Expands a macro; that is, replaces a macro invocation in the AST with the
433 * macro body. Substitutes parameter names for values.
434 * @param n Must be a node of type MACRO_NODE
435 * @param arg Not used
437 static int expand_macro(astnode *n, void *arg, astnode **next)
439 astnode *decl;
440 astnode *decl_body;
441 astnode *exp_body;
442 astnode *formals;
443 astnode *actuals;
444 astnode *id;
445 astnode *expr;
446 int i;
447 /* Keeps track of the current/total number of macro expansions */
448 static int count = 0;
449 /* Get the name of the macro to expand */
450 id = astnode_get_child(n, 0);
451 /* Look up its definition in symbol table */
452 symtab_entry *e = symtab_lookup(id->ident);
453 /* If it's not in the symbol table, error. */
454 if (e == NULL) {
455 err(n->loc, "unknown macro or directive `%s'", id->ident);
456 /* Remove from AST */
457 astnode_remove(n);
458 astnode_finalize(n);
459 return 0;
461 else if (e->type != MACRO_SYMBOL) {
462 err(n->loc, "cannot expand `%s'; not a macro", e->id);
463 /* Remove from AST */
464 astnode_remove(n);
465 astnode_finalize(n);
466 return 0;
468 else {
469 /* e->def has pointer to proper MACRO_DECL_NODE */
470 decl = (astnode *)e->def;
471 /* Get the lists of formals and actuals */
472 formals = astnode_get_child(decl, 1);
473 actuals = astnode_get_child(n, 1);
474 /* Verify that argument count is correct */
475 if (astnode_get_child_count(formals) != astnode_get_child_count(actuals)) {
476 err(n->loc, "macro `%s' does not take %d argument(s)", id->ident, astnode_get_child_count(actuals) );
477 /* Remove from AST */
478 astnode_remove(n);
479 astnode_finalize(n);
480 return 0;
482 /* Expand the body */
483 decl_body = astnode_get_child(decl, 2);
484 exp_body = astnode_clone(decl_body, n->loc);
485 assert(astnode_get_type(exp_body) == LIST_NODE);
486 /* Substitute actuals for formals */
487 for (i=0; i<astnode_get_child_count(actuals); i++) {
488 /* The id to substitute */
489 id = astnode_get_child(formals, i);
490 /* The expression to substitute it with */
491 expr = astnode_get_child(actuals, i);
492 /* Do it! */
493 substitute_expr_for_id(expr, id, exp_body);
495 /* Make locals a bit more global */
496 globalize_macro_expanded_locals(exp_body, count);
497 /* Replace MACRO_NODE by the macro body instance */
499 astnode *stmts = astnode_remove_children(exp_body);
500 astnode_replace(n, stmts);
501 *next = stmts;
502 astnode_finalize(exp_body);
504 /* Discard the replaced node */
505 astnode_finalize(n);
506 /* Increase macro expansion counter */
507 count++;
509 /* */
510 return 0;
513 /*---------------------------------------------------------------------------*/
516 * Does constant folding of expression.
517 * If the expression can be folded, the original expression is replaced by the
518 * new one, and the original expression is finalized.
519 * @param expr Expression
520 * @return Original expression, if couldn't fold, otherwise new, folded expression
522 astnode *astproc_fold_constants(astnode *expr)
524 astnode *folded;
525 astnode *lhs;
526 astnode *rhs;
527 if (expr == NULL) { return NULL; }
528 folded = NULL;
529 if (astnode_is_type(expr, ARITHMETIC_NODE)) {
530 /* Fold operands recursively */
531 lhs = astproc_fold_constants(LHS(expr));
532 rhs = astproc_fold_constants(RHS(expr));
533 switch (expr->oper) {
534 /* Binary ops */
535 case PLUS_OPERATOR:
536 case MINUS_OPERATOR:
537 case MUL_OPERATOR:
538 case DIV_OPERATOR:
539 case MOD_OPERATOR:
540 case AND_OPERATOR:
541 case OR_OPERATOR:
542 case XOR_OPERATOR:
543 case SHL_OPERATOR:
544 case SHR_OPERATOR:
545 case LT_OPERATOR:
546 case GT_OPERATOR:
547 case EQ_OPERATOR:
548 case NE_OPERATOR:
549 case LE_OPERATOR:
550 case GE_OPERATOR:
551 /* See if it can be folded */
552 if ( (astnode_is_type(lhs, INTEGER_NODE)) &&
553 (astnode_is_type(rhs, INTEGER_NODE)) ) {
554 /* Both sides are integer literals, so fold. */
555 switch (expr->oper) {
556 case PLUS_OPERATOR: folded = astnode_create_integer(lhs->integer + rhs->integer, expr->loc); break;
557 case MINUS_OPERATOR: folded = astnode_create_integer(lhs->integer - rhs->integer, expr->loc); break;
558 case MUL_OPERATOR: folded = astnode_create_integer(lhs->integer * rhs->integer, expr->loc); break;
559 case DIV_OPERATOR: folded = astnode_create_integer(lhs->integer / rhs->integer, expr->loc); break;
560 case MOD_OPERATOR: folded = astnode_create_integer(lhs->integer % rhs->integer, expr->loc); break;
561 case AND_OPERATOR: folded = astnode_create_integer(lhs->integer & rhs->integer, expr->loc); break;
562 case OR_OPERATOR: folded = astnode_create_integer(lhs->integer | rhs->integer, expr->loc); break;
563 case XOR_OPERATOR: folded = astnode_create_integer(lhs->integer ^ rhs->integer, expr->loc); break;
564 case SHL_OPERATOR: folded = astnode_create_integer(lhs->integer << rhs->integer, expr->loc); break;
565 case SHR_OPERATOR: folded = astnode_create_integer(lhs->integer >> rhs->integer, expr->loc); break;
566 case LT_OPERATOR: folded = astnode_create_integer(lhs->integer < rhs->integer, expr->loc); break;
567 case GT_OPERATOR: folded = astnode_create_integer(lhs->integer > rhs->integer, expr->loc); break;
568 case EQ_OPERATOR: folded = astnode_create_integer(lhs->integer == rhs->integer, expr->loc); break;
569 case NE_OPERATOR: folded = astnode_create_integer(lhs->integer != rhs->integer, expr->loc); break;
570 case LE_OPERATOR: folded = astnode_create_integer(lhs->integer <= rhs->integer, expr->loc); break;
571 case GE_OPERATOR: folded = astnode_create_integer(lhs->integer >= rhs->integer, expr->loc); break;
573 default:
574 fprintf(stderr, "internal error: operator not handled in astproc_fold_constants()\n");
575 assert(0);
576 folded = expr;
577 break;
579 if (folded != expr) {
580 /* Replace expression by folded one. */
581 astnode_replace(expr, folded);
582 astnode_finalize(expr);
583 return folded;
586 else if ( (astnode_is_type(lhs, STRING_NODE)) &&
587 (astnode_is_type(rhs, STRING_NODE)) ) {
588 /* Both sides are string literals. */
589 /* Folding is defined only for certain operators. */
590 switch (expr->oper) {
591 case PLUS_OPERATOR:
592 /* String concatenation. */
593 folded = astnode_create(STRING_NODE, expr->loc);
594 folded->string = (char *)malloc(strlen(lhs->string) + strlen(rhs->string) + 1);
595 if (folded->string != NULL) {
596 strcpy(folded->string, lhs->string);
597 strcat(folded->string, rhs->string);
599 break;
601 /* String comparison. */
602 case LT_OPERATOR: folded = astnode_create_integer(strcmp(lhs->string, rhs->string) < 0, expr->loc); break;
603 case GT_OPERATOR: folded = astnode_create_integer(strcmp(lhs->string, rhs->string) > 0, expr->loc); break;
604 case EQ_OPERATOR: folded = astnode_create_integer(strcmp(lhs->string, rhs->string) == 0, expr->loc); break;
605 case NE_OPERATOR: folded = astnode_create_integer(strcmp(lhs->string, rhs->string) != 0, expr->loc); break;
606 case LE_OPERATOR: folded = astnode_create_integer(strcmp(lhs->string, rhs->string) <= 0, expr->loc); break;
607 case GE_OPERATOR: folded = astnode_create_integer(strcmp(lhs->string, rhs->string) >= 0, expr->loc); break;
609 default:
610 folded = expr;
611 break;
613 if (folded != expr) {
614 /* Replace expression by folded one. */
615 astnode_replace(expr, folded);
616 astnode_finalize(expr);
617 return folded;
620 else if ((astnode_get_type(lhs) == STRING_NODE) &&
621 (astnode_get_type(rhs) == INTEGER_NODE) &&
622 (expr->oper == PLUS_OPERATOR)) {
623 /* Left side is string and right side is integer.
624 Result is a string. */
625 char str[32];
626 snprintf(str, sizeof (str), "%d", rhs->integer);
627 folded = astnode_create(STRING_NODE, expr->loc);
628 folded->string = (char *)malloc(strlen(lhs->string) + strlen(str) + 1);
629 if (folded->string != NULL) {
630 strcpy(folded->string, lhs->string);
631 strcat(folded->string, str);
633 /* Replace expression by folded one. */
634 astnode_replace(expr, folded);
635 astnode_finalize(expr);
636 return folded;
638 else if ((astnode_get_type(rhs) == STRING_NODE) &&
639 (astnode_get_type(lhs) == INTEGER_NODE) &&
640 (expr->oper == PLUS_OPERATOR)) {
641 /* Left side is integer and right side is string.
642 Result is a string. */
643 char str[32];
644 snprintf(str, sizeof (str), "%d", lhs->integer);
645 folded = astnode_create(STRING_NODE, expr->loc);
646 folded->string = (char *)malloc(strlen(str) + strlen(rhs->string) + 1);
647 if (folded->string != NULL) {
648 strcpy(folded->string, str);
649 strcat(folded->string, rhs->string);
651 /* Replace expression by folded one. */
652 astnode_replace(expr, folded);
653 astnode_finalize(expr);
654 return folded;
656 /* Use some mathematical identities... */
657 else if ((astnode_is_type(lhs, INTEGER_NODE) && (lhs->integer == 0))
658 && (expr->oper == PLUS_OPERATOR)) {
659 /* 0+expr == expr */
660 astnode_remove_child(expr, rhs);
661 astnode_replace(expr, rhs);
662 astnode_finalize(expr);
663 return rhs;
665 else if ((astnode_is_type(rhs, INTEGER_NODE) && (rhs->integer == 0))
666 && (expr->oper == PLUS_OPERATOR)) {
667 /* expr+0 == expr */
668 astnode_remove_child(expr, lhs);
669 astnode_replace(expr, lhs);
670 astnode_finalize(expr);
671 return lhs;
673 else if ((astnode_is_type(lhs, INTEGER_NODE) && (lhs->integer == 1))
674 && (expr->oper == MUL_OPERATOR)) {
675 /* 1*expr == expr */
676 astnode_remove_child(expr, rhs);
677 astnode_replace(expr, rhs);
678 astnode_finalize(expr);
679 return rhs;
681 else if ((astnode_is_type(rhs, INTEGER_NODE) && (rhs->integer == 1))
682 && ((expr->oper == MUL_OPERATOR) || (expr->oper == DIV_OPERATOR)) ) {
683 /* expr*1 == expr */
684 /* expr/1 == expr */
685 astnode_remove_child(expr, lhs);
686 astnode_replace(expr, lhs);
687 astnode_finalize(expr);
688 return lhs;
690 else {
691 /* No chance of folding this one. */
693 break;
695 /* Unary ops */
696 case NEG_OPERATOR:
697 case NOT_OPERATOR:
698 case LO_OPERATOR:
699 case HI_OPERATOR:
700 case UMINUS_OPERATOR:
701 case BANK_OPERATOR:
702 /* See if it can be folded */
703 if (astnode_is_type(lhs, INTEGER_NODE)) {
704 /* Fold it. */
705 switch (expr->oper) {
706 case NEG_OPERATOR: folded = astnode_create_integer(~lhs->integer, expr->loc); break;
707 case NOT_OPERATOR: folded = astnode_create_integer(!lhs->integer, expr->loc); break;
708 case LO_OPERATOR: folded = astnode_create_integer(lhs->integer & 0xFF, expr->loc); break;
709 case HI_OPERATOR: folded = astnode_create_integer((lhs->integer >> 8) & 0xFF, expr->loc); break;
710 case UMINUS_OPERATOR: folded = astnode_create_integer(-lhs->integer, expr->loc); break;
711 default: break;
713 /* Replace expression by folded one. */
714 astnode_replace(expr, folded);
715 astnode_finalize(expr);
716 return folded;
718 else {
719 /* Couldn't fold this one. */
721 break;
724 /* Couldn't fold it, return original expression */
725 return expr;
728 /*---------------------------------------------------------------------------*/
731 * Substitutes identifier if it has a constant definition in symbol table.
732 * @param expr Node of type IDENTIFIER_NODE
734 static astnode *substitute_ident(astnode *expr)
736 astnode *c;
737 symtab_entry *e;
738 /* Look it up in symbol table */
739 e = symtab_lookup(expr->ident);
740 if (e != NULL) {
741 /* Found it. Test if it's a define. */
742 if (e->type == CONSTANT_SYMBOL) {
743 /* This is a defined symbol that should be
744 replaced by the expression it stands for */
745 c = astnode_clone((astnode *)e->def, expr->loc);
746 astnode_replace(expr, c);
747 astnode_finalize(expr);
748 expr = c;
751 else {
752 /* Didn't find it in symbol table. */
754 return expr;
758 * Substitutes sizeof with proper constant.
759 * @param expr Node of type SIZEOF_NODE
761 static astnode *reduce_sizeof(astnode *expr)
763 int ok;
764 astnode *c;
765 astnode *id;
766 astnode *type;
767 astnode *count;
768 symtab_entry *e;
770 count = NULL;
771 if (astnode_is_type(LHS(expr), IDENTIFIER_NODE)) {
772 /* Identifier might be the name of a user-defined type, OR
773 it might be the name of a variable of a user-defined type */
774 type = NULL;
775 /* Look it up */
776 id = LHS(expr);
777 e = symtab_global_lookup(id->ident);
778 if (e != NULL) {
779 switch (e->type) {
780 case STRUC_SYMBOL:
781 case UNION_SYMBOL:
782 case RECORD_SYMBOL:
783 case ENUM_SYMBOL:
784 type = astnode_create_datatype(USER_DATATYPE, astnode_clone(id, id->loc), id->loc);
785 break;
787 case VAR_SYMBOL:
788 type = astnode_clone(LHS(e->def), id->loc);
789 if (astnode_is_type(e->def, STORAGE_NODE)) {
790 count = astnode_clone(RHS(e->def), id->loc);
792 else {
793 count = astnode_create_integer(astnode_get_child_count(e->def)-1, id->loc);
795 break;
797 default:
798 /* Can't take sizeof of this symbol type */
799 break;
802 if (type == NULL) {
803 /* Unknown */
804 type = astnode_create_datatype(USER_DATATYPE, astnode_clone(id, id->loc), id->loc);
806 /* Replace identifier by datatype node */
807 astnode_replace(id, type);
808 astnode_finalize(id);
810 type = LHS(expr);
811 switch (type->datatype) {
812 case BYTE_DATATYPE:
813 case CHAR_DATATYPE:
814 c = astnode_create_integer(1, expr->loc);
815 astnode_replace(expr, c);
816 astnode_finalize(expr);
817 expr = c;
818 break;
820 case WORD_DATATYPE:
821 c = astnode_create_integer(2, expr->loc);
822 astnode_replace(expr, c);
823 astnode_finalize(expr);
824 expr = c;
825 break;
827 case DWORD_DATATYPE:
828 c = astnode_create_integer(4, expr->loc);
829 astnode_replace(expr, c);
830 astnode_finalize(expr);
831 expr = c;
832 break;
834 case USER_DATATYPE:
835 /* Look up the data type in symbol table */
836 id = LHS(type);
837 e = symtab_global_lookup(id->ident);
838 ok = 0;
839 if (e != NULL) {
840 switch (e->type) {
841 case STRUC_SYMBOL:
842 case UNION_SYMBOL:
843 /* Datatype is defined, replace sizeof with proper expression */
844 c = astnode_clone((astnode *)(e->struc.size), ((astnode *)(e->struc.size))->loc);
845 astnode_replace(expr, c);
846 astnode_finalize(expr);
847 expr = c;
848 ok = 1;
849 break;
851 case RECORD_SYMBOL:
852 case ENUM_SYMBOL:
853 /* 1 byte */
854 c = astnode_create_integer(1, expr->loc);
855 astnode_replace(expr, c);
856 astnode_finalize(expr);
857 expr = c;
858 ok = 1;
859 break;
861 default:
862 /* Dunno the size of this symbol type */
863 break;
866 if (!ok) {
867 /* Datatype not defined, error */
868 err(expr->loc, "size of `%s' is unknown", id->ident);
869 /* Replace by 1 */
870 c = astnode_create_integer(1, expr->loc);
871 astnode_replace(expr, c);
872 astnode_finalize(expr);
873 return c;
875 break;
877 default:
878 err(expr->loc, "substitute_sizeof(): unknown type");
879 break;
881 if (count != NULL) {
882 c = astnode_create_arithmetic(
883 MUL_OPERATOR,
884 astnode_clone(expr, expr->loc),
885 count,
886 expr->loc
888 astnode_replace(expr, c);
889 astnode_finalize(expr);
890 expr = c;
892 return expr;
896 * Substitutes A::B with an expression.
897 * If A is a struct: substitute with offset of B
898 * If A is a union: substitute with 0
899 * If A is an enumeration: substitute with value for B
900 * @param expr Node of type SCOPE_NODE
902 static astnode *reduce_scope(astnode *expr)
904 symtab_entry *ns;
905 symtab_entry *sym;
906 astnode *c;
907 astnode *namespace;
908 astnode *symbol;
909 /* Look up the namespace */
910 namespace = LHS(expr);
911 ns = symtab_lookup(namespace->ident);
912 if (ns != NULL) {
913 /* Look up the local symbol */
914 symtab_push(ns->symtab);
915 symbol = RHS(expr);
916 sym = symtab_lookup(symbol->ident);
917 if (sym != NULL) {
918 /* See if we can replace it */
919 switch (ns->type) {
920 case STRUC_SYMBOL:
921 case UNION_SYMBOL:
922 case RECORD_SYMBOL:
923 /* Replace with field offset */
924 c = astnode_clone(sym->field.offset, sym->field.offset->loc);
925 astnode_replace(expr, c);
926 astnode_finalize(expr);
927 expr = c;
928 break;
930 case ENUM_SYMBOL:
931 /* Replace with enum entry value */
932 c = astnode_clone(sym->def, sym->def->loc);
933 astnode_replace(expr, c);
934 astnode_finalize(expr);
935 expr = c;
936 break;
938 default:
939 break;
942 symtab_pop();
944 return expr;
947 static astnode *reduce_expression(astnode *expr);
950 * Handles remainder of fields in A.B.C.D . ..., where one or more fields may be indexed.
951 * @param expr Node of type DOT_NODE, INDEX_NODE or IDENTIFIER_NODE
953 static astnode *reduce_dot_recursive(astnode *expr)
955 astnode *term;
956 astnode *offset;
957 astnode *left;
958 astnode *right;
959 astnode *type;
960 symtab_entry *field;
961 symtab_entry *def;
962 astnode *index = NULL;
963 /* Get identifiers involved: 'right' is field in 'left' */
964 left = LHS(expr);
965 if (astnode_is_type(left, INDEX_NODE)) {
966 left = LHS(left); /* Need identifier */
968 right = RHS(expr);
969 if (astnode_is_type(right, DOT_NODE)) {
970 right = LHS(right); /* Need identifier */
972 if (astnode_is_type(right, INDEX_NODE)) {
973 index = RHS(right);
974 right = LHS(right); /* Need identifier */
976 /* Lookup 'right' in 'left's symbol table (on stack) */
977 field = symtab_lookup(right->ident);
978 /* Look up variable's type definition */
979 type = LHS(field->def);
980 /* Copy its offset */
981 offset = astnode_clone(field->field.offset, right->loc);
982 if (index != NULL) {
983 /* Create expression: identifier + sizeof(datatype) * index */
984 offset = astnode_create_arithmetic(
985 PLUS_OPERATOR,
986 offset,
987 astnode_create_arithmetic(
988 MUL_OPERATOR,
989 astnode_create_sizeof(astnode_clone(type, type->loc), expr->loc),
990 astnode_clone(index, index->loc),
991 index->loc
993 expr->loc
996 /* See if more subfields to process */
997 expr = RHS(expr);
998 if (astnode_is_type(expr, DOT_NODE)) {
999 /* Next field */
1000 def = symtab_global_lookup(LHS(type)->ident);
1001 symtab_push(def->symtab);
1002 term = reduce_dot_recursive(expr);
1003 symtab_pop();
1004 /* Construct sum */
1005 offset = astnode_create_arithmetic(
1006 PLUS_OPERATOR,
1007 offset,
1008 term,
1009 expr->loc
1012 return offset;
1016 * Transforms A.B.C.D . ... to A + offset(B) + offset(C) + ...
1017 * No error checking, since validate_dotref() should have been called previously.
1018 * @param expr Node of type DOT_NODE
1020 static astnode *reduce_dot(astnode *expr)
1022 symtab_entry *father;
1023 symtab_entry *def;
1024 astnode *type;
1025 astnode *left;
1026 astnode *term1;
1027 astnode *term2;
1028 astnode *sum;
1029 astnode *index = NULL;
1030 /* Look up parent in global symbol table */
1031 left = LHS(expr); /* expr := left . right */
1032 if (astnode_is_type(left, INDEX_NODE)) {
1033 index = RHS(left);
1034 left = LHS(left); /* Need identifier */
1036 father = symtab_lookup(left->ident);
1037 /* Look up variable's type definition */
1038 type = LHS(father->def); /* DATATYPE_NODE */
1039 def = symtab_lookup(LHS(type)->ident);
1040 /* 1st term of sum is the leftmost structure identifier */
1041 term1 = astnode_clone(left, left->loc);
1042 if (index != NULL) {
1043 /* Create expression: identifier + sizeof(datatype) * index */
1044 term1 = astnode_create_arithmetic(
1045 PLUS_OPERATOR,
1046 term1,
1047 astnode_create_arithmetic(
1048 MUL_OPERATOR,
1049 astnode_create_sizeof(astnode_clone(type, type->loc), expr->loc),
1050 astnode_clone(index, index->loc),
1051 index->loc
1053 expr->loc
1056 /* Add offsets recursively */
1057 symtab_push(def->symtab);
1058 term2 = reduce_dot_recursive(expr);
1059 symtab_pop();
1060 /* Calculate final sum */
1061 sum = astnode_create_arithmetic(
1062 PLUS_OPERATOR,
1063 term1,
1064 term2,
1065 expr->loc
1067 sum = reduce_expression(sum);
1068 /* Replace dotted expression by sum */
1069 astnode_replace(expr, sum);
1070 astnode_finalize(expr);
1071 return sum;
1075 * Reduces MASK operation to a field mask.
1076 * @param mask A node of type MASK_NODE
1078 static astnode *reduce_mask(astnode *mask)
1080 symtab_entry *ns;
1081 symtab_entry *sym;
1082 astnode *c;
1083 astnode *namespace;
1084 astnode *symbol;
1085 astnode *expr;
1086 /* Child is a scope node, record::field */
1087 expr = LHS(mask);
1088 /* Look up the namespace */
1089 namespace = LHS(expr);
1090 ns = symtab_lookup(namespace->ident);
1091 if (ns != NULL) {
1092 /* Make sure it's a record */
1093 if (ns->type != RECORD_SYMBOL) {
1094 err(expr->loc, "`%s' is not a record");
1095 /* Replace by 0 */
1096 c = astnode_create_integer(0, expr->loc);
1097 astnode_replace(mask, c);
1098 astnode_finalize(mask);
1099 expr = c;
1101 else {
1102 /* Look up the local symbol */
1103 symtab_push(ns->symtab);
1104 symbol = RHS(expr);
1105 sym = symtab_lookup(symbol->ident);
1106 if (sym != NULL) {
1107 /* Calculate field mask */
1108 // mask = ((1 << width) - 1) << offset
1109 c = astnode_create_arithmetic(
1110 SHL_OPERATOR,
1111 astnode_create_arithmetic(
1112 MINUS_OPERATOR,
1113 astnode_create_arithmetic(
1114 SHL_OPERATOR,
1115 astnode_create_integer(1, expr->loc),
1116 astnode_clone(sym->field.size, expr->loc),
1117 expr->loc
1119 astnode_create_integer(1, expr->loc),
1120 expr->loc
1122 astnode_clone(sym->field.offset, expr->loc),
1123 expr->loc
1125 c = reduce_expression(c);
1126 astnode_replace(mask, c);
1127 astnode_finalize(mask);
1128 expr = c;
1130 symtab_pop();
1133 return expr;
1137 * Reduces identifier[expression] to identifier + sizeof(identifier type) * expression
1139 static astnode *reduce_index(astnode *expr)
1141 symtab_entry *e;
1142 astnode *c;
1143 astnode *type;
1144 astnode *id;
1145 astnode *index;
1146 id = LHS(expr);
1147 index = reduce_expression(RHS(expr));
1148 /* Lookup identifier */
1149 e = symtab_lookup(id->ident);
1150 /* Get its datatype */
1151 type = LHS(e->def);
1152 /* Create expression: identifier + sizeof(datatype) * index */
1153 c = astnode_create_arithmetic(
1154 PLUS_OPERATOR,
1155 astnode_clone(id, id->loc),
1156 astnode_create_arithmetic(
1157 MUL_OPERATOR,
1158 astnode_create_sizeof(astnode_clone(type, type->loc), expr->loc),
1159 astnode_clone(index, index->loc),
1160 index->loc
1162 expr->loc
1164 /* Replace index expression */
1165 astnode_replace(expr, c);
1166 astnode_finalize(expr);
1167 /* Return the new expression */
1168 return c;
1172 * Substitutes all identifiers that represent EQU defines with their
1173 * corresponding expression.
1174 * @param expr The expression whose defines to substitute
1176 static astnode *substitute_defines(astnode *expr)
1178 switch (astnode_get_type(expr)) {
1179 case ARITHMETIC_NODE:
1180 substitute_defines(LHS(expr));
1181 substitute_defines(RHS(expr));
1182 break;
1184 case IDENTIFIER_NODE:
1185 expr = substitute_ident(expr);
1186 break;
1188 case SIZEOF_NODE:
1189 expr = reduce_sizeof(expr);
1190 break;
1192 case MASK_NODE:
1193 expr = reduce_mask(expr);
1194 break;
1196 case INDEX_NODE:
1197 substitute_defines(LHS(expr));
1198 substitute_defines(RHS(expr));
1199 break;
1201 case DOT_NODE:
1202 substitute_defines(LHS(expr));
1203 substitute_defines(RHS(expr));
1204 break;
1206 default:
1207 /* Nada */
1208 break;
1210 return expr;
1216 static astnode *reduce_highlevel_constructs(astnode *expr)
1218 switch (astnode_get_type(expr)) {
1219 case ARITHMETIC_NODE:
1220 reduce_highlevel_constructs(LHS(expr));
1221 reduce_highlevel_constructs(RHS(expr));
1222 break;
1224 case SCOPE_NODE:
1225 expr = reduce_scope(expr);
1226 break;
1228 case DOT_NODE:
1229 expr = reduce_dot(expr);
1230 break;
1232 case INDEX_NODE:
1233 expr = reduce_index(expr);
1234 break;
1236 default:
1237 /* Nada */
1238 break;
1240 return expr;
1244 * Really reduces an expression.
1245 * @param expr Expression to attempt to reduce
1247 static astnode *reduce_expression_complete(astnode *expr)
1249 return astproc_fold_constants( reduce_highlevel_constructs( substitute_defines(expr) ) );
1253 * Reduces an expression.
1254 * It does two things:
1255 * 1. Substitute all equates by their value
1256 * 2. Folds constants in the resulting expression
1257 * If the expression is reduced, the original expression is replaced by the
1258 * new one, the original is finalized, and a pointer to the new expression
1259 * is returned.
1260 * If the expression is not reduced, the original pointer is returned.
1262 static astnode *reduce_expression(astnode *expr)
1264 return astproc_fold_constants( substitute_defines(expr) );
1268 * Reduces RECORD instance to a single byte (DB statement).
1269 * @param r Record's symbol table entry
1270 * @param expr Record initializer
1271 * @param flat List on which to append the reduced form
1273 static void reduce_record(symtab_entry *r, astnode *init, astnode *flat)
1275 ordered_field_list *list;
1276 symtab_entry *e;
1277 astnode *val;
1278 astnode *term;
1279 astnode *result;
1280 astnode *mask;
1281 astnode *repl;
1282 /* Validate initializer */
1283 if (!astnode_is_type(init, STRUC_NODE)) {
1284 err(init->loc, "record initializer expected");
1285 return;
1287 /* Go through fields */
1288 symtab_push(r->symtab);
1289 result = astnode_create_integer(0, init->loc);
1290 for (val = init->first_child, list = r->struc.fields; (val != NULL) && (list != NULL); list = list->next, val = val->next_sibling) {
1291 if (astnode_is_type(val, NULL_NODE)) {
1292 continue;
1294 if (astnode_is_type(val, STRUC_NODE)) {
1295 err(init->loc, "record field initializer expected");
1296 continue;
1298 /* Get field definition */
1299 e = list->entry;
1300 /* Calculate field mask */
1301 // mask = ((1 << width) - 1) << offset
1302 mask = astnode_create_arithmetic(
1303 SHL_OPERATOR,
1304 astnode_create_arithmetic(
1305 MINUS_OPERATOR,
1306 astnode_create_arithmetic(
1307 SHL_OPERATOR,
1308 astnode_create_integer(1, val->loc),
1309 astnode_clone(e->field.size, val->loc),
1310 val->loc
1312 astnode_create_integer(1, val->loc),
1313 val->loc
1315 astnode_clone(e->field.offset, val->loc),
1316 val->loc
1318 /* Shift val left e->field.offset bits, AND with mask */
1319 term = astnode_create_arithmetic(
1320 AND_OPERATOR,
1321 astnode_create_arithmetic(
1322 SHL_OPERATOR,
1323 astnode_clone(val, val->loc),
1324 astnode_clone(e->field.offset, val->loc),
1325 val->loc
1327 mask,
1328 val->loc
1330 /* OR the value with the result so far */
1331 result = astnode_create_arithmetic(
1332 OR_OPERATOR,
1333 result,
1334 term,
1335 val->loc
1337 result = reduce_expression(result);
1339 /* Determine reason for stopping loop */
1340 if (val != NULL) {
1341 err(init->loc, "too many field initializers");
1343 /* Make byte data node (packed record value) */
1344 repl = astnode_create_data(
1345 astnode_create_datatype(BYTE_DATATYPE, NULL, init->loc),
1346 result,
1347 init->loc
1349 /* Add to list */
1350 astnode_add_child(flat, repl);
1351 /* Restore old symbol table */
1352 symtab_pop();
1356 * Reduces ENUM instance to DB.
1357 * @param e Enumeration's symbol table entry
1358 * @param expr Expression
1359 * @param flat List on which to append the reduced form
1361 static void reduce_enum(symtab_entry *e, astnode *expr, astnode *list)
1363 symtab_entry *sym;
1364 astnode *repl;
1365 if (!astnode_is_type(expr, IDENTIFIER_NODE)) {
1366 err(expr->loc, "identifier expected");
1368 else {
1369 /* Look up the enumeration symbol */
1370 symtab_push(e->symtab);
1371 sym = symtab_lookup(expr->ident);
1372 symtab_pop();
1373 /* Make byte data node (symbol value) */
1374 repl = astnode_create_data(
1375 astnode_create_datatype(BYTE_DATATYPE, NULL, expr->loc),
1376 astnode_clone(sym->def, expr->loc),
1377 expr->loc
1379 /* Add to list */
1380 astnode_add_child(list, repl);
1384 static void flatten_struc_recursive(symtab_entry *s, astnode *init, astnode *flat);
1387 * Flattens a union initializer to a sequence of native data values.
1388 * Verify similar to flattening of structure, but only single field allowed.
1389 * @param s Union's symbol table definition
1390 * @param init Union initializer
1391 * @param flat List on which to append the flattened form
1393 static void flatten_union_recursive(symtab_entry *s, astnode *init, astnode *flat)
1395 astnode *fill;
1396 astnode *type;
1397 astnode *count;
1398 symtab_entry *e;
1399 symtab_entry *t;
1400 astnode *val;
1401 astnode *valvals;
1402 astnode *temp;
1403 ordered_field_list *list;
1404 int num;
1405 /* Validate initializer */
1406 if (!astnode_is_type(init, STRUC_NODE)) {
1407 err(init->loc, "union initializer expected");
1408 return;
1410 /* Go through fields */
1411 symtab_push(s->symtab);
1412 fill = astnode_clone(s->struc.size, flat->loc);
1413 for (val = init->first_child, list = s->struc.fields; (val != NULL) && (list != NULL); list = list->next, val = val->next_sibling) {
1414 if (astnode_is_type(val, NULL_NODE)) {
1415 continue;
1417 if (!astnode_equal(fill, s->struc.size)) {
1418 err(init->loc, "only one field of union can be initialized");
1419 continue;
1421 /* Get field definition */
1422 e = list->entry;
1423 /* Symbol definition is STORAGE_NODE w/ two children: type and count */
1424 type = LHS(e->def);
1425 count = RHS(e->def);
1426 /* Decide what to do based on field type and value */
1427 switch (type->datatype) {
1428 case BYTE_DATATYPE:
1429 case CHAR_DATATYPE:
1430 case WORD_DATATYPE:
1431 case DWORD_DATATYPE:
1432 if (astnode_is_type(val, STRUC_NODE)) {
1433 /* Handle multi-value array */
1434 temp = astnode_clone(val, val->loc);
1435 valvals = astnode_remove_children(temp);
1436 astnode_finalize(temp);
1437 astnode_add_child(flat,
1438 astnode_create_data(
1439 astnode_create_datatype(type->datatype, NULL, type->loc),
1440 valvals,
1441 val->loc
1444 num = astnode_get_child_count(val);
1445 } else {
1446 /* Output single value */
1447 astnode_add_child(flat,
1448 astnode_create_data(
1449 astnode_create_datatype(type->datatype, NULL, type->loc),
1450 astnode_clone(val, val->loc),
1451 val->loc
1454 num = astnode_is_type(val, STRING_NODE) ? strlen(val->string) : 1;
1456 if (num > count->integer) {
1457 err(val->loc, "initializer for field `%s' exceeds field size", e->id);
1459 /* Fill in remainder of field if necessary: count - 1 */
1460 else if (count->integer > num) {
1461 astnode_add_child(flat,
1462 astnode_create_storage(
1463 astnode_create_datatype(type->datatype, NULL, type->loc),
1464 astproc_fold_constants(
1465 astnode_create_arithmetic(
1466 MINUS_OPERATOR,
1467 astnode_clone(count, count->loc),
1468 astnode_create_integer(num, flat->loc),
1469 count->loc
1472 val->loc
1476 break;
1478 case USER_DATATYPE:
1479 /* Look up user type definition */
1480 t = symtab_global_lookup(LHS(type)->ident);
1481 switch (t->type) {
1482 case STRUC_SYMBOL:
1483 flatten_struc_recursive(t, val, flat);
1484 break;
1486 case UNION_SYMBOL:
1487 flatten_union_recursive(t, val, flat);
1488 break;
1490 case RECORD_SYMBOL:
1491 reduce_record(t, val, flat);
1492 break;
1494 case ENUM_SYMBOL:
1495 reduce_enum(t, val, flat);
1496 break;
1498 default:
1499 break;
1501 break;
1503 /* Decrease fill amount according to field size */
1504 fill = astproc_fold_constants(
1505 astnode_create_arithmetic(
1506 MINUS_OPERATOR,
1507 fill,
1508 astnode_clone(e->field.size, flat->loc),
1509 flat->loc
1513 /* Determine reason for stopping loop */
1514 if (val != NULL) {
1515 err(init->loc, "too many field initializers");
1517 if (fill->integer > 0) {
1518 /* Fill remainder of union with zeroes */
1519 astnode_add_child(flat,
1520 astnode_create_storage(
1521 astnode_create_datatype(BYTE_DATATYPE, NULL, flat->loc),
1522 fill,
1523 flat->loc
1527 symtab_pop();
1531 * Flattens a structure initializer to a sequence of native data values.
1532 * @param s Structure's symbol table definition
1533 * @param init Structure initializer
1534 * @param flat List on which to append the flattened form
1536 static void flatten_struc_recursive(symtab_entry *s, astnode *init, astnode *flat)
1538 astnode *fill;
1539 astnode *type;
1540 astnode *count;
1541 astnode *temp;
1542 symtab_entry *e;
1543 symtab_entry *t;
1544 astnode *val;
1545 astnode *valvals;
1546 ordered_field_list *list;
1547 int num;
1548 /* Validate initializer */
1549 if (!astnode_is_type(init, STRUC_NODE)) {
1550 err(init->loc, "structure initializer expected");
1551 return;
1553 /* Go through fields */
1554 symtab_push(s->symtab);
1555 fill = astnode_clone(s->struc.size, flat->loc);
1556 for (val = init->first_child, list = s->struc.fields; (val != NULL) && (list != NULL); list = list->next, val = val->next_sibling) {
1557 /* Get field definition */
1558 e = list->entry;
1559 /* Check if normal field or anonymous union */
1560 if (e->type == UNION_SYMBOL) {
1561 if (astnode_is_type(val, NULL_NODE)) {
1562 /* Output union size bytes to fill in field */
1563 astnode_add_child(flat,
1564 astnode_create_storage(
1565 astnode_create_datatype(BYTE_DATATYPE, NULL, val->loc),
1566 astnode_clone(e->struc.size, val->loc),
1567 val->loc
1570 } else {
1571 flatten_union_recursive(e, val, flat);
1572 /* Decrease fill amount according to union size */
1573 fill = astproc_fold_constants(
1574 astnode_create_arithmetic(
1575 MINUS_OPERATOR,
1576 fill,
1577 astnode_clone(e->struc.size, flat->loc),
1578 flat->loc
1582 } else {
1583 /* VAR_SYMBOL */
1584 /* Symbol definition is STORAGE_NODE w/ two children: type and count */
1585 type = LHS(e->def);
1586 count = RHS(e->def);
1587 /* Decide what to do based on field type and value */
1588 switch (type->datatype) {
1589 case BYTE_DATATYPE:
1590 case CHAR_DATATYPE:
1591 case WORD_DATATYPE:
1592 case DWORD_DATATYPE:
1593 if (astnode_is_type(val, NULL_NODE)) {
1594 /* Output field_size bytes to fill in field */
1595 astnode_add_child(flat,
1596 astnode_create_storage(
1597 astnode_create_datatype(type->datatype, NULL, type->loc),
1598 astnode_clone(count, count->loc),
1599 val->loc
1602 } else {
1603 if (astnode_is_type(val, STRUC_NODE)) {
1604 /* Handle multi-value array */
1605 temp = astnode_clone(val, val->loc);
1606 valvals = astnode_remove_children(temp);
1607 astnode_finalize(temp);
1608 astnode_add_child(flat,
1609 astnode_create_data(
1610 astnode_create_datatype(type->datatype, NULL, type->loc),
1611 valvals,
1612 val->loc
1615 num = astnode_get_child_count(val);
1616 } else {
1617 /* Output single value */
1618 astnode_add_child(flat,
1619 astnode_create_data(
1620 astnode_create_datatype(type->datatype, NULL, type->loc),
1621 astnode_clone(val, val->loc),
1622 val->loc
1625 num = astnode_is_type(val, STRING_NODE) ? strlen(val->string) : 1;
1627 if (astnode_is_type(count, INTEGER_NODE) && (count->integer < num)) {
1628 err(val->loc, "initializer for field `%s' exceeds field size", e->id);
1630 /* Fill in remainder of field if necessary: count - 1 */
1631 else if ( (astnode_is_type(count, INTEGER_NODE) && (count->integer > num))
1632 || !astnode_is_type(count, INTEGER_NODE) ) {
1633 astnode_add_child(flat,
1634 astnode_create_storage(
1635 astnode_create_datatype(type->datatype, NULL, flat->loc),
1636 astproc_fold_constants(
1637 astnode_create_arithmetic(
1638 MINUS_OPERATOR,
1639 astnode_clone(count, flat->loc),
1640 astnode_create_integer(num, flat->loc),
1641 flat->loc
1644 flat->loc
1649 break;
1651 case USER_DATATYPE:
1652 /* Look up user type definition */
1653 t = symtab_global_lookup(LHS(type)->ident);
1654 if (astnode_is_type(val, NULL_NODE)) {
1655 /* Output sizeof(type) bytes to fill in */
1656 astnode_add_child(flat,
1657 astnode_create_storage(
1658 astnode_create_datatype(BYTE_DATATYPE, NULL, val->loc),
1659 astnode_clone(t->struc.size, val->loc),
1660 val->loc
1663 } else {
1664 switch (t->type) {
1665 case STRUC_SYMBOL:
1666 flatten_struc_recursive(t, val, flat);
1667 break;
1669 case UNION_SYMBOL:
1670 flatten_union_recursive(t, val, flat);
1671 break;
1673 case RECORD_SYMBOL:
1674 reduce_record(t, val, flat);
1675 break;
1677 case ENUM_SYMBOL:
1678 reduce_enum(t, val, flat);
1679 break;
1681 default:
1682 break;
1685 break;
1687 /* Decrease fill amount according to field size */
1688 fill = astproc_fold_constants(
1689 astnode_create_arithmetic(
1690 MINUS_OPERATOR,
1691 fill,
1692 astnode_clone(e->field.size, flat->loc),
1693 flat->loc
1698 /* Determine reason for stopping loop */
1699 if (val != NULL) {
1700 err(init->loc, "too many field initializers");
1702 else if (list != NULL) {
1703 /* All fields not initialized; fill remainder of struc with zeroes */
1704 astnode_add_child(flat,
1705 astnode_create_storage(
1706 astnode_create_datatype(BYTE_DATATYPE, NULL, flat->loc),
1707 fill,
1708 flat->loc
1711 } else {
1712 astnode_finalize(fill);
1714 symtab_pop();
1718 * Converts data that is expressed in a high-level form (such as structure initializers)
1719 * to a simple sequence of bytes.
1720 * @param n The source node to flatten
1721 * @param type The type of data that n is an instance of
1722 * @param list List on which to append the resulting sequence of items (bytes/words/dwords)
1724 static void flatten_user_data(astnode *n, astnode *type, astnode *list)
1726 symtab_entry *def;
1727 /* Look up type definition */
1728 def = symtab_global_lookup(LHS(type)->ident);
1729 if (def != NULL) {
1730 switch (def->type) {
1731 case STRUC_SYMBOL:
1732 /* Flatten structure initializer to series of simple data statements */
1733 flatten_struc_recursive(def, n, list);
1734 break;
1736 case UNION_SYMBOL:
1737 /* Flatten union initializer to series of simple data statements */
1738 flatten_union_recursive(def, n, list);
1739 break;
1741 case RECORD_SYMBOL:
1742 reduce_record(def, n, list);
1743 break;
1745 case ENUM_SYMBOL:
1746 reduce_enum(def, n, list);
1747 break;
1749 default:
1750 break;
1755 /*---------------------------------------------------------------------------*/
1758 * Loads the character map specified by the node.
1759 * @param n Node of type CHARMAP_NODE
1761 static int load_charmap(astnode *n, void *arg, astnode **next)
1763 /* TODO: should probably be done in the parsing phase (same path resolution as for INCSRC and INCBIN) */
1764 astnode *file;
1765 /* Get file descriptor */
1766 file = astnode_get_child(n, 0);
1767 /* Try to load the charmap */
1768 if (charmap_parse(file->file_path, charmap) == 0) {
1769 err(n->loc, "could not open `%s' for reading", file->file_path);
1771 return 0;
1775 * First-time processing of instruction node.
1776 * @param n Node of type INSTRUCTION_NODE
1777 * @param arg Not used
1779 static int process_instruction(astnode *n, void *arg, astnode **next)
1781 astnode *expr;
1782 if (in_dataseg) {
1783 err(n->loc, "instructions not allowed in data segment");
1784 /* Remove from AST */
1785 astnode_remove(n);
1786 astnode_finalize(n);
1787 return 0;
1789 else {
1790 /* The instruction operand */
1791 expr = astnode_get_child(n, 0);
1792 /* Substitute defines and fold constants */
1793 reduce_expression(expr);
1794 return 1;
1799 * First-time processing of data node.
1800 * @param n Node of type DATA_NODE
1801 * @param arg Not used
1803 static int process_data(astnode *n, void *arg, astnode **next)
1805 int j;
1806 int k;
1807 astnode *type;
1808 astnode *expr;
1809 astnode *list;
1810 astnode *stmts;
1811 type = astnode_get_child(n, 0);
1812 assert(astnode_is_type(type, DATATYPE_NODE));
1813 if (in_dataseg) {
1814 err(n->loc, "value not allowed in data segment");
1815 /* Replace with storage node */
1816 astnode_replace(
1818 astnode_create_storage(
1819 astnode_create_datatype(BYTE_DATATYPE, NULL, n->loc),
1820 astnode_create_integer(1, n->loc),
1821 n->loc
1824 astnode_finalize(n);
1825 return 0;
1827 if (type->datatype == USER_DATATYPE) {
1828 /* Make sure the type exists */
1829 if (symtab_global_lookup(LHS(type)->ident) == NULL) {
1830 err(n->loc, "unknown type `%s'", LHS(type)->ident);
1831 /* Remove from AST */
1832 astnode_remove(n);
1833 astnode_finalize(n);
1834 return 0;
1835 } else {
1836 /* Attempt to reduce user data to native data */
1837 list = astnode_create(LIST_NODE, n->loc);
1838 for (expr = type->next_sibling; expr != NULL; expr = expr->next_sibling) {
1839 flatten_user_data(expr, type, list);
1841 /* Replace initializers with generated list */
1842 stmts = astnode_remove_children(list);
1843 astnode_replace(n, stmts);
1844 astnode_finalize(n);
1845 astnode_finalize(list);
1846 *next = stmts;
1847 return 0;
1850 /* Go through the list of data values, replacing defines and folding constants */
1851 for (j=1; j<astnode_get_child_count(n); j++) {
1852 expr = astnode_get_child(n, j);
1853 /* Substitute defines and fold constants */
1854 expr = reduce_expression(expr);
1855 /* If it's a string, replace by array of integers */
1856 /* (makes it easier to process later... favour regularity) */
1857 if (astnode_is_type(expr, STRING_NODE)) {
1858 astnode_remove_child(n, expr); /* Remove string */
1859 for (k=strlen(expr->string)-1; k>=0; k--) {
1860 /* Check if we should map character from custom charmap */
1861 if (type->datatype == CHAR_DATATYPE) {
1862 expr->string[k] = charmap[(unsigned)expr->string[k]];
1864 /* Append character value to array */
1865 astnode_insert_child(n, astnode_create_integer((unsigned char)expr->string[k], n->loc), j);
1867 if (type->datatype == CHAR_DATATYPE) {
1868 /* It's normal byte array now */
1869 type->datatype = BYTE_DATATYPE;
1871 j += strlen(expr->string)-1;
1872 astnode_finalize(expr);
1875 return 1;
1879 * First-time processing of storage node.
1880 * @param n Node of type STORAGE_NODE
1881 * @param arg Not used
1883 static int process_storage(astnode *n, void *arg, astnode **next)
1885 int item_size;
1886 astnode *type;
1887 astnode *expr;
1888 astnode *new_expr;
1889 type = LHS(n);
1890 expr = RHS(n);
1891 /* If not BYTE_DATATYPE, multiply by word/dword-size */
1892 switch (type->datatype) {
1893 case BYTE_DATATYPE:
1894 case CHAR_DATATYPE: item_size = 1; break;
1895 case WORD_DATATYPE: item_size = 2; break;
1896 case DWORD_DATATYPE: item_size = 4; break;
1897 default: item_size = 1; break; // ### Hmmm...
1899 if (item_size != 1) {
1900 new_expr = astnode_create_arithmetic(
1901 MUL_OPERATOR,
1902 astnode_clone(expr, expr->loc),
1903 astnode_create_integer(item_size, expr->loc),
1904 expr->loc
1906 astnode_replace(expr, new_expr);
1907 astnode_finalize(expr);
1908 expr = new_expr;
1909 type->datatype = BYTE_DATATYPE;
1911 /* Substitute defines and fold constants */
1912 expr = reduce_expression(expr);
1913 // TODO: Validate range somewhere else than here please... ???
1914 if (astnode_is_type(expr, INTEGER_NODE)) {
1915 if ((expr->integer <= 0) || (expr->integer >= 0x10000)) {
1916 err(n->loc, "operand out of range");
1919 return 1;
1923 * Process EQU node.
1924 * @param n Node of type EQU_NODE
1925 * @param arg Not used
1927 static int process_equ(astnode *n, void *arg, astnode **next)
1929 symtab_entry *e;
1930 astnode *id;
1931 astnode *expr;
1932 /* The expression which describes the value */
1933 expr = astnode_clone(astnode_get_child(n, 1), n->loc);
1934 /* Substitute defines and fold constants */
1935 expr = reduce_expression(expr);
1936 /* The identifier which is being defined */
1937 id = astnode_get_child(n, 0);
1938 /* Look up in symbol table */
1939 e = symtab_lookup(id->ident);
1940 if (e == NULL) {
1941 /* Symbol is being defined */
1942 // TODO: Check that expression is a constant?
1943 /* Enter it in symbol table */
1944 symtab_enter(id->ident, CONSTANT_SYMBOL, expr, 0);
1945 } else {
1946 /* Symbol is being redefined */
1947 /* This is not allowed for EQU equate! */
1948 if (!astnode_equal((astnode *)(e->def), expr)) {
1949 warn(n->loc, "redefinition of `%s' is not identical; ignored", id->ident);
1952 /* Remove the equate node from the tree. */
1953 astnode_remove(n);
1954 astnode_finalize(n);
1955 return 0;
1959 * Process '=' node.
1960 * @param n Node of type ASSIGN_NODE
1961 * @param arg Not used
1963 static int process_assign(astnode *n, void *arg, astnode **next)
1965 symtab_entry *e;
1966 astnode *id;
1967 astnode *expr;
1968 /* If it's part of ENUM declaration, don't touch */
1969 if (astnode_has_ancestor_of_type(n, ENUM_DECL_NODE)) {
1970 return 0;
1972 /* Very similar to EQU, except symbol 1) can be
1973 redefined and 2) is volatile (see end of proc) */
1974 /* The expression which describes the value */
1975 expr = astnode_clone(astnode_get_child(n, 1), n->loc);
1976 /* Substitute defines and fold constants */
1977 expr = reduce_expression(expr);
1978 /* The identifier which is being (re)defined */
1979 id = astnode_get_child(n, 0);
1980 /* Look up in symbol table */
1981 e = symtab_lookup(id->ident);
1982 if (e == NULL) {
1983 /* Symbol is being defined for the first time */
1984 /* Note that the VOLATILE_FLAG is set */
1985 symtab_enter(id->ident, CONSTANT_SYMBOL, expr, VOLATILE_FLAG);
1986 } else {
1987 /* Symbol is being redefined */
1988 /* This is OK for ASSIGN equate, simply replace definition */
1989 // ### store a list of definitions
1990 expr->loc = e->def->loc;
1991 e->def = expr;
1993 /* Remove the equate node from the tree. */
1994 astnode_remove(n);
1995 astnode_finalize(n);
1996 return 0;
2000 * Process IFDEF-node.
2001 * @param n Node of type IFDEF_NODE
2002 * @param arg Not used
2004 static int process_ifdef(astnode *n, void *arg, astnode **next)
2006 symtab_entry *e;
2007 astnode *id;
2008 astnode *stmts;
2009 /* The identifier which is being tested */
2010 id = astnode_get_child(n, 0);
2011 e = symtab_lookup(id->ident);
2012 if (e != NULL) {
2013 /* Symbol is defined. */
2014 /* Replace IFDEF node by the true-branch statement list */
2015 stmts = astnode_remove_children(astnode_get_child(n, 1));
2016 astnode_replace(n, stmts);
2017 *next = stmts;
2018 } else {
2019 /* Symbol is not defined. */
2020 /* Replace IFDEF node by the false-branch statement list (if any) */
2021 stmts = astnode_remove_children( astnode_get_child(n, 2));
2022 if (stmts != NULL) {
2023 astnode_replace(n, stmts);
2024 *next = stmts;
2025 } else {
2026 astnode_remove(n);
2029 /* Discard the original node */
2030 astnode_finalize(n);
2031 return 0;
2035 * Process IFNDEF-node.
2036 * @param n Node of type IFNDEF_NODE
2037 * @param arg Not used
2039 static int process_ifndef(astnode *n, void *arg, astnode **next)
2041 symtab_entry *e;
2042 astnode *id;
2043 astnode *stmts;
2044 /* The identifier which is being tested */
2045 id = astnode_get_child(n, 0);
2046 e = symtab_lookup(id->ident);
2047 if (e == NULL) {
2048 /* Symbol is not defined. */
2049 /* Replace IFNDEF node by the true-branch statement list */
2050 stmts = astnode_remove_children(astnode_get_child(n, 1));
2051 astnode_replace(n, stmts);
2052 *next = stmts;
2053 } else {
2054 /* Symbol is defined. */
2055 /* Replace IFNDEF node by the false-branch statement list, if any */
2056 stmts = astnode_remove_children(astnode_get_child(n, 2));
2057 if (stmts != NULL) {
2058 astnode_replace(n, stmts);
2059 *next = stmts;
2060 } else {
2061 astnode_remove(n);
2064 /* Discard the original node */
2065 astnode_finalize(n);
2066 return 0;
2070 * Process IF-node.
2071 * @param n Node of type IF_NODE
2072 * @param arg Not used
2074 static int process_if(astnode *n, void *arg, astnode **next)
2076 astnode *expr;
2077 astnode *stmts;
2078 astnode *c;
2079 int ret = 0;
2080 /* IF_NODE has a list of CASE, DEFAULT nodes as children */
2081 for (c = astnode_get_first_child(n); c != NULL; c = astnode_get_next_sibling(c) ) {
2082 if (astnode_is_type(c, CASE_NODE)) {
2083 /* The expression which is being tested */
2084 expr = astnode_get_child(c, 0);
2085 /* Try to reduce expression to literal */
2086 expr = reduce_expression(expr);
2087 /* Resulting expression must be an integer literal,
2088 since this is static evaluation.
2089 In other words, it can't contain label references.
2091 if (astnode_is_type(expr, INTEGER_NODE)) {
2092 /* Non-zero is true, zero is false */
2093 if (expr->integer) {
2094 /* Replace IF node by the true-branch statement list */
2095 stmts = astnode_remove_children( astnode_get_child(c, 1) );
2096 astnode_replace(n, stmts);
2097 astnode_finalize(n);
2098 *next = stmts;
2099 return ret;
2101 } else {
2102 /* Error, expression is not constant */
2103 err(expr->loc, "conditional expression does not evaluate to literal");
2105 } else { /* DEFAULT_NODE */
2106 /* Replace IF node by the false-branch statement list */
2107 stmts = astnode_remove_children(c);
2108 astnode_replace(n, stmts);
2109 astnode_finalize(n);
2110 *next = stmts;
2111 return ret;
2114 /* No match, remove IF node from AST */
2115 astnode_remove(n);
2116 astnode_finalize(n);
2117 return ret;
2121 * Process dataseg-node.
2122 * @param n Node of type DATASEG_NODE
2123 * @param arg Not used
2125 static int process_dataseg(astnode *n, void *arg, astnode **next)
2127 modifiers = n->modifiers;
2128 in_dataseg = 1; /* true */
2129 return 0;
2133 * Process codeseg-node.
2134 * @param n Node of type CODESEG_NODE
2135 * @param arg Not used
2137 static int process_codeseg(astnode *n, void *arg, astnode **next)
2139 modifiers = 0;
2140 in_dataseg = 0; /* false */
2141 return 0;
2145 * Process org-node.
2146 * @param n Node of type ORG_NODE
2147 * @param arg Not used
2149 static int process_org(astnode *n, void *arg, astnode **next)
2151 if (!xasm_args.pure_binary) {
2152 err(n->loc, "org directive can only be used when output format is pure 6502 binary");
2153 } else {
2154 astnode *addr = astnode_get_child(n, 0);
2155 addr = reduce_expression_complete(addr);
2156 if (astnode_is_type(addr, INTEGER_NODE)) {
2157 /* Range check */
2158 if ((addr->integer < 0) || (addr->integer >= 0x10000)) {
2159 err(n->loc, "org address out of 64K range");
2161 } else {
2162 err(n->loc, "org address does not evaluate to literal");
2163 /* Remove from AST */
2164 astnode_remove(n);
2165 astnode_finalize(n);
2168 return 0;
2172 * Process REPT node.
2173 * @param n Node of type REPT_NODE
2174 * @param arg Not used
2176 static int process_rept(astnode *n, void *arg, astnode **next)
2178 astnode *count;
2179 astnode *stmts;
2180 astnode *list;
2181 /* The repeat count */
2182 count = astnode_get_child(n, 0);
2183 /* Try to reduce count expression to literal */
2184 count = reduce_expression_complete(count);
2185 /* Resulting expression must be an integer literal,
2186 since this is static evaluation.
2188 if (astnode_is_type(count, INTEGER_NODE)) {
2189 if (count->integer < 0) {
2190 warn(n->loc, "REPT ignored; negative repeat count (%d)", count->integer);
2191 /* Remove from AST */
2192 astnode_remove(n);
2193 astnode_finalize(n);
2194 } else if (count->integer > 0) {
2195 /* Expand body <count> times */
2196 list = astnode_clone(astnode_get_child(n, 1), n->loc);
2197 stmts = astnode_remove_children(list);
2198 astnode_finalize(list);
2199 while (--count->integer > 0) {
2200 list = astnode_clone(astnode_get_child(n, 1), n->loc);
2201 astnode_add_sibling(stmts, astnode_remove_children(list) );
2202 astnode_finalize(list);
2204 astnode_replace(n, stmts);
2205 astnode_finalize(n);
2206 *next = stmts;
2207 } else {
2208 /* count == 0, remove from AST */
2209 astnode_remove(n);
2210 astnode_finalize(n);
2212 } else {
2213 err(n->loc, "repeat count does not evaluate to literal");
2214 /* Remove from AST */
2215 astnode_remove(n);
2216 astnode_finalize(n);
2218 return 0;
2222 * Process WHILE node.
2223 * @param n Node of type WHILE_NODE
2224 * @param arg Not used
2226 static int process_while(astnode *n, void *arg, astnode **next)
2228 astnode *expr;
2229 astnode *stmts;
2230 astnode *list;
2231 /* The boolean expression */
2232 expr = astnode_get_child(n, 0);
2233 /* Try to reduce expression to literal */
2234 expr = reduce_expression(astnode_clone(expr, expr->loc));
2235 /* Resulting expression must be an integer literal,
2236 since this is static evaluation.
2238 if (astnode_is_type(expr, INTEGER_NODE)) {
2239 /* Expand body if the expression is true */
2240 if (expr->integer) {
2241 list = astnode_clone(astnode_get_child(n, 1), n->loc);
2242 stmts = astnode_remove_children(list);
2243 astnode_finalize(list);
2244 astnode_replace(n, stmts);
2245 astnode_add_sibling(stmts, n); /* Clever huh? */
2246 *next = stmts;
2247 } else {
2248 /* Remove WHILE node from AST */
2249 astnode_remove(n);
2250 astnode_finalize(n);
2252 } else {
2253 err(n->loc, "while expression does not evaluate to literal");
2254 /* Remove WHILE node from AST */
2255 astnode_remove(n);
2256 astnode_finalize(n);
2258 astnode_finalize(expr);
2259 return 0;
2262 /*---------------------------------------------------------------------------*/
2265 * Enters a macro into the symbol table.
2266 * @param n Must be a node of type MACRO_DECL_NODE
2267 * @param arg Not used
2269 static int enter_macro(astnode *n, void *arg, astnode **next)
2271 astnode *id = astnode_get_child(n, 0); /* Child 0 is macro identifier */
2272 assert(astnode_get_type(id) == IDENTIFIER_NODE);
2273 if (symtab_enter(id->ident, MACRO_SYMBOL, n, 0) == NULL) {
2274 /* ### This could be allowed, you know... */
2275 err(n->loc, "duplicate symbol `%s'", id->ident);
2277 /* Remove from AST */
2278 astnode_remove(n);
2279 // ### n is not finalized???
2280 return 0;
2284 * Enters a label into the symbol table.
2285 * @param n Must be a node of type LABEL_NODE
2287 static int enter_label(astnode *n, void *arg, astnode **next)
2289 symtab_entry *e;
2290 astnode *addr;
2291 /* Make sure it's unique first */
2292 if (symtab_lookup(n->ident)) {
2293 err(n->loc, "duplicate symbol `%s'", n->ident);
2294 /* Remove from AST */
2295 astnode_remove(n);
2296 astnode_finalize(n);
2297 } else {
2298 /* Enter it! */
2299 e = symtab_enter(n->ident, LABEL_SYMBOL, n, (in_dataseg ? DATA_FLAG : 0) | modifiers );
2300 /* Check if hardcoded address */
2301 addr = reduce_expression_complete(RHS(n));
2302 if (astnode_is_type(addr, INTEGER_NODE)) {
2303 /* Store it */
2304 e->address = addr->integer;
2305 e->flags |= ADDR_FLAG;
2306 } else if (!astnode_is_type(addr, CURRENT_PC_NODE)) {
2307 err(n->loc, "label address does not evaluate to literal");
2309 /* Increase namespace counter */
2310 label_count++;
2312 /* */
2313 return 0;
2317 * Enters a variable declaration in symbol table.
2318 * @param n Must be a node of type VAR_DECL_NODE
2320 static int enter_var(astnode *n, void *arg, astnode **next)
2322 astnode *id = LHS(n); /* Variable identifier */
2323 assert(astnode_get_type(id) == IDENTIFIER_NODE);
2324 /* Make sure it's unique first */
2325 if (symtab_lookup(id->ident)) {
2326 err(n->loc, "duplicate symbol `%s'", id->ident);
2327 /* Remove from AST */
2328 astnode_remove(n);
2329 astnode_finalize(n);
2330 return 0;
2331 } else {
2332 /* Validate modifiers */
2333 if ((n->modifiers & ZEROPAGE_FLAG) && !in_dataseg) {
2334 warn(n->loc, "zeropage modifier has no effect in code segment");
2335 n->modifiers &= ~ZEROPAGE_FLAG;
2337 /* Enter it! */
2338 symtab_enter(id->ident, VAR_SYMBOL, astnode_clone(RHS(n), n->loc), (in_dataseg ? DATA_FLAG : 0) | n->modifiers | modifiers);
2339 /* */
2340 return 1;
2345 * Enters a procedure declaration in symbol table.
2346 * @param n Must be a node of type PROC_NODE
2348 static int enter_proc(astnode *n, void *arg, astnode **next)
2350 astnode *id;
2351 if (in_dataseg) {
2352 err(n->loc, "procedures not allowed in data segment");
2353 /* Remove from AST */
2354 astnode_remove(n);
2355 astnode_finalize(n);
2356 return 0;
2358 id = LHS(n); /* Procedure identifier */
2359 assert(astnode_get_type(id) == IDENTIFIER_NODE);
2360 /* Make sure it's unique first */
2361 if (symtab_lookup(id->ident)) {
2362 err(n->loc, "duplicate symbol `%s'", id->ident);
2363 /* Remove from AST */
2364 astnode_remove(n);
2365 astnode_finalize(n);
2366 return 0;
2367 } else {
2368 /* Enter it! RHS(n) is the list of procedure statements */
2369 symtab_enter(id->ident, PROC_SYMBOL, RHS(n), (in_dataseg ? DATA_FLAG : 0) );
2370 /* Increase global namespace counter */
2371 label_count++;
2372 /* */
2373 return 1;
2378 * Enters a simple <identifier> <storage> structure member.
2379 * @param c Node of type VAR_DECL_NODE
2380 * @param offset Offset of this field
2381 * @param plist List of symbol table's entries
2382 * @param struc_id Structure identifier (for error messages)
2383 * @return New offset (old offset + size of this field)
2385 static astnode *enter_struc_atomic_field(astnode *c, astnode *offset, ordered_field_list ***plist, astnode *struc_id)
2387 astnode *field_id;
2388 astnode *field_data;
2389 astnode *field_size;
2390 symtab_entry *fe;
2391 /* c has two children: id and STORAGE_NODE */
2392 field_id = LHS(c);
2393 assert(astnode_get_type(field_id) == IDENTIFIER_NODE);
2394 field_data = RHS(c);
2395 reduce_expression(RHS(field_data));
2396 /* Validate the declaration -- no data initialized */
2397 if (astnode_is_type(field_data, DATA_NODE)) {
2398 err(c->loc, "data initialization not allowed here");
2399 return(offset);
2401 /* Try to enter field in structure's symbol table */
2402 fe = symtab_enter(
2403 field_id->ident,
2404 VAR_SYMBOL,
2405 astnode_clone(field_data, field_data->loc),
2408 if (fe == NULL) {
2409 err(c->loc, "duplicate symbol `%s' in structure `%s'", field_id->ident, struc_id->ident);
2410 return(offset);
2412 /* Add to ordered list of fields */
2413 (**plist) = malloc(sizeof(ordered_field_list));
2414 (**plist)->entry = fe;
2415 (**plist)->next = NULL;
2416 *plist = &((**plist)->next);
2417 /* Set field offset */
2418 fe->field.offset = astnode_clone(offset, offset->loc);
2419 /* Calculate field size in bytes: sizeof(datatype) * count */
2420 field_size = astnode_create_arithmetic(
2421 MUL_OPERATOR,
2422 astnode_create_sizeof(astnode_clone(LHS(field_data), field_data->loc), field_data->loc),
2423 astnode_clone(RHS(field_data), field_data->loc),
2424 field_data->loc
2426 field_size = reduce_expression(field_size);
2427 /* Set field size */
2428 fe->field.size = astnode_clone(field_size, field_size->loc);
2429 /* Add field size to total offset */
2430 offset = astnode_create_arithmetic(
2431 PLUS_OPERATOR,
2432 offset,
2433 field_size,
2434 offset->loc
2436 offset = reduce_expression(offset);
2437 return(offset);
2440 static void enter_union_fields(symtab_entry *, astnode *);
2443 * Attempts to enter an (anonymous) union's members into structure's symbol table.
2444 * @param n Node of type UNION_DECL_NODE
2445 * @param offset Current parent structure offset
2446 * @param plist Ordered list of parent structure's fields
2448 astnode *enter_struc_union_field(astnode *n, astnode *offset, ordered_field_list ***plist, astnode *struc_id)
2450 ordered_field_list *ls;
2451 symtab_entry *se;
2452 symtab_entry *fe;
2453 static int id = 0;
2454 char id_str[16];
2455 astnode *union_id;
2456 union_id = LHS(n);
2457 if (astnode_is_type(union_id, IDENTIFIER_NODE)) {
2458 err(n->loc, "anonymous union expected");
2459 return(offset);
2461 /* Put UNION in symbol table */
2462 snprintf(id_str, sizeof (id_str), "%d", id++);
2463 se = symtab_enter(id_str, UNION_SYMBOL, n, 0);
2464 enter_union_fields(se, n);
2465 /* Add to ordered list of fields */
2466 (**plist) = malloc(sizeof(ordered_field_list));
2467 (**plist)->entry = se;
2468 (**plist)->next = NULL;
2469 *plist = &((**plist)->next);
2470 /* Add to parent structure as well, with same offsets */
2471 for (ls = se->struc.fields; ls != NULL; ls = ls->next) {
2472 /* Try to enter field in structure's symbol table */
2473 fe = symtab_enter(
2474 ls->entry->id,
2475 VAR_SYMBOL,
2476 astnode_clone(ls->entry->def, ls->entry->def->loc),
2479 if (fe == NULL) {
2480 err(ls->entry->def->loc, "duplicate symbol `%s' in structure `%s'", ls->entry->id, struc_id->ident);
2481 continue;
2483 /* Set field offset */
2484 fe->field.offset = astnode_clone(offset, offset->loc);
2485 /* Set field size */
2486 fe->field.size = astnode_clone(se->struc.size, offset->loc);
2488 /* Advance offset by size of union */
2489 offset = astnode_create_arithmetic(
2490 PLUS_OPERATOR,
2491 offset,
2492 astnode_clone(se->struc.size, offset->loc),
2493 offset->loc
2495 offset = reduce_expression(offset);
2496 return(offset);
2500 * Enters struc type into symbol table based on AST node.
2501 * - Creates a symbol table for the structure
2502 * - Validates and enters all its fields
2503 * - Calculates offset of each field in the structure, and total size
2504 * @param n Node of type STRUC_DECL_NODE
2506 static int enter_struc(astnode *n, void *arg, astnode **next)
2508 ordered_field_list **plist;
2509 symtab_entry *se;
2510 astnode *c;
2511 astnode *offset;
2512 astnode *struc_id = LHS(n); /* Child 0 is struc identifier */
2513 /* Put STRUC in symbol table */
2514 se = symtab_enter(struc_id->ident, STRUC_SYMBOL, n, 0);
2515 if (se == NULL) {
2516 err(n->loc, "duplicate symbol `%s'", struc_id->ident);
2517 } else {
2518 /* Put the fields of the structure in local symbol table */
2519 se->symtab = symtab_create();
2520 offset = astnode_create_integer(0, n->loc); /* offset = 0 */
2521 plist = &se->struc.fields;
2522 for (c = struc_id->next_sibling; c != NULL; c = c->next_sibling) {
2523 /* Check if it's a field declaration */
2524 if (astnode_is_type(c, VAR_DECL_NODE)) {
2525 offset = enter_struc_atomic_field(c, offset, &plist, struc_id);
2527 /* Check if (anonymous) union */
2528 else if (astnode_is_type(c, UNION_DECL_NODE)) {
2529 offset = enter_struc_union_field(c, offset, &plist, struc_id);
2530 } else {
2531 err(c->loc, "field declaration expected");
2532 continue;
2535 /* Store total size of structure */
2536 se->struc.size = offset;
2537 /* Restore previous symbol table */
2538 symtab_pop();
2540 /* ### Remove STRUC node from AST */
2541 // astnode_remove(n);
2542 // astnode_finalize(n);
2543 return 0;
2547 * Enters fields of union into its symbol table.
2549 static void enter_union_fields(symtab_entry *se, astnode *n)
2551 ordered_field_list **plist;
2552 astnode *c;
2553 astnode *field_id;
2554 astnode *field_data;
2555 astnode *field_size;
2556 symtab_entry *fe;
2558 se->symtab = symtab_create();
2559 se->struc.size = astnode_create_integer(0, n->loc);
2560 plist = &se->struc.fields;
2561 /* Process field declarations */
2562 for (c = RHS(n); c != NULL; c = c->next_sibling) {
2563 /* Make sure it's a field declaration */
2564 if (!astnode_is_type(c, VAR_DECL_NODE)) {
2565 err(c->loc, "field declaration expected");
2566 continue;
2568 /* c has two children: id and STORAGE_NODE */
2569 field_id = LHS(c);
2570 assert(astnode_get_type(field_id) == IDENTIFIER_NODE);
2571 field_data = RHS(c);
2572 reduce_expression(RHS(field_data));
2573 /* Validate the declaration -- no data initialized */
2574 if (astnode_is_type(field_data, DATA_NODE)) {
2575 err(c->loc, "data initialization not allowed here");
2576 continue;
2578 /* Calculate field size in bytes: sizeof(datatype) * count */
2579 field_size = astnode_create_arithmetic(
2580 MUL_OPERATOR,
2581 astnode_create_sizeof(astnode_clone(LHS(field_data), field_data->loc), field_data->loc),
2582 astnode_clone(RHS(field_data), field_data->loc),
2583 field_data->loc
2585 field_size = reduce_expression(field_size);
2586 /* Make sure field size is a constant */
2587 if (!astnode_is_type(field_size, INTEGER_NODE)) {
2588 err(c->loc, "union member must be of constant size");
2589 astnode_finalize(field_size);
2590 /* Use default size: 1 byte */
2591 field_size = astnode_create_integer(1, field_data->loc);
2593 /* Try to enter field in structure's symbol table */
2594 fe = symtab_enter(
2595 field_id->ident,
2596 VAR_SYMBOL,
2597 astnode_clone(field_data, field_data->loc),
2600 if (fe == NULL) {
2601 err(c->loc, "duplicate symbol `%s' in union `%s'", field_id->ident, se->id);
2602 astnode_finalize(field_size);
2603 continue;
2605 /* Add to ordered list of fields */
2606 (*plist) = malloc(sizeof(ordered_field_list));
2607 (*plist)->entry = fe;
2608 (*plist)->next = NULL;
2609 plist = &((*plist)->next);
2610 /* Set field offset (0 for all) and size */
2611 fe->field.offset = astnode_create_integer(0, n->loc);
2612 fe->field.size = astnode_clone(field_size, field_size->loc);
2613 /* See if field size of this member is largest so far */
2614 if (se->struc.size->integer < field_size->integer) {
2615 astnode_finalize(se->struc.size);
2616 se->struc.size = field_size;
2617 } else {
2618 astnode_finalize(field_size);
2621 symtab_pop();
2625 * Enters union type into symbol table based on AST node.
2626 * @param n Node of type UNION_DECL_NODE
2628 static int enter_union(astnode *n, void *arg, astnode **next)
2630 symtab_entry *se;
2631 astnode *union_id = astnode_get_child(n, 0); /* Child 0 is union identifier */
2632 /* Check for anonymous union */
2633 if (astnode_is_type(union_id, NULL_NODE)) {
2634 err(n->loc, "anonymous union not allowed in global scope");
2635 } else {
2636 /* Put UNION in symbol table */
2637 assert(astnode_get_type(union_id) == IDENTIFIER_NODE);
2638 se = symtab_enter(union_id->ident, UNION_SYMBOL, n, 0);
2639 if (se == NULL) {
2640 err(n->loc, "duplicate symbol `%s'", union_id->ident);
2641 } else {
2642 /* Put the fields of the union in local symbol table */
2643 enter_union_fields(se, n);
2646 /* ### Remove UNION node from AST */
2647 // astnode_remove(n);
2648 // astnode_finalize(n);
2649 return 0;
2653 * Enters enumerated type into symbol table based on AST node.
2654 * @param n Node of type ENUM_DECL_NODE
2656 static int enter_enum(astnode *n, void *arg, astnode **next)
2658 astnode *c;
2659 astnode *id;
2660 astnode *val;
2661 symtab_entry *se;
2662 astnode *enum_id = astnode_get_child(n, 0); /* Child 0 is enum identifier */
2663 /* Enter in global symbol table */
2664 assert(astnode_get_type(enum_id) == IDENTIFIER_NODE);
2665 se = symtab_enter(enum_id->ident, ENUM_SYMBOL, n, 0);
2666 if (se == NULL) {
2667 err(n->loc, "duplicate symbol `%s'", enum_id->ident);
2668 } else {
2669 /* Add all the enum symbols to its own symbol table */
2670 se->symtab = symtab_create();
2671 val = NULL;
2672 for (c = enum_id->next_sibling; c != NULL; c = c->next_sibling) {
2673 if (astnode_is_type(c, IDENTIFIER_NODE)) {
2674 id = c;
2675 if (val == NULL) {
2676 val = astnode_create_integer(0, c->loc);
2677 } else {
2678 val = astnode_create_integer(val->integer+1, c->loc);
2680 } else {
2681 id = LHS(c);
2682 val = reduce_expression_complete(astnode_clone(RHS(c), RHS(c)->loc));
2683 if (!astnode_is_type(val, INTEGER_NODE)) {
2684 err(c->loc, "initializer does not evaluate to integer literal");
2685 astnode_finalize(val);
2686 /* Use default value */
2687 val = astnode_create_integer(0, c->loc);
2690 if (symtab_enter(id->ident, CONSTANT_SYMBOL, val, 0) == NULL) {
2691 err(c->loc, "duplicate symbol `%s' in enumeration `%s'", id->ident, enum_id->ident);
2692 continue;
2695 symtab_pop();
2697 /* ### Remove ENUM node from AST */
2698 // astnode_remove(n);
2699 // astnode_finalize(n);
2700 return 0;
2704 * Enters record type into symbol table based on AST node.
2705 * @param n Node of type RECORD_DECL_NODE
2707 static int enter_record(astnode *n, void *arg, astnode **next)
2709 ordered_field_list **plist;
2710 astnode *c;
2711 astnode *field_id;
2712 astnode *field_width;
2713 int size;
2714 int offset;
2715 symtab_entry *se;
2716 symtab_entry *fe;
2717 astnode *record_id = astnode_get_child(n, 0); /* Child 0 is record identifier */
2718 assert(astnode_get_type(record_id) == IDENTIFIER_NODE);
2719 /* Enter in global symbol table */
2720 se = symtab_enter(record_id->ident, RECORD_SYMBOL, n, 0);
2721 if (se == NULL) {
2722 err(n->loc, "duplicate symbol `%s'", record_id->ident);
2724 else {
2725 /* Add all the record fields to record's own symbol table */
2726 se->symtab = symtab_create();
2727 offset = 8;
2728 plist = &se->struc.fields;
2729 for (c = record_id->next_sibling; c != NULL; c = c->next_sibling) {
2730 /* c has two children: field identifier and its width */
2731 field_id = LHS(c);
2732 field_width = astnode_clone(reduce_expression(RHS(c)), RHS(c)->loc);
2733 /* Validate the width -- must be positive integer literal */
2734 if (!astnode_is_type(field_width, INTEGER_NODE)) {
2735 err(c->loc, "record member `%s' is not of constant size", field_id->ident);
2736 continue;
2738 if ((field_width->integer <= 0) || (field_width->integer >= 8)) {
2739 err(c->loc, "width of record member `%s' is out of range (%d)", field_id->ident, field_width->integer);
2740 continue;
2742 /* Attempt to enter field in record's symbol table */
2743 fe = symtab_enter(field_id->ident, VAR_SYMBOL, c, 0);
2744 if (fe == NULL) {
2745 err(c->loc, "duplicate symbol `%s' in record `%s'", field_id->ident, record_id->ident);
2746 continue;
2748 /* Add to ordered list of fields */
2749 (*plist) = malloc(sizeof(ordered_field_list));
2750 (*plist)->entry = fe;
2751 (*plist)->next = NULL;
2752 plist = &((*plist)->next);
2753 /* Set field offset */
2754 offset = offset - field_width->integer;
2755 fe->field.offset = astnode_create_integer(offset, c->loc);
2756 /* Set field size (width) */
2757 fe->field.size = field_width;
2759 size = 8 - offset;
2760 if (size > 8) {
2761 err(n->loc, "size of record `%s' (%d) exceeds 8 bits", record_id->ident, size);
2762 } else {
2763 /* Set size of record (in bits) */
2764 se->struc.size = astnode_create_integer(size, n->loc);
2766 symtab_pop();
2768 /* ### Remove RECORD node from AST */
2769 // astnode_remove(n);
2770 // astnode_finalize(n);
2771 return 0;
2775 * Globalizes a local.
2776 * The node is morphed into its global equivalent (LABEL_NODE or IDENTIFIER_NODE).
2777 * @param n A node of type LOCAL_LABEL_NODE or LOCAL_ID_NODE
2778 * @param arg Pointer to namespace counter
2780 static int globalize_local(astnode *n, void *arg, astnode **next)
2782 char str[32];
2783 /* Make it global by appending namespace counter to the id */
2784 snprintf(str, sizeof (str), "#%d", label_count);
2785 if (astnode_is_type(n, LOCAL_LABEL_NODE)) {
2786 /* Local label definition, use label field */
2787 n->label = realloc(n->label, strlen(n->label)+strlen(str)+1);
2788 strcat(n->label, str);
2789 /* This node is now a unique, global label */
2790 n->type = LABEL_NODE;
2791 /* Make sure it's unique */
2792 if (symtab_lookup(n->label)) {
2793 err(n->loc, "duplicate symbol `%s'", n->label);
2794 /* Remove from AST */
2795 astnode_remove(n);
2796 astnode_finalize(n);
2797 return 0;
2798 } else {
2799 /* Enter it in symbol table */
2800 symtab_enter(n->label, LABEL_SYMBOL, n, (in_dataseg ? DATA_FLAG : 0) );
2802 } else {
2803 /* Local label reference, use ident field */
2804 n->ident = realloc(n->ident, strlen(n->ident)+strlen(str)+1);
2805 strcat(n->ident, str);
2806 /* This node is now a unique, global identifier */
2807 n->type = IDENTIFIER_NODE;
2809 return 1;
2813 * Tags symbols as extrn.
2814 * @param n A node of type EXTRN_NODE
2816 static int tag_extrn_symbols(astnode *n, void *arg, astnode **next)
2818 astnode *id;
2819 astnode *type;
2820 astnode *list;
2821 symtab_entry *e;
2822 /* Get symbol type specifier */
2823 type = astnode_get_child(n, 0);
2824 /* Go through the list of identifiers */
2825 list = astnode_get_child(n, 1);
2826 for (id=astnode_get_first_child(list); id != NULL; id=astnode_get_next_sibling(id) ) {
2827 /* Look up identifier in symbol table */
2828 e = symtab_lookup(id->ident);
2829 if (e != NULL) {
2830 if (!(e->flags & EXTRN_FLAG)) {
2831 /* Error, can't import a symbol that's defined locally! */
2832 // TODO: this is okay?
2833 err(n->loc, "`%s' declared as extrn but is defined locally", id->ident);
2836 else {
2837 // TODO: store external unit name
2838 switch (astnode_get_type(type)) {
2839 case DATATYPE_NODE:
2840 /* Put it in symbol table */
2841 symtab_enter(id->ident, VAR_SYMBOL, astnode_create_data(astnode_clone(type, n->loc), NULL, n->loc), EXTRN_FLAG);
2842 break;
2844 case INTEGER_NODE:
2845 /* type->integer is (LABEL|PROC)_SYMBOL */
2846 symtab_enter(id->ident, type->integer, NULL, EXTRN_FLAG);
2847 break;
2849 default:
2850 break;
2854 /* Remove extrn node from AST */
2855 astnode_remove(n);
2856 astnode_finalize(n);
2858 return 0;
2864 static int process_message(astnode *n, void *arg, astnode **next)
2866 astnode *mesg = reduce_expression_complete(LHS(n));
2867 if (astnode_is_type(mesg, STRING_NODE)) {
2868 printf("%s\n", mesg->string);
2870 else if (astnode_is_type(mesg, INTEGER_NODE)) {
2871 printf("%d\n", mesg->integer);
2873 else {
2874 err(mesg->loc, "string or integer argument expected");
2876 astnode_remove(n);
2877 astnode_finalize(n);
2878 return 0;
2884 static int process_warning(astnode *n, void *arg, astnode **next)
2886 astnode *mesg = reduce_expression_complete(LHS(n));
2887 if (astnode_is_type(mesg, STRING_NODE)) {
2888 warn(mesg->loc, mesg->string);
2890 else {
2891 err(mesg->loc, "string argument expected");
2893 astnode_remove(n);
2894 astnode_finalize(n);
2895 return 0;
2901 static int process_error(astnode *n, void *arg, astnode **next)
2903 astnode *mesg = reduce_expression_complete(LHS(n));
2904 if (astnode_is_type(mesg, STRING_NODE)) {
2905 err(mesg->loc, mesg->string);
2907 else {
2908 err(mesg->loc, "string argument expected");
2910 astnode_remove(n);
2911 astnode_finalize(n);
2912 return 0;
2916 * Processes a forward branch declaration.
2917 * @param n Node of type FORWARD_BRANCH_DECL_NODE
2918 * @param arg Not used
2920 static int process_forward_branch_decl(astnode *n, void *arg, astnode **next)
2922 astnode *l;
2923 int i;
2924 char str[32];
2925 assert(!strchr(n->ident, '#'));
2926 /* Get branch info structure for label (+, ++, ...) */
2927 forward_branch_info *fwd = &forward_branch[strlen(n->ident)-1];
2928 /* Morph n to globally unique label */
2929 snprintf(str, sizeof (str), "#%d", fwd->counter);
2930 n->label = (char *)realloc(n->ident, strlen(n->ident)+strlen(str)+1);
2931 strcat(n->label, str);
2932 n->type = LABEL_NODE;
2933 symtab_enter(n->label, LABEL_SYMBOL, n, 0);
2934 /* Fix reference identifiers */
2935 for (i=0; i<fwd->index; i++) {
2936 l = fwd->refs[i];
2937 l->ident = (char *)realloc(l->ident, strlen(n->ident)+1);
2938 strcpy(l->ident, n->ident);
2940 /* Prepare for next declaration */
2941 fwd->index = 0;
2942 fwd->counter++;
2943 return 0;
2947 * Processes a backward branch declaration.
2948 * @param n Node of type BACKWARD_BRANCH_DECL_NODE
2949 * @param arg Not used
2951 static int process_backward_branch_decl(astnode *n, void *arg, astnode **next)
2953 char str[32];
2954 assert(!strchr(n->ident, '#'));
2955 /* Get branch info */
2956 backward_branch_info *bwd = &backward_branch[strlen(n->ident)-1];
2957 bwd->decl = n;
2958 /* Morph n to globally unique label */
2959 snprintf(str, sizeof (str), "#%d", bwd->counter);
2960 n->label = (char *)realloc(n->ident, strlen(n->ident)+strlen(str)+1);
2961 strcat(n->label, str);
2962 n->type = LABEL_NODE;
2963 symtab_enter(n->label, LABEL_SYMBOL, n, 0);
2964 /* Prepare for next declaration */
2965 bwd->counter++;
2966 return 0;
2970 * Processes a forward branch label reference.
2971 * @param n Node of type FORWARD_BRANCH_NODE
2972 * @param arg Not used
2974 static int process_forward_branch(astnode *n, void *arg, astnode **next)
2976 /* Add n to proper forward_branch array */
2977 forward_branch_info *fwd = &forward_branch[strlen(n->ident)-1];
2978 fwd->refs[fwd->index++] = n;
2979 /* Change to identifier node */
2980 n->type = IDENTIFIER_NODE;
2981 return 0;
2985 * Processes a backward branch label reference.
2986 * @param n Node of type BACKWARD_BRANCH_NODE
2987 * @param arg Not used
2989 static int process_backward_branch(astnode *n, void *arg, astnode **next)
2991 /* Get branch info */
2992 backward_branch_info *bwd = &backward_branch[strlen(n->ident)-1];
2993 /* Make sure it's a valid reference */
2994 if (bwd->decl != NULL) {
2995 /* Fix n->ident */
2996 n->ident = (char *)realloc(n->ident, strlen(bwd->decl->ident)+1);
2997 strcpy(n->ident, bwd->decl->ident);
2999 /* Change to identifier node */
3000 n->type = IDENTIFIER_NODE;
3001 return 0;
3004 /*---------------------------------------------------------------------------*/
3006 static int is_field_ref(astnode *n)
3008 astnode *p = astnode_get_parent(n);
3009 /* Case 1: id.id */
3010 if (astnode_is_type(p, DOT_NODE)) return 1;
3011 /* Case 2: id.id[expr] */
3012 if (astnode_is_type(p, INDEX_NODE) && (n == LHS(p)) && astnode_is_type(astnode_get_parent(p), DOT_NODE) ) return 1;
3013 return 0;
3017 * Checks that the given identifier node is present in symbol table.
3018 * Issues error if it is not, and replaces with integer 0.
3019 * @param n A node of type IDENTIFIER_NODE
3021 static int validate_ref(astnode *n, void *arg, astnode **next)
3023 int i;
3024 symbol_ident_list list;
3025 symtab_entry *enum_def;
3026 int ret = 1;
3027 if (is_field_ref(n)) {
3028 return 1; /* Validated by validate_dotref() */
3030 /* Look it up in symbol table */
3031 symtab_entry * e = symtab_lookup(n->ident);
3032 if (e == NULL) {
3033 /* This identifier is unknown */
3034 /* Maybe it is part of an enumeration */
3035 symtab_list_type(ENUM_SYMBOL, &list);
3036 for (i=0; i<list.size; i++) {
3037 enum_def = symtab_lookup(list.idents[i]);
3038 symtab_push(enum_def->symtab);
3039 e = symtab_lookup(n->ident);
3040 symtab_pop();
3041 if (e != NULL) {
3042 /* Found it */
3043 /* Replace id by SCOPE_NODE */
3044 astnode *scope = astnode_create_scope(
3045 astnode_create_identifier(enum_def->id, n->loc),
3046 astnode_clone(n, n->loc), n->loc);
3047 astnode_replace(n, scope);
3048 astnode_finalize(n);
3049 *next = scope;
3050 ret = 0;
3051 break;
3054 symtab_list_finalize(&list);
3055 /* If still not found, error */
3056 if (e == NULL) {
3057 strtok(n->ident, "#"); /* Remove globalize junk */
3058 // err(n->loc, "unknown symbol `%s'", n->ident);
3059 /* ### Replace by integer 0 */
3060 //astnode_replace(n, astnode_create_integer(0, n->loc) );
3061 //astnode_finalize(n);
3062 warn(n->loc, "`%s' undeclared; assuming external label", n->ident);
3063 e = symtab_enter(n->ident, LABEL_SYMBOL, NULL, EXTRN_FLAG);
3066 assert(e);
3067 /* Increase reference count */
3068 e->ref_count++;
3069 return ret;
3073 * Validates top-level (not part of structure) indexed identifier.
3074 * @param n Node of type INDEX_NODE
3075 * @param arg Not used
3077 static int validate_index(astnode *n, void *arg, astnode **next)
3079 symtab_entry *e;
3080 astnode *id;
3081 astnode *type;
3082 if (is_field_ref(LHS(n))) {
3083 return 1; /* Validated by validate_dotref() */
3085 id = LHS(n);
3086 if (!astnode_is_type(id, IDENTIFIER_NODE)) {
3087 err(n->loc, "identifier expected");
3088 astnode_replace(n, astnode_create_integer(0, n->loc) );
3089 astnode_finalize(n);
3090 return 0;
3092 e = symtab_lookup(id->ident);
3093 if (e != NULL) {
3094 type = LHS(e->def);
3095 if (!astnode_is_type(type, DATATYPE_NODE)) {
3096 err(n->loc, "`%s' cannot be indexed", id->ident);
3097 astnode_replace(n, astnode_create_integer(0, n->loc) );
3098 astnode_finalize(n);
3099 return 0;
3100 } else {
3101 // TODO: bounds check
3102 astnode *reduced = reduce_index(n);
3103 if (reduced != n) {
3104 *next = reduced;
3105 return 0;
3108 } else {
3109 err(n->loc, "unknown symbol `%s'", id->ident);
3110 astnode_replace(n, astnode_create_integer(0, n->loc) );
3111 astnode_finalize(n);
3112 return 0;
3114 return 1;
3118 * Checks that A::B is valid.
3119 * If it's not valid it is replaced by integer 0.
3120 * @param n Node of type SCOPE_NODE
3122 static int validate_scoperef(astnode *n, void *arg, astnode **next)
3124 astnode *symbol;
3125 astnode *namespace = LHS(n);
3126 /* Look up namespace in global symbol table */
3127 symtab_entry * e = symtab_lookup(namespace->ident);
3128 if (e == NULL) {
3129 /* Error, this identifier is unknown */
3130 err(n->loc, "unknown namespace `%s'", namespace->ident);
3131 /* Replace by integer 0 */
3132 astnode_replace(n, astnode_create_integer(0, n->loc) );
3133 astnode_finalize(n);
3134 return 0;
3135 } else {
3136 /* Get symbol on right of :: operator */
3137 symbol = RHS(n);
3138 /* Namespace was found, check its type */
3139 switch (e->type) {
3140 case STRUC_SYMBOL:
3141 case UNION_SYMBOL:
3142 case RECORD_SYMBOL:
3143 case ENUM_SYMBOL:
3144 /* OK, check the symbol */
3145 symtab_push(e->symtab);
3146 e = symtab_lookup(symbol->ident);
3147 if (e == NULL) {
3148 /* Error, symbol is not in namespace */
3149 err(n->loc, "unknown symbol `%s' in namespace `%s'", symbol->ident, namespace->ident);
3150 /* Replace by integer 0 */
3151 astnode_replace(n, astnode_create_integer(0, n->loc) );
3152 astnode_finalize(n);
3154 symtab_pop();
3155 break;
3157 default:
3158 err(n->loc, "`%s' is not a namespace", namespace->ident);
3159 /* Replace by integer 0 */
3160 astnode_replace(n, astnode_create_integer(0, n->loc) );
3161 astnode_finalize(n);
3162 break;
3165 return 0;
3169 * Validates right part of dotted reference recursively.
3170 * Assumes that left part's symbol table is on stack.
3171 * @param n Node of type DOT_NODE
3173 static void validate_dotref_recursive(astnode *n, astnode *top)
3175 astnode *left;
3176 astnode *right;
3177 astnode *type;
3178 symtab_entry *field;
3179 symtab_entry *def;
3180 left = LHS(n);
3181 if (astnode_is_type(left, INDEX_NODE)) {
3182 left = LHS(left); /* Need identifier */
3184 right = RHS(n);
3185 if (astnode_is_type(right, DOT_NODE)) {
3186 right = LHS(right); /* Need identifier */
3188 if (astnode_is_type(right, INDEX_NODE)) {
3189 right = LHS(right); /* Need identifier */
3191 /* Lookup 'right' in 'left's symbol table */
3192 assert(astnode_get_type(right) == IDENTIFIER_NODE);
3193 field = symtab_lookup(right->ident);
3194 if (field == NULL) {
3195 /* Error, this symbol is unknown */
3196 err(n->loc, "`%s' is not a member of `%s'", right->ident, left->ident);
3197 /* Replace by integer 0 */
3198 astnode_replace(top, astnode_create_integer(0, top->loc) );
3199 astnode_finalize(top);
3200 } else {
3201 /* See if more subfields to process */
3202 n = RHS(n);
3203 if (astnode_is_type(n, DOT_NODE)) {
3204 /* Verify the variable's type -- should be user-defined */
3205 type = LHS(field->def);
3206 if ((type == NULL) || (type->datatype != USER_DATATYPE)) {
3207 err(n->loc, "member `%s' of `%s' is not a structure", right->ident, left->ident);
3208 /* Replace by integer 0 */
3209 astnode_replace(top, astnode_create_integer(0, top->loc) );
3210 astnode_finalize(top);
3211 } else {
3212 /* Look up variable's type definition and verify it's a structure */
3213 def = symtab_global_lookup(LHS(type)->ident);
3214 if (def == NULL) {
3215 err(n->loc, "member '%s' of '%s' is of unknown type (`%s')", right->ident, left->ident, LHS(type)->ident);
3216 /* Replace by integer 0 */
3217 astnode_replace(top, astnode_create_integer(0, top->loc) );
3218 astnode_finalize(top);
3219 } else if ( !((def->type == STRUC_SYMBOL) || (def->type == UNION_SYMBOL)) ) {
3220 err(n->loc, "member `%s' of `%s' is not a structure", right->ident, left->ident);
3221 /* Replace by integer 0 */
3222 astnode_replace(top, astnode_create_integer(0, top->loc) );
3223 astnode_finalize(top);
3224 } else {
3225 /* Next field */
3226 symtab_push(def->symtab);
3227 validate_dotref_recursive(n, top);
3228 symtab_pop();
3236 * Validates A.B.C.D. . ...
3237 * Replaces the whole thing with integer 0 if not.
3238 * @param n Node of type DOT_NODE
3240 static int validate_dotref(astnode *n, void *arg, astnode **next)
3242 symtab_entry *father;
3243 symtab_entry *def;
3244 astnode *type;
3245 astnode *left;
3246 if (astnode_has_ancestor_of_type(n, DOT_NODE)) {
3247 return 1; /* Already validated, since this function is recursive */
3249 /* Look up parent in global symbol table */
3250 left = LHS(n); /* n := left . right */
3251 if (astnode_is_type(left, INDEX_NODE)) {
3252 left = LHS(left); /* Need identifier */
3254 father = symtab_lookup(left->ident);
3255 if (father == NULL) {
3256 /* Error, this symbol is unknown */
3257 err(n->loc, "unknown symbol `%s'", left->ident);
3258 /* Replace by integer 0 */
3259 astnode_replace(n, astnode_create_integer(0, n->loc) );
3260 astnode_finalize(n);
3261 return 0;
3262 } else {
3263 /* Increase reference count */
3264 father->ref_count++;
3265 /* Verify the variable's type -- should be user-defined */
3266 type = LHS(father->def);
3267 if ((type == NULL) || (type->datatype != USER_DATATYPE)) {
3268 err(n->loc, "`%s' is not a structure", left->ident);
3269 /* Replace by integer 0 */
3270 astnode_replace(n, astnode_create_integer(0, n->loc) );
3271 astnode_finalize(n);
3272 return 0;
3273 } else {
3274 /* Look up variable's type definition and verify it's a structure */
3275 def = symtab_lookup(LHS(type)->ident);
3276 if (def == NULL) {
3277 err(n->loc, "'%s' is of unknown type (`%s')", left->ident, LHS(type)->ident);
3278 /* Replace by integer 0 */
3279 astnode_replace(n, astnode_create_integer(0, n->loc) );
3280 astnode_finalize(n);
3281 return 0;
3282 } else if ( !((def->type == STRUC_SYMBOL) || (def->type == UNION_SYMBOL)) ) {
3283 err(n->loc, "`%s' is not a structure", left->ident);
3284 /* Replace by integer 0 */
3285 astnode_replace(n, astnode_create_integer(0, n->loc) );
3286 astnode_finalize(n);
3287 return 0;
3288 } else {
3289 /* Verify fields recursively */
3290 symtab_push(def->symtab);
3291 validate_dotref_recursive(n, n);
3292 symtab_pop();
3296 return 1;
3299 /*---------------------------------------------------------------------------*/
3302 * Evaluates expressions involved in conditional assembly, and removes the
3303 * appropriate branches from the AST.
3304 * Does some other stuff too, such as substitute equates and fold constants.
3306 void astproc_first_pass(astnode *root)
3308 /* Table of callback functions for our purpose. */
3309 static astnodeprocmap map[] = {
3310 { LABEL_NODE, enter_label },
3311 { VAR_DECL_NODE, enter_var },
3312 { PROC_NODE, enter_proc },
3313 { STRUC_DECL_NODE, enter_struc },
3314 { UNION_DECL_NODE, enter_union },
3315 { ENUM_DECL_NODE, enter_enum },
3316 { RECORD_DECL_NODE, enter_record },
3317 { LOCAL_LABEL_NODE, globalize_local },
3318 { LOCAL_ID_NODE, globalize_local },
3319 { MACRO_DECL_NODE, enter_macro },
3320 { MACRO_NODE, expand_macro },
3321 { REPT_NODE, process_rept },
3322 { WHILE_NODE, process_while },
3323 { DATASEG_NODE, process_dataseg },
3324 { CODESEG_NODE, process_codeseg },
3325 { ORG_NODE, process_org },
3326 { CHARMAP_NODE, load_charmap },
3327 { INSTRUCTION_NODE, process_instruction },
3328 { DATA_NODE, process_data },
3329 { STORAGE_NODE, process_storage },
3330 { EQU_NODE, process_equ },
3331 { ASSIGN_NODE, process_assign },
3332 { IFDEF_NODE, process_ifdef },
3333 { IFNDEF_NODE, process_ifndef },
3334 { IF_NODE, process_if },
3335 { EXTRN_NODE, tag_extrn_symbols },
3336 { MESSAGE_NODE, process_message },
3337 { WARNING_NODE, process_warning },
3338 { ERROR_NODE, process_error },
3339 { FORWARD_BRANCH_DECL_NODE, process_forward_branch_decl },
3340 { BACKWARD_BRANCH_DECL_NODE, process_backward_branch_decl },
3341 { FORWARD_BRANCH_NODE, process_forward_branch },
3342 { BACKWARD_BRANCH_NODE, process_backward_branch },
3343 { 0, NULL }
3345 reset_charmap();
3346 branch_init();
3347 in_dataseg = 0; /* codeseg is default */
3348 /* Do the walk. */
3349 astproc_walk(root, NULL, map);
3350 /* Remove all the volatile constants from the symbol table */
3351 /* These are the ones defined with the '=' operator, whose identifiers should
3352 all have been replaced by their value in the syntax tree now. Since
3353 they're not referenced anywhere we can safely dispose of them.
3354 The EQUates on the other hand should be kept, since they will
3355 possibly be exported. */
3356 #ifdef ENABLE_BUGGY_THING // ### FIXME
3358 int i;
3359 symbol_ident_list list;
3360 symtab_entry *e;
3361 symtab_list_type(CONSTANT_SYMBOL, &list);
3362 for (i = 0; i < list.size; ++i) {
3363 e = symtab_lookup(list.idents[i]);
3364 if (e->flags & VOLATILE_FLAG) {
3365 symtab_remove(list.idents[i]);
3368 symtab_list_finalize(&list);
3370 #endif
3373 /*---------------------------------------------------------------------------*/
3376 * Tags labels as public.
3377 * @param n A node of type PUBLIC_NODE
3379 static int tag_public_symbols(astnode *n, void *arg, astnode **next)
3381 astnode *id;
3382 symtab_entry *e;
3383 /* Go through the list of identifiers */
3384 for (id=astnode_get_first_child(n); id != NULL; id = astnode_get_next_sibling(id) ) {
3385 /* Look up identifier in symbol table */
3386 e = symtab_lookup(id->ident);
3387 if (e != NULL) {
3388 /* Symbol exists. Set the proper flag unless ambiguous. */
3389 if (e->flags & EXTRN_FLAG) {
3390 err(n->loc, "`%s' already declared extrn", id->ident);
3391 } else {
3392 switch (e->type) {
3393 case LABEL_SYMBOL:
3394 case CONSTANT_SYMBOL:
3395 case VAR_SYMBOL:
3396 case PROC_SYMBOL:
3397 /* GO! */
3398 e->flags |= PUBLIC_FLAG;
3399 break;
3401 default:
3402 err(n->loc, "`%s' is of non-exportable type", id->ident);
3403 break;
3406 } else {
3407 /* Warning, can't export a symbol that's not defined. */
3408 warn(n->loc, "`%s' declared as public but is not defined", id->ident);
3411 /* Remove PUBLIC_NODE from AST */
3412 astnode_remove(n);
3413 astnode_finalize(n);
3415 return 0;
3419 * Sets alignment for a set of (data) labels.
3420 * @param n A node of type ALIGN_NODE
3422 static int tag_align_symbols(astnode *n, void *arg, astnode **next)
3424 int pow;
3425 astnode *id;
3426 astnode *idents;
3427 astnode *expr;
3428 symtab_entry *e;
3429 /* Go through the list of identifiers */
3430 idents = LHS(n);
3431 for (id=astnode_get_first_child(idents); id != NULL; id = astnode_get_next_sibling(id) ) {
3432 /* Look up identifier in symbol table */
3433 e = symtab_lookup(id->ident);
3434 if (e != NULL) {
3435 /* Symbol exists. Set the proper flag unless ambiguous. */
3436 if (!(e->flags & DATA_FLAG)) {
3437 err(n->loc, "cannot align a code symbol (`%s')", id->ident);
3438 } else {
3439 switch (e->type) {
3440 case LABEL_SYMBOL:
3441 case VAR_SYMBOL:
3442 expr = reduce_expression(RHS(n));
3443 if (!astnode_is_type(expr, INTEGER_NODE)) {
3444 err(n->loc, "alignment expression must be an integer literal");
3445 } else if ((expr->integer < 0) || (expr->integer >= 0x10000)) {
3446 err(n->loc, "alignment expression out of range");
3447 } else if (expr->integer > 1) {
3448 pow = 0;
3449 switch (expr->integer) {
3450 case 32768: pow++;
3451 case 16384: pow++;
3452 case 8192: pow++;
3453 case 4096: pow++;
3454 case 2048: pow++;
3455 case 1024: pow++;
3456 case 512: pow++;
3457 case 256: pow++;
3458 case 128: pow++;
3459 case 64: pow++;
3460 case 32: pow++;
3461 case 16: pow++;
3462 case 8: pow++;
3463 case 4: pow++;
3464 case 2: pow++;
3465 /* GO! */
3466 e->flags |= ALIGN_FLAG;
3467 e->align = pow;
3468 break;
3470 default:
3471 err(n->loc, "alignment expression must be a power of 2");
3472 break;
3475 break;
3477 default:
3478 err(n->loc, "`%s' cannot be aligned", id->ident);
3479 break;
3483 else {
3484 /* Warning, can't align a symbol that's not defined. */
3485 warn(n->loc, "alignment ignored for undefined symbol `%s'", id->ident);
3488 /* Remove ALIGN_NODE from AST */
3489 astnode_remove(n);
3490 astnode_finalize(n);
3492 return 0;
3495 /*---------------------------------------------------------------------------*/
3498 * Removes unused labels from a syntax tree (and symbol table).
3499 * Unused labels are labels that are defined but not referenced anywhere.
3500 * This function assumes that the reference counts have already been calculated.
3502 void remove_unused_labels()
3504 int i;
3505 char *id;
3506 astnode *n;
3507 symbol_ident_list list;
3508 symtab_list_type(LABEL_SYMBOL, &list);
3509 for (i=0; i<list.size; i++) {
3510 /* Look up label in symbol table */
3511 id = list.idents[i];
3512 symtab_entry * e = symtab_lookup(id);
3513 /* If reference count is zero, AND label isn't declared public, remove it. */
3514 if ((e->ref_count == 0) && ((e->flags & PUBLIC_FLAG) == 0)) {
3515 n = e->def;
3516 strtok(n->label, "#"); /* Remove globalize junk */
3517 warn(n->loc, "`%s' defined but not used", n->label);
3518 /* Remove label from AST */
3519 astnode_remove(n);
3520 astnode_finalize(n);
3521 //symtab_remove(n->label); ### FIXME leads to crash sometimes...
3524 symtab_list_finalize(&list);
3528 * If the storage is of user-defined type, replaces it with
3529 * .DSB sizeof(type) * count
3531 static int reduce_user_storage(astnode *n, void *arg, astnode **next)
3533 astnode *type;
3534 astnode *count;
3535 astnode *byte_storage;
3536 symtab_entry *e;
3537 type = LHS(n);
3538 if (type->datatype == USER_DATATYPE) {
3539 /* Look it up */
3540 e = symtab_lookup(LHS(type)->ident);
3541 if (e != NULL) {
3542 /* Replace by DSB */
3543 count = RHS(n);
3544 byte_storage = astnode_create_storage(
3545 astnode_create_datatype(BYTE_DATATYPE, NULL, type->loc),
3546 astnode_create_arithmetic(
3547 MUL_OPERATOR,
3548 astnode_create_sizeof(
3549 astnode_create_identifier(LHS(type)->ident, n->loc),
3550 n->loc
3552 astnode_clone(count, n->loc),
3553 n->loc
3555 n->loc
3557 astnode_replace(n, byte_storage);
3558 astnode_finalize(n);
3559 *next = byte_storage;
3560 return 0;
3561 } else {
3562 err(n->loc, "unknown symbol `%s'", LHS(type)->ident);
3563 /* Remove from AST */
3564 astnode_remove(n);
3565 astnode_finalize(n);
3566 return 0;
3569 return 1;
3573 * Second major pass over AST.
3575 void astproc_second_pass(astnode *root)
3577 /* Table of callback functions for our purpose. */
3578 static astnodeprocmap map[] = {
3579 { IDENTIFIER_NODE, validate_ref },
3580 { SCOPE_NODE, validate_scoperef },
3581 { DOT_NODE, validate_dotref },
3582 { INDEX_NODE, validate_index },
3583 { PUBLIC_NODE, tag_public_symbols },
3584 { STORAGE_NODE, reduce_user_storage },
3585 { ALIGN_NODE, tag_align_symbols },
3586 { STRUC_DECL_NODE, noop },
3587 { UNION_DECL_NODE, noop },
3588 { ENUM_DECL_NODE, noop },
3589 { RECORD_DECL_NODE, noop },
3590 { 0, NULL }
3592 in_dataseg = 0; /* codeseg is default */
3593 /* Do the walk. */
3594 astproc_walk(root, NULL, map);
3595 /* */
3596 remove_unused_labels();
3599 /*---------------------------------------------------------------------------*/
3602 * Translates a single instruction.
3603 * @param n A node of type INSTRUCTION_NODE
3605 static int translate_instruction(astnode *n, void *arg, astnode **next)
3607 unsigned char c;
3608 /* Put the operand in final form */
3609 astnode *o = reduce_expression_complete( LHS(n) );
3610 assert(o == LHS(n));
3611 /* Convert (mnemonic, addressing mode) pair to opcode */
3612 n->instr.opcode = opcode_get(n->instr.mnemonic, n->instr.mode);
3613 /* Test if opcode is invalid */
3614 if (n->instr.opcode == 0xFF) {
3615 /* Check for the special cases */
3616 if ((n->instr.mnemonic == STX_MNEMONIC) && (n->instr.mode == ABSOLUTE_Y_MODE)) {
3617 /* Doesn't have absolute version, "scale down" to zeropage */
3618 n->instr.mode = ZEROPAGE_Y_MODE;
3619 n->instr.opcode = opcode_get(n->instr.mnemonic, n->instr.mode);
3620 } else if ((n->instr.mnemonic == STY_MNEMONIC) && (n->instr.mode == ABSOLUTE_X_MODE)) {
3621 /* Doesn't have absolute version, "scale down" to zeropage */
3622 n->instr.mode = ZEROPAGE_X_MODE;
3623 n->instr.opcode = opcode_get(n->instr.mnemonic, n->instr.mode);
3624 } else if (n->instr.mode == ABSOLUTE_MODE) {
3625 /* Check for relative addressing (these are parsed as absolute mode) */
3626 switch (n->instr.mnemonic) {
3627 case BCC_MNEMONIC:
3628 case BCS_MNEMONIC:
3629 case BEQ_MNEMONIC:
3630 case BMI_MNEMONIC:
3631 case BNE_MNEMONIC:
3632 case BPL_MNEMONIC:
3633 case BVC_MNEMONIC:
3634 case BVS_MNEMONIC:
3635 /* Fix addressing mode and opcode */
3636 n->instr.mode = RELATIVE_MODE;
3637 n->instr.opcode = opcode_get(n->instr.mnemonic, n->instr.mode);
3638 break;
3642 if (n->instr.opcode != 0xFF) {
3643 /* If the operand is a constant, see if we can "reduce" from
3644 absolute mode to zeropage mode */
3645 if ((astnode_is_type(o, INTEGER_NODE)) &&
3646 ((unsigned long)o->integer < 256) &&
3647 ((c = opcode_zp_equiv(n->instr.opcode)) != 0xFF)) {
3648 /* Switch to the zeromode version */
3649 n->instr.opcode = c;
3650 switch (n->instr.mode) {
3651 case ABSOLUTE_MODE: n->instr.mode = ZEROPAGE_MODE; break;
3652 case ABSOLUTE_X_MODE: n->instr.mode = ZEROPAGE_X_MODE;break;
3653 case ABSOLUTE_Y_MODE: n->instr.mode = ZEROPAGE_Y_MODE;break;
3654 default: /* Impossible to get here, right? */ break;
3657 /* If the operand is a constant, make sure it fits */
3658 if (astnode_is_type(o, INTEGER_NODE)) {
3659 switch (n->instr.mode) {
3660 case IMMEDIATE_MODE:
3661 case ZEROPAGE_MODE:
3662 case ZEROPAGE_X_MODE:
3663 case ZEROPAGE_Y_MODE:
3664 case PREINDEXED_INDIRECT_MODE:
3665 case POSTINDEXED_INDIRECT_MODE:
3666 /* Operand must fit in 8 bits */
3667 if (!IS_BYTE_VALUE(o->integer)) {
3668 warn(o->loc, "operand out of range; truncated");
3669 o->integer &= 0xFF;
3671 break;
3673 case ABSOLUTE_MODE:
3674 case ABSOLUTE_X_MODE:
3675 case ABSOLUTE_Y_MODE:
3676 case INDIRECT_MODE:
3677 /* Operand must fit in 8 bits */
3678 if ((unsigned long)o->integer >= 0x10000) {
3679 warn(o->loc, "operand out of range; truncated");
3680 o->integer &= 0xFFFF;
3682 break;
3684 case RELATIVE_MODE:
3685 /* Constant isn't allowed here is it? */
3686 break;
3688 default:
3689 break;
3692 else if (astnode_is_type(o, STRING_NODE)) {
3693 /* String operand doesn't make sense here */
3694 err(n->loc, "invalid operand");
3696 } else {
3697 /* opcode_get() returned 0xFF */
3698 err(n->loc, "invalid addressing mode");
3700 return 0;
3704 * ### Is this really such a good idea?
3706 static int maybe_merge_data(astnode *n, void *arg, astnode **next)
3708 astnode *temp;
3709 astnode *type;
3710 type = LHS(n);
3711 /* Only merge if no debugging, otherwise line information is lost. */
3712 if (!xasm_args.debug && astnode_is_type(*next, DATA_NODE) &&
3713 astnode_equal(type, LHS(*next)) ) {
3714 /* Merge ahead */
3715 temp = *next;
3716 astnode_finalize( astnode_remove_child_at(temp, 0) ); /* Remove datatype node */
3717 astnode_add_child(n, astnode_remove_children(temp) );
3718 astnode_finalize(temp);
3719 *next = n;
3720 } else {
3721 /* Reduce expressions to final form */
3722 for (n = n->first_child; n != NULL; n = temp->next_sibling) {
3723 temp = reduce_expression_complete(n);
3724 if (astnode_is_type(temp, INTEGER_NODE)) {
3725 /* Check that value fits according to datatype */
3726 switch (type->datatype) {
3727 case BYTE_DATATYPE:
3728 if (!IS_BYTE_VALUE(temp->integer)) {
3729 warn(temp->loc, "operand out of range; truncated");
3730 temp->integer &= 0xFF;
3732 break;
3734 case WORD_DATATYPE:
3735 if (!IS_WORD_VALUE(temp->integer)) {
3736 warn(temp->loc, "operand out of range; truncated");
3737 temp->integer &= 0xFFFF;
3739 break;
3741 case DWORD_DATATYPE:
3742 break;
3744 default:
3745 break;
3750 return 0;
3756 static int maybe_merge_storage(astnode *n, void *arg, astnode **next)
3758 astnode *temp;
3759 astnode *new_count;
3760 astnode *old_count;
3761 if (astnode_is_type(*next, STORAGE_NODE) &&
3762 astnode_equal(LHS(n), LHS(*next)) ) {
3763 /* Merge ahead */
3764 temp = *next;
3765 astnode_finalize( astnode_remove_child_at(temp, 0) ); /* Remove datatype node */
3766 old_count = RHS(n);
3767 /* Calculate new count */
3768 new_count = astnode_create_arithmetic(
3769 PLUS_OPERATOR,
3770 astnode_remove_child_at(temp, 0),
3771 astnode_clone(old_count, n->loc),
3772 n->loc
3774 new_count = reduce_expression_complete(new_count);
3775 astnode_replace(old_count, new_count);
3776 astnode_finalize(old_count);
3777 astnode_finalize(temp);
3778 *next = n;
3779 } else {
3780 reduce_expression_complete(RHS(n));
3782 return 0;
3786 * Replaces .proc by its label followed by statements.
3788 static int flatten_proc(astnode *n, void *arg, astnode **next)
3790 astnode *id = LHS(n);
3791 astnode *list = RHS(n);
3792 astnode_remove(id);
3793 id->type = LABEL_NODE;
3794 astnode_insert_child(list, id, 0);
3795 astnode *stmts = astnode_remove_children(list);
3796 astnode_replace(n, stmts);
3797 astnode_finalize(n);
3798 *next = stmts;
3799 return 0;
3805 static int flatten_var_decl(astnode *n, void *arg, astnode **next)
3807 astnode *stmts = LHS(n);
3808 astnode_remove_children(n);
3809 stmts->type = LABEL_NODE;
3810 astnode_replace(n, stmts);
3811 astnode_finalize(n);
3812 *next = stmts;
3813 return 0;
3817 * Third and final pass (if the output isn't pure 6502).
3818 * Translates instructions, merges data and storage nodes,
3819 * and reduces their operands to final form on the way.
3821 void astproc_third_pass(astnode *root)
3823 /* Table of callback functions for our purpose. */
3824 static astnodeprocmap map[] = {
3825 { INSTRUCTION_NODE, translate_instruction },
3826 { DATA_NODE, maybe_merge_data },
3827 { STORAGE_NODE, maybe_merge_storage },
3828 { VAR_DECL_NODE, flatten_var_decl },
3829 { PROC_NODE, flatten_proc },
3830 { STRUC_DECL_NODE, noop },
3831 { UNION_DECL_NODE, noop },
3832 { ENUM_DECL_NODE, noop },
3833 { RECORD_DECL_NODE, noop },
3834 { 0, NULL }
3836 in_dataseg = 0; /* codeseg is default */
3837 /* Do the walk. */
3838 astproc_walk(root, NULL, map);
3841 /*---------------------------------------------------------------------------*/
3844 * Evaluates the given expression, _without_ replacing it in the AST
3845 * (unlike astproc_reduce_expression() and friends).
3847 static astnode *eval_expression(astnode *expr)
3849 switch (astnode_get_type(expr)) {
3851 case ARITHMETIC_NODE: {
3852 astnode *lhs = eval_expression(LHS(expr));
3853 astnode *rhs = eval_expression(RHS(expr));
3854 switch (expr->oper) {
3855 /* Binary ops */
3856 case PLUS_OPERATOR:
3857 case MINUS_OPERATOR:
3858 case MUL_OPERATOR:
3859 case DIV_OPERATOR:
3860 case MOD_OPERATOR:
3861 case AND_OPERATOR:
3862 case OR_OPERATOR:
3863 case XOR_OPERATOR:
3864 case SHL_OPERATOR:
3865 case SHR_OPERATOR:
3866 case LT_OPERATOR:
3867 case GT_OPERATOR:
3868 case EQ_OPERATOR:
3869 case NE_OPERATOR:
3870 case LE_OPERATOR:
3871 case GE_OPERATOR:
3872 if (astnode_is_type(lhs, INTEGER_NODE)
3873 && astnode_is_type(rhs, INTEGER_NODE)) {
3874 /* Both sides are integer literals. */
3875 switch (expr->oper) {
3876 case PLUS_OPERATOR: return astnode_create_integer(lhs->integer + rhs->integer, expr->loc);
3877 case MINUS_OPERATOR: return astnode_create_integer(lhs->integer - rhs->integer, expr->loc);
3878 case MUL_OPERATOR: return astnode_create_integer(lhs->integer * rhs->integer, expr->loc);
3879 case DIV_OPERATOR: return astnode_create_integer(lhs->integer / rhs->integer, expr->loc);
3880 case MOD_OPERATOR: return astnode_create_integer(lhs->integer % rhs->integer, expr->loc);
3881 case AND_OPERATOR: return astnode_create_integer(lhs->integer & rhs->integer, expr->loc);
3882 case OR_OPERATOR: return astnode_create_integer(lhs->integer | rhs->integer, expr->loc);
3883 case XOR_OPERATOR: return astnode_create_integer(lhs->integer ^ rhs->integer, expr->loc);
3884 case SHL_OPERATOR: return astnode_create_integer(lhs->integer << rhs->integer, expr->loc);
3885 case SHR_OPERATOR: return astnode_create_integer(lhs->integer >> rhs->integer, expr->loc);
3886 case LT_OPERATOR: return astnode_create_integer(lhs->integer < rhs->integer, expr->loc);
3887 case GT_OPERATOR: return astnode_create_integer(lhs->integer > rhs->integer, expr->loc);
3888 case EQ_OPERATOR: return astnode_create_integer(lhs->integer == rhs->integer, expr->loc);
3889 case NE_OPERATOR: return astnode_create_integer(lhs->integer != rhs->integer, expr->loc);
3890 case LE_OPERATOR: return astnode_create_integer(lhs->integer <= rhs->integer, expr->loc);
3891 case GE_OPERATOR: return astnode_create_integer(lhs->integer >= rhs->integer, expr->loc);
3893 default: /* ### Error, actually */
3894 break;
3897 /* Use some mathematical identities... */
3898 else if ((astnode_is_type(lhs, INTEGER_NODE) && (lhs->integer == 0))
3899 && (expr->oper == PLUS_OPERATOR)) {
3900 /* 0+expr == expr */
3901 return astnode_clone(rhs, rhs->loc);
3902 } else if ((astnode_is_type(rhs, INTEGER_NODE) && (rhs->integer == 0))
3903 && (expr->oper == PLUS_OPERATOR)) {
3904 /* expr+0 == expr */
3905 return astnode_clone(lhs, lhs->loc);
3906 } else if ((astnode_is_type(lhs, INTEGER_NODE) && (lhs->integer == 1))
3907 && (expr->oper == MUL_OPERATOR)) {
3908 /* 1*expr == expr */
3909 return astnode_clone(rhs, rhs->loc);
3910 } else if ((astnode_is_type(rhs, INTEGER_NODE) && (rhs->integer == 1))
3911 && ((expr->oper == MUL_OPERATOR) || (expr->oper == DIV_OPERATOR)) ) {
3912 /* expr*1 == expr */
3913 /* expr/1 == expr */
3914 return astnode_clone(lhs, lhs->loc);
3916 break;
3918 /* Unary ops */
3919 case NEG_OPERATOR:
3920 case NOT_OPERATOR:
3921 case LO_OPERATOR:
3922 case HI_OPERATOR:
3923 case UMINUS_OPERATOR:
3924 case BANK_OPERATOR:
3925 if (astnode_is_type(lhs, INTEGER_NODE)) {
3926 switch (expr->oper) {
3927 case NEG_OPERATOR: return astnode_create_integer(~lhs->integer, expr->loc);
3928 case NOT_OPERATOR: return astnode_create_integer(!lhs->integer, expr->loc);
3929 case LO_OPERATOR: return astnode_create_integer(lhs->integer & 0xFF, expr->loc);
3930 case HI_OPERATOR: return astnode_create_integer((lhs->integer >> 8) & 0xFF, expr->loc);
3931 case UMINUS_OPERATOR: return astnode_create_integer(-lhs->integer, expr->loc);
3932 default: break;
3935 break;
3936 } /* switch */
3937 } break;
3939 case INTEGER_NODE:
3940 return astnode_clone(expr, expr->loc);
3942 case IDENTIFIER_NODE: {
3943 symtab_entry *e = symtab_lookup(expr->ident);
3944 // ### assert(e->type == LABEL_SYMBOL);
3945 if (e->flags & ADDR_FLAG)
3946 return astnode_create_integer(e->address, expr->loc);
3947 } break;
3949 case CURRENT_PC_NODE:
3950 return astnode_create_integer(in_dataseg ? dataseg_pc : codeseg_pc, expr->loc);
3952 default:
3953 break;
3954 } /* switch */
3955 return 0;
3959 * Sets the address of the label to be the currently calculated PC.
3961 static int set_label_address(astnode *label, void *arg, astnode **next)
3963 symtab_entry *e = symtab_lookup(label->ident);
3964 // ### assert(e && (e->type == LABEL_SYMBOL));
3965 e->address = in_dataseg ? dataseg_pc : codeseg_pc;
3966 e->flags |= ADDR_FLAG;
3967 return 0;
3971 * Sets the current PC to the address specified by the ORG node.
3973 static int set_pc_from_org(astnode *org, void *arg, astnode **next)
3975 astnode *addr = LHS(org);
3976 assert(astnode_is_type(addr, INTEGER_NODE));
3977 if (in_dataseg)
3978 dataseg_pc = addr->integer;
3979 else
3980 codeseg_pc = addr->integer;
3981 return 0;
3985 * Ensures that the given symbol is defined.
3987 static int ensure_symbol_is_defined(astnode *id, void *arg, astnode **next)
3989 symtab_entry *e = symtab_lookup(id->ident);
3990 assert(e);
3991 if ((e->flags & EXTRN_FLAG) && !(e->flags & ERROR_UNDEFINED_FLAG)) {
3992 err(id->loc, "cannot generate pure binary because `%s' is not defined", id->ident);
3993 e->flags |= ERROR_UNDEFINED_FLAG;
3995 return 0;
3999 * Increments PC according to the size of the instruction.
4001 static int inc_pc_by_instruction(astnode *instr, void *arg, astnode **next)
4003 assert(!in_dataseg);
4004 if (LHS(instr)) {
4005 /* Has operand */
4006 unsigned char zp_op = opcode_zp_equiv(instr->instr.opcode);
4007 if (zp_op != 0xFF) {
4008 /* See if we can optimize this to a ZP-instruction */
4009 astnode *operand = eval_expression(LHS(instr));
4010 if (operand && astnode_is_type(operand, INTEGER_NODE)) {
4011 if ((operand->integer >= 0) && (operand->integer < 256)) {
4012 instr->instr.opcode = zp_op;
4014 astnode_finalize(operand);
4018 codeseg_pc += opcode_length(instr->instr.opcode);
4019 return 1;
4023 * Increments PC according to the size of the defined data.
4025 static int inc_pc_by_data(astnode *data, void *arg, astnode **next)
4027 astnode *type = LHS(data);
4028 int count = astnode_get_child_count(data) - 1;
4029 int nbytes;
4030 assert(!in_dataseg);
4031 switch (type->datatype) {
4032 case BYTE_DATATYPE: nbytes = count; break;
4033 case WORD_DATATYPE: nbytes = count * 2; break;
4034 case DWORD_DATATYPE: nbytes = count * 4; break;
4035 default:
4036 assert(0);
4037 break;
4039 codeseg_pc += nbytes;
4040 return 0;
4044 * Increments PC according to the size of the included binary.
4046 static int inc_pc_by_binary(astnode *node, void *arg, astnode **next)
4048 assert(!in_dataseg);
4049 codeseg_pc += node->binary.size;
4050 return 0;
4054 * Increments PC according to the size of the storage.
4056 static int inc_pc_by_storage(astnode *storage, void *arg, astnode **next)
4058 astnode *type = LHS(storage);
4059 assert(type->datatype == BYTE_DATATYPE);
4060 astnode *count = eval_expression(RHS(storage));
4061 if (count) {
4062 if (astnode_get_type(count) == INTEGER_NODE) {
4063 if (in_dataseg)
4064 dataseg_pc += count->integer;
4065 else
4066 codeseg_pc += count->integer;
4068 astnode_finalize(count);
4070 return 1;
4074 * This pass is only performed if the output format is pure 6502.
4075 * It ensures that it is actually possible to generate pure 6502
4076 * for this syntax tree (i.e. no external symbols).
4077 * Furthermore, it calculates the address of all labels, so that
4078 * everything is ready for the final output phase.
4080 void astproc_fourth_pass(astnode *root)
4082 int x;
4083 /* ### Should loop while there's a change in the address of
4084 one or more labels */
4085 for (x = 0; x < 2; ++x) {
4086 in_dataseg = 0; /* codeseg is default */
4087 dataseg_pc = 0;
4088 codeseg_pc = 0;
4089 /* Table of callback functions for our purpose. */
4090 static astnodeprocmap map[] = {
4091 { DATASEG_NODE, process_dataseg },
4092 { CODESEG_NODE, process_codeseg },
4093 { ORG_NODE, set_pc_from_org },
4094 { LABEL_NODE, set_label_address },
4095 { IDENTIFIER_NODE, ensure_symbol_is_defined },
4096 { INSTRUCTION_NODE, inc_pc_by_instruction },
4097 { DATA_NODE, inc_pc_by_data },
4098 { STORAGE_NODE, inc_pc_by_storage },
4099 { BINARY_NODE, inc_pc_by_binary },
4100 { STRUC_DECL_NODE, noop },
4101 { UNION_DECL_NODE, noop },
4102 { ENUM_DECL_NODE, noop },
4103 { RECORD_DECL_NODE, noop },
4104 { 0, NULL }
4106 /* Do the walk. */
4107 astproc_walk(root, NULL, map);
4111 /*---------------------------------------------------------------------------*/
4114 * Writes an instruction.
4116 static int write_instruction(astnode *instr, void *arg, astnode **next)
4118 FILE *fp = (FILE *)arg;
4119 unsigned char op = instr->instr.opcode;
4120 int len = opcode_length(op);
4121 fputc(op, fp);
4122 if (len > 1) {
4123 /* Write operand */
4124 astnode *operand = eval_expression(LHS(instr));
4125 if(!astnode_is_type(operand, INTEGER_NODE)) {
4126 /* ### This is rather fatal, it should be a literal by this point */
4127 err(instr->loc, "operand does not evaluate to literal");
4128 } else {
4129 int value = operand->integer;
4130 if (len == 2) {
4131 /* Check if it's a relative jump */
4132 switch (op) {
4133 case 0x10:
4134 case 0x30:
4135 case 0x50:
4136 case 0x70:
4137 case 0x90:
4138 case 0xB0:
4139 case 0xD0:
4140 case 0xF0:
4141 /* Calculate difference between target and address of next instruction */
4142 value = value - (codeseg_pc + 2);
4143 if (!IS_BYTE_VALUE(value)) {
4144 err(operand->loc, "branch out of range");
4145 value &= 0xFF;
4147 break;
4149 default:
4150 if (!IS_BYTE_VALUE(value)) {
4151 warn(operand->loc, "operand out of range; truncated");
4152 value &= 0xFF;
4154 break;
4156 fputc((unsigned char)value, fp);
4157 } else {
4158 assert(len == 3);
4159 if (!IS_WORD_VALUE(value)) {
4160 warn(operand->loc, "operand out of range; truncated");
4161 value &= 0xFFFF;
4163 fputc((unsigned char)value, fp);
4164 fputc((unsigned char)(value >> 8), fp);
4167 astnode_finalize(operand);
4169 codeseg_pc += opcode_length(instr->instr.opcode);
4170 return 0;
4174 * Writes data.
4176 static int write_data(astnode *data, void *arg, astnode **next)
4178 FILE *fp = (FILE *)arg;
4179 astnode *type = LHS(data);
4180 astnode *expr;
4181 assert(!in_dataseg);
4182 for (expr = RHS(data); expr != NULL; expr = astnode_get_next_sibling(expr) ) {
4183 int value;
4184 astnode *e = eval_expression(expr);
4185 assert(e->type == INTEGER_NODE);
4186 value = e->integer;
4187 switch (type->datatype) {
4188 case BYTE_DATATYPE:
4189 if (!IS_BYTE_VALUE(value)) {
4190 warn(expr->loc, "operand out of range; truncated");
4191 value &= 0xFF;
4193 fputc((unsigned char)value, fp);
4194 codeseg_pc += 1;
4195 break;
4197 case WORD_DATATYPE:
4198 if (!IS_WORD_VALUE(value)) {
4199 warn(expr->loc, "operand out of range; truncated");
4200 value &= 0xFFFF;
4202 fputc((unsigned char)value, fp);
4203 fputc((unsigned char)(value >> 8), fp);
4204 codeseg_pc += 2;
4205 break;
4207 case DWORD_DATATYPE:
4208 fputc((unsigned char)value, fp);
4209 fputc((unsigned char)(value >> 8), fp);
4210 fputc((unsigned char)(value >> 16), fp);
4211 fputc((unsigned char)(value >> 24), fp);
4212 codeseg_pc += 4;
4213 break;
4215 default:
4216 assert(0);
4217 break;
4219 astnode_finalize(e);
4221 return 0;
4225 * Writes storage (padding).
4227 static int write_storage(astnode *storage, void *arg, astnode **next)
4229 FILE *fp = (FILE *)arg;
4230 astnode *type = LHS(storage);
4231 astnode *count = eval_expression(RHS(storage));
4232 assert(type->datatype == BYTE_DATATYPE);
4233 assert(!in_dataseg);
4234 if (count) {
4235 int i;
4236 assert(astnode_get_type(count) == INTEGER_NODE);
4237 for (i = 0; i < count->integer; ++i)
4238 fputc(0, fp);
4239 codeseg_pc += count->integer;
4240 astnode_finalize(count);
4242 return 0;
4246 * Writes binary.
4248 static int write_binary(astnode *node, void *arg, astnode **next)
4250 FILE *fp = (FILE *)arg;
4251 assert(!in_dataseg);
4252 fwrite(node->binary.data, 1, node->binary.size, fp);
4253 codeseg_pc += node->binary.size;
4254 return 0;
4258 * This pass is only performed if the output format is pure 6502.
4259 * It writes the binary code.
4261 void astproc_fifth_pass(astnode *root)
4263 FILE *fp = fopen(xasm_args.output_file, "wb");
4264 if (!fp) {
4265 fprintf(stderr, "could not open '%s' for writing\n", xasm_args.output_file);
4266 ++err_count;
4267 return;
4269 /* Table of callback functions for our purpose. */
4270 static astnodeprocmap map[] = {
4271 { DATASEG_NODE, process_dataseg },
4272 { CODESEG_NODE, process_codeseg },
4273 { ORG_NODE, set_pc_from_org },
4274 { INSTRUCTION_NODE, write_instruction },
4275 { DATA_NODE, write_data },
4276 { STORAGE_NODE, write_storage },
4277 { BINARY_NODE, write_binary },
4278 { STRUC_DECL_NODE, noop },
4279 { UNION_DECL_NODE, noop },
4280 { ENUM_DECL_NODE, noop },
4281 { RECORD_DECL_NODE, noop },
4282 { 0, NULL }
4284 in_dataseg = 0; /* codeseg is default */
4285 dataseg_pc = 0;
4286 codeseg_pc = 0;
4287 /* Do the walk. */
4288 astproc_walk(root, fp, map);
4289 fclose(fp);