C/C++ KAST 構文リファレンス

KAST 式のドラフト作成

KAST 式は、チェッカーが構文指摘のチェックのターゲットとする AST (抽象構文ツリー) 内の 1 つ以上の位置を記述します。

開始点は、目的の指摘を含むテストケース (単純なほど効果的) です。

Checker Studio は、以下を提供することで KAST 式のドラフト作成を単純化します。

  • 抜粋の視覚的表現
  • コンテキスト依存ヘルプ形式の詳細な KAST ノードタイプおよび依存関係の定義
  • KAST 式をテストする簡単な方法

例については、C/C++ KAST 例を参照してください。

構文

各 KAST 式は、ダブルスラッシュ (//) で始まり、スラッシュ記号で区切られたステップのシーケンスが続きます。各ステップは、特定の AST ノードに適用するサブパターンを指定します。

タイプ名の代わりに '*' を使用することができます。

チェッカーと一致すると、記述された順序の最後のノードと一致したノードでメッセージが報告されます。

例:

//IfStmt

この KAST 式には タイプ IfStmt の任意の AST ノードと一致する 1 つのステップ IfStmt が含まれます。完全な KAST 式は、すべての if ステートメントを検索する として解釈できます。

//IfStmt[Then::ExprStmt]

上述の KAST 式は、2 つのステップ IfStmt とThen::ExprStmt に分解することができます。2 番目のステップは子の名前 (Then) および子ノードのタイプ (ExprStmt) を指定します。上述の KAST 式は、「expression ステートメントおよび then ブランチを持つすべての if ステートメントを検索する」と解釈できます。

KAST 式に複数のステップが含まれる場合、後続の各ステップでは子の名前を指定する必要があります。子の名前の指定が必要なのは、単一の AST ノードに同じタイプの複数の子がある場合があるためです。この例としては、両方のブランチが複合ステートメントである if ステートメントがあります。その場合、子ノードのタイプを使用してパスを一意的に識別することができません。子の名前は一意であるため、トラバーサルの方向を明白に指定します。

//IfStmt[Else::Null]

この KAST 式には、IfStmt とElse::Null の 2 つのステップがあります。この式は、else ブランチを持たないすべての if ステートメントを検索する として解釈できます。

条件

KAST 式内のステップは、単なる子ノードのタイプの制限よりも複雑になる場合があります。子タイプの名前の後には、現在の AST ノードに対してチェックする必要のある条件である一連の述語のシーケンスが続く場合があります。条件は、角括弧内に入れ、ブール式または KAST 部分式のいずれかです。

//BinaryExpr [@Op = KTC_OPCODE_ADD]

2 つのステップがあります: BinaryExpr と[@Op = KTC_OPCODE_ADD]。

KAST 式は 演算が + であるすべてのバイナリ式を検索する として解釈されます。

2 番目のステップは、BinaryExpr ノードの属性の条件 ([@Op = KTC_OPCODE_ADD]) を指定します -- アット 記号 (@) は、現在のノードの属性を示すために使用されます。

//CallExpr/Func::IdExpr[Name::Name[@Id='gets']]

この式には、gets() 関数のすべての呼び出しを検索するための 4 つのステップがあります。2 番目のステップには、追加の 2 つのステップを条件として持つ入れ子の KAST 式が含まれます。

条件も参照してください。

修飾子

軸修飾子は次のように複数あります。

parent

Type1/parent::Type2

タイプ Type1 のノードはタイプ Type2 の親を持つことを意味します。

ancestor

Type1/ancestor::Type2

タイプ Type1 のノードはタイプ Type2 の祖先を持つことを意味します。

descendant

Type1/descendant::Type2

タイプ Type1 のノードはタイプ Type2 の子孫を持つことを意味します。

descendant-or-self

Type1/descendant-or-self::Type2

1) Type1 はタイプ Type2 のスーパータイプであるか、2) タイプ Type1 のノードはタイプ Type2 の子孫を持つことを意味します。特に、この軸は Type1 の代わりに '*' が使用されている場合に役立ちます。

following-sibling

Type1/following-sibling::Type2

2 つのノードが同じリストの子に属し、このリストではタイプが Type2 のノードがタイプ Type1 のノードの後 (直後または推移的) に続くことを意味します。

next-sibling

Type1/next-sibling::Type2

2 つのノードが同じリストの子に属し、このリストではタイプが Type2 のノードがタイプ Type1 のノードの直後に続くことを意味します。

child_name

Type1/<child_name>::Type2

Type1 ノードの子 child-name はタイプ Type2 であることを意味します。そのような子を持つ AST タイプがない場合は、エラーが報告されます。

sibling_indexafter a child name

Type1/<child name>[<sibling_index>]::Type2

タイプ Type1 のノードが、タイプ Type2 のノードのリストの子の sibling_index-th 要素であることを意味します。

sibling qualifier

//CallExpr/Exprs[*]::BinaryExpr

角括弧の間に数値ではなくアスタリスクが指定されている場合、対応するリストの子で最初に一致する要素が使用されます。上の式は、関数呼び出しにタイプ 'ExprBinary' の引数が少なくとも 1 つある場合に一致します。

NULL

//CallExpr/Args::Null

不在、別個、またはリストの子を表すためには、Null キーワードを使用する必要があります。

条件

KAST 式の各要素は、0 以上の条件を持つことができます。

各条件は、ブール式であり、角括弧内に入れる必要があります。パス要素は、対応するすべての条件が満たされた場合、AST ノードと一致させます。

