クソアニメのクソ言語を作ってみた

初めて投稿する記事がこんなタイトルで申し訳ないです...

この記事では、ひとむかしに流行ったクソアニメ、**ポプテピピック**のプログラミング言語を**Brainf*ck**をベースに作ってみたという記事です。

※本記事ではタイトルに見られるように汚い単語が多く出てきます

##概要
気づいたのは4月上旬、アニメの放送が終了した後、「ジョジョ言語があるんだからさすがにポプテピ言語があってもいいだろwww」と思い調べたのですが、なんと1件もヒットせず...！[^1]  
[^1]: 5月に調べたら既にあったので載せておきます。https://bf-gen.uhyohyo.net/lang/5a9ac3a9232162182c628c5c

**これはもう自力で実装するしかねぇ！！**  

と思い、Brainf*ckをポプテピ語録に置き換えた**ポプテピ言語PPTP**のインタプリタをC言語で作成しました。
後悔はしてない。

##Brainf*ckとは
Brainf*ckは~~頭がクソになる~~シンプルなプログラミング言語です。
たとえば以下のコードをご覧ください。

```Brainfuck:hello.bf
+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+
++.>-.------------.<++++++++.--------.+++.------.--------.>+.
```

これをBrainf*ckのコンパイラもしくはインタプリタで実行すると、

```
Hello,world!
```

と実行されます！~~わけが分からないよ~~

Brainf*ckは以下のたった8つの命令で構成されています。

