以下代码片段如何用于生成AST?

时间:2011-04-12 23:17:48

标签: compiler-construction yacc bison compiler-theory abstract-syntax-tree

我们正在为Al Aho的编译器类编写一个编译器,我们正在考虑以下代码来生成AST。这是一些背景知识。我们希望将作用域规则实现为一组name-id映射,并且我们希望在进入之前将一组映射推送到堆栈并生成声明的节点。

compound_statement : {pushScope();} statement_list {popScope();}

那么,这是我的问题。这是如何运作的?这段代码什么时候执行?当解析器减少此生产时,它会被执行吗?哪个部分发生在?我应该去办公时间才能找到答案吗?

2 个答案:

答案 0 :(得分:1)

您的问题涉及构建AST节点,但您的解释主体对符号表进行了明确的讨论。这些想法不一样! AST代表程序的结构。符号表表示关于哪些名称在何处以及它们具有哪些类型的推断。

在你的符号表焦点之后,你在“输入”一个块时按下当前范围并在“退出”时弹出它的概念在概念上是正确的,因为它抽象地实现了每块的新范围。 / p>

我认为你不能让YACC做你所说的,因为我不确定你是否可以在语法规则的任何一点附加语义动作。我相信您只能将操作作为一个整体附加到规则中,并且该操作仅在规则被识别(“减少”)时才会运行。因此,如果您真的想要这样做,您需要弯曲语法以创建插入语义操作的机会。您可以通过重写规则来实现这一点(遵循您的风格,我认为这实际上不是有效的YACC语法):

  compound_statement : block_start statement_list block_end ;
  block_start = '{' pushScope() ;
  block_end = '}' popScope();

我添加了阻止开始和结束对称的动作,但你可以多一点,嗯,简约(笑):

  compound_statement : block_start statement_list '}' popScope() ;
  block_start = '{' pushScope() ;

这里的真正秘诀是在您输入块后通过向原始规则添加子规则来创建缩减/语义操作执行机会。我经常使用一个空规则来完成这个:

  compound_statement : '{' compound_statement_sub_rule block_start statement_list '}' popScope() ;
  compound_statement_sub_rule = pushScope() ;

已经展示了如何做到这一点,我认为你根本不想这样做。你正在做的是与解析过程纠缠在一起的语义。如果沿着这条路走下去,你会发现自己用复杂的动作装饰剩下的语法来创建/查找标识符。通常最好使用语义动作来简单地构建语法树,然后在解析完成后,遍历语法树以实现符号表构造/标识符查找。

我会去办公时间,问你能想到多少问题,不管你认为他们是否愚蠢。它会得到很好的回报。

答案 1 :(得分:0)

当你将一个动作粘贴到yacc中规则的“中间”时,它会为动作创建一个新的隐藏非终端,并在隐藏的非终端减少时执行规则。所以你的规则是:

compound_statement : {pushScope();} statement_list {popScope();} ;

等同于:

compound_statement : hidden_rule statement_list {popScope();} ;
hidden_rule : {pushScope();} ;

另外,yacc将正确修改动作中的$ n个引用,以便它们引用正确的内容。

因此pushScope将在hidden_rule减少时执行(在statement_list中的任何语句减少之前执行),而popScope在所有语句减少后执行,所以这实际上就是你想要的。