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視聴者のみなさま、ありがとうございました。