『自由力』を身に付けるサイト「リバトレ」も見てね!!

新プログラミング言語『Zero』開発!言語デザインも解説!

いずみん

ということで、新プログラミング言語を作りました(笑)

と言いたいところですが、ほぼ↓の書籍に記載の「Diksam」という言語のパクリです。。お許しを。。

そのままパクってもいいよ」と仰ってくれているので、お言葉に甘えてパクらせていただきました。
が、何の前置きもなく「新しい言語作ったで」と言っちゃうのは人としてどうかと思うので、一言添えさせていただきました。

目次

ソースコードはこちら

ソースコードは上記リポジトリにありますので、興味のある方は是非。

新プログラミング言語の話の前に

なぜ新プログラミング言語を作ったのか

なぜ新プログラミング言語を作ったのかですが、それは「興味があったから」です。

今や無数のプログラミング言語がありますが、そのプログラミング言語がどうやってできているのかを知っている人はかなり少ないはずです。

ましてや、プログラミング言語を作ったことがある人はほぼいないでしょう。

新プログラミング言語を作ることに意味はあるのか

「意味はあるのか?」と聞かれたら、意味はないですね

そもそも自分の作った言語が流行ることなんてほぼありません。

大前提多くの人に使われなくてはいけませんし、今はプログラミング言語もかなりの数があるので、よっぽどの理由がないと流行らないでしょう。

新プログラミング言語を作るのは楽しい

プログラミング言語を作るには、「lex」「yacc」等の知識が必要です。

また、各ツールはC言語のツールであるため、C言語に関する知識もある程度必要になります。

C言語はさておき、「lex」「yacc」なんて普段使うことのないツールですが、こういう古めかしいツールを触るのが実は楽しかったりします

いずみん

字句解析・構文解析をしている自分に酔いしれることもできます(笑)

新プログラミング言語を作ることの良さ

プログラミング言語を作ろうとすると、まず「自分が作りたい言語のデザイン」を考えることになります。

そのためには、現在流行っているプログラミング言語のデザインをある程度把握しておく必要があります。

その上で、「この言語のこういうところはいいな~」「この言語のこういうところは気にくわんな~」等をグダグダ考えるわけです。

個人的には、この「言語デザインを考える」という部分が、プログラミング言語を作る一番の醍醐味だと思っています。

いずみん

言語のすべてを自分で決めることができる」というのが一番楽しいポイントですね。

Zeroを作るまでの経緯

新プログラミング言語を作る前に

まず、プログラミング言語の作り方が全く分からなかったので色々とググりました

1つだけ「それらしいサイト」を見つけましたが、それ以外はあまり参考にならない。。

で、あとから気付いたのですが、この「それらしいサイト」の内容を本にしたものが冒頭で紹介した書籍になります。

いずみん

僕はかなりの恩恵を受けているので個人名を出したい位ですが、勝手に出すのもあれなので書籍の方を再度ご紹介しておきます。

書籍で情報収集

日本人でプログラミング言語の神と言えば、Ruby開発者の「まつもとゆきひろ」さんです。

ということで、Matzさんの本も一冊購入して読みました。

いずみん

この本の面白いところは言語のデザインに深く触れている点です。

有名なプログラミング言語を片っ端から触る

先ほどの本を読めば、プログラミング言語の作り方は何となく掴めます。

次に、ひたすら有名なプログラミング言語を触りました

僕は元々「Java」「PHP」「フロント関連」は業務で触ったことがあったので、「C」「C++」「Python」「Go」など、それなりに有名な言語を片っ端から勉強しました。

いずみん

Rubyを触らなかったのは、資格勉強をした時に触っていたのと、先ほどのMatzさんの書籍でRubyの思想は何となく理解できたからです。

新プログラミング言語のデザインを決める

大体やるべきことはやったので、新プログラミング言語のデザインを決めました。

以下が新プログラミング言語に搭載したいポイントだったのですが、やはり僕はJavaが好きなので、かなりJavaチックです。

  • 静的型付け言語である
  • オブジェクト指向である
  • バイトコードはファイルとして出力しない
  • 拡張子は「ze」である

新プログラミング言語作成

では実際にプログラミング言語を作ります。

環境構築

環境構築については下記を参照してください。

Zeroの作成に着手

冒頭でもお話しした通り、基本的には書籍のソースコードを複製したものです

コピー元のソースコードをZero用に書き換えていますが、機能自体はほぼ変わりません。

