How to mix binary and unary operators?

I’m writing a simple grammar that always resolve to a single line binary expression.
E.g.: variable1 < variable2 - variable3

Here is my .grammar:

@top Program { expression* }
expression { (expression | ExpressionComponent) Operator ExpressionComponent }
ExpressionComponent { UnaryOperator* Variable }
@tokens {
  Variable { $[a-z]+ $[a-zA-Z_0-9]* }
  Operator { ("|" | "&" | "=" | "!=" | ">" | ">=" | "<" | "<=" | "-" | "+" | "/" | "*") }
  UnaryOperator { ("-" | "+") }
  space { $[ ]+ }
}
@skip { space }

That works well except for unary operators. The generator complains that overlapping tokens appear in the same context. I understand why, but not how to resolve it.
There can be any number of unary operators modifying the sign of the variable. E.g.: variable1 < --variable2 - -+-variable3
It’s simple to read (the first symbol between two variables is a binary operator, the (optional) following symbols are unary operators), but I’m not sure how to write it. Also, there are no increment (++) or decrement (--) operators nor parenthesis.

I tried modifying precedence without success. What am I missing?

Thanks!

1 Like

Overlapping tokens aren’t a grammar-level issue. That error comes up when some of the tokens (quoted strings and rules defined in @tokens) can match the same input. Which is clearly the case for your UnaryOperator and Operator tokens. Use a single token type for “+”/“-”, not two different tokens that both match it.

1 Like

Thank you! You put me on the right track. I also had to fix precedence.
Here is the working code for anyone wondering (also please tell me if that doesn’t make sense):

@top Program { expression* }
expression { (expression | ExpressionComponent) !binary (Operator | AddSubOperator) ExpressionComponent }
ExpressionComponent { !unary AddSubOperator* Variable }
@precedence { unary @right, binary @left }
@tokens {
  Variable { $[a-z]+ $[a-zA-Z_0-9]* }
  Operator { ("|" | "&" | "=" | "!=" | ">" | ">=" | "<" | "<=" | "/" | "*") }
  AddSubOperator { ("-" | "+") }
  space { $[ ]+ }
}
@skip { space }
1 Like