Skip to content

Instantly share code, notes, and snippets.

@lmdexpr
Last active August 29, 2015 14:11
Show Gist options
  • Save lmdexpr/23b61e1daa1f29d5fd55 to your computer and use it in GitHub Desktop.
Save lmdexpr/23b61e1daa1f29d5fd55 to your computer and use it in GitHub Desktop.
がっこうかだいってやつ
#if __INCLUDE_LEVEL__ <= LIMIT + 1
TARGET[__INCLUDE_LEVEL__ - 1].istarget = is(OP_CODES[__INCLUDE_LEVEL__ - 1]);
#include __FILE__
#endif
* 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
* 0
R 10
W 10
R 11
W 11
L 10
A 11
T 12
W 12
H 0
/ 0
* 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
#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