implemented infix operator parsing

This commit is contained in:
Karma Riuk
2025-07-11 10:30:37 +02:00
parent 6e471a91d5
commit a7f5950a55
7 changed files with 155 additions and 6 deletions

View File

@@ -4,6 +4,13 @@
namespace ast { namespace ast {
infix_expr::infix_expr(
token::token token, std::string op, ast::expression* left
)
: token(std::move(token)),
op(op),
left(left) {}
std::string infix_expr::token_literal() const { std::string infix_expr::token_literal() const {
return token.literal; return token.literal;
} }

View File

@@ -5,6 +5,7 @@
namespace ast { namespace ast {
struct infix_expr : expression { struct infix_expr : expression {
infix_expr(token::token, std::string, ast::expression*);
token::token token; token::token token;
expression* left; expression* left;
std::string op; std::string op;

View File

@@ -2,6 +2,7 @@
#include "ast/errors/error.hpp" #include "ast/errors/error.hpp"
#include "ast/expressions/identifier.hpp" #include "ast/expressions/identifier.hpp"
#include "ast/expressions/infix.hpp"
#include "ast/expressions/integer.hpp" #include "ast/expressions/integer.hpp"
#include "ast/expressions/prefix.hpp" #include "ast/expressions/prefix.hpp"
#include "token/token.hpp" #include "token/token.hpp"
@@ -36,6 +37,40 @@ namespace parser {
token::type::MINUS, token::type::MINUS,
std::bind(&parser::parse_prefix_expr, this) std::bind(&parser::parse_prefix_expr, this)
); );
using namespace std::placeholders;
register_infix(
token::type::PLUS,
std::bind(&parser::parse_infix_expr, this, _1)
);
register_infix(
token::type::MINUS,
std::bind(&parser::parse_infix_expr, this, _1)
);
register_infix(
token::type::ASTERISK,
std::bind(&parser::parse_infix_expr, this, _1)
);
register_infix(
token::type::SLASH,
std::bind(&parser::parse_infix_expr, this, _1)
);
register_infix(
token::type::EQ,
std::bind(&parser::parse_infix_expr, this, _1)
);
register_infix(
token::type::NEQ,
std::bind(&parser::parse_infix_expr, this, _1)
);
register_infix(
token::type::GT,
std::bind(&parser::parse_infix_expr, this, _1)
);
register_infix(
token::type::LT,
std::bind(&parser::parse_infix_expr, this, _1)
);
} }
void parser::next_token() { void parser::next_token() {
@@ -72,15 +107,27 @@ namespace parser {
} }
} }
ast::expression* parser::parse_expression(precedence) { ast::expression* parser::parse_expression(precedence prec) {
auto it = prefix_parse_fns.find(current.type); auto prefix_it = prefix_parse_fns.find(current.type);
if (it == prefix_parse_fns.end()) { if (prefix_it == prefix_parse_fns.end()) {
unkown_prefix_error(current); unkown_prefix_error(current);
return nullptr; return nullptr;
} }
prefix_parse_fn func = it->second; prefix_parse_fn prefix = prefix_it->second;
return func(); ast::expression* left = prefix();
while (next.type != token::type::SEMICOLON
&& prec < precedence_for(next.type)) {
auto infix_it = infix_parse_fns.find(next.type);
if (infix_it == infix_parse_fns.end())
return left;
next_token();
infix_parse_fn infix = infix_it->second;
left = infix(left);
}
return left;
}; };
ast::return_stmt* parser::parse_return() { ast::return_stmt* parser::parse_return() {
@@ -178,4 +225,13 @@ namespace parser {
ret->right = parse_expression(precedence::PREFIX); ret->right = parse_expression(precedence::PREFIX);
return ret; return ret;
}; };
ast::expression* parser::parse_infix_expr(ast::expression* left) {
ast::infix_expr* ret =
new ast::infix_expr(current, current.literal, left);
precedence prec = precedence_for(current.type);
next_token();
ret->right = parse_expression(prec);
return ret;
};
} // namespace parser } // namespace parser

View File

@@ -49,5 +49,7 @@ namespace parser {
ast::expression* parse_identifier(); ast::expression* parse_identifier();
ast::expression* parse_integer(); ast::expression* parse_integer();
ast::expression* parse_prefix_expr(); ast::expression* parse_prefix_expr();
ast::expression* parse_infix_expr(ast::expression*);
}; };
} // namespace parser } // namespace parser

