Updated tests to use printsignednumber subroutine from debug.pvvs instead of stdio...
[vvhitespace] / vv_interpreter.c
index 337fd61..b548a50 100644 (file)
@@ -118,10 +118,18 @@ parse_label(uint8_t * code, size_t * pc)
     uint8_t c;
     while ((c = code[(*pc)++]) != '\n') {
         label = label << 1;
     uint8_t c;
     while ((c = code[(*pc)++]) != '\n') {
         label = label << 1;
-        if (c == ' ') label++;
+        if (c == '\t') label++;
+    }
+    return label;
+}
+
+uint16_t
+check_label(size_t * labels, uint16_t label, size_t * pc)
+{
+    if (!labels[label]) {
+        fprintf(stderr, "Trying to process label 0x%X.\n", label);
+        ws_die(pc, "uninitialized label (forgot an include?)");
     }
     }
-    // TODO: Where should I handle attempts to access an unitialized label?
-    //       For now, leave it undefined in a nasal demon sense.
     return label;
 }
 
     return label;
 }
 
@@ -130,11 +138,10 @@ populate_labels(size_t * labels, uint8_t * code, size_t code_size)
 {
     size_t cp = 0;
     while (cp <= code_size) {
 {
     size_t cp = 0;
     while (cp <= code_size) {
-        if (code[cp] == '\v') {
+        if (code[cp++] == '\v') {
             uint16_t temp_label = parse_label(code, &cp);
             labels[temp_label] = cp;
         }
             uint16_t temp_label = parse_label(code, &cp);
             labels[temp_label] = cp;
         }
-        cp++;
     }
 }
 
     }
 }
 
@@ -155,14 +162,26 @@ process_imp_stack(uint8_t * code, size_t * pc, int64_t ** sp)
 
                 /* Now, construct the number and push to TOS. */
                 /* I'm assuming the numbers are read MSb first. */
 
                 /* Now, construct the number and push to TOS. */
                 /* I'm assuming the numbers are read MSb first. */
-                int64_t number = 0;
+                uint64_t number = 0; /* Unsigned to accomodate magnitude of most negative number. */
                 uint8_t temp;
                 while ((temp = next_code_byte(code,pc)) != '\n') {
                     if (temp == '\v') ws_die(pc, "non-binary digit in number");
                     number <<= 1;
                     if (temp == '\t') number++;
                 }
                 uint8_t temp;
                 while ((temp = next_code_byte(code,pc)) != '\n') {
                     if (temp == '\v') ws_die(pc, "non-binary digit in number");
                     number <<= 1;
                     if (temp == '\t') number++;
                 }
-                stack_push(sp, number*sign);
+                /* Without temporarily casting to something >64-bit, the most negative */
+                /* number will overflow when performing 'number*sign'. Instead, we     */
+                /* pick off the most negative number as a special case.                */
+                if (number == (1ULL << 63) && sign == -1) {
+                    /* C parses negative integer literals first as signed positive */
+                    /* integer literals, then applying a unary negation operator.  */
+                    /* Thus, the most negative value is unreachable directly.      */
+                    int64_t number_temp = -9223372036854775807LL; /* First store -((2^63)-1)  */
+                    number_temp--;                                /* Now turn it into -(2^63) */
+                    stack_push(sp, number_temp);
+                } else {
+                    stack_push(sp, number*sign);
+                }
             }
             break;
         case '\n':
             }
             break;
         case '\n':
@@ -234,7 +253,7 @@ process_imp_arithmetic(uint8_t * code, size_t * pc, int64_t ** sp)
                     case '\t':
                         /* Modulo */
                         temp = stack_pop(sp);
                     case '\t':
                         /* Modulo */
                         temp = stack_pop(sp);
-                        stack_push(sp, stack_pop(sp)%temp);
+                        stack_push(sp, llabs(stack_pop(sp) % llabs(temp)));
                         break;
                     default: ws_die(pc, "malformed arithmetic IMP"); break;
                 }
                         break;
                     default: ws_die(pc, "malformed arithmetic IMP"); break;
                 }
@@ -248,6 +267,7 @@ void
 process_imp_flowcontrol(uint8_t * code, size_t * pc, int64_t ** sp, size_t * labels,
                         size_t ** rsp)
 {
 process_imp_flowcontrol(uint8_t * code, size_t * pc, int64_t ** sp, size_t * labels,
                         size_t ** rsp)
 {
+    size_t temp_pc;
     switch (next_code_byte(code,pc)) {
         case '\n':
             /* Technically another LF is required but we ignore it. */
     switch (next_code_byte(code,pc)) {
         case '\n':
             /* Technically another LF is required but we ignore it. */
@@ -266,15 +286,13 @@ process_imp_flowcontrol(uint8_t * code, size_t * pc, int64_t ** sp, size_t * lab
                         break;
                     case '\t':
                         /* Call a subroutine. */
                         break;
                     case '\t':
                         /* Call a subroutine. */
-                        {
-                            size_t temp_pc = labels[parse_label(code, pc)];
-                            *((*rsp)++) = *pc;
-                            *pc = temp_pc;
-                        }
+                        temp_pc = labels[check_label(labels, parse_label(code, pc), pc)];
+                        *((*rsp)++) = *pc;
+                        *pc = temp_pc;
                         break;
                     case '\n':
                         /* Jump unconditionally to a label. */
                         break;
                     case '\n':
                         /* Jump unconditionally to a label. */
-                        *pc = labels[parse_label(code, pc)];
+                        *pc = labels[check_label(labels, parse_label(code, pc), pc)];
                         break;
                     default:
                         ws_die(pc, "malformed flow control IMP");
                         break;
                     default:
                         ws_die(pc, "malformed flow control IMP");
@@ -287,11 +305,13 @@ process_imp_flowcontrol(uint8_t * code, size_t * pc, int64_t ** sp, size_t * lab
                 switch (next_code_byte(code,pc)) {
                     case ' ':
                         /* Jump to a label if TOS == 0 */
                 switch (next_code_byte(code,pc)) {
                     case ' ':
                         /* Jump to a label if TOS == 0 */
-                        if (stack_pop(sp) == 0) *pc = labels[parse_label(code, pc)];
+                        temp_pc = labels[check_label(labels, parse_label(code, pc), pc)];
+                        if (stack_pop(sp) == 0) *pc = temp_pc;
                         break;
                     case '\t':
                         /* Jump to a label if TOS < 0. */
                         break;
                     case '\t':
                         /* Jump to a label if TOS < 0. */
-                        if (stack_pop(sp) < 0) *pc = labels[parse_label(code, pc)];
+                        temp_pc = labels[check_label(labels, parse_label(code, pc), pc)];
+                        if (stack_pop(sp) < 0) *pc = temp_pc;
                         break;
                     case '\n':
                         /* Return from subroutine. */
                         break;
                     case '\n':
                         /* Return from subroutine. */