I'm writing a jsonpath parser with JavaCC and need to distinguish between a simple object(such as $.book) and an array (such as $.book[0]), here is how the jjt file goes:
void Root() #void: {}
{
<ROOT><SEPARATOR> Expression() (<EOL>)? # starts with $.
}
void Expression() #void: {}
{
Variable()
(
<SEPARATOR>
Variable()
)*
}
void Variable() #void: {} # here is where the error resides
{
LOOKAHEAD(Object()) # a choice conflict between book and book[0]
Object()
|
Array()
}
void Object():
{
Token t;
}
{
t = <IDENTIFIER> # such as $.book
{
jjtThis.setName(t.image);
}
}
void Array():
{
Token t;
}
{
t = <IDENTIFIER> # such as book[0]
{
jjtThis.setName(t.image);
}
<BRACKET_OPEN>t=<INTEGER_LITERAL><BRACKET_CLOSE> # such as [0]
{
jjtThis.setIndex(java.lang.Integer.parseInt(t.image));
}
}
With the generated JsonPathParser, it does not work as expected:
SimpleNode node = new JsonPathParser(new StringReader("$.book[0]")).parse();
SimpleNode child = simpleNode.jjtGetChild(0);
assertTrue(child instanceof ASTArray); # assert failure, child is of type ASTObject
I understand that the root cause resides here: LOOKAHEAD(Object()) Object() | Array(), but I could not make it correct.
Tried to use t = <IDENTIFIER>(?!\[) in Object() method to make sure it's not followed by a [, but got a org.javacc.jjtree.ParseException: Encountered " "?" "? "" at line 96, column 27 error.
Any help is highly appreciated.
Finally work it out. In one word we have to use "semantic lookahead" to achieve this. A quick answer is shown as below, and for details please read this article: https://www.cs.purdue.edu/homes/hosking/javacc/doc/lookahead.html