例 5:AST ツリーをトラバースする
セマンティック情報を確認したので、今度はカスタム関数が AST ノードのツリーをどのようにトラバースするかを確認します。KAST 式によりこのトラバースは非常に簡単になりますが、カスタム関数内でトラバースを実行することが必要な場合があります。これは、ktc_proceed() API で実行できます。
簡単な KAST 式
簡単な KAST 式から始めます。次に例を示します。
// FuncDef / FuncBody / Stmt::CompoundStmt / Stmts[*]::ExprStmt
この式は、コンテンツにバインドする複合ステートメントを通して関数の定義からその本体にナビゲートし、その複合語で最初の最上位の expression ステートメントを取り上げます。
void foo(int someParams) { int someVariables; for( ... ) { } someVariables = 32; // This ExprStmt will be our result }
この演習では、通常の FuncDef ノードで呼び出されるカスタム関数は、関数のさまざまなステートメントをトラバースし、expression ステートメントを使用して何かを行う必要があります。ktc_proceed() 関数はこの目的で使用できます。
ktc_proceed() function
ktc_proceed() 関数は、チェッカーが進む必要がある開始ノードおよびエッジ指定子を受け取ります。Checker Studio の FuncDef ノードを調べる場合、一般に子エッジがあることを確認します。
FuncDef DeclSpecs[] :: DeclSpec Declarator :: MaybeDeclarator KRParams[] :: DeclOrStmt FuncBody :: AnyFuncBody
Checker Studio の AST の表現では、FuncDef ノードから、4 種類の子エッジ (DeclSpecs、Declarator、KRParams、および FuncBody) を通じて進むことができ、それぞれには特定の特殊化 (DeclSpec、MaybeDeclarator、DeclOrStmt、および AnyFuncBody) があることを示しています。エッジの特殊化を確認するには、目的のノードを展開します。次のように表示されます。
FuncDef DeclSpecs[] :: DeclSpec BuiltinType Declarator :: MaybeDeclarator Declarator KRParams[] :: DeclOrStmt FuncBody :: AnyFuncBody FuncBody
たとえば、KAST のすべての void 関数をチェッカーに検出させる場合、FuncDef を次のように特殊化できます。
// FuncDef / DeclSpecs[*]::BuiltinType [ @Spec = KTC_BUILTINTYPE_VOID ]
ktc API を使用してこの目的を達成するには、次の関数シーケンスを使用します。
// Assume we start with 'node' referencing the FuncDef node, as usual int isVoid(ktc_tree_t node) { return ( (node = ktc_proceed(node, cid_DeclSpecs)) != 0 ) && ( ktc_isTreeType(node, tid_BuiltinType) ) && ( ktc_getBuiltinType(node) == KTC_BUILTINTYPE_VOID ) ? 1 : 0; } HOOKS_SET_START ... XPath_register_int_hook("isVoid", isVoid); HOOKS_SET_END
これで、同じ KAST ステートメントを次のように簡素化することができます。
// FuncDef [ isVoid() ]
実際には、ktc_sema_getFunctionType() を使用したセマンティック情報で関数型を調べるでしょう。しかし、ktc_proceed() の方がこの例に適しています。