如何通过实现ANTLR生成的Visitor创建复杂的POJO

时间:2018-08-10 17:48:19

标签: java parsing antlr4 visitor visitor-pattern

我正在使用ANTLR4,并为我正在设计的新语言编写了词法分析器和解析器语法。我想通过解析该语言来创建Java POJO。

语言

{dept dept-name="human resources"}
   {emp name="john doe" age=23 address="123 Main St, Spring Field, CO 12345" /}
{/dept}

Java POJO

public class Department {
  private final class name;
  private final List<Employee>
}

public class Employee {
  private final String name;
  private final int age;
  private final Address address;
}

public class Address {
  private final String streetAddress;
  private final String city;
  private final String state;
  private final int zip;
  private final int zipExt;
}

我已经能够正确定义语法。我能够使用Antlr工具生成Visitor类。 Visitor类采用通用类型T,并在访问每个节点时返回类型T的实例。我需要在访问AST的“地址”部分时返回一个地址,而在访问AST的“雇员”部分时返回一个雇员。因此,我不确定用于Visitor实现的T类型是什么。

我对如何通过实施ANTLR给出的“访问者”来构造上述部门POJO感到困惑。

PS:请注意,我不能更改部门,员工和地址类别。另外,请不要建议使用XML或JSON。我只是想学习如何在ANTLR中解决这样的问题。

谢谢!

1 个答案:

答案 0 :(得分:1)

假设这是解析器的头。g4语法 您的整个脚本是一个filefile可以由多个元素组成。 元素可以是pagepageGrouppagepageGroup还有其他组成部分。

parser grammar MyCustomParser;
file: element* EOF;
element: page | pageGroup;

然后,一旦运行Antlr命令,您将获得许多生成的文件,其中大多数文件的名称可能类似于MyCustomParser$XXXContext.class。这些文件表示解析树中的节点。在我们的情况下,我们将有MyCustomParser.PageContextMyCustomParser.PageGroupContext,依此类推。

一个特别重要的节点是解析树的根节点MyCustomParser.FileContext。其子元素将是元素上下文,而元素上下文的子元素将是上述页面上下文或页面组上下文。

现在有了这个根节点,您所需要做的就是从根开始递归地访问解析树中的所有节点。而且,当您访问节点时,可以根据存储在这些节点中的值来生成POJO。

获取根节点

//....
MyCustomParser parser = new MyCustomParser(tokens);
MyCustomParser.FileContext fileContext = parser.file();

请注意,我们将方法称为file()。方法名称与您的根规则名称相同。

您不必使用生成的树访问者。它只是在这里帮助您节省一些锅炉模板代码,因为在大多数情况下,我们以相同的方式来运送这棵或那棵树。

您提到了泛型类型问题。大多数时候,您的POJO可能有一个公共的父类,或实现一个公共的接口。然后,您可以只使用父类或接口。但是根据您的情况,您无法修改POJO,因此使用生成的树可能并不容易。