forked from KPGPMC/furlang
Parse binop expressions
Signed-off-by: CHatingPython <chatingpython@gmail.com>
This commit is contained in:
+15
-10
@@ -45,16 +45,21 @@ token_handle<> lexer::next_token() {
|
||||
|
||||
char ch = get();
|
||||
switch (ch) {
|
||||
case '(': return { location, token_t::Lparen, m_content.substr(m_cursor++, 1) };
|
||||
case ')': return { location, token_t::Rparen, m_content.substr(m_cursor++, 1) };
|
||||
case '{': return { location, token_t::Lbrace, m_content.substr(m_cursor++, 1) };
|
||||
case '}': return { location, token_t::Rbrace, m_content.substr(m_cursor++, 1) };
|
||||
case '[': return { location, token_t::Lbracket, m_content.substr(m_cursor++, 1) };
|
||||
case ']': return { location, token_t::Rbracket, m_content.substr(m_cursor++, 1) };
|
||||
case ';': return { location, token_t::Semicolon, m_content.substr(m_cursor++, 1) };
|
||||
case ':': return { location, token_t::Colon, m_content.substr(m_cursor++, 1) };
|
||||
case ',': return { location, token_t::Comma, m_content.substr(m_cursor++, 1) };
|
||||
case '.': return { location, token_t::Dot, m_content.substr(m_cursor++, 1) };
|
||||
case '(': ++m_cursor; return { location, token_t::Lparen };
|
||||
case ')': ++m_cursor; return { location, token_t::Rparen };
|
||||
case '{': ++m_cursor; return { location, token_t::Lbrace };
|
||||
case '}': ++m_cursor; return { location, token_t::Rbrace };
|
||||
case '[': ++m_cursor; return { location, token_t::Lbracket };
|
||||
case ']': ++m_cursor; return { location, token_t::Rbracket };
|
||||
case ';': ++m_cursor; return { location, token_t::Semicolon };
|
||||
case ':': ++m_cursor; return { location, token_t::Colon };
|
||||
case ',': ++m_cursor; return { location, token_t::Comma };
|
||||
case '.': ++m_cursor; return { location, token_t::Dot };
|
||||
case '+': ++m_cursor; return { location, token_t::Plus };
|
||||
case '-': ++m_cursor; return { location, token_t::Minus };
|
||||
case '*': ++m_cursor; return { location, token_t::Star };
|
||||
case '/': ++m_cursor; return { location, token_t::Slash };
|
||||
case '%': ++m_cursor; return { location, token_t::Percent };
|
||||
case '"': {
|
||||
std::size_t begin = ++m_cursor;
|
||||
while (m_cursor < m_content.size() && m_content[m_cursor] != '"')
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace furc::front {
|
||||
|
||||
@@ -121,11 +122,7 @@ ast::node_handle<ast::statement_node> parser::parse_statement() {
|
||||
}
|
||||
|
||||
ast::node_handle<ast::expression_node> parser::parse_expression() {
|
||||
const auto& tok = peek_token();
|
||||
|
||||
auto literal = parse_literal();
|
||||
if (literal.present()) return std::move(literal);
|
||||
return { tok.location(), "unexpected token"s + tok->type + ", expected expression or literal" };
|
||||
return parse_expression_rhs(parse_expression_primary(), 16);
|
||||
}
|
||||
|
||||
ast::node_handle<ast::literal_node> parser::parse_literal() {
|
||||
@@ -149,6 +146,64 @@ ast::node_handle<ast::literal_node> parser::parse_literal() {
|
||||
return { tok.location(), "unexpected token "s + tok->type + ", expected literal" };
|
||||
}
|
||||
|
||||
enum class binop_associativity {
|
||||
Left,
|
||||
Right,
|
||||
};
|
||||
|
||||
struct binop_info {
|
||||
ast::binop_expression_node_t type;
|
||||
std::uint32_t precedence;
|
||||
binop_associativity associativity;
|
||||
|
||||
static binop_info left(ast::binop_expression_node_t type, std::uint32_t precedence) {
|
||||
return { type, precedence, binop_associativity::Left };
|
||||
}
|
||||
|
||||
static binop_info right(ast::binop_expression_node_t type, std::uint32_t precedence) {
|
||||
return { type, precedence, binop_associativity::Right };
|
||||
}
|
||||
};
|
||||
|
||||
ast::expression_node_h parser::parse_expression_primary() {
|
||||
const auto& tok = peek_token();
|
||||
|
||||
auto literal = parse_literal();
|
||||
if (literal.present()) return std::move(literal);
|
||||
return { tok.location(), "unexpected token"s + tok->type + ", expected expression or literal" };
|
||||
}
|
||||
|
||||
ast::expression_node_h parser::parse_expression_rhs(const ast::expression_node_h& init, std::uint32_t precedence) {
|
||||
static std::unordered_map<token_t, binop_info> s_binops = {
|
||||
{ token_t::Plus, binop_info::left(ast::binop_expression_node_t::Add, 5) },
|
||||
{ token_t::Minus, binop_info::left(ast::binop_expression_node_t::Sub, 5) },
|
||||
{ token_t::Star, binop_info::left(ast::binop_expression_node_t::Mul, 4) },
|
||||
{ token_t::Slash, binop_info::left(ast::binop_expression_node_t::Div, 4) },
|
||||
{ token_t::Percent, binop_info::left(ast::binop_expression_node_t::Mod, 5) },
|
||||
};
|
||||
|
||||
ast::expression_node_h lhs = init;
|
||||
while (true) {
|
||||
auto it = s_binops.find(peek_token()->type);
|
||||
if (it == s_binops.end()) return lhs;
|
||||
binop_info current = it->second;
|
||||
if (current.precedence >= precedence) return lhs;
|
||||
auto opToken = next_token();
|
||||
|
||||
auto rhs = parse_expression_primary();
|
||||
|
||||
auto nextIt = s_binops.find(peek_token()->type);
|
||||
if (nextIt != s_binops.end()) {
|
||||
binop_info next = nextIt->second;
|
||||
|
||||
rhs = std::move(parse_expression_rhs(rhs,
|
||||
current.precedence + static_cast<std::uint32_t>(current.associativity == binop_associativity::Right)));
|
||||
}
|
||||
|
||||
lhs = ast::binop_expression_node_h{ opToken.location(), m_arena, current.type, std::move(lhs), std::move(rhs) };
|
||||
}
|
||||
}
|
||||
|
||||
ast::function_body_handle parser::parse_body() {
|
||||
ast::function_body body;
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(void) {
|
||||
furc::front::parser parser("<TEMP>", "func main() {\n return 67;return \"uwu\";\n}");
|
||||
furc::front::parser parser("<TEMP>", "func main() {\n return 7 + 6 * 10; // 130\n}");
|
||||
std::cout << parser.parse() << '\n';
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user