As you described, operator precedence is implemented with operator
production A calling the next more higher precedence operator
production B, followed optionally by the operator symbol and the next
higher precedence operator production B again.
It is not possible for a test to call the operator production A and
force its optional branch to be taken.
(regarding (1): you can test a single production, but cannot force an
optional branch inside the production to be taken.)
(regarding (3): rewriting the grammar to separate the two cases
would make the grammar slower and maybe harder to understand.
For example
void RelationalExpression() : { } {
AdditiveExpression() [ <RELATIONAL_OP> AdditiveExpression() ]
}
could become something like
void RelationalExpression() : { } {
LOOKAHEAD(AdditiveExpression() <RELATIONAL_OP>)
RelationalExpression2()
|
AdditiveExpression()
}
void RelationalExpression2() : { } {
AdditiveExpression() <RELATIONAL_OP> AdditiveExpression()
}
This would allow tests to call RelationalExpression2 to require the
<RELATIONAL_OP> and 2nd parameter, but it would also mean that before
the parser can decide which branch to take, it has to do extra work to
look ahead past the entire additive expression [which could be a
complicated expression with many terms].)
What you can do is check the effects of calling the production.
The simplest check is to check what tokens were consumed.
(regarding (2): one way is to collect the tokens that were consumed,
though that may require modifying the parser if it does not already
to this.
Another way might be to design the tests so a unique next token
remains after the test case input is parsed. For example on input
"a+b<c", after parsing AdditiveExpression a+b, the next token
should be "<".)
(For parsers that create a parse tree [such as using JJTree], the test
could check the type of the created parse node to see if it was a
RelationalExpressionNode or an AdditiveExpressionNode, etc.)
(If you think the productions are confusingly named since a
RelationalExpression does not always consume a relational operator,
think of them as shorthand for something longer like
RelationalExpression abbreviates RelationalOrHigherPrecedenceExpression
AdditiveExpression abbreviates AdditiveOrHigherPrecedenceExpression
)
Hope this helps.


|