From 6d43c1316cf2e7f438c6ca73a43b63d063d7029f Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Tue, 31 Dec 2019 20:51:34 +0300 Subject: parser: support unary + --- server/parser/parser.hpp | 24 ++++++++++++++++++------ test/unit_tests/parser.cpp | 23 ++++++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/server/parser/parser.hpp b/server/parser/parser.hpp index 7d6f31d..fb2a5ff 100644 --- a/server/parser/parser.hpp +++ b/server/parser/parser.hpp @@ -36,7 +36,7 @@ public: private: double exec_expr() { - return exec_expr(exec_primary(), parser::BinaryOp::min_precedence()); + return exec_expr(exec_factor(), parser::BinaryOp::min_precedence()); } double exec_expr(double lhs, unsigned min_prec) { @@ -45,7 +45,7 @@ private: const auto prev_prec = prev.get_precedence(); m_lexer.drop_token(); - auto rhs = exec_primary(); + auto rhs = exec_factor(); for (op = peek_operator(); op.has_value(); op = peek_operator()) { const auto next = *op; @@ -77,16 +77,28 @@ private: return parser::BinaryOp::from_token(*token); } - double exec_primary() { + double exec_factor() { if (!m_lexer.has_token()) { - throw ParserError{"expected '-', '(' or a number"}; + throw ParserError{"expected '-', '+', '(' or a number"}; } using Type = lexer::Token::Type; if (m_lexer.drop_token_of_type(Type::MINUS).has_value()) { - return -exec_primary(); + return -exec_factor(); } + if (m_lexer.drop_token_of_type(Type::PLUS).has_value()) { + return exec_factor(); + } + return exec_atom(); + } + + double exec_atom() { + if (!m_lexer.has_token()) { + throw ParserError{"expected '-', '+', '(' or a number"}; + } + + using Type = lexer::Token::Type; if (m_lexer.drop_token_of_type(Type::LEFT_PAREN).has_value()) { const auto inner = exec_expr(); @@ -100,7 +112,7 @@ private: return token.value().as_number(); } - throw ParserError{"expected '-', '(' or a number"}; + throw ParserError{"expected '-', '+', '(' or a number"}; } Lexer m_lexer; diff --git a/test/unit_tests/parser.cpp b/test/unit_tests/parser.cpp index 37d9e0a..594e162 100644 --- a/test/unit_tests/parser.cpp +++ b/test/unit_tests/parser.cpp @@ -24,20 +24,31 @@ namespace { namespace exec::valid { const std::vector input{ + // Constants and unary operators: "1", + "-1", + "--1", + "+--+-2", + // Basic binary operators: " 1 + 2 ", " 2 * 1 + 3 ", " 2 * (1 + 3) ", " 2 * (1 + 3 * (1 - -3)) ", - " -2 * ---- (3 + -100e-1) ", // Looks weird, but also works in e.g. Python + // Looks weird, but also works in e.g. Python: + " -2 * -+--- (3 + -100e-1) ", + // Power operator is right-associative: "2 ^ 3 ^ 3", - "(2 ^ 3) ^ 3", // Power operator is right-associative + "(2 ^ 3) ^ 3", + // Power operator has higher precedence than the unary minus: "(.5 ^ -1) ^ 4", - ".5 ^ -1 ^ 4", // Power operator has higher precedence than the unary minus + ".5 ^ -1 ^ 4", }; const std::vector expected{ 1, + -1, + 1, + -2, 3, 5, 8, @@ -55,14 +66,16 @@ namespace exec::invalid { const std::vector input{ "", + // Missing operand: " 1 + ", + // Unmatched parentheses: " 2 * (1 + 3 ", " 2 * (1 + 3) )", }; const std::vector error_msg{ - "server error: parser error: expected '-', '(' or a number", - "server error: parser error: expected '-', '(' or a number", + "server error: parser error: expected '-', '+', '(' or a number", + "server error: parser error: expected '-', '+', '(' or a number", "server error: parser error: missing closing ')'", "server error: parser error: expected a binary operator", }; -- cgit v1.2.3