Skip to content

Instantly share code, notes, and snippets.

@mgronhol
Created July 17, 2012 09:34
Show Gist options
  • Save mgronhol/6553af49ff4d173c29b2 to your computer and use it in GitHub Desktop.
Save mgronhol/6553af49ff4d173c29b2 to your computer and use it in GitHub Desktop.
Small stack virtual machine
/*
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