式は次のタイプのうちのいずれかです。

  • BOOL
  • INT
  • DOUBLE
  • TREE (AST ノード)
  • SEMA (AST ノードに関連付けられたセマンティック情報)
  • STRING

BOOL 値、INT 値、DOUBLE 値は、相互に変換できます。また、TREE 値と SEMA 値は BOOL 型に変換できます。

次のタイプの式がサポートされています。

Path 式: 子修飾子で始まります: [Expr::BinaryExpr/Left::ConstExpr]

path 式が KAST パターン全体を構成する場合、'//' で始まり、ノードタイプ名が続きます。これは、対応するサブツリーは AST の任意の場所で照合されることを意味します。一方、path 式が KAST 式内の条件の 1 つである場合、または条件の一部である場合は、子の名前、またはその他の軸の修飾子で始まります。これは、そのパスはこの式が関連付けられているノードから始まる必要があることを意味します。

論理和式: Expression1 | Expression2

否定式: not Expression

関数式: Func(Expr1, Expr2, ...)

組み込み関数とカスタム関数の両方を使用できます。

C/C++ カスタム関数を参照してください。

ドット式: Expression.Func(...)

このような式の右部分は関数呼び出しである必要があります。ドット式の左部分の式は、右部分の関数の最初の引数として処理されます。a.b(c) は b(a, c) と同等です。

属性式: @attribute_name

算術式: Expression1 [+, -, /, *] Expression2

関係式: Expression1 [>, <, >=, <=, =, !=] Expression2

括弧式: (Expression)

定数式: 'abc' , 2.0

演算のタイプ、クラス指定子などを表す整数定数のリテラル表現がいくつかあります。

変数式: $variable

変数を参照してください。

サポートされている演算

以下に優先順位が高いものから演算を示します。

()、.not +、- >、>=、<、<= =、!= |

変数

変数を使用すると、KAST 式はよりわかりやすく効果的なものになります。変数を使用する前に、それに値を割り当てる必要があります。

[ $<varname> := <expression> ]

フィールド'expression' には条件 で説明したどの式を指定することもできます。

これで、条件、およびこの式要素に関連付けられたその他の割り当てでこの変数を使用することができます。

例:

[$size1 := getTypeSize(Expr1::ExprIdent)] [$size2 := getTypeSize(Expr2::ConstExpr)] [$size1 + 1 > $size2 - 1]

変数 size1 とsize2 に値を割り当ててから、式でその変数を使用しました。

その他の拡張子

KAST 式および path 条件には反復シーケンスを含めることができます。反復シーケンスとは、ノードタイプで始まり修飾子で終わるサブパスのことです。

反復シーケンスは、波括弧で囲み、修飾子とノードタイプ名の間に配置できます。

//BinaryExpr/Left::{BinaryExpr/Right::}ConstExpr

反復シーケンスは、対応する位置でゼロ回以上一致させることができます。上述の例は、次のような無限数の式に相当します。

//BinaryExpr/Left::ConstExpr
//BinaryExpr/Left::ConstExpr/Right::ConstExpr
//BinaryExpr/Left::ConstExpr/Right::ConstExpr/Right::ConstExpr

ノードの実際のタイプが重要ではない場合は、タイプ名の代わりに '*' 記号を使用することもできます。しかし、次のように 'short anonymous children' 表記を使用する方が効果的な場合もあります。

<Child name>

上記は以下と同等です。

<Child name>::*

たとえば、次の条件は同等です。

[isConstant(Expr1::*)], [isConstant(Expr1)], [(Expr1::*).isConstant()] and [Expr1.isConstant()]

すべてのケースで '*' を省略することはできないことに注意してください。KAST 式の反復シーケンスおよび末尾以外の要素では、完全な構文を使用してください。次の例を考えてください。

例:

//BinaryExpr/Right::*[isConstant()]

上記を以下によって置換することはできません。

//BinaryExpr/Right[isConstant()]

それは、名前の後の角括弧が兄弟インデックスの指定に使用されているからです。

組み込み関数

Checker Studio は、C/C++ の組み込み関数のリストを提供します。リストを表示するには、次の手順に従います。

  1. Checker Studio を起動します。
  2. [ヘルプ] > [ヘルプトピック] > [KAST リファレンス] > [C/C++ KAST 組み込み関数] に移動します。

    組み込み関数がアルファベット順にリストされます。

関数の最初の引数は 'ドット' 表記を使用して指定できます。条件を参照してください。

関連する概念

条件を参照してください。

C/C++ カスタム関数

カスタム関数により KAST チェッカーを作成するプロセスについては、チュートリアル 3 - カスタム関数を使用した C/C++ KAST チェッカーの作成で説明しています。

チェッカーの性能

祖先/子孫 (または親/子) 指定子を 1 つの KAST 式で使用する KAST チェッカーでは、解析速度が大幅に落ちます。

祖先ノードは、AST のルートまでの "上昇" をトリガし、指定された名前のすべての定義の検索を試みますが、子孫ノードはサブツリーの完全なトラバーサルをトリガします。

解析結果を迅速に出すためには、祖先/子孫または親/子の組み合わせの使用を避けることが最も効果的です。

C/C++ KAST チェッカーの場合は、セマンティック情報で使用できるカスタム関数を作成してみてください。AST のトランスバースよりも効果的です。たとえば、関数 'ktc_sema_findAllByName(scope, name)' を使用すると、指定の名前を持ち、C/C++ プログラムの特定の時点で表示されるすべての関数/変数/タイプのリストを取得できます。