There are many algorithms to convert infix to postfix all over the web. But my question is how to make that to support functions? For example sin(x+y)*z.
I will appr
Although @mickeymoon algorithm seems to work, I still had to make some adjustments(didn't work for me) so I think it can be helpful for somebody another implementation(Java like implementation). Based on https://en.wikipedia.org/wiki/Shunting-yard_algorithm
Stack<Token> stack = new Stack<>();
List<Token> result = new ArrayList<>();
//https://en.wikipedia.org/wiki/Shunting-yard_algorithm
// with small adjustment for expressions in functions. Wiki example works only for constants as arguments
for (Token token : tokens) {
if (isNumber(token) || isIdentifier(token)) {
result.add(token);
continue;
}
if (isFunction(token)) {
stack.push(token);
continue;
}
// if OP(open parentheses) then put to stack
if (isOP(token)) {
stack.push(token);
continue;
}
// CP(close parentheses) pop stack to result until OP
if (isCP(token)) {
Token cur = stack.pop();
while (!isOP(cur)) {
if (!isComma(cur)) {
result.add(cur);
}
cur = stack.pop();
}
continue;
}
if (isBinaryOperation(token)) {
if (!stack.empty()) {
Token cur = stack.peek();
while ((!isBinaryOperation(cur)
|| (isBinaryOperation(cur) && hasHigherPriority(cur, token))
|| (hasEqualPriority(cur, token) && isLeftAssociative(token)))
&& !isOP(cur)
) {
// no need in commas in resulting list if we now how many parameters the function need
if (!isComma(cur)) {
result.add(cur);
}
stack.pop();
if (!stack.empty()) {
cur = stack.peek();
}
}
}
stack.push(token);
continue;
}
if (isComma(token)) {
Token cur = stack.peek();
while (!(isOP(cur) || isComma(cur))) {
result.add(cur);
stack.pop();
if (!stack.empty()) {
cur = stack.peek();// don't pop if priority is less
}
}
stack.push(token);
}
}
while (!stack.empty()) {
Token pop = stack.pop();
if (!isComma(pop)) {
result.add(pop);
}
}
return result;
I tested it with various complex expressions including function composition and complex arguments(doesn't work with example from Wiki algorithm). A couple of examples(e is just a variable, min,max, rand - functions):
Input: (3.4+2^(5-e))/(1+5/5)
Output: 3.4 2 5 e - ^ + 1 5 / + /
Input: 2+rand(1.4+2, 3+4)
Output: 2 1.4 2 + 3 4 + rand +
Input: max(4+4,min(1*10,2+(3-e)))
Output: 4 4 + 1 10 * 2 3 e - + min max
I also tested it with complex function with three arguments(where each argument is an expression by itself) and it words fine.
Here is the github for my java function that takes the list of tokens and returns the list of tokens in postfix notation. And here is the function that takes the output from first function and calculates the value of the expression
binary operators like +
can be considered as +(x,y)
Similarly Consider sin, cos, etc functions as unary operators. So, sin(x+y)*z can be written as x y + sin z *
. You need to give these unary functions special treatment.
The code you'll have to work out yourself. Using your specific case as an example might help get you started; the postfix form of sin(x + y) * z
would be:
x y + sin z *
Note that in this one example some operations operation on two values (+
and *
), and others one (sin
)
If you are looking for an algorithm that gives you the conversion infix to postfix including function call support, you can use the below pseudocode(which looks like python code). I have written this for my case but not yet tested thouroughly. If you find any bugs please let me know.
I have also written a Java implementation for the same.
Also, there are few things to note about this implementation:
This algorithm assumes a stream of tokens in infix. It does not parse a expression string. So each token can be identified as an operand, operator, function call etc.
There are 7 different kinds of tokens:
Function call starts are denoted by [
character in the algorithm and function call ends are denoted by ]
. Please note that function call termination is a different token than Right Paranthesis )
although they may be represented by the same character in the string expression.
Every operator is a binary operator with precedence and associativity as their usual meaning.
Comma ,
is a special binary operator with precedence of NEGATIVE INFINITY
and associativity as LEFT (same as + and *). Comma operator is used to separate the arguments of a function call. So for a function call:
f(a,b,c)
first comma separates a and b
second comma separates a,b and c
So the postfix for the above will be
ab,c,f
You can view Comma operator as a add to list function which adds the second argument to the list specified by the first argument or if both are single values it creates a list of two values.
infix_to_postfix(infix):
postfix = []
infix.add(')')
stack = []
stack.push('(')
for each token in infix:
if token is operand:
postfix.add(token)
if token is '[':
stack.push(token)
else if token is operator:
if stack is empty OR
stack[top] is '(' or stack[top] is '[':
stack.push(token)
else if (operator)token['precedence'] > stack[top]['precedence'] OR
( (operator)token['precedence'] == stack[top]['precedence'] AND
(operator)token['associativity') == 'RIGHT' ):
stack.push(token)
else
postfix.add(stack.pop())
stack.push(token)
else if token is '(':
stack.push(token)
else if token is ')':
while topToken = stack.pop() NOT '(':
postfix.add(topToken)
else if token is ']':
while True:
topToken = stack.pop()
postfix.add(topToken)
if topToken is '[':
break
else if token is ',':
while topToken = stack.peek() NOT '[':
postfix.add(topToken)
stack.pop()
stack.push(token)
Thats quite easy: It work with functions too, the regular operators you use (like +,-,*) are functions too. Your problem is, that what you consider "function" (like sin) is not in infix, but they are in prefix.
To come back to your problem: Just convert these prefix functions into postfix (you should find prefix to postfix on the web too - my assumption is that you dont know the "prefix" term) beforehand.
EDIT: Basicaly it is nothing more that first convert the arguments and output them in sequence and append the name of the function afterwards.