feat: add while loops
This commit is contained in:
parent
14717958c6
commit
538205e8a5
29 changed files with 1248 additions and 282 deletions
2
Makefile
2
Makefile
|
@ -10,6 +10,8 @@ build:
|
||||||
test:
|
test:
|
||||||
gcc ${TEST_SRCS_ENC} ./tests/* -o ./bin/test ${CXXFLAGS_WITHOUT_PKGS}
|
gcc ${TEST_SRCS_ENC} ./tests/* -o ./bin/test ${CXXFLAGS_WITHOUT_PKGS}
|
||||||
./bin/test
|
./bin/test
|
||||||
|
test-no-run:
|
||||||
|
gcc ${TEST_SRCS_ENC} ./tests/* -o ./bin/test ${CXXFLAGS_WITHOUT_PKGS}
|
||||||
sandbox:
|
sandbox:
|
||||||
gcc ${TEST_SRCS_ENC} ./sandbox.c -o ./bin/sandbox ${CXXFLAGS_WITHOUT_PKGS}
|
gcc ${TEST_SRCS_ENC} ./sandbox.c -o ./bin/sandbox ${CXXFLAGS_WITHOUT_PKGS}
|
||||||
./bin/sandbox
|
./bin/sandbox
|
||||||
|
|
17
README.md
17
README.md
|
@ -22,15 +22,22 @@ ToDo List:
|
||||||
- [X] implement basic math functions
|
- [X] implement basic math functions
|
||||||
- [X] implement random_int(min, max)
|
- [X] implement random_int(min, max)
|
||||||
- [X] implement print_number(message)
|
- [X] implement print_number(message)
|
||||||
|
- [X] add unit tests
|
||||||
|
- [X] allow to set variables
|
||||||
|
- [X] read line comments
|
||||||
|
- [ ] add modulus operator '%'
|
||||||
- [ ] implement input_number()
|
- [ ] implement input_number()
|
||||||
- [ ] base of the CLI
|
- [ ] base of the CLI
|
||||||
- [ ] evaluate expression from stdin
|
- [ ] evaluate expression from stdin
|
||||||
- [ ] read a file
|
- [ ] read a file
|
||||||
- [X] allow to set variables
|
- [ ] if statements
|
||||||
- [X] read line comments
|
- [ ] while statements (with break)
|
||||||
- [ ] conditionals
|
- [ ] add functions support
|
||||||
- [ ] add unit tests
|
- [ ] add config header file
|
||||||
- [ ] function call stack
|
- [ ] ability to modify keywords and customize the lang
|
||||||
|
- [ ] add strings support
|
||||||
|
- [ ] add list support
|
||||||
|
|
||||||
|
|
||||||
## The language
|
## The language
|
||||||
|
|
||||||
|
|
9
examples/fibo.ltor
Normal file
9
examples/fibo.ltor
Normal 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
304
log.err
Normal 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
|
41
sandbox.c
41
sandbox.c
|
@ -23,12 +23,13 @@ int main () {
|
||||||
// memcpy(&dst, &yes, 4);
|
// memcpy(&dst, &yes, 4);
|
||||||
// printf("yes: %d \n", dst);
|
// 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++");
|
// int hashRes = var_store_hash_name(store, "HelloWorld++");
|
||||||
// printf("hashRes: %d \n", hashRes);
|
// printf("hashRes: %d \n", hashRes);
|
||||||
int val = 1234;
|
// int val = 1234;
|
||||||
var_store_set(store, "foo", TYPE_INT, &val);
|
// 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"));
|
//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("size of type %d \n", get_size_of_type(store->container[key].type));
|
||||||
//printf("%d \n", *((int*) store->container[key].dataPtr));
|
//printf("%d \n", *((int*) store->container[key].dataPtr));
|
||||||
|
|
||||||
int val2 = 0;
|
// int val2 = 0;
|
||||||
var_store_copy(store, "foo", &val2);
|
// 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();
|
struct StateContainer* state = state_init();
|
||||||
process_line(state, "# some random comment");
|
process_script(state, lines1);
|
||||||
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;
|
// struct List l1;
|
||||||
|
|
||||||
|
|
|
@ -355,6 +355,7 @@ Arguments:
|
||||||
- Input String: char pointer (the source of the evaluation)
|
- Input String: char pointer (the source of the evaluation)
|
||||||
- Result: int pointer (where the result of the evaluation will be written)
|
- 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 evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int _len = strlen(inputStr);
|
int _len = strlen(inputStr);
|
||||||
|
@ -397,10 +398,14 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
|
||||||
}
|
}
|
||||||
|
|
||||||
// display the partition
|
// display the partition
|
||||||
|
if (EVALUATOR_DEBUG_LEVEL >= 2) {
|
||||||
printf("partitionPtr: %d \n", partitionPtr);
|
printf("partitionPtr: %d \n", partitionPtr);
|
||||||
|
}
|
||||||
for (int j = 0; j < partitionPtr; j++) {
|
for (int j = 0; j < partitionPtr; j++) {
|
||||||
|
if (EVALUATOR_DEBUG_LEVEL >= 2) {
|
||||||
printf("start %d ", partitionStartPos[j]);
|
printf("start %d ", partitionStartPos[j]);
|
||||||
printf("stop %d ", partitionStopPos[j]);
|
printf("stop %d ", partitionStopPos[j]);
|
||||||
|
}
|
||||||
int len = partitionStopPos[j] - partitionStartPos[j];
|
int len = partitionStopPos[j] - partitionStartPos[j];
|
||||||
|
|
||||||
char buff[_len];
|
char buff[_len];
|
||||||
|
@ -410,9 +415,10 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buff[len] = 0;
|
buff[len] = 0;
|
||||||
|
if (EVALUATOR_DEBUG_LEVEL >= 2) {
|
||||||
printf("content %s \n", buff);
|
printf("content %s \n", buff);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// once we've lexed our expression, we want to analyse if it's righly parenthesized
|
// once we've lexed our expression, we want to analyse if it's righly parenthesized
|
||||||
int parenthesisCount = 0;
|
int parenthesisCount = 0;
|
||||||
|
@ -446,14 +452,16 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
|
||||||
struct List evalList;
|
struct List evalList;
|
||||||
// NOTICE: for some reason the struct don't reset after a usage
|
// NOTICE: for some reason the struct don't reset after a usage
|
||||||
list_reset(&evalList);
|
list_reset(&evalList);
|
||||||
printf("\n - constructing list \n");
|
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("\n - constructing list \n");
|
||||||
// initializing the evaluation list
|
// initializing the evaluation list
|
||||||
for (int j = 0; j < partitionPtr; j++) {
|
for (int j = 0; j < partitionPtr; j++) {
|
||||||
|
|
||||||
int startPos = partitionStartPos[j];
|
int startPos = partitionStartPos[j];
|
||||||
int stopPos = partitionStopPos[j];
|
int stopPos = partitionStopPos[j];
|
||||||
|
if (EVALUATOR_DEBUG_LEVEL >= 2) {
|
||||||
printf("=== %d\n", j);
|
printf("=== %d\n", j);
|
||||||
printf("startPos %d, stopPos %d\n", startPos, stopPos);
|
printf("startPos %d, stopPos %d\n", startPos, stopPos);
|
||||||
|
}
|
||||||
int len = stopPos - startPos;
|
int len = stopPos - startPos;
|
||||||
|
|
||||||
// modifiy the start and stop pos to trim spaces
|
// 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
|
buff[len] = 0; // terminate the buff
|
||||||
|
|
||||||
// TODO: SPLIT INTO A FUNCTION "identify_token(char* str)"
|
// TODO: SPLIT INTO A FUNCTION "identify_token(char* str)"
|
||||||
|
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("buff: '%s' \n", buff);
|
||||||
printf("buff: '%s' \n", buff);
|
|
||||||
|
|
||||||
char dumbValue = (char) 0;
|
char dumbValue = (char) 0;
|
||||||
|
|
||||||
|
@ -506,7 +513,7 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (len == 1 && is_operator(buff[0])) {
|
if (len == 1 && is_operator(buff[0])) {
|
||||||
printf("found op\n");
|
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("found op\n");
|
||||||
char opValue = buff[0];
|
char opValue = buff[0];
|
||||||
list_set(&evalList, evalList.num_elements, TYPE_OPERATOR, &opValue);
|
list_set(&evalList, evalList.num_elements, TYPE_OPERATOR, &opValue);
|
||||||
continue;
|
continue;
|
||||||
|
@ -532,7 +539,11 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
|
||||||
// identify token
|
// identify token
|
||||||
// first try a variable then a func name
|
// first try a variable then a func name
|
||||||
// not a float, check if this is a common function 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) {
|
if (varKey == -1) {
|
||||||
// did not find the var name
|
// did not find the var name
|
||||||
short funcID = identify_func_name(buff);
|
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);
|
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
|
// check the content of this thing
|
||||||
|
if (EVALUATOR_DEBUG_LEVEL >= 2) {
|
||||||
list_print(&evalList);
|
list_print(&evalList);
|
||||||
printf("Now going to actually evaluate \n");
|
printf("Now going to actually evaluate \n");
|
||||||
|
}
|
||||||
|
|
||||||
while (evalList.num_elements > 1) {
|
while (evalList.num_elements > 1) {
|
||||||
list_print(&evalList);
|
if (EVALUATOR_DEBUG_LEVEL >= 2) list_print(&evalList);
|
||||||
|
|
||||||
// int reduceVarOpStat = evaluator_reduce_var(state, &evalList);
|
// int reduceVarOpStat = evaluator_reduce_var(state, &evalList);
|
||||||
// int reduceFuncOpStat = evaluator_reduce_function_call(&evalList, 0);
|
// 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 == 3) stat = evaluator_reduce_not_pattern(&evalList);
|
||||||
if (m == 4) stat = evaluator_reduce_operator_pattern(&evalList);
|
if (m == 4) stat = evaluator_reduce_operator_pattern(&evalList);
|
||||||
if (m == 5) stat = evaluator_reduce_parenthesis_pattern(&evalList);
|
if (m == 5) stat = evaluator_reduce_parenthesis_pattern(&evalList);
|
||||||
printf("Tried mod %d got stat %d \n", m, stat);
|
|
||||||
if (stat > 0) {
|
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);
|
list_print(&evalList);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (stat == 0) {
|
if (stat == 0) {
|
||||||
didReduced = 1;
|
didReduced = 1;
|
||||||
}
|
}
|
||||||
|
@ -589,8 +604,11 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
|
||||||
if (!didReduced) {
|
if (!didReduced) {
|
||||||
// all scans failed to find things to reduce
|
// all scans failed to find things to reduce
|
||||||
// this is actually a failure because we can't do anything to get down to 1 element in the eval list
|
// this is actually a failure because we can't do anything to get down to 1 element in the eval list
|
||||||
printf("ERR Evaluator: could not reduce more, dumping evalList: \n");
|
printf("ERR Evaluator: could not reduce more \n");
|
||||||
|
if (EVALUATOR_DEBUG_LEVEL >= 2) {
|
||||||
|
printf("dumping evalList: \n");
|
||||||
list_print(&evalList);
|
list_print(&evalList);
|
||||||
|
}
|
||||||
return 400;
|
return 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#ifndef EVALUATOR_H_
|
#ifndef EVALUATOR_H_
|
||||||
#define EVALUATOR_H_
|
#define EVALUATOR_H_
|
||||||
|
|
||||||
|
#define EVALUATOR_DEBUG_LEVEL 1
|
||||||
|
|
||||||
int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr);
|
int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -259,13 +259,8 @@ int execute_func(short funcID, short argsLen, unsigned char* argsTypes, int* arg
|
||||||
// call the function implementation
|
// call the function implementation
|
||||||
// first cast the function ptr
|
// first cast the function ptr
|
||||||
impl(resPtr, resTypePtr, argsTypes, argsValues);
|
impl(resPtr, resTypePtr, argsTypes, argsValues);
|
||||||
if (*resTypePtr == TYPE_FLOAT) {
|
|
||||||
printf("Got TYPE_FLOAT with val: %f \n", get_float_from_int_rep(*resPtr));
|
printf("Got %s \n", get_repr(*resTypePtr, 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,11 @@
|
||||||
#include "./utils.h"
|
#include "./utils.h"
|
||||||
#include "./line_processing.h"
|
#include "./line_processing.h"
|
||||||
|
#include "./stack.h"
|
||||||
#include "./evaluator.h"
|
#include "./evaluator.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.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 is_char_accepted_in_var_name(char symbol)
|
||||||
{
|
{
|
||||||
int c = (int) symbol;
|
int c = (int) symbol;
|
||||||
|
@ -55,15 +43,42 @@ int recognize_comment_statement(char* lineStr)
|
||||||
return 1;
|
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 {
|
like
|
||||||
short name_start;
|
if machin then
|
||||||
short name_stop;
|
while machin do
|
||||||
short expression_start;
|
*/
|
||||||
};
|
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)
|
int recognize_set_statement(char* lineStr, struct SetStatement* res)
|
||||||
{
|
{
|
||||||
|
static char setStatementStartKeyword[] = "set";
|
||||||
|
static char setStatementStopKeyword[] = "to";
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int mode = 1;
|
int mode = 1;
|
||||||
int arg = 0;
|
int arg = 0;
|
||||||
|
@ -79,90 +94,49 @@ int recognize_set_statement(char* lineStr, struct SetStatement* res)
|
||||||
mode 8 the expression
|
mode 8 the expression
|
||||||
*/
|
*/
|
||||||
while (lineStr[i] != '\0') {
|
while (lineStr[i] != '\0') {
|
||||||
|
//printf("mode: %d, char: '%c' \n", mode, lineStr[i]);
|
||||||
if (mode == 1) {
|
if (mode == 1) {
|
||||||
if (lineStr[i] == 's') {
|
if (str_needle_at_pos(setStatementStartKeyword, lineStr, i)) {
|
||||||
mode = 2;
|
mode = 2;
|
||||||
arg = 0;
|
i += strlen(setStatementStartKeyword);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (lineStr[i] != ' ') {
|
if (lineStr[i] != ' ') break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (mode == 2) {
|
if (mode == 2) {
|
||||||
if (arg == 0 && lineStr[i] == 's') {
|
if (arg > 0 && is_char_accepted_in_var_name(lineStr[i])) {
|
||||||
arg++;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (arg == 1 && lineStr[i] == 'e') {
|
|
||||||
arg++;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (arg == 2 && lineStr[i] == 't') {
|
|
||||||
mode = 3;
|
mode = 3;
|
||||||
arg = 0;
|
arg = 0;
|
||||||
|
res->name_start = i;
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
if (lineStr[i] != ' ') break;
|
||||||
|
arg++;
|
||||||
}
|
}
|
||||||
if (mode == 3) {
|
if (mode == 3) {
|
||||||
if (arg > 0 && is_char_accepted_in_var_name(lineStr[i])) {
|
if (lineStr[i] == ' ') {
|
||||||
mode = 4;
|
mode = 4;
|
||||||
arg = 0;
|
arg = 0;
|
||||||
res->name_start = i;
|
res->name_stop = i;
|
||||||
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (lineStr[i] != ' ') {
|
if (!is_char_accepted_in_var_name(lineStr[i])) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
arg++;
|
|
||||||
}
|
}
|
||||||
if (mode == 4) {
|
if (mode == 4) {
|
||||||
if (lineStr[i] == ' ') {
|
if (str_needle_at_pos(setStatementStopKeyword, lineStr, i)) {
|
||||||
mode = 5;
|
mode = 5;
|
||||||
arg = 0;
|
i += strlen(setStatementStopKeyword);
|
||||||
res->name_stop = i;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!is_char_accepted_in_var_name(lineStr[i])) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (mode == 5) {
|
if (mode == 5) {
|
||||||
if (arg > 0 && lineStr[i] == 't') {
|
if (arg == 0 && lineStr[i] != ' ') break;
|
||||||
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] != ' ') {
|
if (arg > 0 && lineStr[i] != ' ') {
|
||||||
// success
|
// success
|
||||||
mode = 8;
|
mode = 6;
|
||||||
res->expression_start = i;
|
res->expression_start = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -171,23 +145,170 @@ int recognize_set_statement(char* lineStr, struct SetStatement* res)
|
||||||
|
|
||||||
i++;
|
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) {
|
if (mode != 6) return 0;
|
||||||
// we've failed to recognize the pattern
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return a struct with anchors to the groups
|
|
||||||
return 1;
|
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)
|
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
|
// process
|
||||||
int len = strlen(str);
|
int len = strlen(str);
|
||||||
// int startPos = 0;
|
// int startPos = 0;
|
||||||
|
@ -217,15 +338,97 @@ int process_line(struct StateContainer* state, char* str)
|
||||||
|
|
||||||
//int stat = 0;
|
//int stat = 0;
|
||||||
if (recognize_comment_statement(str)) {
|
if (recognize_comment_statement(str)) {
|
||||||
printf("Comment recognized \n");
|
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Comment recognized \n");
|
||||||
|
state->linePtr++;
|
||||||
return 1;
|
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;
|
struct SetStatement setStatementParsing;
|
||||||
if (recognize_set_statement(str, &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)
|
// handle the set statement (set a variable)
|
||||||
int nameLen = setStatementParsing.name_stop-setStatementParsing.name_start;
|
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++) {
|
for (int z = 0; z < nameLen; z++) {
|
||||||
name[z] = str[setStatementParsing.name_start + z];
|
name[z] = str[setStatementParsing.name_start + z];
|
||||||
}
|
}
|
||||||
|
@ -233,13 +436,84 @@ int process_line(struct StateContainer* state, char* str)
|
||||||
|
|
||||||
int res;
|
int res;
|
||||||
byte resType;
|
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) {
|
if (evalStat != 0) {
|
||||||
printf("Syntax error for line \"%s\"\n", str);
|
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);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,5 +525,70 @@ int process_line(struct StateContainer* state, char* str)
|
||||||
printf("Syntax error for line \"%s\"\n", str);
|
printf("Syntax error for line \"%s\"\n", str);
|
||||||
return 0;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,35 @@
|
||||||
#ifndef LINE_PROCESSING_H_
|
#ifndef LINE_PROCESSING_H_
|
||||||
#define 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);
|
int process_line(struct StateContainer* state, char* str);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
93
src/main.c
93
src/main.c
|
@ -1,4 +1,4 @@
|
||||||
#include <stdbool.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "./stack.h"
|
#include "./stack.h"
|
||||||
|
@ -7,78 +7,39 @@
|
||||||
#include "./evaluator.h"
|
#include "./evaluator.h"
|
||||||
#include "./utils.h"
|
#include "./utils.h"
|
||||||
#include "./types.h"
|
#include "./types.h"
|
||||||
//int create_stack(int a, int b)
|
#include "./line_processing.h"
|
||||||
|
|
||||||
void test_list()
|
byte load_file(char* filename, char** resultPtr) {
|
||||||
{
|
FILE* f = fopen(filename, "rb");
|
||||||
// test dynamic list
|
|
||||||
struct List l1;
|
|
||||||
|
|
||||||
printf("0: %d \n", list_append_int(&l1, 844));
|
if (!f) {
|
||||||
printf("1: %d \n", list_get_type(&l1, 0));
|
return 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]);
|
|
||||||
}
|
}
|
||||||
printf("\n");
|
fseek(f, 0, SEEK_END);
|
||||||
|
long length = ftell(f);
|
||||||
list_get_int(&l1, 0, &val);
|
fseek (f, 0, SEEK_SET);
|
||||||
printf("6: %d \n", val);
|
char* buffer = (char*) malloc(length);
|
||||||
|
if (!buffer) {
|
||||||
list_delete(&l1, 0);
|
return 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]);
|
|
||||||
}
|
}
|
||||||
// 844, 855, 866, 877
|
if (buffer) {
|
||||||
list_get_int(&l1, 2, &val);
|
fread(buffer, 1, length, f);
|
||||||
printf("6: %d \n", val);
|
}
|
||||||
|
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;
|
// printf("Invalid usage use --help to document your self\n");
|
||||||
int resType = 0;
|
printf("CLI not implemented yet ¯\\_(ツ)_/¯ \n");
|
||||||
int evalStatus = evaluate(inputStr2, &res, &resType);
|
return 1;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(
|
int operate(
|
||||||
byte operator,
|
byte operator,
|
||||||
byte typeA, int aRepr,
|
byte typeA, int aRepr,
|
||||||
|
@ -79,7 +69,7 @@ int operate(
|
||||||
a = convert_to_float(typeA, aRepr);
|
a = convert_to_float(typeA, aRepr);
|
||||||
b = convert_to_float(typeB, bRepr);
|
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 == '+') {
|
if (operator == '+') {
|
||||||
res = a+b;
|
res = a+b;
|
||||||
|
@ -96,13 +86,13 @@ int operate(
|
||||||
} else {
|
} else {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
printf("Got float: %f \n", res);
|
if (OPERATE_DEBUG_LEVEL) printf("Got float: %f \n", res);
|
||||||
// get int representation of float
|
// get int representation of float
|
||||||
*resPtr = *(int *)(&res);
|
*resPtr = *(int *)(&res);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (typeA == TYPE_INT && typeB == TYPE_INT) {
|
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;
|
*typeRes = TYPE_INT;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
if (operator == '+') {
|
if (operator == '+') {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
|
||||||
#ifndef OPERATOR_H_
|
#ifndef OPERATOR_H_
|
||||||
#define OPERATOR_H_
|
#define OPERATOR_H_
|
||||||
|
|
||||||
|
#define OPERATE_DEBUG_LEVEL 0
|
||||||
|
|
||||||
int is_operator(char candidate);
|
int is_operator(char candidate);
|
||||||
|
|
||||||
int operate(
|
int operate(
|
||||||
|
|
54
src/stack.c
54
src/stack.c
|
@ -1,35 +1,55 @@
|
||||||
|
#include "./utils.h"
|
||||||
#include "./stack.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) {
|
struct IntStack* stack = (struct IntStack*) malloc(sizeof(struct IntStack));
|
||||||
// return a stack overflow error
|
stack->length = 0;
|
||||||
return 1;
|
stack->allocated = 8;
|
||||||
}
|
stack->data = (int*) malloc(stack->allocated * sizeof(int));
|
||||||
|
|
||||||
stack->data[stack->end_pos] = valueToPush;
|
return stack;
|
||||||
stack->end_pos = stack->end_pos + 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int int_stack_pop(struct IntStack* stack, int* valuePtr)
|
byte int_stack_push(struct IntStack* stack, int valueToPush)
|
||||||
{
|
{
|
||||||
if (stack->end_pos == 0) {
|
if (stack->length == stack->allocated) {
|
||||||
// return a stack underflow error
|
stack->allocated *= 2;
|
||||||
return 1;
|
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;
|
return 1;
|
||||||
*valuePtr = stack->data[stack->end_pos];
|
}
|
||||||
|
|
||||||
|
byte int_stack_pop(struct IntStack* stack, int* valuePtr)
|
||||||
|
{
|
||||||
|
if (stack->length == 0) {
|
||||||
|
// error, nothing to pop
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*valuePtr = stack->data[stack->length-1];
|
||||||
|
|
||||||
|
stack->length--;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int int_stack_length(struct IntStack* stack)
|
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");
|
||||||
|
}
|
||||||
|
|
16
src/stack.h
16
src/stack.h
|
@ -1,17 +1,21 @@
|
||||||
|
#include "./utils.h"
|
||||||
#ifndef STACK_H_
|
#ifndef STACK_H_
|
||||||
#define STACK_H_
|
#define STACK_H_
|
||||||
|
|
||||||
#define STACK_LEN 255
|
|
||||||
|
|
||||||
struct IntStack {
|
struct IntStack {
|
||||||
int end_pos;
|
int length;
|
||||||
int data[STACK_LEN];
|
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);
|
int int_stack_length(struct IntStack* stack);
|
||||||
|
|
||||||
|
void int_stack_print(struct IntStack* stack);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
23
src/state.c
23
src/state.c
|
@ -3,23 +3,20 @@
|
||||||
#include "./state.h"
|
#include "./state.h"
|
||||||
#include <stdlib.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* state_init()
|
||||||
{
|
{
|
||||||
struct StateContainer* ptr = (struct StateContainer*) malloc(sizeof(struct StateContainer));
|
struct StateContainer* ptr = (struct StateContainer*) malloc(sizeof(struct StateContainer));
|
||||||
ptr->varStore = var_store_init();
|
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;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
src/state.h
36
src/state.h
|
@ -5,18 +5,31 @@ we store:
|
||||||
- the functions names and their references
|
- the functions names and their references
|
||||||
*/
|
*/
|
||||||
#include "./utils.h"
|
#include "./utils.h"
|
||||||
|
#include "./stack.h"
|
||||||
#include "./var_store.h"
|
#include "./var_store.h"
|
||||||
#ifndef STATE_H_
|
#ifndef STATE_H_
|
||||||
#define STATE_H_
|
#define STATE_H_
|
||||||
|
|
||||||
struct StateContainer {
|
struct StateContainer {
|
||||||
|
struct VariableStore* varStore;
|
||||||
|
|
||||||
|
// if true, continue to look for new lines to execute
|
||||||
|
byte running;
|
||||||
|
|
||||||
// the line we are currently processing
|
// the line we are currently processing
|
||||||
int linePtr;
|
int linePtr;
|
||||||
// usefull when we are in SKIP_BLOCK mode, we'will count the nb of block (begin/end)
|
|
||||||
int blocStack;
|
// store the head address of loops
|
||||||
// FULL, SKIP_BLOC, etc
|
struct IntStack* loopStack;
|
||||||
byte mode;
|
|
||||||
struct VariableStore* varStore;
|
// 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 FunctionStore* funcStore;
|
||||||
// struct StringStore* strStore ??
|
// struct StringStore* strStore ??
|
||||||
};
|
};
|
||||||
|
@ -24,3 +37,16 @@ struct StateContainer {
|
||||||
struct StateContainer* state_init();
|
struct StateContainer* state_init();
|
||||||
|
|
||||||
#endif
|
#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
|
||||||
|
*/
|
||||||
|
|
14
src/types.c
14
src/types.c
|
@ -53,3 +53,17 @@ char* get_repr(byte type, void* valPtr)
|
||||||
sprintf(res, "UNKNOWN(%d)", type);
|
sprintf(res, "UNKNOWN(%d)", type);
|
||||||
return res;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -17,4 +17,8 @@ int get_size_of_type(byte type);
|
||||||
|
|
||||||
char* get_repr(byte type, void* data);
|
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
|
#endif
|
||||||
|
|
50
src/utils.c
50
src/utils.c
|
@ -1,4 +1,5 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include "./utils.h"
|
#include "./utils.h"
|
||||||
|
|
||||||
int get_int_rep_from_float(float ft)
|
int get_int_rep_from_float(float ft)
|
||||||
|
@ -262,8 +263,51 @@ int is_full_of_space(char* str)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* trim_space(char* str)
|
void trim_space(char* dst, char* subject)
|
||||||
{
|
{
|
||||||
// TODO: implements me
|
// trim spaces on both sides
|
||||||
return str;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,11 @@ float m_tan(float x);
|
||||||
|
|
||||||
int is_full_of_space(char* str);
|
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
|
#endif
|
||||||
|
|
|
@ -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;
|
hash += (get_int_rep_from_char(varName[i])*integer_pow(9, i)) % MAX_INTEGER;
|
||||||
i++;
|
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;
|
return hash % store->allocatedLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +72,9 @@ byte var_store_set(struct VariableStore* store, char* varName, byte type, void*
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (store->container[key].type == 0) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
if (strcmp(store->container[key].namePtr, varName) == 0) {
|
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].namePtr = namePtr;
|
||||||
store->container[key].dataPtr = dataPtr;
|
store->container[key].dataPtr = dataPtr;
|
||||||
|
|
||||||
store->length++;
|
|
||||||
if (2*store->length >= store->allocatedLength) {
|
if (2*store->length >= store->allocatedLength) {
|
||||||
// do smth to double the store->allocatedLength
|
// do smth to double the store->allocatedLength
|
||||||
// e.g reallocate the store->container
|
// e.g reallocate the store->container
|
||||||
|
// FIXME: copy all variables to their new keys
|
||||||
store->allocatedLength = 2*store->allocatedLength;
|
store->allocatedLength = 2*store->allocatedLength;
|
||||||
store->container = (struct VariableContainer*) realloc(store->container, sizeof(struct VariableContainer) * store->allocatedLength);
|
store->container = (struct VariableContainer*) realloc(store->container, sizeof(struct VariableContainer) * store->allocatedLength);
|
||||||
if (store->container == NULL) {
|
if (store->container == NULL) {
|
||||||
|
@ -182,3 +187,19 @@ float var_store_get_float(struct VariableStore* store, char* varName)
|
||||||
var_store_copy(store, varName, &val);
|
var_store_copy(store, varName, &val);
|
||||||
return 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");
|
||||||
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
#include "./test_utils.h"
|
#include "./test_utils.h"
|
||||||
#include "./test_evaluation.h"
|
#include "./test_evaluation.h"
|
||||||
#include "./test_line_processing.h"
|
#include "./test_line_processing.h"
|
||||||
|
#include "./test_stack.h"
|
||||||
|
#include "./test_var_store.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
printf("== UNIT TESTS == \n");
|
printf("== UNIT TESTS == \n");
|
||||||
|
test_var_store();
|
||||||
|
test_stack();
|
||||||
test_utils();
|
test_utils();
|
||||||
test_evaluation();
|
test_evaluation();
|
||||||
test_line_processing();
|
test_line_processing();
|
||||||
|
|
|
@ -7,28 +7,112 @@
|
||||||
#include "../src/evaluator.h"
|
#include "../src/evaluator.h"
|
||||||
#include "../src/state.h"
|
#include "../src/state.h"
|
||||||
#include "../src/var_store.h"
|
#include "../src/var_store.h"
|
||||||
|
#include "../src/line_processing.h"
|
||||||
|
|
||||||
void test_line_processing()
|
void test_line_processing()
|
||||||
{
|
{
|
||||||
printf("== test line processing == \n");
|
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(recognize_termination_keyword("end", "01 end", 2));
|
||||||
assert(process_line(state, "# some random comment"));
|
assert(!recognize_termination_keyword("end", "01 end == something end", 2));
|
||||||
assert(process_line(state, "set VAR_A to 8.5"));
|
assert(!recognize_termination_keyword("end", "xend", 0));
|
||||||
printf("%d \n", var_store_get_int(state->varStore, "VAR_A"));
|
assert(!recognize_termination_keyword("end", "end", 0));
|
||||||
assert(float_almost_equal(8.5, var_store_get_float(state->varStore, "VAR_A")));
|
assert(recognize_termination_keyword("end", " end", 0));
|
||||||
|
|
||||||
assert(process_line(state, "set VAR_B to 1.5"));
|
struct SetStatement res;
|
||||||
assert(float_almost_equal(1.5, var_store_get_float(state->varStore, "VAR_B")));
|
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"));
|
struct IfStatement resIf;
|
||||||
assert(142 == var_store_get_int(state->varStore, "VAR_C"));
|
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"));
|
struct WhileStatement resWhile;
|
||||||
assert(float_almost_equal(10, var_store_get_float(state->varStore, "VAR_D")));
|
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"));
|
struct StateContainer* state1 = state_init();
|
||||||
assert(float_almost_equal(10, var_store_get_float(state->varStore, "VAR_D")));
|
|
||||||
|
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
39
tests/test_stack.c
Normal 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
1
tests/test_stack.h
Normal file
|
@ -0,0 +1 @@
|
||||||
|
void test_stack();
|
|
@ -62,4 +62,16 @@ void test_utils()
|
||||||
// char src2[] = "hello";
|
// char src2[] = "hello";
|
||||||
// char* trimed2 = trim_space(&src2);
|
// char* trimed2 = trim_space(&src2);
|
||||||
// assert(strcmp("hello", trimed2) == 0);
|
// 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
18
tests/test_var_store.c
Normal 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
1
tests/test_var_store.h
Normal file
|
@ -0,0 +1 @@
|
||||||
|
void test_var_store();
|
Loading…
Reference in a new issue