-
Notifications
You must be signed in to change notification settings - Fork 1
/
ShuntingYard.cs
100 lines (86 loc) · 2.92 KB
/
ShuntingYard.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
using System;
using System.Collections.Generic;
namespace Calculator
{
/// <summary>
/// http://en.wikipedia.org/wiki/Shunting-yard_algorithm
/// </summary>
public class ShuntingYard
{
readonly Queue<Token> infixTokens;
public ShuntingYard (Queue<Token> infixTokens)
{
this.infixTokens = infixTokens;
}
public Queue<Token> PostfixTokens
{
get {
return InfixToPostfix ();
}
}
private static Queue<Token> CloneQueue(Queue<Token> queue)
{
Queue<Token> clonedQueue = new Queue<Token>();
foreach (var item in queue) {
clonedQueue.Enqueue (item);
}
return clonedQueue;
}
private Queue<Token> InfixToPostfix()
{
Queue<Token> infixTokensCopy = CloneQueue (this.infixTokens); // mutate separate queue
Queue<Token> outputQueue = new Queue<Token> ();
Stack<Token> operatorStack = new Stack<Token> ();
TokenType lastTokenType = TokenType.None;
while (infixTokensCopy.Count > 0) {
Token token = infixTokensCopy.Dequeue ();
if (token.Type == TokenType.Number) {
outputQueue.Enqueue (token);
} else if (token.Type == TokenType.Function) {
operatorStack.Push (token);
} else if (token.Type == TokenType.FunctionArgSeparator) {
while (operatorStack.Peek().Type != TokenType.LeftParen) {
outputQueue.Enqueue (operatorStack.Pop ());
}
} else if (token.Type == TokenType.Operator) {
if ((operatorStack.Count == 0 && outputQueue.Count == 0) ||
(lastTokenType == TokenType.Operator) ||
(lastTokenType == TokenType.LeftParen) ||
(lastTokenType == TokenType.FunctionArgSeparator)) { // this is a unary operator
if (token.Value == "-") {
token = new Token ("#"); // unary minus operator
} else if (token.Value == "+") {
token = new Token ("@");
}
}
Operator operator1 = new Operator (token);
while (operatorStack.Count > 0 && operatorStack.Peek().Type == TokenType.Operator) {
Operator operator2 = new Operator (operatorStack.Peek ());
if ((operator1.Associativity == "left" && operator1.Precedence <= operator2.Precedence) ||
(operator1.Associativity == "right" && operator1.Precedence < operator2.Precedence)) {
operatorStack.Pop ();
outputQueue.Enqueue (operator2.Op);
} else {
break;
}
}
operatorStack.Push (operator1.Op);
} else if (token.Type == TokenType.LeftParen) {
operatorStack.Push (token);
} else if (token.Type == TokenType.RightParen) {
while (operatorStack.Peek().Type != TokenType.LeftParen) {
outputQueue.Enqueue (operatorStack.Pop ());
}
operatorStack.Pop (); // discard left parenthesis
if (operatorStack.Count > 0 && operatorStack.Peek().Type == TokenType.Function) {
outputQueue.Enqueue (operatorStack.Pop ());
}
}
lastTokenType = token.Type;
}
while (operatorStack.Count > 0)
outputQueue.Enqueue (operatorStack.Pop ());
return outputQueue;
}
}
}