diff --git a/HISTORY b/HISTORY index 85fbc55..6cf9030 100755 --- a/HISTORY +++ b/HISTORY @@ -1,3 +1,6 @@ +Jul. 12 2015 +Added array manipulation functions + Jun. 19 2015 Added an mb_schedule_suspend interface to schedule to suspend the execution diff --git a/core/my_basic.c b/core/my_basic.c index 1b7ebc7..aa0ad67 100755 --- a/core/my_basic.c +++ b/core/my_basic.c @@ -78,7 +78,7 @@ extern "C" { /** Macros */ #define _VER_MAJOR 1 #define _VER_MINOR 1 -#define _VER_REVISION 56 +#define _VER_REVISION 57 #define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION)) /* Uncomment this line to treat warnings as error */ @@ -670,6 +670,7 @@ static void _set_error_pos(mb_interpreter_t* s, int pos, unsigned short row, uns static int_t _get_size_of(_data_e type); static bool_t _try_get_value(_object_t* obj, mb_value_u* val, _data_e expected); +static int _get_array_pos(struct mb_interpreter_t* s, _array_t* arr, int* d, int c); static int _get_array_index(mb_interpreter_t* s, _ls_node_t** l, unsigned int* index); static bool_t _get_array_elem(mb_interpreter_t* s, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type); static int _set_array_elem(mb_interpreter_t* s, _ls_node_t* ast, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type); @@ -677,6 +678,7 @@ static int _set_array_elem(mb_interpreter_t* s, _ls_node_t* ast, _array_t* arr, static void _init_array(_array_t* arr); static void _clear_array(_array_t* arr); static void _destroy_array(_array_t* arr); +static bool_t _is_array(void* obj); static bool_t _is_string(void* obj); static char* _extract_string(_object_t* obj); static bool_t _is_internal_object(_object_t* obj); @@ -685,6 +687,8 @@ static int _destroy_object(void* data, void* extra); static int _destroy_object_non_syntax(void* data, void* extra); static int _remove_source_object(void* data, void* extra); static int _compare_numbers(const _object_t* first, const _object_t* second); +static _data_e _public_type_to_internal_type(mb_data_e t); +static mb_data_e _internal_type_to_public_type(_data_e t); static int _public_value_to_internal_object(mb_value_t* pbl, _object_t* itn); static int _internal_object_to_public_value(_object_t* itn, mb_value_t* pbl); static void _try_clear_intermediate_value(void* data, void* extra, mb_interpreter_t* s); @@ -1635,6 +1639,35 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { } _ls_pushback(opnd, c); f++; + } else if(c->type == _DT_VAR && c->data.variable->data->type == _DT_ARRAY) { + ast = ast->prev; + result = _get_array_index(s, &ast, &arr_idx); + if(result != MB_FUNC_OK) { + _handle_error_on_obj(s, SE_RN_CALCULATION_ERROR, DON(ast), MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + _get_array_elem(s, c->data.variable->data->data.array, arr_idx, &arr_val, &arr_type); + arr_elem = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(arr_elem, 0, sizeof(_object_t)); + _ls_pushback(garbage, arr_elem); + arr_elem->type = arr_type; + arr_elem->ref = true; + if(arr_type == _DT_INT) { + arr_elem->data.integer = arr_val.integer; + } else if(arr_type == _DT_REAL) { + arr_elem->data.float_point = arr_val.float_point; + } else if(arr_type == _DT_STRING) { + arr_elem->data.string = arr_val.string; + } else if(arr_type == _DT_USERTYPE) { + arr_elem->data.usertype = arr_val.usertype; + } else { + mb_assert(0 && "Unsupported"); + } + if(f) { + _handle_error_on_obj(s, SE_RN_OPERATOR_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + _ls_pushback(opnd, arr_elem); + f++; } else { if(c->type == _DT_VAR && ast) { _object_t* _err_var = (_object_t*)(ast->data); @@ -1700,7 +1733,7 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { } c = (_object_t*)(_ls_popback(opnd)); - if(!c || !(c->type == _DT_INT || c->type == _DT_REAL || c->type == _DT_STRING || c->type == _DT_VAR || c->type == _DT_USERTYPE)) { + if(!c || !(c->type == _DT_INT || c->type == _DT_REAL || c->type == _DT_STRING || c->type == _DT_VAR || c->type == _DT_USERTYPE || c->type == _DT_ARRAY)) { _set_current_error(s, SE_RN_INVALID_DATA_TYPE); result = MB_FUNC_ERR; @@ -1718,6 +1751,9 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { (*val)->data.string = (char*)mb_malloc(_sl + 1); (*val)->data.string[_sl] = '\0'; memcpy((*val)->data.string, c->data.string, _sl + 1); + } else if(c->type == _DT_ARRAY) { + (*val)->data = c->data; + c->type = _DT_NIL; } else { (*val)->data = c->data; } @@ -2343,6 +2379,7 @@ bool_t _try_get_value(_object_t* obj, mb_value_u* val, _data_e expected) { bool_t result = false; mb_assert(obj && val); + if(obj->type == _DT_INT && (expected == _DT_ANY || expected == _DT_INT)) { val->integer = obj->data.integer; result = true; @@ -2356,8 +2393,38 @@ bool_t _try_get_value(_object_t* obj, mb_value_u* val, _data_e expected) { return result; } +int _get_array_pos(struct mb_interpreter_t* s, _array_t* arr, int* d, int c) { + /* Calculate the index, used when interactive with host */ + int result = 0; + int i = 0; + int n = 0; + + mb_assert(s && arr && d); + + if(c < 0 || c > arr->dimension_count) { + result = -1; + + goto _exit; + } + for(i = 0; i < c; i++) { + n = d[i]; + if(n < 0 || n >= arr->dimensions[i]) { + result = -1; + + goto _exit; + } + if(result) + result *= n; + else + result += n; + } + +_exit: + return result; +} + int _get_array_index(mb_interpreter_t* s, _ls_node_t** l, unsigned int* index) { - /* Calculate the index */ + /* Calculate the index, used when walking through an AST */ int result = MB_FUNC_OK; _ls_node_t* ast = 0; _object_t* arr = 0; @@ -2374,10 +2441,13 @@ int _get_array_index(mb_interpreter_t* s, _ls_node_t** l, unsigned int* index) { /* Array name */ ast = (_ls_node_t*)(*l); - if(!ast || ((_object_t*)(ast->data))->type != _DT_ARRAY) { + if(!ast || !_is_array(ast->data)) { _handle_error_on_obj(s, SE_RN_ARRAY_IDENTIFIER_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); } - arr = (_object_t*)(ast->data); + if(((_object_t*)(ast->data))->type == _DT_ARRAY) + arr = (_object_t*)(ast->data); + else + arr = ((_object_t*)(ast->data))->data.variable->data; /* ( */ if(!ast->next || ((_object_t*)(ast->next->data))->type != _DT_FUNC || ((_object_t*)(ast->next->data))->data.func->pointer != _core_open_bracket) { _handle_error_on_obj(s, SE_RN_OPEN_BRACKET_EXPECTED, @@ -2598,7 +2668,9 @@ void _destroy_array(_array_t* arr) { mb_assert(arr); _clear_array(arr); - safe_free(arr->name); + if(arr->name) { + safe_free(arr->name); + } #ifndef MB_SIMPLE_ARRAY if(arr->types) { safe_free(arr->types); @@ -2607,6 +2679,22 @@ void _destroy_array(_array_t* arr) { safe_free(arr); } +bool_t _is_array(void* obj) { + /* Determine whether an object is an array value or an array variable */ + bool_t result = false; + _object_t* o = 0; + + mb_assert(obj); + + o = (_object_t*)obj; + if(o->type == _DT_ARRAY) + result = true; + else if(o->type == _DT_VAR) + result = o->data.variable->data->type == _DT_ARRAY; + + return result; +} + bool_t _is_string(void* obj) { /* Determine whether an object is a string value or a string variable */ bool_t result = false; @@ -2799,6 +2887,38 @@ int _compare_numbers(const _object_t* first, const _object_t* second) { return result; } +_data_e _public_type_to_internal_type(mb_data_e t) { + /* Convert a public mb_data_e type to an internal _data_e */ + switch(t) { + case MB_DT_INT: + return _DT_INT; + case MB_DT_REAL: + return _DT_REAL; + case MB_DT_STRING: + return _DT_STRING; + case MB_DT_USERTYPE: + return _DT_USERTYPE; + default: + return _DT_NIL; + } +} + +mb_data_e _internal_type_to_public_type(_data_e t) { + /* Convert an internal mb_data_e type to a public _data_e */ + switch(t) { + case _DT_INT: + return MB_DT_INT; + case _DT_REAL: + return MB_DT_REAL; + case _DT_STRING: + return MB_DT_STRING; + case _DT_USERTYPE: + return MB_DT_USERTYPE; + default: + return MB_DT_NIL; + } +} + int _public_value_to_internal_object(mb_value_t* pbl, _object_t* itn) { /* Assign a public mb_value_t to an internal _object_t */ int result = MB_FUNC_OK; @@ -2825,6 +2945,11 @@ int _public_value_to_internal_object(mb_value_t* pbl, _object_t* itn) { itn->type = _DT_USERTYPE; itn->data.usertype = pbl->value.usertype; + break; + case MB_DT_ARRAY: + itn->type = _DT_ARRAY; + itn->data.array = pbl->value.array; + break; default: result = MB_FUNC_ERR; @@ -2861,6 +2986,11 @@ int _internal_object_to_public_value(_object_t* itn, mb_value_t* pbl) { pbl->type = MB_DT_USERTYPE; pbl->value.usertype = itn->data.usertype; + break; + case _DT_ARRAY: + pbl->type = MB_DT_ARRAY; + pbl->value.array = itn->data.array; + break; default: result = MB_FUNC_ERR; @@ -3798,6 +3928,134 @@ int mb_push_value(struct mb_interpreter_t* s, void** l, mb_value_t val) { return result; } +int mb_init_array(struct mb_interpreter_t* s, void** l, mb_data_e t, int* d, int c, void** a) { + /* Create an array */ + int result = MB_FUNC_OK; + _array_t* arr = 0; + _data_e type = _DT_NIL; + int j = 0; + int n = 0; + + mb_assert(s && l && d && a); + + *a = 0; +#ifdef MB_SIMPLE_ARRAY + if(t == MB_DT_REAL) { + type = _DT_REAL; + } else if(t == MB_DT_STRING) { + type = _DT_STRING; + } else { + result = MB_NEED_COMPLEX_ARRAY; + + goto _exit; + } +#else /* MB_SIMPLE_ARRAY */ + type = _DT_REAL; +#endif /* MB_SIMPLE_ARRAY */ + + arr = (_array_t*)mb_malloc(sizeof(_array_t)); + memset(arr, 0, sizeof(_array_t)); + arr->type = type; + arr->name = 0; + for(j = 0; j < c; j++) { + n = d[j]; + arr->dimensions[arr->dimension_count++] = n; + if(arr->count) + arr->count *= n; + else + arr->count += n; + } + _init_array(arr); + if(!arr->raw) { + arr->dimension_count = 0; + arr->dimensions[0] = 0; + arr->count = 0; + } + *a = arr; + +_exit: + return result; +} + +int mb_get_array_len(struct mb_interpreter_t* s, void** l, void* a, int r, int* i) { + /* Get the length of an array */ + int result = MB_FUNC_OK; + _array_t* arr = 0; + + mb_assert(s && l); + arr = (_array_t*)a; + if(r < 0 || r >= arr->dimension_count) { + result = MB_RANK_OUT_OF_BOUNDS; + + goto _exit; + } + if(i) + *i = arr->dimensions[r]; + +_exit: + return result; +} + +int mb_get_array_elem(struct mb_interpreter_t* s, void** l, void* a, int* d, int c, mb_value_t* val) { + /* Get an element of an array with a given index */ + int result = MB_FUNC_OK; + _array_t* arr = 0; + int index = 0; + _data_e type = _DT_NIL; + + mb_assert(s && l); + arr = (_array_t*)a; + if(c < 0 || c > arr->dimension_count) { + result = MB_RANK_OUT_OF_BOUNDS; + + goto _exit; + } + if(!val) + goto _exit; + + index = _get_array_pos(s, arr, d, c); + if(index < 0) { + result = MB_INDEX_OUT_OF_BOUNDS; + + goto _exit; + } + + _get_array_elem(s, arr, index, &val->value, &type); + val->type = _internal_type_to_public_type(type); + +_exit: + return result; +} + +int mb_set_array_elem(struct mb_interpreter_t* s, void** l, void* a, int* d, int c, mb_value_t val) { + /* Set an element of an array with a given index */ + int result = MB_FUNC_OK; + _array_t* arr = 0; + int index = 0; + _data_e type = _DT_NIL; + + mb_assert(s && l); + arr = (_array_t*)a; + if(c < 0 || c > arr->dimension_count) { + result = MB_RANK_OUT_OF_BOUNDS; + + goto _exit; + } + + index = _get_array_pos(s, arr, d, c); + if(index < 0) { + result = MB_INDEX_OUT_OF_BOUNDS; + + goto _exit; + } + + type = _public_type_to_internal_type(val.type); + _set_array_elem(s, 0, arr, (unsigned int)index, &val.value, &type); + +_exit: + return result; +} + int mb_dispose_value(struct mb_interpreter_t* s, mb_value_t val) { /* Dispose a value */ int result = MB_FUNC_OK; diff --git a/core/my_basic.h b/core/my_basic.h index 89bdb7a..8cb505e 100755 --- a/core/my_basic.h +++ b/core/my_basic.h @@ -142,6 +142,9 @@ extern "C" { # define MB_LOOP_BREAK 5001 # define MB_LOOP_CONTINUE 5002 # define MB_SUB_RETURN 5101 +# define MB_NEED_COMPLEX_ARRAY 6001 +# define MB_RANK_OUT_OF_BOUNDS 6002 +# define MB_INDEX_OUT_OF_BOUNDS 6003 # define MB_DEBUG_ID_NOT_FOUND 7001 # define MB_EXTENDED_ABORT 9001 #endif /* MB_CODES */ @@ -219,11 +222,12 @@ typedef enum mb_error_e { } mb_error_e; typedef enum mb_data_e { - MB_DT_NIL = -1, - MB_DT_INT = 0, - MB_DT_REAL, - MB_DT_STRING, - MB_DT_USERTYPE + MB_DT_NIL = 0, + MB_DT_INT = 1 << 1, + MB_DT_REAL = 1 << 2, + MB_DT_STRING = 1 << 3, + MB_DT_USERTYPE = 1 << 4, + MB_DT_ARRAY = 1 << 12 } mb_data_e; typedef union mb_value_u { @@ -231,6 +235,7 @@ typedef union mb_value_u { real_t float_point; char* string; void* usertype; + void* array; } mb_value_u; typedef struct mb_value_t { @@ -272,6 +277,10 @@ MBAPI int mb_push_real(struct mb_interpreter_t* s, void** l, real_t val); MBAPI int mb_push_string(struct mb_interpreter_t* s, void** l, char* val); MBAPI int mb_push_usertype(struct mb_interpreter_t* s, void** l, void* val); MBAPI int mb_push_value(struct mb_interpreter_t* s, void** l, mb_value_t val); +MBAPI int mb_init_array(struct mb_interpreter_t* s, void** l, mb_data_e t, int* d, int c, void** a); +MBAPI int mb_get_array_len(struct mb_interpreter_t* s, void** l, void* a, int r, int* i); +MBAPI int mb_get_array_elem(struct mb_interpreter_t* s, void** l, void* a, int* d, int c, mb_value_t* val); +MBAPI int mb_set_array_elem(struct mb_interpreter_t* s, void** l, void* a, int* d, int c, mb_value_t val); MBAPI int mb_dispose_value(struct mb_interpreter_t* s, mb_value_t val); MBAPI int mb_load_string(struct mb_interpreter_t* s, const char* l); diff --git a/output/my_basic.exe b/output/my_basic.exe index 120e022..3c46727 100755 Binary files a/output/my_basic.exe and b/output/my_basic.exe differ diff --git a/output/my_basic_mac b/output/my_basic_mac index 8eee60b..a32db8f 100755 Binary files a/output/my_basic_mac and b/output/my_basic_mac differ diff --git a/resource/my_basic.rc b/resource/my_basic.rc index 2cda7fb..d28918b 100755 --- a/resource/my_basic.rc +++ b/resource/my_basic.rc @@ -36,8 +36,8 @@ IDI_ICON_MAIN ICON "icon.ico" VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,1,56,0 - PRODUCTVERSION 1,1,56,0 + FILEVERSION 1,1,57,0 + PRODUCTVERSION 1,1,57,0 FILEFLAGSMASK 0x17L # ifdef _DEBUG FILEFLAGS 0x1L @@ -55,13 +55,13 @@ VALUE "Comments", "MY-BASIC" VALUE "CompanyName", "W. Renxin" VALUE "FileDescription", "MY-BASIC interpreter" - VALUE "FileVersion", "1, 1, 56, 0" + VALUE "FileVersion", "1, 1, 57, 0" VALUE "InternalName", "my_basic" VALUE "LegalCopyright", "Copyright (C) 2011 - 2015 W. Renxin" VALUE "LegalTrademarks", "MY-BASIC" VALUE "OriginalFilename", "my_basic.exe" VALUE "ProductName", "MY-BASIC" - VALUE "ProductVersion", "1, 1, 56, 0" + VALUE "ProductVersion", "1, 1, 57, 0" END END BLOCK "VarFileInfo"