LR(1)直接解析为抽象语法树

时间:2015-05-26 18:28:19

标签: java parsing tree abstract-syntax-tree lr

所以我最近问question这个问题并得到了很好的答复。但是,所描述的步骤似乎更像是创建具体语法树的步骤。

  

LR解析过程中的每个减少对应于内部   解析树中的节点。减少的规则是内部AST   节点,从堆栈弹出的项目对应于子节点   那个内部节点。推送到goto的项目对应于   内部节点,而由shift操作推送的那些对应于   AST的叶子(代币)。

     

将所有这些放在一起,您可以通过创建一个简单的方法来构建AST   每次进行减少并连接所有内容时,都会有新的内部节点   合适的。   〜克里斯·多德

我知道所采取的步骤暗示了解析树,但我不想显式构建解析树。并且每次减少生成一个节点似乎会导致整个解析树。我认为如果看到某个状态,我只构建一个节点。然而,这似乎无法正常工作。

1 个答案:

答案 0 :(得分:1)

您不需要在每次减少上构建节点,而您构建的节点不需要包含每个减少的符号。缩小符号也不需要以与解析相同的顺序出现。

在许多情况下,AST是完整解析树的简化,与上面相对应。

简单的例子,对于表达式语法,使用类似yacc的解析器生成器:

expr: term            { $$ = $1; /* see below */ }
    | expr '+' term   { $$ = new_sum_node($1, $3); }
term: factor          { $$ = $1; /* see below */ }
    | term '*' factor { $$ = new_product_node($1, $3); }
factor: '(' expr ')'  { $$ = $2; /* See below */ }
      | ID            { $$ = new_variable_node($1); }
      | NUMBER        { $$ = new_literal_node($1); }

AST构建为非终端的语义值。期望函数new_*_node返回指定类型的新分配节点。 (这里我们假设有一些机制可以从指针中推断出它是什么类型的节点。例如,可以使用子类型和虚函数。)

在Yacc(和类似的解析器生成器)中,每个符号(终端或非终端)都有一个关联的"值",并且每个生产都有一个相关的操作,在生产减少时执行。生产的动作可以分配"值"非终端的减少。该动作可以利用"值"右侧的组件,因为每个组件都是终端(其值由扫描仪设置)或已经减少的非终端。实际上,这是一个S-attributed grammar

上述一些减少在AST中根本没有出现。特别是,单位减少(expr:termterm:factor)只是通过右侧的AST。类似地,括号缩减term:'(' expr ')'只是通过expr的AST,结果括号有效地从AST中消失。 (在所有语言中都不正确;在某些语言中,显然冗余的括号实际上会影响语义,您需要创建一个AST节点来记录事实。)

在Yacc中,如果未指定任何操作,$$ = $1是默认的减少操作,并且由于大多数单位减少从AST中消除,因此通常会显示它们而不进行减少操作。我将它们明确地用于教学目的;在实践中,你不应该这样做。