ROSE 編譯器框架/程式翻譯
ROSE 擁有高階中間表示,適合構建源到源的翻譯器。這可以透過重新構建輸入原始碼的 AST,然後將轉換後的 AST 反解析到輸出原始碼來實現。
官方教程: 第 32 章 ROSE 教程 的 AST 構造
許多初學者的疑問在閱讀完本章後應該可以得到解答。
列表
- 程式碼生成: 程式碼片段(基於 SageBuilder 函式)、CUDA、PolyOpt、MPI、向量化等。
- 迴圈轉換: 交換、平鋪、展開、摺疊等。
- 內聯: 請參見 ROSE 編譯器框架/內聯器
- 外聯: 請參見 ROSE 編譯器框架/外聯器
- AutoPar,
- 自動調整(程式碼變體)等。
使用 ROSE 構建的翻譯器被設計為像編譯器一樣(gcc、g++、gfortran 等,具體取決於輸入檔案型別)。
因此,翻譯器的使用者只需要更改輸入檔案的構建系統,就可以使用翻譯器代替原始編譯器。
主要文章位於 ROSE 編譯器框架/處理編譯指示
使用編譯指示來指導翻譯器通常很有用。
提供了一組解析器構建函式來幫助建立遞迴下降解析器
一旦您包含了標頭檔案 AstFromString.h(位於 src/frontend/SageIII/astFromString 中),您就可以訪問名稱空間中定義的變數和函式。
有一個示例專案正在進行編譯指示解析,並將結果儲存到 AST 屬性中。 https://github.com/rose-compiler/rose-develop/tree/master/projects/pragmaParsing
重構/構造 AST 的官方指南強烈建議使用 SageBuilder 和 SageInterface 名稱空間中的輔助函式來建立 AST 部分並將其移動。這些輔助函式嘗試在低級別更改中保持穩定,並足夠智慧,可以透明地設定許多邊緣並維護符號表。
希望擁有更低級別控制的使用者可能希望直接呼叫 AST 節點和符號表的成員函式來顯式地操作 AST 中的邊緣和符號。但這個過程非常繁瑣且容易出錯。
可能某些構建器函式尚未提供,尤其是對於 C++ 結構,例如模板宣告等。我們正在積極地解決這個問題。在此期間,您可以直接使用 new 運算子和其他成員函式作為變通方法。
準備翻譯器的輸出
- 準備一個最簡單的原始檔 (b.c) 作為翻譯器的示例輸出
- 避免包含任何系統標頭檔案
- 使用 ROSE_INSTALLATION_TREE/bin/dotGeneratorWholeASTGraph 為 b.c 生成完整的 AST,有關視覺化 AST 的更多詳細資訊,請參見 如何視覺化 AST。
- 研究 AST 節點型別及其父子關係的點圖。
- 使用 SageInterface 或 SageBuilder 函式來重構源 AST 圖,使其成為您想要生成的 AST 圖
- 如果沒有 SageBuilder 函式可以建立您想要的內容。您可能必須使用 new 運算子建立節點,並自行處理邊緣和符號。
更多詳細資訊,請參見 如何建立一個翻譯器
簡單的先序遍歷不適合構建翻譯器,因為翻譯器可能會更改遍歷預期稍後訪問的節點。從概念上講,這本質上與 C++ 迭代器失效類似。
為了安全地轉換 AST,建議使用由先序遍歷生成的語句列表的反向迭代器。這與由後序遍歷生成的列表不同。
例如,假設我們有一個子樹:parent <child 1, child 2>,
- 先序遍歷將生成一個列表:parent, child 1, child2
- 後序遍歷將生成一個列表:child 1, child 2, parent。
- 先序遍歷的反向迭代器將為您提供:child2, child 1 和 parent。根據我們的經驗,使用此順序進行轉換是最安全的。
在 https://github.com/rose-compiler/rose/tree/master/tests/roseTests/astInterfaceTests 下有很多測試翻譯器
其他示例
- 將一個複雜語句拆分成多個簡單的語句:ROSE/projects/backstroke/ExtractFunctionArguments.C
請參見 轉換跟蹤
用於精確定位原始碼結構的字串。對於將迴圈、函式等傳遞給翻譯器以進行處理很有用,更多內容請參見
斷言失敗: (expr->get_startOfConstruct() != NULL), 函式 unparseExpression,檔案 ../../../ROSE/src/backend/unparser/languageIndependenceSupport/unparseLanguageIndependentConstructs.C,第 812 行。
void visitorTraversal::visit(SgNode* sgn){
SageBuilder::pushScopeStack(body);
SgAssignOp* sao = isSgAssignOp(sgn);
if(!sao)
return;
SgVarRefExp* svr = SageBuilder::buildVarRefExp("mami");
SgIntVal* siv = SageBuilder::buildIntVal(33);
SgAssignOp* newsao = new SgAssignOp(svr, siv, NULL);
SageInterface::replaceWithPattern(sao, newsao);
SageBuilder::popScopeStack();
}
原因是: SgAssignOp* newsao = new SgAssignOp(svr, siv, NULL);
expr->get_startOfConstruct() != NULL 表明沒有起始檔案位置。SageBuilder 中有一個現有的函式可以構建 Assign Op 並處理許多細節,包括檔案資訊物件。否則,如果使用原始 new 運算子,則需要自己維護這些細節。