可以对代码进行反编译的典型方法是什么?目前,我正在编写一种简单的编程语言,并且它的处理方式是递归的。循环的节点列表,并说当前节点是一个变量节点,它将调用emit_variable_node
函数,它将字符串附加到字符串,例如:
以下代码是psuedo-ish,我在C中编写项目,并编译为C.
char *file_contents;
void emit_variable_node(VariableNode *var) {
// I know += doesn't work on strings, just pretend it does.
file_contents += var.getType();
file_contents += " "; // a space
file_contents += var.getName();
// etc
}
我还假设我们给出的代码已经过语义分析,并且是正确的。然后将file_contents字符串存储到临时文件中,该文件在由C编译器编译后删除。
这是一种不好的做法,还是有更好,更清洁的方法来做到这一点?
答案 0 :(得分:5)
您可以通过任何方式编写解析器,并在解析时生成代码,不需要AST节点(“语法定向转换”)。这通常会产生非常糟糕的代码,因为代码生成器没有机会将上下文考虑在内以生成更好的代码。
您可以构建一个构建抽象语法树(AST)作为第一遍的解析器,然后在第二遍传递树生成代码而不查看任何相邻节点。这只是其中ASTs的前一个答案。 这是stunningly bad example of unoptimized transpiler output完成这样的事情。
更好的是从AST生成代码,其中每个AST节点本地代码生成器检查其邻居,以决定做什么。这将为您提供更好的代码。
更好的解决方案是遵循传统编译器的主导,为您的语言构建良好的前端,包括符号表和控制以及数据流分析。然后,您可以使用它来生成更好的代码。
关于实际代码生成:是的,您可以打印文本字符串。字符串模板更方便一些,但它们只是打印文本字符串的一种奇特方式,因此它们不会增加任何功能或提高生成的代码质量。
更好的解决方案是将源语言中的AST转换为目标语言中的AST,包括所有本地检查,并使用符号表和流分析中的信息。这样做的好处是,通过在目标语言中生成AST,您现在可以在目标语言中应用源语言中无法实现的优化。 [真正的编译器会做这样的事情,但是他们使用的术语是“将AST转换为IR(内部表示)”并且他们在IR上进行优化。]在目标AST的所有优化完成后,你必须漂亮地打印最终的AST ...使用类似字符串模板的东西。
大多数人没有精力从头开始构建一个好的转换器。所以他们做了一些像第一个建议(只是说')的hacky事情。但是,如果您想要将代码从一种语言转换为另一种语言,那么请查看我们的DMS Software Reengineering Toolkit。 DMS具有多种语言的解析器,可以实现自定义语言的解析器,自动构建AST,为Life After Parsing提供大量支持,例如,构建符号表和流分析,进行AST到AST转换,并且具有漂亮的打印机。 DMS is designed to be a platform to support this kind of task。这意味着您可以专注于构建任务的高质量翻译部分,而不是尝试构建所有有用的基础架构。