This repository has been archived by the owner on Mar 25, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Parser.cs
141 lines (115 loc) · 5.67 KB
/
Parser.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Linq;
namespace CI.Calculator {
/**
* The Parser.
* Reads a string and creates a calculator.
*/
public class Parser {
// Parses a Calculator Expression.
public static int Parse(string Expression) {
// Check for Expression Length.
if (string.IsNullOrEmpty(Expression) || Expression.Length <= 1)
throw new ArgumentException("Invalid input string: Not Enough Characters.", nameof(Expression));
// Break the String, character by character.
char[] ToParse = Expression.ToCharArray();
// If the first character isn't a '(', it is an incorrect format.
if (ToParse.First() != '(')
throw new InvalidOperationException($"Invalid character '{ToParse.First()}' at 1.");
// The Current Level we are at.
int Level = 0;
// The Current Operation we are Processing.
Calculator.Operation CurrentOperation = null;
// The String we are currently parsing.
string ParseString = string.Empty;
// Loop all Characters.
for (int i = 0; i < ToParse.Length; i++) {
// The Current Character.
char Current = ToParse[i];
// Switch Current.
switch (Current) {
// Check for Open Operation '('.
case '(': {
// Increment Level.
Level++;
// Create new Current Operation.
CurrentOperation = new Calculator.Operation {
// Make sure parent is set.
Parent = CurrentOperation
};
} break;
// Check for End Operation ')'.
case ')': {
// Decrement Level.
Level--;
// Check for Parent.
if (CurrentOperation.Parent != null) {
// Push Current Operation to Parent's Stack.
CurrentOperation.Parent.Numbers.Add(new Calculator.Operation.Container {
// Set Container Value.
Value = CurrentOperation
});
// Set Current Operation to Parent.
CurrentOperation = CurrentOperation.Parent;
}
} break;
// Check for Number Input.
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
// If our Operation Type is not none, we've got a problem!
if (CurrentOperation.Type != Calculator.Operation.OpType.None)
throw new InvalidOperationException($"Invalid character '{Current}' at {i + 1}, expected ')'.");
// Add to Parse String.
ParseString += Current;
} break;
// Check for a Space.
case ' ': {
// If we can have a last character and the last character is a ')', continue to next.
if (i - 1 >= 0 && ToParse[i - 1] == ')')
continue;
// Check for Parsed String.
if (string.IsNullOrEmpty(ParseString))
throw new InvalidOperationException($"Invalid Space at {i + 1}.");
// We've got a valid number, let's create a new Container.
Calculator.Operation.Container NewContainer = new Calculator.Operation.Container {
// Set Value.
Value = int.Parse(ParseString)
};
// Reset Parse String.
ParseString = string.Empty;
// Push to the Operation Stack.
CurrentOperation.Numbers.Add(NewContainer);
} break;
// Check for Operations.
case (char) Calculator.Operation.OpType.Add:
case (char) Calculator.Operation.OpType.Subtract:
case (char) Calculator.Operation.OpType.Multiply:
case (char) Calculator.Operation.OpType.Divide:
case (char) Calculator.Operation.OpType.Exponent:
case (char) Calculator.Operation.OpType.SquareRoot: {
// Check for Operation.
if (CurrentOperation.Type != Calculator.Operation.OpType.None)
throw new InvalidOperationException($"Invalid character '{Current}' at {i + 1}, expected ')'.");
// Set Operation.
CurrentOperation.Type = (Calculator.Operation.OpType) Current;
} break;
// Default, throw exception.
default: throw new InvalidOperationException($"Invalid character '{Current}' at {i + 1}.");
}
}
// Check for Level.
if (Level != 0)
throw new InvalidOperationException($"Missing ')' at {ToParse.Length}.");
// Return the Calculation of the Main Container.
return CurrentOperation.Calculate();
}
}
}