2019.09.19 Thursday
ArduinoでBrainf*ck
昨日会社で骨董ものの逆ポーランド記法電卓をもらった。
逆ポーランド記法だと計算がスタックへのプッシュ/ポップを逐次行っていくだけで済むのでシンプルらしい。
それで何となくデジタル回路的なことなにかやりたいなあ、と思いつき、昨夜は何となく名著「CPUの創りかた」を眺めたりしていた。
C++でデジタル回路シミュレータを作ってCPUのエミュレーションしようかなあとか思って少しコードを書いてみたが、思ったよりも難しくて断念。回路のトポロジーの表現が難しい。出来なくはないと思うがかなり時間食いそうで今は難しい。
で、何かないかなあ、と考えていたら、以前C言語でBrainf*ckインタプリタ作ったなあと思い出した。以前の自分の記事を引用する。
”Brainf*ckにはたった8つの命令しかない。例えば'>'はポインタのインクリメント、'+'はポインタがさす値のインクリメントのような具合。あとはジャンプとか入出力がある。”
そういうことでかなりな低級言語。
これをArduinoで動かしてみよう!
まずは、シリアル通信を使って、コードをArduinoに送信すると、結果がシリアル通信で送られてくるものを作りたい。
コードは記事の最後。ほぼ以前作ったインタプリタの流用。
例えば
+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.
はBrainf*ck版Hello worldだが、これを送信すれば
という感じに返ってきます。
案外簡単。
最終的にはシリアル通信を使わないオフラインBrainf*ckコンピュータを作りたいなあ。
入出力端子を制御する拡張命令を加えれば多少は役に立つ?
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop()
{
// put your main code here, to run repeatedly:
static char cmd[256];
static int n = 0;
static int mode = 0;//0=input, 1=output
//static int N = 100;
static int ptr = 0;
static char mem[256];
for(int i=0;i<256;i++) mem[i] = 0;
if(mode==0)
{
char c = Serial.read();
if(c=='¥n') mode = 1;
else if(c!=-1) cmd[n++] = c;
//Serial.print("Humidity: ");
}
else if(mode==1)
{
Serial.print("¥n");
Serial.print("code: ");
for(int i=0; i<n; i++)
{
Serial.print(cmd[i]);
}
Serial.print("¥n");
for(int i=0;i<n;i++)//命令を実行していく
{
//printf("%d¥n",i);
switch(cmd[i])
{
case '>' :
ptr++;
break;
case '<' :
ptr--;
break;
case '+' :
mem[ptr]++;
break;
case '-' :
mem[ptr]--;
break;
case '.' :
// putchar(mem[ptr]);
//Serial.print(mem[ptr],DEC);
Serial.print(mem[ptr]);
break;
case ',' :
//mem[ptr] = getchar();
//mem[ptr]
break;
case '[' :
if(!mem[ptr])
{
int n1 = 1;//[の個数
int n2 = 0;//]の個数
i++;
while(n1!=n2)//右に走査していき、[の個数=]の個数になったらbreak
{
if(cmd[i]==']') n2++;
else if(cmd[i]=='[') n1++;
i++;
}
i--;
}
break;
case ']' :
if(mem[ptr])
{
int n1 = 0;//[の個数
int n2 = 1;//]の個数
i--;
while(n1!=n2)//左に走査していき、[の個数=]の個数になったらbreak
{
if(cmd[i]==']') n2++;
else if(cmd[i]=='[') n1++;
i--;
}
i += 2;
i--;
}
break;
}
}
mode = 0;
n = 0;
}
}