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

后端 未结 6 625
眼角桃花
眼角桃花 2020-12-09 16:25

I\'ve been working on implementing the Shunting-Yard Algorithm in JavaScript for class.

Here is my work so far:

var userInput = prompt(\"Enter in a m         


        
相关标签:
6条回答
  • 2020-12-09 16:31

    In my Java implementation I did it in next way:

    expression = expression.replace(" ", "").replace("(-", "(0-")
                    .replace(",-", ",0-");
            if (expression.charAt(0) == '-') {
                expression = "0" + expression;
            }
    
    0 讨论(0)
  • 2020-12-09 16:33

    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.

    0 讨论(0)
  • 2020-12-09 16:37

    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.

    0 讨论(0)
  • 2020-12-09 16:38

    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 'p', 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)

    0 讨论(0)
  • 2020-12-09 16:48

    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...

    0 讨论(0)
  • 2020-12-09 16:48

    To handle floating point numbers you can change your (number part of) regex to:

    /([0-9]+\.?[0-9]*)/
    

    so the final regex would be:

    /([0-9]+\.?[0-9]*|[*+-\/()])/
    

    And for handling unary minus operator, you can change it to another character like 'u'. (As it is explained here by -TGO)

    The javascript code that i wrote for handling unary minus operator based on the link given is:

    // expr is the given infix expression from which, all the white spaces has been
    // removed.(trailing and leading and in between white space characters)
    const operators = ['+', '*', '-', '/', '^'];
    const openingBrackets = ['(', '[', '{'];
    let exprArr = Array.from(expr);
    // Since strings are immutable in js, I am converting it to an array for changing 
    // unary minus to 'u'
    for (let i = 0; i < expr.length; i++) {
        if (expr[i] === '-') {
            if (i === 0) {
                exprArr[i] = 'u';
            } else if (operators.includes(expr[i - 1])) {
                exprArr[i] = 'u';
            } else if (openingBrackets.includes(expr[i - 1])) {
                exprArr[i] = 'u';
            } else {
                // '-' is not a unary operator
                // it is a binary operator or we have the wrong expression, so...
                if (!openingBrackets.includes(expr[i + 1]) && !/[0-9]/.test(expr[i + 1])) {
                    throw new Error("Invalid Expression...");
                }
            }
        }
    }
    // And finally converting back to a string.
    let expr2 = exprArr.join('');
    
    0 讨论(0)
提交回复
热议问题