跳转到内容

ROSE 编译器框架/程序翻译

来自维基教科书,自由的教科书

ROSE 拥有高级中间表示,适合构建源到源的翻译器。这可以通过重新构建输入源代码的 AST,然后将转换后的 AST 反解析到输出源代码来实现。

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

许多初学者的疑问在阅读完本章后应该可以得到解答。

翻译列表

[编辑 | 编辑源代码]

列表

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 运算符,则需要自己维护这些细节。

华夏公益教科书