#include #include #include #include #include /* 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++; } }