feat: add while loops

This commit is contained in:
Matthieu Bessat 2022-05-15 18:46:16 +02:00
parent 14717958c6
commit 538205e8a5
29 changed files with 1248 additions and 282 deletions

View file

@ -10,6 +10,8 @@ build:
test:
gcc ${TEST_SRCS_ENC} ./tests/* -o ./bin/test ${CXXFLAGS_WITHOUT_PKGS}
./bin/test
test-no-run:
gcc ${TEST_SRCS_ENC} ./tests/* -o ./bin/test ${CXXFLAGS_WITHOUT_PKGS}
sandbox:
gcc ${TEST_SRCS_ENC} ./sandbox.c -o ./bin/sandbox ${CXXFLAGS_WITHOUT_PKGS}
./bin/sandbox

View file

@ -22,15 +22,22 @@ ToDo List:
- [X] implement basic math functions
- [X] implement random_int(min, max)
- [X] implement print_number(message)
- [X] add unit tests
- [X] allow to set variables
- [X] read line comments
- [ ] add modulus operator '%'
- [ ] implement input_number()
- [ ] base of the CLI
- [ ] evaluate expression from stdin
- [ ] read a file
- [X] allow to set variables
- [X] read line comments
- [ ] conditionals
- [ ] add unit tests
- [ ] function call stack
- [ ] if statements
- [ ] while statements (with break)
- [ ] add functions support
- [ ] add config header file
- [ ] ability to modify keywords and customize the lang
- [ ] add strings support
- [ ] add list support
## The language

9
examples/fibo.ltor Normal file
View file

@ -0,0 +1,9 @@
set a to 1
set b to 1
set i to 0
while i < 10 do
set c to a
set a to a+b
set b to c
print_number a
end

304
log.err Normal file
View file

@ -0,0 +1,304 @@
./src/funcs.c:43:33: error: '#' is not followed by a macro parameter
43 | #define SIMPLE_FUNC_BINDING(name) ({\
| ^
./src/funcs.c:51:1: warning: return type defaults to int [-Wimplicit-int]
51 | SIMPLE_FUNC_BINDING(sqrt)
| ^~~~~~~~~~~~~~~~~~~
./src/funcs.c: In function SIMPLE_FUNC_BINDING:
./src/funcs.c:53:1: error: expected declaration specifiers before SIMPLE_FUNC_BINDING
53 | SIMPLE_FUNC_BINDING(exp)
| ^~~~~~~~~~~~~~~~~~~
./src/funcs.c:114:1: error: expected =, ,, ;, asm or __attribute__ before { token
114 | {
| ^
./src/funcs.c:121:1: warning: empty declaration
121 | struct FuncIntro {
| ^~~~~~
./src/funcs.c:129:8: error: parameter intros is initialized
129 | struct FuncIntro intros[] = {
| ^~~~~~~~~
./src/funcs.c:130:5: warning: braces around scalar initializer
130 | {"abs", &abs_impl, 1},
| ^
./src/funcs.c:130:5: note: (near initialization for intros)
./src/funcs.c:130:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
130 | {"abs", &abs_impl, 1},
| ^~~~~
./src/funcs.c:130:6: note: (near initialization for intros)
./src/funcs.c:130:13: warning: excess elements in scalar initializer
130 | {"abs", &abs_impl, 1},
| ^
./src/funcs.c:130:13: note: (near initialization for intros)
./src/funcs.c:130:24: warning: excess elements in scalar initializer
130 | {"abs", &abs_impl, 1},
| ^
./src/funcs.c:130:24: note: (near initialization for intros)
./src/funcs.c:132:5: warning: braces around scalar initializer
132 | {"sqrt", &sqrt_impl, 1},
| ^
./src/funcs.c:132:5: note: (near initialization for intros)
./src/funcs.c:132:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
132 | {"sqrt", &sqrt_impl, 1},
| ^~~~~~
./src/funcs.c:132:6: note: (near initialization for intros)
./src/funcs.c:132:15: error: sqrt_impl undeclared (first use in this function)
132 | {"sqrt", &sqrt_impl, 1},
| ^~~~~~~~~
./src/funcs.c:132:15: note: each undeclared identifier is reported only once for each function it appears in
./src/funcs.c:132:14: warning: excess elements in scalar initializer
132 | {"sqrt", &sqrt_impl, 1},
| ^
./src/funcs.c:132:14: note: (near initialization for intros)
./src/funcs.c:132:26: warning: excess elements in scalar initializer
132 | {"sqrt", &sqrt_impl, 1},
| ^
./src/funcs.c:132:26: note: (near initialization for intros)
./src/funcs.c:132:5: warning: excess elements in scalar initializer
132 | {"sqrt", &sqrt_impl, 1},
| ^
./src/funcs.c:132:5: note: (near initialization for intros)
./src/funcs.c:133:5: warning: braces around scalar initializer
133 | {"exp", &exp_impl, 1},
| ^
./src/funcs.c:133:5: note: (near initialization for intros)
./src/funcs.c:133:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
133 | {"exp", &exp_impl, 1},
| ^~~~~
./src/funcs.c:133:6: note: (near initialization for intros)
./src/funcs.c:133:14: error: exp_impl undeclared (first use in this function)
133 | {"exp", &exp_impl, 1},
| ^~~~~~~~
./src/funcs.c:133:13: warning: excess elements in scalar initializer
133 | {"exp", &exp_impl, 1},
| ^
./src/funcs.c:133:13: note: (near initialization for intros)
./src/funcs.c:133:24: warning: excess elements in scalar initializer
133 | {"exp", &exp_impl, 1},
| ^
./src/funcs.c:133:24: note: (near initialization for intros)
./src/funcs.c:133:5: warning: excess elements in scalar initializer
133 | {"exp", &exp_impl, 1},
| ^
./src/funcs.c:133:5: note: (near initialization for intros)
./src/funcs.c:135:5: warning: braces around scalar initializer
135 | {"sin", &sin_impl, 1},
| ^
./src/funcs.c:135:5: note: (near initialization for intros)
./src/funcs.c:135:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
135 | {"sin", &sin_impl, 1},
| ^~~~~
./src/funcs.c:135:6: note: (near initialization for intros)
./src/funcs.c:135:14: error: sin_impl undeclared (first use in this function)
135 | {"sin", &sin_impl, 1},
| ^~~~~~~~
./src/funcs.c:135:13: warning: excess elements in scalar initializer
135 | {"sin", &sin_impl, 1},
| ^
./src/funcs.c:135:13: note: (near initialization for intros)
./src/funcs.c:135:24: warning: excess elements in scalar initializer
135 | {"sin", &sin_impl, 1},
| ^
./src/funcs.c:135:24: note: (near initialization for intros)
./src/funcs.c:135:5: warning: excess elements in scalar initializer
135 | {"sin", &sin_impl, 1},
| ^
./src/funcs.c:135:5: note: (near initialization for intros)
./src/funcs.c:136:5: warning: braces around scalar initializer
136 | {"cos", &cos_impl, 1},
| ^
./src/funcs.c:136:5: note: (near initialization for intros)
./src/funcs.c:136:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
136 | {"cos", &cos_impl, 1},
| ^~~~~
./src/funcs.c:136:6: note: (near initialization for intros)
./src/funcs.c:136:14: error: cos_impl undeclared (first use in this function); did you mean abs_impl?
136 | {"cos", &cos_impl, 1},
| ^~~~~~~~
| abs_impl
./src/funcs.c:136:13: warning: excess elements in scalar initializer
136 | {"cos", &cos_impl, 1},
| ^
./src/funcs.c:136:13: note: (near initialization for intros)
./src/funcs.c:136:24: warning: excess elements in scalar initializer
136 | {"cos", &cos_impl, 1},
| ^
./src/funcs.c:136:24: note: (near initialization for intros)
./src/funcs.c:136:5: warning: excess elements in scalar initializer
136 | {"cos", &cos_impl, 1},
| ^
./src/funcs.c:136:5: note: (near initialization for intros)
./src/funcs.c:137:5: warning: braces around scalar initializer
137 | {"tan", &tan_impl, 1},
| ^
./src/funcs.c:137:5: note: (near initialization for intros)
./src/funcs.c:137:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
137 | {"tan", &tan_impl, 1},
| ^~~~~
./src/funcs.c:137:6: note: (near initialization for intros)
./src/funcs.c:137:14: error: tan_impl undeclared (first use in this function)
137 | {"tan", &tan_impl, 1},
| ^~~~~~~~
./src/funcs.c:137:13: warning: excess elements in scalar initializer
137 | {"tan", &tan_impl, 1},
| ^
./src/funcs.c:137:13: note: (near initialization for intros)
./src/funcs.c:137:24: warning: excess elements in scalar initializer
137 | {"tan", &tan_impl, 1},
| ^
./src/funcs.c:137:24: note: (near initialization for intros)
./src/funcs.c:137:5: warning: excess elements in scalar initializer
137 | {"tan", &tan_impl, 1},
| ^
./src/funcs.c:137:5: note: (near initialization for intros)
./src/funcs.c:138:5: warning: braces around scalar initializer
138 | {"ln", &ln_impl, 1},
| ^
./src/funcs.c:138:5: note: (near initialization for intros)
./src/funcs.c:138:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
138 | {"ln", &ln_impl, 1},
| ^~~~
./src/funcs.c:138:6: note: (near initialization for intros)
./src/funcs.c:138:13: error: ln_impl undeclared (first use in this function)
138 | {"ln", &ln_impl, 1},
| ^~~~~~~
./src/funcs.c:138:12: warning: excess elements in scalar initializer
138 | {"ln", &ln_impl, 1},
| ^
./src/funcs.c:138:12: note: (near initialization for intros)
./src/funcs.c:138:22: warning: excess elements in scalar initializer
138 | {"ln", &ln_impl, 1},
| ^
./src/funcs.c:138:22: note: (near initialization for intros)
./src/funcs.c:138:5: warning: excess elements in scalar initializer
138 | {"ln", &ln_impl, 1},
| ^
./src/funcs.c:138:5: note: (near initialization for intros)
./src/funcs.c:139:5: warning: braces around scalar initializer
139 | {"log", &log_impl, 1},
| ^
./src/funcs.c:139:5: note: (near initialization for intros)
./src/funcs.c:139:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
139 | {"log", &log_impl, 1},
| ^~~~~
./src/funcs.c:139:6: note: (near initialization for intros)
./src/funcs.c:139:14: error: log_impl undeclared (first use in this function)
139 | {"log", &log_impl, 1},
| ^~~~~~~~
./src/funcs.c:139:13: warning: excess elements in scalar initializer
139 | {"log", &log_impl, 1},
| ^
./src/funcs.c:139:13: note: (near initialization for intros)
./src/funcs.c:139:24: warning: excess elements in scalar initializer
139 | {"log", &log_impl, 1},
| ^
./src/funcs.c:139:24: note: (near initialization for intros)
./src/funcs.c:139:5: warning: excess elements in scalar initializer
139 | {"log", &log_impl, 1},
| ^
./src/funcs.c:139:5: note: (near initialization for intros)
./src/funcs.c:141:5: warning: braces around scalar initializer
141 | {"max", &max_impl, 2},
| ^
./src/funcs.c:141:5: note: (near initialization for intros)
./src/funcs.c:141:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
141 | {"max", &max_impl, 2},
| ^~~~~
./src/funcs.c:141:6: note: (near initialization for intros)
./src/funcs.c:141:14: error: max_impl undeclared (first use in this function)
141 | {"max", &max_impl, 2},
| ^~~~~~~~
./src/funcs.c:141:13: warning: excess elements in scalar initializer
141 | {"max", &max_impl, 2},
| ^
./src/funcs.c:141:13: note: (near initialization for intros)
./src/funcs.c:141:24: warning: excess elements in scalar initializer
141 | {"max", &max_impl, 2},
| ^
./src/funcs.c:141:24: note: (near initialization for intros)
./src/funcs.c:141:5: warning: excess elements in scalar initializer
141 | {"max", &max_impl, 2},
| ^
./src/funcs.c:141:5: note: (near initialization for intros)
./src/funcs.c:142:5: warning: braces around scalar initializer
142 | {"get_pi", &get_pi_impl, 0},
| ^
./src/funcs.c:142:5: note: (near initialization for intros)
./src/funcs.c:142:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
142 | {"get_pi", &get_pi_impl, 0},
| ^~~~~~~~
./src/funcs.c:142:6: note: (near initialization for intros)
./src/funcs.c:142:17: error: get_pi_impl undeclared (first use in this function)
142 | {"get_pi", &get_pi_impl, 0},
| ^~~~~~~~~~~
./src/funcs.c:142:16: warning: excess elements in scalar initializer
142 | {"get_pi", &get_pi_impl, 0},
| ^
./src/funcs.c:142:16: note: (near initialization for intros)
./src/funcs.c:142:30: warning: excess elements in scalar initializer
142 | {"get_pi", &get_pi_impl, 0},
| ^
./src/funcs.c:142:30: note: (near initialization for intros)
./src/funcs.c:142:5: warning: excess elements in scalar initializer
142 | {"get_pi", &get_pi_impl, 0},
| ^
./src/funcs.c:142:5: note: (near initialization for intros)
./src/funcs.c:143:5: warning: braces around scalar initializer
143 | {"", 0, 0}
| ^
./src/funcs.c:143:5: note: (near initialization for intros)
./src/funcs.c:143:6: warning: initialization of struct FuncIntro * from incompatible pointer type char * [-Wincompatible-pointer-types]
143 | {"", 0, 0}
| ^~
./src/funcs.c:143:6: note: (near initialization for intros)
./src/funcs.c:143:10: warning: excess elements in scalar initializer
143 | {"", 0, 0}
| ^
./src/funcs.c:143:10: note: (near initialization for intros)
./src/funcs.c:143:13: warning: excess elements in scalar initializer
143 | {"", 0, 0}
| ^
./src/funcs.c:143:13: note: (near initialization for intros)
./src/funcs.c:143:5: warning: excess elements in scalar initializer
143 | {"", 0, 0}
| ^
./src/funcs.c:143:5: note: (near initialization for intros)
./src/funcs.c:146:12: error: storage class specified for parameter nbOfFuncs
146 | static int nbOfFuncs = sizeof(intros)/sizeof(struct FuncIntro);
| ^~~~~~~~~
./src/funcs.c:146:1: error: parameter nbOfFuncs is initialized
146 | static int nbOfFuncs = sizeof(intros)/sizeof(struct FuncIntro);
| ^~~~~~
./src/funcs.c:146:30: warning: sizeof on array function parameter intros will return size of struct FuncIntro * [-Wsizeof-array-argument]
146 | static int nbOfFuncs = sizeof(intros)/sizeof(struct FuncIntro);
| ^
./src/funcs.c:129:18: note: declared here
129 | struct FuncIntro intros[] = {
| ^~~~~~
./src/funcs.c:152:1: error: expected =, ,, ;, asm or __attribute__ before { token
152 | {
| ^
./src/funcs.c:162:1: error: expected =, ,, ;, asm or __attribute__ before { token
162 | {
| ^
./src/funcs.c:51:1: warning: type of sqrt defaults to int [-Wimplicit-int]
51 | SIMPLE_FUNC_BINDING(sqrt)
| ^~~~~~~~~~~~~~~~~~~
./src/funcs.c:146:12: error: declaration for parameter nbOfFuncs but no such parameter
146 | static int nbOfFuncs = sizeof(intros)/sizeof(struct FuncIntro);
| ^~~~~~~~~
./src/funcs.c:129:18: error: declaration for parameter intros but no such parameter
129 | struct FuncIntro intros[] = {
| ^~~~~~
./src/funcs.c:196: error: expected { at end of input
./src/funcs.c:51:1: warning: unused parameter sqrt [-Wunused-parameter]
51 | SIMPLE_FUNC_BINDING(sqrt)
| ^~~~~~~~~~~~~~~~~~~
./src/funcs.c:146:12: warning: unused parameter nbOfFuncs [-Wunused-parameter]
146 | static int nbOfFuncs = sizeof(intros)/sizeof(struct FuncIntro);
| ^~~~~~~~~
./src/funcs.c:196: warning: control reaches end of non-void function [-Wreturn-type]
./src/number_parsing.c: In function parse_clean_positive_integer:
./src/number_parsing.c:21:29: warning: binary constants are a C2X feature or GCC extension
21 | (numeralIndex & 0b001111)
| ^~~~~~~~
make: *** [Makefile:11: test] Error 1

View file

@ -23,12 +23,13 @@ int main () {
// memcpy(&dst, &yes, 4);
// printf("yes: %d \n", dst);
struct VariableStore* store = var_store_init();
//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);
// int val = 1234;
// var_store_set(store, "foo", TYPE_INT, &val);
// var_store_get_key(store, "while i < 10 then");
//printf("Pos of var: %d \n", var_store_get_pos(store, "foo"));
@ -39,19 +40,33 @@ int main () {
//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);
// int val2 = 0;
// var_store_copy(store, "foo", &val2);
printf("Value of var: %d \n", val2);
// printf("Value of var: %d \n", val2);
// printf("==== \n");
// printf("==== \n");
// char* lines = "# hello world\n"
// "set x to 5\n"
// "set y to 1\n"
// "if !(x+y = 6) then\n"
// " print_number(x+y)\n"
// "end\n"
// "\n";
char* lines1 = "set x to 5\n"
"set y to 1\n"
"if !(x+y = 6) then\n"
" print_number(x+y)\n"
"end\n"
"\n";
printf("%s", lines1);
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))");
process_script(state, lines1);
// struct List l1;

View file

@ -355,6 +355,7 @@ Arguments:
- Input String: char pointer (the source of the evaluation)
- Result: int pointer (where the result of the evaluation will be written)
*/
// FIXME: allow for multiple line expressions
int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr) {
int i = 0;
int _len = strlen(inputStr);
@ -397,10 +398,14 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
}
// display the partition
if (EVALUATOR_DEBUG_LEVEL >= 2) {
printf("partitionPtr: %d \n", partitionPtr);
}
for (int j = 0; j < partitionPtr; j++) {
if (EVALUATOR_DEBUG_LEVEL >= 2) {
printf("start %d ", partitionStartPos[j]);
printf("stop %d ", partitionStopPos[j]);
}
int len = partitionStopPos[j] - partitionStartPos[j];
char buff[_len];
@ -410,9 +415,10 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
}
}
buff[len] = 0;
if (EVALUATOR_DEBUG_LEVEL >= 2) {
printf("content %s \n", buff);
}
}
// once we've lexed our expression, we want to analyse if it's righly parenthesized
int parenthesisCount = 0;
@ -446,14 +452,16 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
struct List evalList;
// NOTICE: for some reason the struct don't reset after a usage
list_reset(&evalList);
printf("\n - constructing list \n");
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("\n - constructing list \n");
// initializing the evaluation list
for (int j = 0; j < partitionPtr; j++) {
int startPos = partitionStartPos[j];
int stopPos = partitionStopPos[j];
if (EVALUATOR_DEBUG_LEVEL >= 2) {
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
@ -485,8 +493,7 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
buff[len] = 0; // terminate the buff
// TODO: SPLIT INTO A FUNCTION "identify_token(char* str)"
printf("buff: '%s' \n", buff);
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("buff: '%s' \n", buff);
char dumbValue = (char) 0;
@ -506,7 +513,7 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
continue;
}
if (len == 1 && is_operator(buff[0])) {
printf("found op\n");
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("found op\n");
char opValue = buff[0];
list_set(&evalList, evalList.num_elements, TYPE_OPERATOR, &opValue);
continue;
@ -532,7 +539,11 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
// identify token
// first try a variable then a func name
// not a float, check if this is a common function name
short varKey = (short) var_store_get_key(state->varStore, buff);
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("now going to identify token '%s' \n");
if (EVALUATOR_DEBUG_LEVEL >= 2) var_store_print(state->varStore);
int varKey = (int) var_store_get_key(state->varStore, buff);
if (varKey == -1) {
// did not find the var name
short funcID = identify_func_name(buff);
@ -549,15 +560,17 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
list_set(&evalList, evalList.num_elements, TYPE_VAR_NAME, &varKey);
}
}
printf("end of a token id\n");
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("end of a token identification\n");
}
// check the content of this thing
if (EVALUATOR_DEBUG_LEVEL >= 2) {
list_print(&evalList);
printf("Now going to actually evaluate \n");
}
while (evalList.num_elements > 1) {
list_print(&evalList);
if (EVALUATOR_DEBUG_LEVEL >= 2) list_print(&evalList);
// int reduceVarOpStat = evaluator_reduce_var(state, &evalList);
// int reduceFuncOpStat = evaluator_reduce_function_call(&evalList, 0);
@ -576,11 +589,13 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
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);
printf("ERR Evaluator: mode %d reducing failed \n", m);
if (EVALUATOR_DEBUG_LEVEL >= 2) {
printf("dumping evalList: \n");
list_print(&evalList);
}
}
if (stat == 0) {
didReduced = 1;
}
@ -589,8 +604,11 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
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");
printf("ERR Evaluator: could not reduce more \n");
if (EVALUATOR_DEBUG_LEVEL >= 2) {
printf("dumping evalList: \n");
list_print(&evalList);
}
return 400;
}

