我正在尝试将给定 cfg 之后的表达式的语法定向翻译的语义规则编写为 3 个代码表示形式。
考虑,
在这里,为什么是|| 需要操作员?gen() 似乎是唯一需要的东西,因为它做了需要做的事情。
我正在尝试将给定 cfg 之后的表达式的语法定向翻译的语义规则编写为 3 个代码表示形式。
考虑,
在这里,为什么是|| 需要操作员?gen() 似乎是唯一需要的东西,因为它做了需要做的事情。
这组规则描述了一种属性语法,一种用于计算树属性的方案。这样的方案几乎总是纯粹的功能性(没有副作用)。它在每个规则/树节点上计算属性,在它们使用的符号中命名为 XY,其中 X 代表规则/树(例如,具有变体 E1 和 E2 的 S 和 E。Y 代表计算的属性(在这种情况下,有“代码”和“地点”属性。
每个规则对应一个子树,E = E1 + E2 对应于 S 表达式表示法中的树 (E+ E1 E2)。“E.code:=...”表示计算“...”并将结果分配给“E(+)”树根的属性“code”(“综合”属性);“E1.code:=...”表示计算“...”并分配给“E1”叶(“继承属性”)。不在赋值左侧的“XY”表示“获取节点 X 上属性 Y 的值”。
使用的计算是“newtemp”(这实际上应该是“newtemp()”,因为它不是一个变量,而是一个函数)、“gen(...)”和“||”。“gen”显然是在做制造个别指令的关键工作。但它的结果是什么?一个简单的答案是“一个字符串”;更复杂的答案可能是生成指令的二进制表示。
“||”的目的 是将代码生成步骤的结果组装成生成的代码流;如果生成结果是一个字符串,“||” 可以是一个字符串连接,如果结果是一个二进制记录,它将二进制记录的列表连接成一个列表。
您可能会因为认为“gen”只是产生它的结果并将它们写入一个未提及的输出流而感到困惑。这将违反不允许这样的属性语法的精神。“||” 需要运算符来计算向上传递树的功能结果。
您可能会弯曲属性语法,因此 gen确实写入隐藏流。在那种情况下,所有的“||” 运算符消失了,之前计算的结果(例如“E1.code”)的提及也消失了。如果您的属性树评估是从左到右(一个大的)并且,当严格从左到右完成时,生成的子树组合以产生结果流的顺序是正确的,则您可以进行这项工作。如果属性语法说“E.code = E2.code || E1.code || gen(...)”,也就是说,它正在对生成的代码进行重新排序,那么隐藏输出流技巧将不起作用。
换个角度看:假设您想在大型程序上快速评估此属性语法。如果您坚持纯函数语法,那么您可以并行评估所有属性!您使用递归过程为每个孩子分叉 helper grain。[听起来很疯狂?不是,我有一个属性评估系统(请参阅我的简历),它完全按照这个原则工作]。在这种情况下,隐藏的输出流也不起作用,因为并行性可能会导致以任何顺序访问子级。