Updated repository

This commit is contained in:
Veit Heller
2014-12-04 16:05:29 +01:00
parent 279ee60d9d
commit 06cb8a39b1
22 changed files with 103 additions and 398 deletions

108
README.md
View File

@@ -1,7 +1,105 @@
Virtual Machines Veits Virtual Machine
---------------- ---------------------
[![Build Status](https://travis-ci.org/hellerve/Virtual-Machines.png?branch=master)](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.

View File

@@ -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

View File

@@ -1,4 +0,0 @@
Naive Brainf\*ck Interpreter
---------------------------
A virtual machine that executes brainf\*ck code.

View File

@@ -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;
}

View File

@@ -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

View File

@@ -1,42 +0,0 @@
++++++++++
[
>
+++++++
>
++++++++++
>
+++
>
+
<<<<
-
]
>
++
.
>
+
.
+++++++
..
+++
.
>
++
.
<<
+++++++++++++++
.
>
.
+++
.
------
.
--------
.
>
+
.
>
.

View File

@@ -1 +0,0 @@
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

View File

@@ -1 +0,0 @@
[

View File

@@ -1,5 +0,0 @@
++++[>+++++<-]>[<++++++++++++>-]+<+[
>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+
>>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]
<<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-
]

View File

@@ -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 --).