From 217f5c2f928c7095b35a69e39a2c78cdef47984b Mon Sep 17 00:00:00 2001 From: bog Date: Fri, 29 Sep 2023 20:11:39 +0200 Subject: [PATCH] ADD: cmp operations. --- doc/grammar.bnf | 8 +++++- lib/Compiler.cpp | 59 ++++++++++++++++++++++++++++++++++++++ lib/Lexer.cpp | 13 +++++++++ lib/Node.hpp | 32 +++++++++++---------- lib/Parser.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++++++- lib/Parser.hpp | 5 ++++ tests/Lexer.cpp | 27 ++++++++++++++++++ tests/Parser.cpp | 15 ++++++++++ 8 files changed, 216 insertions(+), 17 deletions(-) diff --git a/doc/grammar.bnf b/doc/grammar.bnf index a2fdb80..b05552e 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -14,8 +14,13 @@ BLOCK ::= obrace INSTR* cbrace DIR ::= hash ident EXPR (as ident)? EXPR ::= -| ADDSUB +| OR +OR ::= AND (or AND)* +AND ::= EQNE (and EQNE)* + +EQNE ::= CMP ((eq|ne) CMP)? +CMP ::= ADDSUB ((lt|le|gt|ge) ADDSUB)? ADDSUB ::= MULDIVMOD ((add|sub) MULDIVMOD)* MULDIVMOD ::= LITERAL ((mul|div|mod) LITERAL)* @@ -25,6 +30,7 @@ LITERAL ::= | int | CALL | NS +| not LITERAL CALL ::= ident opar ARGS cpar ARGS ::= (EXPR (comma EXPR)*)? diff --git a/lib/Compiler.cpp b/lib/Compiler.cpp index 378a069..1805ca1 100644 --- a/lib/Compiler.cpp +++ b/lib/Compiler.cpp @@ -377,6 +377,65 @@ namespace wg true)); } break; + case NODE_BOOL: { + return llvm::ConstantInt::getBool(m_mod.context(), + node->repr() == "true"); + } break; + + case NODE_AND: { + auto lhs = compile(node->child(0)); + auto rhs = compile(node->child(1)); + return m_builder->CreateAnd(lhs, rhs); + } break; + + case NODE_OR: { + auto lhs = compile(node->child(0)); + auto rhs = compile(node->child(1)); + return m_builder->CreateOr(lhs, rhs); + } break; + + case NODE_NOT: { + auto lhs = compile(node->child(0)); + return m_builder->CreateNot(lhs); + } break; + + case NODE_EQ: { + auto lhs = compile(node->child(0)); + auto rhs = compile(node->child(1)); + return m_builder->CreateICmpEQ(lhs, rhs); + } break; + + case NODE_NE: { + auto lhs = compile(node->child(0)); + auto rhs = compile(node->child(1)); + return m_builder->CreateICmpNE(lhs, rhs); + } break; + + case NODE_LT: { + auto lhs = compile(node->child(0)); + auto rhs = compile(node->child(1)); + return m_builder->CreateICmpSLT(lhs, rhs); + } break; + + case NODE_LE: { + auto lhs = compile(node->child(0)); + auto rhs = compile(node->child(1)); + return m_builder->CreateICmpSLE(lhs, rhs); + } break; + + case NODE_GT: { + auto lhs = compile(node->child(0)); + auto rhs = compile(node->child(1)); + return m_builder->CreateICmpSGT(lhs, rhs); + } break; + + + case NODE_GE: { + auto lhs = compile(node->child(0)); + auto rhs = compile(node->child(1)); + return m_builder->CreateICmpSGE(lhs, rhs); + } break; + default: WG_ASSERT(false, std::string() diff --git a/lib/Lexer.cpp b/lib/Lexer.cpp index 10587aa..5cbd33d 100644 --- a/lib/Lexer.cpp +++ b/lib/Lexer.cpp @@ -5,11 +5,24 @@ namespace wg { /*explicit*/ Lexer::Lexer() { + add_keyword("true", NODE_BOOL, true); + add_keyword("false", NODE_BOOL, true); add_keyword("as", NODE_AS); add_keyword("int", NODE_TYPE, true); add_keyword("fun", NODE_FUN); add_keyword("return", NODE_RETURN); add_keyword("extern", NODE_EXTERN); + add_keyword("and", NODE_AND); + add_keyword("or", NODE_OR); + add_keyword("not", NODE_NOT); + + add_text("==", NODE_EQ); + add_text("<>", NODE_NE); + + add_text("<", NODE_LT); + add_text("<=", NODE_LE); + add_text(">", NODE_GT); + add_text(">=", NODE_GE); add_text(".", NODE_DOT); add_text("{", NODE_OBRACE); diff --git a/lib/Node.hpp b/lib/Node.hpp index a13897e..3c71cf2 100644 --- a/lib/Node.hpp +++ b/lib/Node.hpp @@ -4,21 +4,23 @@ #include "commons.hpp" #include "Loc.hpp" -#define NODE_TYPES(G) \ - G(NODE_PROG), \ - G(NODE_IDENT), \ - G(NODE_HASH), \ - G(NODE_DIR), \ - G(NODE_INT), \ - G(NODE_ADD), G(NODE_SUB), \ - G(NODE_MUL),G(NODE_DIV), \ - G(NODE_MOD), G(NODE_OPAR), G(NODE_CPAR), \ - G(NODE_SEMICOLON), G(NODE_COMMA), G(NODE_CALL), \ - G(NODE_ARGS), G(NODE_TYPE), G(NODE_RETURN), \ - G(NODE_FUN), G(NODE_PARAMS), G(NODE_BLOCK), \ - G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_FUNDECL), \ - G(NODE_EXTERN), G(NODE_RET), G(NODE_DOT), G(NODE_NS), \ - G(NODE_AS) +#define NODE_TYPES(G) \ + G(NODE_PROG), \ + G(NODE_IDENT), \ + G(NODE_HASH), \ + G(NODE_DIR), \ + G(NODE_INT), \ + G(NODE_ADD), G(NODE_SUB), \ + G(NODE_MUL),G(NODE_DIV), \ + G(NODE_MOD), G(NODE_OPAR), G(NODE_CPAR), \ + G(NODE_SEMICOLON), G(NODE_COMMA), G(NODE_CALL), \ + G(NODE_ARGS), G(NODE_TYPE), G(NODE_RETURN), \ + G(NODE_FUN), G(NODE_PARAMS), G(NODE_BLOCK), \ + G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_FUNDECL), \ + G(NODE_EXTERN), G(NODE_RET), G(NODE_DOT), G(NODE_NS), \ + G(NODE_AS), G(NODE_BOOL), G(NODE_AND), G(NODE_OR), \ + G(NODE_NOT), G(NODE_EQ), G(NODE_NE), G(NODE_LT), G(NODE_GT), \ + G(NODE_LE), G(NODE_GE) namespace wg { diff --git a/lib/Parser.cpp b/lib/Parser.cpp index a4a3880..5ecad16 100644 --- a/lib/Parser.cpp +++ b/lib/Parser.cpp @@ -243,7 +243,71 @@ namespace wg std::shared_ptr Parser::parse_expr() { - return parse_addsub(); + return parse_or(); + } + + std::shared_ptr Parser::parse_or() + { + auto lhs = parse_and(); + + while (type_is(NODE_OR)) + { + auto node = consume(); + node->add_child(lhs); + node->add_child(parse_and()); + lhs = node; + } + + return lhs; + } + + std::shared_ptr Parser::parse_and() + { + auto lhs = parse_eqne(); + + while (type_is(NODE_AND)) + { + auto node = consume(); + node->add_child(lhs); + node->add_child(parse_eqne()); + lhs = node; + } + + return lhs; + } + + std::shared_ptr Parser::parse_eqne() + { + auto lhs = parse_cmp(); + + if (type_is(NODE_EQ) + || type_is(NODE_NE)) + { + auto node = consume(); + node->add_child(lhs); + node->add_child(parse_cmp()); + lhs = node; + } + + return lhs; + } + + std::shared_ptr Parser::parse_cmp() + { + auto lhs = parse_addsub(); + + if (type_is(NODE_LT) + || type_is(NODE_LE) + || type_is(NODE_GT) + || type_is(NODE_GE)) + { + auto node = consume(); + node->add_child(lhs); + node->add_child(parse_addsub()); + lhs = node; + } + + return lhs; } std::shared_ptr Parser::parse_addsub() @@ -293,7 +357,15 @@ namespace wg return parse_ns(); } + if (type_is(NODE_NOT)) + { + auto node = consume(); + node->add_child(parse_literal()); + return node; + } + if (type_is(NODE_INT) + || type_is(NODE_BOOL) || type_is(NODE_IDENT)) { return consume(); diff --git a/lib/Parser.hpp b/lib/Parser.hpp index b286826..a6fc4b9 100644 --- a/lib/Parser.hpp +++ b/lib/Parser.hpp @@ -38,6 +38,11 @@ namespace wg std::shared_ptr parse_dir(); std::shared_ptr parse_expr(); + std::shared_ptr parse_or(); + std::shared_ptr parse_and(); + + std::shared_ptr parse_eqne(); + std::shared_ptr parse_cmp(); std::shared_ptr parse_addsub(); std::shared_ptr parse_muldivmod(); diff --git a/tests/Lexer.cpp b/tests/Lexer.cpp index bb364c7..6674220 100644 --- a/tests/Lexer.cpp +++ b/tests/Lexer.cpp @@ -84,3 +84,30 @@ TEST_CASE_METHOD(LexerTest, "Lexer_as") test_next(lex, "AS"); test_end(lex); } + +TEST_CASE_METHOD(LexerTest, "Lexer_bool") +{ + wg::Lexer lex; + lex.scan(" true and false or not afalse truea "); + test_next(lex, "BOOL[true]"); + test_next(lex, "AND"); + test_next(lex, "BOOL[false]"); + test_next(lex, "OR"); + test_next(lex, "NOT"); + test_next(lex, "IDENT[afalse]"); + test_next(lex, "IDENT[truea]"); + test_end(lex); +} + +TEST_CASE_METHOD(LexerTest, "Lexer_cmp") +{ + wg::Lexer lex; + lex.scan(" == <> < <= > >= "); + test_next(lex, "EQ"); + test_next(lex, "NE"); + test_next(lex, "LT"); + test_next(lex, "LE"); + test_next(lex, "GT"); + test_next(lex, "GE"); + test_end(lex); +} diff --git a/tests/Parser.cpp b/tests/Parser.cpp index 9d4c3c0..a635888 100644 --- a/tests/Parser.cpp +++ b/tests/Parser.cpp @@ -103,3 +103,18 @@ TEST_CASE_METHOD(ParserTest, "Parser_namespace") "CALL(IDENT[d],ARGS)))", " a.b.c.d(); "); } + +TEST_CASE_METHOD(ParserTest, "Parser_bool") +{ + test_parse("PROG(OR(AND(NOT(BOOL[true]),BOOL[false]),BOOL[true]))", + " not true and false or true; "); +} + +TEST_CASE_METHOD(ParserTest, "Parser_comparisons") +{ + test_parse("PROG(AND(EQ(INT[7],INT[3]),LT(INT[3],INT[7])))", + " 7 == 3 and 3 < 7; "); + + test_parse("PROG(OR(NE(INT[7],INT[3]),GE(INT[3],INT[7])))", + " 7 <> 3 or 3 >= 7; "); +}