#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
/*
Opcodes for the Nameless Language VM
*/
enum Opcode
{
OP_MOVR = 0, //(0000) Move the pointer to the right
OP_MOVL = 1, //(0001) Move the pointer to the left
OP_INC = 2, //(0010) Increment the memory cell under the pointer
OP_DEC = 3, //(0011) Decrement the memory cell under the pointer
OP_POP = 4, //(0100) Output the character signified by the cell at the pointer
OP_PUSH = 5, //(0101) Input a character and store it in the cell at the pointer
OP_JEZ = 6, //(0110) Jump past the matching 0111 if the cell under the pointer is 0
OP_JNZ = 7, //(0111) Jump back to the matching 0110 if the cell under the pointer is nonzero
OP_ADD = 8, //(1000) Add the next command's base 10 equivalent to the current cell
OP_SUB = 9, //(1001) Subtract the next command's base 10 equivalent to the current cell
OP_NOP = 10, //(1010) No Operation
OP_CLC = 11, //(1011) Reset the current cell's value to 0
OP_CLPTR = 12 //(1100) Reset the pointer to point at cell 0
};
typedef struct VM
{
unsigned int tapeSize; //tape size in elements
unsigned int *program; //program to run in VM
unsigned int programLength; //total program length
unsigned int SP; //pointer to tape memory (stack pointer)
unsigned int PC; //pointer to program memory
char *tape; //growable memory
} VirtualMachine;
unsigned int ConvertBinaryStringToUInt(const char *bstring);
size_t __cdecl strlen_ojeb(const char* text);
void PrecompileSource(const char *source, unsigned int **program, unsigned int *programLength);
VirtualMachine *VM_Initialize(unsigned int *source, unsigned int programLength, unsigned int tapesize);
void VM_Run(VirtualMachine *vm);
int main(void)
{
/* hello world program [currently not working due to lack of the jump commands] */
const char *hello = " 00100010001000100010001000100010\
0110\
00000010001000100010\
0110\
000000100010\
0000001000100010\
0000001000100010\
00000010\
00010001000100010011\
0111\
00000010\
00000010\
00000011\
000000000010\
011000010111\
00010011\
0111\
000000000100\
00000011001100110100\
0010001000100010001000100010010001000010001000100100\
000000000100\
000100110100\
00010100\
0010001000100100\
0011001100110011001100110100\
001100110011001100110011001100110100\
0000000000100100";
/* reads 5 chars from the input, and outputs them and increments them before outputting [works] */
const char *cat = "010100100000\
010100100000\
010100100000\
010100100000\
01010010\
1100\
01000000\
01000000\
01000000\
01000000\
01000000";
/* reads and prints out one char [works] */
const char *pushpop = "010100100100";
unsigned int *compiledProgram = NULL;
unsigned int programLength = 0;
PrecompileSource(pushpop, &compiledProgram, &programLength);
VirtualMachine *environment = NULL;
environment = VM_Initialize(compiledProgram, programLength, 100);
assert(environment != NULL);
VM_Run(environment);
getchar();
getchar();
return 0;
}
/*
@procedure(VM_Run)
This function is responsible for decoding the opcode and executing the operation over the Virtual Machine
@param(vm): The Virtual Machine environment over which the Nameless program runs
@param(opcode): The 4bit buffer containing one opcode
*/
void VM_Run(VirtualMachine *vm)
{
int loopcnt = 0;
while (vm->PC != vm->programLength)
{
int op = vm->program[vm->PC];
switch (op)
{
case OP_MOVR: //(0000) Move the pointer to the right
{
if (vm->SP == vm->tapeSize - 1)
{
vm->SP = 0;
}
else
{
vm->SP++;
}
break;
}
case OP_MOVL: //(0001) Move the pointer to the left
{
if (vm->SP == 0)
{
vm->SP = vm->tapeSize - 1;
}
else
{
vm->SP--;
}
break;
}
case OP_INC: //(0010) Increment the memory cell under the pointer
{
vm->tape[vm->SP]++;
break;
}
case OP_DEC: //(0011) Decrement the memory cell under the pointer
{
vm->tape[vm->SP]--;
break;
}
case OP_POP: //(0100) Output the character signified by the cell at the pointer
{
char c = vm->tape[vm->SP];
printf("%c", c);
break;
}
case OP_PUSH: //(0101) Input a character and store it in the cell at the pointer
{
scanf(" %c", &vm->tape[vm->SP]);
break;
}
case OP_JEZ: //(0110) Jump past the matching 0111 if the cell under the pointer is 0
{
break;
}
case OP_JNZ: //(0111) Jump back to the matching 0110 if the cell under the pointer is nonzero
{
break;
}
case OP_ADD: //(1000) Add the next command's base 10 equivalent to the current cell
{
vm->tape[vm->SP] += vm->program[vm->PC + 1];
break;
}
case OP_SUB: //(1001) Subtract the next command's base 10 equivalent to the current cell
{
vm->tape[vm->SP] -= vm->program[vm->PC + 1];
break;
}
case OP_NOP: //(1010) No Operation
{
//No Operation
break;
}
case OP_CLC: //(1011) Reset the current cell's value to 0
{
vm->tape[vm->SP] = 0;
break;
}
case OP_CLPTR: //(1100) Reset the pointer to point at cell 0
{
vm->SP = 0;
break;
}
}
vm->PC++;
}
}
/*
@function(VM_Initialize)
Initializes the Virtual Machine with a program and creates a tape with [tapesize] number of cells
@param(source): The Nameless Language program source
@param(tapesize): The size of the tape memory to be created
@return(vm): The pre-created and allocated virtual machine ready to use
*/
VirtualMachine *VM_Initialize(unsigned int *source, unsigned int programLength, unsigned int tapesize)
{
VirtualMachine *vm = (VirtualMachine *)malloc(sizeof(VirtualMachine));
vm->tape = (char *)calloc(tapesize, sizeof(char));
vm->tapeSize = tapesize;
vm->program = source;
vm->programLength = programLength;
vm->SP = 0;
vm->PC = 0;
return vm;
}
/*
@function(PrecompileSource)
"Precompiles" the source to base10 ordinal array (unsigned int []) and removes bad input and/or comments
@param(source): The Nameless Language program source
@param(program): The program to be precompiled
@param(programLength): The precompiled program length
*/
void PrecompileSource(const char *source, unsigned int **program, unsigned int *programLength)
{
unsigned int compiled[10000];
register unsigned int len = strlen_ojeb(source);
register unsigned int srclen = 0;
char op[5];
op[4] = '\0';
for (register int i = 0; i < len; i++)
{
if (source[i] == '0' || source[i] == '1')
{
register int cnt = srclen % 4;
op[cnt] = source[i];
srclen++;
if (cnt == 3)
{
compiled[(*programLength)] = ConvertBinaryStringToUInt(op);
(*programLength)++;
}
}
}
*program = compiled;
}
/*
@function(ConvertBinaryStringToUInt)
Converts the binary string into a decimal number
@param(bstring): The binary number as string
@return(total): The base10 value of the binary string
*/
unsigned int ConvertBinaryStringToUInt(const char *bstring)
{
const char* start = &bstring[0];
unsigned int total = 0;
while (*start)
{
total <<= 1;
if (*start++ == '1')
{
total ^= 1;
}
}
return total;
}
/*
@function(strlen_ojeb)
This string length function is here only because it is a bit faster code than in the standard library, feel free to use your own
@param(text): The text which length we want to know
@return(): The string length
*/
size_t __cdecl strlen_ojeb(const char* text)
{
const char *s;
const uint32_t* pdwText;
register uint32_t dwText;
pdwText = (uint32_t*)text;
while (1)
{
dwText = *pdwText;
if ((dwText - 0x01010101UL) & ~dwText & 0x80808080UL)
{
s = (const char*)pdwText;
while (*s)
{
s++;
}
return s - text;
}
pdwText++;
}
}
Comments
0 B
|👍
/👎
0 B
|0 👍
/0 👎
0 B
|0 👍
/0 👎