Mindを「.class」ファイルに変換してみた備忘録

# JMindのソース例(本編は次から)

```FizzBuzz2.src
メインとは
    ３０を　回数指定し
        「」をつみ
        回数を　３で　割った余りが　ゼロ？　ならば
            「Fizz」を　合成し
        つぎに
        回数を　５で　割った余りが　ゼロ？　ならば
            「Buzz」を　合成し
        つぎに
        複写し　空列？　ならば
            捨て
            回数をつみ
        つぎに
        何でも表示することを
    繰り返すこと。
```

# これはなに

これは私がプログラミング言語MindのソースコードをJVM上で動く「.class」ファイルに変換するのを楽しんでいる、という自分語りと備忘録です。

※あくまで "Mindのソースコードを「.class」ファイルに変換するプログラム" ですが、長ったらしいので以下では**恐れながら**「コンパイラ」と言い換えます。

ソース：https://github.com/Snowman-s/JMind

# きっかけ

PHP上でJVMを作成されていた某ちょうぜつエンジニアに感化されて僕もこんなことができるようになりたいなぁと思っていました。

そこで、個人的に気に入ってた日本語プログラミング言語Mindを、JVM上で動かせるようにしたいなと思いまして。

名前を先人たちに倣いJMindとしまして。

さぁ早速作りますよ。MindでMindのコンパイラを。

(※JVMを作る話では無くて、「.class」ファイルへのコンパイラを作る話です。)

# 苦労譚

## UTF-8

これが最初で割と大きい壁でした。SourceTreeがうまくShiftJISを読み込んでくれなかったので仕方なくMindのソースコードをUTF-8で動かせるようなプログラムを書きました。**Mindで。**あとバッチ

内容はShiftJISにファイルを変換してからコンパイラを動かす簡単なものです。

ソース:https://github.com/Snowman-s/MindTools

## 中間コード(「.mco」ファイル)

MindもJavaと同じく現在は中間コードを採用しており、それが「.mco」ファイルです。ですがどれだけ探してもそのファイルのフォーマットが見つかりませんでした。終わり。

ということで自分で１から構文解析的なことをやることになりました。

## 「スタック」

「.class」ファイルの動作原理、およびMindの仕組みはスタック言語であり、一見親和性が高く見えます。

**そんなことはない**――でした。

私が読み取りが正しければ、JVMのスタックはメソッドが終了すると強制リセットがかかり、Mindにおける単語はそうではないという大きな違いがあります。(https://docs.oracle.com/javase/specs/jvms/se14/html/jvms-6.html#jvms-6.5.return)

何とか使えないかと試行錯誤していましたが、僕の技術ではだめでしたので、しょうがなく一つのコレクションを使いまわすことにしました。

選ばれたのは、java.util.Stackでした。(のちにjava.util.LinkedListに変更。)

その結果、メインの単語で一つのコレクションをnewし、他のあらゆる単語はそのコレクションを受け取ってそれをスタックとするように設計されました。(まだ複数の単語定義は実装されていません。)

なお、この方法では数値や文字をスタックに積むためにいちいちInteger.valueOfやInteger.intValueを通さなければならないので、処理時間は見込めません。(いつか最適化を図っています。)

## 文字列およびファイル

このコンパイラは仕様上、中間ファイルにバリバリ書き出しバリバリ読み込みます。

Mindではローカルな文字列実体の中身は単語外では保証されず、ファイルの情報に上書きされることがあります。(そうと分かっていてもグローバルにすると名前空間が減る恐怖があり。)

このような大規模なプログラムを書いたことが無いのもあって、ファイル操作に関するソースコードは結構泥沼化しています。

# 明るい話(たのしかったこと)

## スタック言語

スタック言語はコンパイラに非常に優しかったです。
一つ一つの単語だけ見てその都度実行すればいいのです。

構文解析的なことは非常に楽に終わらせることが出来ました。

~~但し「かつ」と「または」、お前は駄目だ。~~「かつ」と「または」はまだ実装されていません。

## JVM上で動作可能に

「.class」ファイルにしたことでJVM上で動かすことができる、つまりJavaのコードからJMindのメソッドを呼ぶことが出来たときは僕の中でブレイクスルーが起きました。(JMind側からJavaのメソッドを呼ぶのはまだ実装されていません。)

以下に例をくっつけておきます。

```MWithJava.src
※Mind側
PrintNumbersとは
    （受け取った数を）　回数指定し
        回数を　何でも表示することを
    繰り返すこと。
```

```java:JWithJava.src
import java.util.*;
public class JWithJava {
    //Java側
    //MWithJava.srcをコンパイルして、
    //これを実行する。
    public static void main(String[] args) {
        LinkedList<Object> s = new LinkedList<>();
        s.push(30);
        //Mindソースの関数を呼ぶ。
        MWithJava.PrintNumbers(s);
    }
}
```

```terminal
> jmindc MWithJava.src
> javac -encoding UTF-8 JWithJava.java
> java JWithJava
123456789101112131415161718192021222324252627282930
```
## 「何でも表示」単語
上記の例でも少し出てきましたが、JMindにはMindにはない「何でも表示する」という単語が追加されています。これは、あらゆるオブジェクト(数値、文字列など)を標準出力することができる単語です。

「.class」で実装する、つまり表示にSystem.outのprint(Ljava/lang/Object;)Vを使わせてもらったことで、このようなことが可能になりました。

# 回想のまとめ(結論)

色々ドタバタしながら作っていましたが、最終的には良い経験になったと思います。

今でも気まぐれにちょくちょく機能が追加されているので気になったらのぞいてみてください。(最近では「選択する」が追加されました。)

以上です。あとに続くのはサンプルソースなので見たい人は見てください。

#スクラップ(サンプルソース、GitHubにもあります)

## 仲間外れ

```Declare.src
メインとは
    クラスの人数は　変数
    一グループあたりの人数は　変数
    余った人数は　変数

    ３９を　クラスの人数に　入れ
    ２を　一グループあたりの人数に　入れ

    クラスの人数を
    一グループあたりの人数で　割った余りを
    余った人数に　入れ

    余った人数が　ゼロ以外？　ならば
        「じゃあ先生とグループになろうか」を　一行表示し
    つぎに。
```

## 突き出しFizzBuzz
```FizzBuzz.src
メインとは
    ３０を　回数指定し
        回数を　１５で　割った余りが　ゼロ？　ならば
            「FizzBuzz」を
        さもなければ
            回数を　３で　割った余りが　ゼロ？　ならば
                「Fizz」を
            さもなければ
                回数を　５で　割った余りが　ゼロ？　ならば
                    「Buzz」を
                さもなければ
                    回数を
                つぎに
            つぎに
        つぎに
        何でも表示することを
    繰り返すこと。
```

## JMindにハローワールド
```HelloWorld.src
メインとは
    「こんにちは！　世界！」を　一行表示すること。
```

## スタック言語本領発揮
```InputSum.src
メインとは
    ０をつみ
    ここから
        一つ数値入力し　複写して
        ゼロ？　ならば
            捨てて
            打ち切る
        つぎに
        加えてゆくことを
    繰り返して
    「合計は」を　表示してから
    何でも一行表示すること。
```

## 辛辣な人たち
```Select.src
メインとは
    一つ数値入力し
    選択する
        「声小さいよ」
        「良く聞こえなかったな」
        「なんて言ったの？」
        真
    選択終わり
    何でも一行表示する。
```