Reputation: 690
If we look at the bash sources, and the yacc grammar specifically, we can see that all redirections are defined as such :
redirection
: GREATER WORD
| LESS WORD
| NUMBER GREATER WORD
| NUMBER LESS WORD
| REDIR_WORD GREATER WORD
| REDIR_WORD LESS WORD
| GREATER_GREATER WORD
| NUMBER GREATER_GREATER WORD
| REDIR_WORD GREATER_GREATER WORD
| GREATER_BAR WORD
| NUMBER GREATER_BAR WORD
| REDIR_WORD GREATER_BAR WORD
| LESS_GREATER WORD
| NUMBER LESS_GREATER WORD
| REDIR_WORD LESS_GREATER WORD
| LESS_LESS WORD
| NUMBER LESS_LESS WORD
| REDIR_WORD LESS_LESS WORD
| LESS_LESS_MINUS WORD
| NUMBER LESS_LESS_MINUS WORD
| REDIR_WORD LESS_LESS_MINUS WORD
| LESS_LESS_LESS WORD
| NUMBER LESS_LESS_LESS WORD
| REDIR_WORD LESS_LESS_LESS WORD
| LESS_AND NUMBER
| NUMBER LESS_AND NUMBER
| REDIR_WORD LESS_AND NUMBER
| GREATER_AND NUMBER
| NUMBER GREATER_AND NUMBER
| REDIR_WORD GREATER_AND NUMBER
| LESS_AND WORD
| NUMBER LESS_AND WORD
| REDIR_WORD LESS_AND WORD
| GREATER_AND WORD
| NUMBER GREATER_AND WORD
| REDIR_WORD GREATER_AND WORD
| GREATER_AND DASH
| NUMBER GREATER_AND DASH
| REDIR_WORD GREATER_AND DASH
| LESS_AND DASH
| NUMBER LESS_AND DASH
| REDIR_WORD LESS_AND DASH
| AND_GREATER WORD
| AND_GREATER_GREATER WORD
;
In my visitor, when visitRedirection
is called this feels almost impossible to know which alternative the visitor is currently in easily.. I could label each alternatives using #
and labels but adding 43 visit methods for just a single production rules seems somewhat excessive.
Usually I would just do some null
checks by doing ctx.GREATER() != null
to know if the first alternative was chosen, but in this example there's almost always 2 clashing alternatives, for instance :
GREATER WORD
NUMBER GREATER WORD
So should I do ctx.NUMBER() != null && ctx.GREATER() != null
to match the second alternative and ctx.NUMBER() == null && ctx.GREATER() != null
to match the first ?
Is there an easier or cleaner way to be able to know which specific alternative the visitor is currently in ?
Upvotes: 4
Views: 578
Reputation: 53337
Restructure your grammar to have less alternatives. Many of them have common leading or trailing parts, for example:
redirection
: GREATER WORD
| LESS WORD
| NUMBER (GREATER | LESS) WORD
| REDIR_WORD (GREATER | LESS | LESS_LESS_MINUS) WORD
| ...
This way you have a unique first token in each alt, which you can then assign to a local variable:
redirection
: op = GREATER WORD
| op = LESS WORD
| op = NUMBER subOp= (GREATER | LESS) WORD
| op = REDIR_WORD subOp =(GREATER | LESS | LESS_LESS_MINUS) WORD
| ...
With that you can easily check in which alt you are in your listener/visitor:
public exitRedirection(RedirectionContext ctx) {
switch (ctx.op.getType()) {
case YourParser.GREATER_WORD: {
break;
}
case YourParser.REDIR_WORD: {
switch (ctx.supOp.getType()) {
case YourParser.LESS_LESS_MINUS: {
break;
}
}
break;
}
}
Upvotes: 3