initial
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
bin/
|
41
Makefile
Normal file
41
Makefile
Normal file
@@ -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
|
22
README.md
Normal file
22
README.md
Normal file
@@ -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.
|
||||
|
||||
<hr/>
|
||||
|
||||
*Have fun!*
|
4
examples/example.mml
Normal file
4
examples/example.mml
Normal file
@@ -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.
|
113
src/cmm.c
Normal file
113
src/cmm.c
Normal file
@@ -0,0 +1,113 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
Reference in New Issue
Block a user