Updated repository
This commit is contained in:
1 parent
279ee60d9d
commit
06cb8a39b1
22 files changed
+103
-398
No files matched your search
File renamed without changes.
@@ -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
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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 @@
|
|||||||
++++[>+++++<-]>[<++++++++++++>-]+<+[
|
|
||||||
>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+
|
|
||||||
>>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]
|
|
||||||
<<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-
|
|
||||||
]
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
-105
@@ -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