kmyaccでWebkitのCSSパーサをPHPから使いたい、と思って色々作業。
- 先駆者
- Stagehand_PHP_Parser - /src/Stagehand/PHP - リポジトリ - Piece Framework
- http://redmine.piece-framework.com/projects/stagehand-php-parser/repository/revisions/master/show/src/Stagehand/PHP
上記の方との違いは、
なるべく素のままで、拡張はする方が好きなように拡張できれば、という方針です。
ソースなど
- kmyacc - 多言語対応LALRパーサー生成系
- http://www005.upp.so-net.ne.jp/kmori/kmyacc/
- yaccの生成を多言語できるように、テンプレート機能を持ったパーサー生成
- 手を加えるのが簡単すぎる。
- PHP版のテンプレートの元を作った方
- PHPのyaccを作ったよ - ベイエリア情報局
- http://blog.bz2.jp/archives/2008/01/phpyacc.html
- 上記のバグを修正した方
- ActionScriptのyaccを作ったよ - yukobaのブログ
- http://d.hatena.ne.jp/yukoba/20080220/p1
- 今回は、このPHPテンプレートを元に手を加えています。
- インストール&デモ
- ハタさんのブログ(復刻版) : kmyacc-phpを触る
- http://blog.xole.net/article.php?id=653
- 各種パッチを当てまくったkmyacc
- kmyacc に各種パッチを当てまくったバージョンを fork しました - muddy brown thang
- http://d.hatena.ne.jp/moriyoshi/20090824/1251119737
- 本家で採用してくれないかな。
変更内容
- グローバル変数 -> static変数
- 定数 -> const
- 関数 -> クラスメソッド
- 見やすいように整形
- アクセス権を設定したのでPHP5オンリーです。
lexer(amachang さんのをPHPに移植)
PHP 5.3 or higher is required.
PHP 5.3 以上が必要です。
静的な呼び出しの継承に
遅延静的束縛 (Late Static Bindings)を使用しているためです。
http://php.net/manual/ja/language.oop5.late-static-bindings.php
PHP 5.3 未満で使用するには、
継承を止めて、「static::」を「self::」に書き直します。
概要
amachang さん以下のものをPHPに移植したものです。
「WebKit の CSS の字句解析部分を JavaScript に移植しました」
http://d.hatena.ne.jp/amachang/20080502/1209732467
規則部の移植元 :
http://svn.webkit.org/repository/webkit/trunk/WebCore/css/tokenizer.flex
amachang さん作との違い :
1点目 :
汎用的な機能をもった Lexer クラスと
Lexer クラスに WebKit の CSS の字句解析に必要な情報を
オーバーライドした CssLexer クラスという構成になっています。
そのため、
amachang さん作では、
直接書かれていた css のコメント部分を無視している処理を一般化しています。
また、
無視をするかどうかを制御する setIgnore メソッドを追加しています。
2点目 :
Lexer クラスは、トークンの値を含んでいないため、
その結果の扱いには、注意が必要です。
なぜなら、
トークンの値は、 yacc などの構文解析器生成系による生成が必要で、
lex だけではその値を知り得ないためです。
(yacc と lex はセットで扱うので、
lex の中に含んでしまうのも可能です。
但し、その場合には、
yacc 側のトークン値が変化した場合、lex 側を書き直す処理が必要になります。)
Lexer::lex() では、以下の結果を返します。
array( $maybe_yychar, // トークン名の文字列(string) または ASCII 値 $value, // マッチした文字列 $next // マッチした文字列を削除したソース );
本来は、トークンの値(int)、または、ASCII 値(int)を返す必要がありますが、
トークンの値を「知らない」ことになっているため、
マッチしたトークンについては、そのトークン名を文字列(string)で返し、
そうでないものは、ASCII 値(int)を返します。
そのため、
呼び出し側で、トークンの値を適当に返す必要があります。
例)
<?php class KMyacc { const INTEGER = 257; /* 略 */ }
と定義されている中で yylex() から、Lexer クラスを呼ぶ場合
<?php /** * $maybe_yychar => string 'INTEGER' * $value => string '123' * $next => string '' */ list($maybe_yychar, $value, $next) = Lexer::lex('123'); $yychar = is_string($maybe_yychar) ? constant('self::' . $maybe_yychar) : $maybe_yychar;