From: Brendan Hansen Date: Sat, 20 Jun 2020 02:38:04 +0000 (-0500) Subject: Added bin ops with precedence; bug fixes X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=f7489e89e73d10dce694f599a6b29b02480b6aa2;p=onyx.git Added bin ops with precedence; bug fixes --- diff --git a/include/onyxparser.h b/include/onyxparser.h index df4adab6..91dc48ff 100644 --- a/include/onyxparser.h +++ b/include/onyxparser.h @@ -21,10 +21,6 @@ typedef struct OnyxParser { OnyxToken *prev_token; OnyxToken *curr_token; - // BUG: This way of handling identifiers will work for now, - // but it will not allow for shadowing. Also, variable names - // cannot be the same as any function or global variable. - // That will get annoying to program. // NOTE: A table of the current identifiers in the current scope. // If the identifier doesn't at the time of parsing, it is an error. // Cleared at the end of a block. diff --git a/include/onyxutils.h b/include/onyxutils.h index 63b6f601..a63e4558 100644 --- a/include/onyxutils.h +++ b/include/onyxutils.h @@ -2,4 +2,7 @@ #include "onyxparser.h" +extern bh_scratch global_scratch; +extern bh_allocator global_scratch_allocator; + void onyx_ast_print(OnyxAstNode* program, i32 indent); diff --git a/onyx b/onyx index 86ccaf9e..59fdd5b4 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/minimal.onyx b/progs/minimal.onyx index 0218c517..a78a82af 100644 --- a/progs/minimal.onyx +++ b/progs/minimal.onyx @@ -16,18 +16,18 @@ diff_square :: proc (a i32, b i32) -> i32 { c := a - b; // Mutable d :: a + b; // Constant - return (c * d) as i32; + return c * d; } export do_stuff :: proc -> i32 { res := diff_square((4 + 5) as i32, (2 + 3) as i32); res = res + foo(); - // res should be 66 - return res * (0 - 1); + // res should be -66 + return res * -1; } -export float_test :: proc -> f32 { - return (1.2f + 5.3f); +float_test :: proc -> f32 { + return 3.14159f; } export main :: proc { diff --git a/src/onyx.c b/src/onyx.c index 5a07b655..816a38a7 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -9,6 +9,12 @@ #include "onyxwasm.h" int main(int argc, char *argv[]) { + + bh_allocator alloc = bh_heap_allocator(); + + bh_scratch_init(&global_scratch, alloc, 16 * 1024); // NOTE: 16 KB + global_scratch_allocator = bh_scratch_allocator(&global_scratch); + bh_file source_file; bh_file_error err = bh_file_open(&source_file, argv[1]); if (err != BH_FILE_ERROR_NONE) { @@ -16,8 +22,6 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - bh_allocator alloc = bh_heap_allocator(); - // NOTE: 1st: Read file contents bh_file_contents fc = bh_file_read_contents(alloc, &source_file); bh_file_close(&source_file); @@ -51,7 +55,7 @@ int main(int argc, char *argv[]) { onyx_message_print(&msgs); goto main_exit; } else { - onyx_ast_print(program, 0); + // onyx_ast_print(program, 0); bh_printf("\nNo errors.\n"); } diff --git a/src/onyxparser.c b/src/onyxparser.c index 4a65939a..9cdbda49 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -1,6 +1,7 @@ #include "onyxlex.h" #include "onyxmsgs.h" #include "onyxparser.h" +#include "onyxutils.h" static const char* ast_node_names[] = { "ERROR", @@ -240,6 +241,22 @@ static OnyxAstNode* parse_factor(OnyxParser* parser) { return expr; } + case TOKEN_TYPE_SYM_MINUS: + { + parser_next_token(parser); + OnyxAstNode* factor = parse_factor(parser); + + OnyxAstNode* negate_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_NEGATE); + negate_node->left = factor; + negate_node->type = factor->type; + + if ((factor->flags & ONYX_AST_FLAG_COMPTIME) != 0) { + negate_node->flags |= ONYX_AST_FLAG_COMPTIME; + } + + return negate_node; + } + case TOKEN_TYPE_SYMBOL: { OnyxToken* sym_token = expect(parser, TOKEN_TYPE_SYMBOL); @@ -310,82 +327,89 @@ static OnyxAstNode* parse_factor(OnyxParser* parser) { return NULL; } -static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left) { - OnyxAstNodeKind kind = -1; - - switch (parser->curr_token->type) { - case TOKEN_TYPE_SYM_PLUS: kind = ONYX_AST_NODE_KIND_ADD; break; - case TOKEN_TYPE_SYM_MINUS: kind = ONYX_AST_NODE_KIND_MINUS; break; - case TOKEN_TYPE_SYM_STAR: kind = ONYX_AST_NODE_KIND_MULTIPLY; break; - case TOKEN_TYPE_SYM_FSLASH: kind = ONYX_AST_NODE_KIND_DIVIDE; break; - case TOKEN_TYPE_SYM_PERCENT: kind = ONYX_AST_NODE_KIND_MODULUS; break; - default: break; - } - - if (kind != -1) { - OnyxToken* bin_op_tok = parser->curr_token; - parser_next_token(parser); - - OnyxAstNode* right = parse_factor(parser); - - // NOTE: Typechecking like this will not be here for long but - // want to start working on it early - if (left->type != right->type) { - onyx_message_add(parser->msgs, - ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE, - bin_op_tok->pos, - left->type->name, right->type->name); - return &error_node; - } - - OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, kind); - bin_op->left = left; - bin_op->right = right; - bin_op->type = left->type; - - if ((left->flags & ONYX_AST_FLAG_COMPTIME) != 0 && (right->flags & ONYX_AST_FLAG_COMPTIME) != 0) { - bin_op->flags |= ONYX_AST_FLAG_COMPTIME; - } - - return bin_op; - } - - return &error_node; +static inline i32 get_precedence(OnyxAstNodeKind kind) { + switch (kind) { + case ONYX_AST_NODE_KIND_ADD: return 1; + case ONYX_AST_NODE_KIND_MINUS: return 1; + case ONYX_AST_NODE_KIND_MULTIPLY: return 2; + case ONYX_AST_NODE_KIND_DIVIDE: return 2; + case ONYX_AST_NODE_KIND_MODULUS: return 3; + case ONYX_AST_NODE_KIND_CAST: return 4; + default: return -1; + } } static OnyxAstNode* parse_expression(OnyxParser* parser) { - OnyxAstNode* left = parse_factor(parser); + bh_arr(OnyxAstNode*) tree_stack = NULL; + bh_arr_new(global_scratch_allocator, tree_stack, 4); + bh_arr_set_length(tree_stack, 0); - switch (parser->curr_token->type) { - case TOKEN_TYPE_SYM_PLUS: - case TOKEN_TYPE_SYM_MINUS: - case TOKEN_TYPE_SYM_STAR: - case TOKEN_TYPE_SYM_FSLASH: - case TOKEN_TYPE_SYM_PERCENT: - { - OnyxAstNode* expr = parse_bin_op(parser, left); - return expr; - } - case TOKEN_TYPE_KEYWORD_CAST: - { - parser_next_token(parser); - OnyxTypeInfo* type = parse_type(parser); + OnyxAstNode* left = parse_factor(parser); + OnyxAstNode* right; + OnyxAstNode* root = left; + + i32 bin_op_kind; + OnyxToken* bin_op_tok; + + while (1) { + bin_op_kind = -1; + switch (parser->curr_token->type) { + case TOKEN_TYPE_SYM_PLUS: bin_op_kind = ONYX_AST_NODE_KIND_ADD; break; + case TOKEN_TYPE_SYM_MINUS: bin_op_kind = ONYX_AST_NODE_KIND_MINUS; break; + case TOKEN_TYPE_SYM_STAR: bin_op_kind = ONYX_AST_NODE_KIND_MULTIPLY; break; + case TOKEN_TYPE_SYM_FSLASH: bin_op_kind = ONYX_AST_NODE_KIND_DIVIDE; break; + case TOKEN_TYPE_SYM_PERCENT: bin_op_kind = ONYX_AST_NODE_KIND_MODULUS; break; + case TOKEN_TYPE_KEYWORD_CAST: bin_op_kind = ONYX_AST_NODE_KIND_CAST; break; + default: goto expression_done; + } - // NOTE: This may be premature in the parser but a cast - // node doesn't need to exist if the source and target - // types are the same - if (type == left->type) return left; + if (bin_op_kind != -1) { + bin_op_tok = parser->curr_token; + parser_next_token(parser); + + OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, bin_op_kind); + + while ( !bh_arr_is_empty(tree_stack) && + get_precedence(bh_arr_last(tree_stack)->kind) >= get_precedence(bin_op_kind)) + bh_arr_pop(tree_stack); + + if (bh_arr_is_empty(tree_stack)) { + // NOTE: new is now the root node + bin_op->left = root; + root = bin_op; + } else { + bin_op->left = bh_arr_last(tree_stack)->right; + bh_arr_last(tree_stack)->right = bin_op; + } + + bh_arr_push(tree_stack, bin_op); + + if (bin_op_kind == ONYX_AST_NODE_KIND_CAST) { + bin_op->type = parse_type(parser); + } else { + right = parse_factor(parser); + if (left->type != right->type) { + onyx_message_add(parser->msgs, + ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE, + bin_op_tok->pos, + left->type->name, right->type->name); + + find_token(parser, TOKEN_TYPE_SYM_SEMICOLON); + return &error_node; + } - OnyxAstNode* cast_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_CAST); - cast_node->type = type; - cast_node->left = left; + bin_op->right = right; + bin_op->type = right->type; - return cast_node; - } - default: break; - } + if ((left->flags & ONYX_AST_FLAG_COMPTIME) != 0 && (right->flags & ONYX_AST_FLAG_COMPTIME) != 0) { + bin_op->flags |= ONYX_AST_FLAG_COMPTIME; + } + } + } + } - return left; +expression_done: + return root; } static OnyxAstNode* parse_if_stmt(OnyxParser* parser) { diff --git a/src/onyxutils.c b/src/onyxutils.c index 5f0e97c9..77cd47d0 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -2,6 +2,9 @@ #include "onyxlex.h" #include "onyxparser.h" +bh_scratch global_scratch; +bh_allocator global_scratch_allocator; + #define print_indent { if (indent > 0) bh_printf("\n"); for (int i = 0; i < indent; i++) bh_printf(" "); } void onyx_ast_print(OnyxAstNode* node, i32 indent) { diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 27760df3..ce965f20 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -333,6 +333,32 @@ static void process_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* break; } + case ONYX_AST_NODE_KIND_NEGATE: + { + OnyxTypeInfoKind type_kind = expr->type->kind; + + if (type_kind == ONYX_TYPE_INFO_KIND_INT32) { + bh_arr_push(func->code, ((WasmInstruction){ WI_I32_CONST, 0x00 })); + process_expression(mod, func, expr->left); + bh_arr_push(func->code, ((WasmInstruction){ WI_I32_SUB, 0x00 })); + + } else if (type_kind == ONYX_TYPE_INFO_KIND_INT64) { + bh_arr_push(func->code, ((WasmInstruction){ WI_I64_CONST, 0x00 })); + process_expression(mod, func, expr->left); + bh_arr_push(func->code, ((WasmInstruction){ WI_I64_SUB, 0x00 })); + + } else { + process_expression(mod, func, expr->left); + + if (type_kind == ONYX_TYPE_INFO_KIND_FLOAT32) + bh_arr_push(func->code, ((WasmInstruction){ WI_F32_NEG, 0x00 })); + + if (type_kind == ONYX_TYPE_INFO_KIND_FLOAT64) + bh_arr_push(func->code, ((WasmInstruction){ WI_F32_NEG, 0x00 })); + } + break; + } + case ONYX_AST_NODE_KIND_LOCAL: case ONYX_AST_NODE_KIND_PARAM: {