-
-
Save phorward/66b4a3df4bc0aeaf24a23d27a097ff08 to your computer and use it in GitHub Desktop.
Demonstration of a simple stack virtual machine & assembler
This file contains 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
/* | |
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