2019年9月18日水曜日

brainfuckを作ってみた。


プログラムの概念を作ったチューリングによれば、「コンピュータ言語は少なくともチューリング完全でなければプログラミング言語とは呼ばれない」という決まりがあるようです。
そして、チューリング完全な最小の言語としてbrainfuckという言語があります。

https://qiita.com/TomoShiozawa/items/25dcce1540085df71053

なんか情報系の大学の計算機理論やコンパイラ理論で「brainfuckを作ってみよう!」ってよく習うらしいですが、おじさん習ったことないぞ。brainfuckできたの1991年だもんなぁ。

しかもgithubなどで世の中に落ちているこのbrainfuckの実装はプログラムを習った学生が作っているためかどれもバグだらけじゃないか。
チューリング完全の理解も間違っている。
バグがバグを生む負の連鎖になっているので、正しいbrainfuckを作ってみました。

https://qiita.com/takl/items/6ffe14db22974b1f74ce

とりあえずここのページのコードがかなりゴールに近いしソースがわかりやすいのでここからソースをとってきて改良。

------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if 0

#define PROG ">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++."
const char * const prog = PROG;

#else

const char * const prog =
">+++++[>+++++++<-]>.<<++[>+++++[>+++++++<-]<-]>>.+++++.<++[>-----<-]>-.<++"
"[>++++<-]>+.<++[>++++<-]>+.[>+>+>+<<<-]>>>[<<<+>>>-]<<<<<++[>+++[>---<-]<-"
"]>>+.+.<+++++++[>----------<-]>+.<++++[>+++++++<-]>.>.-------.-----.<<++[>"
">+++++<<-]>>.+.----------------.<<++[>-------<-]>.>++++.<<++[>++++++++<-]>"
".<++++++++++[>>>-----------<<<-]>>>+++.<-----.+++++.-------.<<++[>>+++++++"
"+<<-]>>+.<<+++[>----------<-]>.<++[>>--------<<-]>>-.------.<<++[>++++++++"
"<-]>+++.---....>++.<----.--.<++[>>+++++++++<<-]>>+.<<++[>+++++++++<-]>+.<+"
"+[>>-------<<-]>>-.<--.>>.<<<+++[>>++++<<-]>>.<<+++[>>----<<-]>>.++++++++."
"+++++.<<++[>---------<-]>-.+.>>.<<<++[>>+++++++<<-]>>-.>.>>>[-]>>[-]<+[<<["
"-],[>>>>>>>>>>>>>+>+<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>[<<<<<<<<<<<<<<+>>>>>>>>"
">>>>>>-]<<+>[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-"
"[-[-[-[-[-[-[-[-[-[-[-[<->[-]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]<["
"<<<<<<<<<<<<[-]>>>>>>>>>>>>[-]]<<<<<<<<<<<<[<+++++[>---------<-]>++[>]>>[>"
"+++++[>+++++++++<-]>--..-.<+++++++[>++++++++++<-]>.<+++++++++++[>-----<-]>"
"++.<<<<<<.>>>>>>[-]<]<<<[-[>]>>[>++++++[>+++[>++++++<-]<-]>>++++++.-------"
"------.----.+++.<++++++[>----------<-]>.++++++++.----.<++++[>+++++++++++++"
"++++<-]>.<++++[>-----------------<-]>.+++++.--------.<++[>+++++++++<-]>.[-"
"]<<<<<<<.>>>>>]<<<[-[>]>>[>+++++[>+++++++++<-]>..---.<+++++++[>++++++++++<"
"-]>.<+++++++++++[>-----<-]>++.<<<<<<.>>>>>>[-]<]<<<[-[>]>>[>+++[>++++[>+++"
"+++++++<-]<-]>>-.-----.---------.<++[>++++++<-]>-.<+++[>-----<-]>.<++++++["
">----------<-]>-.<+++[>+++<-]>.-----.<++++[>+++++++++++++++++<-]>.<++++[>-"
"----------------<-]>.+++++.--------.<++[>+++++++++<-]>.[-]<<<<<<<.>>>>>]<<"
"<[<+++[>-----<-]>+[>]>>[>+++++[>+++++++++<-]>..<+++++++[>++++++++++<-]>---"
".<+++++[>----------<-]>---.<<<<<<.>>>>>>[-]<]<<<[--[>]>>[>+++++[>+++++++++"
"<-]>--..<+++++++[>++++++++++<-]>-.<+++++[>----------<-]>---.[-]<<<<<<.>>>>"
">]<<<[<+++[>----------<-]>+[>]>>[>+++[>++++[>++++++++++<-]<-]>>-.<+++[>---"
"--<-]>.+.+++.-------.<++++++[>----------<-]>-.++.<+++++++[>++++++++++<-]>."
"<+++++++[>----------<-]>-.<++++++++[>++++++++++<-]>++.[-]<<<<<<<.>>>>>]<<<"
"[--[>]>>[>+++++[>+++++[>+++++<-]<-]>>.[-]<<<<<<<.>>>>>]<<<[<++++++++++[>--"
"--------------<-]>--[>]>>[<<<<[-]]]]]]]]]]]>>]<++[>+++++[>++++++++++<-]<-]"
">>+.<+++[>++++++<-]>+.<+++[>-----<-]>.+++++++++++.<+++++++[>----------<-]>"
"------.++++++++.-------.<+++[>++++++<-]>.<++++++[>+++++++++++<-]>.<+++++++"
"+++.";
#endif


