How do I solve ambiguity between `a+b` and `a +b`?

My language have unary +, binary +, and haskell style application notation that concatenates callee and argument directly, so a+b is ambiguous that it can be a+b(binary +) or a +b(a applied to +b). My expectation is to prefer binary + over application when such expression occurs. I didn’t figure out how to do it.

@top Program { expression }

@skip { space }
@precedence {
  application @right
  add-unary
  add @left
}

expression {
  Identifier |
  Application { expression !application expression } |
  AddUnary { !add-unary ("+" | "-") expression } |
  Add { expression !add ("+" | "-") expression }
}

@tokens {
  Identifier { $[a-zA-Z_]$[a-zA-Z_0-9]* }
  space { $[ \t\n\r]+ }
  "+" "-"
}

@detectDelim

It parses a+b as Program(Application(Identifier,AddUnary("+",Identifier))). I’ve tried @dynamicPrecedence with no luck, but I’m not sure I’ve understood this feature so I didn’t show it in code above. Can you show me what’s the correct way to make it parse a+b as binary + expression?
Thanks.

Your precedences seem the wrong way around—you’ll want add above add-unary if it is to take precedence over it.

What I want is not making add take precedence over add-unary. What I want is to parse a+b as binary +, not a applied to +b. The problem is between Application and Add, not AddUnary and Add.

@marijn does this make sense?

No, it doesn’t. Did you actually try changing the precedences? Did it not fix the problem?

I tried. I moved add above add-unary:

@precedence {
  application @right
  add @left
  add-unary
}

After the change a+b is parsed as binary +, which is what I want, but as a result -a+b is parsed as -(a+b), which is not what I want. That’s why I put add below add-unary in the first place. I want -a+b be parsed as (-a)+b like in most languages.

Sounds like you need different precedences for unary minus and unary plus then.

I don’t expect unary minus and unary plus to have different precedences because they will be both categorized as additive unary operators and have same precedence. That is, -a+b will be parsed as (-a)+b, while +a+b will be parsed as (+a)+b similarly.

However, if we need different precedences for them for technical reason, that is acceptable.

To summarize, my requirement is to define an expression grammar that contains unary +/-, binary +/-, and application, where:

  • +/- operations will be parsed as in most popular languages like c or js
  • application will be direct concatenation like in haskell, and have higher precedence than any +/- expressions
  • Disambiguation: for expressions like a+b, parse it as a+b(binary +), not a (+b)(a applied to +b)

Example:

  • -a+b => (-a)+b
  • -a b => -(a b)