From 14717958c628497b8cafb2250b32ae8e4e64ae2c Mon Sep 17 00:00:00 2001 From: Matthieu Bessat Date: Fri, 6 May 2022 13:13:58 +0200 Subject: [PATCH] feat(Evaluator): add some binary operators --- README.md | 8 +-- src/evaluator.c | 103 +++++++++++++++++++++++------------ src/operate.c | 78 ++++++++++++++++++++------ tests/test_evaluation.c | 40 ++++++++++++++ tests/test_line_processing.c | 4 +- 5 files changed, 174 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index dc01e59..64d0345 100644 --- a/README.md +++ b/README.md @@ -18,16 +18,16 @@ I didn't really study how others languages works beforehand, I'm just guessing h ToDo List: - [X] pow operator -- [ ] binary operators +- [X] binary operators - [X] implement basic math functions - [X] implement random_int(min, max) -- [ ] implement print_number(message) +- [X] implement print_number(message) - [ ] implement input_number() - [ ] base of the CLI - [ ] evaluate expression from stdin - [ ] read a file -- [ ] allow to set variables -- [ ] read line comments +- [X] allow to set variables +- [X] read line comments - [ ] conditionals - [ ] add unit tests - [ ] function call stack diff --git a/src/evaluator.c b/src/evaluator.c index a2cfd41..2a9c839 100644 --- a/src/evaluator.c +++ b/src/evaluator.c @@ -44,7 +44,7 @@ int evaluator_reduce_operator_pattern(struct List* evalList) { list_get(evalList, patternPos+2, &b); int res = 0; - unsigned char typeRes = 0; + byte typeRes = 0; int operateStatus = operate(operator, typeA, a, typeB, b, &typeRes, &res); if (operateStatus != 0) { // the pattern that matched, did not worked as expected @@ -80,24 +80,21 @@ int evaluator_reduce_minus_pattern(struct List* evalList) { for (int i = 0; i < evalList->num_elements; i++) { if ( ((i >= 1 && !is_type_number(list_get_type(evalList, i-1))) || (i == 0)) && + ((i >= 1 && list_get_type(evalList, i-1) != TYPE_CLOSE_PARENTHESIS) || (i == 0)) && list_get_type(evalList, i) == TYPE_OPERATOR && is_type_number(list_get_type(evalList, i+1)) ) { char candidateOperator; list_get(evalList, i, &candidateOperator); - if (candidateOperator != '-') { - continue; - } + if (candidateOperator != '-') continue; patternPos = i; break; } } - if (patternPos == -1) { - // we did not find anything to reduce we return negative - return -1; - } + if (patternPos == -1) return -1; + // we found a positive pattern, we gonna reduce int type = list_get_type(evalList, patternPos+1); int val; @@ -124,6 +121,43 @@ int evaluator_reduce_minus_pattern(struct List* evalList) { return 0; } +int evaluator_reduce_not_pattern(struct List* evalList) { + int patternPos = -1; + for (int i = 0; i < evalList->num_elements; i++) { + if ( + list_get_type(evalList, i) == TYPE_OPERATOR && + is_type_number(list_get_type(evalList, i+1)) + ) { + char candidateOperator; + list_get(evalList, i, &candidateOperator); + if (candidateOperator != '!') continue; + + patternPos = i; + break; + } + } + + if (patternPos == -1) return -1; + + int type = list_get_type(evalList, patternPos+1); + int val; + list_get(evalList, patternPos+1, &val); + + int res = 0; + byte typeRes = 0; + int operateStatus = operate('!', 0, 0, type, val, &typeRes, &res); + if (operateStatus != 0) { + printf("ERR Evaluator: cannot operate \n"); + return 400; + } + + if (typeRes != TYPE_INT) return 300; + + list_set(evalList, patternPos, typeRes, &res); + list_delete(evalList, patternPos+1); + + return 0; +} /** This sub script will look for pattern like ({Number}) @@ -525,37 +559,34 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig while (evalList.num_elements > 1) { list_print(&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); + // we are going to look for pattern to reduce // the order is really important here - 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); + byte didReduced = 0; + for (int m = 0; m < 6; m++) { + short stat = 0; + if (m == 0) stat = evaluator_reduce_var(state, &evalList); + if (m == 1) stat = evaluator_reduce_function_call(&evalList, 0); + if (m == 2) stat = evaluator_reduce_minus_pattern(&evalList); + if (m == 3) stat = evaluator_reduce_not_pattern(&evalList); + if (m == 4) stat = evaluator_reduce_operator_pattern(&evalList); + if (m == 5) stat = evaluator_reduce_parenthesis_pattern(&evalList); + printf("Tried mod %d got stat %d \n", m, stat); + if (stat > 0) { + printf("ERR Evaluator: mode %d reducing failed, dumping evalList: \n", m); + list_print(&evalList); + } + if (stat == 0) { + didReduced = 1; + } + } - 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 reduceFuncOpStat; - } - if (reduceOperatorOpStat > 0) { - printf("ERR Evaluator: operator reducing failed, dumping evalList: \n"); - list_print(&evalList); - return reduceOperatorOpStat; - } - - if ( - reduceVarOpStat == -1 && - reduceFuncOpStat == -1 && - reduceOperatorOpStat == -1 && - reduceParenthesisOpStat == -1 && - reduceMinusOpStat == -1 - ) { + if (!didReduced) { // all scans failed to find things to reduce // this is actually a failure because we can't do anything to get down to 1 element in the eval list printf("ERR Evaluator: could not reduce more, dumping evalList: \n"); diff --git a/src/operate.c b/src/operate.c index e223067..4392171 100644 --- a/src/operate.c +++ b/src/operate.c @@ -10,36 +10,74 @@ int is_operator(char candidate) { candidate == '/' || candidate == '+' || candidate == '-' || - candidate == '^' + candidate == '^' || + candidate == '=' || + candidate == '!' || + candidate == '&' || + candidate == '|' ); } +int convert_to_int(byte type, int repr) { + if (type == TYPE_FLOAT) return (int) *((int*) &repr); + return repr; +} + +float convert_to_float(byte type, int repr) { + if (type == TYPE_INT) return (float) repr; + return *((float*) &repr); +} + int operate( - unsigned char operator, - unsigned char typeA, int aRepr, - unsigned char typeB, int bRepr, - unsigned char* typeRes, int* resPtr + byte operator, + byte typeA, int aRepr, + byte typeB, int bRepr, + byte* typeRes, int* resPtr ) { - + if (operator == '!') { + *typeRes = TYPE_INT; + // we will only take type B to emphezize that this unary operator is at the left of the only argument + int x = 0; + if (typeB == TYPE_FLOAT) x = (int) *((float*) &bRepr); + if (typeB == TYPE_INT) x = bRepr; + + if (x == 0) *resPtr = 1; + if (x != 0) *resPtr = 0; + + return 0; + } + if (operator == '=') { + *typeRes = TYPE_INT; + if (typeA == TYPE_FLOAT || typeB == TYPE_FLOAT) { + *resPtr = (int) convert_to_float(typeA, aRepr) == convert_to_float(typeB, bRepr); + } + if (typeA == TYPE_INT && typeB == TYPE_INT) { + *resPtr = (int) aRepr == bRepr; + } + + return 0; + } + if (operator == '&') { + *typeRes = TYPE_INT; + *resPtr = (int) (convert_to_int(typeA, aRepr) & convert_to_int(typeB, bRepr)); + + return 0; + } + if (operator == '|') { + *typeRes = TYPE_INT; + *resPtr = (int) (convert_to_int(typeA, aRepr) | convert_to_int(typeB, bRepr)); + + return 0; + } if ( typeA == TYPE_FLOAT || typeB == TYPE_FLOAT || operator == '/' ) { *typeRes = TYPE_FLOAT; float a, b, res; - if (typeA == TYPE_FLOAT) { - *((int*) &a) = aRepr; - } - if (typeB == TYPE_FLOAT) { - *((int*) &b) = bRepr; - } - if (typeA == TYPE_INT) { - a = (float) aRepr; - } - if (typeB == TYPE_INT) { - b = (float) bRepr; - } + a = convert_to_float(typeA, aRepr); + b = convert_to_float(typeB, bRepr); printf("Appling operation: %f %c %f \n", a, operator, b); @@ -53,6 +91,8 @@ int operate( res = a/b; } else if (operator == '^') { res = m_float_pow(a, b); + } else if (operator == '=') { + res = (int) (a == b); } else { return 2; } @@ -73,6 +113,8 @@ int operate( res = aRepr*bRepr; } else if (operator == '^') { res = integer_pow(aRepr, bRepr); + } else if (operator == '=') { + res = (int) (aRepr == bRepr); } else { return 2; } diff --git a/tests/test_evaluation.c b/tests/test_evaluation.c index f47c3e9..7188c3c 100644 --- a/tests/test_evaluation.c +++ b/tests/test_evaluation.c @@ -81,4 +81,44 @@ void test_evaluation() evaluate(state, "abs(abs(-2))", &resVal, &resType); assert(resType == TYPE_INT); assert(2 == resVal); + + evaluate(state, "2 = 2", &resVal, &resType); + assert(resType == TYPE_INT); + assert(1 == resVal); + + evaluate(state, "2 = 3", &resVal, &resType); + assert(resType == TYPE_INT); + assert(0 == resVal); + + evaluate(state, "2 = 3.2", &resVal, &resType); + assert(resType == TYPE_INT); + assert(0 == resVal); + + evaluate(state, "!(2 = 3)", &resVal, &resType); + assert(resType == TYPE_INT); + assert(1 == resVal); + + evaluate(state, "!! 0", &resVal, &resType); + assert(resType == TYPE_INT); + assert(0 == resVal); + + evaluate(state, "(! (! 1)) + 0", &resVal, &resType); + assert(resType == TYPE_INT); + assert(1 == resVal); + + evaluate(state, "!!2", &resVal, &resType); + assert(resType == TYPE_INT); + assert(1 == resVal); + + evaluate(state, "1 & 1", &resVal, &resType); + assert(resType == TYPE_INT); + assert(1 == resVal); + + evaluate(state, "1 & ((1+0)-1)", &resVal, &resType); + assert(resType == TYPE_INT); + assert(0 == resVal); + + evaluate(state, "1 & (1 | 0)", &resVal, &resType); + assert(resType == TYPE_INT); + assert(1 == resVal); } diff --git a/tests/test_line_processing.c b/tests/test_line_processing.c index ca5913f..5de92ae 100644 --- a/tests/test_line_processing.c +++ b/tests/test_line_processing.c @@ -28,5 +28,7 @@ void test_line_processing() 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"))); - + + 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"))); }