Last active
August 29, 2015 14:11
-
-
Save lmdexpr/23b61e1daa1f29d5fd55 to your computer and use it in GitHub Desktop.
がっこうかだいってやつ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if __INCLUDE_LEVEL__ <= LIMIT + 1 | |
TARGET[__INCLUDE_LEVEL__ - 1].istarget = is(OP_CODES[__INCLUDE_LEVEL__ - 1]); | |
#include __FILE__ | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* 0 | |
; initialize | |
C 1 | |
T 10 ; for increment | |
C 0 | |
T 1023 | |
; data | |
; 0 ~ 9 is input data | |
; 10 ~ is immutable value | |
; 100 ~ is variable | |
; ~ 1023 is stack | |
; code | |
; 0 ~ is entry point (initialize) | |
; 30 ~ is main codes | |
; 800 is call back address | |
; ~ 1019 is function | |
; 1020 is end | |
; input | |
R 0 ; inpute_data | |
J 30 | |
; main loop | |
* 30 | |
L 1023 | |
A 10 ; acc++ | |
T 1023 | |
; if acc == inpute_data then exit | |
S 0 | |
Z 1020 | |
; else | |
L 1023 | |
T 1 | |
; call canDiv? | |
J 900 | |
; if canDiv? | |
* 800 | |
Z 50 ; match | |
J 30 | |
; then pattern | |
* 50 | |
W 1023 | |
J 30 | |
; canDiv? ([1] % [0] == 0) | |
; [1023] <- acc | |
; acc <- [0] | |
; acc <- acc / [0] * [0] - [1] | |
* 900 | |
T 1023 | |
L 0 | |
D 1 | |
M 1 | |
S 0 | |
J 800 | |
; end point | |
* 1020 | |
H 0 | |
/ 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* 0 | |
R 10 | |
W 10 | |
R 11 | |
W 11 | |
L 10 | |
A 11 | |
T 12 | |
W 12 | |
H 0 | |
/ 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* 0 | |
C 0 | |
T 0 | |
J 100 | |
* 100 | |
L 0 | |
R 1 | |
A 1 | |
T 0 | |
L 1 | |
Z 200 | |
J 100 | |
* 200 | |
W 0 | |
H 0 | |
/ 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <ctype.h> | |
#define DEBUG 0 | |
#define DATA_LEN 1024 | |
#define CODE_LEN 1024 | |
#define BUFLEN 256 | |
// with GCC extension (##__VA_ARGS__は引数がない場合に手前のカンマを削除する) | |
#define error(msg, ...) {\ | |
fprintf(stderr, "\033[31m\033[40mERROR\033[39m\033[49m:" msg "\n", ##__VA_ARGS__);\ | |
exit(EXIT_FAILURE);\ | |
} | |
// with GCC extension (##__VA_ARGS__) | |
#define err_with_strtol(endp, msg, ...) {\ | |
if (endp != NULL && endp[0] != '\n' && endp[0] != ';' && !isspace(endp[0]))\ | |
error(msg, ##__VA_ARGS__);\ | |
} | |
// \033はESCの意味.特殊な画面制御におけるエスケープ | |
#if DEBUG == 1 | |
# define debug_print_string(var) printf("\033[33m\033[40mTrace\033[39m\033[49m:(string)%s:%s", #var, var); | |
# define debug_print_char(var) printf("\033[33m\033[40mTrace\033[39m\033[49m:(char)%s:%c\n", #var, var); | |
# define debug_print_int(var) printf("\033[33m\033[40mTrace\033[39m\033[49m:(int)%s:%d\n", #var, var); | |
# define debug_nl puts(""); | |
#else | |
# define debug_print_string(var) | |
# define debug_print_char(var) | |
# define debug_print_int(var) | |
# define debug_nl | |
#endif | |
typedef long ADDRESS; | |
typedef int ACCUMULATOR; | |
typedef int DATA; | |
typedef struct { | |
char func; | |
ADDRESS addr; | |
} instruction; | |
typedef struct { | |
const instruction *ir; | |
ADDRESS pc; | |
ACCUMULATOR acc; | |
} CPU; | |
typedef struct { | |
instruction *code; | |
DATA *data; | |
} memory; | |
typedef struct { | |
FILE *in; | |
FILE *out; | |
memory mem; | |
CPU cpu; | |
bool running; | |
} machine; | |
#define OP_CODES "LCTASMDJZRWH/" | |
#define KIND_OF_PARSER 13 | |
/* 配列の要素に指定できなくなるため断念。コンパイル時に文字列の長さを調べればよい | |
#define KIND_OF_PARSER ({\ | |
static int len = strlen(OP_CODES);\ | |
len;\ | |
}) | |
*/ | |
//implementation of anonymous function with GCC extension (複文の式化, 関数内関数定義) | |
#define LAMBDA(RET, ARG_LIST, BODY) ({\ | |
RET __lambda_funcion__ ARG_LIST { BODY };\ | |
__lambda_funcion__;\ | |
}) | |
#define is(c) LAMBDA(bool, (char d), return c == d;) | |
typedef void (*INSTANCE)(machine *, int); | |
typedef bool (*IS_TARGET)(char); | |
typedef struct { | |
INSTANCE instance; | |
IS_TARGET istarget; | |
} parser; | |
void init_machine(machine *); | |
void read_code(machine *, int, char const* []); | |
void compile(instruction *, ADDRESS *, FILE *); | |
void init_parser(parser *); | |
void step(machine *, parser *); | |
void run(machine *); | |
void streamclear(FILE *); | |
int main(int argc, char const* argv[]) | |
{ | |
char c; | |
machine m; | |
puts("initializing machine..."); | |
init_machine(&m); | |
puts("done.\n"); | |
puts("interpreting code..."); | |
read_code(&m, argc - 1, argv + 1); | |
puts("done.\n"); | |
printf("run? y/n(default: y)\n> "); | |
scanf("%[yn]", &c); | |
streamclear(stdin); | |
if (c != 'n') { | |
puts(""); | |
run(&m); | |
puts(""); | |
} | |
puts("exit."); | |
return 0; | |
} | |
void init_machine(machine *m) | |
{ | |
static instruction code[CODE_LEN]; | |
static DATA data[DATA_LEN]; | |
m->in = stdin; | |
m->out = stdout; | |
m->mem.code = code; | |
m->mem.data = data; | |
m->running = false; | |
} | |
void read_code(machine *m, int c, char const* filenames[]) | |
{ | |
FILE *fp = NULL; | |
if (c > 0) { | |
if ((fp = fopen(filenames[0], "r")) == NULL) | |
exit(EXIT_FAILURE); | |
} else { | |
puts("Give me command line argument.\nexit."); | |
exit(EXIT_FAILURE); | |
} | |
puts("\tcompiling..."); | |
compile(m->mem.code, &(m->cpu.pc), fp); | |
puts("\tdone."); | |
fclose(fp); | |
} | |
void compile(instruction *code, ADDRESS *pc, FILE *fp) | |
{ | |
char buf[BUFLEN], *endp; | |
long w_ptr; | |
int line = 0; | |
do { | |
if (!fgets(buf, BUFLEN, fp)) | |
error("Missing \'/\' code."); | |
line++; | |
debug_print_string(buf); | |
if (buf[0] == '\n' || buf[0] == ';') | |
continue; | |
if (buf[0] == '*') { | |
w_ptr = strtol(buf + 2, &endp, 0); | |
debug_print_int(w_ptr); | |
debug_nl; | |
} else { | |
if (strchr(OP_CODES, buf[0]) == NULL) | |
error("line[%d] Unknown code %c", line, buf[0]); | |
code[w_ptr].func = buf[0]; | |
code[w_ptr].addr = strtol(buf + 2, &endp, 0); | |
debug_print_char(code[w_ptr].func); | |
debug_print_int(code[w_ptr].addr); | |
debug_print_int(w_ptr); | |
err_with_strtol(endp, "line[%d] Invalid argument: %s in %s", line, endp, buf + 2); | |
w_ptr++; | |
} | |
debug_nl; | |
} while (buf[0] != '/'); | |
*pc = strtol(buf + 2, &endp, 0); | |
err_with_strtol(endp, "line[%d] Invalid argument: %s in %s", line, endp, buf + 2); | |
} | |
void load(machine *m, int n) { m->cpu.acc = m->mem.data[n]; } | |
void cload(machine *m, int n) { m->cpu.acc = n; } | |
void store(machine *m, int n) { m->mem.data[n] = m->cpu.acc; } | |
void add(machine *m, int n) { m->cpu.acc += m->mem.data[n]; } | |
void sub(machine *m, int n) { m->cpu.acc -= m->mem.data[n]; } | |
void mul(machine *m, int n) { m->cpu.acc *= m->mem.data[n]; } | |
void divi(machine *m, int n) { m->cpu.acc /= m->mem.data[n]; } | |
void jump(machine *m, int n) { m->cpu.pc = n - 1; } | |
void jumpz(machine *m, int n) { if(m->cpu.acc == 0) jump(m, n); } | |
void read(machine *m, int n) | |
{ fprintf(m->out, "\tinput(from vm):"); fscanf(m->in, "%d", &(m->mem.data[n])); } | |
void write(machine *m, int n) | |
{ fprintf(m->out, "\toutput(from vm):%d\n", m->mem.data[n]); } | |
void halt(machine *m, int n) { m->running = false; } | |
void init_parser(parser *p) | |
{ | |
INSTANCE funcs[KIND_OF_PARSER] = | |
{load, cload, store, add, sub, mul, divi, jump, jumpz, read, write, halt}; | |
int i = 0; | |
puts("\tinitializing parser..."); | |
#define LIMIT KIND_OF_PARSER - 2 | |
#define TARGET p | |
#include "assign_is_target.h" | |
for (i = 0; i < KIND_OF_PARSER; i++) | |
p[i].instance = funcs[i]; | |
p[KIND_OF_PARSER - 1].instance = LAMBDA(void, (machine *m, int n), error("Segmentation fault");); | |
p[KIND_OF_PARSER - 1].istarget = LAMBDA(bool, (char d), return true;); | |
puts("\tdone."); | |
} | |
void step(machine *m, parser *p) | |
{ | |
int i, a; | |
instruction *code = m->mem.code; | |
for (i = 0; i < KIND_OF_PARSER; i++) | |
if (p[i].istarget(code[m->cpu.pc].func)) | |
break; | |
debug_print_char(code[m->cpu.pc].func); | |
debug_print_int(code[m->cpu.pc].addr); | |
debug_print_int(m->cpu.pc); | |
debug_nl; | |
p[i].instance(m, code[m->cpu.pc].addr); | |
(m->cpu.pc)++; | |
} | |
void run(machine *m) | |
{ | |
parser p[KIND_OF_PARSER]; | |
m->running = true; | |
init_parser(p); | |
puts("running machine..."); | |
while (m->running) | |
step(m, p); | |
puts("done."); | |
} | |
void streamclear(FILE *stream) | |
{ | |
while (fgetc(stream) != '\n') | |
; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment