fixes for assembler - label addrs and DAT statements
[dcpu16] / as-dcpu16.c
index 820b8376cf2b0f1365fc5212d4a888a050debe72..f22e848867ce58d74c831dff22c0c6ab5e7a9042 100644 (file)
@@ -22,6 +22,7 @@
  *    needs ability to specify location for code or data
  *    needs ability to specify label as relative to another label
  *    short labels not correctly computed
+ *    in label struct, store index of instruction rather than ptr, ptrs for iteration in addr calculation are ugly
  */
 
 static const char * const src_id_ = "$Id$";
@@ -140,9 +141,14 @@ void label_addr_calculate_(struct dynamic_array *instructionps, struct dynamic_a
 
         l = (struct label_ *)DYNARRAY_ITEM(*labels, i);
 
+        DEBUG_PRINTFQ("%s: calculating address of label '%s'\n", __func__, l->label);
+
+#if 0
+force full resolution while debugging
         /* if it's already calculated, great. */
         if (l->ready)
             continue;
+#endif
 
         /*
          *  starting at the instruction for this label,
@@ -150,14 +156,24 @@ void label_addr_calculate_(struct dynamic_array *instructionps, struct dynamic_a
          *  until we get to the start or a known prior label address.
          *  update our label with the freshly calculated addr
          */
-        for (instr = ((struct label_ *)DYNARRAY_ITEM(*labels, i))->instr;
-             instr >= (struct instruction_ **)DYNARRAY_ITEM(*instructionps, 0);
-             instr--) {
 
-            if ((*instr)->ready)
-                DEBUG_PRINTF("%s: instr not ready\n", __func__);
+        /* first fetch the instruction associated with the label we want to know about.. */
+        /* the addr of this instruction will be whatever follows all the preceding instructions */
+        /* so back up one before counting instruction lengths... */
+        instr = ((struct label_ *)DYNARRAY_ITEM(*labels, i))->instr;
+        /* is it the first one? */
+        if (instr == (struct instruction_ **)DYNARRAY_ITEM(*instructionps, 0))
+            break;
+
+        instr--;
+
+        while (instr >= (struct instruction_ **)DYNARRAY_ITEM(*instructionps, 0)) {
+            if ((*instr)->ready == 0)
+                DEBUG_PRINTF("%s: instr '%s' not ready\n", __func__, (*instr)->opcode);
             word_count += (*instr)->length;
 
+            DEBUG_PRINTF("%s: instr '%s' takes '%u' bytes\n", __func__, (*instr)->opcode, (*instr)->length);
+
             /* have we come across an instruction which a label points to?
                it should already be calculated, so just add that on and be done */
             if ((*instr)->label
@@ -174,6 +190,7 @@ void label_addr_calculate_(struct dynamic_array *instructionps, struct dynamic_a
                 word_count += addr;
                 break;
             }
+            instr--;
         }
         l->addr = word_count;
         l->ready = 1;
@@ -373,6 +390,8 @@ int value_bits_(struct dynamic_array *labels, const char *operand_orig, DCPU16_W
             char *reg;
             char *constant;
 
+            DEBUG_PRINTFQ("is multipart.. ");
+
             /* eat the plus */
             *ep = '\0';
             ep++;
@@ -410,10 +429,13 @@ int value_bits_(struct dynamic_array *labels, const char *operand_orig, DCPU16_W
                 *nextwordused += 1;
                 DEBUG_PRINTFQ("is a dereferenced register (%c) + constant (%hu)\n", *reg, *nextword);
                 return 0x10 | register_enumerate_(*reg);
-            } else if (errno) {
+            } else if (errno == ERANGE) {
+#if 0
+oh, right, labels fall through
                 DEBUG_PRINTFQ("is out of range\n");
                 fprintf(stderr, "trouble with operand '%s': %s\n", operand_orig, strerror(errno));
                 return -1;
+#endif
             }
 
             /* what? still here? assume it's a label, I guess */
@@ -509,9 +531,9 @@ int instruction_print_(struct instruction_ *i, unsigned int with_label) {
     int r;
 
     if (with_label)
-        r = printf("%-16s %3s", i->label ? i->label : "", i->opcode);
-    else
-        r = printf("%3s", i->opcode);
+        r = printf("%-16s ", i->label ? i->label : "");
+
+        r = printf("%3s", i->opcode ? i->opcode : "");
 
     for (o = i->operands; o; o = o->next)
         r += printf(" %s%s", o->operand, o->next ? "," : "");
@@ -523,6 +545,7 @@ int instruction_print_(struct instruction_ *i, unsigned int with_label) {
  *  Parses a zero-terminated line of input into a newly-allocated struct instruction_.
  *  [label] instruction [operand[,operand[,...]]]
  *  Does no validation of contents of any of these tokens, as of yet.
+ *  does not clean up after itself if a malloc fails
  */
 static
 int tokenize_line_(char *line, struct instruction_ **next_instr) {
@@ -594,6 +617,7 @@ int tokenize_line_(char *line, struct instruction_ **next_instr) {
         /* if we have an opcode, we'll need at least one word to compile instruction */
         instr_words_needed++;
 
+        /* build a list of operands to hang off this instruction */
         while ( (x = strqtok_r(NULL, ",", '\\', quotes, &qt, &st)) ) {
             struct operand_ *new_operand;
             char *y;
@@ -688,13 +712,25 @@ int instr_assemble_(struct dynamic_array *labels, struct instruction_ *i, unsign
     if (opt_.verbose > 2) {
         printf("%s: assembling %p ", __func__, i);
         instruction_print_(i, 1);
-        printf("(line :%zu)\n", i->src_line);
+        printf("(line %zu)\n", i->src_line);
     }
 
+#if 0
+while debugging, always reassemble
     if (i->ready) {
         /* already assembled, nothing to do */
         return 0;
     }
+#endif
+
+    if (i->opcode == NULL) {
+        assert(i->label);
+        assert(i->operands == NULL);
+        /* just a label, move along */
+        i->length = 0;
+        i->ready = 1;
+        return 0;
+    }
 
     /* special case DAT */
     if (strncasecmp(i->opcode, "DAT", 3) == 0) {
@@ -710,6 +746,7 @@ int instr_assemble_(struct dynamic_array *labels, struct instruction_ *i, unsign
             DEBUG_PRINTF("DAT operand:'%s' next:%p\n", o->operand, o->next);
 
             /* is this a string? */
+            /* does it start with a quote, and end with the same quote? */
             if ( (x = strchr("\"'`", o->operand[0])) ) {
                 dat_len = strlen(o->operand) - 1;
                 if (o->operand[dat_len] == *x) {
@@ -746,7 +783,7 @@ int instr_assemble_(struct dynamic_array *labels, struct instruction_ *i, unsign
 
             /* otherwise assume it's a label, even if we don't know what it is */
             if (label_addr_(labels, o->operand, &i->instr_words[i->length])) {
-                DEBUG_PRINTF("(deferred label resolution)\n");
+                DEBUG_PRINTF("(deferred label '%s' resolution)\n", o->operand);
                 incomplete = 1;
             }
             i->length++;