zz log

zaininnari Blog

kmyacc(多言語対応LALRパーサー生成系)のPHPテンプレートからグローバル変数を削除した&lexerの移植

kmyaccでWebkitCSSパーサをPHPから使いたい、と思って色々作業。

上記の方との違いは、
なるべく素のままで、拡張はする方が好きなように拡張できれば、という方針です。

環境

  • OS : Ubuntu 9.10
  • PHP : 5.3.2
  • kmyacc : 4.1.4

ソースなど

変更内容

  • グローバル変数 -> 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に移植したものです。


WebKitCSS の字句解析部分を JavaScript に移植しました」
http://d.hatena.ne.jp/amachang/20080502/1209732467



規則部の移植元 :
http://svn.webkit.org/repository/webkit/trunk/WebCore/css/tokenizer.flex



amachang さん作との違い :


1点目 :
汎用的な機能をもった Lexer クラスと
Lexer クラスに WebKitCSS の字句解析に必要な情報を
オーバーライドした 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;