树构造中的ANTLR-孙子节点

树构造中的ANTLR-孙子节点,antlr,grammar,declarative,Antlr,Grammar,Declarative,我试图写一个声明式语法,其中声明和其他语句的顺序并不重要。但是,对于解析,我希望语法输出以有序的方式生成一棵树。假设该语言由声明(decl)和赋值(assign)组成。例如: decl x assign y 2 assign x 1 decl y 我想让程序用一棵树来表示,所有声明都在一个子树中,所有赋值都在另一个子树中。对于上面的示例,类似于: (PROGRAM (DECLARATIONS x y) (ASSIGNMENTS (y 2) (x

我试图写一个声明式语法,其中声明和其他语句的顺序并不重要。但是,对于解析,我希望语法输出以有序的方式生成一棵树。假设该语言由声明(
decl
)和赋值(
assign
)组成。例如:

decl x
assign y 2
assign x 1
decl y
我想让程序用一棵树来表示,所有声明都在一个子树中,所有赋值都在另一个子树中。对于上面的示例,类似于:

(PROGRAM
    (DECLARATIONS x y)
    (ASSIGNMENTS
        (y 2)
        (x 1)))
我可以在树构造期间执行这种重新排列,还是应该编写树语法

我可以在树构造期间执行这种重新排列,还是应该编写树语法

这两种方法都可以,但我建议在令牌解析期间对节点进行分组

我对我编写的任何树重写语法都不满意,因为这些语法必须重新发现每个可分组节点所在的位置,因此需要分组。令牌解析器在常规处理过程中接触所有这些数据,树语法最终遍历这些节点的树,就像令牌解析器遍历其令牌输入一样。如果只是为了分组,我认为树解析器不值得这么麻烦

无论如何,在解析器中管理分组归根结底就是在生成
decl
assign
节点后保存它们,然后在它们的分组级别出现时再次将它们推出。这里有一个简单的例子

声明的
compileationunit
的产品是
^(程序{createTree(声明,decls)}{createTree(赋值,赋值)})
,它将分组节点添加到
程序
。方法
createTree
用于一次性构建分组节点及其子节点

也许有一种巧妙的方法可以让ANTLR为您整合所有内容,但这种方法是有效的,而且是不言自明的

所以考虑到这个输入

decl x
assign y 2
assign x 1
decl y
。。。为上述语法生成的令牌解析器生成此树作为输出:

(PROGRAM 
    (DECLARATIONS 
        (decl x) 
        (decl y)) 
    (ASSIGNMENTS 
        (assign y 2) 
        (assign x 1)))

我认为这里有一个比另一个更简单的答案:

token { DECLS; ASSIGNS; }

prog: (d+=decl | a+=assign)* EOF -> ^(DECLS $d*) ^(ASSIGNS $a*) ;

...
当然,可以根据您喜欢的规则进行调整

但是,您确定需要这样做吗?为什么不在解析器中构建DECL指令的符号表,然后只构建赋值的AST,您可以在树遍历中进行检查


吉姆

对于这样一个简单的案例,这肯定是一个快速处理的方法。简单接受-谢谢!为了回答你的问题,我不完全确定我是否需要这样做,但正如我对另一个答案的评论,我不喜欢将代码混入语法。对我来说,合乎逻辑的步骤是在AST中分离声明,在AST中,分离的解析代码可以轻松地处理它们。感谢您的详细回答!我个人不喜欢把代码和语法混在一起,但我想我总有一天会克服的…@DanielBuckmaster我不会因为你的偏见而责怪你,我的答案是针对一个更一般的情况(将深度n的后代分组到任意深度(PROGRAM (DECLARATIONS (decl x) (decl y)) (ASSIGNMENTS (assign y 2) (assign x 1)))
token { DECLS; ASSIGNS; }

prog: (d+=decl | a+=assign)* EOF -> ^(DECLS $d*) ^(ASSIGNS $a*) ;

...