しょぼいマシンで自作プログラミング言語を作ってみる (6)
字句解析をするための最後の準備
字句解析するにも、まずは標準入力から文字を受け付けるところから
エンコーディングの判定までできたので、字句解析の準備はあと一歩です。
字句解析をするにも標準入力やファイルから文字列を読み込むことから始めなければなりません。
なのでmain処理が必要になります。
main関数は移譲したい
main関数の実処理は別ファイルに書きます。
別ファイルに書く理由としては、そのmain処理に対しテストもできるかも? といった目論見からです。
src/main.cppで記述するmain関数の処理は一行です。
ただ別ファイルで記述した関数を呼び出すだけ。
src/lib/main/main.cppに実処理を記述する方向で進めます。引数、戻り値の型はmain関数と合わせます。
移譲したmain関数でやるべきこと
まずは実行モードの判定からです。どうせやるなら、コンパイラモードとインタプリタモードを切り替えられるようにしたいです。
コンパイラモードはファイルの内容、もしくはechoコマンドの出力のパイプなりリダイレクトされた標準入力を元に一括でコンパイルできるようにします。
インタプリタモードはキーボード入力を受け付けて逐次解釈できるようにします。
キーボード入力を受け付けているかを判定するにはどうすべきか?
<unistd.h>にあるisatty()を利用します。
stdinのファイルディスクリプタを渡して、戻ってきた値が1以上ならばキーボード入力を受け付けていると判別できます。
Windowsの場合は<io.h>の_isatty()らしいですね。
これを使うと何が美味しいかというと、echo文の結果をパイプして渡したときと渡さなかったことで、プロンプトの有無を制御できることだったりします。
上記のisatty()を利用して、stdinがキーボード入力を受け付けているかどうかを元にインタプリタモードか、コンパイラモードかを振り分けます。
stdinがキーボード入力を受け付けている場合かつ、引数にソースファイル名が指定されていない場合はインタプリタモード、それ以外はコンパイラモードです。
include/cli/配下、src/lib/cli配下にそのモードに応じた処理を記述していきましょうか。
ひとまずはインタプリタモードで入力されたものからLLVM IRを出力できるようにしたいと思います。
字句解析
やっと、字句解析の話に
いろいろと字句解析をするための前提条件を満たすために尽力してきました。
やっとです。やっと、ここからが本番となります。
字句解析をできるようにします。
字句解析結果を保持するクラス
字句解析の結果、洗い出された単語の一単位を以後、トークンとします。
ひとまずは、そのトークンの情報を保持するクラスを用意しておきましょうか。
トークンの情報として、トークンの出現位置(行、列)、トークン種別、トークン文字列を保持しておきます。
そして、トークンへのポインタを持つ動的配列も用意しておきます。
あとはトークンの出現位置が決まった段階で動的配列に追加。トークン種別とトークン文字列が決まった段階で、動的配列の最後の要素が指し示す先にトークン種別とトークン文字列を設定。
そんな流れで実装します。include/parser/token.hpp、src/lib/parser/token.cppに実装しましょうか。
字句解析をするクラス
まずは半角空白(0x20)、改行(0x0a、0x0d)はトークンを区切るものとして扱います。
水平タブ(0x09)もトークンを区切るものとして扱います。
Pythonでは水平タブの数がブロックのネストを決めるというオフサイドルールがあるようですが、gallopでは適用しません。
ということでひとまずは整数であるかの判定をします。
整数は0から9の数字の連続ですね。また、負の数の場合はハイフン(0x2d)が数字の前に付きます。
ということでinclude/parser/lexer.hpp、src/lib/parser/lexer.cppに実装しましょうか。
整数の判定ができたら、小数表記、指数表記も対応しましょう。
小数表記は整数部のあとにドット(0x2e)ーーいわゆる小数点ですねーー、その後に数字が連続してあることが条件となります。とはいいつつも、小数点の後ろに続く小数部の数字はなくても可としましょうかーーGoやPythonでは許容しているみたいですしーー。
指数表記は整数、もしくは小数の後ろに英字のe(大文字小文字は問いません)があり、かつ、その後ろに正負の符号(正の符号は省略可です)、かつ、その後ろに数字が連続してあることが条件となります。小数表記とは異なり、eの後ろの指数部は必須です。
とりあえず、正常な10進数のトークンは取れるようにはなりました。
なりましたけれど……、異常なトークンの場合はどうしましょう?
例えば、指数表記が不正だった場合ですね。
ということで、その話は次回にでもするとしましょう。