跳轉到內容

ROSE 編譯器框架/AST 匹配

來自華夏公益教科書,自由的教科書,為一個開放的世界

AST 匹配機制

  • rose/src/midend/astMatching

以下文件位於以下檔案(但尚未完成,並且不會顯示在 doxygen 中)

  • rose/src/midend/astMatching/AstMatching.docs

這些示例很好地概述了您可以使用匹配器執行的操作。請注意,它使用自己的解析器並實現了自己的規範語言來指定匹配表示式(具有許多不同的運算子)。匹配器是在 AST 迭代器之上實現的 - 因此,匹配器是迭代器的一個用例。

AstMatching 機制允許指定任意大的模式,以便在 AST 中的任何子樹上進行匹配。這些模式以字串形式指定,並且可以使用 AST 節點的型別名稱來指定 AST 模式。此外,還提供變數和一些運算子,以允許指定複雜的模式。也可以使用 '_' 忽略匹配中的子樹。二元運算子 '|' 允許將不同的匹配子表示式組合成一個表示式。變數用於指定儲存在匹配結果中的已匹配子樹的指標,以便使用者進一步處理。

在下面的示例中,我們匹配兩邊都有變數的賦值,例如 x=y,並將結果分配給變數 $R。

 
#include "rose.h"   
#include "AstTerm.h"
#include "AstMatching.h"
   
AstMatching m;
MatchResult res=m.performMatching("$R=SgAssignOp(SgVarRef,SgVarRef)",astRoot);

其中 'astRoot' 是指向 AST 中某個節點的指標。AssignOp 和 SgVarRef 是 ROSE AST 節點的名稱,$R 是匹配器變數的名稱。

在上面的示例中,將匹配所有表示具有兩個變數作為運算元的賦值操作的子樹。美元符號表示變數。在上面的示例中,指向已匹配子樹的指標被分配給變數 $R。所有已匹配賦值的結果儲存在型別為 AstMatchingResult 的變數 res 中。匹配結果是一組對映,其中每個對映代表一次成功匹配的結果,幷包含變數名稱和指向相應 AST 子樹的指標對。

變數用作鍵來儲存/檢索結果中已匹配的子樹。可以隨意使用多個變數(鍵),並且支援兩種使用形式。變數以引導美元符號和任意數量的字母和下劃線(單個下劃線用作萬用字元)表示。可以使用變數賦值符號將指定模式的指標分配給變數。

變數的示例使用

[編輯 | 編輯原始碼]

例如,$R=SgAssignOp(SgVarRef,_,_) 與所有在左側具有變數並在右側具有某些表示式的賦值匹配。


或者,我們也可以使用 $R=SgAssignOp($X=SgVarRef,$Y=_) - 在這種情況下,我們還將指向已匹配變數節點的指標和指向 rhs 上表達式的指標儲存在匹配結果中。


對於表示式 $Y=_,我們也可以簡單地將其寫為 $Y 作為簡寫,因此我們也可以使用 $R=SgAssignOp($X=SgVarRef,$Y) 代替。不允許將變數分配給變數,例如 $Z=$Y。

忽略子樹(萬用字元 '_')

[編輯 | 編輯原始碼]

也可以使用匹配表示式中的 '_' 指定忽略子樹進行匹配。例如,如果我們使用 SgAssignOp(_,_),我們可以匹配 AST 中的所有賦值節點,但忽略表示 rhs 和 lhs 的 AST 的結構。

可以透過在匹配表示式中使用“null”顯式匹配空值。例如,$X=SgForStatement(_,_,_,_,null) 將匹配所有第五個引數為 0 的 SgForStatement 項。

運算子

[編輯 | 編輯原始碼]

跳過子樹運算子 '#'

[編輯 | 編輯原始碼]