struct stack {
int* vp;
int sz;
int pos;
};


void stack_init(struct stack* a)
{
if (a == NULL)return;
a->sz = 1;
a->pos = 0;
a->vp = malloc(sizeof(int) * a->sz);
}

void stack_push(struct stack* a, int n)
{
if (a == NULL)return;
if (a->pos + 1 == a->sz) {
a->sz = a->sz * 2;
a->vp = realloc(a->vp, sizeof(int) * a->sz);
}
a->vp[a->pos] = n;
a->pos++;
}

int stack_pop(struct stack* a)
{
if (a == NULL)return 0;
if (a->pos == 0) {
return 0;
}
a->pos--;
return a->vp[a->pos];
}

const char *back(const char *ip) {
int nest = 0;

while (1) {
if (ip == prog) {
printf("invalid ']'\n");
exit(EXIT_FAILURE);
}

switch (*--ip) {
case '[':
if (nest == 0) return ip;
--nest;
break;
case ']':
++nest;
break;
default:
break;
}
}
}

const char *forth(const char *ip) {
int nest = 0;

while (1) {
switch (*ip++) {
case '\0':
printf("invalid '['\n");
exit(EXIT_FAILURE);
case '[':
++nest;
break;
case ']':
if (nest == 0) return ip;
--nest;
break;
default:
break;
}
}
}

int main() {
struct stack ls, rs;
stack_init(&ls);
stack_init(&rs);

int cell = 0;
const char *ip = prog;

while (1) {
switch (*ip++) {
case '\0':
return 0;
case '+':
++cell;
break;
case '-':
--cell;
break;
case ';':
printf("[%d]", cell);
fflush(stdout);
break;
case '.':
printf("%c", cell);
fflush(stdout);
break;
case ',':
cell = getchar();
break;
case '>':
stack_push(&ls, cell);
cell = stack_pop(&rs);
break;
case '<':
stack_push(&rs, cell);
cell = stack_pop(&ls);
break;
case '[':
if (cell == 0) ip = forth(ip);
break;
case ']':
if (cell != 0) ip = back(ip - 1) + 1;
break;
default:
break;
}
}
}

------------------------------

このbrainfuckはチューリング完全な言語で、チューリング完全な言語を実装できる言語もチューリング完全らしいです。
ということで、C言語もチューリング完全ですね。

きっと大学だと「brainfuckを実装し、C言語がチューリング完全であることを示せ」とか課題が出るんだろうな。


2019年9月3日火曜日

C言語インタープリターで遊ぶ

最近人気のPythonですが、Python自体は結構サイズが大きくて、Pythonを動かすのにたくさんのライブラリが必要です。
手軽に動かせる軽量のインタープリタ言語ないかなぁ。

調べてみると、picocというコンパクトなC言語インタープリタがあるらしい。
ということで、C言語インタープリタをビルドしてみました。

https://github.com/jpoirier/picoc
https://gitlab.com/zsaleeba/picoc


このpicocですが、ソースを見る限り簡単に拡張できます。
関数ポインターは実装されていないけれど、結構本格的なC言語が実装されています。
system()とかの関数も動くので、これちょっとしたスクリプトやマクロの代わりに使えるじゃん。

とりあえず、インタープリタを拡張して、dlopen()やdlsym()も動くようにしてみました。
これで、いろんなDLLをよんでいろんなことができる。


---------------------------
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#ifdef _WIN32
#include <windows.h>
#endif
#ifdef unix
#include <unistd.h>
#endif


#define MAX_AAA 50
#ifdef MAX_AAA
#define MAX_BBB 100
#endif

#ifdef _WIN32
#define PLAT "Windows"
#else
#ifdef unix
#define PLAT "unix"
#else
#ifdef PICOC_VERSION
#define PLAT "picoc"
#else
#define PLAT "unknown"
#endif
#endif
#endif

#define print(a) printf("%s\n",a);

static int test()
{
printf("test()\n");
return 123;
}


int main()
{
void* vp=(void*)0x12345678;
double d=0;

printf("test hello %d \n",MAX_BBB);
printf("PLAT=%s\n",PLAT);
printf("vp=%p\n",vp);
test();
system("cmd");

return 0;
}

---------------------------