Compiler construction LL(1)语法是否需要通过条件跳转或非条件跳转的翻译来扩充?
考虑下面的语法Compiler construction LL(1)语法是否需要通过条件跳转或非条件跳转的翻译来扩充?,compiler-construction,Compiler Construction,考虑下面的语法 S -> for id:= E to E by E do S end S -> other E -> num 假设上述语法为LL(1),也为SLR(1) 在自底向上的解析器中,如《编译器原理与技术与工具》一书中的Pr.Alfred.Vho所述,我们在一次转换中使用额外的产生式规则(M->e)来扩充语法,例如,转换条件跳转和非条件跳转 S -> for id:= E M to E by E do S M end M S -> other E -&g
S -> for id:= E to E by E do S end
S -> other
E -> num
假设上述语法为LL(1)
,也为SLR(1)
在自底向上的解析器中,如《编译器原理与技术与工具》一书中的Pr.Alfred.Vho所述,我们在一次转换中使用额外的产生式规则(M->e)来扩充语法,例如,转换条件跳转和非条件跳转
S -> for id:= E M to E by E do S M end M
S -> other
E -> num
M -> e {Semantic Action()}
正如您所看到的,我们用额外的产生式规则(M)扩充了语法,因此我们知道trueList
和falseList
跳转
所以这里是我主要关心的问题,也就是说,我们是否需要增加像LL(1)这样的自上而下的语法来翻译条件跳转,而不是像SLR(1)那样的条件跳转?正如您在问题中所指出的,这本教科书的作者专门讨论的是单次翻译。添加标记非终结符是在LR语法中用于在右手的处理中间执行动作的常用技术;您引用(或编写)的
for
语句就是这种技术的一个例子。(但是,请注意,右侧的最后一个M
是不必要的;它可能只是for
语句本身的缩减操作的一部分。)
这根本不是自下而上解析的要求。最好将其描述为一次性翻译的要求。在编写《龙书》时,计算机有限的计算能力迫使编译器编写者采用策略来减少编译器的通过次数,但如今这种技术是不必要的,而且通常是不可取的。在解析过程中构造一个抽象语法树(AST),并在解析后遍历AST时进行所有语义分析(包括代码生成),这样更简单、更快、更通用
如果您构建了一个AST,那么就不再需要为了将操作偷偷带入正确的序列而使用解析算法。相反,您可以按照您正在进行的特定分析认为方便的任何顺序遍历树
从本质上讲,关于自上而下的解析也可以做出相同的评论;如果要将动作排序到解析中,则需要找到将动作插入到产品中的方法。如果您使用的是基于表的LL解析器生成器,那么至少需要这样做。然而,LL语法用于构建递归下降解析器是非常常见的。由于递归下降解析器是用图灵完全编程语言编写的完全通用的计算机程序,因此在程序中的某个点插入操作不需要任何特殊的东西。您只需将操作放在解析器中的适当位置
一开始,这看起来像是一种简化,但它很快就会把你的程序变成一团意大利面条,不同的动作都是以一点一点的方式同时计算的,这使得所有的计算都很难跟上。经验告诉我们,有时是痛苦的,最好将一个程序组织成单独的松散耦合的任务,每个任务在自己的控制流中执行。因此,您可能最终也会将自上而下的解析器转换为语法树生成器,而不是不断地说:“是的,我想实现该功能,但我的编译器的结构使其变得困难。”丰富的文本,提前感谢。你提到一些有趣的事情,我想问你,但在此之前,我应该多读一点再问。