您只需要一个对源语言的所有语义细节进行建模的 AST。根据定义,如果它确实对语义进行了正确建模,并且您的语言包含三元运算符,那么它也将正确地对应用运算符的特定顺序进行建模(例如,前置模数覆盖的结果,如括号)。
所以你的问题不在 AST 中。它使用优先级不同的类似(三元)运算符生成另一种语言。
这是代码生成中的一个古老问题:目标的运算符与源的运算符不完全匹配,因此输出不能是一对一的。在您的情况下,您应该能够通过生成带有括号的 PHP 三元运算符来控制顺序以实现原始语义,因此这不是一个大问题。
通常,生成实现预期结果的代码序列可能非常复杂,并且有很多方法可以做到这一点。这就是编译器书籍厚而不是薄的原因。您似乎已经隐含地选择了“获取 AST,步行 AST,吐出代码”;这几乎是一个即时代码生成器。如果您不关心生成的代码是否特别好,并且目标语言与源语言非常接近,那么这种方法就足够了。
如果代码生成问题更复杂,通常发生的情况是 AST 用于生成相当于计算的数据流模型,由产生结果的算子组成,并使用先前算子的结果,以“算子”为基础获取变量值和常量。然后遍历数据流表示生成代码;这样做的好处是您可以在数据流表示中选择一个运算符,在目标语言中找到一个匹配的代码序列,生成它,然后担心如何收集操作数。更好的方案将数据流子图(表示等效的复合目标语言结构)与生成的数据流图相匹配;这可以产生明显更好的代码。经常,可以在原始代码生成之后应用目标语言特定的优化来生成更好的代码。在这两种情况下,您都必须担心管理运算符结果;它们可以直接提供给下一个目标语言运算符,还是必须进入某种临时存储(对于机器代码,这可以是另一个寄存器或内存位置)。做这一切并不容易;同样,这就是编译器书籍不薄的原因。
这个想法的一个变体是源到源的程序转换。这会将源代码中的构造“直接”映射到目标代码中的构造,尽管这通常是通过在 AST 上操作在幕后完成的,因为未解析的编程语言文本很难匹配。我们的DMS 软件再造工具包就是这种系统的一个例子。使用这样的工具,您可以在源语言中编写模式(隐式匹配解析树),并在目标语言中编写相应的模式(隐式生成目标语言 AST)。您可以编写复杂的源或目标结构,以提供上述数据流图匹配的大部分效果。生成后优化包含更多将目标代码转换为目标代码的重写规则。
底线:除非您的翻译真的很琐碎,否则拥有 AST 是不够的。您可以在这个 SO 答案中阅读更多关于您需要什么的信息:https ://stackoverflow.com/a/3460977/120163
警告:大声的意见随之而来。
关于“转码器”:我更喜欢术语“编译”、“翻译”或“源到源”编译器。近 40 年来,我一直在构建程序分析和操作工具。在遇到这个 SO 问题之前,我从未听说过“转码器”一词:体验将遗留 Cobol/PL1 迁移到 Java 以及描述恕我直言的一个真正糟糕的代码翻译方案,称为 NACA。我听说这个词越来越受欢迎。我不明白为什么当我们有完全合适的术语时我们必须发明另一个术语。通常这是有人发明大祭司的标志;“让我们发明一个闪亮的新术语,这样人们就不会真正理解我们在做什么”。一世'