跳轉到內容

ROSE 編譯器框架/程式翻譯

來自華夏公益教科書,自由的教科書

ROSE 擁有高階中間表示,適合構建源到源的翻譯器。這可以透過重新構建輸入原始碼的 AST,然後將轉換後的 AST 反解析到輸出原始碼來實現。

官方教程: 第 32 章 ROSE 教程 的 AST 構造

許多初學者的疑問在閱讀完本章後應該可以得到解答。

翻譯列表

[編輯 | 編輯原始碼]

列表

  • 程式碼生成: 程式碼片段(基於 SageBuilder 函式)、CUDA、PolyOpt、MPI、向量化等。
  • 迴圈轉換: 交換、平鋪、展開、摺疊等。
  • 內聯: 請參見 ROSE 編譯器框架/內聯器
  • 外聯: 請參見 ROSE 編譯器框架/外聯器
  • AutoPar,
  • 自動調整(程式碼變體)等。

ROSE 翻譯器的預期行為

[編輯 | 編輯原始碼]

使用 ROSE 構建的翻譯器被設計為像編譯器一樣(gcc、g++、gfortran 等,具體取決於輸入檔案型別)。

因此,翻譯器的使用者只需要更改輸入檔案的構建系統,就可以使用翻譯器代替原始編譯器。

處理編譯指示

[編輯 | 編輯原始碼]

主要文章位於 ROSE 編譯器框架/處理編譯指示

使用編譯指示來指導翻譯器通常很有用。

提供了一組解析器構建函式來幫助建立遞迴下降解析器

一旦您包含了標頭檔案 AstFromString.h(位於 src/frontend/SageIII/astFromString 中),您就可以訪問名稱空間中定義的變數和函式。

有一個示例專案正在進行編譯指示解析,並將結果儲存到 AST 屬性中。 https://github.com/rose-compiler/rose-develop/tree/master/projects/pragmaParsing

SageBuilder 和 SageInterface

[編輯 | 編輯原始碼]

重構/構造 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 運算子建立節點,並自行處理邊緣和符號。

更多詳細資訊,請參見 如何建立一個翻譯器

遍歷 AST 的順序

[編輯 | 編輯原始碼]

簡單的先序遍歷不適合構建翻譯器,因為翻譯器可能會更改遍歷預期稍後訪問的節點。從概念上講,這本質上與 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)

[編輯 | 編輯原始碼]

斷言失敗: (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 運算子,則需要自己維護這些細節。

華夏公益教科書