|  命令  |  動作   |
|:------:|:------:|
|>|ポインタを１つ先に進める|
|<|ポインタを１つ前に戻す|
|+|ポインタが指す値を１増やす|
|-|ポインタが指す値を１減らす|
|.|ポインタが指す値を出力する|
|,|値を入力して、 ポインタが指す場所に入れる|
|[|ポインタが指す値が0だったら対応する次の ] までジャンプ|
|]|対応する前の [ までジャンプ|

~~簡単でしょ？~~
ポインタが分からない人はメモリの番地を指す変数とでも思っていてください。

Brainf*ckは最低限の命令で構成されているため、サイズが小さくなります。
しかし、シンプルすぎるがゆえにソースコードは解読しづらく、難解プログラミング言語とも呼ばれています。

一方で、これらのシンプルな命令だけでちゃんとしたプログラミング言語が作れてしまうため、命令を別のものに置き換えれば**自作言語が簡単に作れてしまうのです！！**
たとえばどのようなものがあるかはぜひググってみてください。

##命令の名前を決める
それではBrainf*ckについての理解が深まったところで、Brainf*ckの命令をポプテピピックバージョンに置き換え、PPTPの命令にしていきます。
ここからポプテピ要素が増えていくので安心してください。

|  Brainf*ck命令  |  PPTP命令  |
|:---------------:|:----------:|
|>|がんばるぞい！|
|<|エイサイハラマスコ～イ|
|+|えい|
|-|ヘールシェイク！|
|.|いっぱいちゅき|
|,|ボブネミミッミ|
|[|ポプちん|
|]|ピピ美ちゃん|
考えがいろいろあってチョイスをしましたが、長くなるので省略します。察してください。

また、これ以外の単語が出てきた場合はコメントということにします。
なぜかというと、ソースコードを普通の文章にした方が楽しいからです。

##PPTPインタプリタの作成
さあ、プログラミングの時間です。
僕の得意分野がC言語というだけの理由で、C言語を使用しました。
あとになって構文解析ライブラリという存在を知りましたが、そんなもん知るか！ゼロから書かせろ！という頑固な性格により、C言語を突き通しました。
以下がPPTPインタプリタのソースコードです。

```C:pptp.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char chp[50000]={0};
char *p = chp;
long int start[40];
long int end[40];
int scount=0;

/* 見つけた単語に対応する命令を実行する関数 */
void Statement(int num, FILE *fp){
  static int isfind = 0;
  if(isfind){
    if(num == 6){
      isfind++;
    }
    if(num == 5){
      isfind--;
    }
    if(!isfind){
      start[scount] = -1;
    }
    return;
  }
  switch(num){
  case 0: /* エイサイハラマスコ～イ */
    p--;
    break;
  case 1: /* ヘールシェイク！ */
    (*p)--;
    break;
  case 2: /* ボブネミミッミ */
    *p = getc(stdin);
    break;
  case 3: /* いっぱいちゅき */
    putc(*p,stdout);
    break;
  case 4: /* がんばるぞい！ */
    p++;
    break;
  case 5: /* ピピ美ちゃん */
    scount--;
    end[scount]=ftell(fp);
    fseek(fp,start[scount]-strlen("ポプちん"),SEEK_SET);
    break;
  case 6: /* ポプちん */
    start[scount]=ftell(fp);
    scount++;
    if(*p == 0){
      scount--;
      if(end[scount]!=-1){
        fseek(fp,end[scount],SEEK_SET);
        end[scount] = -1;
        start[scount] = -1;
      }else{
        isfind=1;
      }
    }
    break;
  case 7: /* えい */
    (*p)++;
    break;
  }
}

int main(int argc, char *argv[]){
  char str[256];
  char strlist[][256]={
    "エイサイハラマスコ～イ",
    "ヘールシェイク！",
    "ボブネミミッミ",
    "いっぱいちゅき",
    "がんばるぞい！",
    "ピピ美ちゃん",
    "ポプちん",
    "えい",
    ""
  };

  int maxlength;
  int length = 0;
  int i;
  FILE *fp;

  /* ソースコードが指定されていないor正しくない */
  if(argc != 2){
    printf("さてはアンチだなオメー\n");
    exit(1);
  }
  if(strcmp(strstr(argv[1],"."),".pptp")){
    printf("さてはアンチだなオメー\n");
    exit(1);
  }

  /* ファイルが開けない */
  if((fp=fopen(argv[1],"rb"))==NULL){
    printf("失敗したのだ...叩かないでほしいのだ...\n");
    exit(1);
  }

  for(int i=0;i<40;i++){
    start[i] = -1;
    end[i] = -1;
  }

  /* この辺で構文解析 */
  for(;;){
    int maxsize;
    maxlength=strlen(strlist[0]);
    if((maxsize = fread(str,1,maxlength,fp)) == 0){
      break;
    }
    str[maxsize + 1] = '\0';

    if(maxsize < maxlength)
      maxlength = maxsize;

    for(i = 0;strlist[i][0]!='\0';i++){
      length = strlen(strlist[i]);
      if(!strncmp(str, strlist[i], length)){
        fseek(fp,-maxlength+length,SEEK_CUR);
        Statement(i,fp);
        break;
      }
    }
    if(strlist[i][0]=='\0'){
      fseek(fp,-maxlength+1,SEEK_CUR);
    }

  }

  fclose(fp);

  return 0;
}
```

すいません、書いたのが2ヶ月前でどんな考えで書いたか覚えてませんでした。
しかも、スクリプトの間違いとか用意した配列以上のメモリを指定しようとしてもC言語側でエラーを出さなければエラーを一切出さないクソダメなコードです。

そのため**安全性は保証していません**。
ちゃんとしたスクリプトを書けばちゃんと動くのでご心配なく。

(以下プログラムの雑な解説なんで飛ばしてどうぞ)

構文解析の部分では、確かある程度の長さの文字列をスクリプトから取り出し、その先頭が命令文字列と一致していればStatement関数で実行してその文字分先に進めて、命令でなかったら1文字読み取り位置を進めるといった感じにしたと思います。
ソースコードの読み取り位置はピピ美ちゃんの力により戻るので、fseekを使ってファイルの読み取り位置を戻すようにしています。

Statement関数で一番困ったのはポプちんとピピ美ちゃんです。基本的には見つけたらその位置を配列に入れて、ピピ美ちゃんから対応するポプちんの元へ向かうようにしています。
しかし、ポプちんのときにポインタが0だと対応するピピ美ちゃんへ戻ればいいのですが、ピピ美ちゃんを見つけていないのにポプちんから移動することもあります。
それらをいい感じに実装してうまくいっているのですが、どうやっているのか忘れました。

スタックの考え方を使えばよさげですが、この頃はスタックの使い道を把握していなかったので、どうしようもないです。

##実行・・・の前にスクリプトを書く
インタプリタをコンパイルしてPPTPという実行ファイルにしたら、あとは実行するだけです。
そのためにまず、PPTPのスクリプトを書く必要があります。
今回は拡張子は.pptpのみを許すようにしているので、ちゃんとしましょう。

しかし、ただでさえBrainf*ckを書くことが難しいのに、いきなりポプテピ言語から書き始めるのは竹書房でも難しいです。なので、Brainf*ckからポプテピ言語に変換するプログラムを作成しました。
が、載せるのを省略します。自力で作ってね！

ということで、さきほどのHelloWorldプログラムをPPTPに変換し、コメントという名の無駄文を加えたスクリプトがこちらになります。

```hello.pptp
えいえい　怒った？怒ってないよ
えいえいえいえいえいえいえい　怒った？怒ってないよ

ポプちんがんばるぞい！

えいえいえいえいえいえいえいえいがんばるぞい！
えいえいえいえいえいえいえいえいえいえいえいがんばるぞい！
えいえいえいえいえい　怒った？怒ってないよ(もう見た)
エイサイハラマスコ～イエイサイハラマスコ～イ
エイサイハラマスコ～イヘールシェイク！

ピピ美ちゃんがんばるぞい！いっぱいちゅきがんばるぞい！

えいえいいっぱいちゅき！
えいえいえいえいえいえいえいいっぱいちゅきいっぱいちゅき！
えいえいえいいっぱいちゅきがんばるぞい！

そのとき！矢野のギターが地獄を揺さぶる・・・！！！
ヘールシェイク！いっぱいちゅきヘールシェイク！
ヘールシェイク！ヘールシェイク！ヘールシェイク！ヘールシェイク！
ヘールシェイク！ヘールシェイク！ヘールシェイク！ヘールシェイク！
ヘールシェイク！ヘールシェイク！ヘールシェイク！

いっぱいちゅきエイサイハラマスコ～イ
えいえいえいえいえいえいえいえいいっぱいちゅき

僕、ベーコンむしゃむしゃくん！ベーコン食べるの大好きさ！
今日はね、僕の大好きなベーコンを焼いていこうと思います！
まず、油をいれて、そこにベーコンを入れたら完成d
アッッッッツゥゥゥッッッッゥウウ！！！！！！！！！！！

矢野はまだ、、、終わっちゃいねぇ！！
ヘールシェイク！ヘールシェイク！ヘールシェイク！
ヘールシェイク！ヘールシェイク！ヘールシェイク！
ヘールシェイク！ヘールシェイク！

ピピピッピ、いっぱいちゅき！えいえいえいいっぱいちゅき！

ヘールシェイク！ヘールシェイク！ヘールシェイク！
ヘールシェイク！ヘールシェイク！ヘールシェイク！
いっぱいちゅきヘールシェイク！ヘールシェイク！ヘールシェイク！
ヘールシェイク！ヘールシェイク！ヘールシェイク！
ヘールシェイク！ヘールシェイク！・・・・・

次回、星色ガールドロップ・エピソード０！
いっぱいちゅきがんばるぞい！

来週も、恋にドロップ！

「ポプ子・ピピ美」えいいっぱいちゅき！！！！！！

終劇（ザ・エンドってね）
```

まさにカオスとはこのことを言うんではないでしょうか。

関係ない文があることで、ポプテピピックであることに間違いはないんですが、ほんとにプログラムとして動くのかとても心配になりますね。大丈夫です、ちゃんと動きます。

##いよいよ実行！
さあいよいよ実行のときです。
このインタプリタはどの環境でも動くと思うので（保証はしませんが）、ぜひともやってみてください。

```console
$ ./PPTP hello.pptp
Hello,world!
```
動きましたね！！~~画像貼れよ~~

##最後に
いかがだったでしょうか。
今回はC言語でしたが他の言語でもインタプリタは作成できます。また、命令も自分の好きなように変えることができます。
世界に一つ自分だけのプログラミング言語があるというのはとても気持ちのよいことではありませんか！

ブームを過ぎたクソアニメの言語など日の目を浴びることはないと思いますが、Brainf*ckのインタプリタを作ったという点では自分にとって成長機会になったのではないかなと思います。

最後になりましたが、自力で作ったpptpファイルを載せておきます。コメントはないです。
なにが出力されるかはスクリプトを読むか実行するまでのお楽しみということで。

```
えいえいえいえいポプちんがんばるぞい！
えいえいえいえいポプちんがんばるぞい！
えいえいえいえいえいがんばるぞい！
えいえいえいえいがんばるぞい！
えいえいえいえいえいがんばるぞい！
えいえいエイサイハラマスコ～イエイサイハラマスコ～イ
エイサイハラマスコ～イエイサイハラマスコ～イヘールシェイク！
ピピ美ちゃんがんばるぞい！ヘールシェイク！がんばるぞい！
えいエイサイハラマスコ～イエイサイハラマスコ～イ
エイサイハラマスコ～イヘールシェイク！
ピピ美ちゃんがんばるぞい！がんばるぞい！えいがんばるぞい！
えいがんばるぞい！いっぱいちゅきヘールシェイク！
いっぱいちゅきえいいっぱいちゅきがんばるぞい！
いっぱいちゅきエイサイハラマスコ～イ
えいえいえいえいいっぱいちゅきエイサイハラマスコ～イいっぱいちゅき
ヘールシェイク！ヘールシェイク！ヘールシェイク！ヘールシェイク！
いっぱいちゅきエイサイハラマスコ～イいっぱいちゅきがんばるぞい！
がんばるぞい！がんばるぞい！いっぱいちゅき
エイサイハラマスコ～イエイサイハラマスコ～イ
えいえいえいえいいっぱいちゅきがんばるぞい！
ヘールシェイク！ヘールシェイク！ヘールシェイク！ヘールシェイク！
いっぱいちゅきエイサイハラマスコ～イエイサイハラマスコ～イ
ヘールシェイク！ヘールシェイク！ヘールシェイク！ヘールシェイク！
いっぱいちゅきがんばるぞい！
ヘールシェイク！ヘールシェイク！いっぱいちゅき
```

-----------