我需要以这样的形式解析配置文件
"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 : [ trn] -> channel(HIDDEN);
和它的结果是这样的树在预览树
我已经有功能添加节点到我的树的形式(其他要求):
添加"label 1" "label 2"…"标签n"
解析器的完美结果是:
- "代理1"ip"192.67.4.1"
- "代理1"端口"12345"
- "代理1"邻居"代理2"ip"192.67.4.2"
- "代理1"邻居"代理2"端口"12345"
但是我不能得到进一步和实现我的解析器来获得这样的字符串数组。所以我的问题是怎么做?我知道我需要扩展类似于BasicListener的Parser但无法管理这个
解决方案
首先,让我们将命名的备选root
更改为:
group
: node '(' (group (',')?)+ ')' # root
| node # value
;
这允许我们跟踪每个group
的标头(node
)。当我进一步提到树时,我的意思是配置树结构。然后让我们做两个定义:
- 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
的头放到堆栈中。否则,我们将检索部分路径并将其添加到根的头。当我们在树的叶子上偶然发现value
时,我们完成了路径。我们pop()
部分路径,然后我们添加node
值。结果字符串(完整路径)进入paths
列表。