
どうもなんでこのブログ主に言われてここで記事を書いてるかわからないのどかはです
実は続いているこの連載
さあ、実装していきます
前の記事はこちらです
こっからはついてこれるやつ
大分解説を諦めていきます
さて前回で新鮮な無をPCに与えましたがこっからはPCに型ってやつを教え込んでいきます
さて型をつけるために型をなくしていきましょう(?)
更に関数を呼び出すときに変数という箱を使うようにします
便利なんすわあ
こうすると
後バイトコード用にenumってやつを使って便利に僕たちのプログラミング言語の命令をまとめます
void* arg; void* r; int (*e)(void); typedef enum { INITE, ENV, INITR, REG, SETR, SETF, CALL, CNULL, EVAL } CODE; CODE c;
はい、そして前のやつをこんな風に
void* initEnvironments(){ e = NULL; return e;}void* environments(){ return e;}void* initRegisters(){ r = NULL; return r;}void* registers(){ return r;}void* setRegisters(){ return r = (int)arg;}void* setFunc(){ e = (int (*)())arg; return e;}void* callFunc(){ r = e(); return r;}void* returnNull(){ return NULL;}
ここまできたらバイトコードを解釈する世界のカオスを生み出した邪悪なる存在evalってやつを生み出します
evalって言ってるけど超循環評価機でも万能なものでもないです
あ、エラー関数も用意します
int error(char* message){ printf(message); return -1;}void eval(){ switch ((CODE)c) { case INITE: initEnvironments(); break; case ENV: environments(); break; case INITR: initRegisters(); break; case REG: registers(); break; case SETR: setRegisters(); break; case SETF: setFunc(); break; case CALL: callFunc(); break; case CNULL: returnNull(); break; case EVAL: eval(); break; default: error("コードがありません"); }}
main関数を書き換えろ〜
int main(void){ c = INITR; eval(); printf("code c = %d\n", c); printf("register r = %d\n", (int)registers()); printf("environments e = %p\n", environments()); c = INITE; eval(); printf("code c = %d\n", c); printf("register r = %d\n", (int)registers()); printf("environments e = %p\n", environments()); arg = 10; c = SETR; eval(); printf("code c = %d\n", c); printf("register r = %d\n", (int)registers()); printf("environments e = %p\n", environments()); arg = &returnNull; c = SETF; eval(); printf("code c = %d\n", c); printf("register r = %d\n", (int)registers()); printf("environments e = %p\n", environments()); c = CALL; eval(); printf("code c = %d\n", c); printf("register r = %d\n", (int)registers()); printf("environments e = %p\n", environments()); printf("新鮮な無 %p\n", returnNull()); return 0;}
はい、お疲れ様でした