【问题标题】:Macro Replacement during Code Generation代码生成期间的宏替换
【发布时间】:2009-06-02 03:36:18
【问题描述】:

目前我有一些遗留代码,它会生成操作码。如果代码有更多数量的宏,那么代码生成会花费很多时间(以小时计!!)。 我已经完成了逻辑,他们通过搜索宏并替换其中的每个变量来处理宏,例如内联。
有没有一种方法可以在不操作字符串的情况下对其进行优化?

【问题讨论】:

  • 哈哈。你到底在说什么?什么宏,操作码和什么代码生成?什么字符串?
  • 你能举个例子让你的问题更容易理解吗?
  • 您使用的是什么编译器,或者您指的是一些内部预处理器?
  • 建议添加标签'compilers'、'compiler-theory',并使用这些标签检查其他问题。

标签: c++ compiler-construction macros


【解决方案1】:

在开始此类过程之前,您必须标记您的输入。 (我不能高度推荐著名的Dragon Book - 即使是古老的版本也经受住了时间的考验,2006 年的更新版本看起来很棒)。编译是最好分成更小的阶段的工作:如果您的第一阶段对标记执行词法分析,将行拆分为关键字、标识符、常量等,那么查找对宏的引用并查看它们要简单得多在符号表中。 (使用 lex 或 flex 之类的工具或它们的现代等效工具之一为您完成这项工作也相对容易,而不是尝试从头开始)。

“线索”似乎是如果代码有更多数量的宏,那么代码生成会花费很多时间。听起来这个过程在宏的数量上是线性的,这肯定太多了。我假设这个过程一次发生一行(如果您的语言允许,显然这具有巨大的价值,因为您不需要将程序视为一个巨大的字符串),并且伪代码看起来像

for(each line in the program)
{
    for(each macro definition)
    {
        test if the macro appears;
        perform replacement if needed;
    }
}

这显然与宏定义的数量成比例。

使用标记化,它看起来像这样:

for(each line in the program)
{
    tokenize the line;
    for(each token in the line)
    {
        switch(based on the token type)
        {
            case(an identifier)
                lookup the identifier in the table of macro names;
                perform replacement as necessary;
            ....
        }
    }
}

这主要与程序的大小(而不是定义的数量)有关 - 符号表查找当然可以使用比循环遍历它们更优化的数据结构来完成,因此不再成为重要因素。第二步是 yacc 和 bison(以及它们更现代的变体)等程序可以愉快地生成代码来做的事情。

事后思考:在解析宏定义时,您也可以将它们存储为令牌流,并标记为“占位符”名称的标识符以进行参数替换.扩展宏时,切换到该令牌流。 (同样,像 flex 这样的东西很容易做到)。

【讨论】:

    【解决方案2】:

    我有一个应用程序,它有自己的语法。它支持典型编译器支持的所有类型的数据类型(甚至宏)。更准确地说,它是一种编译器,它通过将程序(使用该语法编写)作为输入来生成操作码。 为了处理宏,它使用文本替换逻辑 例如:

    宏添加 (a:int, b:int)

    int c = a + b
    

    结束宏

    // 程序总和

    ..

    int x = 10, y = 10;

    加(x, y);

    ..

    //程序结束

    更换后会是

    // 程序总和

    ..

    int x = 10, y = 10;

    int c = x + y

    ..

    //程序结束

    此文本替换需要大量时间,即用宏逻辑替换宏调用。 有没有最佳的方法来做到这一点?

    【讨论】:

    • 如果您将整个文件放在 std::String 中,那么在大文件中替换宏需要时间也就不足为奇了。可能将每一行代码作为双端队列中的一个元素。替换是我想的更重要的因素
    【解决方案3】:

    如果不了解更多的预处理器/解析/编译过程,这真的很难回答。一种想法是将宏名称存储在符号表中。解析时,首先根据该表检查文本标记,如果找到匹配项,则将替换写入新字符串,并通过解析器运行,然后继续解析宏紧括号后的原始文本。

    根据您的操作码语法,另一个想法可能是 - 当您在解析时遇到宏定义时,生成操作码,但用占位符代替参数。然后,当解析器遇到对宏的调用时,生成用于评估参数的代码,并将该代码插入到预生成的宏代码中的占位符的位置。

    【讨论】:

    • 它进行了两次迭代。第一次迭代扫描宏并进行文本替换并构造树。在第二次迭代中,它通过将此树作为输入来生成操作码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    • 2014-08-04
    • 1970-01-01
    • 2022-08-15
    • 1970-01-01
    相关资源
    最近更新 更多