/
Parser.cs
115 lines (103 loc) · 3.44 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
using System.Collections.Generic;
using System.Linq;
using Funk.Expressions;
using TokenEnum = Funk.BetterEnumerator<Funk.Token>;
namespace Funk
{
public static class Parser
{
public static AbstractSyntaxTree ParseAST(IEnumerable<Token> tokens)
{
// Parse an abstract syntax tree
if (TryParseExpressions(tokens, out List<IExpression> exprs))
{
return new AbstractSyntaxTree(exprs);
}
// Unable to parse the AST due to invalid syntax
else
{
throw new FatalException("Invalid syntax");
}
}
public static bool TryParseExpressions(IEnumerable<Token> tokens, out List<IExpression> result)
{
// Empty token list
// Return an empty expression list
if (tokens.Count() == 0)
{
result = new List<IExpression>();
return true;
}
List<IExpression> exprs = new List<IExpression>();
TokenEnum tokenEnum = new TokenEnum(tokens);
// Parse top-level expressions from tokens one by one
do
{
// Expression parsed successfully
if (TryParseNextExpression(tokenEnum, out IExpression expr))
{
exprs.Add(expr);
}
// Unrecognized expression syntax
else
{
result = null;
return false;
}
}
while (tokenEnum.MoveNext());
result = exprs;
return true;
}
public static bool TryParseNextExpression(TokenEnum tokenEnum, out IExpression result)
{
List<Token> tokenBuffer = new List<Token>();
// Gradually add tokens to the token buffer
// until they match an expression pattern
// or until the parser runs out of tokens
do
{
tokenBuffer.Add(tokenEnum.Current);
// Try to parse an expression from the tokens in the token buffer
if (TryParseExpression(tokenBuffer, out IExpression expr))
{
result = expr;
return true;
}
}
while (tokenEnum.MoveNext());
// Unrecognized expression syntax
result = null;
return false;
}
public static bool TryParseExpression(List<Token> tokens, out IExpression result)
{
// Number
if (NumberExpression.TryParse(tokens, out NumberExpression numExpr))
{
result = numExpr;
return true;
}
// Symbol
else if (SymbolExpression.TryParse(tokens, out SymbolExpression symExpr))
{
result = symExpr;
return true;
}
// Function definition
else if (FunctionExpression.TryParse(tokens, out FunctionExpression funcExpr))
{
result = funcExpr;
return true;
}
// Function call
else if (CallExpression.TryParse(tokens, out CallExpression callExpr))
{
result = callExpr;
return true;
}
result = null;
return false;
}
}
}