Updated repository
This commit is contained in:
108
README.md
108
README.md
@@ -1,7 +1,105 @@
|
||||
Virtual Machines
|
||||
----------------
|
||||
Veits Virtual Machine
|
||||
---------------------
|
||||
|
||||
[](https://travis-ci.org/hellerve/Virtual-Machines)
|
||||
A virtual machine that executes assembler-like code.
|
||||
|
||||
Performance
|
||||
-----------
|
||||
|
||||
Performance is pretty okay on basic, small programs. The included factorial
|
||||
function takes 0.1 second on 100000 iterations. As a scale, a Python 3.3 program
|
||||
on the same machine using the code:
|
||||
|
||||
``
|
||||
def fac(n):
|
||||
if n < 2: return 1
|
||||
else: return n * fac(n-1)
|
||||
fac(12)
|
||||
``
|
||||
|
||||
takes about 3.7 seconds on 100000 iterations.
|
||||
|
||||
This does not say anything about overall performance though and I am not
|
||||
sure whether this small, funny test has any real value in measuring performance.
|
||||
Also, Python is much more feature-rich, so you cannot compare the two at all.
|
||||
|
||||
DISCLAIMER: Parsing takes quite a long time, so try to write your programs as
|
||||
concise as possible.
|
||||
|
||||
Instruction set
|
||||
---------------
|
||||
|
||||
Up until now, all the operations are executed on integers(hence the
|
||||
I\* prefix).
|
||||
|
||||
*Operations overview*:
|
||||
|
||||
* IADD - Adds the two items to each other that are on top of the stack
|
||||
and stores the result on top of the stack.
|
||||
|
||||
* ISUB - Subtracts the two items from each other that are on top of the
|
||||
stack and stores the result on top of the stack.
|
||||
|
||||
* IMULT - Multiplies the two items to each other that are on top of the
|
||||
stack and stores the result on top of the stack.
|
||||
|
||||
* IDIV - Performs a division operation to the two items that are on top
|
||||
of the stack and stores the result on top of the stack.
|
||||
|
||||
* IMOD - Performs a modulo operation to the two items that are on top
|
||||
of the stack and stores the result on top of the stack.
|
||||
|
||||
* ILT - Checks whether the item on top of the stack is greater than the
|
||||
item below it and stores a boolean on top of the stack.
|
||||
|
||||
* IEQ - Checks whether the item on top of the stack is equal to the
|
||||
item below it and stores a boolean on top of the stack.
|
||||
|
||||
* IGT - Checks whether the item on top of the stack is smaller than the
|
||||
item below it and stores a boolean on top of the stack.
|
||||
|
||||
* ILEQ - Checks whether the item on top of the stack is smaller than or
|
||||
equal to the item below it and stores a boolean on top of the stack.
|
||||
|
||||
* IGEQ - Checks whether the item on top of the stack is greater than or
|
||||
equal to the item below it and stores a boolean on top of the stack.
|
||||
|
||||
* BR - Jumps to the instruction that is provided as an argument.
|
||||
|
||||
* BRT - Jumps to the instruction that is provided as an argument if the
|
||||
value on top of the stack is TRUE.
|
||||
|
||||
* BRF - Jumps to the instruction that is provided as an argument if the
|
||||
value on top of the stack is FALSE.
|
||||
|
||||
* ICONST - Puts the argument provided to the operation on top of the
|
||||
stack.
|
||||
|
||||
* LOAD - Loads an element from any position on the stack on top of the
|
||||
stack(usually used to get function arguments like this: LOAD -3).
|
||||
|
||||
* GLOAD - Loads an element from any position on the data segment on
|
||||
top of the stack.
|
||||
|
||||
* STORE - Stores an element on the stack.
|
||||
|
||||
* GSTORE - Stores an element in the data segment.
|
||||
|
||||
* PRINT - Prints the element on top of the stack as character.
|
||||
|
||||
* IPRINT - Prints the element on top of the stack as integer.
|
||||
|
||||
* POP - Pops the element on top of the stack.
|
||||
|
||||
* HALT - Ends the program.
|
||||
|
||||
* CALL - calls a subroutine with a number of arguments.
|
||||
|
||||
* RET - Returns from a subroutine with a return value.
|
||||
|
||||
* FETCH - Fetches a value.
|
||||
|
||||
* IINC -Increments the value on top of the stack by one(equal to ++).
|
||||
|
||||
* IDEC -Decrements the value on top of the stack by one(equal to --).
|
||||
|
||||
Just a bunch of immature interpreters. One interprets brainfuck code(nbfi -
|
||||
naive brainfuck interpreter), the other uses an assembly-based dsl.
|
||||
|
@@ -1,43 +0,0 @@
|
||||
override CFLAGS+=-Werror -Wall -g -fPIC -O2 -DNDEBUG -std=c99 -ftrapv -Wfloat-equal -Wundef -Wwrite-strings -Wconversion -Wuninitialized -pedantic
|
||||
PREFIX=/usr/bin/
|
||||
BUILDDIR=bin/
|
||||
|
||||
TARGET=nbfi
|
||||
SOURCES=$(wildcard src/*.c)
|
||||
|
||||
#Makes everything
|
||||
all:
|
||||
mkdir $(BUILDDIR) 2> /dev/null || true
|
||||
cc $(CFLAGS) $(SOURCES) -o $(BUILDDIR)$(TARGET)
|
||||
@echo
|
||||
@echo Running tests:
|
||||
@echo
|
||||
make tests
|
||||
@echo Compilation successfull.
|
||||
|
||||
# Runs the tests
|
||||
tests:
|
||||
./test.sh
|
||||
|
||||
#Uses picky extensions and makes everything(Extensions may break compiling)
|
||||
dev:
|
||||
make all CFLAGS+=-Wshadow -Wunreachable-code -Wswitch-enum -Wswitch-default -Wcast-align -Winit-self -Wpointer-arith
|
||||
|
||||
#Cleans directory(no uninstall!)
|
||||
clean:
|
||||
rm -rf bin
|
||||
|
||||
#Installs into specified(or default) directory
|
||||
install:
|
||||
install -d $(PREFIX)$(TARGET)
|
||||
install $(BUILDDIR)$(TARGET) $(PREFIX)$(TARGET)
|
||||
|
||||
#Uninstalls from specified(or default)directory
|
||||
uninstall:
|
||||
rm -rf $(PREFIX)$(TARGET)
|
||||
|
||||
#Checks for bad functions
|
||||
BADFUNCS='[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)'
|
||||
check:
|
||||
@echo Files with potentially dangerous functions:
|
||||
@grep $(BADFUNCS) $(SOURCES) || echo None
|
@@ -1,4 +0,0 @@
|
||||
Naive Brainf\*ck Interpreter
|
||||
---------------------------
|
||||
|
||||
A virtual machine that executes brainf\*ck code.
|
161
nbfi/src/nbfi.c
161
nbfi/src/nbfi.c
@@ -1,161 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*end instruction*/
|
||||
#define END 0
|
||||
/*increment pointer instruction, equivalent to > */
|
||||
#define INC_DP 1
|
||||
/*decrement pointer instruction, equivalent to < */
|
||||
#define DEC_DP 2
|
||||
/*increment value instruction, equivalent to + */
|
||||
#define INC_VAL 3
|
||||
/*decrement value instruction, equivalent to - */
|
||||
#define DEC_VAL 4
|
||||
/*output value instruction, equivalent to . */
|
||||
#define OUT 5
|
||||
/*input value instruction, equivalent to , */
|
||||
#define IN 6
|
||||
/*jump forward instruction, equivalent to [ */
|
||||
#define JMP_FWD 7
|
||||
/*jump back instruction, equivalent to ] */
|
||||
#define JMP_BCK 8
|
||||
|
||||
/*Maximum program size*/
|
||||
#define PROGRAM_SIZE 1048576
|
||||
/*Maximum stack size*/
|
||||
#define MAX_SIZE 5024291
|
||||
/*Maximum data size*/
|
||||
#define DATA_SIZE 1638375
|
||||
|
||||
/*Push macro, implements stack operation push*/
|
||||
#define PUSH(A) (stack[sp++] = A)
|
||||
/*Pop macro, implements stack operation pop*/
|
||||
#define POP() (stack[--sp])
|
||||
/*Empty macro, implements stack operation check if empty*/
|
||||
#define EMPTY() (sp == 0)
|
||||
/*Full macro, implements stack operation check if full*/
|
||||
#define FULL() (sp == MAX_SIZE)
|
||||
|
||||
|
||||
/**
|
||||
* @brief die
|
||||
* @param code -> the error code
|
||||
* @param message -> the error message
|
||||
*
|
||||
* Lets the program die and emits an error message.
|
||||
*/
|
||||
static inline void die(int code, const char* message){
|
||||
fprintf(stderr, "%s\n", message);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief An instruction struct
|
||||
*
|
||||
* Consists of operator and operand,
|
||||
* the easiest way of abstracting
|
||||
* an instruction.
|
||||
*/
|
||||
struct instruction{
|
||||
unsigned int operator; ///< Operator
|
||||
unsigned int operand; ///< Operand
|
||||
};
|
||||
|
||||
/*The program as an array of structs*/
|
||||
static struct instruction program[PROGRAM_SIZE];
|
||||
/*The stack*/
|
||||
static unsigned int stack[MAX_SIZE];
|
||||
/*The stack pointer*/
|
||||
static unsigned long sp = 0;
|
||||
|
||||
/**
|
||||
* @brief compile
|
||||
* @param fp -> the file
|
||||
*
|
||||
* Compiles a file to bytecode and saves that within program.
|
||||
*/
|
||||
void compile(FILE* fp){
|
||||
unsigned int pc = 0, jmp_pc;
|
||||
int ip;
|
||||
while ((ip = getc(fp)) != EOF && pc < MAX_SIZE){
|
||||
switch (ip) {
|
||||
case '>': program[pc].operator = INC_DP; break;
|
||||
case '<': program[pc].operator = DEC_DP; break;
|
||||
case '+': program[pc].operator = INC_VAL; break;
|
||||
case '-': program[pc].operator = DEC_VAL; break;
|
||||
case '.': program[pc].operator = OUT; break;
|
||||
case ',': program[pc].operator = IN; break;
|
||||
case '[':
|
||||
program[pc].operator = JMP_FWD;
|
||||
if (FULL())
|
||||
die(127, "nbfi:compile: Cannot jump forwards: Stack is full.");
|
||||
PUSH(pc);
|
||||
break;
|
||||
case ']':
|
||||
if (EMPTY())
|
||||
die(127, "nbfi:compile: Cannot jump backwards: Stack is full.");
|
||||
jmp_pc = POP();
|
||||
program[pc].operator = JMP_BCK;
|
||||
program[pc].operand = jmp_pc;
|
||||
program[jmp_pc].operand = pc;
|
||||
break;
|
||||
default:
|
||||
if(ip > 32 && ip < 128)
|
||||
fprintf(stderr, "nbfi:compile: Warning: Unknown command: %c\n", ip);
|
||||
pc--;
|
||||
break;
|
||||
}
|
||||
pc++;
|
||||
}
|
||||
if(!EMPTY())
|
||||
die(127, "nbfi:compile: Program ends with non-empty stack.");
|
||||
if(pc == MAX_SIZE)
|
||||
die(127, "nbfi:compile: Program exceeds maximum program size.");
|
||||
program[pc].operator = END;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief execute
|
||||
*
|
||||
* Executes the bytecode within program.
|
||||
*/
|
||||
void execute(){
|
||||
unsigned int data[DATA_SIZE], pc = 0;
|
||||
unsigned int ptr = DATA_SIZE;
|
||||
while (--ptr) data[ptr] = 0;
|
||||
while (program[pc].operator != END && ptr < DATA_SIZE){
|
||||
switch (program[pc].operator){
|
||||
case INC_DP: ptr++; break;
|
||||
case DEC_DP: ptr--; break;
|
||||
case INC_VAL: data[ptr]++; break;
|
||||
case DEC_VAL: data[ptr]--; break;
|
||||
case OUT: putchar((signed int)data[ptr]); break;
|
||||
case IN: data[ptr] = (unsigned int)getchar(); break;
|
||||
case JMP_FWD: if(!data[ptr]) { pc = program[pc].operand; } break;
|
||||
case JMP_BCK: if(data[ptr]) { pc = program[pc].operand; } break;
|
||||
default: die(127, "nbfi:execute: Unknown instruction.");
|
||||
}
|
||||
pc++;
|
||||
}
|
||||
if(ptr == DATA_SIZE)
|
||||
die(127, "nbfi:execute: Program used up too much memory.");
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief main
|
||||
* @param argc -> argument counter
|
||||
* @param argv -> argument vector
|
||||
*
|
||||
* compiles and executes brainfuck code from a file.
|
||||
*/
|
||||
int main(int argc, const char * argv[]){
|
||||
FILE *fp;
|
||||
if(argc != 2)
|
||||
die(127, "nbfi:parse: Wrong number of arguments supplied.");
|
||||
if(!(fp = fopen(argv[1], "r")))
|
||||
die(127, "nbfi:parse: File could not be opened.");
|
||||
compile(fp);
|
||||
fclose(fp);
|
||||
execute();
|
||||
return 0;
|
||||
}
|
31
nbfi/test.sh
31
nbfi/test.sh
@@ -1,31 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
for i in `ls test | grep -v fail` ; do
|
||||
echo Running test $i:
|
||||
echo ---------------------
|
||||
bin/nbfi test/$i
|
||||
return=$?
|
||||
if [ $return != 0 ] ; then
|
||||
echo Test $i failed.
|
||||
exit 1
|
||||
fi
|
||||
echo
|
||||
echo ---------------------
|
||||
echo End of test $i
|
||||
echo
|
||||
done
|
||||
|
||||
for i in `ls test/*fail*` ; do
|
||||
echo Running expected fail test $i:
|
||||
echo ---------------------
|
||||
bin/nbfi $i
|
||||
return=$?
|
||||
if [ $return != 127 ] ; then
|
||||
echo Test $i failed.
|
||||
exit 1
|
||||
fi
|
||||
echo
|
||||
echo ---------------------
|
||||
echo End of test $i
|
||||
echo
|
||||
done
|
@@ -1,42 +0,0 @@
|
||||
++++++++++
|
||||
[
|
||||
>
|
||||
+++++++
|
||||
>
|
||||
++++++++++
|
||||
>
|
||||
+++
|
||||
>
|
||||
+
|
||||
<<<<
|
||||
-
|
||||
]
|
||||
>
|
||||
++
|
||||
.
|
||||
>
|
||||
+
|
||||
.
|
||||
+++++++
|
||||
..
|
||||
+++
|
||||
.
|
||||
>
|
||||
++
|
||||
.
|
||||
<<
|
||||
+++++++++++++++
|
||||
.
|
||||
>
|
||||
.
|
||||
+++
|
||||
.
|
||||
------
|
||||
.
|
||||
--------
|
||||
.
|
||||
>
|
||||
+
|
||||
.
|
||||
>
|
||||
.
|
@@ -1 +0,0 @@
|
||||
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
|
@@ -1 +0,0 @@
|
||||
[
|
@@ -1,5 +0,0 @@
|
||||
++++[>+++++<-]>[<++++++++++++>-]+<+[
|
||||
>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+
|
||||
>>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]
|
||||
<<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-
|
||||
]
|
105
vvm/README.md
105
vvm/README.md
@@ -1,105 +0,0 @@
|
||||
Veits Virtual Machine
|
||||
---------------------
|
||||
|
||||
A virtual machine that executes assembler-like code.
|
||||
|
||||
Performance
|
||||
-----------
|
||||
|
||||
Performance is pretty okay on basic, small programs. The included factorial
|
||||
function takes 0.1 second on 100000 iterations. As a scale, a Python 3.3 program
|
||||
on the same machine using the code:
|
||||
|
||||
``
|
||||
def fac(n):
|
||||
if n < 2: return 1
|
||||
else: return n * fac(n-1)
|
||||
fac(12)
|
||||
``
|
||||
|
||||
takes about 3.7 seconds on 100000 iterations.
|
||||
|
||||
This does not say anything about overall performance though and I am not
|
||||
sure whether this small, funny test has any real value in measuring performance.
|
||||
Also, Python is much more feature-rich, so you cannot compare the two at all.
|
||||
|
||||
DISCLAIMER: Parsing takes quite a long time, so try to write your programs as
|
||||
concise as possible.
|
||||
|
||||
Instruction set
|
||||
---------------
|
||||
|
||||
Up until now, all the operations are executed on integers(hence the
|
||||
I\* prefix).
|
||||
|
||||
*Operations overview*:
|
||||
|
||||
* IADD - Adds the two items to each other that are on top of the stack
|
||||
and stores the result on top of the stack.
|
||||
|
||||
* ISUB - Subtracts the two items from each other that are on top of the
|
||||
stack and stores the result on top of the stack.
|
||||
|
||||
* IMULT - Multiplies the two items to each other that are on top of the
|
||||
stack and stores the result on top of the stack.
|
||||
|
||||
* IDIV - Performs a division operation to the two items that are on top
|
||||
of the stack and stores the result on top of the stack.
|
||||
|
||||
* IMOD - Performs a modulo operation to the two items that are on top
|
||||
of the stack and stores the result on top of the stack.
|
||||
|
||||
* ILT - Checks whether the item on top of the stack is greater than the
|
||||
item below it and stores a boolean on top of the stack.
|
||||
|
||||
* IEQ - Checks whether the item on top of the stack is equal to the
|
||||
item below it and stores a boolean on top of the stack.
|
||||
|
||||
* IGT - Checks whether the item on top of the stack is smaller than the
|
||||
item below it and stores a boolean on top of the stack.
|
||||
|
||||
* ILEQ - Checks whether the item on top of the stack is smaller than or
|
||||
equal to the item below it and stores a boolean on top of the stack.
|
||||
|
||||
* IGEQ - Checks whether the item on top of the stack is greater than or
|
||||
equal to the item below it and stores a boolean on top of the stack.
|
||||
|
||||
* BR - Jumps to the instruction that is provided as an argument.
|
||||
|
||||
* BRT - Jumps to the instruction that is provided as an argument if the
|
||||
value on top of the stack is TRUE.
|
||||
|
||||
* BRF - Jumps to the instruction that is provided as an argument if the
|
||||
value on top of the stack is FALSE.
|
||||
|
||||
* ICONST - Puts the argument provided to the operation on top of the
|
||||
stack.
|
||||
|
||||
* LOAD - Loads an element from any position on the stack on top of the
|
||||
stack(usually used to get function arguments like this: LOAD -3).
|
||||
|
||||
* GLOAD - Loads an element from any position on the data segment on
|
||||
top of the stack.
|
||||
|
||||
* STORE - Stores an element on the stack.
|
||||
|
||||
* GSTORE - Stores an element in the data segment.
|
||||
|
||||
* PRINT - Prints the element on top of the stack as character.
|
||||
|
||||
* IPRINT - Prints the element on top of the stack as integer.
|
||||
|
||||
* POP - Pops the element on top of the stack.
|
||||
|
||||
* HALT - Ends the program.
|
||||
|
||||
* CALL - calls a subroutine with a number of arguments.
|
||||
|
||||
* RET - Returns from a subroutine with a return value.
|
||||
|
||||
* FETCH - Fetches a value.
|
||||
|
||||
* IINC -Increments the value on top of the stack by one(equal to ++).
|
||||
|
||||
* IDEC -Decrements the value on top of the stack by one(equal to --).
|
||||
|
Reference in New Issue
Block a user