Example 6: Emulating simple KAST expressions in a custom functionTo make the traversal of KAST tree nodes in next few examples more readable, we will create a wrapper function that allows us to emulate certain types of KAST expressions, specifically those that traverse a node tree top-down. Consider the following code: typedef struct { ktc_childId_t edge; ktc_treeType_t type; } TRULE; ktc_tree_t traverse(ktc_tree_t node, TRULE* rules) { ktc_tree_t rc = node; TRULE* ptr = rules; while( rc && ptr->edge ) { rc = ktc_proceed(rc, ptr->edge); if( rc && !ktc_isTreeType(rc, ptr->type) ) rc = 0; ptr++; } return rc; } Now, invoking a traversal is as simple as declaring an array of TRULE structures and calling the 'traverse' function. The result of 'traverse' is either the destination of the traversal or zero (if the traversal wasn't possible, or one of the specializations for validation didn't match). For each entry in the TRULE array, the function validates that it can proceed through the defined child edge and that the type of the node reached matches that expected. This continues until the end of the array (marked by the guard of a 0 edge). To see the function in action, let's go back to our requirement from the previous example (// FuncDef / FuncBody / Stmt::CompoundStmt / Stmts[*]::ExprStmt) to get to the statements within a function body so we can begin looking for expressions. As always, our custom function will be invoked on the FuncDef node, so we don't need to look for that, but starting from there we can traverse to the statements collection within the function using the following rules: TRULE stmts[] = { { cid_FuncBody, tid_Any }, { cid_Stmt, tid_CompoundStmt }, { cid_Stmts, tid_Any }, { 0, 0 } } ktc_tree_t statements = traverse(node, stmts); Note that the various features of KAST that allow for collection and dimension searching aren't natively available in ktc and must be coded individually. If you want to perform the equivalent of a â-œdescendant::â-? search, it's best to perform that part of it in a KAST expression if possible, so that you don't have to write a subtree search algorithm of your own. We'll explore writing a more complicated search pattern in a custom function in the next example, but in general use KAST for complex node traversal schemes wherever possible. |