fixed a calculation crash bug. fixed a memory leak with intermediate value.
This commit is contained in:
parent
3242da03d5
commit
090fd0b900
4
HISTORY
Normal file → Executable file
4
HISTORY
Normal file → Executable file
@ -1,3 +1,7 @@
|
||||
Dec. 17 2014
|
||||
Fixed a calculation crash bug
|
||||
Fixed a memory leak with intermediate value
|
||||
|
||||
Dec. 16 2014
|
||||
Fixed a negative calculation bug in a function argument
|
||||
|
||||
|
171
core/my_basic.c
Normal file → Executable file
171
core/my_basic.c
Normal file → Executable file
@ -78,7 +78,7 @@ extern "C" {
|
||||
/** Macros */
|
||||
#define _VER_MAJOR 1
|
||||
#define _VER_MINOR 0
|
||||
#define _VER_REVISION 44
|
||||
#define _VER_REVISION 45
|
||||
#define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION))
|
||||
|
||||
/* Uncomment this line to treat warnings as error */
|
||||
@ -215,6 +215,7 @@ static const char* _ERR_DESC[] = {
|
||||
"Jump label expected",
|
||||
"Variable expected",
|
||||
"Invalid identifier usage",
|
||||
"Operator expected",
|
||||
"Calculation error",
|
||||
"Divide by zero",
|
||||
"MOD by zero",
|
||||
@ -370,13 +371,11 @@ static _object_t* _exp_assign = 0;
|
||||
_object_t* opnd1 = (_object_t*)(tpptr->e1); \
|
||||
_object_t* opnd2 = (_object_t*)(tpptr->e2); \
|
||||
_object_t* val = (_object_t*)(tpptr->e3); \
|
||||
opndv1.type = \
|
||||
(opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv1.type = (opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv1.data = opnd1->type == _DT_VAR ? opnd1->data.variable->data->data : opnd1->data; \
|
||||
opndv2.type = \
|
||||
(opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv2.type = (opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv2.data = opnd2->type == _DT_VAR ? opnd2->data.variable->data->data : opnd2->data; \
|
||||
if(opndv1.type == _DT_INT && opndv2.type == _DT_INT) { \
|
||||
val->type = _DT_REAL; \
|
||||
@ -400,13 +399,11 @@ static _object_t* _exp_assign = 0;
|
||||
_object_t* opnd1 = (_object_t*)(tpptr->e1); \
|
||||
_object_t* opnd2 = (_object_t*)(tpptr->e2); \
|
||||
_object_t* val = (_object_t*)(tpptr->e3); \
|
||||
opndv1.type = \
|
||||
(opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv1.type = (opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv1.data = opnd1->type == _DT_VAR ? opnd1->data.variable->data->data : opnd1->data; \
|
||||
opndv2.type = \
|
||||
(opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv2.type = (opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv2.data = opnd2->type == _DT_VAR ? opnd2->data.variable->data->data : opnd2->data; \
|
||||
if(opndv1.type == _DT_INT && opndv2.type == _DT_INT) { \
|
||||
if((real_t)(opndv1.data.integer __optr opndv2.data.integer) == (real_t)opndv1.data.integer __optr (real_t)opndv2.data.integer) { \
|
||||
@ -435,13 +432,11 @@ static _object_t* _exp_assign = 0;
|
||||
_object_t* opnd1 = (_object_t*)(tpptr->e1); \
|
||||
_object_t* opnd2 = (_object_t*)(tpptr->e2); \
|
||||
_object_t* val = (_object_t*)(tpptr->e3); \
|
||||
opndv1.type = \
|
||||
(opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv1.type = (opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv1.data = opnd1->type == _DT_VAR ? opnd1->data.variable->data->data : opnd1->data; \
|
||||
opndv2.type = \
|
||||
(opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv2.type = (opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv2.data = opnd2->type == _DT_VAR ? opnd2->data.variable->data->data : opnd2->data; \
|
||||
if(opndv1.type == _DT_INT && opndv2.type == _DT_INT) { \
|
||||
val->type = _DT_INT; \
|
||||
@ -494,13 +489,11 @@ static _object_t* _exp_assign = 0;
|
||||
_object_t* opnd1 = (_object_t*)(tpptr->e1); \
|
||||
_object_t* opnd2 = (_object_t*)(tpptr->e2); \
|
||||
_object_t* val = (_object_t*)(tpptr->e3); \
|
||||
opndv1.type = \
|
||||
(opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv1.type = (opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv1.data = opnd1->type == _DT_VAR ? opnd1->data.variable->data->data : opnd1->data; \
|
||||
opndv2.type = \
|
||||
(opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv2.type = (opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \
|
||||
_DT_INT : _DT_REAL; \
|
||||
opndv2.data = opnd2->type == _DT_VAR ? opnd2->data.variable->data->data : opnd2->data; \
|
||||
if((opndv2.type == _DT_INT && opndv2.data.integer == 0) || (opndv2.type == _DT_REAL && opndv2.data.float_point == 0.0f)) { \
|
||||
if((opndv1.type == _DT_INT && opndv1.data.integer == 0) || (opndv1.type == _DT_REAL && opndv1.data.float_point == 0.0f)) { \
|
||||
@ -670,6 +663,7 @@ static char* _extract_string(_object_t* obj);
|
||||
static bool_t _is_internal_object(_object_t* obj);
|
||||
static int _dispose_object(_object_t* obj);
|
||||
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 int _public_value_to_internal_object(mb_value_t* pbl, _object_t* itn);
|
||||
@ -691,6 +685,15 @@ static int _close_std_lib(mb_interpreter_t* s);
|
||||
|
||||
/* ========================================================} */
|
||||
|
||||
/*
|
||||
** {========================================================
|
||||
** Protected function declarations
|
||||
*/
|
||||
|
||||
MBAPI int mb_dispose_value(mb_interpreter_t* s, mb_value_t val);
|
||||
|
||||
/* ========================================================} */
|
||||
|
||||
/*
|
||||
** {========================================================
|
||||
** Lib declarations
|
||||
@ -746,10 +749,10 @@ static int _core_exit(mb_interpreter_t* s, void** l);
|
||||
static int _core_goto(mb_interpreter_t* s, void** l);
|
||||
static int _core_gosub(mb_interpreter_t* s, void** l);
|
||||
static int _core_return(mb_interpreter_t* s, void** l);
|
||||
static int _core_end(mb_interpreter_t* s, void** l);
|
||||
#ifdef _MB_ENABLE_ALLOC_STAT
|
||||
static int _core_mem(mb_interpreter_t* s, void** l);
|
||||
#endif /* _MB_ENABLE_ALLOC_STAT */
|
||||
static int _core_end(mb_interpreter_t* s, void** l);
|
||||
|
||||
/** Std lib */
|
||||
static int _std_abs(mb_interpreter_t* s, void** l);
|
||||
@ -1231,20 +1234,14 @@ unsigned int _ht_hash_int(void* ht, void* d) {
|
||||
|
||||
unsigned int _ht_hash_real(void* ht, void* d) {
|
||||
real_t r = *(real_t*)d;
|
||||
union {
|
||||
real_t r;
|
||||
int_t i;
|
||||
} u;
|
||||
union { real_t r; int_t i; } u;
|
||||
u.r = r;
|
||||
|
||||
return _ht_hash_int(ht, &u.i);
|
||||
}
|
||||
|
||||
unsigned int _ht_hash_ptr(void* ht, void* d) {
|
||||
union {
|
||||
int_t i;
|
||||
void* p;
|
||||
} u;
|
||||
union { int_t i; void* p; } u;
|
||||
u.p = d;
|
||||
|
||||
return _ht_hash_int(ht, &u.i);
|
||||
@ -1705,8 +1702,7 @@ bool_t _is_expression_terminal(mb_interpreter_t* s, _object_t* obj) {
|
||||
(obj->data.func->pointer == _core_then ||
|
||||
obj->data.func->pointer == _core_else ||
|
||||
obj->data.func->pointer == _core_to ||
|
||||
obj->data.func->pointer == _core_step)
|
||||
);
|
||||
obj->data.func->pointer == _core_step));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1727,6 +1723,7 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
|
||||
_object_t* theta = 0;
|
||||
char pri = '\0';
|
||||
int* inep = 0;
|
||||
int f = 0;
|
||||
|
||||
unsigned int arr_idx = 0;
|
||||
mb_value_u arr_val;
|
||||
@ -1772,10 +1769,8 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
|
||||
ast = ast->next;
|
||||
_ls_pushback(optr, _exp_assign);
|
||||
while(
|
||||
!(c->type == _DT_FUNC &&
|
||||
strcmp(c->data.func->name, "#") == 0) ||
|
||||
!(((_object_t*)(_ls_back(optr)->data))->type == _DT_FUNC &&
|
||||
strcmp(((_object_t*)(_ls_back(optr)->data))->data.func->name, "#") == 0)) {
|
||||
!(c->type == _DT_FUNC && strcmp(c->data.func->name, "#") == 0) ||
|
||||
!(((_object_t*)(_ls_back(optr)->data))->type == _DT_FUNC && strcmp(((_object_t*)(_ls_back(optr)->data))->data.func->name, "#") == 0)) {
|
||||
if(!hack) {
|
||||
if(c->type == _DT_FUNC && c->data.func->pointer == _core_open_bracket) {
|
||||
++bracket_count;
|
||||
@ -1807,6 +1802,7 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
|
||||
while(bracket_count) {
|
||||
_ls_pushback(optr, &_cb);
|
||||
bracket_count--;
|
||||
f = 0;
|
||||
}
|
||||
errn = ast;
|
||||
}
|
||||
@ -1830,7 +1826,11 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
|
||||
} 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_FUNC) {
|
||||
ast = ast->prev;
|
||||
result = (c->data.func->pointer)(s, (void**)(&ast));
|
||||
@ -1844,7 +1844,11 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
|
||||
if(result != MB_FUNC_OK) {
|
||||
goto _exit;
|
||||
}
|
||||
if(f) {
|
||||
_handle_error_on_obj(s, SE_RN_OPERATOR_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
|
||||
}
|
||||
_ls_pushback(opnd, c);
|
||||
f++;
|
||||
} else {
|
||||
if(c->type == _DT_VAR && ast) {
|
||||
_object_t* _err_var = (_object_t*)(ast->data);
|
||||
@ -1852,7 +1856,11 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
|
||||
_handle_error_on_obj(s, SE_RN_INVALID_ID_USAGE, DON(ast), MB_FUNC_ERR, _exit, result);
|
||||
}
|
||||
}
|
||||
if(f) {
|
||||
_handle_error_on_obj(s, SE_RN_OPERATOR_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
|
||||
}
|
||||
_ls_pushback(opnd, c);
|
||||
f++;
|
||||
}
|
||||
if(ast) {
|
||||
c = (_object_t*)(ast->data);
|
||||
@ -1873,6 +1881,7 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
|
||||
_ls_pushback(optr, c);
|
||||
c = (_object_t*)(ast->data);
|
||||
ast = ast->next;
|
||||
f = 0;
|
||||
|
||||
break;
|
||||
case '=':
|
||||
@ -1936,8 +1945,8 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
|
||||
_exit:
|
||||
_ls_foreach(garbage, _destroy_object);
|
||||
_ls_destroy(garbage);
|
||||
_ls_foreach(optr, _destroy_object);
|
||||
_ls_foreach(opnd, _destroy_object);
|
||||
_ls_foreach(optr, _destroy_object_non_syntax);
|
||||
_ls_foreach(opnd, _destroy_object_non_syntax);
|
||||
_ls_destroy(optr);
|
||||
_ls_destroy(opnd);
|
||||
*l = ast;
|
||||
@ -1955,9 +1964,7 @@ bool_t _is_print_terminal(mb_interpreter_t* s, _object_t* obj) {
|
||||
result =
|
||||
(obj->type == _DT_EOS) ||
|
||||
(obj->type == _DT_SEP && obj->data.separator == ':') ||
|
||||
(obj->type == _DT_FUNC &&
|
||||
(obj->data.func->pointer == _core_else)
|
||||
);
|
||||
(obj->type == _DT_FUNC && (obj->data.func->pointer == _core_else));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -2852,6 +2859,28 @@ _exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
int _destroy_object_non_syntax(void* data, void* extra) {
|
||||
/* Destroy a non syntax object */
|
||||
int result = _OP_RESULT_NORMAL;
|
||||
_object_t* obj = 0;
|
||||
mb_unrefvar(extra);
|
||||
|
||||
mb_assert(data);
|
||||
|
||||
obj = (_object_t*)data;
|
||||
if(!obj->source_pos) {
|
||||
if(!_dispose_object(obj)) {
|
||||
goto _exit;
|
||||
}
|
||||
safe_free(obj);
|
||||
}
|
||||
|
||||
_exit:
|
||||
result = _OP_RESULT_DEL_NODE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int _remove_source_object(void* data, void* extra) {
|
||||
/* Remove an object referenced from source code */
|
||||
int result = _OP_RESULT_DEL_NODE;
|
||||
@ -3000,14 +3029,7 @@ int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) {
|
||||
ast = ast->next;
|
||||
} else if(obj && obj->type == _DT_VAR) {
|
||||
_handle_error_on_obj(s, SE_RN_COLON_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
|
||||
} else if(
|
||||
(obj && obj->type != _DT_FUNC) || (
|
||||
obj && obj->type == _DT_FUNC && (
|
||||
_is_operator(obj->data.func->pointer) ||
|
||||
_is_flow(obj->data.func->pointer)
|
||||
)
|
||||
)
|
||||
) {
|
||||
} else if((obj && obj->type != _DT_FUNC) || (obj && obj->type == _DT_FUNC && (_is_operator(obj->data.func->pointer) || _is_flow(obj->data.func->pointer)))) {
|
||||
ast = ast->next;
|
||||
} else {
|
||||
_handle_error_on_obj(s, SE_RN_COLON_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
|
||||
@ -3228,6 +3250,26 @@ int _close_std_lib(mb_interpreter_t* s) {
|
||||
|
||||
/* ========================================================} */
|
||||
|
||||
/*
|
||||
** {========================================================
|
||||
** Protected function definitions
|
||||
*/
|
||||
|
||||
int mb_dispose_value(mb_interpreter_t* s, mb_value_t val) {
|
||||
/* Dispose a value */
|
||||
int result = MB_FUNC_OK;
|
||||
|
||||
mb_assert(s);
|
||||
|
||||
if(val.type == MB_DT_STRING) {
|
||||
mb_free(val.value.string);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ========================================================} */
|
||||
|
||||
/*
|
||||
** {========================================================
|
||||
** Public functions definitions
|
||||
@ -3390,6 +3432,7 @@ int mb_close(mb_interpreter_t** s) {
|
||||
|
||||
running = (_running_context_t*)((*s)->running_context);
|
||||
|
||||
mb_dispose_value(*s, running->intermediate_value);
|
||||
_ls_foreach(running->temp_values, _destroy_object);
|
||||
_ls_destroy(running->temp_values);
|
||||
_ls_destroy(running->in_neg_expr);
|
||||
@ -5058,17 +5101,6 @@ _exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
int _core_end(mb_interpreter_t* s, void** l) {
|
||||
/* END statement */
|
||||
int result = MB_FUNC_OK;
|
||||
|
||||
mb_assert(s && l);
|
||||
|
||||
result = MB_FUNC_END;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef _MB_ENABLE_ALLOC_STAT
|
||||
int _core_mem(mb_interpreter_t* s, void** l) {
|
||||
/* MEM statement */
|
||||
@ -5085,6 +5117,17 @@ int _core_mem(mb_interpreter_t* s, void** l) {
|
||||
}
|
||||
#endif /* _MB_ENABLE_ALLOC_STAT */
|
||||
|
||||
int _core_end(mb_interpreter_t* s, void** l) {
|
||||
/* END statement */
|
||||
int result = MB_FUNC_OK;
|
||||
|
||||
mb_assert(s && l);
|
||||
|
||||
result = MB_FUNC_END;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Std lib */
|
||||
int _std_abs(mb_interpreter_t* s, void** l) {
|
||||
/* Get the absolute value of a number */
|
||||
|
1
core/my_basic.h
Normal file → Executable file
1
core/my_basic.h
Normal file → Executable file
@ -161,6 +161,7 @@ typedef enum mb_error_e {
|
||||
SE_RN_JUMP_LABEL_EXPECTED,
|
||||
SE_RN_VARIABLE_EXPECTED,
|
||||
SE_RN_INVALID_ID_USAGE,
|
||||
SE_RN_OPERATOR_EXPECTED,
|
||||
SE_RN_CALCULATION_ERROR,
|
||||
SE_RN_DIVIDE_BY_ZERO,
|
||||
SE_RN_MOD_BY_ZERO,
|
||||
|
BIN
output/my_basic.exe
Normal file → Executable file
BIN
output/my_basic.exe
Normal file → Executable file
Binary file not shown.
8
resource/my_basic.rc
Normal file → Executable file
8
resource/my_basic.rc
Normal file → Executable file
@ -62,8 +62,8 @@ IDI_ICON_MAIN ICON "icon.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,44
|
||||
PRODUCTVERSION 1,0,0,44
|
||||
FILEVERSION 1,0,0,45
|
||||
PRODUCTVERSION 1,0,0,45
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -81,13 +81,13 @@ BEGIN
|
||||
VALUE "Comments", "MY-BASIC"
|
||||
VALUE "CompanyName", "W. Renxin"
|
||||
VALUE "FileDescription", "MY-BASIC interpreter"
|
||||
VALUE "FileVersion", "1, 0, 0, 44"
|
||||
VALUE "FileVersion", "1, 0, 0, 45"
|
||||
VALUE "InternalName", "my_basic"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2011 - 2014 W. Renxin"
|
||||
VALUE "LegalTrademarks", "MY-BASIC"
|
||||
VALUE "OriginalFilename", "my_basic.exe"
|
||||
VALUE "ProductName", "MY-BASIC"
|
||||
VALUE "ProductVersion", "1, 0, 0, 44"
|
||||
VALUE "ProductVersion", "1, 0, 0, 45"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
0
shell/main.c
Normal file → Executable file
0
shell/main.c
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user