Created
April 4, 2010 08:30
-
-
Save cdleary/355236 to your computer and use it in GitHub Desktop.
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> | |
#include <stdbool.h> | |
#define STACK_SIZE 1024 | |
#ifdef DEBUG | |
# define ASSERT(__condition) do { \ | |
if (!(__condition)) { \ | |
printf("Assertion failure: " #__condition); \ | |
abort(); \ | |
} \ | |
} while (false) | |
#else | |
# define ASSERT(__condition) | |
#endif | |
typedef union { | |
enum BytecodeValues { | |
LOAD_IMM = 0, | |
ADD = 1, | |
SUB = 2, | |
MUL = 3, | |
PRINT = 4, | |
POP = 5, | |
SWAP = 6, | |
STOP = 7, | |
} name; | |
struct { | |
unsigned precise : 3; | |
} bitflag; | |
int value; | |
} Bytecode; | |
#define PRECISE(__bytecode) ((__bytecode).bitflag.precise) | |
Bytecode program[] = {LOAD_IMM, (Bytecode) 6, LOAD_IMM, (Bytecode) 5, LOAD_IMM, (Bytecode) 4, | |
SUB, SUB, PRINT, STOP}; | |
static int stack[STACK_SIZE]; | |
static int vpc = 0; | |
static int sp = 0; /* Limit index (no value at it). */ | |
int | |
Interpret() { | |
#define DISPATCH do { \ | |
switch (PRECISE(program[vpc++])) { \ | |
case LOAD_IMM: goto load_imm; \ | |
case ADD: goto add; \ | |
case SUB: goto sub; \ | |
case MUL: goto mul; \ | |
case PRINT: goto print; \ | |
case POP: goto pop; \ | |
case SWAP: goto swap; \ | |
case STOP: goto stop; \ | |
default: goto bad_opcode; \ | |
} \ | |
} while (false) | |
int retcode; | |
switch (PRECISE(program[vpc++])) { | |
load_imm: | |
case LOAD_IMM: | |
stack[sp] = program[vpc++].value; | |
sp += 1; | |
DISPATCH; | |
add: | |
case ADD: | |
ASSERT(sp > 1); | |
stack[sp - 2] = stack[sp - 2] + stack[sp - 1]; | |
sp -= 1; | |
DISPATCH; | |
sub: | |
case SUB: | |
ASSERT(sp > 1); | |
stack[sp - 2] = stack[sp - 2] - stack[sp - 1]; | |
sp -= 1; | |
DISPATCH; | |
mul: | |
case MUL: | |
ASSERT(sp > 1); | |
stack[sp - 2] = stack[sp - 2] * stack[sp - 1]; | |
sp -= 1; | |
DISPATCH; | |
print: | |
case PRINT: | |
ASSERT(sp > 0); | |
printf("%d\n", stack[sp - 1]); | |
sp -= 1; | |
DISPATCH; | |
pop: | |
case POP: | |
ASSERT(sp > 0); | |
sp--; | |
DISPATCH; | |
swap: | |
case SWAP: | |
{ | |
ASSERT(sp > 1); | |
int tmp = stack[sp - 2]; | |
stack[sp - 2] = stack[sp - 1]; | |
stack[sp - 1] = tmp; | |
DISPATCH; | |
} | |
stop: | |
case STOP: | |
retcode = (sp > 0) ? EXIT_FAILURE : EXIT_SUCCESS; | |
break; | |
bad_opcode: | |
default: | |
retcode = EXIT_FAILURE; | |
} | |
printf("Done: %d\n", retcode); | |
return retcode; | |
#undef DISPATCH | |
} | |
#ifdef EXECUTABLE | |
int | |
main(int argc, char **argv) { | |
return Interpret(); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment