代码生成期间的宏替换

时间:2008-11-14 15:34:07

标签: c++ compiler-construction macros

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

3 个答案:

答案 0 :(得分: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(以及它们更现代的变体)这样的程序可以愉快地生成代码。

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

答案 1 :(得分:0)

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

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

int c = a + b

结束宏

//程序总和

...

int x = 10,y = 10;

添加(x,y);

...

//程序结束

更换后将是

//程序总和

...

int x = 10,y = 10;

int c = x + y

...

//程序结束

这个文本替换需要花费很多时间,即用宏逻辑替换宏调用。 有最佳方​​法吗?

答案 2 :(得分:0)

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

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