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 ?
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;
        }
    }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With