diff --git a/README.md b/README.md index da6bb20..5bd5d1f 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ ToDo List: - [ ] add inclusive operators like '!=', '>=', '<=' - [ ] add support for priority operators - [X] add input_number() std function -- [ ] add null type (dirty way to handle no returns and some errors) -- [ ] add type() std function and others type checking functions +- [X] add NULL type (dirty way to handle no returns and some errors) +- [X] add type() std function and others type checking functions - [X] add ceil() and floor() std functions - [X] base of the CLI - [ ] evaluate expression from stdin @@ -49,6 +49,7 @@ ToDo List: - [ ] add fully features strings support - [ ] add [classic problem solving](https://rosettacode.org) with code examples - [ ] add Web Assembly support and publish a demo website +- [ ] refactor: use malloc for list - [ ] refactor: remove inconsistency on how functions returns error codes ## Installation @@ -151,8 +152,7 @@ random_int(min, max) random_float(min, max) type(var) -> return the type of a var as int is_null(var) -is_int(var) -is_float(var) +is_number(var) print_string(str) print_newline() print_ascii(nb) diff --git a/src/evaluator.c b/src/evaluator.c index 9ad577b..8cfc085 100644 --- a/src/evaluator.c +++ b/src/evaluator.c @@ -170,7 +170,7 @@ int evaluator_reduce_parenthesis_pattern(struct List* evalList) { if ( ((i >= 1 && list_get_type(evalList, i-1) != TYPE_FUNC_NAME) || (i == 0)) && list_get_type(evalList, i) == TYPE_OPEN_PARENTHESIS && - is_type_number(list_get_type(evalList, i+1)) && + is_type_literal(list_get_type(evalList, i+1)) && list_get_type(evalList, i+2) == TYPE_CLOSE_PARENTHESIS ) { patternPos = i; @@ -208,7 +208,7 @@ int evaluator_reduce_var(struct StateContainer* state, struct List* evalList) { byte type = var_store_get_type_from_key(state->varStore, varKey); - if (EVALUATOR_DEBUG_LEVEL >= 2) printf("Going to reduce var key %d at pos %d\n", patternPos); + if (EVALUATOR_DEBUG_LEVEL >= 2) printf("Going to reduce var key %d at pos %d\n", varKey, patternPos); byte varVal[get_size_of_type(type)]; var_store_copy_from_key(state->varStore, varKey, &varVal); @@ -288,7 +288,7 @@ int evaluator_reduce_function_call(struct List* evalList, int initialPosition) { } if ( - is_type_number(list_get_type(evalList, pos)) && + is_type_literal(list_get_type(evalList, pos)) && list_get_type(evalList, pos+1) == TYPE_COMMA ) { // this is a new argument @@ -297,7 +297,7 @@ int evaluator_reduce_function_call(struct List* evalList, int initialPosition) { continue; } if ( - is_type_number(list_get_type(evalList, pos)) && + is_type_literal(list_get_type(evalList, pos)) && list_get_type(evalList, pos+1) == TYPE_CLOSE_PARENTHESIS ) { // we didn't match the last pattern so it's the last argument @@ -572,7 +572,7 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig printf("Now going to actually evaluate...\n"); } - while (evalList.num_elements > 1 || !is_type_number(list_get_type(&evalList, 0))) { + while (evalList.num_elements > 1 || !is_type_literal(list_get_type(&evalList, 0))) { if (EVALUATOR_DEBUG_LEVEL >= 2) list_print(&evalList); // int reduceVarOpStat = evaluator_reduce_var(state, &evalList); diff --git a/src/evaluator.h b/src/evaluator.h index 40a8424..13eb35a 100644 --- a/src/evaluator.h +++ b/src/evaluator.h @@ -2,7 +2,7 @@ #ifndef EVALUATOR_H_ #define EVALUATOR_H_ -#define EVALUATOR_DEBUG_LEVEL 0 +#define EVALUATOR_DEBUG_LEVEL (G_DEBUG_LEVEL) int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr); diff --git a/src/funcs.c b/src/funcs.c index 92696d6..5fbf44c 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -5,6 +5,35 @@ #include "./config.h" #include "./types.h" #include "./utils.h" +#include "./number_parsing.h" + +// just return the type id of a variable +int type_impl(int* res, unsigned char* resType, unsigned char* types, int* args) +{ + UNUSED(args); + *resType = TYPE_INT; + *res = types[0]; + + return 0; +} + +int is_null_impl(int* res, unsigned char* resType, unsigned char* types, int* args) +{ + UNUSED(args); + *resType = TYPE_INT; + *res = types[0] == TYPE_NULL; + + return 0; +} + +int is_number_impl(int* res, unsigned char* resType, unsigned char* types, int* args) +{ + UNUSED(args); + *resType = TYPE_INT; + *res = is_type_number(types[0]); + + return 0; +} int abs_impl(int* res, unsigned char* resType, unsigned char* types, int* args) { @@ -100,6 +129,9 @@ int print_ascii_impl(int* res, unsigned char* resType, unsigned char* types, int int print_newline_impl(int* res, unsigned char* resType, unsigned char* types, int* args) { + UNUSED(types); + UNUSED(args); + *resType = TYPE_INT; *res = 1; printf("\n"); @@ -109,6 +141,8 @@ int print_newline_impl(int* res, unsigned char* resType, unsigned char* types, i int input_number_impl(int* res, unsigned char* resType, unsigned char* types, int* args) { + UNUSED(types); + UNUSED(args); printf("? "); char* line; @@ -119,16 +153,16 @@ int input_number_impl(int* res, unsigned char* resType, unsigned char* types, in // printf("len=%d, lineSize=%d '%s' \n", len, lineSize, line); - char* toParse[lineSize+1]; - str_extract(toParse, line, 0, lineSize-1); + char toParse[lineSize+1]; + str_extract((char*) toParse, line, 0, lineSize-1); - int st = parse_int(toParse, res); + int st = parse_int((char*) &toParse, res); if (st == 0) { *resType = TYPE_INT; return 0; } if (st != 0) { - st = parse_float(toParse, (float*) res); + st = parse_float((char*) &toParse, (float*) res); if (st == 0) { *resType = TYPE_FLOAT; return 0; @@ -248,6 +282,8 @@ int max_impl(int* res, unsigned char* resType, unsigned char* types, int* args) int get_pi_impl(int* res, unsigned char* resType, unsigned char* types, int* args) { + UNUSED(args); + UNUSED(types); float val = CST_PI; *res = *(int *)(&val); *resType = TYPE_FLOAT; @@ -294,6 +330,10 @@ struct FuncIntro { // void* are actually long! struct FuncIntro intros[] = { + {"type", &type_impl, 1}, + {"is_null", &is_null_impl, 1}, + {"is_number", &is_number_impl, 1}, + {"abs", &abs_impl, 1}, {"sqrt", &sqrt_impl, 1}, diff --git a/src/line_processing.h b/src/line_processing.h index 96e3e7b..ad262f8 100644 --- a/src/line_processing.h +++ b/src/line_processing.h @@ -2,7 +2,7 @@ #ifndef LINE_PROCESSING_H_ #define LINE_PROCESSING_H_ -#define LINE_PROCESSING_DEBUG_LEVEL 0 +#define LINE_PROCESSING_DEBUG_LEVEL (G_DEBUG_LEVEL) #define BLOCK_IF 2 #define BLOCK_WHILE 3 diff --git a/src/list.c b/src/list.c index 0b84b23..09112b5 100644 --- a/src/list.c +++ b/src/list.c @@ -188,48 +188,12 @@ void list_print(struct List* list) printf("=== LIST REPORT === \n"); printf("num of elements: %d \n", list->num_elements); for (int i = 0; i < list->num_elements; i++) { - printf("- i: %d, ", i); + int type = list_get_type(list, i); - if (type == TYPE_INT) { - int d = 0; - list_get(list, i, &d); - - printf("type: INT, val: %d", d); - } - if (type == TYPE_FLOAT) { - float d = 0; - list_get(list, i, &d); - - printf("type: FLOAT, val: %f", d); - } - if (type == TYPE_OPERATOR) { - char d = 0; - list_get(list, i, &d); - - printf("type: OPERATOR, val: %d '%c'", d, d); - } - if (type == TYPE_FUNC_NAME) { - short d = 0; - list_get(list, i, &d); - - printf("type: FUNC_NAME, val: %d", d); - } - if (type == TYPE_VAR_NAME) { - short d = 0; - list_get(list, i, &d); - - printf("type: VAR_NAME, val: %d", d); - } - if (type == TYPE_OPEN_PARENTHESIS) { - printf("type: OPEN_PARENTHESIS"); - } - if (type == TYPE_COMMA) { - printf("type: COMMA"); - } - if (type == TYPE_CLOSE_PARENTHESIS) { - printf("type: CLOSE_PARENTHESIS"); - } - printf("\n"); + int data = 0; + list_get(list, i, &data); + + printf("- i: %d, %s \n", i, get_repr(type, (void*) &data)); } printf("=== END === \n"); } diff --git a/src/types.c b/src/types.c index dcc9096..3e79a33 100644 --- a/src/types.c +++ b/src/types.c @@ -3,6 +3,11 @@ #include #include +int is_type_literal(byte type) +{ + return is_type_number(type) || type == TYPE_NULL; +} + int is_type_number(byte type) { return type == TYPE_INT || type == TYPE_FLOAT; @@ -25,6 +30,7 @@ int get_size_of_type(byte type) return 1; } if ( + t == TYPE_NULL || t == TYPE_OPEN_PARENTHESIS || t == TYPE_CLOSE_PARENTHESIS || t == TYPE_COMMA @@ -36,25 +42,36 @@ int get_size_of_type(byte type) char* get_repr(byte type, void* valPtr) { - char* res= (char*) malloc(sizeof(char)*32); + char* res = (char*) malloc(sizeof(char)*32); + if (res == 0) return 0; if (type == 0) { + sprintf(res, "NO_TYPE"); + } else if (type == TYPE_NULL) { sprintf(res, "NULL"); - return res; - } - if (type == TYPE_INT) { + } else if (type == TYPE_INT) { sprintf(res, "INT(%d)", *((int*) valPtr)); - return res; - } - if (type == TYPE_FLOAT) { + } else if (type == TYPE_FLOAT) { sprintf(res, "FLOAT(%f)", *((float*) valPtr)); - return res; + } else if (type == TYPE_OPEN_PARENTHESIS) { + sprintf(res, "OPEN_PARENTHESIS"); + } else if (type == TYPE_CLOSE_PARENTHESIS) { + sprintf(res, "CLOSE_PARENTHESIS"); + } else if (type == TYPE_COMMA) { + sprintf(res, "COMMA"); + } else if (type == TYPE_OPERATOR) { + sprintf(res, "OPERATOR(%c)", *((char*) valPtr)); + } else if (type == TYPE_VAR_NAME) { + sprintf(res, "VAR_NAME(ref: %d)", *((int*) valPtr)); + } else if (type == TYPE_FUNC_NAME) { + sprintf(res, "FUNC_NAME(ref: %d)", *((int*) valPtr)); + } else { + sprintf(res, "UNKNOWN type=%d", type); } - - sprintf(res, "UNKNOWN type=%d", type); return res; } int convert_to_int(byte type, int repr) { + if (type == TYPE_NULL) return 0; if (type == TYPE_FLOAT) return (int) *((int*) &repr); return repr; } diff --git a/src/types.h b/src/types.h index f6236f5..2bfd4d0 100644 --- a/src/types.h +++ b/src/types.h @@ -2,6 +2,7 @@ #ifndef TYPES_H_ #define TYPES_H_ +#define TYPE_NULL 1 #define TYPE_INT 2 #define TYPE_FLOAT 3 #define TYPE_OPERATOR 32 @@ -11,10 +12,15 @@ #define TYPE_OPEN_PARENTHESIS 64 #define TYPE_CLOSE_PARENTHESIS 65 + +int is_type_literal(byte type); + int is_type_number(byte type); int get_size_of_type(byte type); +// get short string representation of a type +// usefull when printing a report char* get_repr(byte type, void* data); byte convert_to_bool(byte type, int repr); diff --git a/src/utils.h b/src/utils.h index 10cd57b..6cd8d25 100644 --- a/src/utils.h +++ b/src/utils.h @@ -3,6 +3,9 @@ #ifndef UTILS_H_ #define UTILS_H_ +// useful to silent warning of gcc of uunused parameters in functions +#define UNUSED(x) (void)(x) + #define CST_PI 3.1415926535 // define custom type (unsigned char) diff --git a/src/var_store.c b/src/var_store.c index 0bed8fc..8892dd9 100644 --- a/src/var_store.c +++ b/src/var_store.c @@ -4,6 +4,8 @@ #include #include +#define MAX_INTEGER 47797852 + struct VariableStore* var_store_init() { struct VariableStore* store = (struct VariableStore*) malloc(sizeof(struct VariableStore)); @@ -21,10 +23,16 @@ struct VariableStore* var_store_init() for (int i = 0; i < store->allocatedLength; i++) { store->container[i].type = 0; } + var_store_add_constants(store); + return store; } -#define MAX_INTEGER 47797852 +void var_store_add_constants(struct VariableStore* store) +{ + // NULL constant + var_store_set(store, "NULL", TYPE_NULL, 0); +} int var_store_hash_name(struct VariableStore* store, char* varName) { @@ -42,7 +50,7 @@ int var_store_hash_name(struct VariableStore* store, char* varName) byte var_store_set(struct VariableStore* store, char* varName, byte type, void* valuePtr) { //printf("set variable at var name: '%s' \n", varName); - if (!(type == TYPE_FLOAT || type == TYPE_INT)) { + if (!(type == TYPE_FLOAT || type == TYPE_INT || type == TYPE_NULL)) { printf("[ERR] VARSTORE: unsupported type, cannot store type %d\n", type); return 0; } diff --git a/src/var_store.h b/src/var_store.h index 9140390..ac9e305 100644 --- a/src/var_store.h +++ b/src/var_store.h @@ -32,6 +32,9 @@ struct VariableStore { struct VariableStore* var_store_init(); +// add to the store some useful constants (like NULL constructor) +void var_store_add_constants(struct VariableStore* store); + int var_store_hash_name(struct VariableStore* store, char* varName); // get a pointer to the area of memory where is store the variable diff --git a/tests/test_evaluation.c b/tests/test_evaluation.c index b9ab7e6..eefe447 100644 --- a/tests/test_evaluation.c +++ b/tests/test_evaluation.c @@ -175,4 +175,20 @@ void test_evaluation() assert(resType == TYPE_INT); printf("actually got: %d \n", resVal); assert(7 == resVal); + + evaluate(state, "is_number(123)", &resVal, &resType); + assert(resType == TYPE_INT); + assert(resVal); + + evaluate(state, "is_number(-25.5)", &resVal, &resType); + assert(resType == TYPE_INT); + assert(resVal); + + evaluate(state, "is_number(NULL)", &resVal, &resType); + assert(resType == TYPE_INT); + assert(!resVal); + + evaluate(state, "is_null(NULL)", &resVal, &resType); + assert(resType == TYPE_INT); + assert(resVal); }