-
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathParser.cs
More file actions
130 lines (108 loc) · 4.1 KB
/
Parser.cs
File metadata and controls
130 lines (108 loc) · 4.1 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
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
using StringMath.Expressions;
using System.Collections.Generic;
namespace StringMath
{
/// <summary>A simple parser.</summary>
internal sealed class Parser
{
private readonly Tokenizer _tokenzier;
private readonly IMathContext _mathContext;
private Token _currentToken;
/// <summary>Initializes a new instance of a parser.</summary>
/// <param name="tokenizer">The tokenizer.</param>
/// <param name="mathContext">The math context.</param>
public Parser(Tokenizer tokenizer, IMathContext mathContext)
{
_tokenzier = tokenizer;
_mathContext = mathContext;
}
/// <inheritdoc />
public IExpression Parse()
{
_currentToken = _tokenzier.ReadToken();
IExpression result = ParseBinaryExpression();
Match(TokenType.EndOfCode);
return result;
}
private IExpression ParseBinaryExpression(IExpression? left = default, Precedence? parentPrecedence = default)
{
if (left == default)
{
if (_mathContext.IsUnary(_currentToken.Text))
{
Token operatorToken = Take();
left = new UnaryExpression(operatorToken.Text, ParseBinaryExpression(left, Precedence.Prefix));
}
else
{
left = ParsePrimaryExpression();
if (_currentToken.Type == TokenType.Exclamation)
{
Token operatorToken = Take();
left = new UnaryExpression(operatorToken.Text, left);
}
}
}
while (!IsEndOfStatement())
{
if (_mathContext.IsBinary(_currentToken.Text))
{
Precedence precedence = _mathContext.GetBinaryPrecedence(_currentToken.Text);
if (parentPrecedence >= precedence)
{
return left;
}
Token operatorToken = Take();
left = new BinaryExpression(left, operatorToken.Text, ParseBinaryExpression(parentPrecedence: precedence));
}
else
{
return left;
}
}
return left;
}
private IExpression ParsePrimaryExpression() => _currentToken.Type switch
{
TokenType.Number => new ConstantExpression(Take().Text),
TokenType.Operator when _mathContext.IsFunction(_currentToken.Text) => ParseInvocationExpression(),
TokenType.Identifier => new VariableExpression(Take().Text),
TokenType.OpenParen => ParseGroupingExpression(),
_ => throw MathException.UnexpectedToken(_currentToken),
};
private IExpression ParseInvocationExpression()
{
var fnName = Take().Text;
Match(TokenType.OpenParen);
var arguments = new List<IExpression>(2);
do
{
if (_currentToken.Text == ",")
Take();
var argExpr = ParseBinaryExpression();
arguments.Add(argExpr);
}
while (_currentToken.Text == ",");
Match(TokenType.CloseParen);
return new InvocationExpression(fnName, arguments);
}
private IExpression ParseGroupingExpression()
{
Take();
IExpression expr = ParseBinaryExpression();
Match(TokenType.CloseParen);
return expr;
}
private Token Match(TokenType tokenType) => _currentToken.Type == tokenType
? Take()
: throw MathException.UnexpectedToken(_currentToken, tokenType);
private Token Take()
{
Token previous = _currentToken;
_currentToken = _tokenzier.ReadToken();
return previous;
}
private bool IsEndOfStatement()
=> _currentToken.Type == TokenType.EndOfCode;
}
}