<p>Most languages use <code>+</code>/<code>-</code> for addition and subtraction, in addition to using <code>+</code>/<code>-</code> as unary prefix positive/negative operators (the former typically being a no-op). However, this can easily lead to ambiguity.</p>
<p>For example, many languages include a <code>++</code> or <code>--</code> operator. Sometimes these are prefix/postfix increment or decrement operators, typically in C-like languages, and sometimes they're binary operators, such as concatenation in Haskell. When <code>++</code> is an operator, <code>1++2</code> becomes ambiguous; is it <code>1 ++ 2</code>, or <code>1 + (+2)</code>?</p>
<p>Another example is languages where function application doesn't require parentheses (for example, <code>add 1 2</code>). In this case, even <code>2 - 1</code> could be ambiguous; is it the subtraction <code>2 - 1</code>, or is it a <code>2</code> followed by a <code>-1</code>? This case could <em>maybe</em> be solved by tracking the number of arguments to any functions before those tokens, but this falls apart with cases like a three-argument function followed by <code>1 - 2 3 - 4</code>.</p>
<p>How can this ambiguity be resolved, whether by changing the syntax (such as APL's separate &quot;high minus&quot; for negative number literals), the parsing (such as signficant whitespace), or some other aspect of the language?</p>

<syntax><language-design><operators><parsing><ambiguity>
How can ambiguity with unary and binary operators be resolved?
CC BY-SA 4.0
2023-05-16T19:05:35.190Z
Oh, this also comes up with `*` for multiplication, pointer dereferencing, and/or exponentiation (`**`).
rydwolf
CC BY-SA 4.0
2023-05-16T21:32:17.933Z
Precedence, parenthesis, or spaces. It can just be established that one form has precedence over another.
CPlus
<p>If you do come across any conflicts that may arise from a clash between unary and binary operators, I'd recommend checking out a language with a similar set of operators to see how they handle them. You could also write a few snippets in your language to see what mix-ups could occur and implement edge cases for them (e.g. <code>x - -y</code> can be written as <code>x--y</code> which could potentially get interpreted as <code>x-- y</code> or <code>x --y</code>).</p>
<p>Don't worry about missing a few, most of them will be caught in testing and the early versions of the language.</p>

CC BY-SA 4.0
2023-05-21T07:14:05.420Z
2023-05-21T07:14:05.420Z
just Paul
<h1>Who says you have to?</h1>
<p>Never mind that APL has a separate &quot;high minus&quot; for negative literal numbers, the APL unary/binary operators (called monadic/dyadic functions in APL lingo) scheme is unambiguous, because:</p>
<ul>
<li>No multi-glyphs are used; each symbol stands on its own.</li>
<li>All single-argument calls are on the same side.</li>
<li>All operators have the same precedence.</li>
</ul>
<p>APL specifically has unary operators on the left, and operators having long right scope, but this is rather arbitrary, and any scheme adhering to the above rules will be unambiguous.</p>
<p>It is even possible to use mult-glyphs, but then the involved glyphs must not have unary meanings to the side away from their companion glyphs. In fact, GNU APL uniquely <em>does</em> have a few bi-glyph operators that work like this.</p>

CC BY-SA 4.0
2023-05-16T20:06:03.917Z
2023-05-16T20:06:03.917Z
Adám
<p>This is called <a href="https://en.wikipedia.org/wiki/Maximal_munch" rel="noreferrer">maximal munch</a>, and is usually handled during lexing. It means that the lexer will make the tokens as large as possible. This is obvious with identifiers, <code>abc</code> won't be lexed as <code>[a, b, c]</code> but will instead be lexed a single token <code>abc</code>. The same applies to operators. Take <code>&quot;---x&quot;</code> and this simple lexer:</p>
<pre><code>def lex(input_string):
    tokens = []
    i = 0

    while i &lt; len(input_string):
        while input_string[i].strip() == &quot;&quot;:
            i += 1
        current_char = input_string[i]

        if current_char == &quot;-&quot;:
            # Check if it's '--' or '-'
            if input_string[i + 1] == &quot;-&quot;:
                tokens.append(&quot;--&quot;)
                i += 2
            else:
                # It's '-' token
                tokens.append(&quot;-&quot;)
                i += 1

        else:
            # Match other characters as individual tokens
            tokens.append(current_char)
            i += 1

    return tokens
</code></pre>
<p>first the lexer will see that it starts with <code>-</code>, it will check if the next character is also <code>-</code> and because it is lex it as <code>--</code>. The lexer will then loop to see the next token (which is the third <code>-</code>), the lexer will check if the next token is <code>-</code>, it is but the character after isn't <code>-</code> so it will be lexed as <code>-</code>. Finally the lexer will see the <code>x</code> and lex it as <code>x</code>. All together it produces <code>--, -, x</code> for <code>---x</code>. But for <code>- --x</code> it produces <code>-, --, x</code>.</p>
<p>For what you said, with <code>1++2</code> being <code>1 ++ 2</code> or <code>1 + (+2)</code>. The answer is <code>1 ++ 2</code> again due to maximal munch. Of course maximal munch isn't used in all languages and so it can vary from language to language.</p>

CC BY-SA 4.0
2023-05-16T19:48:27.073Z
2023-05-16T19:48:27.073Z
a coder
CC BY-SA 4.0
2023-05-16T19:59:19.920Z
There could be some issues with using this specifically (e.g., `- --x` makes sense, but `-- -x` doesn't), but I guess any guaranteed order for how ambiguous situations are handled would be a solution
rydwolf
CC BY-SA 4.0
2023-05-16T20:04:57.253Z
@RadvylfPrograms There definitely are issues with this!  In C/C++ for example `---x` is also parsed as `-- - x` and (with GCC) trying to compile gets the error `lvalue required as decrement operand`. It's definitely possible to add special handling, but that makes the language more complicated for a small issue (writing `-(--x)` or `- --x` isn't that hard), so it's probably unneeded.
a coder
<h1>Require parentheses whenever different operators are mixed</h1>
<p>Whenever different operators appear in the same expression, whether infix, prefix, or postfix, they must be fully parenthesised. No exceptions. Chains of the same operator, like <code>1+2+3</code> can be ok, but anything else has to be resolved by the programmer.</p>
<p>In this case, <code>1+-2</code> can only be a single hypothetical <code>+-</code> operator and <code>1 + - 2</code> is a <em>syntax error</em> because the infix <code>+</code> and prefix <code>-</code> operators are mingled. The longest-token rule allows identifying <code>++</code> or <code>--</code> as a single operator, and that will be consistent even if one of the signs is swapped, so flipping <code>1++2</code> into <code>1+-2</code> doesn't suddenly change the parse. In this way, errors happen early — either a syntax error, or no-such-operator — and ultimately programmers won't write the difficult expressions into their program in the first place.</p>
<p>This <strong>also deals to precedence and associativity issues</strong>. Especially when there are user-defined operators, there is no universal set of rules for interpreting how they combine, and even with only basic arithmetic operations mixing them together is a common source of bugs. A reader will never be faced with guessing how <code>1 # 2 @ 3</code> or <code>1#@2</code> is parsed, or have a subtle bug where refactoring <code>x</code>⇒<code>x+1</code> introduced a bug changing <code>2 * x</code> to <code>2 * x + 1</code>, if any ambiguity must always be resolved immediately.</p>
<p>For cases like <code>add 1 - 2</code>, this same rule applies because <em>juxtaposition is also an operator there</em> — it's just a hidden one, written as a space or a token boundary between the <code>add</code> and <code>1</code>. This is a syntax error and always has to be disambiguated as <code>add (1 - 2)</code>, <code>add 1 (-2)</code>, or <code>(add 1) - 2</code> - no special cases.</p>
<h2>Drawbacks</h2>
<p>This rule can be annoying for standard arithmetic expressions, but it's helpful whenever others are involved, and it can be a plus to be consistent. It also prohibits code like <code>x||!y&amp;&amp;z</code>, which is probably a plus for reducing logic errors too.</p>
<p>I wouldn't use this in every language, but it's a good option if the expected audience is novice users especially, or when unrestricted user operators are desirable and expected to be on the same level as built-in operators.</p>

CC BY-SA 4.0
2023-05-16T21:30:46.187Z
2023-05-16T21:30:46.187Z
Michael Homer
<p>In Haskell and ML, which don't use parenthesis for function calls, their solution to the problem is that they require parenthesis around unary operators:</p>
<pre><code>f x (-1) 
</code></pre>

CC BY-SA 4.0
2023-05-16T22:15:21.253Z
2023-05-16T22:15:21.253Z
hugomg
<h1>Spacing</h1>
<p>Swift allows <code>a * b</code> and <code>a*b</code> for infix operators, but <code>a *b</code> is interpreted as a prefix operator on <code>b</code>, and <code>a* b</code> is interpreted as a postfix operator on <code>a</code>.</p>
<p><a href="https://github.com/mlochbaum/ILanguage/blob/master/doc/introduction.md" rel="noreferrer">The I programming language uses whitespace for precedence</a> too, rather than parentheses. I don't think this is very user-friendly, but hey, it exists.</p>

CC BY-SA 4.0
2023-05-16T19:08:42.903Z
2023-05-16T23:45:39.843Z
2023-05-16T23:45:39.843Z
Bbrk24
CC BY-SA 4.0
2023-07-04T19:05:53.837Z
Oh, so *that's* why Swift doesn't allow uneven spacing in expressions like `2 + 2` (`2+ 2` is not allowed).  I had learned the rule, but didn't know there was a *reason* behind it other than cosmetic (because the lopsided version is ugly :D)
Quack E. Duck
CC BY-SA 4.0
2024-01-29T15:35:44.487Z
C# also has this in some cases. The expression `a++ + b` has unary `++` "from the right" (postfix) on `a` and the right-most `+` is binary (i.e. addition), whereas `a + ++b` has unary `++` "from the left" (prefix) on `b` instead, and here the left-most `+` is the binary operator. There is also `a + + +b` in which the two right-most plusses are unary (behaves the same as `a + (+(+b))`). Of course, it is allowed to add parentheses if you prefer. In the absence of any spaces in between the plusses, like `a+++b`, there is some rule that says this reads as `(a++) + b`.
Jeppe Stig Nielsen
CC BY-SA 4.0
2024-01-29T15:37:15.690Z
... (continued) And with spaces, you can have more plusses still, for example `a++ + + ++b` which has (in order from left to right) postfix `++`, binary `+`, unary `+`, and prefix `++`.
Jeppe Stig Nielsen
# How can ambiguity with unary and binary operators be resolved?
Posted by: username_0 on 2023-05-16
Most languages use `+`/`-` for addition and subtraction, in addition to using `+`/`-` as unary prefix positive/negative operators (the former typically being a no-op). However, this can easily lead to ambiguity.

For example, many languages include a `++` or `--` operator. Sometimes these are prefix/postfix increment or decrement operators, typically in C-like languages, and sometimes they're binary operators, such as concatenation in Haskell. When `++` is an operator, `1++2` becomes ambiguous; is it `1 ++ 2`, or `1 + (+2)`?

Another example is languages where function application doesn't require parentheses (for example, `add 1 2`). In this case, even `2 - 1` could be ambiguous; is it the subtraction `2 - 1`, or is it a `2` followed by a `-1`? This case could *maybe* be solved by tracking the number of arguments to any functions before those tokens, but this falls apart with cases like a three-argument function followed by `1 - 2 3 - 4`.

How can this ambiguity be resolved, whether by changing the syntax (such as APL's separate "high minus" for negative number literals), the parsing (such as signficant whitespace), or some other aspect of the language?
**Tags:** syntax language-design operators parsing ambiguity
> **Comments:**
> **username_0**: Oh, this also comes up with `*` for multiplication, pointer dereferencing, and/or exponentiation (`**`).  
> **username_1**: Precedence, parenthesis, or spaces. It can just be established that one form has precedence over another.  
---
## 6 answers
### Answer by username_3 on 2023-05-16. Score: 10
# Who says you have to?

Never mind that APL has a separate "high minus" for negative literal numbers, the APL unary/binary operators (called monadic/dyadic functions in APL lingo) scheme is unambiguous, because:

* No multi-glyphs are used; each symbol stands on its own.
* All single-argument calls are on the same side.
* All operators have the same precedence.

APL specifically has unary operators on the left, and operators having long right scope, but this is rather arbitrary, and any scheme adhering to the above rules will be unambiguous.

It is even possible to use mult-glyphs, but then the involved glyphs must not have unary meanings to the side away from their companion glyphs. In fact, GNU APL uniquely *does* have a few bi-glyph operators that work like this.
---
### Answer by username_4 on 2023-05-16. Score: 9
This is called maximal munch, and is usually handled during lexing. It means that the lexer will make the tokens as large as possible. This is obvious with identifiers, abc won't be lexed as [a, b, c] but will instead be lexed a single token abc. The same applies to operators. Take "---x" and this simple lexer:
def lex(input_string):
    tokens = []
    i = 0

    while i < len(input_string):
        while input_string[i].strip() == "":
            i += 1
        current_char = input_string[i]

        if current_char == "-":
            # Check if it's '--' or '-'
            if input_string[i + 1] == "-":
                tokens.append("--")
                i += 2
            else:
                # It's '-' token
                tokens.append("-")
                i += 1

        else:
            # Match other characters as individual tokens
            tokens.append(current_char)
            i += 1

    return tokens

first the lexer will see that it starts with -, it will check if the next character is also - and because it is lex it as --. The lexer will then loop to see the next token (which is the third -), the lexer will check if the next token is -, it is but the character after isn't - so it will be lexed as -. Finally the lexer will see the x and lex it as x. All together it produces --, -, x for ---x. But for - --x it produces -, --, x.
For what you said, with 1++2 being 1 ++ 2 or 1 + (+2). The answer is 1 ++ 2 again due to maximal munch. Of course maximal munch isn't used in all languages and so it can vary from language to language.
> **Comments:**
> **username_0** (2023-05-16): There could be some issues with using this specifically (e.g., `- --x` makes sense, but `-- -x` doesn't), but I guess any guaranteed order for how ambiguous situations are handled would be a solution  
> **username_4** (2023-05-16): @RadvylfPrograms There definitely are issues with this!  In C/C++ for example `---x` is also parsed as `-- - x` and (with GCC) trying to compile gets the error `lvalue required as decrement operand`. It's definitely possible to add special handling, but that makes the language more complicated for a small issue (writing `-(--x)` or `- --x` isn't that hard), so it's probably unneeded.  
---
### Answer by username_5 on 2023-05-16. Score: 9
# Require parentheses whenever different operators are mixed

Whenever different operators appear in the same expression, whether infix, prefix, or postfix, they must be fully parenthesised. No exceptions. Chains of the same operator, like `1+2+3` can be ok, but anything else has to be resolved by the programmer.

In this case, `1+-2` can only be a single hypothetical `+-` operator and `1 + - 2` is a *syntax error* because the infix `+` and prefix `-` operators are mingled. The longest-token rule allows identifying `++` or `--` as a single operator, and that will be consistent even if one of the signs is swapped, so flipping `1++2` into `1+-2` doesn't suddenly change the parse. In this way, errors happen early — either a syntax error, or no-such-operator — and ultimately programmers won't write the difficult expressions into their program in the first place.

This **also deals to precedence and associativity issues**. Especially when there are user-defined operators, there is no universal set of rules for interpreting how they combine, and even with only basic arithmetic operations mixing them together is a common source of bugs. A reader will never be faced with guessing how `1 # 2 @ 3` or `1#@2` is parsed, or have a subtle bug where refactoring `x`⇒`x+1` introduced a bug changing `2 * x` to `2 * x + 1`, if any ambiguity must always be resolved immediately.

For cases like `add 1 - 2`, this same rule applies because *juxtaposition is also an operator there* — it's just a hidden one, written as a space or a token boundary between the `add` and `1`. This is a syntax error and always has to be disambiguated as `add (1 - 2)`, `add 1 (-2)`, or `(add 1) - 2` - no special cases.

## Drawbacks

This rule can be annoying for standard arithmetic expressions, but it's helpful whenever others are involved, and it can be a plus to be consistent. It also prohibits code like `x||!y&&z`, which is probably a plus for reducing logic errors too.

I wouldn't use this in every language, but it's a good option if the expected audience is novice users especially, or when unrestricted user operators are desirable and expected to be on the same level as built-in operators.
---
### Answer by username_6 on 2023-05-16. Score: 7
In Haskell and ML, which don't use parenthesis for function calls, their solution to the problem is that they require parenthesis around unary operators:
f x (-1)
---
### Answer by username_7 on 2023-05-16. Score: 7
# Spacing

Swift allows `a * b` and `a*b` for infix operators, but `a *b` is interpreted as a prefix operator on `b`, and `a* b` is interpreted as a postfix operator on `a`.

[The I programming language uses whitespace for precedence](https://github.com/mlochbaum/ILanguage/blob/master/doc/introduction.md) too, rather than parentheses. I don't think this is very user-friendly, but hey, it exists.
> **Comments:**
> **username_8** (2023-07-04): Oh, so *that's* why Swift doesn't allow uneven spacing in expressions like `2 + 2` (`2+ 2` is not allowed).  I had learned the rule, but didn't know there was a *reason* behind it other than cosmetic (because the lopsided version is ugly :D)  
> **username_9** (2024-01-29): C# also has this in some cases. The expression `a++ + b` has unary `++` "from the right" (postfix) on `a` and the right-most `+` is binary (i.e. addition), whereas `a + ++b` has unary `++` "from the left" (prefix) on `b` instead, and here the left-most `+` is the binary operator. There is also `a + + +b` in which the two right-most plusses are unary (behaves the same as `a + (+(+b))`). Of course, it is allowed to add parentheses if you prefer. In the absence of any spaces in between the plusses, like `a+++b`, there is some rule that says this reads as `(a++) + b`.  
> **username_9** (2024-01-29): ... (continued) And with spaces, you can have more plusses still, for example `a++ + + ++b` which has (in order from left to right) postfix `++`, binary `+`, unary `+`, and prefix `++`.  
---
### Answer by username_2 on 2023-05-21. Score: 3
If you do come across any conflicts that may arise from a clash between unary and binary operators, I'd recommend checking out a language with a similar set of operators to see how they handle them. You could also write a few snippets in your language to see what mix-ups could occur and implement edge cases for them (e.g. `x - -y` can be written as `x--y` which could potentially get interpreted as `x-- y` or `x --y`).

Don't worry about missing a few, most of them will be caught in testing and the early versions of the language.
---
