From 591a51290c76d6e6c6f8f9832560758ba6eaace8 Mon Sep 17 00:00:00 2001 From: hellerve Date: Tue, 14 Jul 2015 18:06:44 +0200 Subject: [PATCH] initial --- .gitignore | 1 + Makefile | 41 ++++++++++++++++ README.md | 22 +++++++++ examples/example.mml | 4 ++ src/cmm.c | 113 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 181 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 examples/example.mml create mode 100644 src/cmm.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e660fd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1675326 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +STD=-std=c11 +override CFLAGS+=-Werror -Wall -g -fPIC -O2 -DNDEBUG -ftrapv -Wfloat-equal -Wundef -Wwrite-strings -Wconversion -Wuninitialized -pedantic +PREFIX=/usr/bin/ +BUILDDIR=bin/ + +CC=cc + +TARGET=cmm +SOURCES=$(wildcard src/*.c) + +#Makes everything +all: + mkdir $(BUILDDIR) 2> /dev/null || true + $(CC) $(CFLAGS) $(SOURCES) -o $(BUILDDIR)$(TARGET) + +#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 -fsanitize=address $(STD)" + +#Runs all tests +runtests: + ./test.sh + +#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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..adae884 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +#cmm + +A C implementation of the [Mythical Machine](http://www.openbookproject.net/courses/python4fun/simulator.html) +that executes its' bytecode. + +##Building & Installing + +The project comes with a Makefile. Just run `make` to get a build in the +`bin` directory. If you really want to install it, run `make install`. That +will only work on Unix systems, though, I am afraid and may clutter your workspace. + +##Usage + +``` +usage: cmm program_name +``` + +This will "parse" the file and execute the bytecode. + +
+ +*Have fun!* diff --git a/examples/example.mml b/examples/example.mml new file mode 100644 index 0000000..b6d2f20 --- /dev/null +++ b/examples/example.mml @@ -0,0 +1,4 @@ +100 031012 Load register one with the number 12 +101 032013 Load register two with the number 13 +102 051002 Add register two to register one. +103 000000 Halt. The answer is in register one. diff --git a/src/cmm.c b/src/cmm.c new file mode 100644 index 0000000..4439c2f --- /dev/null +++ b/src/cmm.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include + +typedef struct program { + int p_reg; + int i_reg; + int mem[1000]; + int reg[10]; +} program; + +program* get_new_program() { + program* ret = calloc(1, sizeof(ret)); + + return ret; +} + +static inline void print_usage(char* name, uint8_t code) { + printf("usage: %s program_name\n", name); + exit(code); +} + +static inline void unparseable() { + puts("the program is unparseable!"); + exit(127); +} + +int execute(program* ex) { + int opcode, r, addr; + + ex->i_reg = ex->mem[ex->p_reg++]; + + opcode = ex->i_reg / 10000; + r = (ex->i_reg / 1000) % 10; + addr = ex->i_reg % 1000; + + switch(opcode) { + case 0: return 0; + break; + case 1: ex->reg[r] = ex->mem[addr]; + break; + case 2: ex->mem[addr] = ex->reg[r]; + break; + case 3: ex->reg[r] = addr; + break; + case 4: ex->reg[r] = ex->mem[ex->reg[addr]]; + break; + case 5: ex->reg[r] += ex->reg[addr]; + break; + case 6: ex->reg[r] -= ex->reg[addr]; + break; + case 7: ex->reg[r] *= ex->reg[addr]; + break; + case 8: ex->reg[r] /= ex->reg[addr]; + break; + case 10: ex->p_reg += addr; + break; + case 11: if (!ex->reg[r]) ex->p_reg = addr; + break; + } + + return 1; +} + +program* load_program(char* file_name) { + FILE* file = fopen(file_name, "r"); + char* line = NULL; + char* token = NULL; + size_t len = 0; + uint8_t count; + ssize_t read; + int address[2]; + + program* ret = get_new_program(); + + if(!file) return NULL; + + while((read = getline(&line, &len, file)) != -1) { + if(line[0] < '0') continue; + + token = strtok(line, " "); + count = 0; + + while(token) { + if(count > 1) { + ret->mem[address[0]] = address[1]; + break; + } + + address[count] = atoi(token); + + count++; + token = strtok(NULL, " "); + } + } + + return ret; +} + +int main(int argc, char** argv) { + if(argc != 2) print_usage(argv[0], 1); + + program* gotten = load_program(argv[1]); + + if(!gotten) unparseable(); + + gotten->p_reg = 100; + + while(execute(gotten)); + + return 0; +}