ANTLR4如何获取树结构

How to get a tree structure ANLTR4

我需要像这样解析配置文件

"agent 1"(
"ip"("192.67.4.1"),
"port"("12345"),
"neighbours"(
    "agent 2"(
        "ip"("192.67.4.2"),
        "port"("12345")),
    "agent 3"(
        "ip"("192.67.4.1"),
        "port"("12346"))),
"measurements"(
    "voltage"("4.2V"),
    "power"("7KW")))

到目前为止我得到的是语法(大部分是通过少数教程的试错法获得的)

grammar Tree;

compileUnit
    :   group EOF
    ;

group
    :   (node '(' group ')' (',')? )*                # root
    |   node                                         # value
    ;
node
    : STRING                                         # label
    ;

STRING   :   '"'[ a-zA-Z0-9\.]+'"';
WS      :   [ \t\r\n] -> channel(HIDDEN);

它的结果在预览中是这样的树 Tree

我已经具备以某种形式(其他要求)向我的树添加节点的功能:

ADD "label 1" "label 2" ... "label n"

因此解析器的完美结果将是字符串数组,如:

但我无法进一步实现我的解析器来获取这样的字符串数组。所以我的问题是该怎么做?我知道我需要扩展 BasicListener 的 Parser 之类的东西,但无法管理它。

解决方案

首先,让我们将命名替代项 root 更改为:

group
    :   node '(' (group (',')?)+ ')'     # root
    |   node                             # value
    ;

这使我们能够跟踪每个 group 的 header(node)。当我进一步提到 tree 时,我的意思是 config 树结构 。那我们来做两个定义:

  • path - 是从树根到树叶收集的一串值(例如"Agent 1" "neighbours" "agent 2" "ip" "192.67.4.2"),
  • 部分路径 - 是不以树叶结束的路径(未完成的路径,例如"Agent 1" "neighbours" "agent 2" "ip" ).

现在我们将编写一个简单的树侦听器,它将收集 路径

public class TreeToArray extends TreeBaseListener {
    Stack<String> partialPath = new Stack<>();
    public List<String> paths = new ArrayList<>();

    @Override
    public void enterRoot(TreeParser.RootContext ctx) {
        if (partialPath.isEmpty()) {
            // We are in top-root, partial path consists of top-root's name
            partialPath.push(ctx.node().getText());
        } else {
            // We are in one of the sub-roots, partialPath.peek() returns a current partial path
            partialPath.push(partialPath.peek() + " " + ctx.node().getText());
        }
    }

    @Override
    public void enterValue(TreeParser.ValueContext ctx) {
        paths.add(partialPath.peek() + " " + ctx.getText());
    }

    @Override
    public void exitRoot(TreeParser.RootContext ctx) {
        partialPath.pop();
    }
}

堆栈 partialPath 保留有关当前构建的 部分路径 的信息。当我们访问主路径时,首先 root (例如 "Agent 1")我们没有任何 部分路径 ,因此我们将 root的header。否则我们检索 部分路径 并向其添加根的 header。当我们偶然发现 value 我们在树的叶子上时,我们完成了 路径 。我们 pop() 部分路径 ,然后我们向其添加 node 值。结果字符串(完整的 path)进入 paths 列表。