-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.cpp
127 lines (112 loc) · 4.45 KB
/
parser.cpp
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
#include "lexer.h"
#include "abstract_syntax_tree.h"
#include "parser.h"
#include <iostream>
#include <optional>
#include <vector>
namespace BallLang
{
// variable
// identifier ( {ExprAST},... )
std::optional<ExprAST> parseIdentifierExpr(Token&& token) {
std::string& name = std::get<std::string>(token.value);
if (std::cin.peek() != '(') return VariableExprAST{std::move(name)};
if (getTok().type != OPEN_PAREN) return std::nullopt; // peek didn't work
std::vector<ExprAST> args{};
while (std::optional<ExprAST> exprOptional = parseExpression(getTok())) {
args.emplace_back(std::move(exprOptional.value()));
switch(getTok().type) {
case COMMA: continue;
case CLOSE_PAREN: return CallExprAST {std::move(name), std::move(args)};
default: return std::nullopt;
}
}
return std::nullopt;
}
std::optional<ExprAST> parsePrimary(Token&& token) {
switch(token.type) {
case IDENTIFIER:
return parseIdentifierExpr(std::move(token));
case NUMBER:
return NumberExprAST(std::get<double>(token.value));
case OPEN_PAREN: {
std::optional<ExprAST> expression = parseExpression(getTok());
if (expression.has_value() && getTok().type == CLOSE_PAREN)
return expression; // hopefully rvo, if not could optimize
else return std::nullopt;
}
default:
return std::nullopt;
}
}
// LHS {binop} RHS
std::optional<ExprAST> parseRHS(int lastPrecedence, ExprAST&& LHS) {
while (true) {
if (!BinopPrecedence.contains(std::cin.peek()))
return LHS; // can't handle spaces before binop rn
Token binop = getTok();
if (binop.type != BINOP) return std::nullopt; // peek failure
int currentOpPrecedence = BinopPrecedence.at(std::get<char>(binop.value));
if (currentOpPrecedence < lastPrecedence)
return LHS;
std::optional<ExprAST> RHS = parsePrimary(getTok());
if (!RHS.has_value()) return std::nullopt;
const auto nextBinopPrecedence = BinopPrecedence.find(std::cin.peek());
if (nextBinopPrecedence != BinopPrecedence.end() && currentOpPrecedence < nextBinopPrecedence->second)
RHS = parseRHS(currentOpPrecedence + 1, std::move(RHS.value()));
// recursive parseRHS - should rework this messy logic to make more sense
LHS = BinaryExprAST {
std::get<char>(binop.value),
std::move(LHS),
std::move(RHS.value())
};
}
}
// {primary} {RHS}
std::optional<ExprAST> parseExpression(Token&& token) {
std::optional<ExprAST> LHS = parsePrimary(std::move(token));
if (!LHS.has_value()) return std::nullopt;
return parseRHS(0, std::move(LHS.value()));
}
// funcName ( args... )
std::optional<PrototypeAST> parsePrototype(Token&& token) {
if (token.type != TokenType::IDENTIFIER) return std::nullopt;
std::string& functionName = std::get<std::string>(token.value);
const Token openParen = getTok();
if (openParen.type != TokenType::OPEN_PAREN) return std::nullopt;
std::vector<std::string> functionArgs{};
while (true) {
Token arg = getTok();
if (arg.type == TokenType::IDENTIFIER)
functionArgs.push_back(std::move(std::get<std::string>(arg.value)));
else if (arg.type == TokenType::CLOSE_PAREN)
return PrototypeAST { std::move(functionName), std::move(functionArgs) };
else
return std::nullopt;
}
}
// def {prototype} {expression}
std::optional<FunctionAST> parseDefinition(Token&& _token) { // throw away def
std::optional<PrototypeAST> prototype = parsePrototype(getTok());
if (!prototype.has_value()) return std::nullopt;
std::optional<ExprAST> expression = parseExpression(getTok());
if (!expression.has_value()) return std::nullopt;
return FunctionAST {
std::move(prototype.value()),
std::move(expression.value())
};
}
// {expression}
std::optional<FunctionAST> parseTopLevelExpr(Token&& token) {
if (std::optional<ExprAST> expression = parseExpression(std::move(token)))
return FunctionAST {
std::move(PrototypeAST {"anonymous_expression", std::vector<std::string>{}}),
std::move(expression.value())
};
else return std::nullopt;
}
// extern {prototypeAST}
std::optional<PrototypeAST> parseExtern(Token&& _token) { // throw away initial extern
return parsePrototype(getTok());
}
}