Upload
doaki
View
1.004
Download
1
Embed Size (px)
DESCRIPTION
Citation preview
詳説ぺちぺち闇 PHP 勉強会 + PHP ソースコードリー
ディングワークショップ2012/01/28
do_aki
do_aki ( どぅーあき )
• | 所属 | > 株式会社もしも (ドロップシッピング・アフィリエイト ASP )
• | 仕事 | > インフラ(サーバ管理)兼 Web アプリケーション開発
• | 出現 | > 渋谷・山手線沿線• | 特性 | > PHPer
http://do-aki.net/
あじぇんだ
• 第 1 章 ぺちぺち• 第 2 章 Scanner ( 字句解析器 )• 第 3 章 Parser ( 構文解析器 )• まとめ
第 1 章ぺちぺち
闇鍋的P H P魔改造
2011/09/10 PHP カンファレンス 2011Presented By do_aki
PHP の言語そのものの作りとかよく知らないし、内部構造もよく分からないけど、オレオレ PHP を
作ってみたくてトライ&エラー繰り返していたら気づいたら PHP を基にした日本語プログラミング言語ができちゃってたから発表して
みたよ!・・・というもの
<?php function HelloPHP() { echo "Hello PHP World"; } HelloPHP(); PHP
ぺちぺち 関数 はろーぺちぺち () ここから 「 " はろー ぺちぺち わーるど " 」と表示 ; ここまで
はろーぺちぺち ();
ぺちぺち
条件分岐
もし [ 条件 ] ならば…
そうでないならば…
条件おわり
繰り返し
繰り返し [ 条件 ] の間ここから
…ここまで
変数 / 条件 / 演算子
変数 : ほげ は 0 です
1 が 2 より小さい (1<2)1 が 2 より大きい (1>2)
1 足す 2 (1+2)10 を 3 で割った余り (10%3)
組み合わせるとぺちぺち変数 : ほげ は 1 です ;
繰り返し 変数 : ほげ が 10 以下 の間ここから もし 変数 : ほげ を 3 で割った余り が 0 に等しい ならば
「 “アホ \n" 」と表示 ; そうでないならば
「 変数 : ほげ ,"\n" 」と表示 ; 条件おわり 変数 : ほげ に 変数 : ほげ 足す 1 を代入 ;ここまで
ぺちぺち と PHP の違い
add 98 lines & modify 22 lines
・ Zend/zend_language_scanner.l
・ Zend/zend_language_parser.y
add 65 lines & modify 1 line
第 2 章Scanner
<ST_IN_SCRIPTING>"function" { return T_FUNCTION;}
<ST_IN_SCRIPTING>“{“ { yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); return '{';}
zend_language_scanner.lの半分から下あたり
スキャナの状態
この文字列が来たら
このトークンを返す
<ST_IN_SCRIPTING>“def" { return T_FUNCTION;}
<ST_IN_SCRIPTING>“{“ { yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); return '{';}
zend_language_scanner.lの半分から下あたり
function の代わりに def
なんちゃって ruby のできあがり
スキャナの状態
この文字列が来たら
このトークンを返す<?php
def hello() { echo “like ruby?”; }
<ST_IN_SCRIPTING>"function" { return T_FUNCTION;}
<ST_IN_SCRIPTING>“{“ { yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); return '{';}
ぺちぺちでは
<ST_IN_SCRIPTING>“{“|” ここから” {
<ST_IN_SCRIPTING>“function“|” 関数” {
スキャナの状態• 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
全部で10 の状
態を持つ
スキャナの状態• 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
初期状態基本状態-> これ${ これ }$xxx[ これ ]“ これ”` これ `<<<“DOC” の後<<<‘DOC’ の後DOC の終わり
ほとんどはこの状態
ぺちぺち動かず
ぺちぺちecho "petipeti!\n";
ぺちぺちecho "petipeti!\n";
OK
NG
<INITIAL>"<?php"([ \t]|{NEWLINE})
<INITIAL>("<?php"|" ぺちぺち ")([ \t]|{NEWLINE}) {
<ST_IN_SCRIPTING>("?>"|"</script"{WHITESPACE}*">"){NEWLINE}? {
<ST_IN_SCRIPTING>("?>"|"</script"{WHITESPACE}*">"|" ぺちぺちおしまい "){NEWLINE}? {
これだけじゃ足りない orz<INITIAL>{ANY_CHAR} ???
落とし穴• “ 変数”の扱いは少し複雑– 3 カ所 + 隠し 1 カ所 (Parser 側から
のみ参照 )
• 複雑な処理をしているところも– HEREDOC , NOWDOC– __CLASS__
• 簡単にセグる
<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
<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; }
変数名をコピーして保持
第 2 章 Scanner まとめ• 元々あるキーワードの変更 / 追加は簡単
• スキャナの状態もほとんど意識する必要はない
• ところどころ C で無理矢理処理してる部分があるので注意
第 2 章 Scanner
完
第 3 章Parser
Scanner によるトークンへの分解
T_OPEN_TAGT_VARIABLE ‘=‘ T_VARIABLE‘+’T_LNUMBER‘;’T_INCT_VARIABLE‘;’
<?php$x = $a +
1;++$x;
Syntax Error
T_LNUMBER‘=’T_VARIABLE ‘;‘
1 = $a;
Perser にトークンの並びが定義されていない
zend_language_parser.yfully_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 言語+α)
トークンの並び
zend_language_parser.y
拡張するために新たにルールを作る
処理をどう書けばいいのか分からない orz
BAD
似ているルールを真似る
T_VARIABLE‘+’T_LNUMBER
$a + 1
T_VARIABLET_JA_PLUST_LNUMBER
$a 足す 1
expr '+' expr { zend_do_binary_op(ZEND_ADD, &$$, &$1, &$3 TSRMLS_CC); }
expr T_JA_PLUS expr { zend_do_binary_op(ZEND_ADD, &$$, &$1, &$3 TSRMLS_CC); }
New!
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 statementT_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
ぺちぺち
PHP
落とし穴• 突然現れる ‘ $’ – Scanner で T_VARIABLE として処理され
てない! ?
• 本気でやるなら opecode / ZendAPI の知識が必須
• コンパイルしてみないと分からない
Parser は 複雑なパズル
解きやすくするツール・方法あったら教えてほしいなー
第 3 章 Parser
完
まとめ
Php をいじり倒す 10 の方法 (2009) http://www.slideshare.net/moriyoshi/php10
言いたかったこと• オレオレ PHP 作るの難しくないよ!• 拡張作るのも良いけど、言語そのものに
コミットメントしてもいいんじゃないかな
• PHP を楽しむ人が増えて、 PHP がより一層面白いものになってくれたらいいな
改造のお供に• GNU GLOBAL (
http://www.gnu.org/software/global/)– 静的にソースコードを解析するのに便利!– PHP のソースを展開したディレクトリで
– CGI 使えれば検索も可能
htags -Ffgnasv
ありがとうございました• 質疑応答?