コピー元のソースコードのダウンロードサイトは書籍に記載されており、本記事で勝手に記載するのもどうかと思ったので割愛します。
欲しい場合は、先ほど紹介した参考サイトからダウンロードするか、ZeroをパクってもらえればOKです。
ちなみに後で書きますが、Zeroも無償で複製してもらっていいので、どんどんパクっちゃってください

Zeroという名前について

Zeroについて説明する前に、Zeroという名前にした理由をお話ししていませんでした。

実は命名には色々理由があるので、箇条書きにしてみます。

  • ゼロから言語を作れるように(誰もが無償で複製可能という意味)。
  • B’zの大ファンで「ZERO」という曲が好きだから。
  • 日本らしい名前を付けたかったのですが、靖国神社で零戦を見て「日本の象徴と言えば零戦じゃね?」と思ったから。

最初の理由以外は後付けくさいですが、そこはまあ勘弁です。

ただ、一番は「ゼロから言語を作れるように」という点で、ソースコードはできる限り分かりやすく書いていくつもりです。

注意した点

注意した点として、世の中にあるプログラミング言語と名称が被らないようにだけは気を付けました

Zeroについて

さて、ようやくZeroの説明です。

何はともあれサンプルがあるとイメージが湧きやすいかと思うので、FizzBuzzのサンプルコードを載せておきます。

int i;

for(i = 1; i <= 100; i++) {
    if(i % 15 == 0) {
        print("FizzBuzz\n");
    } elsif(i % 3 == 0) {
        print("Fizz\n");
    } elsif(i % 5 == 0) {
        print("Buzz\n");
    } else {
        print("" + i + "\n");
    }
}

言語仕様については後述しているのでそちらを見てください。

ここでは、Zeroのざっくり概要をお話していきます。

静的型付け言語である

サンプルにある通り、Zeroは「静的型付け言語」です。

個人的に型がない言語は嫌いです

オブジェクト指向言語である

Zeroは、オブジェクト指向言語です。

当然クラスやインタフェース、継承という概念を持ち合わせていますが、詳細については言語仕様の方で書くのでこちらでは割愛します。

バイトコードは出力しない

Zeroはバイトコードをメモリ上に持ちます

つまり、バイトコードが出力されないので、変な訳の分からないファイルは出力されません

拡張子は「ze」

拡張子は悩みましたが、「ze」にしました。

最初は「zero」にしようかなとも考えましたが、長いのでやめました。

個人的には、世の中にある全拡張子と被らなければいいやと思っていたので、気を付けたのはそこだけでした。

バイトコードは仮想マシン「ZVM」が実行する

JavaだとJVMという仮想マシンが存在します。

それと同じで、Zeroにもバイトコードを実行するZVMが存在します

ZVMは、「Zero Virtual Machine」の略です。

Zeroの言語仕様

さてここからは、Zeroの詳細な言語仕様をお話しします。

各説明箇所にサンプルのソースコードも載せておきます。

規則

予約語

Zeroには予約語があります。

以下に記載の予約語は変数名などに使用することはできません。

abstract boolean break case catch class const constructor continue default delegate do double else elsif enum false final finally for foreach if instanceof int interface native_pointer new null override private public rename require return string super switch this throw throws true try virtual void while

識別子

これも一般的なプログラミング言語と基本的には同じです。

  • 最初の1文字目は、英字もしくはアンダーバー(_)であること。
  • 2文字目以降は、英字・数字・アンダーバー(_)であること。

識別子とは「変数名」「関数名」「クラス名」などです。

ホワイトスペース

Zeroのホワイトスペースは、「空白」「タブ」「改行」です。

上記3つは識別子の区切り文字以上の機能を持ちません。

コメント

コメントは、「/* */」「//」の2種類が使用可能です。

型の取り得る値の範囲は、ZVMがコンパイルされるC言語環境のものと一致します。

整数型(int)

整数型です。

// 整数型
int hoge;

実数型(double)

実数型です。

// 実数型
double hoge;

論理型(boolean)

論理型です。

値は「true」、もしくは「false」です。

// 論理型
boolean hoge;

文字列型(string)

文字列型です。

null代入可能であり、変更不可(immutable)です。

// 文字列型
string hoge;

void型(void)

void型です。

特殊型で、関数の戻り値がない場合のみ使用可能です。

// void型
void hoge() {
    // 処理
}

配列型

配列の要素数は宣言時に決定しなくても問題なしです。

