diff --git a/include/lexer.h b/include/lexer.h index d87441c..eccf1dc 100644 --- a/include/lexer.h +++ b/include/lexer.h @@ -34,6 +34,7 @@ typedef enum { LEXER_EMPTY_INPUT, LEXER_NULL_ARG, LEXER_WRONG_SYNTAX, + LEXER_BUF_OVERFLOW, } LexerErr; // Can be thought as tokens, they will be used by the parser. @@ -68,6 +69,7 @@ size_t ASTNodeArray_len(ASTNodeArray *arr); // Lexer funtions as well as few functionality LexerErr tokenize(const char* input, ASTNodeArray *out); LexerErr tokenize_number(const char* input, size_t *offset, ASTNode *out); -LexerErr string_to_number(const char* str, double *number); +LexerErr string_to_number(const char* input, size_t *offset, double *number); +void reverser_string(char* input); #endif // !LEXER_H diff --git a/src/lexer.c b/src/lexer.c index 859ff93..b0abbb8 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -1,6 +1,10 @@ #include "lexer.h" +#include +#include +#include #include #include +#include #define NODE_ARRAY_DEFAULT_SIZE 64 // Helps state machine for the lexer :) @@ -78,6 +82,16 @@ ASTNodeArrayErr ASTNodeArray_pop(ASTNodeArray *arr, size_t index, ASTNode *out) if (index >= arr->len) { return ARRAY_OUT_OF_BOUNDS; } + + if (arr->cap / 4 > arr->len) { + size_t new_cap = arr->cap / 2; + ASTNode *tmp = realloc(arr->data, new_cap * sizeof(ASTNode)); + if (tmp == NULL) { + return ARRAY_ALLOC; + } + arr->data = tmp; + arr->cap = new_cap; + } if (out != NULL) { ASTNode node_to_delete = arr->data[index]; @@ -97,3 +111,40 @@ size_t ASTNodeArray_len(ASTNodeArray *arr) { } return arr->len; } + +// CURRENTLY, it only supports ints, not clear how floating +// point is implemented but i'll figure it out +LexerErr string_to_number(const char *input, size_t *offset, double *number) { + char buf[128] = { '\0' }; + size_t buf_pos = 0; + + size_t current = *offset; + while (isdigit(input[current])) { + buf[buf_pos] = input[current]; + + if (buf_pos >= sizeof(buf)) { + return LEXER_BUF_OVERFLOW; + } + current++; + buf_pos++; + } + + int c = 0; + long count = 0; + while (buf[c] != '\0') { + + int digit = buf[c] - '0'; + + if (count > (INT_MAX - digit) / 10) { + return LEXER_FAILED_NUMBER_CONVERSION; + } + count = count * 10; + count += digit; + + c++; + } + + *number = (double) count; + *offset = current; + return LEXER_OK; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 99aff45..3aad9e4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,10 +1,17 @@ find_package(cmocka REQUIRED) add_executable(test_nodeArray test_ASTNodeArray.c) +add_executable(test_lexer test_lexer.c) target_link_libraries(test_nodeArray calculator_lib cmocka::cmocka ) +target_link_libraries(test_lexer + calculator_lib + cmocka::cmocka +) + add_test(NAME nodeArray_tests COMMAND test_nodeArray) +add_test(NAME lexer_tests COMMAND test_lexer) diff --git a/test/test_ASTNodeArray.c b/test/test_ASTNodeArray.c index 6d81a97..cc28297 100644 --- a/test/test_ASTNodeArray.c +++ b/test/test_ASTNodeArray.c @@ -34,12 +34,15 @@ static void test_array_push(void **state) { assert_int_equal(ASTNodeArray_push(&arr, node3), ARRAY_OK); assert_int_equal(ASTNodeArray_len(&arr), 3); + + ASTNodeArray_free(&arr); } static void test_array_pop(void **state) { (void) state; - ASTNodeArray arr = ASTNodeArray_init(2); + // Set to force desize + ASTNodeArray arr = ASTNodeArray_init(16); ASTNode node1 = { .type = NODE_NUMBER, .data = { .number = 90 } @@ -68,8 +71,11 @@ static void test_array_pop(void **state) { assert_int_equal(ASTNodeArray_pop(&arr, 1, &node4), ARRAY_OK); assert_int_equal(node4.type, NODE_NUMBER); assert_int_equal(node4.data.number, 80); + + ASTNodeArray_free(&arr); } + int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_array_push), diff --git a/test/test_lexer.c b/test/test_lexer.c new file mode 100644 index 0000000..8d59e72 --- /dev/null +++ b/test/test_lexer.c @@ -0,0 +1,27 @@ +#include "lexer.h" +#include +#include +#include +#include +#include +#include + +static void test_string_to_number(void **state) { + (void) state; + + char num[16] = "2333t55"; + size_t offset = 0; + double result = 0; + assert_int_equal(string_to_number(num, &offset, &result), 0); + + assert_int_equal(offset, 4); + assert_double_equal(result, 2333, 1e-6); +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_string_to_number), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +}