Created
July 20, 2015 09:59
-
-
Save tonysimpson/ddea0c791755ad97a992 to your computer and use it in GitHub Desktop.
Example of a computed jump based interpreter.
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 <stdint.h> | |
#include <stdio.h> | |
#include <stdbool.h> | |
#include <windows.h> | |
typedef struct { | |
union { | |
bool bool_value; | |
int64_t int64_value; | |
double double_value; | |
void *void_ptr_value; | |
}; | |
} unitype; | |
typedef struct { | |
uint16_t jump_idx; | |
int16_t arg; | |
} instruction; | |
#define GOTO_INSTRUCTION goto *(&&next + jump_table[instructions->jump_idx]) | |
#define | |
unitype jump_machine(unitype * constants, instruction * instructions, bool compile) { | |
static const int jump_table[] = { | |
0, /* 0 */ | |
&&rel_jump - &&next, /* 1 */ | |
&&load_const_reg1 - &&next, /* 2 */ | |
&&load_const_reg2 - &&next, /* 3 */ | |
&&load_const_reg3 - &&next, /* 4 */ | |
&&add_double_reg1_reg2_reg1 - &&next, /* 5 */ | |
&&compare_double_less_than_reg1_reg3_reg4 - &&next, /* 6 */ | |
&&rel_jump_if_reg4 - &&next, /* 7 */ | |
&&return_reg1 - &&next /* 8 */ | |
}; | |
register unitype reg1; | |
register unitype reg2; | |
register unitype reg3; | |
register unitype reg4; | |
GOTO_INSTRUCTION; | |
next: | |
{ | |
instructions++; | |
GOTO_INSTRUCTION; | |
} | |
rel_jump: | |
{ | |
instructions += instructions->arg; | |
GOTO_INSTRUCTION; | |
} | |
load_const_reg1: | |
{ | |
reg1 = constants[instructions->arg]; | |
goto next; | |
} | |
load_const_reg2: | |
{ | |
reg2 = constants[instructions->arg]; | |
goto next; | |
} | |
load_const_reg3: | |
{ | |
reg3 = constants[instructions->arg]; | |
goto next; | |
} | |
add_double_reg1_reg2_reg1: | |
{ | |
reg1.double_value += reg2.double_value; | |
goto next; | |
} | |
compare_double_less_than_reg1_reg3_reg4: | |
{ | |
reg4.bool_value = reg1.double_value < reg3.double_value; | |
goto next; | |
} | |
rel_jump_if_reg4: | |
{ | |
if(reg4.bool_value) { | |
goto rel_jump; | |
} | |
goto next; | |
} | |
return_reg1: | |
{ | |
return reg1; | |
} | |
} | |
int main(int argc, char *argv[]) { | |
unitype constants[] = {{.double_value = 0.5}, {.double_value = 0.75}, {.double_value = 5000000.0}}; | |
instruction instructions[] = { | |
{2, 0}, /* load 0.5 in reg1 */ | |
{3, 1}, /* load 0.75 in reg2 */ | |
{4, 2}, /* load 5000000.0 in reg3 */ | |
{5, 0}, /* reg1 += reg2, jumps here */ | |
{6, 0}, /* reg4 = reg1 < reg3 */ | |
{7, -2}, /* jump -2 if reg4 */ | |
{8, 0} /* return reg1 */ | |
}; | |
LARGE_INTEGER start, end; | |
LARGE_INTEGER freq; | |
double duration; | |
QueryPerformanceCounter(&start); | |
unitype result = jump_machine(constants, instructions); | |
QueryPerformanceCounter(&end); | |
QueryPerformanceFrequency(&freq); | |
duration = ((end.QuadPart - start.QuadPart) * 1.0) / freq.QuadPart; | |
printf("%.09Lg\n", duration); | |
printf("result %f\n", result.double_value); | |
fflush(stdout); | |
QueryPerformanceCounter(&start); | |
double i = 0.5; | |
while(i < 5000000.0) { | |
i += 0.75; | |
} | |
QueryPerformanceCounter(&end); | |
duration = ((end.QuadPart - start.QuadPart) * 1.0) / freq.QuadPart; | |
printf("%.09Lg\n", duration); | |
printf("result %f\n", i); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment