feat: line processing and basic variable support

This commit is contained in:
Matthieu Bessat 2022-05-06 11:49:09 +02:00
parent cb2a1df61f
commit 11fa2b1e6f
21 changed files with 893 additions and 136 deletions

View file

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

92
sandbox.c Normal file
View file

@ -0,0 +1,92 @@
#include <stdio.h>
#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 <stdlib.h>
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);
}

View file

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

View file

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

View file

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

255
src/line_processing.c Normal file
View file

@ -0,0 +1,255 @@
#include "./utils.h"
#include "./line_processing.h"
#include "./evaluator.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
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;
}

7
src/line_processing.h Normal file
View file

@ -0,0 +1,7 @@
#include "./state.h"
#ifndef LINE_PROCESSING_H_
#define LINE_PROCESSING_H_
int process_line(struct StateContainer* state, char* str);
#endif

View file

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

View file

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

25
src/state.c Normal file
View file

@ -0,0 +1,25 @@
#include "./utils.h"
#include "./var_store.h"
#include "./state.h"
#include <stdlib.h>
// #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;
}

26
src/state.h Normal file
View file

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

55
src/types.c Normal file
View file

@ -0,0 +1,55 @@
#include "./utils.h"
#include "./types.h"
#include <stdio.h>
#include <stdlib.h>
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;
}

View file

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

View file

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

184
src/var_store.c Normal file
View file

@ -0,0 +1,184 @@
#include "./types.h"
#include "./var_store.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
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;
}

64
src/var_store.h Normal file
View file

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

60
test.c
View file

@ -1,60 +0,0 @@
#include <stdio.h>
#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);
}

View file

@ -1,5 +1,6 @@
#include "./test_utils.h"
#include "./test_evaluation.h"
#include "./test_line_processing.h"
#include <stdio.h>
int main()
@ -7,4 +8,5 @@ int main()
printf("== UNIT TESTS == \n");
test_utils();
test_evaluation();
test_line_processing();
}

View file

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

View file

@ -0,0 +1,32 @@
#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"
#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")));
}

View file

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