2018年5月3日木曜日

オレオレ言語、Expressoについて・・・そもそも言語とは?

こんにちは、1ヶ月ぐらいぶりでしょうか。はざまです。ここ最近、オレオレ言語のExpressoの記事を立て続けに上げてきましたが、そもそも言語とはなんなのでしょうか?

ここでいう言語とは、もちろん我々が日常生活で使用する自然言語ではなく、プログラミング言語を指していますが、では、プログラミング言語を作るとはどういうことでしょうか?
プログラミング言語を作るには、大きく分けて4つの工程を理解し、制作する必要があります。レキサー(lexer)、パーサ(parser)、アナライザ(analyzer)、ジェネレータ(code generator)です。アナライザは広く言われている呼称かは知りませんが。
Expressoにおいては、レキサー、パーサはパーサジェネレータを使用して自動生成、アナライザは手動生成、ジェネレータは、式木を活用しています。カタカナのままでは、それぞれの役目のイメージが浮かばないと思うので、和訳すると、順にトークン生成器、構文解析器、構文解釈器、コード生成器みたいな感じになります。順に噛み砕いていきましょう。

まず、トークンとは何かですが、その言語において、最低限の意味をなす文字列を表します。例えば日本語だったら、品詞がトークンに当たりますかね。この文章の頭から日本語のレキサーにかけると、こんにちは,1,ヶ月,ぐらい……などとトークン化された単語が表示されるでしょう。
このトークンを元に、その言語で特定の意味を表す文、式などを構成するのが次のパーサの役目です。同様にこのブログの文章をパースすると、こんにちは、1ヶ月、ぐらい……などとパースされて式(まあ日本語だと、微妙ですが、expressionなら意味が通るでしょう)になり、構文木を生成します。
そして、構成された文、式の意味を解析し、何を意図しているかを解釈するのが、次のアナライザの役目です。このブログの文章で行くと、こんにちは=挨拶、1ヶ月=期間、ぐらい=期間の範囲を指定する……などと解釈されて意味(semantics: 自然言語の分野ではこう呼ばれないと思いますが)が構成されます。
さらに、最後のコード生成のフェーズはその名の通り、解釈してできた動作を実際に行うコンピュータが解釈できるコード(まあ、究極的にはアセンブリですね)に置き換える作業です。日本語の例には例えられないので、例はありません。このようにして、ある言語のソースコードは解釈されて実行できるコードに翻訳されます。上記の工程のうち、Expressoの例でもわかるように、第2ステップまではパーサジェネレータにより、文法規則さえ与えれば、自動化できます。もちろん、手でパーサを書くこともできますが、一般にyaccなどのツールを使う方が、最適化が行われて無駄のない構文解析が行えるでしょう。文法の要素の1つにLL(1)というものがありますが、これは手動で書いたパーサでは担保するのが困難でしょう。もちろん、LL(1)は文法そのものに付随する要素なので、文法自体がLL(1)ならば、手で書こうが、機械で生成しようが、LL(1)になります。
一方、意味解析のフェーズは、自動化が難しい分野です。構文木を本にどう解釈、意味付けを行うかは、言語に依存する部分が大きいためです。同じ=記号でも、ある言語は代入と解釈し、ある言語は等号と解釈するかもしれないのです。同様に、コード生成のフェーズも自動化は困難でしょう。この程度なら自動化する手段はありそうですが、この意味をどのように実行できるコードに反映するかも、実装によって異なってきます。

このように、言語を作るとは、主に4つの工程を通して、ただのテキストを実行できる何かに翻訳するプログラムを構成することです。文法は自然言語のように、テキストおよび記号から合法な文字列を導き出すことであり、一般にLL(1)の文法は、いい文法とされます。LL(1)は、1個先のトークンを読むだけで意味の弁別が行えるという意味だからです。先読みが必要ないということは、それだけ動作も速くなります。

いかがでしたでしょうか?あなたもプログラミング言語を作ってみたくなりましたか?言語を作ることは、主にコマンドラインで動くプログラムを作ることになるので、WebなどGUIありきのプログラミングに慣れている方にはハードルが高いかもしれません。ですが、言語自体ができてきてコードコンプリーションなどのユーザ支援の機能を実装する段階に入ると、GUIのプログラミングも出てきます。もちろん、実用的な言語を作るならば、何かしらの目的がないと続かないでしょうが、お遊び程度にCのサブセットを実装してみるのも一興かもしれませんね^ - ^