要素数は動的に確保されます。

// 配列型
int[] hoge = {1, 2, 3};

列挙型

列挙型です。

enum Hoge {
    BLACK,
    BLUE,
    RED,
    GREEN,
    WHITE
};

delegate型

delegate型は、関数の型定義を行うことで変数としての宣言が可能となります。

これに関してはサンプルを見るのが一番分かりやすいかと思います。

delegate int Hoge(double foo);

int bar(double foo) {
    println("Hello World!!");
    return 0;
}

Hoge hoge;

hoge = bar;

println("return " + hoge(0.3));

宣言文

宣言文とは、変数の宣言のことを指します。

int val;

// 変数宣言(初期化子あり)
int val = 1;

変数宣言時には初期化子を設定できます。

// 変数宣言(final)
final int val = 1;

final」を先頭に付与することで値の上書きが禁止されます。

// 変数宣言(const)
const VAL = 1;

const」を先頭に付与することで定数定義が可能となります。

初期化子によって型を決定するため、型の指定は不要です。

if文

if(i % 15 == 0) {
    print("FizzBuzz\n");
} elsif(i % 3 == 0) {
    print("Fizz\n");
} elsif(i % 5 == 0) {
    print("Buzz\n");
} else {
    print("" + i + "\n");
}

波括弧({})は省略不可」です。

switch文

switch (1)
case 1 {
    println("case 1");
} case 2, 3 {
    println("case 2, 3");
} case 4 {
    println("case 4");
} default {
    println("default");
}

Zeroのswitch文は「break」を書く必要がありません。

あるcaseにマッチし処理が実行されたらswitch文を抜ける仕様です。

波括弧({})は省略不可」です。

while文

while (true) {
    print("Hello World!!");
}

波括弧({})は省略不可」です。

do while文

do {
    print("Hello World!!");
} while (true);

波括弧({})は省略不可」です。

for文

int i;

for (i = 0; i < 10; i++) {
    print("Hello World!!");
}

try文

try {
    // 処理
} catch (Exception e) {
    // 処理
} finally {
    // 処理
}

関数

// 例外記載なし
int hoge() {
    // 処理
}

// 例外記載あり
int hoge() throws ArrayIndexOutOfBoundsException {
    // 処理
}

上の関数が下の関数を呼べないということはありません。

クラス・インターフェース

クラス

アクセス修飾子 class クラス名 : スーパークラス, インターフェース {
    フィールド
    コンストラクタ
    メソッド
}

ソースコードだけだと伝わりにくいので、日本語で構文規則を記載しておきます。

public class Child : Parent {
    private int val;

    constructor initialize(int val) {
        this.val = val;
    }

    int getVal() {
        return this.val;
    }

    void setVal(int val) {
        this.val = val;
    }
}

抽象クラス

abstract class Hoge {
}

子クラスは抽象クラスのみ継承をすることが可能です。

言い換えると、あらゆるクラスは抽象クラスしか継承できません

インターフェース

アクセス修飾子 interface Hoge {
}

インターフェースはabstractメソッドしか記述できません。

その他

ファイル名

ファイル名は「スネークケース」とします。

スネークケースでないと動作しないというわけではなく、あくまでZero内での決まりです。

暗黙の型変換

型変換に関しては、以下の規則とします。

  • int型とdouble型の演算は、int型をdouble型に型変換して行う。
  • 文字列型に数字型を結合した場合、数字型を文字列型に型変換して結合する。

Zeroの使い方

Zeroの使い方は環境が整っているかどうかで変わります。

Windowsであれば、「gcc」「bison」「flex」などがPCにインストールされていないと使えません。

というのも、Zeroに対して上記のツールを実行することで最終的に「zero.exe」が出力されますが、これがZeroのソースコードを実行するための実行ファイルになります。

ということで、誰でも使えるように全出力ファイルを「develop」ブランチにプッシュしているので、「最終的な成果物が欲しい!」という方は以下からダウンロードしてください。

Zeroの環境が整っていない方はこちら!

先ほどお話しした通り、PCに諸々インストールされていない方は「develop」ブランチからZeroをダウンロードしてください。

powershell」を起動し、「compiler」フォルダで実行ファイルを実行します。

Zero\compiler> .\zero.exe ..\test\test.ze

今回は「test」フォルダにある「test.ze」を実行してみました。

