字句解析をやってみる
プログラミング言語を作る的な本を 2 冊読み中ですが、そろそろ手元にコードがないとピンとこなくなってきたため、とりあえず作り始めようと思いました。
まずは、字句解析器(Lexical Analyzer)です。Lex を試してみてもよいのですが、自前でもそう大変そうではないので作ってみることにしました。さて、何で書くかなのですが…一番慣れている C# でやろうと思います。まぁ、一度作ってしまえば、多言語への移植も大変ではないですし。また、正規表現は書いていると頭が痛くなっているので、極力使わず。数値のリテラル部分などは、片方の本に載っていたオートマトンの話を使おうと思います。
本を 2 冊読むと、ちょっとずつ方針が違ったのですが、字句解析器に必要な機能としては、
- GetToken 的なメソッドで 1 トークンを取り出せるようにする
- トークンの先読みができるようにする
の 2 つがあれば良いようです。
片方の本では、整数リテラル・文字リテラル・識別子の 3 種類のみを考え、キーワード(if とか)や演算子は識別子に含めてしまう方式でやっていましたが、こちらはあまりしっくりこなかったので、キーワードや演算子は識別子と別物扱いし、キーワードや演算子も種類分けする方針で作ろうと思います。実装では、この前やった CodeMirror の Mode の stream オブジェクトも参考にします。
メソッド | 動作 |
---|---|
string Peek() | ストリームを進めずに次の一文字を読み取ります。終端の場合 null を返します。 |
string Next() | 次の一文字を読み取り、ストリームを 1 文字進めます。終端の場合 null を返します。 |
void SkipToLineEnd() | ストリームを行末へ進めます。 |
bool IsSpace(char c) | c がスペースなら true を返します。 |
void SkipSpace() | スペースを読み飛ばします。 |
bool Match(string pattern, bool advance = true) | 文字列が一致したら true を返す。一致して advance が true なら、文字分進める |
そのほか、stream では、現在の行数と何文字目かもカウントするようにします。基本方針は、Match で長い文字列のキーワードや演算子から一致を確認していって、一致しなかったら、各種リテラルの解析を始めるという感じにします。コメントや文字リテラルに入った場合はステートを変更して、その解析をやっていく感じです。
この辺りは、漠然と頭にはあったのですが、本と CodeMirror の Mode 周りの実装を見て、考えがまとまりました。(このサイトの実装を始めてから、頭でぐるぐるしていたことがスッキリしました)
さて、考えるのはこの辺にして、実装を始めようと思います…
できた
もきょもきょやったらできました。書いたコードを食わせてみたら、それなりに動きました。
将来的に 4 バイト文字にも対応できるように、string でやっています。そのほか、ループが多く処理効率が悪い気もしますが、気にならない速度で動くでしょう。ぐしゃぐしゃっと書いたので、どっかにバグがあると思いますが、ひとまず先に進めそうです。次は、構文解析器を作ってみようと思います。