View file

@ -2,6 +2,8 @@
#ifndef EVALUATOR_H_
#define EVALUATOR_H_
#define EVALUATOR_DEBUG_LEVEL 1
int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr);
#endif

View file

@ -259,13 +259,8 @@ 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);
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);
}
printf("Got %s \n", get_repr(*resTypePtr, resPtr));
return 0;
}

View file

@ -1,23 +1,11 @@
#include "./utils.h"
#include "./line_processing.h"
#include "./stack.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;
@ -55,15 +43,42 @@ int recognize_comment_statement(char* lineStr)
return 1;
}
// recognize in a string a keyword with a space before and a space afer OR the end of string after
/*
CASES:
[SPACE]NEEDLE$
[SPACE]NEEDLE[SPACE+]$
struct SetStatement {
short name_start;
short name_stop;
short expression_start;
};
like
if machin then
while machin do
*/
int recognize_termination_keyword(char* needle, char* subject, int from)
{
int needleLen = strlen(needle);
int subLen = strlen(subject);
int remainLen = subLen - from;
if (remainLen < needleLen+1) {
return 0;
}
char terminationCandidate[remainLen];
str_extract((char*) &terminationCandidate, subject, from, remainLen);
// we could directly integrate the trim space process without extracting the
char trimedTermination[remainLen];
trim_space((char*) &trimedTermination, terminationCandidate);
return strcmp(trimedTermination, needle) == 0;
}
// recognize "set VAR_NAME to EVALUATION"
int recognize_set_statement(char* lineStr, struct SetStatement* res)
{
static char setStatementStartKeyword[] = "set";
static char setStatementStopKeyword[] = "to";
int i = 0;
int mode = 1;
int arg = 0;
@ -79,90 +94,49 @@ int recognize_set_statement(char* lineStr, struct SetStatement* res)
mode 8 the expression
*/
while (lineStr[i] != '\0') {
//printf("mode: %d, char: '%c' \n", mode, lineStr[i]);
if (mode == 1) {
if (lineStr[i] == 's') {
if (str_needle_at_pos(setStatementStartKeyword, lineStr, i)) {
mode = 2;
arg = 0;
i += strlen(setStatementStartKeyword);
continue;
}
if (lineStr[i] != ' ') {
break;
}
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') {
if (arg > 0 && is_char_accepted_in_var_name(lineStr[i])) {
mode = 3;
arg = 0;
res->name_start = i;
i++;
continue;
}
break;
if (lineStr[i] != ' ') break;
arg++;
}
if (mode == 3) {
if (arg > 0 && is_char_accepted_in_var_name(lineStr[i])) {
if (lineStr[i] == ' ') {
mode = 4;
arg = 0;
res->name_start = i;
res->name_stop = i;
i++;
continue;
}
if (lineStr[i] != ' ') {
break;
}
arg++;
if (!is_char_accepted_in_var_name(lineStr[i])) break;
}
if (mode == 4) {
if (lineStr[i] == ' ') {
if (str_needle_at_pos(setStatementStopKeyword, lineStr, i)) {
mode = 5;
arg = 0;
res->name_stop = i;
i += strlen(setStatementStopKeyword);
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] != ' ') break;
if (arg > 0 && lineStr[i] != ' ') {
// success
mode = 8;
mode = 6;
res->expression_start = i;
break;
}
@ -171,23 +145,170 @@ int recognize_set_statement(char* lineStr, struct SetStatement* res)
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
if (mode != 6) return 0;
return 1;
}
// recognize "if EXPRESSION then \n begin (...) \n end"
// FIXME: does no allow for inline if
// FIXME: allow for multiline if statement
int recognize_if_statement(char* lineStr, struct IfStatement* res)
{
static char ifStatementStartKeyword[] = "if";
static char ifStatementStopKeyword[] = "then";
size_t len = strlen(lineStr);
if (len < strlen(ifStatementStartKeyword) + 1 + strlen(ifStatementStopKeyword)) return 0;
//printf("try to reco if statement \n");
int i = 0;
int mode = 1;
int arg = 0;
/*
recognize pattern : ^\s*if {any string} then (\S)+
mode 1 any space
mode 2 "if"
mode 3 any space
mode 4 expression
mode 5 any space
mode 6 "then"
mode 7 any space
mode 8 expression
if we reach the end of the line without getting anything we consider that we need smth after it
multiple modes:
*/
while (lineStr[i] != '\0') {
if (mode == 1) {
if (str_needle_at_pos(ifStatementStartKeyword, lineStr, i)) {
mode = 2;
i += strlen(ifStatementStartKeyword);
continue;
}
if (lineStr[i] != ' ') break;
}
if (mode == 2) {
if (arg > 0 && lineStr[i] != ' ') {
mode = 3;
arg = 0;
res->expression_start = i;
continue;
}
if (lineStr[i] != ' ') break;
arg++;
}
if (mode == 3) {
// in expression
if (arg > 0 && recognize_termination_keyword(ifStatementStopKeyword, lineStr, i)) {
// TODO: may be verify that the expression is valid?
// if an expression contains " then" it will not work that well...
// may be we need to verify that the rest of the line is empty
mode = 4;
arg = 0;
res->expression_stop = i;
continue;
}
arg++;
}
if (mode == 4) break;
i++;
}
if (mode != 4) return 0;
return 1;
}
// recognize "while EXPRESSION then \n begin (...) \n end"
int recognize_while_statement(char* lineStr, struct WhileStatement* res)
{
static char whileStatementStartKeyword[] = "while";
static char whileStatementStopKeyword[] = "do";
size_t len = strlen(lineStr);
if (len < strlen(whileStatementStartKeyword) + 1 + strlen(whileStatementStopKeyword)) return 0;
//printf("try to reco if statement \n");
int i = 0;
int mode = 1;
int arg = 0;
while (lineStr[i] != '\0') {
//printf("i: %d, mode: %d, char: '%c' \n", i, mode, lineStr[i]);
if (mode == 1) {
if (str_needle_at_pos(whileStatementStartKeyword, lineStr, i)) {
mode = 2;
i += strlen(whileStatementStartKeyword);
continue;
}
if (lineStr[i] != ' ') break;
}
if (mode == 2) {
if (arg > 0 && lineStr[i] != ' ') {
mode = 3;
arg = 0;
res->expression_start = i;
continue;
}
if (lineStr[i] != ' ') break;
arg++;
}
if (mode == 3) {
// in expression
if (
arg > 0 &&
recognize_termination_keyword(whileStatementStopKeyword, lineStr, i)
) {
mode = 4;
arg = 0;
res->expression_stop = i;
continue;
}
arg++;
}
if (mode == 4) break;
i++;
}
if (mode != 4) return 0;
return 1;
}
/*
Return 1 if it found a single word with only spaces
basically it does this check:
trim_space(lineStr) == word
*/
int recognize_word(char* lineStr, char* word)
{
int len = strlen(lineStr);
int expectedLen = strlen(word);
if (len < expectedLen) {
return 0;
}
// trim spaces on both sides
int start = 0;
int end = len-1;
while (lineStr[start] == ' ') {
start++;
}
while (lineStr[end] == ' ') {
end--;
}
end +=1;
char dest[end-start];
str_extract((char*) &dest, lineStr, start, end-start);
return strcmp(dest, word) == 0;
}
// Will interpret a line
// the string must be inputed without a new line at the end
int process_line(struct StateContainer* state, char* str)
{
printf("\n ======= PROCESSING LINE '%s' =======\n", str);
if (LINE_PROCESSING_DEBUG_LEVEL >= 1) printf("\n ======= PROCESSING LINE '%s' =======\n", str);
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("skipping: %d, blockStackLen: %d \n", state->skipping, state->blockStack->length);
// process
int len = strlen(str);
// int startPos = 0;
@ -217,15 +338,97 @@ int process_line(struct StateContainer* state, char* str)
//int stat = 0;
if (recognize_comment_statement(str)) {
printf("Comment recognized \n");
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Comment recognized \n");
state->linePtr++;
return 1;
}
if (is_full_of_space(str)) {
state->linePtr++;
return 1;
}
if (recognize_word(str, "end")) {
byte lastBlockType;
int_stack_pop(state->blockStack, (int*) &lastBlockType); // FIXME: use a stack with size byte instead of int
if (!state->skipping && lastBlockType == BLOCK_WHILE) {
int lastLoopLine;
int_stack_pop(state->loopStack, &lastLoopLine);
state->linePtr = lastLoopLine;
return 1;
}
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("recognize end state->blockStackAnchor: %d \n", state->blockStackAnchor);
if (state->skipping && int_stack_length(state->blockStack) == state->blockStackAnchor) {
// end of skipping
state->skipping = 0;
}
state->linePtr++;
return 1;
}
if (recognize_word(str, "continue")) {
int lastLoopLine;
if (!int_stack_pop(state->loopStack, &lastLoopLine)) {
printf("Syntax error: unexpected continue, not in a loop \n");
return 0;
}
state->linePtr = lastLoopLine;
// find the last while if the block stack and pop blocks up to that point
byte lastBlockType;
while (lastBlockType != BLOCK_WHILE) {
if (!int_stack_pop(state->blockStack, &lastBlockType)) {
printf("Syntax error: unexpected continue \n");
}
}
int_stack_pop(state->blockStack, &lastBlockType);
return 1;
}
if (recognize_word(str, "break")) {
int lastLoopLine;
if (!int_stack_pop(state->loopStack, &lastLoopLine)) {
printf("Syntax error: unexpected break, not in a loop \n");
return 0;
}
// go into skip mode
// find the stack anchor coresponding to the last while
// we will need to search in the block stack without poping
int lastLoopAnchor = state->blockStack->length-1;
while (lastLoopAnchor >= 0) {
if (state->blockStack->data[lastLoopAnchor] == BLOCK_WHILE) break;
lastLoopAnchor--;
}
state->blockStackAnchor = lastLoopAnchor+1;
state->skipping = 1;
return 1;
}
struct IfStatement ifStatementParsing;
byte ifRecognized = recognize_if_statement(str, &ifStatementParsing);
struct WhileStatement whileStatementParsing;
byte whileRecognized = recognize_while_statement(str, &whileStatementParsing);
if (state->skipping) {
// we've finish to analyse structure-aware blocks
state->linePtr++;
return 1;
}
struct SetStatement setStatementParsing;
if (recognize_set_statement(str, &setStatementParsing)) {
printf("Set statement recognized \n");
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) {
printf("Set statement recognized (%d, %d, %d) \n",
setStatementParsing.name_start,
setStatementParsing.name_stop,
setStatementParsing.expression_start);
}
// handle the set statement (set a variable)
int nameLen = setStatementParsing.name_stop-setStatementParsing.name_start;
char* name = (char*) malloc(sizeof(char) * nameLen);
char* name = (char*) malloc(sizeof(char) * (nameLen+1));
for (int z = 0; z < nameLen; z++) {
name[z] = str[setStatementParsing.name_start + z];
}
@ -233,13 +436,84 @@ int process_line(struct StateContainer* state, char* str)
int res;
byte resType;
int evalStat = evaluate(state, str + setStatementParsing.expression_start, &res, &resType);
int expressLen = len - setStatementParsing.expression_start;
char express[expressLen];
str_extract((char*) &express, str, setStatementParsing.expression_start, expressLen);
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got expression '%s' \n", express);
int evalStat = evaluate(state, (char*) &express, &res, &resType);
if (evalStat != 0) {
printf("Syntax error for line \"%s\"\n", str);
return 0;
}
printf("==> Set '%s' to %s \n", name, get_repr(resType, &res));
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("==> Set '%s' to %s \n", name, get_repr(resType, &res));
var_store_set(state->varStore, name, resType, &res);
state->linePtr++;
return 1;
}
if (ifRecognized) {
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("If statement recognized express (%d:%d)\n", ifStatementParsing.expression_start, ifStatementParsing.expression_stop);
// expression to evaluate
int expressLen = ifStatementParsing.expression_stop - ifStatementParsing.expression_start;
char dest[len];
str_extract((char*) &dest, str, ifStatementParsing.expression_start, expressLen);
// printf("expression to eval in if '%s' \n", dest);
int res;
byte resType;
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
if (evalStat != 0) {
printf("Syntax error for line \"%s\"\n", str);
return 0;
}
byte doFollow = convert_to_bool(resType, res);
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
if (!doFollow) {
state->blockStackAnchor = int_stack_length(state->blockStack);
state->skipping = 1;
}
int_stack_push(state->blockStack, BLOCK_IF);
state->linePtr++;
return 1;
}
if (whileRecognized) {
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("While statement recognized express (%d:%d)\n", whileStatementParsing.expression_start, whileStatementParsing.expression_stop);
// expression to evaluate
int expressLen = whileStatementParsing.expression_stop - whileStatementParsing.expression_start;
char dest[len];
str_extract((char*) &dest, str, whileStatementParsing.expression_start, expressLen);
// printf("expression to eval in if '%s' \n", dest);
int res;
byte resType;
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
if (evalStat != 0) {
printf("Syntax error for line \"%s\"\n", str);
return 0;
}
byte doFollow = convert_to_bool(resType, res);
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
if (doFollow) {
// follow the line
int_stack_push(state->loopStack, state->linePtr);
}
if (!doFollow) {
state->blockStackAnchor = int_stack_length(state->blockStack);
state->skipping = 1;
}
int_stack_push(state->blockStack, BLOCK_WHILE);
state->linePtr++;
return 1;
}
@ -251,5 +525,70 @@ int process_line(struct StateContainer* state, char* str)
printf("Syntax error for line \"%s\"\n", str);
return 0;
}
state->linePtr++;
return 1;
}
int process_script(struct StateContainer* state, char* script)
{
int lineCount = 0;
int i = 0;
while (script[i] != '\0') {
if (script[i] == '\n') {
lineCount += 1;
}
i++;
}
if (LINE_PROCESSING_DEBUG_LEVEL >= 1) printf("\n ==================================================================== \n");
if (LINE_PROCESSING_DEBUG_LEVEL >= 1) printf(" ======== NEW SCRIPT ======== \n");
if (LINE_PROCESSING_DEBUG_LEVEL >= 1) printf(" ==================================================================== \n");
if (LINE_PROCESSING_DEBUG_LEVEL >= 1) printf("line count: %d \n", lineCount);
// FIXME: conditional line ptr reset
state->linePtr = 0;
int lineStarts[lineCount];
int lineEnds[lineCount];
lineStarts[0] = 0;
i = 0;
int lineIndex = 0;
while (script[i] != '\0') {
if (script[i] == '\n') {
lineEnds[lineIndex] = i;
//printf("end of a line: s: %d e: %d \n", lineStarts[lineIndex], lineEnds[lineIndex]);
if (script[i+1] != '\0') {
lineStarts[lineIndex+1] = i+1;
}
lineIndex++;
}
i++;
}
// for (int j = 0; j < lineCount; j++) {
// int lineLen = (lineEnds[j] - lineStarts[j]);
// char line[lineLen+1];
// str_extract(&line, script, lineStarts[j], lineLen);
// // printf("line %d %d \n", lineStarts[j], lineEnds[j]);
// // printf("line : '%s' \n", line);
// }
while (state->running && state->linePtr != lineCount) {
if (state->linePtr >= lineCount) {
printf("Invalid line %d \n", state->linePtr);
break;
}
int lineLen = (lineEnds[state->linePtr] - lineStarts[state->linePtr]);
char line[lineLen+1];
str_extract((char*) &line, script, lineStarts[state->linePtr], lineLen);
int stat = process_line(state, line);
if (!stat) {
printf("Abnormal end of run at line %d: '%s' \n", state->linePtr, line);
return 0;
}
}
return 1;
}

View file

@ -2,6 +2,35 @@
#ifndef LINE_PROCESSING_H_
#define LINE_PROCESSING_H_
#define LINE_PROCESSING_DEBUG_LEVEL 1
#define BLOCK_IF 2
#define BLOCK_WHILE 3
int recognize_word(char* lineStr, char* word);
int recognize_termination_keyword(char* needle, char* subject, int from);
struct SetStatement {
short name_start;
short name_stop;
short expression_start;
};
int recognize_set_statement(char* lineStr, struct SetStatement* res);
struct IfStatement {
short expression_start;
short expression_stop;
};
int recognize_if_statement(char* lineStr, struct IfStatement* res);
struct WhileStatement {
short expression_start;
short expression_stop;
};
int recognize_while_statement(char* lineStr, struct WhileStatement* res);
int process_script(struct StateContainer* state, char* script);
int process_line(struct StateContainer* state, char* str);
#endif

View file

@ -1,4 +1,4 @@
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "./stack.h"
@ -7,78 +7,39 @@
#include "./evaluator.h"
#include "./utils.h"
#include "./types.h"
//int create_stack(int a, int b)
#include "./line_processing.h"
void test_list()
{
// test dynamic list
struct List l1;
byte load_file(char* filename, char** resultPtr) {
FILE* f = fopen(filename, "rb");
printf("0: %d \n", list_append_int(&l1, 844));
printf("1: %d \n", list_get_type(&l1, 0));
int val;
printf("2: %d \n", list_get_int(&l1, 0, &val));
printf("final value: %d \n", val);
printf("3: %d \n", list_append_int(&l1, 855));
printf("4: %d \n", list_append_int(&l1, 866));
printf("5: %d \n", list_append_int(&l1, 877));
printf("\n");
for (int i = 0; i < l1.num_elements; i++) {
printf("- elem: %d, ptr: %d, type: %d \n", i, l1.ptrArray[i] , l1.typeArray[i]);
if (!f) {
return 0;
}
printf("\n");
list_get_int(&l1, 0, &val);
printf("6: %d \n", val);
list_delete(&l1, 0);
for (int i = 0; i < l1.num_elements; i++) {
printf("- elem: %d, ptr: %d, type: %d \n", i, l1.ptrArray[i] , l1.typeArray[i]);
fseek(f, 0, SEEK_END);
long length = ftell(f);
fseek (f, 0, SEEK_SET);
char* buffer = (char*) malloc(length);
if (!buffer) {
return 0;
}
// 844, 855, 866, 877
list_get_int(&l1, 2, &val);
printf("6: %d \n", val);
if (buffer) {
fread(buffer, 1, length, f);
}
fclose(f);
*resultPtr = buffer;
return 1;
}
int main () {
int main (int argc, char** argv) {
// if (argc == 1) {
// printf("One arg '%s'", argv[0]);
char *inputStr2 = "((1+1))*MAX(4, 5)";
// return 0;
// }
int res = 0;
int resType = 0;
int evalStatus = evaluate(inputStr2, &res, &resType);
printf("evaluation status is: %d \n", evalStatus);
printf("result type is: %d \n", resType);
if (resType == TYPE_FLOAT) {
printf("result is float: %f \n", get_float_from_int_rep(res));
}
if (resType == TYPE_INT) {
printf("result is int: %d \n", res);
}
// example of the use of stack
// struct IntStack exStack;
// int_stack_push(&exStack, 233);
// int_stack_push(&exStack, 298);
// int_stack_push(&exStack, 299);
// int res;
// int_stack_pop(&exStack, &res);
// printf("pop stack: %d \n", res);
// int_stack_pop(&exStack, &res);
// printf("pop stack: %d \n", res);
// int_stack_pop(&exStack, &res);
// printf("pop stack: %d \n", res);
// printf("Invalid usage use --help to document your self\n");
printf("CLI not implemented yet ¯\\_(ツ)_/¯ \n");
return 1;
}

View file

@ -18,16 +18,6 @@ int is_operator(char 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(
byte operator,
byte typeA, int aRepr,
@ -79,7 +69,7 @@ int operate(
a = convert_to_float(typeA, aRepr);
b = convert_to_float(typeB, bRepr);
printf("Appling operation: %f %c %f \n", a, operator, b);
if (OPERATE_DEBUG_LEVEL) printf("Appling operation: %f %c %f \n", a, operator, b);
if (operator == '+') {
res = a+b;
@ -96,13 +86,13 @@ int operate(
} else {
return 2;
}
printf("Got float: %f \n", res);
if (OPERATE_DEBUG_LEVEL) printf("Got float: %f \n", res);
// get int representation of float
*resPtr = *(int *)(&res);
return 0;
}
if (typeA == TYPE_INT && typeB == TYPE_INT) {
printf("Appling operation %d %c %d \n", aRepr, operator, bRepr);
if (OPERATE_DEBUG_LEVEL) printf("Appling operation %d %c %d \n", aRepr, operator, bRepr);
*typeRes = TYPE_INT;
int res = 0;
if (operator == '+') {

View file

@ -1,7 +1,8 @@
#ifndef OPERATOR_H_
#define OPERATOR_H_
#define OPERATE_DEBUG_LEVEL 0
int is_operator(char candidate);
int operate(

View file

@ -1,35 +1,55 @@
#include "./utils.h"
#include "./stack.h"
#include <stdio.h>
#include <stdlib.h>
int int_stack_push(struct IntStack* stack, int valueToPush)
struct IntStack* int_stack_init()
{
if (stack->end_pos == STACK_LEN) {
// return a stack overflow error
return 1;
}
struct IntStack* stack = (struct IntStack*) malloc(sizeof(struct IntStack));
stack->length = 0;
stack->allocated = 8;
stack->data = (int*) malloc(stack->allocated * sizeof(int));
stack->data[stack->end_pos] = valueToPush;
stack->end_pos = stack->end_pos + 1;
return 0;
return stack;
}
int int_stack_pop(struct IntStack* stack, int* valuePtr)
byte int_stack_push(struct IntStack* stack, int valueToPush)
{
if (stack->end_pos == 0) {
// return a stack underflow error
return 1;
if (stack->length == stack->allocated) {
stack->allocated *= 2;
stack->data = realloc(stack->data, stack->allocated * sizeof(int));
}
*valuePtr = stack->end_pos;
stack->data[stack->length] = valueToPush;
stack->length++;
stack->end_pos = stack->end_pos - 1;
*valuePtr = stack->data[stack->end_pos];
return 1;
}
byte int_stack_pop(struct IntStack* stack, int* valuePtr)
{
if (stack->length == 0) {
// error, nothing to pop
return 0;
}
*valuePtr = stack->data[stack->length-1];
stack->length--;
return 1;
}
int int_stack_length(struct IntStack* stack)
{
return stack->end_pos;
return stack->length;
}
void int_stack_print(struct IntStack* stack)
{
printf("= STACK REPORT \n");
for (int i = 0; i < stack->length; i++) {
printf("%d; ", stack->data[i]);
}
printf("\n");
}

View file

@ -1,17 +1,21 @@
#include "./utils.h"
#ifndef STACK_H_
#define STACK_H_
#define STACK_LEN 255
struct IntStack {
int end_pos;
int data[STACK_LEN];
int length;
int allocated;
int* data;
};
int int_stack_push(struct IntStack* stack, int valueToPush);
struct IntStack* int_stack_init();
int int_stack_pop(struct IntStack* stack, int* valuePtr);
byte int_stack_push(struct IntStack* stack, int valueToPush);
byte int_stack_pop(struct IntStack* stack, int* valuePtr);
int int_stack_length(struct IntStack* stack);
void int_stack_print(struct IntStack* stack);
#endif

View file

@ -3,23 +3,20 @@
#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();
ptr->linePtr = 0;
ptr->loopStack = int_stack_init();
ptr->blockStack = int_stack_init();
ptr->blockStackAnchor = 0;
ptr->skipping = 0;
ptr->running = 1;
return ptr;
}

View file

@ -5,18 +5,31 @@ we store:
- the functions names and their references
*/
#include "./utils.h"
#include "./stack.h"
#include "./var_store.h"
#ifndef STATE_H_
#define STATE_H_
struct StateContainer {
struct VariableStore* varStore;
// if true, continue to look for new lines to execute
byte running;
// 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;
// store the head address of loops
struct IntStack* loopStack;
// a stack that tracks the blocks we are in, 0 for a if, 1 for a while..
struct IntStack* blockStack;
// formely known as blockStackLengthBeforeSkip
int blockStackAnchor;
// if true tell the interpreter to skip until the block stack is at the blockStackLengthBeforeSkip
byte skipping;
// struct FunctionStore* funcStore;
// struct StringStore* strStore ??
};
@ -24,3 +37,16 @@ struct StateContainer {
struct StateContainer* state_init();
#endif
/*
proto proof that just a if block counter is not sufficient to really track every if blocks
if true then -> la on dit que ifBlocks = 0
if false then -> la on dit que ifBlocks = 1
smth
if smth then ifBlocks = 2
end ifBlocks = 1
end ifBlocks = 0
end ifBlocks = -1 -> on peut pas retrouver le block d'avant le skip
conclusion: on ne peut pas juste utiliser un compteur à la con, ça ne marche pas il faut obligatoirement utiliser une stack
*/

View file

@ -53,3 +53,17 @@ char* get_repr(byte type, void* valPtr)
sprintf(res, "UNKNOWN(%d)", type);
return res;
}
int convert_to_int(byte type, int repr) {
if (type == TYPE_FLOAT) return (int) *((int*) &repr);
return repr;
}
byte convert_to_bool(byte type, int repr) {
return (byte) (convert_to_int(type, repr) == 1);
}
float convert_to_float(byte type, int repr) {
if (type == TYPE_INT) return (float) repr;
return *((float*) &repr);
}

View file

@ -17,4 +17,8 @@ int get_size_of_type(byte type);
char* get_repr(byte type, void* data);
byte convert_to_bool(byte type, int repr);
int convert_to_int(byte type, int repr);
float convert_to_float(byte type, int repr);
#endif

View file

@ -1,4 +1,5 @@
#include <stdio.h>
#include <string.h>
#include "./utils.h"
int get_int_rep_from_float(float ft)
@ -262,8 +263,51 @@ int is_full_of_space(char* str)
return 1;
}
char* trim_space(char* str)
void trim_space(char* dst, char* subject)
{
// TODO: implements me
return str;
// trim spaces on both sides
int start = 0;
int end = strlen(subject)-1;
while (subject[start] == ' ') start++;
while (subject[end] == ' ') end--;
end += 1;
str_extract(dst, subject, start, end-start);
}
// FIXME: not protected against memory overflow
void str_extract(char* dst, char* subject, int initial, int length)
{
for (int i = 0; i < length; i++) {
dst[i] = subject[initial+i];
}
dst[length] = '\0';
}
byte str_needle_at_pos(char* needle, char* subject, int atPos) {
size_t needleLen = strlen(needle);
if (strlen(subject) < needleLen) {
return 0;
}
char ahead[strlen(needle)+1];
str_extract((char*) &ahead, subject, atPos, needleLen);
return strcmp(needle, ahead) == 0;
}
byte str_starts_with(char* needle, char* subject) {
return str_needle_at_pos(needle, subject, 0);
}
// FIXME: dead code
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;
}

View file

@ -38,6 +38,11 @@ float m_tan(float x);
int is_full_of_space(char* str);
char* trim_space(char* str);
void str_extract(char* res, char* subject, int initial, int length);
byte str_needle_at_pos(char* needle, char* subject, int pos);
byte str_starts_with(char* needle, char* subject);
void trim_space(char* dst, char* subject);
#endif

View file

@ -34,6 +34,8 @@ int var_store_hash_name(struct VariableStore* store, char* varName)
hash += (get_int_rep_from_char(varName[i])*integer_pow(9, i)) % MAX_INTEGER;
i++;
}
// FIXME: when reallocating, we should copy all variables to their new key
// because we use modulus operator, the hash will change whenever we reallocated the table
return hash % store->allocatedLength;
}
@ -70,6 +72,9 @@ byte var_store_set(struct VariableStore* store, char* varName, byte type, void*
while (1)
{
if (store->container[key].type == 0) {
// we finally found an empty space, but we didn't found a variable with the same name
// we have a new variable
store->length++;
break;
}
if (strcmp(store->container[key].namePtr, varName) == 0) {
@ -89,10 +94,10 @@ byte var_store_set(struct VariableStore* store, char* varName, byte type, void*
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
// FIXME: copy all variables to their new keys
store->allocatedLength = 2*store->allocatedLength;
store->container = (struct VariableContainer*) realloc(store->container, sizeof(struct VariableContainer) * store->allocatedLength);
if (store->container == NULL) {
@ -182,3 +187,19 @@ float var_store_get_float(struct VariableStore* store, char* varName)
var_store_copy(store, varName, &val);
return val;
}
void var_store_print(struct VariableStore* store)
{
printf("== VarStore report (%d items) ==\n", store->length);
for (int i = 0; i < store->allocatedLength; i++) {
if (store->container[i].type != 0) {
printf(
"key: %d, '%s' = %s; ",
i,
store->container[i].namePtr,
get_repr(store->container[i].type, store->container[i].dataPtr)
);
}
}
printf("== end of report\n");
}

View file

@ -1,11 +1,15 @@
#include "./test_utils.h"
#include "./test_evaluation.h"
#include "./test_line_processing.h"
#include "./test_stack.h"
#include "./test_var_store.h"
#include <stdio.h>
int main()
{
printf("== UNIT TESTS == \n");
test_var_store();
test_stack();
test_utils();
test_evaluation();
test_line_processing();

View file

@ -7,28 +7,112 @@
#include "../src/evaluator.h"
#include "../src/state.h"
#include "../src/var_store.h"
#include "../src/line_processing.h"
void test_line_processing()
{
printf("== test line processing == \n");
struct StateContainer* state = state_init();
// test string manipulation
assert(!recognize_word("", "hello"));
assert(!recognize_word(" hell", "hello"));
assert(recognize_word("hello", "hello"));
assert(recognize_word("hello ", "hello"));
assert(recognize_word(" hello ", "hello"));
assert(recognize_word(" hello ", "hello"));
assert(recognize_word(" hello ", "hello"));
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(recognize_termination_keyword("end", "01 end", 2));
assert(!recognize_termination_keyword("end", "01 end == something end", 2));
assert(!recognize_termination_keyword("end", "xend", 0));
assert(!recognize_termination_keyword("end", "end", 0));
assert(recognize_termination_keyword("end", " end", 0));
assert(process_line(state, "set VAR_B to 1.5"));
assert(float_almost_equal(1.5, var_store_get_float(state->varStore, "VAR_B")));
struct SetStatement res;
assert(recognize_set_statement("set x to 1", &res));
assert(recognize_set_statement("set someBigThings_yes to (wow)+yes", &res));
assert(!recognize_set_statement("set to ", &res));
assert(!recognize_set_statement("set thing uo to yes", &res));
assert(recognize_set_statement("set varToThing_to to yes", &res));
assert(process_line(state, "set VAR_C to 142"));
assert(142 == var_store_get_int(state->varStore, "VAR_C"));
struct IfStatement resIf;
assert(recognize_if_statement("if something is not cool then", &resIf));
assert(recognize_if_statement("if some_then_var then", &resIf));
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")));
struct WhileStatement resWhile;
assert(recognize_while_statement("while i < 10 do", &resWhile));
assert(recognize_while_statement("while !(i = 10) do", &resWhile));
assert(!recognize_while_statement(" while 1 then", &resWhile));
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")));
struct StateContainer* state1 = state_init();
assert(process_line(state1, "#"));
assert(process_line(state1, "# some random comment"));
assert(process_line(state1, "set VAR_A to 8.5"));
printf("%d \n", var_store_get_int(state1->varStore, "VAR_A"));
assert(float_almost_equal(8.5, var_store_get_float(state1->varStore, "VAR_A")));
assert(process_line(state1, "set VAR_B to 1.5"));
assert(float_almost_equal(1.5, var_store_get_float(state1->varStore, "VAR_B")));
assert(process_line(state1, "set VAR_C to 142"));
assert(142 == var_store_get_int(state1->varStore, "VAR_C"));
assert(process_line(state1, "set VAR_D to VAR_A+VAR_B"));
assert(float_almost_equal(10, var_store_get_float(state1->varStore, "VAR_D")));
assert(process_line(state1, "set VAR_D to VAR_A+VAR_B"));
assert(float_almost_equal(10, var_store_get_float(state1->varStore, "VAR_D")));
assert(process_line(state1, "if VAR_D = 19 & 1 then"));
char* lines1 = "# hello world\n"
"set x to 5\n"
"set y to 1\n"
"if (x+y) = 6 then\n"
" set res to (1024)\n"
"end\n"
"\n";
struct StateContainer* state2 = state_init();
process_script(state2, lines1);
assert(!state2->skipping);
assert(1024 == var_store_get_int(state2->varStore, "res"));
assert(5 == var_store_get_int(state2->varStore, "x"));
assert(1 == var_store_get_int(state2->varStore, "y"));
char* lines2 = "set x to 5\n"
"set y to 1\n"
"set z to -1\n"
"if (x+y) = 6 then\n"
" if z = -1 then\n"
" set res to (1024)\n"
" end\n"
" set res to (res+1)\n"
"end\n";
process_script(state2, lines2);
assert(!state2->skipping);
assert(1025 == var_store_get_int(state2->varStore, "res"));
char* lines3 = "set res to -42\n"
"if 0 then\n"
" set res to 42\n"
"end\n"
"\n";
process_script(state2, lines3);
assert(!state2->skipping);
assert(-42 == var_store_get_int(state2->varStore, "res"));
char* lines4 = "set i to 0\n"
"while !(i = 9) do\n"
" set i to i+1\n"
"end\n";
process_script(state2, lines4);
assert(!state2->skipping);
printf("got i: %d \n", var_store_get_int(state2->varStore, "i"));
assert(9 == var_store_get_int(state2->varStore, "i"));
}

39
tests/test_stack.c Normal file
View file

@ -0,0 +1,39 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "../src/stack.h"
#include "../src/utils.h"
void test_stack()
{
printf("== test stack == \n");
int res;
struct IntStack* stack1 = int_stack_init();
assert(int_stack_push(stack1, 255));
assert(1 == int_stack_length(stack1));
assert(int_stack_push(stack1, 742));
assert(2 == int_stack_length(stack1));
assert(int_stack_pop(stack1, &res));
assert(742 == res);
assert(1 == int_stack_length(stack1));
assert(int_stack_push(stack1, 0));
assert(int_stack_push(stack1, -1));
assert(int_stack_push(stack1, -2));
assert(int_stack_push(stack1, 854));
assert(int_stack_push(stack1, 1024));
assert(int_stack_push(stack1, 2024));
assert(int_stack_push(stack1, 2025));
assert(int_stack_push(stack1, 2026));
assert(16 == stack1->allocated);
printf("%d \n", int_stack_length(stack1));
assert(9 == int_stack_length(stack1));
int_stack_print(stack1);
assert(int_stack_pop(stack1, &res));
assert(2026 == res);
assert(8 == int_stack_length(stack1));
}

1
tests/test_stack.h Normal file
View file

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

View file

@ -62,4 +62,16 @@ void test_utils()
// char src2[] = "hello";
// char* trimed2 = trim_space(&src2);
// assert(strcmp("hello", trimed2) == 0);
char src[] = " termination ";
char dst[strlen(src)];
trim_space((char*) &dst, src);
assert(strcmp("termination", dst) == 0);
char src2[] = "termination";
char dst2[strlen(src2)];
trim_space((char*) &dst2, src2);
assert(strcmp("termination", dst2) == 0);
}

18
tests/test_var_store.c Normal file
View file

@ -0,0 +1,18 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "../src/var_store.h"
void test_var_store()
{
printf("== test var store == \n");
struct VariableStore* store = var_store_init();
int iDest = 0;
for (int i = 0; i < 10; i++) {
var_store_set(store, "i", TYPE_INT, &i);
var_store_copy(store, "i", (void*) &iDest);
assert(i == iDest);
}
}

1
tests/test_var_store.h Normal file
View file

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