CodeZine(コードジン)

特集ページ一覧

PHP_LexerGeneratorとPHP_ParserGeneratorを利用して
PHPで独自の言語を実装する方法

PEARライブラリ活用 (10)

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/12/17 14:00
目次

構文解析器

 構文解析器は次のような手順で作成します。

  1. 構文解析器を定義するファイル(.y)を作成する。
  2. コマンド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)プログラムの構文規則

 プログラムの構文規則は次のようになります。

[リスト5] myparser.y
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)が必要です。

[リスト6] test_parser.php
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

  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:PEARライブラリ活用

もっと読む

著者プロフィール

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

  • WINGSプロジェクト 矢吹 太朗(ヤブキ タロウ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5