How can I modify my Shunting-Yard Algorithm so it accepts unary operators?

纵然是瞬间 提交于 2019-11-29 01:17:12
Austin Taylor

The easiest thing would be to make isNumber match /-?[0-9]+(\.[0-9]+)?/, handling both floating points and negative numbers.

If you really need to handle unary operators (say, unary negation of parenthesized expressions), then you have to:

  • Make them right-associative.
  • Make them higher precedence than any of the infix operators.
  • Handle them separately in EvaluateExpression (make a separate PerformUnaryExpression function which only takes one operand).
  • Distinguish between unary and binary minus in InfixToPostfix by keeping track of some kind of state. See how '-' is turned into '-u' in this Python example.

I wrote up a more thorough explanation of handling unary minus on another SO question.

my suggestion is this. don't handle the '-' as an arithmetic operator. treat it as a 'sign' operator. or treat it as if it's a part of the whole operand (i.e. its sign). what i mean is that everytime you encounter '-', you just have to multiply the operand after it by -1, then proceed to read the next token. :) i hope that helps. just a simple thought...

I could solve this problem by modifying unary operators('+' and '-') to distinguish them from the binary ones.

For example, I called the unary minus 'm' and unary plus '+', making them right-assocative and their precedence equal to the exponent operator('^').

To detect if the operator is unary I simply had to check if the token before the operator was an operator or an opening bracket.

This is my implementation in C++:

        if (isOperator(*token))
        {
            if (!isdigit(*(token - 1)) && *(token - 1) != ')')   // Unary check
            {
                if (*token == '+')
                    *token = 'p';        // To distinguish from the binary ones
                else if (*token == '-')
                    *token = 'm';
                else
                    throw;
            }

            short prec = precedence(*token);
            bool rightAssociative = (*token == '^' || *token == 'm' || *token == 'p');

            if (!operators.empty())
            {
                while (prec < precedence(operators.top()) || (prec == precedence(operators.top()) && !rightAssociative))
                {
                    rpn += operators.top();
                    operators.pop();

                    if (operators.empty())
                        break;
                }
            }
            operators.push(*token);
        }

Here operators is a stack and token is an iterator to the infix expression string

(This just the operator handling part)

When I needed to support this, I did this in an intermediate stage. I started by generating a list of all expression lexemes, then used helper functions to extract operators and operands and the "get operand" function simply consumed two lexemes whenever it saw a unary operator.

It really helps if you use another character to signify "unary minus", though.

In my Java implementation I did it in next way:

expression = expression.replace(" ", "").replace("(-", "(0-")
                .replace(",-", ",0-");
        if (expression.charAt(0) == '-') {
            expression = "0" + expression;
        }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!