From 83a0cee3e332492415b22c5c08ec395d1003649c Mon Sep 17 00:00:00 2001 From: MCorange Date: Fri, 4 Jul 2025 18:05:15 +0300 Subject: [PATCH] restructuring, precomp --- src/dynarray.c | 4 +- src/include/parser.h | 8 - src/include/{ => parser}/ast.h | 0 src/include/parser/parser.h | 13 + src/include/parser/precomp.h | 6 + src/include/parser/tokcmp.h | 15 + src/include/token.h | 8 +- src/{ => parser}/parser.c | 64 +--- src/parser/precomp.c | 594 +++++++++++++++++++++++++++++++++ src/parser/tokcmp.c | 81 +++++ src/token.c | 6 + 11 files changed, 730 insertions(+), 69 deletions(-) delete mode 100644 src/include/parser.h rename src/include/{ => parser}/ast.h (100%) create mode 100644 src/include/parser/parser.h create mode 100644 src/include/parser/precomp.h create mode 100644 src/include/parser/tokcmp.h rename src/{ => parser}/parser.c (51%) create mode 100644 src/parser/precomp.c create mode 100644 src/parser/tokcmp.c diff --git a/src/dynarray.c b/src/dynarray.c index 2b2d291..0d7ea77 100644 --- a/src/dynarray.c +++ b/src/dynarray.c @@ -73,7 +73,9 @@ int _dynarray_pop(void* arr, void* dest) { if (dynarray_length(arr) < 1) { return 1; } - memcpy(dest, arr + (dynarray_length(arr) - 1) * dynarray_stride(arr), dynarray_stride(arr)); + if (dest) { + memcpy(dest, arr + (dynarray_length(arr) - 1) * dynarray_stride(arr), dynarray_stride(arr)); + } _dynarray_field_set(arr, LENGTH, dynarray_length(arr) - 1); // Decrement length. return 0; diff --git a/src/include/parser.h b/src/include/parser.h deleted file mode 100644 index f759046..0000000 --- a/src/include/parser.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _H_MORPH_PARSER -#define _H_MORPH_PARSER - -#include "ast.h" -#include "token.h" -program_t parse(const token_t* tokens); - -#endif // _H_MORPH_PARSER diff --git a/src/include/ast.h b/src/include/parser/ast.h similarity index 100% rename from src/include/ast.h rename to src/include/parser/ast.h diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h new file mode 100644 index 0000000..d818b69 --- /dev/null +++ b/src/include/parser/parser.h @@ -0,0 +1,13 @@ +#ifndef _H_MORPH_PARSER +#define _H_MORPH_PARSER + +#include +#include +program_t parse(const token_t* tokens); + +typedef struct parser_state_s { + program_t prog; + token_t curr_tok; + token_t* tokens; +} parser_state_t; +#endif // _H_MORPH_PARSER diff --git a/src/include/parser/precomp.h b/src/include/parser/precomp.h new file mode 100644 index 0000000..671d1ef --- /dev/null +++ b/src/include/parser/precomp.h @@ -0,0 +1,6 @@ +#ifndef _H_MORPH_PARSER_PRECOMP +#define _H_MORPH_PARSER_PRECOMP + +#include +int compile_value(token_t* tokens); +#endif // _H_MORPH_PARSER_PRECOMP diff --git a/src/include/parser/tokcmp.h b/src/include/parser/tokcmp.h new file mode 100644 index 0000000..c73f3b3 --- /dev/null +++ b/src/include/parser/tokcmp.h @@ -0,0 +1,15 @@ +#ifndef _H_MORPH_PARSER_TOKCMP +#define _H_MORPH_PARSER_TOKCMP + +#include +#include +token_t* expect_token_type(parser_state_t* state, token_type_t type); +token_t* expect_token_type_mul(parser_state_t* state, token_type_t types[], int type_count); +token_t* expect_token_type_ex(parser_state_t* state, token_type_t type, int inner_type); + +// Tests token type, and inner type, so like, op type, kw type, etc. +// Does not edit state.curr_tok +token_t* test_token_type_ex(parser_state_t* state, token_type_t tok_type, int gen_type); +token_t* test_token_type(parser_state_t* state, token_type_t tok_type); + +#endif // _H_MORPH_PARSER_TOKCMP diff --git a/src/include/token.h b/src/include/token.h index 8958a6d..691f714 100644 --- a/src/include/token.h +++ b/src/include/token.h @@ -15,6 +15,7 @@ typedef enum token_type_e { TT_PUSH_CHAR, TT_PUSH_INT, TT_PUSH_FLOAT, + TT_PUSH_BOOL, TT_IDENT } token_type_t; @@ -52,12 +53,14 @@ typedef enum op_type_e { OP_GE, OP_LE, OP_NE, + OP_AND, + OP_OR, // Bit manipulation OP_SHR, OP_SHL, - OP_OR, - OP_AND, + OP_BOR, + OP_BAND, OP_NOT, // stack ops @@ -114,6 +117,7 @@ typedef struct token_s { // NOTE: For PUSH_MEM. It will push the offset of the memory, // that is assigned for that specific memory, from the `memory` label. size_t offset_v; + bool bool_v; double float_v; }; } token_t; diff --git a/src/parser.c b/src/parser/parser.c similarity index 51% rename from src/parser.c rename to src/parser/parser.c index b8d505d..dbc8396 100644 --- a/src/parser.c +++ b/src/parser/parser.c @@ -3,66 +3,13 @@ #include "util.h" #include #include +#include #include -#include #include -#include - -typedef struct parser_state_s { - program_t prog; - token_t curr_tok; - token_t* tokens; -} parser_state_t; - -token_t* expect_token_type(parser_state_t* state, token_type_t type) { - const char* exoected_type_str = get_tok_type_str_dbg(state->curr_tok.type); - if (dynarray_pop(state->tokens, &state->curr_tok) != 0) { - log_error(&state->curr_tok.loc, "Invalid word, expected %s, got nothing.", exoected_type_str); - return NULL; - } - if (state->curr_tok.type != type) { - const char* s1 = get_tok_str_dbg(&state->curr_tok); - log_error(&state->curr_tok.loc, "Invalid word, expected %s, got %s.", exoected_type_str, s1); - return NULL; - } - return &state->curr_tok; -} - -token_t* expect_token_type_ex(parser_state_t* state, token_type_t type, int inner_type) { - const char* exoected_type_str = get_tok_type_str_dbg(state->curr_tok.type); - if (dynarray_pop(state->tokens, &state->curr_tok) != 0) { - log_error(&state->curr_tok.loc, "Invalid word, expected %s, got nothing.", exoected_type_str); - return NULL; - } - // NOTE: all inner types are in a union - if (state->curr_tok.type != type || state->curr_tok.kw_type != inner_type) { - const char* s1 = get_tok_str_dbg(&state->curr_tok); - log_error(&state->curr_tok.loc, "Invalid word, expected %s, got %s.", exoected_type_str, s1); - return NULL; - } - return &state->curr_tok; -} - -// Tests token type, and inner type, so like, op type, kw type, etc. -// Does not edit state.curr_tok -token_t* test_token_type_ex(parser_state_t* state, token_type_t tok_type, int gen_type) { - const char* exoected_type_str = get_tok_type_str_dbg(state->curr_tok.type); - token_t* token = &state->tokens[dynarray_length(state->tokens - 1)]; - // NOTE: tests inner type in a generic way - if (token->type != tok_type || ((int)token->kw_type) != gen_type) { - return NULL; - } - return token; -} - -token_t* test_token_type(parser_state_t* state, token_type_t tok_type) { - const char* exoected_type_str = get_tok_type_str_dbg(state->curr_tok.type); - token_t* token = &state->tokens[dynarray_length(state->tokens - 1)]; - if (token->type != tok_type) { - return NULL; - } - return token; -} +#include +#include +#include +#include int _parse(parser_state_t* state); @@ -128,4 +75,5 @@ int _parse(parser_state_t* state) { assert(true && "TODO: parse all kw's"); } } + return 0; } diff --git a/src/parser/precomp.c b/src/parser/precomp.c new file mode 100644 index 0000000..8ad8280 --- /dev/null +++ b/src/parser/precomp.c @@ -0,0 +1,594 @@ +#include "loc.h" +#include "logger.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// compiles values in the token list, will error if invalid tokens +int compile_value(token_t* tokens) { + // 'f' for float, 'i' for int, 's' for string, 'c' for char + char exclusive_type = '\0'; + token_t* tmp_toks = dynarray_create(token_t); + token_t tok = {0}; + parser_state_t ps = {0}; + ps.tokens = tokens; + while (dynarray_pop(tokens, &tok) == 0) { + switch (tok.type) { + case (TT_PUSH_CSTR): + case (TT_PUSH_STR): { + // TODO: Add C style string literall joining + if (dynarray_length(tokens) != 0) { + log_error(&tok.loc, "Constants do not support C style string literal joining yet"); + return 1; + } + dynarray_push(tmp_toks, tok); + }; break; + case (TT_PUSH_INT): + case (TT_PUSH_FLOAT): + case (TT_PUSH_CHAR): + case (TT_PUSH_BOOL): + case (TT_PUSH_MEM): { + dynarray_push(tmp_toks, tok); + }; break; + case (TT_KW): { + // TODO: Support if statements in constants at compile time against other constants + log_error(&tok.loc, "Keywords are currently not supported in constants"); + return 1; + } + case (TT_IDENT): { + // TODO: Support having other constants as arguments in constants, and memory values for making offsets + log_error(&tok.loc, "Identifiers are currently not supported in constants"); + return 1; + } + case (TT_OP): { + switch (tok.op_type) { + case (OP_ADD): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == TT_PUSH_INT && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v + t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + + } else if (t1->type == TT_PUSH_FLOAT && t2->type == TT_PUSH_FLOAT) { + double_t val = t1->float_v + t2->float_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_FLOAT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + + } else if (t1->type == TT_PUSH_MEM && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v + t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be added together", s1, s2); + return 1; + } + }; break; + case (OP_SUB): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == TT_PUSH_INT && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v - t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + + } else if (t1->type == TT_PUSH_FLOAT && t2->type == TT_PUSH_FLOAT) { + double_t val = t1->float_v - t2->float_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_FLOAT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + + } else if (t1->type == TT_PUSH_MEM && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v - t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be subtracted from eachother", s1, s2); + return 1; + } + }; break; + case (OP_MUL): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == TT_PUSH_INT && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v * t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + + } else if (t1->type == TT_PUSH_FLOAT && t2->type == TT_PUSH_FLOAT) { + double_t val = t1->float_v * t2->float_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_FLOAT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + + } else if (t1->type == TT_PUSH_MEM && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v * t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be multiplied together", s1, s2); + return 1; + } + }; break; + case (OP_DIV): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == TT_PUSH_INT && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v / t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + + } else if (t1->type == TT_PUSH_FLOAT && t2->type == TT_PUSH_FLOAT) { + double_t val = t1->float_v / t2->float_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_FLOAT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + + } else if (t1->type == TT_PUSH_MEM && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v / t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be divided", s1, s2); + return 1; + } + }; break; + case (OP_MOD): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == TT_PUSH_INT && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v % t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + } else if (t1->type == TT_PUSH_MEM && t2->type == TT_PUSH_INT) { + size_t val = t1->int_v % t2->int_v; + loc_t loc = t1->loc; + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be modulo'd together", s1, s2); + return 1; + } + }; break; + case (OP_EQ): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + bool val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v == t2->int_v; + break; + case (TT_PUSH_CSTR): + case (TT_PUSH_STR): + val = strcmp(t1->str_v, t2->str_v) == 0; + break; + case (TT_PUSH_FLOAT): + val = t1->float_v == t2->float_v; + break; + case (TT_PUSH_CHAR): + val = t1->char_v == t2->char_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_BOOL, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + }; break; + case (OP_GT): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + bool val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v > t2->int_v; + break; + case (TT_PUSH_FLOAT): + val = t1->float_v > t2->float_v; + break; + case (TT_PUSH_CHAR): + val = t1->char_v > t2->char_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_BOOL, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + }; break; + case (OP_LT): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + bool val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v < t2->int_v; + break; + case (TT_PUSH_FLOAT): + val = t1->float_v < t2->float_v; + break; + case (TT_PUSH_CHAR): + val = t1->char_v < t2->char_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_BOOL, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + }; break; + case (OP_GE): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + bool val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v >= t2->int_v; + break; + case (TT_PUSH_FLOAT): + val = t1->float_v >= t2->float_v; + break; + case (TT_PUSH_CHAR): + val = t1->char_v >= t2->char_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_BOOL, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + }; break; + case (OP_LE): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + bool val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v <= t2->int_v; + break; + case (TT_PUSH_FLOAT): + val = t1->float_v <= t2->float_v; + break; + case (TT_PUSH_CHAR): + val = t1->char_v <= t2->char_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_BOOL, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + }; break; + case (OP_NE): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + bool val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v != t2->int_v; + break; + case (TT_PUSH_CSTR): + case (TT_PUSH_STR): + val = strcmp(t1->str_v, t2->str_v) != 0; + break; + case (TT_PUSH_FLOAT): + val = t1->float_v != t2->float_v; + break; + case (TT_PUSH_CHAR): + val = t1->char_v != t2->char_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_BOOL, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be compared", s1, s2); + return 1; + } + }; break; + case (OP_SHR): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + size_t val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v >> t2->int_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be SHR'd", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be SHR'd", s1, s2); + return 1; + } + }; break; + case (OP_SHL): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + size_t val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v << t2->int_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be SHL'd", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be SHL'd", s1, s2); + return 1; + } + }; break; + case (OP_BOR): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + size_t val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v | t2->int_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be BOR'd", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be BOR'd", s1, s2); + return 1; + } + }; break; + case (OP_BAND): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + size_t val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->int_v & t2->int_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be BAND'd", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_INT, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be BAND'd", s1, s2); + return 1; + } + }; break; + case (OP_NOT): { + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + bool val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = !t1->bool_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + log_error(&t1->loc, "Tokens %s cannot be negated", s1); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_BOOL, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + }; break; + case (OP_AND): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + bool val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->bool_v && t2->bool_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be AND'd", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_BOOL, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be SHL'd", s1, s2); + return 1; + } + }; break; + case (OP_OR): { + token_t* t2 = &tmp_toks[dynarray_length(tmp_toks - 1)]; + token_t* t1 = &tmp_toks[dynarray_length(tmp_toks - 2)]; + if (t1->type == t2->type) { + bool val = 0; + switch (t1->type) { + case (TT_PUSH_INT): + val = t1->bool_v || t2->bool_v; + break; + default: + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be AND'd", s1, s2); + return 1; + } + dynarray_pop(tokens, NULL); + dynarray_pop(tokens, NULL); + token_t tok = {.type = TT_PUSH_BOOL, .int_v = val, .loc = t1->loc}; + dynarray_push(tokens, tok); + } else { + const char* s1 = get_tok_str_dbg(t1); + const char* s2 = get_tok_str_dbg(t2); + log_error(&t1->loc, "Tokens %s and %s cannot be SHL'd", s1, s2); + return 1; + } + }; break; + default: + const char* s1 = get_tok_str_dbg(&tok); + log_error(&tok.loc, "Using %s is not allowed in Constants", s1); + return 1; + } + } break; + case (TT_NONE): + continue; + } + } + + return 0; +} diff --git a/src/parser/tokcmp.c b/src/parser/tokcmp.c new file mode 100644 index 0000000..188cb09 --- /dev/null +++ b/src/parser/tokcmp.c @@ -0,0 +1,81 @@ +#include "logger.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +token_t* expect_token_type(parser_state_t* state, token_type_t type) { + const char* exoected_type_str = get_tok_type_str_dbg(type); + if (dynarray_pop(state->tokens, &state->curr_tok) != 0) { + log_error(&state->curr_tok.loc, "Invalid word, expected %s, got nothing.", exoected_type_str); + return NULL; + } + if (state->curr_tok.type != type) { + const char* s1 = get_tok_str_dbg(&state->curr_tok); + log_error(&state->curr_tok.loc, "Invalid word, expected %s, got %s.", exoected_type_str, s1); + return NULL; + } + return &state->curr_tok; +} + +token_t* expect_token_type_mul(parser_state_t* state, token_type_t types[], int type_count) { + + char* expected_type_str = malloc(1024 * 4); + int offset = 0; + for (int i = 0; i < type_count; i++) { + offset += snprintf(expected_type_str + offset, 1024, " %s", get_tok_type_str_dbg(types[i])); + } + + if (dynarray_pop(state->tokens, &state->curr_tok) != 0) { + log_error(&state->curr_tok.loc, "Invalid word, expected %s, got nothing.", expected_type_str); + return NULL; + } + + for (int i = 0; i < type_count; i++) { + if (state->curr_tok.type == types[i]) { + return &state->curr_tok; + } + } + const char* s1 = get_tok_str_dbg(&state->curr_tok); + log_error(&state->curr_tok.loc, "Invalid word, expected %s, got %s.", expected_type_str, s1); + return NULL; +} + +token_t* expect_token_type_ex(parser_state_t* state, token_type_t type, int inner_type) { + const char* exoected_type_str = get_tok_type_str_dbg(state->curr_tok.type); + if (dynarray_pop(state->tokens, &state->curr_tok) != 0) { + log_error(&state->curr_tok.loc, "Invalid word, expected %s, got nothing.", exoected_type_str); + return NULL; + } + // NOTE: all inner types are in a union + if (state->curr_tok.type != type || state->curr_tok.kw_type != inner_type) { + const char* s1 = get_tok_str_dbg(&state->curr_tok); + log_error(&state->curr_tok.loc, "Invalid word, expected %s, got %s.", exoected_type_str, s1); + return NULL; + } + return &state->curr_tok; +} + +token_t* test_token_type_ex(parser_state_t* state, token_type_t tok_type, int gen_type) { + const char* exoected_type_str = get_tok_type_str_dbg(state->curr_tok.type); + token_t* token = &state->tokens[dynarray_length(state->tokens - 1)]; + // NOTE: tests inner type in a generic way + if (token->type != tok_type || ((int)token->kw_type) != gen_type) { + return NULL; + } + return token; +} + +token_t* test_token_type(parser_state_t* state, token_type_t tok_type) { + const char* exoected_type_str = get_tok_type_str_dbg(state->curr_tok.type); + token_t* token = &state->tokens[dynarray_length(state->tokens - 1)]; + if (token->type != tok_type) { + return NULL; + } + return token; +} diff --git a/src/token.c b/src/token.c index 0de002c..7c9a005 100644 --- a/src/token.c +++ b/src/token.c @@ -20,6 +20,8 @@ const char* OP_LIST[] = { [OP_NE] = "ne", [OP_SHR] = "shr", [OP_SHL] = "shl", + [OP_BOR] = "bor", + [OP_BAND] = "band", [OP_OR] = "or", [OP_AND] = "and", [OP_NOT] = "not", @@ -78,6 +80,7 @@ const char* get_tok_type_str_dbg(token_type_t tok_t) { case (TT_PUSH_CSTR): return "CString"; case (TT_PUSH_MEM): return "Memory address"; case (TT_PUSH_FLOAT): return "Float"; + case (TT_PUSH_BOOL): return "Bool"; case (TT_NONE): assert(true && "Invalid"); } return "Unreachable"; @@ -119,6 +122,9 @@ const char* get_tok_str_dbg(token_t* tok) { case (TT_PUSH_FLOAT): { snprintf(buf, buf_size, "%f", tok->float_v); }; break; + case (TT_PUSH_BOOL): { + snprintf(buf, buf_size, "%b", tok->bool_v); + }; break; case (TT_NONE): assert(true && "Invalid"); } return buf;