-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathAlgorithms.cs
More file actions
90 lines (81 loc) · 3.96 KB
/
Copy pathAlgorithms.cs
File metadata and controls
90 lines (81 loc) · 3.96 KB
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
// Algorithms.cs, 07.11.2019
// Copyright (C) Dominic Beger 07.11.2019
using System.Collections.Generic;
using SharpMath.Expressions;
using SharpMath.Expressions.Exceptions;
namespace SharpMath
{
/// <summary>
/// Provides algorithms for common mathematical operations.
/// </summary>
public static class Algorithms
{
/// <summary>
/// Converts infix tokens to postfix tokens.
/// </summary>
/// <param name="infixTokens">The infix tokens to convert.</param>
/// <returns>The postfix tokens.></returns>
public static IEnumerable<Token> ShuntingYard(List<Token> infixTokens)
{
var opStack = new Stack<Token<string>>();
var output = new List<Token>(infixTokens.Count);
Token lastToken = null;
foreach (var token in infixTokens)
{
if (lastToken != null)
{
// A constant value or number must be followed by an operator or closing bracket...
if ((lastToken.Type == TokenType.Constant || lastToken.Type == TokenType.Number) &&
token.Type != TokenType.Operator && !token.IsClosingBracket())
throw new ParserException(
"Cannot calculate the postfix tokens of the given input as the term is invalid. A constant or number must be followed by an operator or a closing bracket.");
// A closing bracket must be followed by an operator or another closing bracket...
if (lastToken.IsClosingBracket() && token.Type != TokenType.Operator && !token.IsClosingBracket())
throw new ParserException(
"Cannot calculate the postfix tokens of the given input as the term is invalid. A closing bracket must be followed by an operator or another closing bracket.");
}
lastToken = token;
switch (token.Type)
{
case TokenType.Number:
output.Add((Token<double>) token);
break;
case TokenType.Function:
opStack.Push((Token<string>) token);
break;
case TokenType.Operator:
var currentOperatorToken = (Token<string>) token;
while (opStack.Count > 0 && opStack.Peek().Type == TokenType.Operator &&
(!currentOperatorToken.IsRightAssociative &&
currentOperatorToken.Priority == opStack.Peek().Priority ||
currentOperatorToken.Priority < opStack.Peek().Priority))
output.Add(opStack.Pop());
opStack.Push(currentOperatorToken);
break;
case TokenType.Bracket:
var bracketToken = (Token<string>) token;
switch (bracketToken.Value)
{
case "(":
opStack.Push(bracketToken);
break;
case ")":
while (opStack.Peek().Value != "(")
output.Add(opStack.Pop());
opStack.Pop();
if (opStack.Count > 0 && opStack.Peek().Type == TokenType.Function)
output.Add(opStack.Pop());
break;
}
break;
case TokenType.Constant:
output.Add((Token<string>) token);
break;
}
}
while (opStack.Count > 0) // Flush the remaining stuff
output.Add(opStack.Pop());
return output;
}
}
}