ADD: cmp operations.

main
bog 2023-09-29 20:11:39 +02:00
parent 335189c31c
commit 217f5c2f92
8 changed files with 216 additions and 17 deletions

View File

@ -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)*)?

View File

@ -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()

View File

@ -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);

View File

@ -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
{

View File

@ -243,7 +243,71 @@ namespace wg
std::shared_ptr<Node> Parser::parse_expr()
{
return parse_addsub();
return parse_or();
}
std::shared_ptr<Node> 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<Node> 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<Node> 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<Node> 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<Node> 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();

View File

@ -38,6 +38,11 @@ namespace wg
std::shared_ptr<Node> parse_dir();
std::shared_ptr<Node> parse_expr();
std::shared_ptr<Node> parse_or();
std::shared_ptr<Node> parse_and();
std::shared_ptr<Node> parse_eqne();
std::shared_ptr<Node> parse_cmp();
std::shared_ptr<Node> parse_addsub();
std::shared_ptr<Node> parse_muldivmod();

View File

@ -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);
}

View File

@ -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; ");
}