转译成另一种语言
Transcompiling to another language
可以对代码进行转译的典型方式有哪些?目前,我正在编写一种简单的编程语言,它的处理方式是递归的。循环遍历一个节点列表,如果说当前节点是一个变量节点,它会调用一个emit_variable_node
函数,它会在字面上附加一些代码到一个字符串中,例如:
以下代码是伪代码,我正在用 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 编译器编译后被删除。
这是一种不好的做法,还是有更好、更清洁的方法来做到这一点?
您可以通过任何您喜欢的方式编写解析器,并在解析时生成代码,不需要 AST 节点 ("syntax directed translation")。这通常会产生非常糟糕的代码,因为代码生成器没有机会考虑上下文来生成更好的代码。
您可以构建一个解析器,该解析器构建抽象语法树 (AST) 作为第一遍,然后作为第二遍遍历树生成代码而不查看任何相邻节点。这只是其中包含 AST 的先前答案。
这是 stunningly bad example of unoptimized transpiler output 完成的类似操作。
更好的方法是从 AST 生成代码,其中每个 AST 节点本地代码生成器检查其邻居,以决定要做什么。这会给你更好的代码。
更好的解决方案是效仿传统编译器,为您的语言构建良好的前端,包括符号 table 以及控制和数据流分析。然后您可以使用它来生成更好的代码。
关于实际代码生成:是的,您可以打印文本字符串。字符串模板更方便一些,但它们只是打印文本字符串的一种奇特方式,因此它们不会增加任何功能或提高生成的代码质量。
更好的解决方案是将源语言的 AST 转换为目标语言的 AST,包括所有本地检查和使用来自符号 table 的信息和流分析。这样做的好处是,通过用目标语言生成 AST,您现在可以在目标语言中应用源语言中不可能的优化。 [真正的编译器做这样的事情,他们使用的 but 术语是 "translate AST to IR (internal representation)" 并且他们对 IR 进行优化。]在目标 AST 上的所有优化完成后,您必须漂亮地打印最终的 AST.. . 使用字符串模板之类的东西。
大多数人没有精力从头开始构建一个好的转译器。所以他们做了一些像第一个建议一样的骇人听闻的事情(只是说')。但是,如果您想要将代码从一种语言转换为另一种语言的良好基础,请查看我们的 DMS Software Reengineering Toolkit. DMS has parsers for many languages, can implement parsers for custom languages, automatically builds ASTs, provides a lot of support for Life After Parsing, e.g., building symbol tables and flow analysis, does AST to AST transformation, and has pretty printers. DMS is designed to be a platform to support this kind of task。这意味着您可以专注于构建任务的高质量翻译部分,而不是试图构建所有有用的基础结构。
可以对代码进行转译的典型方式有哪些?目前,我正在编写一种简单的编程语言,它的处理方式是递归的。循环遍历一个节点列表,如果说当前节点是一个变量节点,它会调用一个emit_variable_node
函数,它会在字面上附加一些代码到一个字符串中,例如:
以下代码是伪代码,我正在用 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 编译器编译后被删除。
这是一种不好的做法,还是有更好、更清洁的方法来做到这一点?
您可以通过任何您喜欢的方式编写解析器,并在解析时生成代码,不需要 AST 节点 ("syntax directed translation")。这通常会产生非常糟糕的代码,因为代码生成器没有机会考虑上下文来生成更好的代码。
您可以构建一个解析器,该解析器构建抽象语法树 (AST) 作为第一遍,然后作为第二遍遍历树生成代码而不查看任何相邻节点。这只是其中包含 AST 的先前答案。 这是 stunningly bad example of unoptimized transpiler output 完成的类似操作。
更好的方法是从 AST 生成代码,其中每个 AST 节点本地代码生成器检查其邻居,以决定要做什么。这会给你更好的代码。
更好的解决方案是效仿传统编译器,为您的语言构建良好的前端,包括符号 table 以及控制和数据流分析。然后您可以使用它来生成更好的代码。
关于实际代码生成:是的,您可以打印文本字符串。字符串模板更方便一些,但它们只是打印文本字符串的一种奇特方式,因此它们不会增加任何功能或提高生成的代码质量。
更好的解决方案是将源语言的 AST 转换为目标语言的 AST,包括所有本地检查和使用来自符号 table 的信息和流分析。这样做的好处是,通过用目标语言生成 AST,您现在可以在目标语言中应用源语言中不可能的优化。 [真正的编译器做这样的事情,他们使用的 but 术语是 "translate AST to IR (internal representation)" 并且他们对 IR 进行优化。]在目标 AST 上的所有优化完成后,您必须漂亮地打印最终的 AST.. . 使用字符串模板之类的东西。
大多数人没有精力从头开始构建一个好的转译器。所以他们做了一些像第一个建议一样的骇人听闻的事情(只是说')。但是,如果您想要将代码从一种语言转换为另一种语言的良好基础,请查看我们的 DMS Software Reengineering Toolkit. DMS has parsers for many languages, can implement parsers for custom languages, automatically builds ASTs, provides a lot of support for Life After Parsing, e.g., building symbol tables and flow analysis, does AST to AST transformation, and has pretty printers. DMS is designed to be a platform to support this kind of task。这意味着您可以专注于构建任务的高质量翻译部分,而不是试图构建所有有用的基础结构。