DEV Community

Cover image for Why are Unary Operators so Hard?
Ryan Bae
Ryan Bae

Posted on

Why are Unary Operators so Hard?

So, if you've ever tried using parsers (whether to make your own language, or make a crazy-good calculator), you've probably been at least partially betrayed by unary operators. Stuff like -x, !flag, or counter++ are just hell for a normal-everyday parser. Don't get me wrong; parsers have made a way, but the different ways of how they do it is just... very complicated. But why? Why are unary operators so finicky and weird?

The Core Problem
Unary operators aren't like their binary counterparts (obviously). they take in one input, and spit out a value. But once you actually look at the tokens the parser gets, you'll start to see the problem. Take, for example, 2 + -x.
The lexer returns something like:

Number(2),
Operator(Add),
Operator(Minus),
Variable("x")
Enter fullscreen mode Exit fullscreen mode

But how do we differentiate -u (unary subtraction) and -b? Let's start simple with Pratt parsing.


Pratt Parsing is a top-down parser where it starts not knowing the full expression, and it slowly iterates through the expression, gaining more context the more it reveals. Stuff like binary operators are easy; it's just binding power and waiting. but how does it parse -u? Well, Pratt Parsing uses led and nud: left-denotation and null-denotation. Basically, it's when an operator has a second number (led) or no second number (nud). When you're trying to use -u, then you would use the nud version of -.

For my parser, it uses disambiguation. Basically, if we had something like 7 + -5, it's going to check the last term. if it's a term starter , like an operator, it's a unary operator. If it's a term itself, it's a binary operator. But, you do need to check for all cases.

Top comments (0)