feat(Evaluator): add pow operator

feat(Evaluator): add minus sign reducing
fix(Evaluator): trim spaces
test: add base for unit testing
This commit is contained in:
Matthieu Bessat 2022-04-30 16:16:37 +02:00
parent 17c7c247af
commit a62dd411aa
20 changed files with 654 additions and 137 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
./main
./test
main
bin/*

View file

@ -2,5 +2,11 @@ WERROR?=
CFLAGS=-Wall -Wextra $(WERROR) -pedantic -I.
CXXFLAGS_WITHOUT_PKGS=$(CFLAGS) -fno-exceptions -Wno-missing-braces -Wswitch-enum -lm
TEST_SRCS_ENC := $(foreach DIR,src,$(patsubst $(DIR)/%,%,$(wildcard ./src/*.c)))
TEST_SRCS_ENC := $(filter-out %main.c, $(TEST_SRCS_ENC))
build:
gcc src/* -o ./main ${CXXFLAGS_WITHOUT_PKGS}
gcc src/* -o ./bin/main ${CXXFLAGS_WITHOUT_PKGS}
test:
gcc ${TEST_SRCS_ENC} ./tests/* -o ./bin/test ${CXXFLAGS_WITHOUT_PKGS}
./bin/test

View file

@ -69,6 +69,59 @@ int evaluator_reduce_operator_pattern(struct List* evalList) {
return 0;
}
/**
This sub script will look for pattern like Operator (minus sign) Number
and evaluate that
*/
int evaluator_reduce_minus_pattern(struct List* evalList) {
int patternPos = -1;
for (int i = 0; i < evalList->num_elements; i++) {
if (
((i >= 1 && !is_type_number(list_get_type(evalList, i-1))) || (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;
}
patternPos = i;
break;
}
}
if (patternPos == -1) {
// we did not find anything to reduce we return negative
return -1;
}
// we found a positive pattern, we gonna reduce
int type = list_get_type(evalList, patternPos+1);
int val;
list_get(evalList, patternPos+1, &val);
int res = 0;
unsigned char typeRes = 0;
int operateStatus = operate('*', TYPE_INT, -1, type, val, &typeRes, &res);
if (operateStatus != 0) {
printf("ERR Evaluator: cannot operate \n");
return 400;
}
if (typeRes == TYPE_INT) {
list_set(evalList, patternPos, TYPE_INT, &res);
}
if (typeRes == TYPE_FLOAT) {
// FIXME: invalid type set, we need to flag for float
list_set(evalList, patternPos, TYPE_FLOAT, &res);
}
list_delete(evalList, patternPos+1);
return 0;
}
/**
This sub script will look for pattern like ({Number})
@ -78,6 +131,7 @@ int evaluator_reduce_parenthesis_pattern(struct List* evalList) {
int patternPos = -1;
for (int i = 0; i < evalList->num_elements; i++) {
if (
((i >= 1 && list_get_type(evalList, i-1) != TYPE_FUNC_NAME) || (i == 0)) &&
list_get_type(evalList, i) == TYPE_OPEN_PARENTHESIS &&
is_type_number(list_get_type(evalList, i+1)) &&
list_get_type(evalList, i+2) == TYPE_CLOSE_PARENTHESIS
@ -118,26 +172,13 @@ if we don't find that, we throw an error
int evaluator_reduce_function_call(struct List* evalList) {
int patternPos = -1;
short argsLen = 0;
for (int i = 0; i < evalList->num_elements; i++) {
if (
(list_get_type(evalList, i) == TYPE_FUNC_NAME &&
list_get_type(evalList, i+1) == TYPE_OPEN_PARENTHESIS &&
is_type_number(list_get_type(evalList, i+2)))
) {
// mode: we have at least one argument
patternPos = i;
argsLen = 1;
break;
}
if (
list_get_type(evalList, i) == TYPE_FUNC_NAME &&
list_get_type(evalList, i+1) == TYPE_OPEN_PARENTHESIS &&
list_get_type(evalList, i+2) == TYPE_CLOSE_PARENTHESIS
list_get_type(evalList, i+1) == TYPE_OPEN_PARENTHESIS
) {
// special mode: functions call with no arguments
// mode: we have a function call
patternPos = i;
argsLen = 0;
break;
}
}
@ -151,39 +192,54 @@ int evaluator_reduce_function_call(struct List* evalList) {
// fetch the function ID
list_get(evalList, patternPos, &funcID);
short argsLen = 0;
int pos = patternPos+2;
if (argsLen > 0) {
// now we know we have a start of a function
// we gonna start to look if there is others arguments
// two case: either we have another arguments or we have a closing parenthesis
pos = patternPos+3;
while (1) {
if (argsLen > 16) {
printf("ERR Evaluator: too many arguments passed to func \n");
return 100;
}
if (
list_get_type(evalList, pos) == TYPE_COMMA &&
is_type_number(list_get_type(evalList, pos+1))
) {
// another argument
pos += 2;
argsLen++;
continue;
}
if (
(
list_get_type(evalList, pos) == TYPE_COMMA &&
list_get_type(evalList, pos+1) == TYPE_CLOSE_PARENTHESIS
) || (list_get_type(evalList, pos) == TYPE_CLOSE_PARENTHESIS)
) {
// we close the function call
break;
}
printf("ERR Evaluator: cannot reduce function call \n");
// now we know we have a start of a function
// we gonna start to look if there is others arguments
// two case: either we have another arguments or we have a closing parenthesis
while (1) {
if (argsLen > 16) {
printf("ERR Evaluator: too many arguments passed to func (max out the limit) \n");
return 100;
}
if (
list_get_type(evalList, pos) == TYPE_CLOSE_PARENTHESIS
) {
// end of the function call
pos += 0;
break;
}
if (
list_get_type(evalList, pos) == TYPE_COMMA &&
list_get_type(evalList, pos+1) == TYPE_CLOSE_PARENTHESIS
) {
// end of the function call
pos += 1;
break;
}
if (
is_type_number(list_get_type(evalList, pos)) &&
list_get_type(evalList, pos+1) == TYPE_COMMA
) {
// this is a new argument
pos += 2;
argsLen++;
continue;
}
if (
is_type_number(list_get_type(evalList, pos)) &&
list_get_type(evalList, pos+1) == TYPE_CLOSE_PARENTHESIS
) {
// we didn't match the last pattern so it's the last argument
pos += 1;
argsLen++;
continue;
}
// 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;
}
// now pos is the index of the last component for this func call
@ -209,13 +265,18 @@ int evaluator_reduce_function_call(struct List* evalList) {
// now we can delete in the list from pos+1 patternPos to pos
// just delete N-1 times where N is the number of components in the func call
//printf("start: %d, end: %d \n", patternPos, pos);
//printf("patternPos: %d, pos: %d \n", patternPos, pos);
for (int j = 0; j < (pos-patternPos); j++) {
list_delete(evalList, patternPos);
}
//printf("list report after deleting after applying a func \n");
//list_print(evalList);
//printf("patternPos: %d, resType: %d \n", patternPos, resType);
list_set(evalList, patternPos, resType, &resVal);
return 0;
}
@ -226,7 +287,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, int* typePtr) {
int evaluate(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
@ -315,19 +376,55 @@ int evaluate(char* inputStr, int* resultPtr, int* typePtr) {
}
struct List evalList;
// NOTICE: for some reason the struct don't reset after a usage
list_reset(&evalList);
printf("\n - constructing list \n");
// initializing the evaluation list
for (int j = 0; j < partitionPtr; j++) {
int len = partitionStopPos[j] - partitionStartPos[j];
int startPos = partitionStartPos[j];
int stopPos = partitionStopPos[j];
printf("=== %d\n", j);
printf("startPos %d, stopPos %d\n", startPos, stopPos);
int len = stopPos - startPos;
// 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;
len = stopPos - startPos;
char buff[_len+1];
buff[0] = 0;
// fill the buffer with the component string
for (int z = 0; z < len; z++) {
buff[z] = inputStr[partitionStartPos[j]+z];
buff[z] = inputStr[startPos+z];
}
buff[len] = 0; // terminate the buff
// TODO: SPLIT INTO A FUNCTION "identify_token(char* str)"
buff[len] = 0;
printf("buff: '%s' \n", buff);
char dumbValue = (char) 0;
if (buff[0] == '\0') {
continue;
}
if (len == 1 && buff[0] == '(') {
list_set(&evalList, evalList.num_elements, TYPE_OPEN_PARENTHESIS, &dumbValue);
continue;
@ -341,6 +438,7 @@ int evaluate(char* inputStr, int* resultPtr, int* typePtr) {
continue;
}
if (len == 1 && is_operator(buff[0])) {
printf("found op\n");
char opValue = buff[0];
list_set(&evalList, evalList.num_elements, TYPE_OPERATOR, &opValue);
continue;
@ -374,6 +472,7 @@ int evaluate(char* inputStr, int* resultPtr, int* typePtr) {
list_set(&evalList, evalList.num_elements, TYPE_FUNC_NAME, &funcID);
}
}
printf("end of l\n");
}
// check the content of this thing
@ -383,10 +482,10 @@ int evaluate(char* inputStr, int* resultPtr, int* typePtr) {
while (evalList.num_elements > 1) {
list_print(&evalList);
// we are going to look for pattern
// - 0. OPENP NUM CLOSEP
// - 1. NUM OP NUM
// we are going to look for pattern to reduce
// the order is really important here
int reduceFuncOpStat = evaluator_reduce_function_call(&evalList);
int reduceMinusOpStat = evaluator_reduce_minus_pattern(&evalList);
int reduceOperatorOpStat = evaluator_reduce_operator_pattern(&evalList);
int reduceParenthesisOpStat = evaluator_reduce_parenthesis_pattern(&evalList);
@ -401,7 +500,12 @@ int evaluate(char* inputStr, int* resultPtr, int* typePtr) {
return reduceOperatorOpStat;
}
if (reduceFuncOpStat == -1 && reduceOperatorOpStat == -1 && reduceParenthesisOpStat == -1) {
if (
reduceFuncOpStat == -1 &&
reduceOperatorOpStat == -1 &&
reduceParenthesisOpStat == -1 &&
reduceMinusOpStat == -1
) {
// 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

@ -1,6 +1,6 @@
#ifndef EVALUATOR_H_
#define EVALUATOR_H_
int evaluate(char* inputStr, int* resultPtr, int* typePtr);
int evaluate(char* inputStr, int* resultPtr, unsigned char* typePtr);
#endif

View file

@ -2,16 +2,15 @@
#include <string.h>
#include <math.h>
#include "./types.h"
#include "./repr_utils.h"
#include "./utils.h"
int abs_implementation(int* res, unsigned char* resType, unsigned char* types, int* args)
{
if (types[0] == TYPE_INT) {
*res = args[0];
if (args[0] < 0) {
*res = -args[0];
return 0;
}
*res = args[0];
*resType = TYPE_INT;
return 0;
}
@ -73,7 +72,7 @@ int max_implementation(int* res, unsigned char* resType, unsigned char* types, i
int get_pi_implementation(int* res, unsigned char* resType, unsigned char* types, int* args)
{
float val = 3.1415926535;
float val = CST_PI;
*res = *(int *)(&val);
*resType = TYPE_FLOAT;
return 0;
@ -88,10 +87,10 @@ struct FuncIntro {
// void* are actually long!
struct FuncIntro intros[] = {
{"ABS", &abs_implementation, 1},
{"SQRT", &sqrt_implementation, 1},
{"MAX", &max_implementation, 2},
{"GET_PI", &get_pi_implementation, 0},
{"abs", &abs_implementation, 1},
{"sqrt", &sqrt_implementation, 1},
{"max", &max_implementation, 2},
{"get_pi", &get_pi_implementation, 0},
{"", 0, 0}
};
@ -135,7 +134,13 @@ int execute_func(short funcID, short argsLen, unsigned char* argsTypes, int* arg
// call the function implementation
// first cast the function ptr
impl(resPtr, resTypePtr, argsTypes, argsValues);
printf("Got %d \n", *resPtr);
if (*resTypePtr == TYPE_FLOAT) {
printf("Got TYPE_FLOAT with val: %f \n", get_float_from_int_rep(*resPtr));
} else if (*resTypePtr == TYPE_INT) {
printf("Got TYPE_INT with val: %d \n", *resPtr);
} else {
printf("Got WTF NOTHING (%d) with val: %d \n", *resTypePtr, *resPtr);
}
return 0;
}

View file

@ -194,6 +194,15 @@ int list_delete(struct List* list, int index)
return 0;
}
void list_reset(struct List* list)
{
for (int i = 0; i < list->num_elements; i++) {
list_delete(list, 0);
}
list->data_ptr = 0;
list->bytes_used = 0;
list->num_elements = 0;
}
int list_append_int(struct List* list, int value)
{

View file

@ -68,4 +68,6 @@ int list_delete(struct List* list, int index);
void list_print(struct List*);
void list_reset(struct List* list);
#endif

View file

@ -5,7 +5,7 @@
#include "./list.h"
#include "./number_parsing.h"
#include "./evaluator.h"
#include "./repr_utils.h"
#include "./utils.h"
#include "./types.h"
//int create_stack(int a, int b)

View file

@ -1,29 +1,7 @@
#include <stdio.h>
#include <string.h>
#include "./number_parsing.h"
int is_char_numeral(char candidate) {
int n = (int) candidate;
return (n >= 48 && n <= 57);
}
int integer_pow(int base, int exponent)
{
if (exponent == 0) return 1;
int r = 1;
int multiplier = base;
while (exponent) {
// if exponent is even
if (exponent & 1) {
r *= multiplier;
}
multiplier *= multiplier;
exponent >>= 1; // divide by two the exponent
}
return r;
}
#include "./utils.h"
int parse_clean_positive_integer(int inputStrLen, char* inputStr, int* result) {
/**
@ -152,8 +130,8 @@ int parse_float(char* inputStr, float* resultPtr) {
}
cleanStrIntPart[cleanStrIntPartLen] = 0;
cleanStrFloatPart[cleanStrFloatPartLen] = 0;
printf("clean str int part: /%s/ \n", cleanStrIntPart);
printf("clean str float part: /%s/ \n", cleanStrFloatPart);
// printf("clean str int part: /%s/ \n", cleanStrIntPart);
// printf("clean str float part: /%s/ \n", cleanStrFloatPart);
int intPart = 0;
parse_clean_positive_integer(cleanStrIntPartLen, cleanStrIntPart, &intPart);

View file

@ -1,14 +1,16 @@
#include "./operate.h"
#include "./types.h"
#include <stdio.h>
#include <string.h>
#include "./operate.h"
#include "./types.h"
#include "./utils.h"
int is_operator(char candidate) {
return (
candidate == '*' ||
candidate == '/' ||
candidate == '+' ||
candidate == '-'
candidate == '-' ||
candidate == '^'
);
}
@ -49,6 +51,8 @@ int operate(
res = a*b;
} else if (operator == '/') {
res = a/b;
} else if (operator == '^') {
res = 0;
} else {
return 2;
}
@ -67,6 +71,8 @@ int operate(
res = aRepr-bRepr;
} else if (operator == '*') {
res = aRepr*bRepr;
} else if (operator == '^') {
res = integer_pow(aRepr, bRepr);
} else {
return 2;
}

View file

@ -1,23 +0,0 @@
#include "./repr_utils.h"
int get_int_rep_from_float(float ft)
{
return *(int *)(&ft);
}
/**
* Get a single precision floating point from int representation
* (following IEEE 754)
*/
float get_float_from_int_rep(int representation)
{
float res;
*((int*) &res) = representation;
return res;
}
int get_int_rep_from_char(char c)
{
return *(int *)(&c);
}

View file

@ -1,10 +0,0 @@
#ifndef REPR_UTILS_H_
#define REPR_UTILS_H_
int get_int_rep_from_float(float ft);
float get_float_from_int_rep(int representation);
int get_int_rep_from_char(char c);
#endif

255
src/utils.c Normal file
View file

@ -0,0 +1,255 @@
#include <stdio.h>
#include "./utils.h"
int get_int_rep_from_float(float ft)
{
return *(int *)(&ft);
}
/**
* Get a single precision floating point from int representation
* (following IEEE 754)
*/
float get_float_from_int_rep(int representation)
{
float res;
*((int*) &res) = representation;
return res;
}
int get_int_rep_from_char(char c)
{
return *(int *)(&c);
}
int is_char_numeral(char candidate)
{
int n = (int) candidate;
return (n >= 48 && n <= 57);
}
int float_almost_equal(float a, float b)
{
float diff = a-b;
if (diff < 0) diff = -diff;
return diff < 0.001;
}
int abs_int(int a)
{
return a < 0 ? -a : a;
}
float abs_float(float a)
{
return a < 0 ? -a : a;
}
int integer_pow(int base, int exponent)
{
if (exponent == 0) return 1;
int r = 1;
int multiplier = base;
while (exponent) {
// if exponent is even
if (exponent & 1) {
r *= multiplier;
}
multiplier *= multiplier;
exponent >>= 1; // divide by two the exponent
}
return r;
}
float m_float_pow(float base, int exponent)
{
if (exponent == 0) return 1;
float r = 1;
float multiplier = base;
while (exponent) {
// if exponent is even
if (exponent & 1) {
r *= multiplier;
}
multiplier *= multiplier;
exponent >>= 1; // divide by two the exponent
}
return r;
}
int m_factorial(int x)
{
if (x == 0 || x == 1) {
return 1;
}
int res = 1;
for (int i = 2; i < x+1; i++) {
res *= i;
}
return res;
}
float m_exp(float x)
{
const int n = 10;
float out = 0;
for (int i = 0; i < n; i++) {
out += m_float_pow(x, i)/m_factorial(i);
}
return out;
}
float m_float_mod(float a, float b)
{
float mod;
// Handling negative values
if (a < 0)
mod = -a;
else
mod = a;
if (b < 0)
b = -b;
// Finding mod by repeated subtraction
while (mod >= b)
mod = mod - b;
// Sign of result typically depends
// on sign of a.
if (a < 0)
return -mod;
return mod;
}
float m_sin(float originalX)
{
// use cycles in expension series
if (originalX > 2*CST_PI) {
originalX = m_float_mod(originalX, (float) (2*CST_PI));
}
float x = originalX;
if (originalX > CST_PI) {
x -= CST_PI;
}
const int n = 6;
float out = 0;
int sign = 1;
for (int i = 0; i < n; i++) {
out += sign*(m_float_pow(x, 2*i+1)/m_factorial(2*i+1));
if (sign == 1) {
sign = -1;
} else {
sign = 1;
}
}
if (originalX > CST_PI) {
return -out;
}
return out;
}
float m_cos(float x)
{
return m_sin(x+2*CST_PI);
}
float m_tan(float x)
{
return m_sin(x)/m_cos(x);
}
// float m_get_derivative(float (*func)(float), float a)
// {
// float h = 0.0001;
// return ((func(a+h)-func(a))/h);
// }
// euler method in one dimension
// takes a function and find one of the root
// return the status 0 if success >0 if error
int m_euler_method(float (*func)(float, float), float param, float startsAt, float* resPtr)
{
// (x-b)f'(b)+f(b) = 0
// xf'(b)-bf'(b)+f(b) = 0
// x = (-f(b)+bf'(b))/f'(b)
float cursor = startsAt;
float newCursor = 0;
float derivative = 0;
short runs = 0;
const float h = 0.0001;
while (1)
{
derivative = (func(param, cursor+h)-func(param, cursor))/h;
newCursor = cursor - func(param, cursor)/derivative;
if (abs_float(cursor - newCursor) < 0.0001) {
*resPtr = (cursor + newCursor)/2;
return 0;
}
if (runs > 100) {
printf("ERR: euler methods failed, coup dur pour euler \n");
return 100;
}
cursor = newCursor;
runs++;
}
return 101;
}
float m_sqrt_equation(float x, float y)
{
return m_float_pow(y,2)-x;
}
float m_sqrt(float x)
{
float res = 0;
m_euler_method(&m_sqrt_equation, x, 4, &res);
return res;
}
float m_ln_equation(float x, float y)
{
return m_exp(y)-x;
}
float m_ln(float x)
{
float res = 0;
m_euler_method(&m_ln_equation, x, 4, &res);
return res;
}
int is_full_of_space(char* str)
{
int i = 0;
while (str[i] != '\0') {
if (str[i] != ' ') {
return 0;
}
i++;
}
return 1;
}
char* trim_space(char* str)
{
// TODO: implements me
return str;
}

38
src/utils.h Normal file
View file

@ -0,0 +1,38 @@
#ifndef UTILS_H_
#define UTILS_H_
#define CST_PI 3.1415926535
int get_int_rep_from_float(float ft);
float get_float_from_int_rep(int representation);
int get_int_rep_from_char(char c);
int is_char_numeral(char candidate);
int integer_pow(int base, int exponent);
int float_almost_equal(float a, float b);
int m_factorial(int x);
float m_float_pow(float base, int exponent);
float m_sqrt(float x);
float m_exp(float x);
float m_ln(float x);
float m_sin(float x);
float m_cos(float x);
float m_tan(float x);
int is_full_of_space(char* str);
char* trim_space(char* str);
#endif

29
test.c
View file

@ -3,7 +3,7 @@
#include "./src/list.h"
#include "./src/number_parsing.h"
#include "./src/funcs.h"
#include "./src/repr_utils.h"
#include "./src/utils.h"
int some_computation(int a, int b, int* resPtr)
{
@ -11,7 +11,16 @@ int some_computation(int a, int b, int* resPtr)
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);
@ -33,16 +42,16 @@ int main () {
// void* ptr = &res;
// printf("%d\n", sizeof(ptr));
int found = identify_func_name("ABS");
printf("found: %d \n", found);
// 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));
// 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);

10
tests/test.c Normal file
View file

@ -0,0 +1,10 @@
#include "./test_utils.h"
#include "./test_evaluation.h"
#include <stdio.h>
int main()
{
printf("== UNIT TESTS == \n");
test_utils();
test_evaluation();
}

60
tests/test_evaluation.c Normal file
View file

@ -0,0 +1,60 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "../src/types.h"
#include "../src/number_parsing.h"
#include "../src/utils.h"
#include "../src/evaluator.h"
void test_evaluation()
{
printf("== test evaluation == \n");
// test int parsing
int resVal = 0;
unsigned char resType = 0;
evaluate("-4", &resVal, &resType);
assert(resType == TYPE_INT);
assert(-4 == resVal);
evaluate("-(4+9)+1", &resVal, &resType);
assert(resType == TYPE_INT);
assert(-12 == resVal);
evaluate("(-(8-9+5))+8", &resVal, &resType);
assert(resType == TYPE_INT);
assert(4 == resVal);
evaluate("2^6", &resVal, &resType);
assert(resType == TYPE_INT);
assert(64 == resVal);
evaluate("3 + 4", &resVal, &resType);
assert(resType == TYPE_INT);
assert(7 == resVal);
evaluate("(2*4)+0+0", &resVal, &resType);
assert(resType == TYPE_INT);
assert(8 == resVal);
evaluate("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);
assert(resType == TYPE_INT);
assert(50 == resVal);
evaluate("- ( 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);
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);
assert(resType == TYPE_INT);
assert(4 == resVal);
}

1
tests/test_evaluation.h Normal file
View file

@ -0,0 +1 @@
void test_evaluation();

65
tests/test_utils.c Normal file
View file

@ -0,0 +1,65 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "../src/number_parsing.h"
#include "../src/utils.h"
void test_utils()
{
printf("== test utils == \n");
// test int parsing
char test1[] = "151087";
int res = 0;
parse_clean_positive_integer(strlen(test1), test1, &res);
assert(res == 151087);
char test2[] = "-428579";
parse_int(test2, &res);
assert(res == -428579);
float res3 = 0;
char test3[] = "3121.897";
parse_float(test3, &res3);
assert(float_almost_equal(3121.897, res3));
float res4 = 0;
char test4[] = "-0.4397";
parse_float(test4, &res4);
assert(float_almost_equal(-0.4397, res4));
assert(integer_pow(1, 0) == 1);
assert(integer_pow(2, 1) == 2);
assert(integer_pow(2, 6) == 64);
assert(m_factorial(0) == 1);
assert(m_factorial(1) == 1);
assert(m_factorial(2) == 2);
assert(m_factorial(3) == 6);
assert(m_factorial(4) == 2*3*4);
assert(float_almost_equal(2.7182, m_exp(1.0)));
assert(float_almost_equal(1, m_exp(0)));
assert(float_almost_equal(0, m_sin(0)));
assert(float_almost_equal(1, m_sin(CST_PI/2)));
assert(float_almost_equal(0, m_sin(CST_PI)));
assert(float_almost_equal(-1, m_sin(3*CST_PI/2)));
assert(float_almost_equal(0, m_sin(2*CST_PI)));
assert(float_almost_equal(0, m_sin(4*CST_PI)));
assert(float_almost_equal(1.41421, m_sqrt(2)));
assert(float_almost_equal(2.2360, m_sqrt(5)));
assert(float_almost_equal(0, m_ln(1)));
assert(float_almost_equal(1, m_ln(2.7182818)));
// char src[] = " hello world ";
// char* trimed = trim_space(src);
// assert(strcmp("hello world", trimed) == 0);
// char src2[] = "hello";
// char* trimed2 = trim_space(&src2);
// assert(strcmp("hello", trimed2) == 0);
}

1
tests/test_utils.h Normal file
View file

@ -0,0 +1 @@
void test_utils();