22
src/parser/precedence.cpp Normal file
View File

@@ -0,0 +1,22 @@
#include "precedence.hpp"
namespace parser {
precedence precedence_for(token::type type) {
switch (type) {
case token::type::EQ:
case token::type::NEQ:
return precedence::EQUALS;
case token::type::LT:
case token::type::GT:
return precedence::LESS_GREATER;
case token::type::PLUS:
case token::type::MINUS:
return precedence::SUM;
case token::type::ASTERISK:
case token::type::SLASH:
return precedence::PRODUCT;
default:
return precedence::LOWEST;
}
}
} // namespace parser

View File

@@ -1,3 +1,7 @@
#include "token/type.hpp"
#include <ostream>
namespace parser { namespace parser {
enum class precedence { enum class precedence {
LOWEST, LOWEST,
@@ -8,4 +12,10 @@ namespace parser {
PREFIX, PREFIX,
CALL CALL
}; };
}
precedence precedence_for(token::type);
inline std::ostream& operator<<(std::ostream& os, precedence& p) {
return os << static_cast<int>(p);
}
} // namespace parser

View File

@@ -0,0 +1,51 @@
#include "parser/parser.hpp"
#include <doctest.h>
TEST_SUITE("Precedence") {
TEST_CASE("Raw precedence") {
CHECK(parser::precedence::LOWEST < parser::precedence::EQUALS);
CHECK(parser::precedence::LOWEST < parser::precedence::LESS_GREATER);
CHECK(parser::precedence::LOWEST < parser::precedence::SUM);
CHECK(parser::precedence::LOWEST < parser::precedence::PRODUCT);
CHECK(parser::precedence::LOWEST < parser::precedence::PREFIX);
CHECK(parser::precedence::LOWEST < parser::precedence::CALL);
CHECK(parser::precedence::EQUALS < parser::precedence::LESS_GREATER);
CHECK(parser::precedence::EQUALS < parser::precedence::SUM);
CHECK(parser::precedence::EQUALS < parser::precedence::PRODUCT);
CHECK(parser::precedence::EQUALS < parser::precedence::PREFIX);
CHECK(parser::precedence::EQUALS < parser::precedence::CALL);
CHECK(parser::precedence::LESS_GREATER < parser::precedence::SUM);
CHECK(parser::precedence::LESS_GREATER < parser::precedence::PRODUCT);
CHECK(parser::precedence::LESS_GREATER < parser::precedence::PREFIX);
CHECK(parser::precedence::LESS_GREATER < parser::precedence::CALL);
CHECK(parser::precedence::SUM < parser::precedence::PRODUCT);
CHECK(parser::precedence::SUM < parser::precedence::PREFIX);
CHECK(parser::precedence::SUM < parser::precedence::CALL);
CHECK(parser::precedence::PRODUCT < parser::precedence::PREFIX);
CHECK(parser::precedence::PRODUCT < parser::precedence::CALL);
CHECK(parser::precedence::PREFIX < parser::precedence::CALL);
}
TEST_CASE("Operator precedence") {
auto& prec = parser::precedence_for;
CHECK(prec(token::type::EQ) == prec(token::type::NEQ));
CHECK(prec(token::type::LT) == prec(token::type::GT));
CHECK(prec(token::type::PLUS) == prec(token::type::MINUS));
CHECK(prec(token::type::ASTERISK) == prec(token::type::SLASH));
CHECK(prec(token::type::EQ) < prec(token::type::LT));
CHECK(prec(token::type::EQ) < prec(token::type::PLUS));
CHECK(prec(token::type::EQ) < prec(token::type::ASTERISK));
CHECK(prec(token::type::LT) < prec(token::type::PLUS));
CHECK(prec(token::type::LT) < prec(token::type::ASTERISK));
CHECK(prec(token::type::PLUS) < prec(token::type::ASTERISK));
}
}