PHPカンファレンス2011 でLTしてきました
「闇鍋的PHP魔改造」という中二臭ぷんぷんするタイトルで、オレオレPHPを作ったよという内容のことを話してきました。
以下、より突っ込んだことを。
具体的に何処をどう修正したのかは、
https://github.com/do-aki/petipeti/commit/0d1bc0bf0698c120ebff9ba282f4d0c615838446#L1R92
こちらを見てもらうと。
発表時点では、これ以上の修正はしていません。
字句解析とか
scanner.l の修正は結構簡単で、
-<ST_IN_SCRIPTING>"function" { +<ST_IN_SCRIPTING>"function"|"関数" { return T_FUNCTION; }
この修正だけで、
<?php function hoge(){ }
こいつを
<?php 関数 hoge(){ }
と書けるようになっちゃいます。
ただ、ちょっとはまったのが 「変数」の部分で、最初は以下のように単純に "$" の代わりに "変数:" を割り当てたんですが、
- <ST_IN_SCRIPTING,ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE,ST_VAR_OFFSET>"$"{LABEL} { + <ST_IN_SCRIPTING,ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE,ST_VAR_OFFSET>("$"|"変数:"){LABEL} { zend_copy_value(zendlval, (yytext+1), (yyleng-1)); zendlval->type = IS_STRING; return T_VARIABLE; }
これだと駄目で、
zend_copy_value(zendlval, (yytext+1), (yyleng-1));
これを、
zend_copy_value(zendlval, (yytext+7), (yyleng-7));
こうする必要がありました。
これ、どうやら、"$" に続く文字列をコピーしてるらしいんですね。
なので、もともとは yytext+1 なんですが、"変数:" のバイト数分オフセットしてやる必要があって yytext+7 (UTF-8 なので)
結局、コピペして新たに定義を割り当ててます。
<ST_IN_SCRIPTING,ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE,ST_VAR_OFFSET>"変数:"{LABEL} { zend_copy_value(zendlval, (yytext+7), (yyleng-7)); zendlval->type = IS_STRING; return T_VARIABLE; }
構文解析とか
parser.y に手を入れるのは結構大変でした。
代入については、元々の代入定義である
variable '=' expr { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); }
こいつをまねて、以下のようにするだけなので、比較的簡単なのですが、
variable T_HA expr T_DESU { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); } variable T_NI expr T_DAINYU { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); }
構造そのものに手を入れるようなケース、例えば if 文なんかは、もともと2種類ある if 構文
T_IF '(' expr ')' { zend_do_if_cond(&$3, &$4 TSRMLS_CC); } statement { zend_do_if_after_statement(&$4, 1 TSRMLS_CC); } elseif_list else_single { zend_do_if_end(TSRMLS_C); } T_IF '(' expr ')' ':' { zend_do_if_cond(&$3, &$4 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$4, 1 TSRMLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { zend_do_if_end(TSRMLS_C); }
これらを参考にして、$1 とか $2 とかの数字(それぞれトークンが順序で割り当てられたはず)をずらしたりしてます。
T_JA_IF expr T_NARABA { zend_do_if_cond(&$2, &$3 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$3, 1 TSRMLS_CC); } ja_else_single T_OWARI { zend_do_if_end(TSRMLS_C); }
ja_else_single:
/* empty */
| T_JA_ELSE inner_statement_list
;
修正後だけ見ると、そんなに難しくないように見えるんですが、
結構パタンが重複してしまうのか、コンパイルできなくて嵌ったことがしばしば。
構文定義書いてると、まるでパズルを解いている気分になりますね。
発表時とか
はやり、緊張しました。
もう少し慣れても良いんじゃないかと思ってるんですが、なかなか人前で話すのって慣れないですね。
スライド動かなくなって焦ったし、デモをお見せするときもマウスポインタ見つからなくてアセアセ。
しかも話す速度早すぎたし>< (5分ちょうどで終わったので結果オーライですが)
Ust のアーカイブ( http://www.ustream.tv/recorded/17179193 )見ると、「えー」とか「えっと」とか言い過ぎで聞きづらいですね。
精進します。。。
最後に
PHP カンファレンスを開催していただいた [twitter:@yudoufu] さんを始めとする実行委員の皆様、ありがとうございました。
また、[twitter:@anatoo] さんにこう言ってもらえたので、LTをする踏ん切りがつきました。ありがとうございます。
そして、LT を聞いてくださった、参加者、Ustream視聴者のみなさま、ありがとうございました。