EN JP CN

例 8:'descendent::' 検索を設計する

例 8:'descendent::' 検索を設計する

例 7 のように、その場合には項目—ステートメントのコレクションの全数検索の実行がしばしば必要です。この機能を提供するには、API が関数を公表します。

 ktc_forAllSubtreeNodes(ktc_tree_t, int (*callback)(ktc_tree_t, void*), void*);

この関数は、指定した開始ノードでサブツリーの縦型探索を実行し、特定のパターンの複合ステートメント (または他のすべてのコレクション) を検索したりする簡単な方法を提供します。

この API の別の特徴は、例 3 で使用したクラスメンバーの反復子とは異なり、この関数によりステートデータをコールバックに渡すことができます。よって、グローバルステートの必要はなくなります。任意のデータ構造を定義し、ステートを持ち越してこの API に渡すことができるため、呼び出されると常にコールバックに渡されます。コールバックは、ゼロ (検索を継続)、1 (検索を停止)、2 (子ノードの検索を停止するがこの深さレベルで兄弟の検索を継続) を返すことにより、API の次のステップを駆動できます。

この例の目的では、トラバースの試行に成功した場合に適切なメッセージをビルドログに表示するコールバック関数へのステートデータとして、トラバース規則 (TRULE) の配列を渡します。

 #include <stdio.h>
 #include <XPath_plugins.h>
 #include <ktcAPI.h>
   
 // This function is called for each node found by ktc_forAllSubtreeNodes()
 static int nodeCheck(ktc_tree_t node, void* data)
 {
   node = traverse(node, (TRULE*)data);
   if( node != 0 )
     fprintf(stderr, "Assignment to %s\n", ktc_getIdentifier(node));
   return 0;
 }
   
 int logAssignmentsEx(ktc_tree_t node)
 {
   ktc_semanticInfo_t si = ktc_getSemanticInfo(node);
   fprintf(stderr, "Looking for assignments in function %s\n", ktc_sema_getQualifiedName(si));
  
   // Incoming 'node' is a FuncDef node, so let's get into its CompoundStmt
   // This is the equivalent of the KAST expression:
   //   // FuncDef / FuncBody / Stmt::CompoundStmt
   TRULE stmts[] = {
     {cid_FuncBody, tid_Any},
     {cid_Stmt, tid_CompoundStmt},
     {0, 0}
   };
   node = traverse(node, stmts);
   
   // This set of traversal rules looks for "a = b"
   TRULE idexpr[] = {
     {cid_Expr, tid_BinaryExpr},
     {cid_Left, tid_IdExpr},
     {0, 0}
   };
   ktc_forAllSubtreeNodes(node, nodeCheck, idexpr);
   
   // This set of traversal rules looks for "this->a = b"
   TRULE memexpr[] = {
     {cid_Expr, tid_BinaryExpr},
     {cid_Left, tid_MemberExpr},
     {cid_Name, tid_Any},
     {0, 0}
   };
   ktc_forAllSubtreeNodes(node, nodeCheck, memexpr);
  
   return 1;
 }
  
 HOOKS_SET_START
   ...
   XPath_register_int_hook("logAssignmentsEx", logAssignmentsEx);
 HOOKS_SET_END

この関数は、この演習の 'descendent::' 検索目的を実現します。実世界のカスタムチェッカー関数の次の段階は、expression ステートメントを適切なクラス (たとえば、コンテキストデータを拡張してクラスのセマンティック情報に持ち越す) のメンバー変数への割り当てとして検証することかもしれませんが、このチュートリアルでは割愛します。