Created
July 17, 2012 09:34
-
-
Save mgronhol/6553af49ff4d173c29b2 to your computer and use it in GitHub Desktop.
Small stack virtual machine
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
/* | |
Commands in the virtual machine | |
+ - * / :Pop two numbers from the stack, [add|sub|mul|div] them and push the result back | |
pop :Pops a value from the stack | |
print :Pops a value from the stack and prints it to stdout | |
dup :Duplicates the value which is on top of the stack | |
swap :Swaps two topmost values together | |
push :Pushes value to stack | |
syscall : Do a "syscall" | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
/* Byte code commands */ | |
#define COMMAND_ADD -1000 | |
#define COMMAND_SUB -1001 | |
#define COMMAND_MUL -1002 | |
#define COMMAND_DIV -1003 | |
#define COMMAND_POP -1004 | |
#define COMMAND_PRINT -1005 | |
#define COMMAND_DUP -1006 | |
#define COMMAND_SWAP -1007 | |
#define COMMAND_PUSH -1008 | |
#define COMMAND_SYSCALL -1009 | |
/* System call function pointer defs */ | |
typedef int (*ptr_syscall0)(); | |
typedef int (*ptr_syscall1)(int); | |
typedef int (*ptr_syscall2)(int, int); | |
typedef int (*ptr_syscall3)(int, int, int); | |
/* Syscall struct */ | |
typedef struct Syscall { | |
int params; | |
void *func; | |
} syscall_t; | |
typedef struct Stack { | |
int *values; | |
int pos; | |
int size; | |
} pstack_t; | |
typedef struct Context { | |
pstack_t *code, *stack; | |
syscall_t syscalls[32]; | |
} context_t; | |
pstack_t* stack_create( int size ){ | |
pstack_t *out; | |
if( size < 0 ){ | |
return NULL; | |
} | |
out = (pstack_t *)malloc( sizeof( pstack_t ) ); | |
out->values = (int *)malloc( sizeof( int ) * size ); | |
memset( out->values, 0, size ); | |
out->pos = -1; /* Empty stack has no entries (starts from zero) */ | |
out->size = size; | |
return out; | |
} | |
void stack_free( pstack_t *stack ){ | |
free( stack->values ); | |
free( stack ); | |
} | |
void stack_push( pstack_t *stack, int value ){ | |
stack->pos += 1; | |
if( stack->pos >= stack->size ){ | |
/* error! */ | |
return; | |
} | |
stack->values[ stack->pos ] = value; | |
} | |
int stack_pop( pstack_t * stack ){ | |
int out; | |
if( stack->pos < 0 ){ | |
/* Error! */ | |
return 0; | |
} | |
out = stack->values[ stack->pos ]; | |
stack->pos -= 1; | |
return out; | |
} | |
int stack_is_empty( pstack_t *stack ){ | |
return stack->pos < 0; | |
} | |
void syscall_register( context_t *ctx, int call_id, int Nparams, void *func_pointer ){ | |
ctx->syscalls[call_id].params = Nparams; | |
ctx->syscalls[call_id].func = func_pointer; | |
} | |
int execute( context_t *ctx ){ | |
int cmd = stack_pop( ctx->code ); | |
switch( cmd ){ | |
case COMMAND_ADD: | |
{ | |
int value0, value1; | |
value0 = stack_pop( ctx->stack ); | |
value1 = stack_pop( ctx->stack ); | |
stack_push( ctx->stack, value0 + value1 ); | |
} | |
break; | |
case COMMAND_SUB: | |
{ | |
int value0, value1; | |
value0 = stack_pop( ctx->stack ); | |
value1 = stack_pop( ctx->stack ); | |
stack_push( ctx->stack, value0 - value1 ); | |
} | |
break; | |
case COMMAND_MUL: | |
{ | |
int value0, value1; | |
value0 = stack_pop( ctx->stack ); | |
value1 = stack_pop( ctx->stack ); | |
stack_push( ctx->stack, value0 * value1 ); | |
} | |
break; | |
case COMMAND_DIV: | |
{ | |
int value0, value1; | |
value0 = stack_pop( ctx->stack ); | |
value1 = stack_pop( ctx->stack ); | |
stack_push( ctx->stack, value0 / value1 ); | |
} | |
break; | |
case COMMAND_POP: | |
{ | |
stack_pop( ctx->stack ); | |
} | |
break; | |
case COMMAND_PRINT: | |
{ | |
int value; | |
value = stack_pop( ctx->stack ); | |
printf( "print: %i \n", value ); | |
} | |
break; | |
case COMMAND_DUP: | |
{ | |
int value; | |
value = stack_pop( ctx->stack ); | |
stack_push( ctx->stack, value ); | |
stack_push( ctx->stack, value ); | |
} | |
break; | |
case COMMAND_SWAP: | |
{ | |
int value0, value1; | |
value0 = stack_pop( ctx->stack ); | |
value1 = stack_pop( ctx->stack ); | |
stack_push( ctx->stack, value0 ); | |
stack_push( ctx->stack, value1 ); | |
} | |
break; | |
case COMMAND_PUSH: | |
{ | |
int value; | |
value = stack_pop( ctx->code ); | |
stack_push( ctx->stack, value ); | |
} | |
break; | |
case COMMAND_SYSCALL: | |
{ | |
int call_id = stack_pop( ctx->stack ); | |
int N = ctx->syscalls[call_id].params; | |
int retval = 0; | |
if( N == 0 ){ | |
retval = ((ptr_syscall0)(ctx->syscalls[call_id].func))(); | |
} | |
if( N == 1 ){ | |
int param0 = stack_pop( ctx->stack ); | |
retval = ((ptr_syscall1)(ctx->syscalls[call_id].func))( param0 ); | |
} | |
if( N == 2 ){ | |
int param0 = stack_pop( ctx->stack ); | |
int param1 = stack_pop( ctx->stack ); | |
retval = ((ptr_syscall2)(ctx->syscalls[call_id].func))( param0, param1 ); | |
} | |
if( N == 3 ){ | |
int param0 = stack_pop( ctx->stack ); | |
int param1 = stack_pop( ctx->stack ); | |
int param2 = stack_pop( ctx->stack ); | |
retval = ((ptr_syscall3)(ctx->syscalls[call_id].func))( param0, param1, param2 ); | |
} | |
stack_push( ctx->stack, retval ); | |
} | |
break; | |
default: | |
printf( "Invalid operator: %i\n", cmd ); | |
return -1; | |
break; | |
} | |
return 1; | |
} | |
int main( int argc, char **argv ){ | |
context_t konteksti; | |
int retval = 1; | |
konteksti.stack = stack_create( 100 ); /* hieman reilummin tilaa */ | |
konteksti.code = stack_create( 100 ); /* hieman reilummin tilaa */ | |
stack_push( konteksti.code, COMMAND_PRINT ); | |
stack_push( konteksti.code, COMMAND_ADD ); | |
stack_push( konteksti.code, 2 ); | |
stack_push( konteksti.code, COMMAND_PUSH ); | |
stack_push( konteksti.code, 1 ); | |
stack_push( konteksti.code, COMMAND_PUSH ); | |
while( !stack_is_empty( konteksti.code ) && retval > 0 ) { | |
retval = execute( &konteksti ); | |
} | |
stack_free( konteksti.stack ); | |
stack_free( konteksti.code ); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment