feat(Evaluator): add some binary operators
This commit is contained in:
parent
11fa2b1e6f
commit
14717958c6
5 changed files with 174 additions and 59 deletions
|
@ -18,16 +18,16 @@ I didn't really study how others languages works beforehand, I'm just guessing h
|
||||||
ToDo List:
|
ToDo List:
|
||||||
|
|
||||||
- [X] pow operator
|
- [X] pow operator
|
||||||
- [ ] binary operators
|
- [X] binary operators
|
||||||
- [X] implement basic math functions
|
- [X] implement basic math functions
|
||||||
- [X] implement random_int(min, max)
|
- [X] implement random_int(min, max)
|
||||||
- [ ] implement print_number(message)
|
- [X] implement print_number(message)
|
||||||
- [ ] implement input_number()
|
- [ ] implement input_number()
|
||||||
- [ ] base of the CLI
|
- [ ] base of the CLI
|
||||||
- [ ] evaluate expression from stdin
|
- [ ] evaluate expression from stdin
|
||||||
- [ ] read a file
|
- [ ] read a file
|
||||||
- [ ] allow to set variables
|
- [X] allow to set variables
|
||||||
- [ ] read line comments
|
- [X] read line comments
|
||||||
- [ ] conditionals
|
- [ ] conditionals
|
||||||
- [ ] add unit tests
|
- [ ] add unit tests
|
||||||
- [ ] function call stack
|
- [ ] function call stack
|
||||||
|
|
101
src/evaluator.c
101
src/evaluator.c
|
@ -44,7 +44,7 @@ int evaluator_reduce_operator_pattern(struct List* evalList) {
|
||||||
list_get(evalList, patternPos+2, &b);
|
list_get(evalList, patternPos+2, &b);
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
unsigned char typeRes = 0;
|
byte typeRes = 0;
|
||||||
int operateStatus = operate(operator, typeA, a, typeB, b, &typeRes, &res);
|
int operateStatus = operate(operator, typeA, a, typeB, b, &typeRes, &res);
|
||||||
if (operateStatus != 0) {
|
if (operateStatus != 0) {
|
||||||
// the pattern that matched, did not worked as expected
|
// 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++) {
|
for (int i = 0; i < evalList->num_elements; i++) {
|
||||||
if (
|
if (
|
||||||
((i >= 1 && !is_type_number(list_get_type(evalList, i-1))) || (i == 0)) &&
|
((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 &&
|
list_get_type(evalList, i) == TYPE_OPERATOR &&
|
||||||
is_type_number(list_get_type(evalList, i+1))
|
is_type_number(list_get_type(evalList, i+1))
|
||||||
) {
|
) {
|
||||||
char candidateOperator;
|
char candidateOperator;
|
||||||
list_get(evalList, i, &candidateOperator);
|
list_get(evalList, i, &candidateOperator);
|
||||||
if (candidateOperator != '-') {
|
if (candidateOperator != '-') continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
patternPos = i;
|
patternPos = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patternPos == -1) {
|
if (patternPos == -1) return -1;
|
||||||
// we did not find anything to reduce we return negative
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// we found a positive pattern, we gonna reduce
|
// we found a positive pattern, we gonna reduce
|
||||||
int type = list_get_type(evalList, patternPos+1);
|
int type = list_get_type(evalList, patternPos+1);
|
||||||
int val;
|
int val;
|
||||||
|
@ -124,6 +121,43 @@ int evaluator_reduce_minus_pattern(struct List* evalList) {
|
||||||
return 0;
|
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})
|
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) {
|
while (evalList.num_elements > 1) {
|
||||||
list_print(&evalList);
|
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
|
// we are going to look for pattern to reduce
|
||||||
// the order is really important here
|
// the order is really important here
|
||||||
int reduceVarOpStat = evaluator_reduce_var(state, &evalList);
|
byte didReduced = 0;
|
||||||
int reduceFuncOpStat = evaluator_reduce_function_call(&evalList, 0);
|
for (int m = 0; m < 6; m++) {
|
||||||
int reduceMinusOpStat = evaluator_reduce_minus_pattern(&evalList);
|
short stat = 0;
|
||||||
int reduceOperatorOpStat = evaluator_reduce_operator_pattern(&evalList);
|
if (m == 0) stat = evaluator_reduce_var(state, &evalList);
|
||||||
int reduceParenthesisOpStat = evaluator_reduce_parenthesis_pattern(&evalList);
|
if (m == 1) stat = evaluator_reduce_function_call(&evalList, 0);
|
||||||
|
if (m == 2) stat = evaluator_reduce_minus_pattern(&evalList);
|
||||||
if (reduceVarOpStat > 0) {
|
if (m == 3) stat = evaluator_reduce_not_pattern(&evalList);
|
||||||
printf("ERR Evaluator: var name reducing failed, dumping evalList: \n");
|
if (m == 4) stat = evaluator_reduce_operator_pattern(&evalList);
|
||||||
list_print(&evalList);
|
if (m == 5) stat = evaluator_reduce_parenthesis_pattern(&evalList);
|
||||||
return reduceVarOpStat;
|
printf("Tried mod %d got stat %d \n", m, stat);
|
||||||
}
|
if (stat > 0) {
|
||||||
if (reduceFuncOpStat > 0) {
|
printf("ERR Evaluator: mode %d reducing failed, dumping evalList: \n", m);
|
||||||
printf("ERR Evaluator: function reducing failed, dumping evalList: \n");
|
list_print(&evalList);
|
||||||
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 (
|
if (!didReduced) {
|
||||||
reduceVarOpStat == -1 &&
|
|
||||||
reduceFuncOpStat == -1 &&
|
|
||||||
reduceOperatorOpStat == -1 &&
|
|
||||||
reduceParenthesisOpStat == -1 &&
|
|
||||||
reduceMinusOpStat == -1
|
|
||||||
) {
|
|
||||||
// all scans failed to find things to reduce
|
// 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
|
// 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");
|
printf("ERR Evaluator: could not reduce more, dumping evalList: \n");
|
||||||
|
|
|
@ -10,36 +10,74 @@ int is_operator(char candidate) {
|
||||||
candidate == '/' ||
|
candidate == '/' ||
|
||||||
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(
|
int operate(
|
||||||
unsigned char operator,
|
byte operator,
|
||||||
unsigned char typeA, int aRepr,
|
byte typeA, int aRepr,
|
||||||
unsigned char typeB, int bRepr,
|
byte typeB, int bRepr,
|
||||||
unsigned char* typeRes, int* resPtr
|
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 (
|
if (
|
||||||
typeA == TYPE_FLOAT || typeB == TYPE_FLOAT ||
|
typeA == TYPE_FLOAT || typeB == TYPE_FLOAT ||
|
||||||
operator == '/'
|
operator == '/'
|
||||||
) {
|
) {
|
||||||
*typeRes = TYPE_FLOAT;
|
*typeRes = TYPE_FLOAT;
|
||||||
float a, b, res;
|
float a, b, res;
|
||||||
if (typeA == TYPE_FLOAT) {
|
a = convert_to_float(typeA, aRepr);
|
||||||
*((int*) &a) = aRepr;
|
b = convert_to_float(typeB, bRepr);
|
||||||
}
|
|
||||||
if (typeB == TYPE_FLOAT) {
|
|
||||||
*((int*) &b) = bRepr;
|
|
||||||
}
|
|
||||||
if (typeA == TYPE_INT) {
|
|
||||||
a = (float) aRepr;
|
|
||||||
}
|
|
||||||
if (typeB == TYPE_INT) {
|
|
||||||
b = (float) bRepr;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Appling operation: %f %c %f \n", a, operator, b);
|
printf("Appling operation: %f %c %f \n", a, operator, b);
|
||||||
|
|
||||||
|
@ -53,6 +91,8 @@ int operate(
|
||||||
res = a/b;
|
res = a/b;
|
||||||
} else if (operator == '^') {
|
} else if (operator == '^') {
|
||||||
res = m_float_pow(a, b);
|
res = m_float_pow(a, b);
|
||||||
|
} else if (operator == '=') {
|
||||||
|
res = (int) (a == b);
|
||||||
} else {
|
} else {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +113,8 @@ int operate(
|
||||||
res = aRepr*bRepr;
|
res = aRepr*bRepr;
|
||||||
} else if (operator == '^') {
|
} else if (operator == '^') {
|
||||||
res = integer_pow(aRepr, bRepr);
|
res = integer_pow(aRepr, bRepr);
|
||||||
|
} else if (operator == '=') {
|
||||||
|
res = (int) (aRepr == bRepr);
|
||||||
} else {
|
} else {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,4 +81,44 @@ void test_evaluation()
|
||||||
evaluate(state, "abs(abs(-2))", &resVal, &resType);
|
evaluate(state, "abs(abs(-2))", &resVal, &resType);
|
||||||
assert(resType == TYPE_INT);
|
assert(resType == TYPE_INT);
|
||||||
assert(2 == resVal);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,4 +29,6 @@ void test_line_processing()
|
||||||
assert(process_line(state, "set VAR_D to VAR_A+VAR_B"));
|
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(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")));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue