プログラミング言語を作るにはどうしたらいい?

この記事のタイトルは、私がフォーラムや受け取った電子メールで何度も聞いた質問を反映しています。

好奇心の強い開発者なら誰でも一度は尋ねたことがあると思います。 プログラミング言語がどのように動作するのかに魅了されるのは普通のことです。 残念ながら、私たちが読むほとんどの回答は、非常に学術的または理論的です。 また、実装の詳細が多すぎるものもあります。 それらを読んだ後でも、実際にどのように動作するのか疑問に思うことがあります。 5380>

概要

「プログラミング言語を作る」方法を学びたい人のほとんどは、事実上、コンパイラを構築する方法に関する情報を探しています。 彼らは、新しいプログラミング言語を実行することを可能にする仕組みを理解したいのです。

コンパイラはパズルの基本的な部分ですが、新しいプログラミング言語を作るにはそれ以上のものが必要です:

1) 言語は設計されなければならない。

1)言語を設計する:言語の作成者は、使用するパラダイムと言語の構文について基本的な決定をしなければならない
2)コンパイラを作成する:標準ライブラリを実装しなければならない
3)エディタや構築システムなどのサポートツールを提供しなければならない

これらの各ポイントが何を含んでいるかを詳しく見ていきましょう。

プログラミング言語の設計

これらのことがどのように機能するかを学ぶために独自のコンパイラーを書きたいだけなら、この段階はスキップできます。 既存の言語のサブセットを使用するか、その簡単なバリエーションを考え出すだけで、始めることができます。 5380>

私はプログラミング言語の設計を2つの段階に分けて考えています。

  1. 全体像の段階
  2. 改良の段階

