Skip to content

Instantly share code, notes, and snippets.

@magcius
Created March 16, 2012 07:35
Show Gist options
  • Save magcius/2049013 to your computer and use it in GitHub Desktop.
Save magcius/2049013 to your computer and use it in GitHub Desktop.
#include <glib.h>
typedef struct {
GSList *stack;
char *bytecode;
char *pc;
} MachineState;
static void machine_push (MachineState *state, int v);
static int machine_pop (MachineState *state);
/* pushes an operand onto the operand stack */
static void
op_pushint (MachineState *state,
int v)
{
machine_push (state, v);
}
static void
op_add (MachineState *state)
{
int a, b, res;
a = machine_pop (state);
b = machine_pop (state);
res = a + b;
machine_push (state, res);
}
static void
op_sub (MachineState *state)
{
int a, b, res;
a = machine_pop (state);
b = machine_pop (state);
res = a - b;
machine_push (state, res);
}
static void
op_mul (MachineState *state)
{
int a, b, res;
a = machine_pop (state);
b = machine_pop (state);
res = a * b;
machine_push (state, res);
}
static void
op_mod (MachineState *state)
{
int a, b, res;
a = machine_pop (state);
b = machine_pop (state);
res = a % b;
machine_push (state, res);
}
static void
op_div (MachineState *state)
{
int a, b, res;
a = machine_pop (state);
b = machine_pop (state);
res = a / b;
machine_push (state, res);
}
static void
op_pop (MachineState *state)
{
machine_pop (state);
}
static void
op_dup (MachineState *state)
{
int a;
a = machine_pop (state);
machine_push (state, a);
machine_push (state, a);
}
static void
op_swap (MachineState *state)
{
int a, b;
a = machine_pop (state);
b = machine_pop (state);
machine_push (state, a);
machine_push (state, b);
}
static void
op_print (MachineState *state)
{
int a;
a = machine_pop (state);
g_print ("%d\n", a);
}
static void
op_jmp (MachineState *state,
int loc)
{
/* minus one because pc is unconditionally
* incremented after each op */
state->pc = state->bytecode + loc - 1;
}
static void
op_jz (MachineState *state,
int loc)
{
int test;
test = machine_pop (state);
if (test == 0)
op_jmp (state, loc);
}
static void
op_jnz (MachineState *state,
int loc)
{
int test;
test = machine_pop (state);
if (test != 0)
op_jmp (state, loc);
}
typedef enum {
/* NUL marks the end of the bytecode stream */
OP_NUL = 0,
OP_SWAP,
OP_DUP,
OP_ADD,
OP_SUB,
OP_MUL,
OP_DIV,
OP_MOD,
OP_PRINT,
OP_PUSHINT,
OP_JMP,
OP_JZ,
OP_JNZ,
OP_LAST
} MachineOperation;
/* Because we have different signatures, use a
* void * pointer that we'll cast in the runner. */
static void * operation_funcs[] = {
NULL,
op_swap,
op_dup,
op_add,
op_sub,
op_mul,
op_div,
op_mod,
op_print,
op_pushint,
op_jmp,
op_jz,
op_jnz
};
typedef void (*NoArgumentOp) (MachineState *state);
typedef void (*OneArgumentOp) (MachineState *state, int argument);
static void
machine_run (MachineState *state)
{
state->pc = state->bytecode;
while (*state->pc != OP_NUL) {
char op = *state->pc;
if (op >= OP_LAST) {
g_print ("Operation %d is invalid", op);
return;
} else if (op >= OP_PUSHINT) {
OneArgumentOp func = (OneArgumentOp) operation_funcs[op];
int argument = *(++ state->pc);
func (state, argument);
} else {
NoArgumentOp func = (NoArgumentOp) operation_funcs[op];
func (state);
}
++ state->pc;
}
}
int
main (int argc, char **argv)
{
MachineState state;
int end = 28;
int odd = 23;
char bytecode[] = {
/* Print the current value. */
OP_DUP,
OP_PRINT,
/* If the value is 1, we're finished. */
OP_DUP,
OP_PUSHINT, 1,
OP_SUB,
OP_JZ, end,
/* At the top of the loop, we have a value
* on the stack that's our current Collatz value.
* Do an even/odd test. */
OP_DUP,
OP_PUSHINT, 2,
OP_SWAP,
OP_MOD,
OP_JNZ, odd,
/* Value is even. */
OP_PUSHINT, 3,
OP_MUL,
OP_PUSHINT, 1,
OP_ADD,
OP_JMP, 0,
/* Value is odd. */
OP_PUSHINT, 2,
OP_SWAP,
OP_DIV,
OP_JMP, 0,
OP_NUL
};
state.stack = NULL;
state.bytecode = bytecode;
machine_push (&state, 23);
machine_run (&state);
return 0;
}
static void
machine_push (MachineState *state,
int v)
{
state->stack = g_slist_prepend (state->stack, GINT_TO_POINTER (v));
}
static int
machine_pop (MachineState *state)
{
int v;
v = GPOINTER_TO_INT (state->stack->data);
state->stack = g_slist_delete_link (state->stack, state->stack);
return v;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment