When I was 19 years old I wanted to create a command line interface in gwbasic! I though long and hard about how I would parse a command line and then interprete it. A friend told me I should convert the command to postfix. “2 + 3″ is called infix. Postfix for that would be “2 3 +”. The good thing about it is that postfix is very easy to interprete. Every time you find an argument, such as 2 and 3 in the example, you push it to a stack. When you get to an operator, such as +, you pop the two required arguments from the stack, perform the addition and push the 5 back to the stack.
Dealing with precedence is also very easy. I found a way of doing this, that I think may be original. I would just push every operator to the right following a simple rule. After tokenizing the input string I start with the leftmost token. I walk that token to the right as long as it has lower precedence and as long as it passes the same number of (‘s and )’s. After I walk the first token, I walk the second. That’s all there is to it!
This is not the same way Dijkstra does it with the shunting yard algorithm which uses a stack. All I need is an array! I have tried it with lot’s of different scenarios. I treat operands the same as operators.
This is actually the first time I have ever thought of publishing it. I started thinking someone might take an interest in it. So here it is.
The code example here is a complete example with a rudimentary tokenizer. To try it, compile it with C# 3.5 or port it to your preferred procedural language. After compilation run it with spaces between all tokens. Like PostFix.exe 2 * ( 2 + 3 )
using System;
using System.Collections.Generic;
namespace PostFix
{
class Program
{
static void Main(string[] args)
{
Token[] tokens;
if (args.Length == 0)
{
Console.WriteLine("You called this program without arguments,\nplease enter something for me to calculate.\nPlease remember to use spaces between numbers and operators\nas I am just a sample program without complicated parsing code.");
string input=Console.ReadLine();
tokens = Tokenize(input.Split(new char[] { ' ' }));
}
else
tokens = Tokenize(args);
PostFix(tokens);
float result = Execute(tokens);
Console.WriteLine("Result is: {0}\nPress enter to exit.",result);
Console.ReadLine();
}
private static void PostFix(Token[] tokens)
{
for (int i = 0; i < tokens.Length - 1; i++) { if (tokens[i].Precedence > tokens[i + 1].Precedence)
{
int j = i;
int scopes = 0;
while (j < tokens.Length - 1 && (scopes > 0 ||
tokens[j].Precedence > tokens[j + 1].Precedence))
{
Token tmp = tokens[j];
tokens[j] = tokens[j + 1];
tokens[j + 1] = tmp;
scopes += ((tokens[j].Operator == '(') ? 1 : 0)
- ((tokens[j].Operator == ')') ? 1 : 0);
j++;
}
i--;
}
}
}
private static float Execute(Token[] tokens)
{
Stack stack = new Stack();
foreach (Token token in tokens)
{
switch (token.Operator)
{
case '+':
stack.Push(stack.Pop() + stack.Pop());
break;
case '-':
{
float f1 = stack.Pop();
float f2 = stack.Pop();
stack.Push(f2 - f1);
}
break;
case '*':
stack.Push(stack.Pop() * stack.Pop());
break;
case '/':
{
float f1 = stack.Pop();
float f2 = stack.Pop();
stack.Push(f2 / f1);
}
break;
case '(':
case ')':
break;
default:
stack.Push(token.Operand);
break;
}
}
float result = stack.Pop();
return result;
}
private static Token[] Tokenize(string[] args)
{
Token[] tokens = new Token[args.Length];
int i = 0;
foreach (string arg in args)
{
Token token = new Token();
switch (arg)
{
case "+":
case "-":
token.Operator = arg[0];
token.Precedence = 2;
break;
case "*":
case "/":
token.Operator = arg[0];
token.Precedence = 1;
break;
case "(":
token.Operator = arg[0];
token.Precedence = -1;
break;
case ")":
token.Operator = arg[0];
token.Precedence = 3;
break;
default:
if (!float.TryParse(arg, out token.Operand))
throw new ArgumentException("Unknown token: " + arg);
token.Precedence = 0;
break;
}
tokens[i++] = token;
}
return tokens;
}
}
public struct Token
{
public char Operator;
public float Operand;
public int Precedence;
public override string ToString()
{
if (Operator != 0)
return Operator.ToString();
else
return Operand.ToString();
}
}
}
I think your algorithm is quadratic.
Hello…
When I run this in c# there were certain errors…especially on the stack.pop…why is that so???
Please reply…
Thank you very much…:)
God Bless!
Actually…I tried your code because this is my machine problem…converting infix to postfix using c#…but c# sample codes were very rare..that’s why I’m so happy when I saw your program…
When I put stack.top and stack.empty there were errors…i don’t know why…Are you using a class to access .top and .empty???
Please…Help me to do this…
If there were certain changes on your code please do notify me…
I will really appreciate it from the bottom of my heart…:)
Here are the following errors…(The italicized words are the errors were c# compiler said so)
Error 1 Operator ‘+’ cannot be applied to operands of type ‘object’ and ‘object’
stack.Push(stack.Pop() + stack.Pop());
Error 2 Cannot implicitly convert type ‘object’ to ‘float’. An explicit conversion exists (are you missing a cast?)
float f1 = stack.Pop();
Error 3 Cannot implicitly convert type ‘object’ to ‘float’. An explicit conversion exists (are you missing a cast?)
float f2 = stack.Pop();
Error 4 Operator ‘*’ cannot be applied to operands of type ‘object’ and ‘object’
stack.Push(stack.Pop() * stack.Pop());
Error 5 Cannot implicitly convert type ‘object’ to ‘float’. An explicit conversion exists (are you missing a cast?)
float f1 = stack.Pop();
Error 6 Cannot implicitly convert type ‘object’ to ‘float’. An explicit conversion exists (are you missing a cast?)
float f2 = stack.Pop();
Error 7 Cannot implicitly convert type ‘object’ to ‘float’. An explicit conversion exists (are you missing a cast?)
float result = stack.Pop();
Ok..I’ll check it…:)
By the way, your program accepts algebraic expression or arithmetic expression or both???
ok…Thank you very much!!!
Your program accepts arithmetic expression…
Sir, may I ask question?
In what way can I revise this program where in it will accept an algebraic expression?
Example:
a+b -> to infix ab+
Ok…
Thank you very much for the advice on how to revise your code into an algebraic expression…
I would appreciate if ever there would be an error on my program and you’ll extend your assistance.
Again, thank you very much sir…:)
Thank you sir..:)
I confirmed you already as my friend in Facebook.
Anyway, I’m just a 2nd year college taking up BSIT.
“you would have to change the default-part of the switch in Tokenize method. Instead of throwing an exception when unable to parse the token as a float, you would have to accept it as it is.”
Sir, how would I accept it as it is?
aahhh…okay…:) i see…
default:
if (!float.TryParse(arg, out token.Operand))
throw new ArgumentException(“Unknown token: ” + arg);
token.Operator = arg[0];
token.Precedence = 0;
break;
These part should be replaced right?
Therefore, i should omit the if statement and then store “a” in the Token Class…how about the throw – new ArgumentException it should be omitted also???
I’m sorry if I have so many questions.
I’ve been sleeping very late because of this machine problem.
Although,this should be group project but as you can see sir,I am the only person who is doing this project.
So, I would appreciate all these things sir from the bottom of my heart.
So therefore, I will call Execute() in the main()?
Example:
(a+b)
in order to get the postfix of this i would call
Console.WriteLine(“\n\nResult is: {0}\nPress enter to exit.”,tokens);
But the output is this:
Postfix.Token[]
Why is that so???