From 11fa2b1e6fad6fdbb73a618a8af83486e55e9711 Mon Sep 17 00:00:00 2001 From: Matthieu Bessat Date: Fri, 6 May 2022 11:49:09 +0200 Subject: [PATCH] feat: line processing and basic variable support --- Makefile | 3 + sandbox.c | 92 +++++++++++++ src/evaluator.c | 78 +++++++++-- src/evaluator.h | 3 +- src/funcs.c | 40 ++++-- src/line_processing.c | 255 +++++++++++++++++++++++++++++++++++ src/line_processing.h | 7 + src/list.c | 39 +----- src/list.h | 6 +- src/state.c | 25 ++++ src/state.h | 26 ++++ src/types.c | 55 ++++++++ src/types.h | 12 ++ src/utils.h | 5 + src/var_store.c | 184 +++++++++++++++++++++++++ src/var_store.h | 64 +++++++++ test.c | 60 --------- tests/test.c | 2 + tests/test_evaluation.c | 40 ++++-- tests/test_line_processing.c | 32 +++++ tests/test_line_processing.h | 1 + 21 files changed, 893 insertions(+), 136 deletions(-) create mode 100644 sandbox.c create mode 100644 src/line_processing.c create mode 100644 src/line_processing.h create mode 100644 src/state.c create mode 100644 src/state.h create mode 100644 src/types.c create mode 100644 src/var_store.c create mode 100644 src/var_store.h delete mode 100644 test.c create mode 100644 tests/test_line_processing.c create mode 100644 tests/test_line_processing.h diff --git a/Makefile b/Makefile index 3d3f42d..67e88fb 100644 --- a/Makefile +++ b/Makefile @@ -10,3 +10,6 @@ build: test: gcc ${TEST_SRCS_ENC} ./tests/* -o ./bin/test ${CXXFLAGS_WITHOUT_PKGS} ./bin/test +sandbox: + gcc ${TEST_SRCS_ENC} ./sandbox.c -o ./bin/sandbox ${CXXFLAGS_WITHOUT_PKGS} + ./bin/sandbox diff --git a/sandbox.c b/sandbox.c new file mode 100644 index 0000000..01bd0bf --- /dev/null +++ b/sandbox.c @@ -0,0 +1,92 @@ +#include +#include "./src/types.h" +#include "./src/list.h" +#include "./src/number_parsing.h" +#include "./src/funcs.h" +#include "./src/utils.h" +#include "./src/var_store.h" +#include "./src/line_processing.h" +#include "./src/state.h" +#include + +int main () { + // struct List l1; + + // short val = 17; + // list_set(&l1, 0, TYPE_VAR_NAME, &val); + // list_print(&l1); + + // return 0; + + // int yes = 1234; + // int dst = 0; + // memcpy(&dst, &yes, 4); + // printf("yes: %d \n", dst); + + struct VariableStore* store = var_store_init(); + + // int hashRes = var_store_hash_name(store, "HelloWorld++"); + // printf("hashRes: %d \n", hashRes); + int val = 1234; + var_store_set(store, "foo", TYPE_INT, &val); + + //printf("Pos of var: %d \n", var_store_get_pos(store, "foo")); + + //byte type = var_store_get_type(store, "foo"); + //printf("Type of var: %d \n", type); + + //int key = var_store_get_pos(store, "foo"); + //printf("size of type %d \n", get_size_of_type(store->container[key].type)); + //printf("%d \n", *((int*) store->container[key].dataPtr)); + + int val2 = 0; + var_store_copy(store, "foo", &val2); + + printf("Value of var: %d \n", val2); + + printf("==== \n"); + printf("==== \n"); + struct StateContainer* state = state_init(); + process_line(state, "# some random comment"); + process_line(state, "set VAR_A to 8.5"); + process_line(state, "set VAR_B to 1.5"); + process_line(state, "set VAR_C to VAR_A+VAR_B"); + process_line(state, "print_number(sqrt(VAR_C))"); + + // struct List l1; + + // list_append_int(&l1, 4); + // list_append_char(&l1, '*'); + // list_append_int(&l1, 5); + + // list_print(&l1); + + // list_delete(&l1, 0); + + // list_print(&l1); + + // list_delete(&l1, 0); + + // list_print(&l1); + + // float res = 0; + + // void* ptr = &res; + + // printf("%d\n", sizeof(ptr)); + // int found = identify_func_name("ABS"); + // printf("found: %d \n", found); + + // unsigned char argsType[1] = { TYPE_FLOAT }; + // int argsVals[1] = { get_int_rep_from_float(-3.145) }; + // int resVal = 0; + // unsigned char resType = 0; + // execute_func(found, 1, argsType, argsVals, &resVal, &resType); + // printf("func res type: %d \n", resType); + // printf("func res: %f \n", get_float_from_int_rep(resVal)); + + // int stat = parse_float("1052.254", &res); + // printf("float parsing stat: %d \n", stat); + // printf("final float: %f \n", res); +} + diff --git a/src/evaluator.c b/src/evaluator.c index 713c1f5..a2cfd41 100644 --- a/src/evaluator.c +++ b/src/evaluator.c @@ -6,6 +6,8 @@ #include "./operate.h" #include "./number_parsing.h" #include "./funcs.h" +#include "./var_store.h" +#include "./state.h" /** This sub script will look for pattern like Number Operator Number @@ -154,6 +156,31 @@ int evaluator_reduce_parenthesis_pattern(struct List* evalList) { return 0; } +int evaluator_reduce_var(struct StateContainer* state, struct List* evalList) { + int patternPos = -1; + for (int i = 0; i < evalList->num_elements; i++) { + if ( + list_get_type(evalList, i) == TYPE_VAR_NAME + ) { + patternPos = i; + break; + } + } + if (patternPos == -1) return -1; + + int varKey; + list_get(evalList, patternPos, &varKey); + + byte type = var_store_get_type_from_key(state->varStore, varKey); + + byte varVal[get_size_of_type(type)]; + var_store_copy_from_key(state->varStore, varKey, &varVal); + + list_set(evalList, patternPos, type, &varVal); + + return 0; +} + /* This func will look for a function call pattern that is ready to be evaluated First we will look for this kind of pattern @@ -169,10 +196,14 @@ if we don't find a comma next, we try to find a closing parenthesis if we don't find that, we throw an error */ -int evaluator_reduce_function_call(struct List* evalList) { +int evaluator_reduce_function_call(struct List* evalList, int initialPosition) { int patternPos = -1; - for (int i = 0; i < evalList->num_elements; i++) { + if (initialPosition >= evalList->num_elements) { + return -1; + } + + for (int i = initialPosition; i < evalList->num_elements; i++) { if ( list_get_type(evalList, i) == TYPE_FUNC_NAME && list_get_type(evalList, i+1) == TYPE_OPEN_PARENTHESIS @@ -239,7 +270,10 @@ int evaluator_reduce_function_call(struct List* evalList) { } // we cannot reduce more, it's probably because the func call is not ready to be reduced, meaning that the arguments need to be evaluated - return -1; + + // we need to return to the state of primitive function detection, just skip this primitive + // we need to revaluate at patternPos+2 + return evaluator_reduce_function_call(evalList, patternPos+2); } // now pos is the index of the last component for this func call @@ -287,7 +321,7 @@ Arguments: - Input String: char pointer (the source of the evaluation) - Result: int pointer (where the result of the evaluation will be written) */ -int evaluate(char* inputStr, int* resultPtr, unsigned char* typePtr) { +int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr) { int i = 0; int _len = strlen(inputStr); // we want first to parse the expression and create a stack @@ -461,18 +495,27 @@ int evaluate(char* inputStr, int* resultPtr, unsigned char* typePtr) { } if (st != 0) { + // identify token + // first try a variable then a func name // not a float, check if this is a common function name - short funcID = identify_func_name(buff); - if (funcID == -1) { - // did not find the func name - printf("ERR Evaluator: could not identify token \"%s\" \n", buff); - return 200; + short varKey = (short) var_store_get_key(state->varStore, buff); + if (varKey == -1) { + // did not find the var name + short funcID = identify_func_name(buff); + if (funcID == -1) { + // did not find the func name + printf("ERR Evaluator: could not identify token \"%s\" \n", buff); + return 200; + } + if (funcID >= 0) { + list_set(&evalList, evalList.num_elements, TYPE_FUNC_NAME, &funcID); + } } - if (funcID >= 0) { - list_set(&evalList, evalList.num_elements, TYPE_FUNC_NAME, &funcID); + if (varKey >= 0) { + list_set(&evalList, evalList.num_elements, TYPE_VAR_NAME, &varKey); } } - printf("end of l\n"); + printf("end of a token id\n"); } // check the content of this thing @@ -484,15 +527,21 @@ int evaluate(char* inputStr, int* resultPtr, unsigned char* typePtr) { // we are going to look for pattern to reduce // the order is really important here - int reduceFuncOpStat = evaluator_reduce_function_call(&evalList); + int reduceVarOpStat = evaluator_reduce_var(state, &evalList); + int reduceFuncOpStat = evaluator_reduce_function_call(&evalList, 0); int reduceMinusOpStat = evaluator_reduce_minus_pattern(&evalList); int reduceOperatorOpStat = evaluator_reduce_operator_pattern(&evalList); int reduceParenthesisOpStat = evaluator_reduce_parenthesis_pattern(&evalList); + if (reduceVarOpStat > 0) { + printf("ERR Evaluator: var name reducing failed, dumping evalList: \n"); + list_print(&evalList); + return reduceVarOpStat; + } if (reduceFuncOpStat > 0) { printf("ERR Evaluator: function reducing failed, dumping evalList: \n"); list_print(&evalList); - return reduceOperatorOpStat; + return reduceFuncOpStat; } if (reduceOperatorOpStat > 0) { printf("ERR Evaluator: operator reducing failed, dumping evalList: \n"); @@ -501,6 +550,7 @@ int evaluate(char* inputStr, int* resultPtr, unsigned char* typePtr) { } if ( + reduceVarOpStat == -1 && reduceFuncOpStat == -1 && reduceOperatorOpStat == -1 && reduceParenthesisOpStat == -1 && diff --git a/src/evaluator.h b/src/evaluator.h index 0e41e9a..7ff7693 100644 --- a/src/evaluator.h +++ b/src/evaluator.h @@ -1,6 +1,7 @@ +#include "./state.h" #ifndef EVALUATOR_H_ #define EVALUATOR_H_ -int evaluate(char* inputStr, int* resultPtr, unsigned char* typePtr); +int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr); #endif diff --git a/src/funcs.c b/src/funcs.c index c26bd30..9bb38fe 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -27,6 +27,25 @@ int abs_impl(int* res, unsigned char* resType, unsigned char* types, int* args) return 1; } +int print_number_impl(int* res, unsigned char* resType, unsigned char* types, int* args) +{ + if (types[0] == TYPE_INT) { + int val = args[0]; + printf("REAL_PRINT: %d\n", val); + } + if (types[0] == TYPE_FLOAT) { + float val = get_float_from_int_rep(args[0]); + printf("REAL_PRINT: %f\n", val); + } + if (is_type_number(types[0])) { + *res = 1; + *resType = TYPE_INT; + + return 0; + } + return 1; +} + int simple_float_func(float (*func)(float), int* res, unsigned char* resType, unsigned char* types, int* args) { float x = 0; @@ -42,14 +61,15 @@ int simple_float_func(float (*func)(float), int* res, unsigned char* resType, un return 0; } -// #define SIMPLE_FUNC_BINDING(name) ({\ -// int #name_impl(int* res, unsigned char* resType, unsigned char* types, int* args)\ -// {\ -// return simple_float_func(&m_#name, res, resType, types, args);\ -// }\ -// }) -// -// +/* + #define SIMPLE_FUNC_BINDING(name) ({\ + int #name_impl(int* res, unsigned char* resType, unsigned char* types, int* args)\ + {\ + return simple_float_func(&m_#name, res, resType, types, args);\ + }\ + }) +*/ + // SIMPLE_FUNC_BINDING(sqrt) // // SIMPLE_FUNC_BINDING(exp) @@ -162,8 +182,6 @@ int random_int_impl(int* res, unsigned char* resType, unsigned char* types, int* upper = args[1]; } - int i; - // rand returns a value between 0 and RAND_MAX (which is close to infinite) int num = (rand() % (upper - lower + 1)) + lower; *resType = TYPE_INT; @@ -196,6 +214,8 @@ struct FuncIntro intros[] = { {"max", &max_impl, 2}, {"get_pi", &get_pi_impl, 0}, + + {"print_number", &print_number_impl, 1}, {"", 0, 0} }; diff --git a/src/line_processing.c b/src/line_processing.c new file mode 100644 index 0000000..505709d --- /dev/null +++ b/src/line_processing.c @@ -0,0 +1,255 @@ +#include "./utils.h" +#include "./line_processing.h" +#include "./evaluator.h" +#include +#include +#include + +int cmp_str_in_place(char* against, char* str, int from) +{ + + int i = 0; + while (against[i] != '\0') { + if (against[i] != str[from+i]) { + return 0; + } + i++; + } + return 1; +} + +int is_char_accepted_in_var_name(char symbol) +{ + int c = (int) symbol; + return ( + (c >= 65 && c <= 90) || + (c >= 97 && c <= 122) || + (c >= 48 && c <= 57) || + c == 45 || c == 95 + ); +} + +int recognize_comment_statement(char* lineStr) +{ + int i = 0; + int mode = 1; + /* + recognize pattern : ^\s*#.*$ + mode 1 any space + mode 2 the start of the comment + */ + while (lineStr[i] != '\0') { + if (mode == 1) { + if (lineStr[i] == '#') { + mode = 2; + continue; + } + if (lineStr[i] != ' ') { + break; + } + } + i++; + } + if (mode != 2) return 0; + + return 1; +} + + +struct SetStatement { + short name_start; + short name_stop; + short expression_start; +}; + +int recognize_set_statement(char* lineStr, struct SetStatement* res) +{ + int i = 0; + int mode = 1; + int arg = 0; + /* + recognize pattern : ^\s*set ([a-zA-Z0-9_-]+) to (\S)+ + mode 1 any space + mode 2 set + mode 3 any space + mode 4 var name + mode 5 any space + mode 6 to + mode 7 any space + mode 8 the expression + */ + while (lineStr[i] != '\0') { + if (mode == 1) { + if (lineStr[i] == 's') { + mode = 2; + arg = 0; + continue; + } + if (lineStr[i] != ' ') { + break; + } + } + if (mode == 2) { + if (arg == 0 && lineStr[i] == 's') { + arg++; + i++; + continue; + } + if (arg == 1 && lineStr[i] == 'e') { + arg++; + i++; + continue; + } + if (arg == 2 && lineStr[i] == 't') { + mode = 3; + arg = 0; + i++; + continue; + } + break; + } + if (mode == 3) { + if (arg > 0 && is_char_accepted_in_var_name(lineStr[i])) { + mode = 4; + arg = 0; + res->name_start = i; + continue; + } + if (lineStr[i] != ' ') { + break; + } + arg++; + } + if (mode == 4) { + if (lineStr[i] == ' ') { + mode = 5; + arg = 0; + res->name_stop = i; + continue; + } + if (!is_char_accepted_in_var_name(lineStr[i])) { + break; + } + } + if (mode == 5) { + if (arg > 0 && lineStr[i] == 't') { + mode = 6; + arg = 0; + continue; + } + if (lineStr[i] != ' ') { + break; + } + arg++; + } + if (mode == 6) { + if (arg == 0 && lineStr[i] == 't') { + arg++; + i++; + continue; + } + if (arg == 1 && lineStr[i] == 'o') { + mode = 7; + arg = 0; + i++; + continue; + } + break; + } + if (mode == 7) { + if (arg == 0 && lineStr[i] != ' ') { + break; + } + if (arg > 0 && lineStr[i] != ' ') { + // success + mode = 8; + res->expression_start = i; + break; + } + arg++; + } + + i++; + } + // printf("End of set statement parsing \n"); + // printf("index %d \n", i); + // printf("mode %d \n", mode); + // printf("arg %d \n", arg); + + if (mode != 8) { + // we've failed to recognize the pattern + return 0; + } + + // return a struct with anchors to the groups + return 1; +} + +int process_line(struct StateContainer* state, char* str) +{ + printf("\n ======= PROCESSING LINE '%s' =======\n", str); + // process + int len = strlen(str); + // int startPos = 0; + // int stopPos = len-1; + // // modifiy the start and stop pos to trim spaces + // int startTrimOffset = 0; + // int stopTrimOffset = 0; + // for (int z = 0; z < len; z++) { + // if (inputStr[startPos+z] != ' ') { + // break; + // } + // startTrimOffset++; + // } + // for (int z = 1; z < len; z++) { + // if (inputStr[stopPos-z] != ' ') { + // break; + // } + // stopTrimOffset++; + // } + // startPos += startTrimOffset; + // stopPos -= stopTrimOffset; + + // check for comment + // if (str[startPos] == '#') { + // return; + // } + + //int stat = 0; + if (recognize_comment_statement(str)) { + printf("Comment recognized \n"); + return 1; + } + struct SetStatement setStatementParsing; + if (recognize_set_statement(str, &setStatementParsing)) { + printf("Set statement recognized \n"); + // handle the set statement (set a variable) + int nameLen = setStatementParsing.name_stop-setStatementParsing.name_start; + char* name = (char*) malloc(sizeof(char) * nameLen); + for (int z = 0; z < nameLen; z++) { + name[z] = str[setStatementParsing.name_start + z]; + } + name[len] = '\0'; + + int res; + byte resType; + int evalStat = evaluate(state, str + setStatementParsing.expression_start, &res, &resType); + if (evalStat != 0) { + printf("Syntax error for line \"%s\"\n", str); + } + + printf("==> Set '%s' to %s \n", name, get_repr(resType, &res)); + var_store_set(state->varStore, name, resType, &res); + return 1; + } + + // we evaluate but we dont care about the result + int res; + byte resType; + int evalStat = evaluate(state, str, &res, &resType); + if (evalStat != 0) { + printf("Syntax error for line \"%s\"\n", str); + return 0; + } + return 1; +} diff --git a/src/line_processing.h b/src/line_processing.h new file mode 100644 index 0000000..10700f9 --- /dev/null +++ b/src/line_processing.h @@ -0,0 +1,7 @@ +#include "./state.h" +#ifndef LINE_PROCESSING_H_ +#define LINE_PROCESSING_H_ + +int process_line(struct StateContainer* state, char* str); + +#endif diff --git a/src/list.c b/src/list.c index b8d1b31..0b84b23 100644 --- a/src/list.c +++ b/src/list.c @@ -13,37 +13,6 @@ struct List { }; */ -// get size in byte of a particular type -int get_size_of_type(unsigned char type) -{ - int t = (int) type; - // underlying type is int (4 bytes) - if (t == TYPE_INT || t == TYPE_FLOAT) { - return 4; - } - // underlying type is short (1 byte) - if (t == TYPE_FUNC_NAME) { - return 2; - } - // underlying type is char (1 byte) - if (t == TYPE_OPERATOR) { - return 1; - } - if ( - t == TYPE_OPEN_PARENTHESIS || - t == TYPE_CLOSE_PARENTHESIS || - t == TYPE_COMMA - ) { - return 0; - } - return -1; -} - -int is_type_number(unsigned char type) -{ - return type == TYPE_INT || type == TYPE_FLOAT; -} - unsigned char list_get_type(struct List* list, int index) { if (index >= list->num_elements) { return 0; @@ -84,7 +53,7 @@ int list_get(struct List* list, int index, void* resultPtr) if (type == TYPE_OPERATOR) { *((char*) resultPtr) = *((char*) valuePtr); } - if (type == TYPE_FUNC_NAME) { + if (type == TYPE_FUNC_NAME || type == TYPE_VAR_NAME) { *((short*) resultPtr) = *((short*) valuePtr); } @@ -245,6 +214,12 @@ void list_print(struct List* list) printf("type: FUNC_NAME, val: %d", d); } + if (type == TYPE_VAR_NAME) { + short d = 0; + list_get(list, i, &d); + + printf("type: VAR_NAME, val: %d", d); + } if (type == TYPE_OPEN_PARENTHESIS) { printf("type: OPEN_PARENTHESIS"); } diff --git a/src/list.h b/src/list.h index 6e06070..1f5c49f 100644 --- a/src/list.h +++ b/src/list.h @@ -44,13 +44,9 @@ struct List { int data_ptr; int ptrArray[LIST_SIZE]; unsigned char typeArray[LIST_SIZE]; - unsigned char data[LIST_SIZE]; + unsigned char data[LIST_SIZE]; // FIXME: remove this bc we want to use malloc }; -int is_type_number(unsigned char type); - -int get_size_of_type(unsigned char type); - unsigned char list_get_type(struct List* list, int index); int list_get(struct List* list, int index, void* valuePtr); diff --git a/src/state.c b/src/state.c new file mode 100644 index 0000000..e1ae293 --- /dev/null +++ b/src/state.c @@ -0,0 +1,25 @@ +#include "./utils.h" +#include "./var_store.h" +#include "./state.h" +#include + +// #define STATE_LEN 255 +// #define VARIABLES_LEN 255 + +// struct ProcessingState { +// int linePtr; + +// int variableStore[VARIABLES_LEN]; +// int functionStore[255]; +// //int stringStore[255] +// int data[STACK_LEN]; +// }; + +struct StateContainer* state_init() +{ + struct StateContainer* ptr = (struct StateContainer*) malloc(sizeof(struct StateContainer)); + ptr->varStore = var_store_init(); + + return ptr; +} + diff --git a/src/state.h b/src/state.h new file mode 100644 index 0000000..c8c08a5 --- /dev/null +++ b/src/state.h @@ -0,0 +1,26 @@ +/** +This is where we store the state of our program +we store: +- the variables names and their values (for now only int) +- the functions names and their references +*/ +#include "./utils.h" +#include "./var_store.h" +#ifndef STATE_H_ +#define STATE_H_ + +struct StateContainer { + // the line we are currently processing + int linePtr; + // usefull when we are in SKIP_BLOCK mode, we'will count the nb of block (begin/end) + int blocStack; + // FULL, SKIP_BLOC, etc + byte mode; + struct VariableStore* varStore; + // struct FunctionStore* funcStore; + // struct StringStore* strStore ?? +}; + +struct StateContainer* state_init(); + +#endif \ No newline at end of file diff --git a/src/types.c b/src/types.c new file mode 100644 index 0000000..e3681c4 --- /dev/null +++ b/src/types.c @@ -0,0 +1,55 @@ +#include "./utils.h" +#include "./types.h" +#include +#include + +int is_type_number(byte type) +{ + return type == TYPE_INT || type == TYPE_FLOAT; +} + +// get size in byte of a particular type +int get_size_of_type(byte type) +{ + int t = (int) type; + // underlying type is int (4 bytes) + if (t == TYPE_INT || t == TYPE_FLOAT) { + return 4; + } + // underlying type is short (2 bytes) + if (t == TYPE_FUNC_NAME || t == TYPE_VAR_NAME) { + return 2; + } + // underlying type is char (1 byte) + if (t == TYPE_OPERATOR) { + return 1; + } + if ( + t == TYPE_OPEN_PARENTHESIS || + t == TYPE_CLOSE_PARENTHESIS || + t == TYPE_COMMA + ) { + return 0; + } + return -1; +} + +char* get_repr(byte type, void* valPtr) +{ + char* res= (char*) malloc(sizeof(char)*32); + if (type == 0) { + sprintf(res, "NULL"); + return res; + } + if (type == TYPE_INT) { + sprintf(res, "INT(%d)", *((int*) valPtr)); + return res; + } + if (type == TYPE_FLOAT) { + sprintf(res, "FLOAT(%f)", *((float*) valPtr)); + return res; + } + + sprintf(res, "UNKNOWN(%d)", type); + return res; +} diff --git a/src/types.h b/src/types.h index 1223eab..51fcd8a 100644 --- a/src/types.h +++ b/src/types.h @@ -1,8 +1,20 @@ +#include "./utils.h" +#ifndef TYPES_H_ +#define TYPES_H_ #define TYPE_INT 2 #define TYPE_FLOAT 3 #define TYPE_OPERATOR 32 #define TYPE_COMMA 33 #define TYPE_FUNC_NAME 34 +#define TYPE_VAR_NAME 35 #define TYPE_OPEN_PARENTHESIS 64 #define TYPE_CLOSE_PARENTHESIS 65 + +int is_type_number(byte type); + +int get_size_of_type(byte type); + +char* get_repr(byte type, void* data); + +#endif diff --git a/src/utils.h b/src/utils.h index 05e0767..bc2770e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -3,6 +3,9 @@ #define CST_PI 3.1415926535 +// define custom type (unsigned char) +typedef unsigned char byte; + int get_int_rep_from_float(float ft); float get_float_from_int_rep(int representation); @@ -25,6 +28,8 @@ float m_exp(float x); float m_ln(float x); +float m_log(float base, float x); + float m_sin(float x); float m_cos(float x); diff --git a/src/var_store.c b/src/var_store.c new file mode 100644 index 0000000..ba5e290 --- /dev/null +++ b/src/var_store.c @@ -0,0 +1,184 @@ +#include "./types.h" +#include "./var_store.h" +#include +#include +#include + +struct VariableStore* var_store_init() +{ + struct VariableStore* store = (struct VariableStore*) malloc(sizeof(struct VariableStore)); + if (store == NULL) { + printf("[ERR] VARSTORE: malloc failed for variable store \n"); + return NULL; + } + store->allocatedLength = VAR_STORE_INITIAL_ALLOC_LENGTH; + store->length = 0; + store->container = (struct VariableContainer*) malloc(sizeof(struct VariableContainer) * store->allocatedLength); + if (store->container == NULL) { + printf("[ERR] VARSTORE: malloc failed for first variable container \n"); + return NULL; + } + for (int i = 0; i < store->allocatedLength; i++) { + store->container[i].type = 0; + } + return store; +} + +#define MAX_INTEGER 47797852 + +int var_store_hash_name(struct VariableStore* store, char* varName) +{ + int hash = 0; + int i = 0; + while (varName[i] != '\0') { + hash += (get_int_rep_from_char(varName[i])*integer_pow(9, i)) % MAX_INTEGER; + i++; + } + return hash % store->allocatedLength; +} + +byte var_store_set(struct VariableStore* store, char* varName, byte type, void* valuePtr) +{ + //printf("set variable at var name: '%s' \n", varName); + if (!(type == TYPE_FLOAT || type == TYPE_INT)) { + printf("[ERR] VARSTORE: unsupported type, cannot store type %d\n", type); + return 0; + } + void* dataPtr; + if (type == TYPE_FLOAT || type == TYPE_INT) { + dataPtr = malloc(sizeof(int)); + if (dataPtr == NULL) { + printf("[ERR] VARSTORE: malloc failed for data\n"); + return 1; + } + + // copy the value to the place to store + // copy from stack to heap + memcpy(dataPtr, valuePtr, sizeof(int)); + } + + char* namePtr = (char*) malloc(strlen(varName)); + if (namePtr == NULL) { + printf("[ERR] VARSTORE: malloc failed for var name\n"); + return 1; + } + strcpy(namePtr, varName); + + int originalKey = var_store_hash_name(store, varName); + int key = originalKey; + // handle collision, walk along the array + while (1) + { + if (store->container[key].type == 0) { + break; + } + if (strcmp(store->container[key].namePtr, varName) == 0) { + // we found a variable with the same exact key, so we overwrite it + break; + } + key = (key+1) % store->allocatedLength; + if (key == originalKey) { + // end the search to avoid endless loop + printf("[ERR] VARSTORE: cannot set variable, not enough containers \n"); + return 1; + } + } + + //printf("set variable at key: %d \n", key); + store->container[key].type = type; + store->container[key].namePtr = namePtr; + store->container[key].dataPtr = dataPtr; + + store->length++; + if (2*store->length >= store->allocatedLength) { + // do smth to double the store->allocatedLength + // e.g reallocate the store->container + store->allocatedLength = 2*store->allocatedLength; + store->container = (struct VariableContainer*) realloc(store->container, sizeof(struct VariableContainer) * store->allocatedLength); + if (store->container == NULL) { + printf("[ERR] VARSTORE: relloc failed for container \n"); + return 1; + } + } + + return 0; +} + +// get the real position of a variable (in order to handle collisions) +// return -1 if no pos are found +int var_store_get_key(struct VariableStore* store, char* varName) +{ + //printf("get key for %s \n", varName); + int originalKey = var_store_hash_name(store, varName); + int key = originalKey; + // handle collision, walk along the array + while (1) + { + //printf("inter key: %d %d \n", key, store->container[key].type); + if (store->container[key].type == 0) { + return -1; + } + if (strcmp(store->container[key].namePtr, varName) == 0) { + // we found the position + return key; + } + key = (key+1) % store->allocatedLength; + if (key == originalKey) { + return -1; + } + } +} + +byte var_store_exists(struct VariableStore* store, char* varName) +{ + return var_store_get_key(store, varName) != -1; +} + +byte var_store_get_type_from_key(struct VariableStore* store, int key) +{ + return store->container[key].type; +} + +byte var_store_get_type(struct VariableStore* store, char* varName) +{ + int key = var_store_get_key(store, varName); + if (key < 0) { + return 0; + } + + return var_store_get_type_from_key(store, key); +} + +byte var_store_copy_from_key(struct VariableStore* store, int key, void* dst) +{ + if (key < 0) { + return 1; + } + memcpy(dst, store->container[key].dataPtr, (size_t) get_size_of_type(store->container[key].type)); + return 0; +} + +byte var_store_copy(struct VariableStore* store, char* varName, void* dst) +{ + return var_store_copy_from_key(store, var_store_get_key(store, varName), dst); +} + +int var_store_get_int(struct VariableStore* store, char* varName) +{ + if (var_store_get_type(store, varName) != TYPE_INT) { + return 0; + } + int val; + var_store_copy(store, varName, &val); + return val; +} + +float var_store_get_float(struct VariableStore* store, char* varName) +{ + if (var_store_get_type(store, varName) != TYPE_FLOAT) { + return 0; + } + float val; + var_store_copy(store, varName, &val); + return val; +} diff --git a/src/var_store.h b/src/var_store.h new file mode 100644 index 0000000..ee18725 --- /dev/null +++ b/src/var_store.h @@ -0,0 +1,64 @@ +#include "./types.h" +#include "./utils.h" +#ifndef VAR_STORE_H_ +#define VAR_STORE_H_ + +#define VAR_STORE_INITIAL_ALLOC_LENGTH 32 + +/** + +Variable store + +With an Hash Table + +This is a store in the heap + +Features: +- resizable, when we have too much variable we can reallocate more memory to store + +*/ + +struct VariableContainer { + byte type; + char* namePtr; + void* dataPtr; +}; + +struct VariableStore { + int allocatedLength; + int length; + struct VariableContainer* container; // with (storeAllocatedLength) items +}; + +struct VariableStore* var_store_init(); + +int var_store_hash_name(struct VariableStore* store, char* varName); + +// get a pointer to the area of memory where is store the variable +//void* var_store_get_ptr(struct VariableStore* store, char* varName); +int var_store_get_key(struct VariableStore* store, char* varName); + +// return 1 if var exists 0 else +byte var_store_exists(struct VariableStore* store, char* varName); + +// get type of the variable +// return NULL if the var doesn't exists +byte var_store_get_type_from_key(struct VariableStore* store, int key); +byte var_store_get_type(struct VariableStore* store, char* varName); + +byte var_store_copy_from_key(struct VariableStore* store, int key, void* dest); +byte var_store_copy(struct VariableStore* store, char* varName, void* dest); + +// for debug purpose +int var_store_get_int(struct VariableStore* store, char* varName); +float var_store_get_float(struct VariableStore* store, char* varName); + +// OR +//byte var_store_get_ptr(char* varName, void** ptrPtr); + +// store a variable +byte var_store_set(struct VariableStore* store, char* varName, byte type, void* valuePtr); + +byte var_store_delete(struct VariableStore* store, char* varName); + +#endif diff --git a/test.c b/test.c deleted file mode 100644 index 9fdb52b..0000000 --- a/test.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include "./src/types.h" -#include "./src/list.h" -#include "./src/number_parsing.h" -#include "./src/funcs.h" -#include "./src/utils.h" - -int some_computation(int a, int b, int* resPtr) -{ - *resPtr = a+b; - return 0; -} - -float test_func(float x) -{ - return m_float_pow(x,2)-2; -} - -int main () { - // test of euler - printf("lel : %f \n", m_sqrt(64)); - - - // struct List l1; - - // list_append_int(&l1, 4); - // list_append_char(&l1, '*'); - // list_append_int(&l1, 5); - - // list_print(&l1); - - // list_delete(&l1, 0); - - // list_print(&l1); - - // list_delete(&l1, 0); - - // list_print(&l1); - - // float res = 0; - - // void* ptr = &res; - - // printf("%d\n", sizeof(ptr)); - // int found = identify_func_name("ABS"); - // printf("found: %d \n", found); - - // unsigned char argsType[1] = { TYPE_FLOAT }; - // int argsVals[1] = { get_int_rep_from_float(-3.145) }; - // int resVal = 0; - // unsigned char resType = 0; - // execute_func(found, 1, argsType, argsVals, &resVal, &resType); - // printf("func res type: %d \n", resType); - // printf("func res: %f \n", get_float_from_int_rep(resVal)); - - // int stat = parse_float("1052.254", &res); - // printf("float parsing stat: %d \n", stat); - // printf("final float: %f \n", res); -} - diff --git a/tests/test.c b/tests/test.c index 971cd98..5b8c3be 100644 --- a/tests/test.c +++ b/tests/test.c @@ -1,5 +1,6 @@ #include "./test_utils.h" #include "./test_evaluation.h" +#include "./test_line_processing.h" #include int main() @@ -7,4 +8,5 @@ int main() printf("== UNIT TESTS == \n"); test_utils(); test_evaluation(); + test_line_processing(); } diff --git a/tests/test_evaluation.c b/tests/test_evaluation.c index 6e78861..f47c3e9 100644 --- a/tests/test_evaluation.c +++ b/tests/test_evaluation.c @@ -5,68 +5,80 @@ #include "../src/number_parsing.h" #include "../src/utils.h" #include "../src/evaluator.h" +#include "../src/state.h" void test_evaluation() { printf("== test evaluation == \n"); + struct StateContainer* state = state_init(); + // test int parsing int resVal = 0; unsigned char resType = 0; - evaluate("-4", &resVal, &resType); + evaluate(state, "-4", &resVal, &resType); assert(resType == TYPE_INT); assert(-4 == resVal); - evaluate("-(4+9)+1", &resVal, &resType); + evaluate(state, "-(4+9)+1", &resVal, &resType); assert(resType == TYPE_INT); assert(-12 == resVal); - evaluate("(-(8-9+5))+8", &resVal, &resType); + evaluate(state, "(-(8-9+5))+8", &resVal, &resType); assert(resType == TYPE_INT); assert(4 == resVal); - evaluate("2^6", &resVal, &resType); + evaluate(state, "2^6", &resVal, &resType); assert(resType == TYPE_INT); assert(64 == resVal); - evaluate("3 + 4", &resVal, &resType); + evaluate(state, "3 + 4", &resVal, &resType); assert(resType == TYPE_INT); assert(7 == resVal); - evaluate("(2*4)+0+0", &resVal, &resType); + evaluate(state, "(2*4)+0+0", &resVal, &resType); assert(resType == TYPE_INT); assert(8 == resVal); - evaluate("2.5-(2+0.1)", &resVal, &resType); + evaluate(state, "2.5-(2+0.1)", &resVal, &resType); assert(resType == TYPE_FLOAT); assert(float_almost_equal(0.4, get_float_from_int_rep(resVal))); - evaluate("1^0 + (7*(5 +2))", &resVal, &resType); + evaluate(state, "1^0 + (7*(5 +2))", &resVal, &resType); assert(resType == TYPE_INT); assert(50 == resVal); - evaluate("- ( 0.1+ 0.3 )", &resVal, &resType); + evaluate(state, "- ( 0.1+ 0.3 )", &resVal, &resType); assert(resType == TYPE_FLOAT); assert(float_almost_equal(-0.4, get_float_from_int_rep(resVal))); - evaluate("sqrt(2)-1", &resVal, &resType); + evaluate(state, "sqrt(2)-1", &resVal, &resType); assert(resType == TYPE_FLOAT); assert(float_almost_equal(0.41421, get_float_from_int_rep(resVal))); - evaluate("(abs((0-1)*2)) + abs(2)", &resVal, &resType); + evaluate(state, "(abs((0-1)*2)) + abs(2)", &resVal, &resType); assert(resType == TYPE_INT); assert(4 == resVal); - evaluate("exp(2)-1", &resVal, &resType); + evaluate(state, "exp(2)-1", &resVal, &resType); assert(resType == TYPE_FLOAT); assert(float_almost_equal(6.389, get_float_from_int_rep(resVal))); - evaluate("(cos(2)^2)+(sin(2)^2)", &resVal, &resType); + evaluate(state, "(cos(2)^2)+(sin(2)^2)", &resVal, &resType); assert(resType == TYPE_FLOAT); assert(float_almost_equal(1, get_float_from_int_rep(resVal))); - evaluate("random_int(1, 100)", &resVal, &resType); + evaluate(state, "random_int(1, 100)", &resVal, &resType); assert(resType == TYPE_INT); printf(" - random int: %d \n", resVal); + + evaluate(state, "abs(2)+abs(-2)", &resVal, &resType); + assert(resType == TYPE_INT); + assert(4 == resVal); + + // testing function composition is important + evaluate(state, "abs(abs(-2))", &resVal, &resType); + assert(resType == TYPE_INT); + assert(2 == resVal); } diff --git a/tests/test_line_processing.c b/tests/test_line_processing.c new file mode 100644 index 0000000..ca5913f --- /dev/null +++ b/tests/test_line_processing.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include "../src/types.h" +#include "../src/number_parsing.h" +#include "../src/utils.h" +#include "../src/evaluator.h" +#include "../src/state.h" +#include "../src/var_store.h" + +void test_line_processing() +{ + printf("== test line processing == \n"); + + struct StateContainer* state = state_init(); + + assert(process_line(state, "#")); + assert(process_line(state, "# some random comment")); + assert(process_line(state, "set VAR_A to 8.5")); + printf("%d \n", var_store_get_int(state->varStore, "VAR_A")); + assert(float_almost_equal(8.5, var_store_get_float(state->varStore, "VAR_A"))); + + assert(process_line(state, "set VAR_B to 1.5")); + assert(float_almost_equal(1.5, var_store_get_float(state->varStore, "VAR_B"))); + + assert(process_line(state, "set VAR_C to 142")); + assert(142 == var_store_get_int(state->varStore, "VAR_C")); + + assert(process_line(state, "set VAR_D to VAR_A+VAR_B")); + assert(float_almost_equal(10, var_store_get_float(state->varStore, "VAR_D"))); + +} diff --git a/tests/test_line_processing.h b/tests/test_line_processing.h new file mode 100644 index 0000000..2295350 --- /dev/null +++ b/tests/test_line_processing.h @@ -0,0 +1 @@ +void test_line_processing();