如何从gcc c c代码构建ast(抽象语法树),以便进行如下转换,然后再次将代码复制(生成)为c语法?
if(condition_1){
//lines of code 1
}
#ifdef expression_1
else if(condition_2){
//lines of code 2
}
#endif
进入之内
bool test = condition_1;
if(teste){
//lines of code 1
}
#ifdef expression_1
if(!(test) && condition_2){
//lines of code 2
}
#endif
最佳答案
gcc本身将构建ast,但在扩展预处理器指令之前不会。所以预处理器条件就不存在了。完成转换后重新安装它们将非常困难。做涉及条件句本身的转换是不可能的。
因此gcc本身并不是获得所需ast的好方法。
如果你想解析你的代码示例(else if的条件非常好!),您需要重新设计解析器。这些是为支持重构而设计的解析器。这样的解析器需要捕获比传统解析器更多的内容,例如令牌的列号、词条的格式等,以便能够从修改后的树中再生源文本。对于C,这样的解析器也必须捕获预处理器指令。这些很少见。
其中一个这样的重组解析器是我们的dms软件重组工具包及其c前端,它处理c语言的许多方言,包括gcc 2/3/4/5。它被显式地设计为捕获预处理器条件(包括您的特定示例)。dms还支持使用源到源转换来执行转换。
对于更改为合法版本的OP示例,请置于test.c中:
void main () {
if (condition_1) {
x++;
}
#ifdef expression_1
else if (condition_2) {
y++;
}
#endif
}
…dms c~gcc4解析器(开箱即用)生成以下ast:
C:\DMS\Domains\C\GCC4\Tools\Parser\Source>run ..\domainparser ++AST C:\temp\test.c
C~GCC4 Domain Parser Version 3.0.1(28449)
Copyright (C) 1996-2015 Semantic Designs, Inc; All Rights Reserved; SD Confidential
Powered by DMS (R) Software Reengineering Toolkit
AST Optimizations: remove constant tokens, remove unary productions, compact sequences
Using encoding Unicode-UTF-8?ANSI +CRLF +1 /^I
28 tree nodes in tree.
(translation_unit@C~GCC4=2#3cde920^0 Line 1 Column 1 File C:/temp/test.c
(function_definition@C~GCC4=966#3cde740^1#3cde920:1 Line 1 Column 1 File C:/temp/test.c
(function_head@C~GCC4=967#3047320^1#3cde740:1 Line 1 Column 1 File C:/temp/test.c
(simple_type_specifier@C~GCC4=686#3047180^1#3047320:1 Line 1 Column 1 File C:/temp/test.c)simple_type_specifier
(direct_declarator@C~GCC4=852#3047380^1#3047320:2 Line 1 Column 6 File C:/temp/test.c
|(IDENTIFIER@C~GCC4=1531#3047160^1#3047380:1[`main'] Line 1 Column 6 File C:/temp/test.c)IDENTIFIER
|(parameter_declaration_clause@C~GCC4=900#30473c0^1#3047380:2 Line 1 Column 12 File C:/temp/test.c)parameter_declaration_clause
)direct_declarator#3047380
)function_head#3047320
(compound_statement@C~GCC4=507#3cde1e0^1#3cde740:2 Line 1 Column 14 File C:/temp/test.c
(selection_statement@C~GCC4=539#3cde940^1#3cde1e0:1 Line 2 Column 3 File C:/temp/test.c
|(if_head@C~GCC4=550#30476e0^1#3cde940:1 Line 2 Column 3 File C:/temp/test.c
| (IDENTIFIER@C~GCC4=1531#30473e0^1#30476e0:1[`condition_1'] Line 2 Column 7 File C:/temp/test.c)IDENTIFIER
|)if_head#30476e0
|(compound_statement@C~GCC4=507#3cde700^1#3cde940:2 Line 2 Column 20 File C:/temp/test.c
| (expression_statement@C~GCC4=503#3047740^1#3cde700:1 Line 3 Column 6 File C:/temp/test.c
| (postfix_expression@C~GCC4=205#3047720^1#3047740:1 Line 3 Column 6 File C:/temp/test.c
| (IDENTIFIER@C~GCC4=1531#3047700^1#3047720:1[`x'] Line 3 Column 6 File C:/temp/test.c)IDENTIFIER
| )postfix_expression#3047720
| )expression_statement#3047740
|)compound_statement#3cde700
|(if_directive@C~GCC4=1088#3cde7a0^1#3cde940:3 Line 5 Column 3 File C:/temp/test.c
| ('#'@C~GCC4=1548#3cde820^1#3cde7a0:1[Keyword:0] Line 5 Column 3 File C:/temp/test.c)'#'
| (IDENTIFIER@C~GCC4=1531#3cde1c0^1#3cde7a0:2[`expression_1'] Line 5 Column 10 File C:/temp/test.c)IDENTIFIER
| (new_line@C~GCC4=1578#3cde800^1#3cde7a0:3[Keyword:0] Line 5 Column 22 File C:/temp/test.c)new_line
|)if_directive#3cde7a0
|(selection_statement@C~GCC4=527#3cde840^1#3cde940:4 Line 6 Column 8 File C:/temp/test.c
| (IDENTIFIER@C~GCC4=1531#3047340^1#3cde840:1[`condition_2'] Line 6 Column 12 File C:/temp/test.c)IDENTIFIER
| (compound_statement@C~GCC4=507#3cde860^1#3cde840:2 Line 6 Column 25 File C:/temp/test.c
| (expression_statement@C~GCC4=503#3cde8a0^1#3cde860:1 Line 7 Column 12 File C:/temp/test.c
| (postfix_expression@C~GCC4=205#3cde880^1#3cde8a0:1 Line 7 Column 12 File C:/temp/test.c
| |(IDENTIFIER@C~GCC4=1531#3cde780^1#3cde880:1[`y'] Line 7 Column 12 File C:/temp/test.c)IDENTIFIER
| )postfix_expression#3cde880
| )expression_statement#3cde8a0
| )compound_statement#3cde860
|)selection_statement#3cde840
|(endif_directive@C~GCC4=1092#3cde8c0^1#3cde940:5 Line 9 Column 3 File C:/temp/test.c
| ('#'@C~GCC4=1548#3cde900^1#3cde8c0:1[Keyword:0] Line 9 Column 3 File C:/temp/test.c)'#'
| (new_line@C~GCC4=1578#3cde8e0^1#3cde8c0:2[Keyword:0] Line 9 Column 9 File C:/temp/test.c)new_line
|)endif_directive#3cde8c0
)selection_statement#3cde940
)compound_statement#3cde1e0
)function_definition#3cde740
)translation_unit#3cde920
编辑:op询问如何进行转换。如前所述,dms允许源到源的转换模式,其形式为“如果您看到了这个,请用那个替换它”,在被操作的目标语言的表面语法(在本例中,是gcc4版本的c)中说明。这种转换的价值在于,它们比通过过程调用完成的传统ast黑客代码更容易编写。
为了达到OP的效果,他需要进行以下DMS转换:
default domain C~GCC4; // tells DMS to use C domain with GCC4 dialect
rule transform_pp_conditional_else(c1: condition, c2: condition,
s1: statements, s2: statements,
pc1: preprocessor_condition):
statement -> statement
"if (\c1) { \s1 }
#ifdef \pc1
else if (\c2) { \s2 }
#endif"
->
"{ bool test=\c1;
if (test) { \s1 }
#ifdef \pc1
if (!test && \c2) { \s2 }
#endif
}"
默认域声明告诉dms以下规则适用于gcc4。在dms中,转换称为“规则”;它由子树类型参数化。元引号“…”用于区分DMS重写规则语法和C~GCC4语法。我想剩下的已经很清楚了。
关于c - 使用预处理器指令从C代码进行AST,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34502255/