CodeZine(コードジン)

特集ページ一覧

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

PEARライブラリ活用 (10)

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

字句解析器と構文解析器

 前節の最後の例では「15/5」を手でトークンに分けてから構文解析器にかけましたが、トークンに分ける作業は本来字句解析器の仕事です。字句解析器と構文解析器は連携して使えるようにしなければなりません。

 字句解析器の出力を構文解析器の入力として使えるようにするために、先に作成した字句解析器(MyLexer)を修正したMyLexer2を作ります。修正点は次の2点です。

  • 字句解析器の定義ファイル(plex)で「require_once "myparser.php";」として、字句解析器が構文解析器を参照できるようにする
  • 構文解析器のトークンと構文解析器のそれとを一致させる

 2番目の修正を施すと、mylexer2.plexは次のようになります。

[リスト7] mylexer2.plex
<?php
require_once "myparser.php";

class MyLexer2

(略)

/*!lex2php
PLUS { $this->token = MyParser::PLUS; }
MINUS { $this->token = MyParser::MINUS; }
TIMES { $this->token = MyParser::TIMES; }
DIVIDE { $this->token = MyParser::DIVIDE; }
NUMERAL { $this->token = MyParser::NUMERAL; }
LPAREN { $this->token = MyParser::LPAREN; }
RPAREN { $this->token = MyParser::RPAREN; }
WHITESPACE { return false; }
*/
};
?>

 字句解析器と構文解析器は次のように組み合わせて使います。

 与えられた文字列を本稿で作成した字句解析・構文解析器で処理し、結果を表示する関数doTest()を用意します。同じ文字列をPHPの関数eval()で処理した結果も並べて表示させましょう。

[リスト8] test_lexer_parser.php
//Parserの読み込み・生成
require_once "myparser.php";
$parser = new MyParser();

//Lexerの準備
require_once "PHP/LexerGenerator.php";
new PHP_LexerGenerator('mylexer2.plex');
require_once "mylexer2.php";

//与えられた文字列を処理する関数
function doTest($str) {
    echo "$str \n";
    global $parser;
    $lexer=new MyLexer2($str);
    while ($lexer->yylex()) {//字句解析の結果を構文解析器に渡す
        $parser->doParse($lexer->token, $lexer->value);
    }
    $parser->doParse(0, 0);
    
    //PHPの関数evalで結果を確認
    echo 'EVAL:';
    eval('echo '.$str.';');
    echo "\n\n";
}

//テスト
doTest('10 + 2.1 * ( 3 + 1 )');
doTest('10 + ( 2.1 / 0.5 ) * ( 3 + 1 )');
doTest('10 + ( 2.1 / ( 0.5 + 0.5 ) ) * ( 3 + 1 )');
doTest('10 + + 1');

 実行結果は次のようになり、正しく処理されていることが分かります(「10 + + 1」はここで作成した簡易電卓では処理できません。エラーが発生すべき場所で「SYNTAX ERROR!」と表示されています)。

php test_lexer_parser.php
(略)
10 + 2.1 * ( 3 + 1 )
[token:5, value:10]
[token:1, value:+]
[token:5, value:2.1]
[token:3, value:*]
[token:6, value:(]
[token:5, value:3]
[token:1, value:+]
[token:5, value:1]
[token:7, value:)]
ANS.:18.4
EVAL:18.4

10 + ( 2.1 / 0.5 ) * ( 3 + 1 )
(略)
ANS.:26.8
EVAL:26.8

10 + ( 2.1 / ( 0.5 + 0.5 ) ) * ( 3 + 1 )
(略)
ANS.:18.4
EVAL:18.4

10 + + 1
[token:5, value:10]
[token:1, value:+]
[token:1, value:+]
SYNTAX ERROR!
[token:5, value:1]
ANS.:1
EVAL:11

おわりに

 簡易電卓を作るという例を通じて、PHPで字句解析と構文解析する方法を紹介しました。ここで作成した簡易電卓は本当に簡易的なものですが、PHP上で新しい言語を実装するという技術は、さまざまなところで応用できるでしょう。より高度な電卓を作りたい場合には、参考文献(3)を参照してください。lexやyaccを用いて変数や関数の導入する方法が紹介されています(本稿で紹介したのは、この文献で紹介した電卓の、最も最初のバージョンに相当します)。

 10回にわたるこの連載では、PEARのパッケージの中から、特に基本的だと思われるものを中心に紹介してきました。紹介したパッケージの多くは開発途中のものなので、目的は同じで使い方も同じものがいくつもあって混乱したり、ドキュメントが不十分なために使い方がよく分からなかったり、他の言語の対応物に比べて機能や性能が劣っているためにがっかりすることもありましたが、それらをある程度整理して、使える形で紹介することができたのではないかと思っています。個々の解説記事をそのまま役立ててもらいたいのはもちろんですが、連載の全体が、PHPというプラットフォームを選択するかどうかを判断する一つの材料になれば幸いです。

参考文献

  1. プログラミング言語C++』 Bjarne Stroustrup著、長尾高弘 訳、アジソンウェスレイパブリッシャーズジャパン、1998年12月
  2. コンパイラ入門』 山下義行 著、サイエンス社、2008年07月
  3. UNIXプログラミング環境』 Brian W. Kernighan・Rob Pike 著、Prentice Hall Ptr、石田晴久 訳、アスキー、1985年09月


  • 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