Reputation: 172
I need to parse config file in form like this
"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")))
What i got so far is grammar(mostly obtained just by trial and error method from few tutorials)
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);
and the result of it is tree like this in preview Tree
I already have functionality to add nodes to my tree in a form(other requirement):
ADD "label 1" "label 2" ... "label n"
So the perfect outcome of parser would be String array like:
But I couldn't get further and implement my parser to obtain such String array. So my question is how to do it? I get that I need to extend something like Parser of BasicListener but couldn't manage this.
Upvotes: 2
Views: 139
Reputation: 1003
First, let's change the named alternative root
to:
group
: node '(' (group (',')?)+ ')' # root
| node # value
;
This allows us to track the header (node
) of every group
. When I refer further to a tree what I mean is config tree structure. Then let's make two definitions:
"Agent 1" "neighbours" "agent 2" "ip" "192.67.4.2"
),"Agent 1" "neighbours" "agent 2" "ip"
).Now we will write a simple tree listener that will collect paths.
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();
}
}
The stack partialPath
keeps information about currently built partial path. When we visist the main, first root
(e.g. "Agent 1"
) we don't have any partial paths, so we put onto the stack the root
's header. Otherwise we retrive a partial path and add to it root's header. When we stumble across value
we are at the tree's leaf, we finished the path. We pop()
the partial path, then we add to it node
value. The result string (the full path) goes into the paths
list.
Upvotes: 1