最初の段階では、言語に関する基本的な質問に答えます。 命令型なのか関数型なのか。 あるいは、ステート マシンまたはビジネス ルールに基づくか。

  • 静的型付けまたは動的型付けを行うか。 小さなスクリプトに使うのか、それとも大規模なシステムに使うのか、
  • 私たちにとって最も重要なことは何か: パフォーマンスか? 読みやすさ?
  • 既存のプログラミング言語と似たようなものにしたいですか? C 言語開発者向けか、Python から入ってきた人が学びやすいか。
  • 特定のプラットフォーム (JVM、CLR) で動作するようにしたいのか。 マクロですか? テンプレート? リフレクション?
  • 第2段階では、使用しながら言語を進化させ続ける予定です。 私たちは問題にぶつかり、私たちの言語で表現することが非常に困難または不可能なことに遭遇し、最終的に言語を進化させることになります。

    コンパイラの構築

    コンパイラの構築は、プログラミング言語の作成において最もエキサイティングなステップです。 いったんコンパイラができれば、私たちは実際に言語に命を吹き込むことができるのです。 コンパイラがあれば、その言語で遊び始め、それを使い、最初の設計で何が足りなかったかを確認することができます。 最初の成果を見ることができるのです。

    しかし、どのようにコンパイラーを構築するのでしょうか。

    あらゆるものが複雑であるように、私たちは段階を踏んでそれを行います。 パーサーは式、文、クラスを認識し、それらを表現する内部データ構造を作成します。 パーサーの残りの部分は、元のテキストではなく、これらのデータ構造で動作します。

  • (オプション) パース ツリーを抽象構文木に変換します。 通常、パーサーによって生成されるデータ構造は、コンパイラーにとって重要ではない多くの詳細を含むため、少し低レベルです。 このため、データ構造をより高度なものに並べ替えることが頻繁にあります。
  • シンボルを解決します。 コードではa + 1のように書く。 コンパイラは a が何を指しているのかを理解する必要がある。 それはフィールドなのでしょうか? 変数なのか? メソッドのパラメータなのか? それに答えるためにコードを調べます
  • 私たちはツリーを検証します。 プログラマがエラーを犯していないことを確認する必要があります。 彼はブーリアンとintを合計しようとしていますか? または存在しないフィールドにアクセスしていますか? 適切なエラーメッセージを生成する必要がある
  • 機械語コードを生成する。 この時点では、機械が実行できるものにコードを変換する。 それは適切なマシンコードか、いくつかの仮想マシンのためのバイトコードである可能性がある
  • (オプション) リンクを実行する。 場合によっては、プログラム用に生成されたマシンコードと、インクルードしたい静的ライブラリのコードを組み合わせて、1つの実行ファイルを生成する必要があります
  • コンパイラは常に必要ですか。 いいえ。 インタープリタを書くことができます。インタープリタは実質的に、コンパイラのステップ 1-4 を行い、抽象構文木によって指定されたものを直接実行するプログラムです。 トランスパイラは、ステップ 1 ~ 4 で指定されたことを実行し、すでにコンパイラがある言語 (たとえば C++ や Java) で何らかのコードを出力します

    これら 2 つの選択肢は完全に有効であり、通常必要な労力が小さいため、これらの 2 つのうち 1つを選択することは理にかなっていることが多い。

    私たちはトランスパイラの書き方について説明した記事を書きました。 この記事では、コンパイラとインタープリタの違いについてより詳細に説明します。

    プログラミング言語の標準ライブラリ

    どんなプログラミング言語でも、いくつかのことを行う必要があります:

    • 画面への印刷
    • ファイルシステムへのアクセス
    • ネットワーク接続の使用
    • GUI作成

    これらはシステムの残りの部分と対話するための基本的機能です。 これらがなければ、言語は基本的に役に立たない。 どのようにしてこれらの機能を提供するのだろうか。 標準ライブラリーを作ることである。 これは、私たちのプログラミング言語で書かれたプログラムで呼び出すことができる関数やクラスのセットですが、他の言語で書かれたものになります。 たとえば、多くの言語には、少なくとも部分的に C 言語で書かれた標準ライブラリがあります。

    標準ライブラリには、さらに多くのものを含めることができます。 例えば、リストやマップのような主要なコレクションを表現するクラスや、JSON や XML のような一般的な形式を処理するクラスなどです。 多くの場合、文字列や正規表現を処理する高度な機能を含んでいます。

    言い換えれば、標準ライブラリを書くことは多くの仕事です。 華やかさはなく、コンパイラーを書くほど概念的には面白くありませんが、それでもプログラミング言語を実行可能にする基本的な要素です。

    この要件を回避する方法があります。 1つは、言語を何らかのプラットフォームで動作させ、他の言語の標準ライブラリを再利用できるようにすることである。 例えば、JVM 上で動作するすべての言語は、単に Java 標準ライブラリを再利用できます。

    Supporting tools for a new programming language

    言語を実際に使用できるようにするには、しばしばいくつかのサポートツールを記述する必要があります。 シンタックスハイライト、インラインエラーチェック、および自動補完を備えた専用のエディタは、今日では開発者の生産性を上げるために必要不可欠なものです。 たとえば、デバッガーは厄介なバグに対処するために本当に役に立つかもしれません。 あるいは、maven や gradle に似たビルドシステムは、後でユーザーが求めるものになるでしょう。

    ごく初期にはエディターで十分ですが、ユーザーベースが大きくなると、プロジェクトの複雑さも増し、さらにサポートツールが必要になるでしょう。 願わくば、そのときに、それらを構築するのを喜んで助けてくれるコミュニティがあるとよいのですが。 この記事では、それが単なるプロセスであることを示そうとしました。 それは魅力的で簡単ではありませんが、実現できます。

    さまざまな理由から、プログラミング言語を構築したいと思うかもしれません。 1つの良い理由は楽しみのためであり、もう1つはコンパイラがどのように働くかを学ぶためです。 作成した言語は多くの要因によって、非常に有用なものになるかそうでないものになるかが決まります。

    そしてもちろん、仲間の開発者に自慢することができます。

    言語の作成についてもっと学びたい場合は、私たちが作成した他のリソース、言語の作成方法についてをご覧ください。

    コメントを残す

    メールアドレスが公開されることはありません。