構文解析器
構文解析器は次のような手順で作成します。
- 構文解析器を定義するファイル(.y)を作成する。
- コマンドphplemon.batで構文解析器のためのクラス(.php)を生成する。
構文解析器の定義ファイルの作成
手順1のファイル(.y)の形式は次のとおりです。PHP_ParserGeneratorはLemon ParserというC言語用の構文解析器生成プログラムをPHPに移植したものなので、.yファイルの形式についての詳細は、Lemon Parserのマニュアルを参照してください。
%declare_class { class (1)構文解析器のクラス名 }
(2)トークンのリスト
%syntax_error { (3)エラーを表示するための手続き }
(4)プログラムの構文規則
(1)構文解析器のクラス名
ここでは、構文解析器のクラス名はMyParserとします。
(2)トークンのリスト
トークンのリストは先に字句解析器を生成した際と同じものを指定します。下に書いたものの優先度が高くなることに注意してください(例えば、加算(PLUS)より乗算(TIMES)の優先度が高くなります)。
(3)エラーを表示するための手続き
エラーを表示するための手続きは「echo "SYNTAX ERROR!\n";」でいいでしょう。
(4)プログラムの構文規則
プログラムの構文規則は次のようになります。
program ::= expr(A).{ echo "ANS.:".A."\n"; }
expr(A) ::= expr(B) PLUS expr(C). { A = B + C; }
expr(A) ::= expr(B) MINUS expr(C). { A = B - C; }
expr(A) ::= expr(B) TIMES expr(C). { A = B * C; }
expr(A) ::= expr(B) DIVIDE expr(C). {
if (C != 0) A = B / C;
else echo "DIVIDE BY ZERO!\n";
}
expr(A) ::= LPAREN expr(B) RPAREN. { A = B; }
expr(A) ::= NUMERAL(B). { A = B; }
これらの構文規則は、次のようなことを意味しています。
- プログラム(program)は式(expr)である
- 「expr(A) ::= expr(B) PLUS expr(C). { A = B + C; }」は、「表現(B) PLUS 表現(C)という構文があったとき、実際に行われる処理はB+Cである」ことを表している。他も同様(LPARENは'('、RPARENは')'を表す(後で対応付ける)
実際に行われる処理をPHPで書くため、C言語を利用する場合に比べて早くプロトタイプを作れることが期待されます。
構文規則の組によって言語を定義するというのは、言語処理においてよく行われることで、厳密な理論的背景があります。参考文献(2)のようなコンパイラの教科書を参照してください。
構文解析器クラスの生成
構文解析器のためのファイル(.y)ができたら、コマンドphplemon.batを使って構文解析器のクラスを生成します。
phplemon.bat myparser.y
これによってmyparser.phpというファイルが生成されます。このファイルで定義されるクラスMyParserは、次のような定数を持ちます。
- MyParser::PLUS
- MyParser::MINUS
- MyParser::TIMES
- MyParser::DIVIDE
- MyParser::NUMERAL
- MyParser::LPAREN
- MyParser::RPAREN
作成した構文解析器で、「15/5」を構文解析してみましょう。この文字列は「15, /, 5」に分解することがでますが、これらは順にMyParser::NUMERAL、MyParser::DIVIDE、MyParser::NUMERALに相当します。これらトークンの種類と値を構文解析器に与えて処理します(DIVIDEの値は不要ですが、そのような場合には値を0としておきます)。入力の終わりにdoParse(0,0)が必要です。
require_once "myparser.php"; $parser = new MyParser(); $parser->doParse(MyParser::NUMERAL,15); $parser->doParse(MyParser::DIVIDE,0); $parser->doParse(MyParser::NUMERAL,5); $parser->doParse(0, 0);
実行結果は次のようになります。
php test_parser.php ANS.:3
