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
In my Java implementation I did it in next way:
expression = expression.replace(" ", "").replace("(-", "(0-")
.replace(",-", ",0-");
if (expression.charAt(0) == '-') {
expression = "0" + expression;
}
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.
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:
EvaluateExpression
(make a separate PerformUnaryExpression
function which only takes one operand).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.
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)
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...
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('');