语义分析器的输入是 AST(抽象语法树)。我的问题是:语义分析器的输出是相同的 AST 装饰,还是应该是一棵新树?这棵树叫什么名字?要创建这个新树,我可以使用访问者模式吗?在下面的示例中,在 AST (inttofloat) 中创建了一个新节点。所以我相信它应该总是被创建一棵新树。
1 回答
虽然这是一个老问题,但它是标准的计算机科学编译器构建课程材料,所以也许需要记录一个答案。
您的问题没有一个单一的答案,因为没有一种实现编译器的单一方法。没有完美和正确的答案,这是许多学生认为应该永远存在的。考官经常问这样的问题,让学生表现出理解,而理解是无法通过单一答案的死记硬背来证明的,我相信这就是这里所寻求的。
编译器可以实现为单遍或多遍;抽象语法树可以是内存中的数据结构,也可以通过将其输出到文件中以某种更实质性的方式记录下来,在最早的编译器中,文件通过打孔到纸带或卡片上具有物理表示!如果在编译器阶段之间移动的数据(无论是标记、抽象语法树、中间代码还是目标代码)被输出,那么持有一个抽象语法树的卡片集和持有另一个抽象的卡片集将被输出-syntax-tree 是不同的树还是原始树和该树的另一个版本?即便如此,从哲学上讲,你可以用任何一种方式来争论。
在现代编译器中,数据可能(通常确实)沿着形成编译器不同组件的多个并发任务之间的管道在各个阶段之间移动;然后我们又在一个管道上有一棵树,另一根管道上还有另一棵树。
但是,如果我们在单个程序中实现编译器,在单个进程中运行,那么我们不需要一棵树进一棵树。编译器的所有部分都可以看到所有的存储。一旦语法分析完成,内存中就会有一个树结构,可以由语义分析器处理。由于语法分析器将不再需要,语义分析器一旦处理完语法树就不会再次运行,因此无需制作另一棵树。在内存中遍历树,作为数据结构,并在原地修改树,效率更高。在您的示例中,节点intofloat被语义分析器插入到树中,表示代码中此时需要的类型转换。因此,在这种情况下,我们可以说我们只有一棵树,它由编译器的所有阶段操作。
现在应该考虑已添加的infloat节点。您可能已经假设它是树节点对象的新类型或属性。情况可能并非如此。它可以被认为是一种运算符形式,例如已经存在的=、+和*节点。它可能已经在可用的运算符集中。语义分析所做的只是向树中显式添加一个运算符,该运算符最初可能已显式包含在代码中。实际上没有创建新形式的节点,只是现有节点类型的另一个实例。它可能是你想象的方式,也可能不是。这两个版本都不是正确或错误的方式。
访问者模式的问题与编译器问题是正交的。访问者模式主要是面向对象编程和语言的一个特征。您可以使用树上的访问者模式来实现语义分析器,也可以不实现,如上一段所述。它可以通过任何一种方式完成,并且再次没有一个正确的答案。讨论访问者模式在这样一个问题中的作用可以用来展示对访问者模式及其应用的理解,以及抽象语法树的目的和作用。因此,如果您正在寻找一个正确的答案(是/否),它不存在。只有辩论存在。
通过对问题中词语含义的辩论和比较,我们可以表示理解。
如果这是考试课程作业的一部分,那就是寻求理解的示范,而不是一个神奇的答案。