Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ソースコード→AST→オペコード、の旅を覗いてみる

 ソースコード→AST→オペコード、の旅を覗いてみる

PHPカンファレンス香川2026 での登壇資料です
https://fortee.jp/phpconkagawa-2026/proposal/e26dff71-551f-4be5-b1af-95f425fbae10

Avatar for hideki kinjyo

hideki kinjyo PRO

May 07, 2026

More Decks by hideki kinjyo

Other Decks in Programming

Transcript

  1. 発表に入る前に: 環境テスト 本資料の文字サイズ・オブジェクトのサンプルです。 最大表示領域とあわせて、ご確認ください。 [見えにくい場合] 資料を公開済みなので、ぜひお手元にご用意ください => https://speakerdeck.com/o0h/phpcon-kagawa-2026 or Fortee

    から 縦 幅 は 最 大 で こ こ ま で 使 い ま す ( 下 ま で 見 切 れ ず に 見 え ま す か ? ) 利用しているテキスト・太字もあります ・カラー1・カラー2・カラー3  #phpconkagawa #maki スライド番号この辺 Name substr 吹き出しも あります codecodecode codecodecode codecodecode 矢印
  2. 自己紹介 • 金城秀樹 / きんじょうひでき • GitHub: @o0h / 𝕏

    : @o0h_ • 関東方面から来ました • PHPカンファレンス香川2025に参加してから、 「めりけんや」武蔵小杉(神奈川)店に行くよう になりました  #phpconkagawa #maki
  3. プログラムの実行 [In PHP…] (今日の話題である) ASTやオペコードも、この過程で出てくる話です!  #phpconkagawa #maki S E

    E val var Op ソースコード オペコード <?php class A { ————— ————— AST 0 INIT_FCALL 'hoge' 1 SEND_VAL 1 2 SEND_VAL 10 3 DO_ICALL $0 4 ECHO $0 5 RETURN 1 機械語 00110000 00100000 00100000 01001001 01001110 01001001 01010100 01011111 01000110 01000011 01000001 01001100 01001100 00100000 00100111 01101000 01101111 01100111 01100101 00100111 00001010 00110001 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00001010 00110010 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00110000 00001010 00110011 00100000 <?php T_OPEN_TAG if T_IF \s T_WHITESPACE $a T_VARIABLE \s T_WHITESPACE echo T_ECHO $x T_VARIABLE トークン
  4. 文章→意味、の流れ 単語に分解して =>自分自身だけでなく「次の文字」で分割位置が決まる  #phpconkagawa #maki ① ド → ???

    ② ドア → ??? ③ ドアの → ドア / ??? ④ ドアの前 → ドア / の / ??? ⑤ ドアの前に… → ドア / の / 前 / ???
  5. 単語 is 大事 単語の分割が 一定しないと 意味が定まらない  #phpconkagawa #maki ドアの前に猫がいます

    ドアの前にねこがいます ドアの前にね、子がいます ドアの前、NINECOがいます
  6. 1. 字句解析: 文のまとまりを分割する S E E val var Op ソースコード

    オペコード <?php class A { ————— ————— AST 0 INIT_FCALL 'hoge' 1 SEND_VAL 1 2 SEND_VAL 10 3 DO_ICALL $0 4 ECHO $0 5 RETURN 1 機械語 00110000 00100000 00100000 01001001 01001110 01001001 01010100 01011111 01000110 01000011 01000001 01001100 01001100 00100000 00100111 01101000 01101111 01100111 01100101 00100111 00001010 00110001 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00001010 00110010 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00110000 00001010 00110011 00100000 <?php T_OPEN_TAG if T_IF \s T_WHITESPACE $a T_VARIABLE \s T_WHITESPACE echo T_ECHO $x T_VARIABLE トークン
  7. #phpconkagawa #maki 加算式のトークン <?php $a + $b;  T_OPEN_TAG <?php

    T_VARIABLE $a T_VARIABLE $b ; ; T_WHITESPACE \s + + T_WHITESPACE \s
  8. #phpconkagawa #maki 加算式のトークン <?php $a + $b;  T_OPEN_TAG <?php

    T_VARIABLE $a T_VARIABLE $b ; ; T_WHITESPACE \s + + T_WHITESPACE \s 1文字トークンは そのままの文字を トークン名にすることもある
  9. #phpconkagawa #maki if文のトークン <?php if(!$a){return;} hoge();  T_OPEN_TAG <?php T_IF

    if return return ; ; ( ( ! ! T_VARIABLE $a ) ) { { } } T_STRING hoge ; ; ( ( ) ) T_WHITESPACE \n
  10. #phpconkagawa #maki if文のトークン <?php if(!$a){return;} hoge();  ; ; (

    ( ) ) T_OPEN_TAG <?php T_IF if return return ; ; ( ( ! ! T_VARIABLE $a ) ) { { } } T_WHITESPACE \n T_STRING hoge 引用符がついていない 文字列
  11. 2. 構文解析: 要素を木構造に組み立てる S E E val var Op ソースコード

    オペコード <?php class A { ————— ————— AST 0 INIT_FCALL 'hoge' 1 SEND_VAL 1 2 SEND_VAL 10 3 DO_ICALL $0 4 ECHO $0 5 RETURN 1 機械語 00110000 00100000 00100000 01001001 01001110 01001001 01010100 01011111 01000110 01000011 01000001 01001100 01001100 00100000 00100111 01101000 01101111 01100111 01100101 00100111 00001010 00110001 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00001010 00110010 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00110000 00001010 00110011 00100000 <?php T_OPEN_TAG if T_IF \s T_WHITESPACE $a T_VARIABLE \s T_WHITESPACE echo T_ECHO $x T_VARIABLE トークン
  12. #phpconkagawa #maki プログラムの「木」  <?php $x = $a + $b;

    $x = $a + $b; $x = $a + $b $x $a + $b 式(代入式)の 左辺、右辺それぞれで ノードを分ける
  13. #phpconkagawa #maki プログラムの「木」  <?php $x = $a + $b;

    $x = $a + $b; $x = $a + $b $x $a + $b 右辺の式(加算演算)が 更に式(値)に分かれる $a $b
  14. #phpconkagawa #maki 代入式のAST <?php $x = $a + 9; 

    Expression Statement Other Expr Stmt Program Assign Op_Plus Var a Scalar_Int 9 Var x
  15. #phpconkagawa #maki 関数コール式のAST Program Expr Stmt Func Call Name substr

    Arg List Var x Scalar_Int 1 Scalar_Str abcd 関数コールは、 「関数名」「引数リスト」で 構築される
  16. #phpconkagawa #maki IF文のAST <?php if ($a < $b) { return

    $a; } else { return null; }  Program If Op_Smaller Var a Var b return Var a Else return Const Null
  17. <?php if ($a < $b) { return $a; } else

    { return null; } IF文のAST  Program If Op_Smaller Var a Var b return Var a Else return Const Null if ifは「値を返さない」ので 文として扱う #phpconkagawa #maki
  18. <?php if ($a < $b) { return $a; } else

    { return null; } IF文のAST  Program If Op_Smaller Var a Var b return Var a Else return Const Null < #phpconkagawa #maki
  19. <?php if ($a < $b) { return $a; } else

    { return null; } IF文のAST  Program If Op_Smaller Var a Var b return Var a Else return Const Null $a $b #phpconkagawa #maki
  20. <?php if ($a < $b) { return $a; } else

    { return null; } IF文のAST  Program If Op_Smaller Var a Var b return Var a Else return Const Null return $a #phpconkagawa #maki
  21. <?php if ($a < $b) { return $a; } else

    { return null; } IF文のAST  Program If Op_Smaller Var a Var b return Var a Else return Const Null } else { return null; } #phpconkagawa #maki
  22. <?php function hoge( $x, $y ): int { $ret =

    $x + $y; return $ret; } 関数定義のAST  Program Func Stmts Params Identifier hoge Identifier int 次のスライドへ #phpconkagawa #maki
  23. <?php function hoge( $x, $y ): int { $ret =

    $x + $y; return $ret; } 関数定義のAST  Assign Op_Plus Var x Var ret Var y Return Var ret Param X Param y Stmts Params Expr Stmt #phpconkagawa #maki
  24. #phpconkagawa #maki トークンリスト→AST <?php substr('abcd',1,$x);  Program Expr Stmt Func

    Call Name substr Arg List Var x Scalar_Int 1 Scalar_Str abcd さっき見たコード
  25. #phpconkagawa #maki トークンリスト→AST 1.T_OPEN_TAG 2.T_STRING(substr) 3.( 4.T_CONSTANT_ENCAPSE D_STRING(abcd) 5., 6.T_LNUMBER(1)

    7., 8.T_VARIABLE($x) 9.) 10.;  Program Expr Stmt Func Call Name substr Arg List Var x Scalar_Int 1 Scalar_Str abcd
  26. 次に来るものを「先読み」 して、情報を仕入れる #phpconkagawa #maki トークンリスト→AST 2.T_STRING(substr) 3.( [status: ؔ਺ίʔϧ४උத] 文字列

    + 開きカッコ ؔ਺ίʔϧ 必要なパーツが揃ったら 「関数コール」ノードを作ろう、 という気持ちだけ準備する ってことは関数名! 
  27. #phpconkagawa #maki トークンリスト→AST 3.( 関数コールノードにいて、 開きカッコ Name substr [status: Ҿ਺Ϧετ४උத]

    [status: ؔ਺ίʔϧ४උத] 「引数リストが来るな!」 が分かる ؔ਺ίʔϧ Ҿ਺Ϧετ
  28. #phpconkagawa #maki トークンリスト→AST 4.T_CONSTANT_ENCAPSE D_STRING(abcd) 5., 引用符で囲まれた文字列 Name substr Scalar_Str

    abcd [status: Ҿ਺Ϧετ४උத] [status: ؔ਺ίʔϧ४උத] 引数として渡す値として扱う ؔ਺ίʔϧ Ҿ਺Ϧετ
  29. #phpconkagawa #maki トークンリスト→AST 6.T_LNUMBER(1) 7., Name substr Scalar_Int 1 Scalar_Str

    abcd [status: Ҿ਺Ϧετ४උத] [status: ؔ਺ίʔϧ४උத] 同様に、 Integerの引数を作る ؔ਺ίʔϧ Ҿ਺Ϧετ
  30. #phpconkagawa #maki トークンリスト→AST 8.T_VARIABLE($x) Name substr Var x Scalar_Int 1

    Scalar_Str abcd [status: Ҿ਺Ϧετ४උத] [status: ؔ਺ίʔϧ४උத] 同様に、 変数読み込みの引数を作る ؔ਺ίʔϧ Ҿ਺Ϧετ
  31. #phpconkagawa #maki トークンリスト→AST 9.) Name substr Arg List Var x

    Scalar_Int 1 Scalar_Str abcd [status: Ҿ਺Ϧετ४උ׬ྃʂ] [status: ؔ਺ίʔϧ४උத] 閉じカッコが来たので、 引数リストの内容が確定 ؔ਺ίʔϧ ノードを生成する
  32. #phpconkagawa #maki トークンリスト→AST [status: ؔ਺ίʔϧ४උ׬ྃʂ] Func Call Name substr Arg

    List Var x Scalar_Int 1 Scalar_Str abcd Name + Arg Listが揃った これで関数コールの内容が確定
  33. #phpconkagawa #maki トークンリスト→AST 10.; Expr Stmt Func Call Name substr

    Arg List Var x Scalar_Int 1 Scalar_Str abcd 「文」が確定する デリミタが来たので
  34. 抽象じゃない構造木 具象構文木: 具体的なコンテンツも扱う構文木 (CST: Concrete Syntax Tree) • 空白、改行、; (

    ) , $ などなども保持される • 平易に言うなら、 抽象構文木が「意味(の構造)を保持する」とのに対し、 具象構文木は「書き方を保持する」ようなイメージ  #phpconkagawa #maki
  35. #phpconkagawa #maki CSTの例 ① ソースコードにある全ての テキストが残っている (行番号や文字の位置は別に 持つ)  Program

    php_tag <?php If Stmt "if" expr "(" var "$" name a ")" stmts "{" echo "echo" var "$" name x ";" "}" if ($a) { echo $x; }
  36. #phpconkagawa #maki CSTの例 ① 葉ノード(末端にあるもの) を辿っていけばコードが復 元できる  Program php_tag

    <?php If Stmt "if" expr "(" var "$" name a ")" stmts "{" echo "echo" var "$" name x ";" "}" if ($a) { echo $x; }
  37. #phpconkagawa #maki CSTの例 ② if文のbody部分の`{` `}` が ツリー上からも消えている  "if"

    expr "(" var "$" name a ")" stmts echo "echo" var "$" name x ";" Program php_tag <?php If Stmt if ($a) echo $x;
  38. #phpconkagawa #maki CSTの例 ①(比較用) ソースコードにある全ての テキストが残っている (行番号や文字の位置は別に 持つ)  Program

    php_tag <?php If Stmt "if" expr "(" var "$" name a ")" stmts "{" echo "echo" var "$" name x ";" "}" if ($a) { echo $x; }
  39. #phpconkagawa #maki If Var a echo Var x If Stmt

    "if" expr "(" var "$" name a ")" stmts "{" echo "echo" var "$" name x ";" "}" if ($a) { echo $x; } 同一のコードで2種類の構造木の比較
  40. それぞれに異なる利用目的があり、保持する情報が変わる • 抽象構文木(AST) • 利用者: コード解析やコンパイラ • 保持する情報: プログラムの構造 •

    具象構文木(CST) • 利用者: エディタやコードハイライト • 保持する情報: 構造情報とコンテンツ(テキスト)の対応 • ※ CSTは、PHPの内部で利用されているものではない 抽象/具象構文木の比較  #phpconkagawa #maki
  41. 3. コード生成: 木構造から別の表現に翻訳する S E E val var Op ソースコード

    オペコード <?php class A { ————— ————— AST 0 INIT_FCALL 'hoge' 1 SEND_VAL 1 2 SEND_VAL 10 3 DO_ICALL $0 4 ECHO $0 5 RETURN 1 機械語 00110000 00100000 00100000 01001001 01001110 01001001 01010100 01011111 01000110 01000011 01000001 01001100 01001100 00100000 00100111 01101000 01101111 01100111 01100101 00100111 00001010 00110001 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00001010 00110010 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00110000 00001010 00110011 00100000 <?php T_OPEN_TAG if T_IF \s T_WHITESPACE $a T_VARIABLE \s T_WHITESPACE echo T_ECHO $x T_VARIABLE トークン
  42. そもそもオペコードとは? • みたいな感じで!記号や記法が減り、表現方法が集約される • `= ! { } [ ]

    ' "` などの記号が無くなったり • `for foreach if switch match` などの制御構文が、 全て単純な「ジャンプ命令(`JMPZ JMPNZ` など)」になったり • アセンブリに近い形になる • 1命令ごとに「オペコード(命令) + オペランド(引数)」の形をとる • レジスタ/一時変数に値を置きながら処理を進める • ジャンプ命令で制御フローを表現する  #phpconkagawa #maki
  43. • みたいな感じで!記号や記法が減り、表現方法が集約される • `= ! { } [ ] '

    "` などの記号が無くなったり • `for foreach if switch match` などの制御構文が、 全て単純な「ジャンプ命令(`JMPZ JMPNZ` など)」になったり • アセンブリに近い形になる • 1命令ごとに「オペコード(命令) + オペランド(引数)」の形をとる • レジスタ/一時変数に値を置きながら処理を進める • ジャンプ命令で制御フローを表現する そもそもオペコードとは? • アセンブリに近い形になる  #phpconkagawa #maki これが 機械語の一歩前として 都合がいい
  44. #phpconkagawa #maki 代入式のオペコード <?php $x = $a + 9; 

    Expr Stmt Program Assign Op_Plus Var a Scalar_Int 9 Var x さっき見たコード
  45. 代入式のオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9 Var

    x [Կ͔ͷจ]  #phpconkagawa #maki Expr Stmt =「式文」。 子ノードに「式」を持つ文。 含まれる要素を知る必要があるので、 子ノードに処理を進める
  46. 代入式のオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9 Var

    x [{(Կ͔) = (Կ͔)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki Asign =「代入式」。 左辺・右辺を子ノードに持つ。 左辺→右辺→自分自身、という順番で解決する
  47. 代入式のオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9 Var

    x [{PHPม਺`CV0($x)`=(Կ͔)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki Var =「代入先の変数」。 PHPにわたす変数(x)を用意しつつ、 まだオペコードに出力できる内容はない
  48. 代入式のオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9 Var

    x [(ͳʹ͔)ɾ(ͳʹ͔)ΛՃࢉ͢Δ] [{PHPม਺`CV0($x)`=(↑)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki Binary Operation Plus =「加算」。 左辺・右辺を持つノード。 左辺→右辺→自分自身、という順番で解決する
  49. 代入式のオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9 Var

    x [PHPม਺`CV1($a)`ɾ(ͳʹ͔)ΛՃࢉ͢Δ] [{PHPม਺`CV0($x)`=(↑)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki Expression Variable =「変数読み取り」。 PHPの変数 `$a` を、 Op_Plusの左辺としてセット
  50. 代入式のオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9 Var

    x [PHPม਺`CV1($a)`ɾ`9`ΛՃࢉ͢Δ] [{PHPม਺`CV0($x)`=(↑)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki Scalar Int・・は名前の通り、整数リテラル。 (int)9を、Op_Plusの右辺としてセット
  51. 代入式のオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9 Var

    x [PHPม਺`CV1($a)`ɾ`9`ΛՃࢉ͢Δ] [{PHPม਺`CV0($x)`=(↑)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki 式「Op_Plus」に必要な情報が揃った! リデュース(還元)・エミット(出力)を行う
  52. 代入式のオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9 Var

    x [PHPม਺`CV1($a)`ɾ`9`ΛՃࢉ͢Δ] [{PHPม਺`CV0($x)`=(↑)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki 加算(命令) = オペコード`ADD` 引数(オペランド)1 = `CV1($a)` 引数(オペランド)2 = `9`
  53. 代入式のオペコード Expr Stmt Assign [0000] Var x 0000  T2 =

    ADD CV1($a) int(9) ----- [{PHPม਺`CV0($x)`=(↑)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki 加算(命令) = オペコード`ADD` 引数(オペランド)1 = `CV1($a)` 引数(オペランド)2 = `9`
  54. 代入式のオペコード Expr Stmt Assign [0000] Var x 0000  T2 =

    ADD CV1($a) int(9) ----- [{PHPม਺`CV0($x)`=(↑)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki (PHPには露出しない) 一時的な変数 CV0($x), CV1($a)の 次に出てきたので、 「2」になっている
  55. 代入式のオペコード Expr Stmt Assign [0000] Var x 0000  T2 =

    ADD CV1($a) int(9) ----- [{PHPม਺`CV0($x)`=(↑)ͷ୅ೖࣜ}จ]  #phpconkagawa #maki Assignの右辺が、`T2` にメモされている 還元するために必要な情報 = 左辺・右辺が揃った!
  56. 代入式のオペコード Expr Stmt [0001] 0000  T2 = ADD CV1($a) int(9)

    0001  ASSIGN CV0($x) T2  #phpconkagawa #maki 代入(命令) = オペコード`ASSIGN` 引数(オペランド)1 = `CV0($x)` 引数(オペランド)2 = `T2`
  57. 代入式のオペコード Expr Stmt [0001] 0000  T2 = ADD CV1($a) int(9)

    0001  ASSIGN CV0($x) T2  #phpconkagawa #maki 式文に必要な情報もすべて揃っている 今回は、子ノードの情報を使わないので そのまま破棄 消えてヨシ
  58. 代入式のオペコード Expr Stmt 0000  T2 = ADD CV1($a) int(9) 0001 

    ASSIGN CV0($x) T2  #phpconkagawa #maki このノード自体も、 エミットするべき内容が無いので、 そのまま破棄
  59. 代入式のオペコード 0000  T2 = ADD CV1($a) int(9) 0001  ASSIGN CV0($x)

    T2 0002  RETURN int(1)  #phpconkagawa #maki メインループ終了時(など)には、 自動的に「リターンを付与」して 終わらせる
  60. 代入式のオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9 Var

    x 0000  T2 = ADD CV1($a) int(9) 0001  ASSIGN CV0($x) T2 0002  RETURN int(1)  #phpconkagawa #maki できあがり!👏 <?php $x = $a + 9;
  61. 余談: Stmtノードのオペコード Expr Stmt Assign Op_Plus Var a Scalar_Int 9

    Var x 0000  EXT_STMT 0001  T2 = ADD CV1($a) int(9) 0002  ASSIGN CV0($x) T2 0003  RETURN int(1)  #phpconkagawa #maki 一部のPHP拡張を利用した場合など、 文ごとの処理に入る時に `EXT_STMT`を出力する XDebugなど
  62. IF文のオペコード 0000  T2 = IS_SMALLER CV0($a) CV1($b) 0001  JMPZ T2

    0005 0002  RETURN CV0($a) 0003  JMP 0008 0004  0007  RETURN null 0005  0008  RETURN int(1)  #phpconkagawa #maki <?php if ($a < $b) { return $a; } else { return null; } If Op_Smaller Var a Var b return Var a Else return Const Null
  63. 関数コールのオペコード 0000 INIT_FCALL_BY_NAME 3 string("hoge") 0001 SEND_VAL_EX string("abcd") 1 0002 SEND_VAL_EX int(1) 2

    0003 SEND_VAR_EX CV0($x) 3 0004 DO_FCALL 0005 RETURN int(1)  #phpconkagawa #maki <?php hoge('abcd',1,$x); Expr Stmt Func Call Name hoge Arg List Var x Scalar_Int 1 Scalar_Str abcd
  64. 立ち位置とか目的とか  #phpconkagawa #maki S E E val var Op

    ソースコード オペコード <?php class A { ————— ————— CST 0 INIT_FCALL 'hoge' 1 SEND_VAL 1 2 SEND_VAL 10 3 DO_ICALL $0 4 ECHO $0 5 RETURN 1 機械語 00110000 00100000 00100000 01001001 01001110 01001001 01010100 01011111 01000110 01000011 01000001 01001100 01001100 00100000 00100111 01101000 01101111 01100111 01100101 00100111 00001010 00110001 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00001010 00110010 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00110000 00001010 00110011 00100000 <?php T_OPEN_TAG if T_IF \s T_WHITESPACE $a T_VARIABLE \s T_WHITESPACE echo T_ECHO $x T_VARIABLE トークン S E E val var Op AST
  65. 立ち位置とか目的とか  #phpconkagawa #maki ソースコード <?php class A { —————

    ————— 人間が 読み書きしやすい 語彙が豊富で、 表現力が高い "simple"よりも "easy"さ重視
  66. 立ち位置とか目的とか  #phpconkagawa #maki オペコード 0 INIT_FCALL 'hoge' 1 SEND_VAL

    1 2 SEND_VAL 10 3 DO_ICALL $0 4 ECHO $0 5 RETURN 1 仮想マシン向け 語彙が貧弱で、 記述が煩雑 "easy"よりも "simple"さ重視
  67. 立ち位置とか目的とか  #phpconkagawa #maki 機械語 00110000 00100000 00100000 01001001 01001110

    01001001 01010100 01011111 01000110 01000011 01000001 01001100 01001100 00100000 00100111 01101000 01101111 01100111 01100101 00100111 00001010 00110001 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00001010 00110010 00100000 00100000 01010011 01000101 01001110 01000100 01011111 01010110 01000001 01001100 00100000 00100000 00100000 00110001 00110000 00001010 00110011 00100000 機械(CPU)の 実行に必要 単純・厳密・明示的 ポータビリティは 損なわれる
  68. 3. 実際にそれらはどういう風に定義されてるの • 定義している正体は `Zend/zend_language_scanner.l`ファイル • re2cというツールで使うための設定ファイル • Regular Expressions

    to Code の意味。まんまです!! • https://re2c.org/index.html • ざっくりと言えば「正規表現のルール」が書かれている • 「この状態の時」に「このパターン」が出てきたら「このトークンとみ なす」をルールとして定義していく • 状態 = ダブルクォテーションの中にいる時・配列のオフセットの宣言([] の中)にいる時)、など  #phpconkagawa #maki
  69. 4. 最近の例:Non-Nullable Cast 字句解析の定義 • "(! int)" という記法で "T_NONNULL_INT_CAST" というトークンになる

     #phpconkagawa #maki https://github.com/php/php-src/pull/20275/changes#diff-3e6742a9069b5717cf961c9d6b2aefbd1c730869d8a58123b1b5f3bc3e9082fc
  70. 4. 最近の例:Non-Nullable Cast 構文解析の定義 • "expr" の生成規則に、 新しい規則 "T_NONNULL_INT_CAST expr"

    が追加されている  #phpconkagawa #maki https://github.com/php/php-src/pull/20275/changes#diff-3e6742a9069b5717cf961c9d6b2aefbd1c730869d8a58123b1b5f3bc3e9082fc
  71. なぜASTが必要? • コンパイル過程で必ずしもASTが必要か?というと、そうでもない • 実際、PHPでのAST導入はPHP7から • 参考1: 内部的な変更の観点からのdo_akiさんの解説 • PHP

    AST 徹底解説 | PPT https://www.slideshare.net/slideshow/php-ast/68091348 • 参考2: hnwさんの解説 • PHP7調査(2)コンパイル時にASTを構築するようになった #PHP - Qiita https://qiita.com/hnw/items/4dfdcc6a3eace7fe1936 • 参考2: 「ASTにしなくても処理ができる」の例として、shunsockさんの発表/本 • はじめて作るプログラミング言語 https://zenn.dev/shundeveloper/books/b224dd232e5a22  #phpconkagawa #maki
  72. AST → オペコード • ノードを1つずつ辿って、変換していく • コンパイラの中で、 「この種類のノードだったら、この関数を使って変換だ!」 を繰り返している 

    #phpconkagawa #maki if (ast->kind === ZEND_AST_hogehoge) { zend_compile_hogehoge(ast); } else if (ast->kind === ZEND_AST_fugafuga) { zend_compile_fugafuga(ast); }
  73. 探索例 こうなる  #phpconkagawa #maki ZEND_AST_STMT_LISTͷϊʔυ[0]Λʮzend_compile_top_stmtʯ(ݺͼग़͠ݩ: zend_compile) ZEND_AST_STMT_LISTͷϊʔυ[1]Λʮzend_compile_top_stmtʯ(ݺͼग़͠ݩ: zend_compile_top_stmt) ZEND_AST_ECHOͷϊʔυ[2]Λʮzend_compile_top_stmtʯ(ݺͼग़͠ݩ:

    zend_compile_top_stmt) ZEND_AST_ECHOͷϊʔυ[2]Λʮzend_compile_stmtʯ(ݺͼग़͠ݩ: zend_compile_top_stmt) ZEND_AST_ECHOͷϊʔυ[2]Λʮzend_compile_echoʯ(ݺͼग़͠ݩ: zend_compile_stmt) ZEND_AST_BINARY_OPͷϊʔυ[3]Λʮzend_compile_exprʯ(ݺͼग़͠ݩ: zend_compile_echo) ZEND_AST_BINARY_OPͷϊʔυ[3]Λʮzend_compile_expr_innerʯ(ݺͼग़͠ݩ: zend_compile_expr) ZEND_AST_BINARY_OPͷϊʔυ[3]Λʮzend_compile_binary_opʯ(ݺͼग़͠ݩ: zend_compile_expr_inner) ZEND_AST_ZVALͷϊʔυ[4]Λʮzend_compile_exprʯ(ݺͼग़͠ݩ: zend_compile_binary_op) ZEND_AST_ZVALͷϊʔυ[4]Λʮzend_compile_expr_innerʯ(ݺͼग़͠ݩ: zend_compile_expr) ZEND_AST_BINARY_OPͷϊʔυ[5]Λʮzend_compile_exprʯ(ݺͼग़͠ݩ: zend_compile_binary_op) ZEND_AST_BINARY_OPͷϊʔυ[5]Λʮzend_compile_expr_innerʯ(ݺͼग़͠ݩ: zend_compile_expr) ZEND_AST_BINARY_OPͷϊʔυ[5]Λʮzend_compile_binary_opʯ(ݺͼग़͠ݩ: zend_compile_expr_inner) ZEND_AST_ZVALͷϊʔυ[6]Λʮzend_compile_exprʯ(ݺͼग़͠ݩ: zend_compile_binary_op) ZEND_AST_ZVALͷϊʔυ[6]Λʮzend_compile_expr_innerʯ(ݺͼग़͠ݩ: zend_compile_expr) ZEND_AST_ZVALͷϊʔυ[7]Λʮzend_compile_exprʯ(ݺͼग़͠ݩ: zend_compile_binary_op) ZEND_AST_ZVALͷϊʔυ[7]Λʮzend_compile_expr_innerʯ(ݺͼग़͠ݩ: zend_compile_expr)