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