Successfully reported this slideshow.

More Related Content

Related Books

Free with a 14 day trial from Scribd

See all

詳説ぺちぺち

  1. 1. 詳説ぺちぺち 闇PHP勉強会 + PHPソースコード リーディングワークショップ 2012/01/28 do_aki
  2. 2. do_aki (どぅーあき) • |所属| > 株式会社もしも (ドロップシッピング・アフィリエイトASP) • |仕事| > インフラ(サーバ管理)兼 Webアプリケーション開発 • |出現| > 渋谷・山手線沿線 • |特性| > PHPer http://do-aki.net/
  3. 3. あじぇんだ • 第1章 ぺちぺち • 第2章 Scanner (字句解析器) • 第3章 Parser (構文解析器) • まとめ
  4. 4. 第1章 ぺちぺち
  5. 5. Japanese Programming Language らきすた風 画像生成 (ジェネレーター) http://raki.st/
  6. 6. 闇鍋的 PHP 魔改造 2011/09/10 PHPカンファレンス2011 Presented By do_aki
  7. 7. PHPの言語そのものの作りとかよく 知らないし、内部構造もよく分か らないけど、オレオレPHPを作って みたくてトライ&エラー繰り返し ていたら気づいたらPHPを基にした 日本語プログラミング言語ができ ちゃってたから発表してみたよ! ・・・というもの
  8. 8. <?php function HelloPHP() { echo "Hello PHP World"; } HelloPHP(); PHP ぺちぺち 関数 はろーぺちぺち() ここから 「"はろー ぺちぺち わーるど"」と表示; ここまで ぺちぺち はろーぺちぺち();
  9. 9. 条件分岐 もし [条件] ならば … そうでないならば … 条件おわり
  10. 10. 繰り返し 繰り返し [条件] の間 ここから … ここまで
  11. 11. 変数/条件/演算子 変数:ほげ は 0 です 1 が 2 より小さい (1<2) 1 が 2 より大きい (1>2) 1 足す 2 (1+2) 10 を 3 で割った余り (10%3)
  12. 12. 組み合わせると ぺちぺち 変数:ほげ は 1です; 繰り返し 変数:ほげ が 10 以下 の間 ここから もし 変数:ほげ を 3 で割った余り が 0 に等しい ならば 「 “アホn"」と表示; そうでないならば 「 変数:ほげ,"n"」と表示; 条件おわり 変数:ほげ に 変数:ほげ 足す 1 を代入; ここまで
  13. 13. ぺちぺち と PHP の違い ・Zend/zend_language_scanner.l add 98 lines & modify 22 lines ・Zend/zend_language_parser.y add 65 lines & modify 1 line
  14. 14. 第2章 Scanner
  15. 15. スキャナの状態 zend_language_scanner.l の半分から下あたり <ST_IN_SCRIPTING>"function" { return T_FUNCTION; } この文字列 このトークンを 返す が来たら <ST_IN_SCRIPTING>“{“ { yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); return '{'; }
  16. 16. スキャナの状態 zend_language_scanner.l の半分から下あたり <ST_IN_SCRIPTING>“def" { return T_FUNCTION; } この文字列 このトークンを <?php返す が来たら <ST_IN_SCRIPTING>“{“ { の代わりに def function def hello() { echo “like ruby?”; yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); return '{'; なんちゃって ruby のでき } } あがり
  17. 17. ぺちぺちでは <ST_IN_SCRIPTING>“function“|”関数” { <ST_IN_SCRIPTING>"function" { return T_FUNCTION; } <ST_IN_SCRIPTING>“{“ { ここから” { <ST_IN_SCRIPTING>“{“|” yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); return '{'; }
  18. 18. スキャナの状態 • INITIAL • ST_IN_SCRIPTING • ST_LOOKING_FOR_PROPERTY • ST_LOOKING_FOR_VARNAME • ST_VAR_OFFSET • ST_DOUBLE_QUOTES • ST_BACKQUOTE • ST_HEREDOC • ST_NOWDOC • ST_END_HEREDOC
  19. 19. ほとんどはこの状態 スキャナの状態 • INITIAL 初期状態 • ST_IN_SCRIPTING 基本状態 • ST_LOOKING_FOR_PROPERTY ->これ • ST_LOOKING_FOR_VARNAME ${ これ} • ST_VAR_OFFSET $xxx[これ] • ST_DOUBLE_QUOTES “これ” • ST_BACKQUOTE `これ` • ST_HEREDOC <<<“DOC” の後 • ST_NOWDOC <<<‘DOC’ の後 • ST_END_HEREDOC DOC の終わり
  20. 20. ぺちぺち動かず ぺちぺち echo "petipeti!n"; OK ぺちぺち NG echo "petipeti!n";
  21. 21. <INITIAL>"<?php"([ t]|{NEWLINE}) <INITIAL>("<?php"|"ぺちぺち")([ t]|{NEWLINE}) { <ST_IN_SCRIPTING> ("?>"|"</script"{WHITESPACE}*">"){NEWLINE}? { <ST_IN_SCRIPTING> ("?>"|"</script"{WHITESPACE}*">"|"ぺちぺちおしまい"){NEWLINE}? { これだけじゃ足りない orz <INITIAL>{ANY_CHAR} ???
  22. 22. 落とし穴 • “変数”の扱いは少し複雑 – 3カ所 + 隠し1カ所 (Parser 側からのみ参照) • 複雑な処理をしているところも – HEREDOC , NOWDOC – __CLASS__ • 簡単にセグる
  23. 23. <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; } <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; NG
  24. 24. <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; } 変数名をコ ピーして保持 <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; }
  25. 25. 第2章 Scanner まとめ • 元々あるキーワードの変更/追加は簡単 • スキャナの状態もほとんど意識する必要 はない • ところどころ Cで無理矢理処理してる部分 があるので注意
  26. 26. 第2章 Scanner 完
  27. 27. 第3章 Parser
  28. 28. Scanner によるトークンへの分解 <?php T_OPEN_TAG T_VARIABLE $x = $a + 1; ‘=‘ ++$x; T_VARIABLE ‘+’ T_LNUMBER ‘;’ T_INC T_VARIABLE ‘;’
  29. 29. Syntax Error T_LNUMBER ‘=’ 1 = $a; T_VARIABLE ‘;‘ Perser にトークンの並びが定義さ れていない
  30. 30. zend_language_parser.y ルール名 fully_qualified_class_name: namespace_name { $$ = $1; } | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); } | T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), …(省略) } ; トークンの 処理(C言語+α) 並び
  31. 31. zend_language_parser.y 拡張するために 新たにルールを作る BAD 処理をどう書けばいいのか分 からない orz
  32. 32. 似ているルールを真似る
  33. 33. T_VARIABLE $a + 1 ‘+’ T_LNUMBER expr '+' expr { zend_do_binary_op(ZEND_ADD, &$$, & $1, &$3 TSRMLS_CC); } New! T_VARIABLE $a 足す 1 T_JA_PLUS T_LNUMBER expr T_JA_PLUS expr { zend_do_binary_op(ZEND_A DD, &$$, &$1, &$3 TSRMLS_CC); }
  34. 34. IF 文 T_IF '(' expr ')' { zend_do_if_cond(&$3, &$4); } statement { zend_do_if_after_statement(&$4, 1); } elseif_list else_single { zend_do_if_end(); } else_single: /* empty */ | T_ELSE statement PHP T_JA_IF expr T_NARABA { zend_do_if_cond(&$2, &$3); } inner_statement_list { zend_do_if_after_statement(&$3, 1); } ja_else_single T_OWARI { zend_do_if_end(); } ja_else_single: /* empty */ ぺちぺち | T_JA_ELSE inner_statement_list
  35. 35. 落とし穴 • 突然現れる ‘$’ – Scanner で T_VARIABLE として処理されてな い!? • 本気でやるなら opecode / ZendAPI の知識 が必須 • コンパイルしてみないと分からない
  36. 36. Parser は 複雑なパズル 解きやすくするツール・方法あったら教えてほしいなー
  37. 37. 第3章 Parser 完
  38. 38. まとめ
  39. 39. Phpをいじり倒す10の方法 (2009) http://www.slideshare.net/moriyoshi/php10
  40. 40. 言いたかったこと • オレオレPHP作るの難しくないよ! • 拡張作るのも良いけど、言語そのものに コミットメントしてもいいんじゃないか な • PHPを楽しむ人が増えて、PHP がより一層 面白いものになってくれたらいいな
  41. 41. 改造のお供に • GNU GLOBAL (http://www.gnu.org/software/global/) – 静的にソースコードを解析するのに便利! – PHP のソースを展開したディレクトリで htags -Ffgnasv – CGI 使えれば検索も可能
  42. 42. 最後に • ぺちぺちは github においてあります • http://git.io/petipeti
  43. 43. ありがとうございました • 質疑応答?

×