Zero\compiler> .\zero.exe ..\test\test.ze
hoge    piyo
\nabc
abccde
3 + 5..8
3 - 5..-2
3 + -5..-2
3 * 5..15
3 / 5..0
10 % 3..1
3.0 + 5.0..8.000000
3.0 - 5.0..-2.000000
3.0 + -5.0..-2.000000
3.0 * 5.0..15.000000
3.0 / 5.0..0.600000
10.0 % 3.0..1.000000
3 + 5.0..8.000000
3 - 5.0..-2.000000
3 + -5.0..-2.000000
3 * 5.0..15.000000
3 / 5.0..0.600000
10 % 3.0..1.000000
3.0 + 5..8.000000
3.0 - 5..-2.000000
3.0 + -5..-2.000000
3.0 * 5..15.000000
3.0 / 5..0.600000
10.0 % 3..1.000000
3 + 5..8
3 - 5..-2
3 + -5..-2
3 * 5..15
3 / 5..0
10 % 3..1
3.0 + 5.0..8.000000
3.0 - 5.0..-2.000000
3.0 + -5.0..-2.000000
3.0 * 5.0..15.000000
3.0 / 5.0..0.600000
10.0 % 3.0..1.000000
3 + 5.0..8.000000
3 - 5.0..-2.000000
3 + -5.0..-2.000000
3 * 5.0..15.000000
3 / 5.0..0.600000
10 % 3.0..1.000000
3.0 + 5..8.000000
3.0 - 5..-2.000000
3.0 + -5..-2.000000
3.0 * 5..15.000000
3.0 / 5..0.600000
10.0 % 3..1.000000
1 < 3..true
3 < 1..false
1 <= 3..true
3 <= 1..false
1 == 1..true
1 == 3..false
1 != 3..true
3 != 3..false
1 >= 3..false
3 >= 1..true
3 > 1..true
1 > 3..false
1.0 < 3..true
3 < 1.0..false
1.0 <= 3..true
3 <= 1.0..false
1.0 == 1.0..true
1.0 == 3..false
1 != 3.0..true
3.0 != 3.0..false
3.0 >= 1..true
1 >= 3.0..false
3.0 > 1..true
1 > 3.0..false
1 < 3..true
3 < 1..false
1 <= 3..true
3 <= 1..false
1 == 1..true
1 == 3..false
1 != 3..true
3 != 3..false
1 >= 3..false
3 >= 1..true
3 > 1..true
1 > 3..false
1.0 < 3..true
3 < 1.0..false
1.0 <= 3..true
3 <= 1.0..false
1.0 == 1.0..true
1.0 == 3..false
1.0 != 3..true
3 >= 1.0..true
1.0 >= 3.0..false
3 > 1.0..true
1.0 > 3..false
== good.
!= good.
< good.
<= good.
<= good.
>= good.
>= good.
== good.
!= good.
< good.
<= good.
<= good.
>= good.
>= good.
int_val..5
int_val..3
int_val..9
int_val..3
int_val..1
double_val..5.000000
double_val..3.000000
double_val..9.000000
double_val..3.000000
double_val..1.000000
str_val..strhoge3
int_val..3
double_val..0.000000
a..3, b..4.000000
no_arg
a + b..28
a + b + c..10.000000
boolean_func..true
int_func..3
double_func..3.000000
string_func..hoge
********** recursive call **********
 a..10 a..9 a..8 a..7 a..6 a..5 a..4 a..3 a..2 a..1 a..0
 a..0 a..1 a..2 a..3 a..4 a..5 a..6 a..7 a..8 a..9 a..10
boolean_value..true
!boolean_value..false
true
boolean_value || false
true == true good
true != false good
! operator good.
true_value == true good
true_value != false good
! operator good.
true
good
good
good
********** while statement **********
 i..0 i..1 i..2 i..3 i..4 i..5 i..6 i..7 i..8 i..9
 i..0 i..1 i..2 i..3 i..4 i..5 i..6
********** for statement **********
 i..0 i..1 i..2 i..3 i..4 i..5 i..6
 i..0 i..1 i..2 i..3 i..4 i..5 i..6 i..7 i..8 i..9
********** break with label in while **********
 i..0, j..0
 i..0, j..1
 i..0, j..2
 i..0, j..3
 i..0, j..4
 i..0, j..5
********** break with label in for **********
 i..0, j..0
 i..0, j..1
 i..0, j..2
 i..0, j..3
 i..0, j..4
 i..0, j..5
********** continue in while **********
 i..5 i..6 i..7 i..8 i..9 i..10
