/*
* (c) 2019 Aaron Taylor <ataylor at subgeniuskitty dot com>
- * All rights reserved.
+ * See LICENSE.txt file for copyright and license details.
*/
#include <stdio.h>
#define VERSION 1
-#define HEAPSIZE 1024 /* Size of heap in words */
-#define DATASTACKSIZE 1024 /* Size of stack in words */
-#define RETURNSTACKSIZE 1024 /* Max subroutine call depth */
+#define HEAPSIZE 65536 /* Size of heap in words */
+#define DATASTACKSIZE 65536 /* Size of stack in words */
+#define RETURNSTACKSIZE 65536 /* Max subroutine call depth */
void
print_usage(char ** argv)
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;
}
{
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;
}
- cp++;
}
}
/* 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++;
}
- 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':
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;
}
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. */
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. */
- *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");
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. */
- 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. */
if (pc >= ws_code_size) {
fprintf(stderr, "SIM_ERROR: PC Overrun\n Requested PC: %lu\n Max Address: %lu\n",
pc, ws_code_size-1);
- exit(EXIT_FAILURE);
unset_terminal_mode();
+ exit(EXIT_FAILURE);
}
/* Decode the IMPs */