1
votes

I'm writing a language parser in Antlr4. I'm already quite well versed with it, but I don't want to fall into a pitfall (again), so here it is:

expression
    |   gate=expression QUESTION
            (ifTrue=expression)? COLON
            (ifFalse=expression)?               # TernaryExpression
    |   Identifier                              # IdentifierExpression
    |   literal                                 # LiteralExpression
    |   expression logicalComparator expression # LogicalComparisonExpression
    |   expression logicalOperator expression   # LogicalOperationExpression
    ;

and the input:

user.field == 'STRING' ? user.field + user.otherField : user.somethingElse

The tree I obtain is:

(expression
    (expression
        (expression user) . (expression field)
    )
    (logicalComparator = =)
    (expression
        (expression (literal 'STRING'))
        ? (expression
            (expression
                (expression user) . (expression field)
            )
            (binaryOperator +)
            (expression
                (expression user) . (expression otherField)
            )
        )
        : (expression
            (expression user) . (expression somethingElse)
        )
    )
)

(An expression of logical comparison, where left-hand-side is user.field, comparator is == and right-hand-side is the ternary operator.)

The actual result should be a ternary operator, where gate expression is a logical comparison.

How can I fix it? I was certain, that the fact I placed TernaryExpression above LogicalComparisonExpression will suffice, but apparently it doesn't.

1
After some additional research I found: github.com/antlr/antlr4/issues/303 github.com/antlr/antlr4/issues/268 which seem to indicate, that the problem is in Antlr...Gerino

1 Answers

0
votes

Ok, here is the workaround. I don't like it, but it seems to work for some reason.

In expression rule, changed

|   expression logicalComparator expression # LogicalComparisonExpression

to

|   lhs=expression operator=(   DEQUALS
                                 |LSHARP
                             ) rhs=expression # LogicalComparisonExpression

I placed only two items in operator=(...) for testing purposes.

This has some negative effects though:

  1. inline definition of operators <- I'd love to have them separate for readability.
  2. forces me to tokenize '==' instead of '=' '='. If I try:

    operator=(EQUALS EQUALS | LSHARP)

I get "label assigned to a block which is not a set".

I guess I'll work with this, but I'd still to see if it can be done better.