難解プログラミング言語の作り方/Deadfishをもとにする

このページでは、Deadfishをもとにして新たな言語を作ります。

Deadfishって何ですか 編集

Deadfish(直訳:死んだ魚)は、難解プログラミング言語のひとつで、もともとHQ9+のサブセットとする予定だったそうです[1]。 命令は4つですが、HQ9+のような命令はありません。

Deadfishの命令セット
命令 意味
i インクリメント
d デクリメント
s 数値を2乗
o 数値を出力

たったこれだけ!HQ9+よりも一層作りやすいです。 また、XKCDバリエーションという命令の種類もあります。それはインクリメントがx、2乗がkになっています。

さっそく計画しましょう 編集

仕様は以下のようにします。

  • 数値の型はint型とする。
  • 命令以外の文字はそのまま出力。
  • これ以外はDeadfishの仕様に従う。

命令を決めましょう。

命令
命令 意味
i 数値をインクリメントする。
d 数値をデクリメントする。
x 数値を倍にする。
z 数値を0にする。
g 数値の入力を求め、それを数値に代入する。System名前空間[2]のInt32.TryParse[3]、もしくはそれと同等なものを使用する。変換に失敗した場合、0を代入する。
o 数値を出力する。

実装しましょう 編集

変数の実装 編集

数値カウンタを作ります。

int counter = 0;

インタプリタの実装 編集

もちろんBrainfuckから流用します。

命令の実装 編集

ここで一番大事なのはg命令でInt32.TryParseを使っているところです。仕様を決めるときにそうしたので、Convert.ToInt32[4]などを使うのはダメです。

また、TryParseの2つ目の引数が「out x」となっていますが、関数側が「この変数への変更を反映したいです~」と設定するときにoutをつける必要があるためです。

ふつう関数の中で引数がいじられても元の変数には影響しません。でも、outをつけておくと変更が反映されるのです。似たようなものにrefキーワードがあります。

switch (cmd[i])
{
    case 'i':
        counter++;
        break;
    case 'd':
        counter--;
        break;
    case 'x':
        counter *= 2;   // counter = counter * 2; と同等
        break;
    case 'z':
        counter = 0;
        break;
    case 'g':
        string s = Console.ReadLine();
        int x = 0;
        if (Int32.TryParse(s, out x))
        {
            counter = x;
        }
        else
        {
            counter = 0;
        }
        break;
    case 'o':
        Console.WriteLine(counter);
        break;
}

テスト 編集

GO!テスト 編集

何故GOかと言いますと、プログラムがgoだからです[5]。数字を入力したら、そのままおうむ返しされます。

コード:go

入力例: 44

出力例: 44

全体図 編集

using System;
namespace not_Deadfish
{
    class Program
    {
        static void Main()
        {

            while (true)
            {
                int counter = 0;

                Console.Write("> ");
                string cmd = Console.ReadLine();

                for (int i = 0; i < cmd.Length; i++)
                {
                    switch (cmd[i])
                    {
                        case 'i':
                            counter++;
                            break;
                        case 'd':
                            counter--;
                            break;
                        case 'x':
                            counter *= 2;   // counter = counter * 2; と同等
                            break;
                        case 'z':
                            counter = 0;
                            break;
                        case 'g':
                            string s = Console.ReadLine();
                            int x = 0;
                            if (Int32.TryParse(s, out x))
                            {
                                counter = x;
                            }
                            else
                            {
                                counter = 0;
                            }
                            break;
                        case 'o':
                            Console.WriteLine(counter);
                            break;
                    }
                }
                Console.WriteLine();
            }
        }
    }
}

脚注 編集

  1. ^ 参考文献4を参照。
  2. ^ 名前空間とは、複数のクラス、インターフェースなどをまとめ、衝突の可能性を減らすものです。それで、Systemというのはその名の通り.NETの重要な部分を担っています。
  3. ^ 文字列から数値を取得する関数です。
  4. ^ TryParseと同じように文字列を数値に変換するが、細かい部分がいくつか異なっています。例えば、変換に失敗したら例外を投げることなどです。
  5. ^ こういうプログラムはcatプログラムとか呼ばれたりします。よく使われるのでいろんな種類があります。


前は「難解プログラミング言語の作り方/HQ9+をもとにする」です。

次は「難解プログラミング言語の作り方/ちょっとコーヒーブレイク(1) Esolang wikiに投稿してみよう」です。