feat(Evaluator): add some binary operators

This commit is contained in:
Matthieu Bessat 2022-05-06 13:13:58 +02:00
parent 11fa2b1e6f
commit 14717958c6
5 changed files with 174 additions and 59 deletions

View file

@ -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

View file

@ -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);
if (reduceVarOpStat > 0) {
printf("ERR Evaluator: var name reducing failed, dumping evalList: \n");
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);
return reduceVarOpStat;
}
if (reduceFuncOpStat > 0) {
printf("ERR Evaluator: function reducing failed, dumping evalList: \n");
list_print(&evalList);
return reduceFuncOpStat;
if (stat == 0) {
didReduced = 1;
}
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");

View file

@ -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;
}

View file

@ -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);
}

View file

@ -29,4 +29,6 @@ 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")));
}