Skip to content

Instantly share code, notes, and snippets.

@phorward
Last active August 28, 2019 10:10
Show Gist options
  • Save phorward/66b4a3df4bc0aeaf24a23d27a097ff08 to your computer and use it in GitHub Desktop.
Save phorward/66b4a3df4bc0aeaf24a23d27a097ff08 to your computer and use it in GitHub Desktop.
Demonstration of a simple stack virtual machine & assembler
/*
Demonstration of a simple stack virtual machine & assembler
Input:
lit 10
:loop
cpy
cpy
put
lit 1
sub
cpy
jpc loop
put
Output:
10
9
8
7
6
5
4
3
2
1
0
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef enum {
LIT,
CPY,
ADD,
SUB,
MUL,
DIV,
JMP,
JPC,
EQU,
NEQ,
GRT,
LOT,
GET,
PUT,
CHR
} OPCODE;
int stack[ 1024 ];
int tos = -1;
struct cmd
{
OPCODE c;
int p;
};
struct cmd prg[ 1024 ];
int prg_len = 0;
int pop( void )
{
return stack[ tos-- ];
}
void push( int x )
{
stack[ ++tos ] = x;
}
int assemble()
{
char l[ 1024 ];
char t[ 32 ];
char p[ 32 ];
int i;
struct LTAB
{
char l[32];
int a;
} ltab[1024];
int ltab_cnt = 0;
while( fgets( l, 1024, stdin ) && strcmp( l, "\n" ) )
{
switch( *l )
{
case ';':
case '\0':
break;
case ':':
sscanf( l, ":%s", t );
for( i = 0; i < ltab_cnt; i++ )
if( strcmp( ltab[ i ].l, t ) == 0 )
{
printf( "Label \"%s\" is already defined!\n", t );
return 0;
}
strcpy( ltab[ ltab_cnt ].l, t );
ltab[ ltab_cnt ].a = prg_len;
ltab_cnt++;
break;
default:
sscanf( l, "%s %s", t, p );
#define SET_IF_OPCODE( op, set ) \
if( !strcasecmp( t, op ) ) \
prg[ prg_len ].c = set
SET_IF_OPCODE( "LIT", LIT );
else SET_IF_OPCODE( "CPY", CPY );
else SET_IF_OPCODE( "ADD", ADD );
else SET_IF_OPCODE( "SUB", SUB );
else SET_IF_OPCODE( "MUL", MUL );
else SET_IF_OPCODE( "DIV", DIV );
else SET_IF_OPCODE( "JMP", JMP );
else SET_IF_OPCODE( "JPC", JPC );
else SET_IF_OPCODE( "EQU", EQU );
else SET_IF_OPCODE( "NEQ", NEQ );
else SET_IF_OPCODE( "GRT", GRT );
else SET_IF_OPCODE( "LOT", LOT );
else SET_IF_OPCODE( "GET", GET );
else SET_IF_OPCODE( "PUT", PUT );
else SET_IF_OPCODE( "CHR", CHR );
else
{
printf( "Unknown command: %s\n", t );
return 0;
}
if( prg[ prg_len ].c == JPC )
{
for( i = 0; i < ltab_cnt; i++ )
if( strcmp( ltab[ i ].l, p ) == 0 )
break;
if( i == ltab_cnt )
strcpy( ltab[ ltab_cnt++ ].l, t );
sprintf( p, "%d", i );
}
prg[ prg_len ].p = atoi( p );
prg_len++;
break;
}
}
for( i = 0; i < prg_len; i++ )
if( prg[ i ].c == JPC )
prg[i].p = ltab[prg[i].p].a;
printf( "Program assembled with %d lines of code!!\n", prg_len );
return 1;
}
int main( int argc, char** argv )
{
int x;
int i;
if( !assemble() )
return -1;
printf( "Fine! Now we will execute the program... *g*\n\n" );
for( i = 0; i < prg_len; i++ )
{
/*
int j;
printf( "Cmd = %d Parm = %d, Stack: ", prg[i].c, prg[i].p );
for( j = 0; j <= tos; j++ )
printf( "%d ", stack[ j ] );
printf( "\n" );
*/
switch( prg[i].c )
{
case LIT:
push( prg[i].p );
break;
case CPY:
push( stack[tos] );
break;
case ADD:
push( pop() + pop() );
break;
case SUB:
x = pop();
push( pop() - x );
break;
case MUL:
push( pop() * pop() );
break;
case DIV:
x = pop();
push( pop() / x );
break;
case JMP:
i = prg[i].p - 1;
break;
case JPC:
if( pop() )
i = prg[i].p - 1;
break;
case EQU:
push( pop() == pop() );
break;
case NEQ:
push( !( pop() == pop() ) );
break;
case GRT:
push( !( pop() < pop() ) );
break;
case LOT:
push( !( pop() > pop() ) );
break;
case GET:
scanf( "%d", &x );
push( x );
break;
case PUT:
printf( "%d\n", pop() );
break;
case CHR:
printf( "%c", pop() );
break;
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment