X-Git-Url: http://git.subgeniuskitty.com/vvhitespace/.git/blobdiff_plain/9686c90139fc19b70f42283b1504ab9d5be7932c..a2664738ebe0f2129ca4b547ec977ea0ce1d6e4d:/vv_interpreter.c?ds=inline diff --git a/vv_interpreter.c b/vv_interpreter.c index 39210f1..ca2f772 100644 --- a/vv_interpreter.c +++ b/vv_interpreter.c @@ -11,6 +11,7 @@ #include #include #include +#include #define VERSION 1 @@ -46,12 +47,38 @@ stdin_empty(void) return 1; } +void +set_terminal_mode(void) +{ + struct termios options; + tcgetattr(STDIN_FILENO, &options); + /* Create a cbreak-like environment through the following options. */ + options.c_lflag &= ~ECHO; /* Disable echoing of input characters. */ + options.c_lflag &= ~ICANON; /* Disable cooked/line-oriented mode. */ + options.c_cc[VMIN] = 1; + options.c_cc[VTIME] = 0; + tcsetattr(STDIN_FILENO, TCSANOW, &options); +} + +void +unset_terminal_mode(void) +{ + struct termios options; + tcgetattr(STDIN_FILENO, &options); + /* Undo the changes made in set_terminal_mode(). */ + options.c_lflag |= ECHO; /* Enable echoing of input characters. */ + options.c_lflag |= ICANON; /* Enable cooked/line-oriented mode. */ + options.c_cc[VMIN] = 1; /* Default value from /usr/src/sys/sys/ttydefaults.h */ + options.c_cc[VTIME] = 0; /* Default value from /usr/src/sys/sys/ttydefaults.h */ + tcsetattr(STDIN_FILENO, TCSANOW, &options); +} + void ws_die(size_t * pc, char * msg) { - printf("\n"); printf("SIM_ERROR @ PC %lu: %s\n", *pc, msg); fflush(stdout); + unset_terminal_mode(); exit(EXIT_FAILURE); } @@ -223,8 +250,8 @@ process_imp_flowcontrol(uint8_t * code, size_t * pc, int32_t ** sp, uint32_t * l switch (next_code_byte(code,pc)) { case '\n': /* Technically another LF is required but we ignore it. */ - printf("\n"); fflush(stdout); + unset_terminal_mode(); exit(EXIT_SUCCESS); case ' ': { @@ -234,12 +261,15 @@ process_imp_flowcontrol(uint8_t * code, size_t * pc, int32_t ** sp, uint32_t * l if (next_code_byte(code,pc) != '\v') ws_die(pc,"expected vtab, " "perhaps a whitespace program, rather than vvhitespace?"); /* Jump to next instruction since labels were parsed during startup. */ - parse_label( code, pc); + parse_label(code, pc); break; case '\t': /* Call a subroutine. */ - *((*rsp)++) = *pc; - *pc = labels[parse_label(code, pc)]; + { + size_t temp_pc = labels[parse_label(code, pc)]; + *((*rsp)++) = *pc; + *pc = temp_pc; + } break; case '\n': /* Jump unconditionally to a label. */ @@ -256,10 +286,12 @@ process_imp_flowcontrol(uint8_t * code, size_t * pc, int32_t ** sp, uint32_t * l switch (next_code_byte(code,pc)) { case ' ': /* Jump to a label if TOS == 0 */ + /* TODO: Does WS pop or peek the TOS? */ if (stack_peek(sp,0) == 0) *pc = labels[parse_label(code, pc)]; break; case '\t': /* Jump to a label if TOS < 0. */ + /* TODO: Does WS pop or peek the TOS? */ if (stack_peek(sp,0) < 0) *pc = labels[parse_label(code, pc)]; break; case '\n': @@ -282,9 +314,21 @@ void process_imp_heap(uint8_t * code, size_t * pc, int32_t ** sp, int32_t ** hp) { switch (next_code_byte(code,pc)) { - case ' ' : /* Store to heap */ *(*hp + *((*sp)-1)) = **sp; *sp -= 2; break; - case '\t': /* Retrieve from heap */ **sp = *(*hp + **sp); break; - default : ws_die(pc, "malformed heap IMP"); break; + case ' ' : + /* Store to heap */ + { + int32_t value = stack_pop(sp); + int32_t addr = stack_pop(sp); + *(*hp + addr) = value; + } + break; + case '\t': + /* Retrieve from heap */ + stack_push(sp, *(*hp + stack_pop(sp))); + break; + default: + ws_die(pc, "malformed heap IMP"); + break; } } @@ -296,8 +340,8 @@ process_imp_io(uint8_t * code, size_t * pc, int32_t ** sp, int32_t ** hp) /* Output */ { switch (next_code_byte(code,pc)) { - case ' ' : /* Output character from TOS */ printf("%c", stack_pop(sp)); break; - case '\t': /* Output number from TOS */ printf("%d", stack_pop(sp)); break; + case ' ' : /* Output char from TOS */ printf("%c", stack_pop(sp)); break; + case '\t': /* Output digit from TOS */ printf("%c", stack_pop(sp)+'0'); break; default : ws_die(pc, "malformed output IMP"); break; } fflush(stdout); @@ -310,7 +354,7 @@ process_imp_io(uint8_t * code, size_t * pc, int32_t ** sp, int32_t ** hp) char c = getchar(); switch (next_code_byte(code,pc)) { case '\t': /* Input digit */ c -= '0'; /* fallthrough */ - case ' ' : /* Input character */ *(*hp + *((*sp)--)) = c; break; + case ' ' : /* Input character */ *(*hp + *(--(*sp))) = c; break; default : ws_die(pc, "malformed input IMP"); break; } } @@ -387,13 +431,14 @@ main(int argc, char ** argv) /* * Main Loop */ - + set_terminal_mode(); size_t pc = 0; /* Virtual program counter. Operates in the ws_code_space[] address space. */ while (1) { 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(); } // TODO: Have the SIGTERM signal handler and normal term point return the value // on TOS so I can do rudimentary automated tests. @@ -435,4 +480,5 @@ main(int argc, char ** argv) printf("Program executed.\n"); exit(EXIT_SUCCESS); + unset_terminal_mode(); }