i..10
********** continue in for **********
 i..5 i..6 i..7 i..8 i..9
i..10
********** continue with label in while **********
i..1 j..0, i..2 j..0, i..3 j..0,
i..3 j..0
********** continue with label in for **********
i..0 j..0, i..1 j..1, i..2 j..2,
i..3 j..3
*** i..0***
i == 0
i != 3
i != 2 && i != 3
*** i..1***
i == 1
i != 3
i != 2 && i != 3
*** i..2***
i == 2
i != 3
i == 2 || i == 3
i == 2 && j == 3
*** i..3***
i == else
i == 2 || i == 3
*** i..4***
i == else
i != 3
i != 2 && i != 3
i..11
ii = 10..10
array[3][0]..10
 1 2 3 4 5 6 7 8 9
 2 4 6 8 10 12 14 16 18
 3 6 9 12 15 18 21 24 27
 4 8 12 16 20 24 28 32 36
 5 10 15 20 25 30 35 40 45
 6 12 18 24 30 36 42 48 54
 7 14 21 28 35 42 49 56 63
 8 16 24 32 40 48 56 64 72
 9 18 27 36 45 54 63 72 81
array2[0]..1
array2[1]..2
array2[2]..3
array2[3]..4
array2[4]..5
 1 2 3 4 5 6 7 8 9
 2 4 6 8 10 12 14 16 18
 3 6 9 12 15 18 21 24 27
 4 8 12 16 20 24 28 32 36
 5 10 15 20 25 30 35 40 45
 6 12 18 24 30 36 42 48 54
 7 14 21 28 35 42 49 56 63
 8 16 24 32 40 48 56 64 72
 9 18 27 36 45 54 63 72 81
darray[0]..0.000000
darray[1]..1.000000
darray[2]..2.000000
darray[3]..3.000000
darray[4]..4.000000
darray[5]..5.000000
darray[6]..6.000000
darray[7]..7.000000
darray[8]..8.000000
darray[9]..9.000000
darray[0]..1.000000
darray[1]..2.000000
darray[2]..3.000000
darray[3]..4.000000
darray[4]..5.000000
darray[5]..6.000000
sarray[0]..str0
sarray[1]..str1
sarray[2]..str2
sarray[3]..str3
sarray[4]..str4
sarray[5]..str5
sarray[6]..str6
sarray[7]..str7
sarray[8]..str8
sarray[9]..str9
sarray[0]..1
sarray[1]..2
sarray[2]..3
sarray[3]..4
null_str..null
abcnull
null
OK
OK
OK
OK
{

実行すると、「test.ze」ファイル内のソースコードが実行されました。

Zeroの環境が整っている方はこちら!

環境が整っている方は「main」ブランチからZeroをダウンロードします。

Zero\compiler> gmake

compiler」フォルダで、「make」コマンドを実行します。

実行が完了すると、「compiler」フォルダに「zero.exe」が出力されます。

あとの手順は環境が整っていない方と同じです。

MinGWのデフォルトは「mingw32-make.exe」なのですが、これを「gmake.exe」にしています。

Zeroのテストコード

下記にテストコードのサンプルがあります。

Zeroの色々

ソースコード管理

今更ですが、ソースコードは「GitHub」上で管理しています。

ブランチ 説明
main Zero本体
develop mainブランチの内容+outputファイル
※Zeroの全ファイルです。

Zeroのライセンスについて

基本コピペしてもらってOKです。

Zero」という名前だけ変えて、「新しい言語作ったで!」と声を高らかに言ってもらってもOKです。

もちろん、僕への許可も何もかも必要ありません。

いずみん

できれば「Zero」っていう名前だけは被るからやめてください。。

まとめ

今回は、僕が作った新プログラミング言語「Zero」についてお話ししました。

Zeroをパクってあなただけのプログラミング言語を作っちゃいましょう!

ではまた!

独自プログラミング言語「Zero」

この記事が気に入ったら
フォローしてね!

シェアするんやで!

~ リバトレ ~

お金や副業に関する情報を発信しているよ!

この記事を書いた人

いずみんのアバター いずみん 自由力発信おじ

【自由力発信】うさんくさ笑 | 副業物販で5ヶ月目に月利30万円達成⇨脱サラ予定 | 物販(アパレルせどり)・アフィリエイト・投資で自由になるための情報を発信中?笑 | 元エンジニア | 保有資格約20個

関連記事

コメント

コメントする

目次
閉じる