From b07ece568d8d62ca80a8ba3b43fb46a98e117d5a Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Sat, 23 Oct 2021 18:19:14 +0200 Subject: Add logic operations --- src/bytecode/compiler.h | 88 +++++++++++++++++++++++++++++++++++++++++-------- src/bytecode/lexer.c | 16 ++++----- src/bytecode/lexer.h | 8 ++--- src/bytecode/ops.h | 8 +++++ src/bytecode/vm.h | 43 ++++++++++++++++++++++++ 5 files changed, 137 insertions(+), 26 deletions(-) (limited to 'src/bytecode') diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h index fd5cdbc..6f43416 100755 --- a/src/bytecode/compiler.h +++ b/src/bytecode/compiler.h @@ -58,7 +58,7 @@ parse_fixnum(Chunk *chunk, Token tok) { void parse_tree(Chunk *chunk, Visitor *vs); void -compile_list_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { +compile_list_binary_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { size_t n = 0; while (has_next_token(vs)) { Token tok = peek_token(vs); @@ -73,7 +73,15 @@ compile_list_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { } if (tok.type == TOKEN_RPAREN) { next_token(vs); - break; + if (n <= 1) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_NOT_ENOUGH_ARGS, + .line = list_start.line, + .col = list_start.column, + }); + } + return; } parse_tree(chunk, vs); n++; @@ -81,14 +89,58 @@ compile_list_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { add_code(chunk, op, list_start.line, list_start.column); } } - if (n == 0) { - error_push((Error){ - .type = ERR_TYPE_COMPILER, - .value = ERR_NOT_ENOUGH_ARGS, - .line = list_start.line, - .col = list_start.column, - }); + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_NOT_ENOUGH_ARGS, + .line = list_start.line, + .col = list_start.column, + }); +} + +void +compile_list_unary_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { + size_t n = 0; + while (has_next_token(vs)) { + Token tok = peek_token(vs); + if (tok.type == TOKEN_EOF) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_UNBALANCED_PAREN, + .line = list_start.line, + .col = list_start.column, + }); + return; + } + if (tok.type == TOKEN_RPAREN) { + next_token(vs); + if (n == 0) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_NOT_ENOUGH_ARGS, + .line = list_start.line, + .col = list_start.column, + }); + } + return; + } + parse_tree(chunk, vs); + add_code(chunk, op, list_start.line, list_start.column); + n++; + if (n > 1) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_TOO_MANY_ARGS, + .line = list_start.line, + .col = list_start.column, + }); + } } + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_UNBALANCED_PAREN, + .line = list_start.line, + .col = list_start.column, + }); } void @@ -103,11 +155,19 @@ parse_list(Chunk *chunk, Visitor *vs, Token list_start) { } Token tok = next_token(vs); switch (tok.type) { - case TOKEN_ADD: { compile_list_op(chunk, vs, list_start, OP_SUM); } break; - case TOKEN_SUB: { compile_list_op(chunk, vs, list_start, OP_SUB); } break; - case TOKEN_MUL: { compile_list_op(chunk, vs, list_start, OP_MUL); } break; - case TOKEN_DIV: { compile_list_op(chunk, vs, list_start, OP_DIV); } break; - case TOKEN_MOD: { compile_list_op(chunk, vs, list_start, OP_MOD); } break; + case TOKEN_ADD: { compile_list_binary_op(chunk, vs, list_start, OP_SUM); } break; + case TOKEN_SUB: { compile_list_binary_op(chunk, vs, list_start, OP_SUB); } break; + case TOKEN_MUL: { compile_list_binary_op(chunk, vs, list_start, OP_MUL); } break; + case TOKEN_DIV: { compile_list_binary_op(chunk, vs, list_start, OP_DIV); } break; + case TOKEN_MOD: { compile_list_binary_op(chunk, vs, list_start, OP_MOD); } break; + case TOKEN_NOT: { compile_list_unary_op(chunk, vs, list_start, OP_NOT); } break; + case TOKEN_AND: { compile_list_binary_op(chunk, vs, list_start, OP_AND); } break; + case TOKEN_OR: { compile_list_binary_op(chunk, vs, list_start, OP_OR); } break; + case TOKEN_EQUAL: { compile_list_binary_op(chunk, vs, list_start, OP_EQUAL); } break; + case TOKEN_LESS: { compile_list_binary_op(chunk, vs, list_start, OP_LESS); } break; + case TOKEN_GREATER: { compile_list_binary_op(chunk, vs, list_start, OP_GREATER); } break; + case TOKEN_LESS_EQUAL: { compile_list_binary_op(chunk, vs, list_start, OP_LESS_EQUAL); } break; + case TOKEN_GREATER_EQUAL: { compile_list_binary_op(chunk, vs, list_start, OP_GREATER_EQUAL); } break; default: { error_push((Error){ .type = ERR_TYPE_COMPILER, diff --git a/src/bytecode/lexer.c b/src/bytecode/lexer.c index bc2dd9d..207cebb 100755 --- a/src/bytecode/lexer.c +++ b/src/bytecode/lexer.c @@ -25,10 +25,10 @@ static const char* token_str[] = { [TOKEN_AND] = "TOKEN_AND", [TOKEN_OR] = "TOKEN_OR", [TOKEN_EQUAL] = "TOKEN_EQUAL", - [TOKEN_LESS_THAN] = "TOKEN_LESS_THAN", - [TOKEN_GREATER_THAN] = "TOKEN_GREATER_THAN", - [TOKEN_LESS_EQUAL_THAN] = "TOKEN_LESS_EQUAL_THAN", - [TOKEN_GREATER_EQUAL_THAN] = "TOKEN_GREATER_EQUAL_THAN", + [TOKEN_LESS] = "TOKEN_LESS", + [TOKEN_GREATER] = "TOKEN_GREATER", + [TOKEN_LESS_EQUAL] = "TOKEN_LESS_EQUAL", + [TOKEN_GREATER_EQUAL] = "TOKEN_GREATER_EQUAL", [TOKEN_EOF] = "TOKEN_EOF", }; @@ -155,10 +155,10 @@ find_primitive_type(const StringView value) { if (TOKEN_IS_KEYWORD(value, "and")) { return TOKEN_AND; } if (TOKEN_IS_KEYWORD(value, "or")) { return TOKEN_OR; } if (TOKEN_IS_KEYWORD(value, "=")) { return TOKEN_EQUAL; } - if (TOKEN_IS_KEYWORD(value, "<")) { return TOKEN_LESS_THAN; } - if (TOKEN_IS_KEYWORD(value, ">")) { return TOKEN_GREATER_THAN; } - if (TOKEN_IS_KEYWORD(value, "<=")) { return TOKEN_LESS_EQUAL_THAN; } - if (TOKEN_IS_KEYWORD(value, ">=")) { return TOKEN_GREATER_EQUAL_THAN; } + if (TOKEN_IS_KEYWORD(value, "<")) { return TOKEN_LESS; } + if (TOKEN_IS_KEYWORD(value, ">")) { return TOKEN_GREATER; } + if (TOKEN_IS_KEYWORD(value, "<=")) { return TOKEN_LESS_EQUAL; } + if (TOKEN_IS_KEYWORD(value, ">=")) { return TOKEN_GREATER_EQUAL; } return TOKEN_SYMBOL; } diff --git a/src/bytecode/lexer.h b/src/bytecode/lexer.h index 47fd384..cee2915 100755 --- a/src/bytecode/lexer.h +++ b/src/bytecode/lexer.h @@ -38,10 +38,10 @@ typedef enum TokenType { TOKEN_AND, TOKEN_OR, TOKEN_EQUAL, - TOKEN_LESS_THAN, - TOKEN_GREATER_THAN, - TOKEN_LESS_EQUAL_THAN, - TOKEN_GREATER_EQUAL_THAN, + TOKEN_LESS, + TOKEN_GREATER, + TOKEN_LESS_EQUAL, + TOKEN_GREATER_EQUAL, TOKEN_EOF, } TokenType; diff --git a/src/bytecode/ops.h b/src/bytecode/ops.h index b58631f..b59d65a 100755 --- a/src/bytecode/ops.h +++ b/src/bytecode/ops.h @@ -8,6 +8,14 @@ typedef enum Ops { OP_MUL, OP_DIV, OP_MOD, + OP_NOT, + OP_AND, + OP_OR, + OP_EQUAL, + OP_LESS, + OP_GREATER, + OP_LESS_EQUAL, + OP_GREATER_EQUAL, OP_RETURN, } Ops; diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h index 9b68fc1..c94e22b 100755 --- a/src/bytecode/vm.h +++ b/src/bytecode/vm.h @@ -59,6 +59,35 @@ vm_reset(VM *vm) { array_push(vm->stack, FIXNUM_VAL(y OP x)); \ } while (false) +#define FIXNUM_CMP_OP(OP) \ + do { \ + Object a = array_pop(vm->stack); \ + Object b = array_pop(vm->stack); \ + if (!IS_FIXNUM(a) || !IS_FIXNUM(b)) { \ + error_push((Error){ \ + .type = ERR_TYPE_RUNTIME, \ + .value = ERR_WRONG_ARG_TYPE, \ + .line = vm->chunk->lines[vm->pc - vm->chunk->code - 1].line, \ + .col = vm->chunk->lines[vm->pc - vm->chunk->code - 1].col, \ + }); \ + return; \ + } \ + ssize_t x = AS_FIXNUM(a); \ + ssize_t y = AS_FIXNUM(b); \ + Object result = y OP x ? TRUE_VAL : FALSE_VAL; \ + array_push(vm->stack, result); \ + } while (false) + +#define LOGIC_OP(OP) \ + do { \ + Object a = array_pop(vm->stack); \ + Object b = array_pop(vm->stack); \ + bool x = IS_TRUE(a); \ + bool y = IS_TRUE(b); \ + Object result = y OP x ? TRUE_VAL : FALSE_VAL; \ + array_push(vm->stack, result); \ + } while (false) + void vm_interpret(VM *vm, Chunk *chunk) { vm->chunk = chunk; @@ -97,6 +126,18 @@ vm_interpret(VM *vm, Chunk *chunk) { case OP_MUL: { FIXNUM_BINARY_OP(*); } break; case OP_DIV: { FIXNUM_BINARY_OP(/); } break; case OP_MOD: { FIXNUM_BINARY_OP(%); } break; + case OP_NOT: { + Object prev = array_pop(vm->stack); + Object new = IS_TRUE(prev) ? FALSE_VAL : TRUE_VAL; + array_push(vm->stack, new); + } break; + case OP_AND: { LOGIC_OP(&&); } break; + case OP_OR: { LOGIC_OP(||); } break; + case OP_EQUAL: { FIXNUM_CMP_OP(==); } break; + case OP_LESS: { FIXNUM_CMP_OP(<); } break; + case OP_GREATER: { FIXNUM_CMP_OP(>); } break; + case OP_LESS_EQUAL: { FIXNUM_CMP_OP(<=); } break; + case OP_GREATER_EQUAL: { FIXNUM_CMP_OP(>=); } break; case OP_RETURN: { display(array_pop(vm->stack)); printf("\n"); @@ -123,5 +164,7 @@ vm_interpret(VM *vm, Chunk *chunk) { } #undef FIXNUM_BINARY_OP +#undef FIXNUM_CMP_OP +#undef LOGIC_OP #endif // BDL_VM_H -- cgit v1.2.1