在匹配表示式中放置運算子 '#' 允許從後續匹配中排除任意子樹,以便對匹配操作進行應用。即,標記的子樹不會被遍歷。例如,如果我們只想匹配最外層的 for 語句,而不是巢狀的 for 語句,我們可以使用

   $FOR=SgForStatement(_,_,_,#_,..)

這僅匹配外部 for 語句,因為主體(第四個引數)被排除在應用匹配運算子之外。如果沒有 '#',我們也會匹配內部迴圈。

任意引數運算子 '..'

[編輯 | 編輯原始碼]

此運算子可以在匹配表示式中使用,以指定可以跟隨任意數量的引數。例如,我們可以使用 SgBlock($First,..) 來匹配 SgBlock 中的第一條語句。由於 SgBlock 可以具有任意元數,因此在這方面非常有用。運算子 '..' 在指定節點的元數時最多隻能使用一次,但在匹配模式中可以任意多次使用,例如 SgBlock(SgForStatement($Cond,..),..) 是可以的,但 SgBlock(_,..,_,..) 是不行的。

或運算子 '|'

[編輯 | 編輯原始碼]

此運算子允許組合多個匹配表示式。例如,“SgAddOp($L,$R)|SgSubOp($L,$R)”將匹配 SgAddOp 並將指向其兩個子節點的指標繫結到 $L 和 $R,或者它將匹配 SgSubOp。運算子 '|' 執行短路計算,因此,匹配是從左到右執行的,並且只要其中一個模式可以成功匹配,匹配就會停止。

使用頂層單個變數

[編輯 | 編輯原始碼]
  • performMatching("$R=AssignOp(_,_)",astRoot);
 Match all assignment operators in an AST.
  • performMatching("$R=SgAssignOp(SgVarRefExp,SgIntVal)",astRoot);
 Match all assignment operators with a variable on the lhs and an integer value on the rhs.
  • performMatching("$FORROOT=SgForStatement(_,_,_,#_)",astRoot);
 Match all outer most for loops, but no nested for-loops. The operator '#' ensures that the match expression is not applied on the AST representing the body of the for-statement (4th argument). The pointer to the root of the AST representing the for-loop is bound to $FORROOT.
  • performMatching("$N=_(null)",astRoot);
 Match all nodes with arity 1 and a single null value. The main purpose for such match-expressions is to perform consistency checks in the AST.
  • performMatching("$N=SgInitializedName(null)",astRoot); // 預設ROSE AST中存在許多這樣的節點
 Specifically match all SgInitializedName nodes with a null pointer.

使用多個變數

[編輯 | 編輯原始碼]

變數可以巢狀在模式內部。如果不需要,頂級模式不需要變數。

  • performMatching("SgForStatement($LoopCond,_,_,_)|SgWhile($LoopCond,_)|SgDoWhile(_,$LoopCond)",astRoot);
 Match different Loop constructs and bind variable $LoopCond to the respective loop condition.
  • performMatching("SgAssignOp(SgVarRef,SgAddOp($X,$Y))",astRoot)
 Match assignments with a variable on the rhs and an add-operator on the rhs(root). The pointers to the sub-ASTs representing the lhs and rhs of the add-operator are bound to variables $X and $Y for each match in the AST:
  • performMatching("$Func=SgFunctionCallExp($FuncRef,$Params)",astRoot)
 Match all function calls and bind variable $Func to the root of each such expression, bind $FuncRef to the SgFunctionRefExp (which can be used to obtain the name) and $Params to the AST representing the parameters:

匹配迴圈增量表達式

[編輯 | 編輯原始碼]
#include "AstTerm.h"
#include "AstMatching.h"

    AstMatching m;

     
  // match i++
   MatchResult res=m.performMatching("SgForStatement(_,_,SgPlusPlusOp($I=SgVarRefExp),..)",forloop);
  // match i++ or i==   
  // MatchResult res=m.performMatching("SgForStatement(_,_,SgPlusPlusOp($I=SgVarRefExp)|SgMinusMinusOp($I=SgVarRefExp),..)",forloop);

//    cout<<res.size()<<endl;
    for(MatchResult::iterator i=res.begin();i!=res.end();++i) {
      // obtain the result:each variable is a map
       SgVarRefExp* ivar = isSgVarRefExp( (*i)["$I"]);
       cout<<"var:"<< ivar->unparseToString()<<endl;
    }
[編輯 | 編輯原始碼]

通常,對於給定的子樹,不清楚應該使用哪種模式字串。在這種情況下,您可以先找到其根節點,並使用AstTerm::astTermWithNullValuesToString() 打印出一個模式字串。

  #include "AstTerm.h"
  // check if this is within auto kernel = ...; 
  SgStatement* stmt = SageInterface::getEnclosingStatement(exp);
  AstMatching m;
  MatchResult r =m.performMatching ("$L=SgVariableDeclaration", stmt);
  for(MatchResult::iterator i=r.begin();i!=r.end();++i) {
     SgVariableDeclaration* i1 = isSgVariableDeclaration((*i)["$L"]);
     cout<< AstTerm::astTermWithNullValuesToString(i1)<<endl;
  }

一些示例輸出可能如下所示


"SgAggregateInitializer(SgExprListExp(SgDesignatedInitializer(SgExprListExp(SgAdaOthersExp:others),SgAssignInitializer(SgAggregateInitializer(SgExprListExp(SgDesignatedInitializer(SgExprListExp(SgAdaOthersExp:others),SgAssignInitializer(SgLongDoubleVal:2.0))))))))"


請注意,您不應該直接複製貼上輸出字串作為匹配模式。您需要刪除表示式中的:value 部分。

例如:(SgLongDoubleVal:2.0) 應該變成 (SgLongDoubleVal)


有一個專門的翻譯器來轉儲輸入檔案的 AST 項

  • exampleTranslators/defaultTranslator/astTermGenerator.C

訪問匹配結果

[編輯 | 編輯原始碼]

結果收集在 std::list of std::maps 中。每個 map 代表 AST 中一個位置的一次成功匹配,幷包含所有繫結變數。可以使用名稱和隨機訪問運算子訪問變數。列表中的元素數量(= maps)對應於 AST 中匹配模式的數量。

typedef std::map<std::string,SgNode*> SingleMatchVarBindings;
typedef std::list<SingleMatchVarBindings> MatchResult;


可以按如下方式訪問 AST 中匹配模式的指標

    /* 1 */ AstMatching m;
    /* 2 */ MatchResult res=m.performMatching("$R=SgInitializedName($X)",root);
    /* 3 */ std::cout << "Number of matched patterns: " << r.size() << std::endl;
    /* 4 */ for(MatchResult::iterator i=r.begin();i!=r.end();++i) {
    /* 5 */   cout<<"Match expression variable $R:"<<isSgLocatedNode((*i)["R"])->unparseToString()<<endl;
    /* 6 */   cout<<"Match expression variable $X:"<<isSgLocatedNode((*i)["R"])->unparseToString()<<endl;
    /* 7 */ }

在第 1 行建立了 AstMatching 物件。在第 2 行,將匹配表示式和 AST 的根節點提供給匹配機制,並計算結果。匹配可以在任何感興趣的 AST 子樹上執行,方法是在開始匹配操作時讓 'root' 指向相應的 AST 子樹。在第 3 行列印匹配模式的數量。在第 4-7 行訪問變數 $R 變數 $X,並使用 unparseToString 函式解析相應的匹配 AST 子樹。匹配變數 $R 和 $X 的指標值引用成功匹配 AST 子樹的根節點。

以下是一個更詳細的程式碼示例,用於在整個 ROSE AST 上執行一次匹配操作,並使用迭代器列印所有匹配結果中的 map

#include "AstTerm.h"    
#include "AstMatching.h"

    // Fragment from the matcher_demo program
    AstMatching m;
    MatchResult r=m.performMatching("$R=SgInitializedName(_)",root);
    // print result in readable form for demo purposes
    std::cout << "Number of matched patterns: " << r.size() << std::endl;

// for each matched instance
    for(MatchResult::iterator i=r.begin();i!=r.end();++i) {
      std::cout << "MATCH: \n";

     // obtain the map  
     SingleMatchVarBindings& dict=(*i);
     SgNode* matched_op = dict["$R"] ; // retrieve the node by its key/variable 

      // Alternatively, iterate through all entries in the map.
      // for each variable in the matched instance
      for(SingleMatchVarBindings::iterator vars_iter=(*i).begin();vars_iter!=(*i).end();++vars_iter) {
        SgNode* matchedTerm=(*vars_iter).second;
        std::cout << "  VAR: " << (*vars_iter).first << "=" << AstTerm::astTermWithNullValuesToString(matchedTerm) << " @" << matchedTerm << std::endl;
       }
       std::cout << std::endl;
     }

變數 matchedTerm 被賦予指向與變數繫結的相應 ROSE AST 節點的指標。(*vars_iter).first 是呼叫 performMatching 時匹配表示式中使用的變數的名稱。在本例中,它們是 $R、$X 和 $Y。generateAstTerm 函式是一個輔助函式,用於以可讀的形式在 stdout 上列印 AST。它使用與匹配機制相同的 Ast::iterator_with_null 實現。

示例輸出

    MATCH:
      VAR: $R=SgInitializedName(null) @0x7f1f8914da00

    MATCH:
      VAR: $R=SgInitializedName(null) @0x7f1f8914db28

    MATCH:
      VAR: $R=SgInitializedName(SgAssignInitializer(SgIntVal)) @0x7f1f8914dc50

    MATCH:
      VAR: $R=SgInitializedName(null) @0x7f1f8914dd78

    MATCH:
      VAR: $R=SgInitializedName(null) @0x7f1f8914dea0

    MATCH:
      VAR: $R=SgInitializedName(SgAssignInitializer(SgIntVal)) @0x7f1f8914dfc8

華夏公益教科書