Created
January 14, 2019 12:19
-
-
Save alphaKAI/94c7f44699128c701bbfb3c425c61ec1 to your computer and use it in GitHub Desktop.
Tiny example of direct threaded vm and a naive switch-case implementation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
// Instruction set | |
enum { | |
Push, | |
Add, | |
Sub, | |
Mul, | |
Div, | |
Print, | |
End | |
}; | |
#define STACK_SIZE 1024 | |
int stack[STACK_SIZE]; | |
size_t stack_count = 0; | |
void init_stack() { | |
stack_count = 0; | |
} | |
void push(int v) { | |
stack[stack_count++] = v; | |
} | |
int pop() { | |
if (stack_count > 0) { | |
return stack[--stack_count]; | |
} else { | |
fprintf(stderr, "out of stack\n"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
// naive implementation | |
void itpr1(int ops[], size_t ops_length) { | |
init_stack(); | |
int op, a, b, v; | |
for (size_t i = 0; i < ops_length; i++) { | |
op = ops[i]; | |
switch (op) { | |
case Push: | |
if(!(i + 1 < ops_length && stack_count + 1 < STACK_SIZE)) { | |
fprintf(stderr, "out of order\n"); | |
exit(EXIT_FAILURE); | |
} | |
int v = ops[++i]; | |
push(v); | |
break; | |
case Add: | |
b = pop(); | |
a = pop(); | |
push(a + b); | |
break; | |
case Sub: | |
b = pop(); | |
a = pop(); | |
push(a - b); | |
break; | |
case Mul: | |
b = pop(); | |
a = pop(); | |
push(a * b); | |
break; | |
case Div: | |
b = pop(); | |
a = pop(); | |
push(a / b); | |
break; | |
case Print: | |
v = pop(); | |
push(v); | |
printf("v : %d\n", v); | |
break; | |
case End: | |
return; | |
default: | |
fprintf(stderr, "no default\n"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
} | |
void* xmalloc(size_t size) { | |
void* ptr = malloc(size); | |
if (ptr == NULL) { | |
fprintf(stderr, "Failed to allocate memory\n"); | |
exit(EXIT_FAILURE); | |
} | |
return ptr; | |
} | |
// Direct Threaded VM | |
void itpr2(int ops[], size_t ops_length) { | |
init_stack(); | |
int op = 0, a = 0, b = 0, v = 0; | |
int i = 0; | |
static void* table[] = { | |
&&L_push, | |
&&L_add, | |
&&L_sub, | |
&&L_mul, | |
&&L_div, | |
&&L_print, | |
&&L_end | |
}; | |
void** ops_ptr = xmalloc(sizeof(void*) * ops_length); | |
for(int j = 0; j < ops_length; j++){ | |
ops_ptr[j] = table[ops[j]]; | |
} | |
loop_start: | |
op = ops[i]; | |
goto *table[op]; | |
L_push: | |
{ | |
if(!(i + 1 < ops_length && stack_count + 1 < STACK_SIZE)) { | |
fprintf(stderr, "out of range\n"); | |
exit(EXIT_FAILURE); | |
} | |
v = ops[++i]; | |
push(v); | |
i++; | |
goto *ops_ptr[i]; | |
} | |
L_add: | |
{ | |
b = pop(); | |
a = pop(); | |
push(a + b); | |
i++; | |
goto *ops_ptr[i]; | |
} | |
L_sub: | |
{ | |
b = pop(); | |
a = pop(); | |
push(a - b); | |
i++; | |
goto *ops_ptr[i]; | |
} | |
L_mul: | |
{ | |
b = pop(); | |
a = pop(); | |
push(a * b); | |
i++; | |
goto *ops_ptr[i]; | |
} | |
L_div: | |
{ | |
b = pop(); | |
a = pop(); | |
push(a / b); | |
i++; | |
goto *ops_ptr[i]; | |
} | |
L_print: | |
{ | |
v = pop(); | |
push(v); | |
printf("v : %d\n", v); | |
i++; | |
goto *ops_ptr[i]; | |
} | |
L_end: | |
return; | |
} | |
int main() { | |
int ops[] = { | |
Push, 1, | |
Push, 2, | |
Add, | |
Print, | |
End | |
}; | |
size_t ops_len = sizeof(ops)/sizeof(ops[0]); | |
printf("itpr1:\n"); | |
itpr1(ops, ops_len); | |
printf("itpr2:\n"); | |
itpr2(ops, ops_len); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment