diff --git a/HISTORY b/HISTORY old mode 100755 new mode 100644 index 8cf384f..9a859d6 --- a/HISTORY +++ b/HISTORY @@ -1,3 +1,7 @@ +Apr. 23 2015 Version 1.1 +Added debug APIs +Added (nestable) multi line IF statement support + Apr. 15 2015 Added mb_pop_usertype, mb_push_usertype to support user defined type Polished code @@ -169,5 +173,5 @@ Fixed a suspend / resume bug Feb. 9 2011 Fixed struct mb_interpreter_t declaration warnings on gcc -Feb. 1 2011 +Feb. 1 2011 Version 1.0 First release. diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/MY-BASIC Quick Reference.pdf b/MY-BASIC Quick Reference.pdf old mode 100755 new mode 100644 index e99c1a7..fcaa239 Binary files a/MY-BASIC Quick Reference.pdf and b/MY-BASIC Quick Reference.pdf differ diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 3386fac..fe9f804 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ For more details about using MY-BASIC with exist projects, please see [MY-BASIC * [Redirect PRINT and INPUT](https://github.com/paladin-t/my_basic/wiki/Redirect-PRINT-and-INPUT) * [Use usertype values](https://github.com/paladin-t/my_basic/wiki/Use-usertype-values) * [Customizable macros](https://github.com/paladin-t/my_basic/wiki/Customizable-macros) +* [Write a debugger](https://github.com/paladin-t/my_basic/wiki/Write-a-debugger) * [More scripting API](https://github.com/paladin-t/my_basic/wiki/More-scripting-API) * [File module](https://github.com/paladin-t/my_basic/wiki/File-module) * [FAQ](https://github.com/paladin-t/my_basic/wiki/FAQ) diff --git a/core/my_basic.c b/core/my_basic.c old mode 100755 new mode 100644 index b1e7fe9..baf07cc --- a/core/my_basic.c +++ b/core/my_basic.c @@ -51,7 +51,6 @@ extern "C" { #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4127) -# pragma warning(disable : 4996) #endif /* _MSC_VER */ #ifdef __APPLE__ @@ -77,8 +76,8 @@ extern "C" { /** Macros */ #define _VER_MAJOR 1 -#define _VER_MINOR 0 -#define _VER_REVISION 50 +#define _VER_MINOR 1 +#define _VER_REVISION 51 #define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION)) /* Uncomment this line to treat warnings as error */ @@ -108,6 +107,10 @@ extern "C" { #define DON(__o) ((__o) ? ((_object_t*)((__o)->data)) : 0) +#define _IS_EOS(__o) (__o && ((_object_t*)(__o))->type == _DT_EOS) +#define _IS_SEP(__o, __c) (((_object_t*)(__o))->type == _DT_SEP && ((_object_t*)(__o))->data.separator == __c) +#define _IS_FUNC(__o, __f) (((_object_t*)(__o))->type == _DT_FUNC && ((_object_t*)(__o))->data.func->pointer == __f) + /* Hash table size */ #define _HT_ARRAY_SIZE_SMALL 193 #define _HT_ARRAY_SIZE_MID 1543 @@ -342,6 +345,7 @@ typedef struct mb_interpreter_t { int last_error_pos; unsigned short last_error_row; unsigned short last_error_col; + mb_debug_stepped_handler_t debug_stepped_handler; mb_error_handler_t error_handler; mb_print_func_t printer; mb_input_func_t inputer; @@ -696,8 +700,10 @@ 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); +static void _stepped(mb_interpreter_t* s, _ls_node_t* ast); static int _execute_statement(mb_interpreter_t* s, _ls_node_t** l); static int _skip_to(mb_interpreter_t* s, _ls_node_t** l, mb_func_t f, _data_e t); +static int _skip_if_chunk(mb_interpreter_t* s, _ls_node_t** l); static int _skip_struct(mb_interpreter_t* s, _ls_node_t** l, mb_func_t open_func, mb_func_t close_func); static int _register_func(mb_interpreter_t* s, const char* n, mb_func_t f, bool_t local); @@ -765,7 +771,9 @@ static int _core_let(mb_interpreter_t* s, void** l); static int _core_dim(mb_interpreter_t* s, void** l); static int _core_if(mb_interpreter_t* s, void** l); static int _core_then(mb_interpreter_t* s, void** l); +static int _core_elseif(mb_interpreter_t* s, void** l); static int _core_else(mb_interpreter_t* s, void** l); +static int _core_endif(mb_interpreter_t* s, void** l); static int _core_for(mb_interpreter_t* s, void** l); static int _core_to(mb_interpreter_t* s, void** l); static int _core_step(mb_interpreter_t* s, void** l); @@ -840,7 +848,9 @@ static const _func_t _core_libs[] = { { "IF", _core_if }, { "THEN", _core_then }, + { "ELSEIF", _core_elseif }, { "ELSE", _core_else }, + { "ENDIF", _core_endif }, { "FOR", _core_for }, { "TO", _core_to }, @@ -1351,7 +1361,9 @@ bool_t _is_flow(mb_func_t op) { result = (op == _core_if) || (op == _core_then) || + (op == _core_elseif) || (op == _core_else) || + (op == _core_endif) || (op == _core_for) || (op == _core_to) || (op == _core_step) || @@ -1488,7 +1500,9 @@ bool_t _is_expression_terminal(mb_interpreter_t* s, _object_t* obj) { (obj->type == _DT_SEP) || (obj->type == _DT_FUNC && (obj->data.func->pointer == _core_then || + obj->data.func->pointer == _core_elseif || obj->data.func->pointer == _core_else || + obj->data.func->pointer == _core_endif || obj->data.func->pointer == _core_to || obj->data.func->pointer == _core_step)); @@ -1540,7 +1554,7 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { if(c->type == _DT_STRING) { if(ast->next) { _object_t* _fsn = (_object_t*)ast->next->data; - if(_fsn->type == _DT_FUNC && _fsn->data.func->pointer == _core_add) + if(_IS_FUNC(_fsn, _core_add)) break; } @@ -1559,9 +1573,9 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { !(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) { + if(_IS_FUNC(c, _core_open_bracket)) { ++bracket_count; - } else if(c->type == _DT_FUNC && c->data.func->pointer == _core_close_bracket) { + } else if(_IS_FUNC(c, _core_close_bracket)) { --bracket_count; if(bracket_count < 0) { c = _exp_assign; @@ -1642,7 +1656,7 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { } else { if(c->type == _DT_VAR && ast) { _object_t* _err_var = (_object_t*)(ast->data); - if(_err_var->type == _DT_FUNC && _err_var->data.func->pointer == _core_open_bracket) { + if(_IS_FUNC(_err_var, _core_open_bracket)) { _handle_error_on_obj(s, SE_RN_INVALID_ID_USAGE, DON(ast), MB_FUNC_ERR, _exit, result); } } @@ -1691,7 +1705,7 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { } _ls_pushback(opnd, r); _ls_pushback(garbage, r); - if(c->type == _DT_FUNC && c->data.func->pointer == _core_close_bracket) + if(_IS_FUNC(c, _core_close_bracket)) hack = true; break; @@ -1751,10 +1765,11 @@ bool_t _is_print_terminal(mb_interpreter_t* s, _object_t* obj) { mb_assert(s && obj); - result = - (obj->type == _DT_EOS) || - (obj->type == _DT_SEP && obj->data.separator == ':') || - (obj->type == _DT_FUNC && (obj->data.func->pointer == _core_else)); + result = _IS_EOS(obj) || + _IS_SEP(obj, ':') || + _IS_FUNC(obj, _core_elseif) || + _IS_FUNC(obj, _core_else) || + _IS_FUNC(obj, _core_endif); return result; } @@ -1903,6 +1918,8 @@ int _append_symbol(mb_interpreter_t* s, char* sym, bool_t* delsym, int pos, unsi obj->source_row = row; obj->source_col = col; #else /* MB_ENABLE_SOURCE_TRACE */ + mb_unrefvar(row); + mb_unrefvar(col); obj->source_pos = (char)pos; #endif /* MB_ENABLE_SOURCE_TRACE */ @@ -2181,7 +2198,7 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, _raw_t* value) { } /* _label_t */ if(context->current_char == ':') { - if(!context->last_symbol || context->last_symbol->type == _DT_EOS) { + if(!context->last_symbol || _IS_EOS(context->last_symbol)) { glbsyminscope = _ht_find(s->global_var_dict, sym); if(glbsyminscope) { memcpy(*value, &glbsyminscope->data, sizeof(glbsyminscope->data)); @@ -2400,7 +2417,7 @@ int _get_array_index(mb_interpreter_t* s, _ls_node_t** l, unsigned int* index) { else idx += (unsigned int)val.integer; /* Comma? */ - if(((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ',') + if(_IS_SEP(ast->data, ',')) ast = ast->next; ++dcount; @@ -2848,6 +2865,26 @@ void _try_clear_intermediate_value(void* data, void* extra, mb_interpreter_t* s) running->intermediate_value.type = MB_DT_NIL; } +void _stepped(mb_interpreter_t* s, _ls_node_t* ast) { + /* Called each step */ + _object_t* obj = 0; + + mb_assert(s); + + if(s->debug_stepped_handler) { + if(ast && ast->data) { + obj = (_object_t*)ast->data; +#ifdef MB_ENABLE_SOURCE_TRACE + s->debug_stepped_handler(s, obj->source_pos, obj->source_row, obj->source_col); +#else /* MB_ENABLE_SOURCE_TRACE */ + s->debug_stepped_handler(s, obj->source_pos, 0, 0); +#endif /* MB_ENABLE_SOURCE_TRACE */ + } else { + s->debug_stepped_handler(s, -1, 0, 0); + } + } +} + int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) { /* Execute the ast, core execution function */ int result = MB_FUNC_OK; @@ -2886,9 +2923,9 @@ int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) { goto _exit; if(ast) { obj = (_object_t*)(ast->data); - if(obj && obj->type == _DT_EOS) { + if(_IS_EOS(obj)) { ast = ast->next; - } else if(obj && obj->type == _DT_SEP && obj->data.separator == ':') { + } else if(_IS_SEP(obj, ':')) { skip_to_eoi = false; ast = ast->next; } else if(obj && obj->type == _DT_VAR) { @@ -2912,6 +2949,8 @@ int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) { _exit: *l = ast; + _stepped(s, ast); + return result; } @@ -2940,6 +2979,31 @@ _exit: return result; } +int _skip_if_chunk(mb_interpreter_t* s, _ls_node_t** l) { + /* Skip current IF execution flow to next chunk */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _ls_node_t* tmp = 0; + _object_t* obj = 0; + + mb_assert(s && l); + + ast = *l; + mb_assert(ast && ast->prev); + do { + if(!ast) { + _handle_error_on_obj(s, SE_RN_SYNTAX, DON(tmp), MB_FUNC_ERR, _exit, result); + } + tmp = ast; + obj = (_object_t*)(ast->data); + *l = ast; + ast = ast->next; + } while(!_IS_FUNC(obj, _core_elseif) && !_IS_FUNC(obj, _core_if) && !_IS_FUNC(obj, _core_else)); + +_exit: + return result; +} + int _skip_struct(mb_interpreter_t* s, _ls_node_t** l, mb_func_t open_func, mb_func_t close_func) { /* Skip current structure */ int result = MB_FUNC_OK; @@ -2960,10 +3024,9 @@ int _skip_struct(mb_interpreter_t* s, _ls_node_t** l, mb_func_t open_func, mb_fu obj_prev = (_object_t*)(ast->data); ast = ast->next; obj = (_object_t*)(ast->data); - if(obj->type == _DT_FUNC && obj->data.func->pointer == open_func) { + if(_IS_FUNC(obj, open_func)) { ++count; - } else if(obj->type == _DT_FUNC && obj->data.func->pointer == close_func && - (obj_prev && obj_prev->type == _DT_EOS)) { + } else if(_IS_FUNC(obj, close_func) && _IS_EOS(obj_prev)) { --count; } } while(count); @@ -3437,7 +3500,7 @@ int mb_attempt_open_bracket(struct mb_interpreter_t* s, void** l) { ast = (_ls_node_t*)(*l); ast = ast->next; obj = (_object_t*)(ast->data); - if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_open_bracket)) { + if(!_IS_FUNC(obj, _core_open_bracket)) { _handle_error_on_obj(s, SE_RN_OPEN_BRACKET_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); } ast = ast->next; @@ -3461,7 +3524,7 @@ int mb_attempt_close_bracket(struct mb_interpreter_t* s, void** l) { _handle_error_on_obj(s, SE_RN_CLOSE_BRACKET_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); } obj = (_object_t*)(ast->data); - if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_close_bracket)) { + if(!_IS_FUNC(obj, _core_close_bracket)) { _handle_error_on_obj(s, SE_RN_CLOSE_BRACKET_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); } ast = ast->next; @@ -3483,7 +3546,7 @@ int mb_has_arg(struct mb_interpreter_t* s, void** l) { ast = (_ls_node_t*)(*l); if(ast) { obj = (_object_t*)(ast->data); - if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_close_bracket) && obj->type != _DT_EOS) + if(!_IS_FUNC(obj, _core_close_bracket) && obj->type != _DT_EOS) result = obj->data.integer; } @@ -3637,7 +3700,7 @@ int mb_pop_value(struct mb_interpreter_t* s, void** l, mb_value_t* val) { } if(running->no_eat_comma_mark < _NO_EAT_COMMA && (!inep || (inep && !(*inep)))) { - if(ast && ((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ',') + if(ast && _IS_SEP(ast->data, ',')) ast = ast->next; } @@ -3884,6 +3947,58 @@ int mb_suspend(struct mb_interpreter_t* s, void** l) { return result; } +int mb_debug_get(struct mb_interpreter_t* s, const char* n, mb_value_t* val) { + /* Get the value of an identifier */ + int result = MB_FUNC_OK; + _ls_node_t* v = 0; + _object_t* obj = 0; + + mb_assert(s && n && val); + + v = _ht_find(s->global_var_dict, (void*)n); + if(v) { + obj = (_object_t*)(v->data); + mb_assert(obj->type == _DT_VAR); + result = _internal_object_to_public_value(obj->data.variable->data, val); + } else { + val->type = MB_DT_NIL; + result = MB_DEBUG_ID_NOT_FOUND; + } + + return result; +} + +int mb_debug_set(struct mb_interpreter_t* s, const char* n, mb_value_t val) { + /* Set the value of an identifier */ + int result = MB_FUNC_OK; + _ls_node_t* v = 0; + _object_t* obj = 0; + + mb_assert(s && n); + + v = _ht_find(s->global_var_dict, (void*)n); + if(v) { + obj = (_object_t*)(v->data); + mb_assert(obj->type == _DT_VAR); + result = _public_value_to_internal_object(&val, obj->data.variable->data); + } else { + result = MB_DEBUG_ID_NOT_FOUND; + } + + return result; +} + +int mb_debug_set_stepped_handler(struct mb_interpreter_t* s, mb_debug_stepped_handler_t h) { + /* Set a stepped handler to an interpreter instance */ + int result = MB_FUNC_OK; + + mb_assert(s); + + s->debug_stepped_handler = h; + + return result; +} + mb_error_e mb_get_last_error(struct mb_interpreter_t* s) { /* Get last error information */ mb_error_e result = SE_NO_ERR; @@ -4501,7 +4616,7 @@ int _core_dim(mb_interpreter_t* s, void** l) { dummy.count += (unsigned int)val.integer; ast = ast->next; /* Comma? */ - if(((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ',') + if(_IS_SEP(ast->data, ',')) ast = ast->next; } /* Create or modify raw data */ @@ -4527,6 +4642,7 @@ int _core_if(mb_interpreter_t* s, void** l) { _ls_node_t* ast = 0; _object_t* val = 0; _object_t* obj = 0; + bool_t multi_line = false; _running_context_t* running = 0; mb_assert(s && l); @@ -4537,6 +4653,8 @@ int _core_if(mb_interpreter_t* s, void** l) { ast = ast->next; val = (_object_t*)mb_malloc(sizeof(_object_t)); + +_elseif: memset(val, 0, sizeof(_object_t)); result = _calc_expression(s, &ast, &val); if(result != MB_FUNC_OK) @@ -4545,10 +4663,13 @@ int _core_if(mb_interpreter_t* s, void** l) { obj = (_object_t*)(ast->data); if(val->data.integer) { - if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_then)) { + if(!_IS_FUNC(obj, _core_then)) { _handle_error_on_obj(s, SE_RN_INTEGER_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); } + if(ast && ast->next && _IS_EOS(ast->next->data)) + multi_line = true; + running->skip_to_eoi = _ls_back(running->sub_stack); do { ast = ast->next; @@ -4557,7 +4678,16 @@ int _core_if(mb_interpreter_t* s, void** l) { goto _exit; if(ast) ast = ast->prev; - } while(ast && ((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ':'); + } while(ast && ( + (!multi_line && _IS_SEP(ast->data, ':')) || ( + multi_line && ast->next && ( + !_IS_FUNC(ast->next->data, _core_elseif) && + !_IS_FUNC(ast->next->data, _core_else) && + !_IS_FUNC(ast->next->data, _core_endif) + ) + ) + ) + ); if(!ast) goto _exit; @@ -4570,28 +4700,48 @@ int _core_if(mb_interpreter_t* s, void** l) { goto _exit; } } else { + if(ast && ast->next && _IS_EOS(ast->next->data)) { + multi_line = true; + + _skip_if_chunk(s, &ast); + } + if(multi_line && ast && _IS_FUNC(ast->data, _core_elseif)) { + if(ast) ast = ast->next; + + goto _elseif; + } + result = _skip_to(s, &ast, _core_else, _DT_EOS); if(result != MB_FUNC_OK) goto _exit; obj = (_object_t*)(ast->data); if(obj->type != _DT_EOS) { - if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_else)) { + if(!_IS_FUNC(obj, _core_else)) { _handle_error_on_obj(s, SE_RN_ELSE_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); } do { ast = ast->next; + while(_IS_EOS(ast->data)) + ast = ast->next; result = _execute_statement(s, &ast); if(result != MB_FUNC_OK) goto _exit; if(ast) ast = ast->prev; - } while(ast && ((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ':'); + } while(ast && ( + (!multi_line && _IS_SEP(ast->data, ':')) || + (multi_line && !_IS_FUNC(ast->next->data, _core_endif)) + ) + ); } } _exit: + if(multi_line) + result = _skip_to(s, &ast, _core_endif, _DT_NIL); + _destroy_object(val, 0); *l = ast; @@ -4611,6 +4761,18 @@ int _core_then(mb_interpreter_t* s, void** l) { return result; } +int _core_elseif(mb_interpreter_t* s, void** l) { + /* ELSEIF statement */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + int _core_else(mb_interpreter_t* s, void** l) { /* ELSE statement */ int result = MB_FUNC_OK; @@ -4623,6 +4785,18 @@ int _core_else(mb_interpreter_t* s, void** l) { return result; } +int _core_endif(mb_interpreter_t* s, void** l) { + /* ENDIF statement */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + int _core_for(mb_interpreter_t* s, void** l) { /* FOR statement */ int result = MB_FUNC_OK; @@ -4660,7 +4834,7 @@ int _core_for(mb_interpreter_t* s, void** l) { ast = ast->prev; obj = (_object_t*)(ast->data); - if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_to)) { + if(!_IS_FUNC(obj, _core_to)) { _handle_error_on_obj(s, SE_RN_TO_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); } @@ -4678,7 +4852,7 @@ _to: goto _exit; obj = (_object_t*)(ast->data); - if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_step)) { + if(!_IS_FUNC(obj, _core_step)) { step_val = _OBJ_INT_UNIT; } else { ast = ast->next; @@ -4702,7 +4876,7 @@ _to: } else { /* Keep looping */ obj = (_object_t*)(ast->data); - while(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_next)) { + while(!_IS_FUNC(obj, _core_next)) { result = _execute_statement(s, &ast); if(result == MB_LOOP_CONTINUE) { /* NEXT */ if(!running->next_loop_var || running->next_loop_var == var_loop) { /* This loop */ @@ -4826,7 +5000,7 @@ _loop_begin: if(loop_cond_ptr->data.integer) { /* Keep looping */ obj = (_object_t*)(ast->data); - while(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_wend)) { + while(!_IS_FUNC(obj, _core_wend)) { result = _execute_statement(s, &ast); if(result == MB_LOOP_BREAK) { /* EXIT */ if(_skip_struct(s, &ast, _core_while, _core_wend) != MB_FUNC_OK) @@ -4885,7 +5059,7 @@ int _core_do(mb_interpreter_t* s, void** l) { ast = ast->next; obj = (_object_t*)(ast->data); - if(!(obj->type == _DT_EOS)) { + if(!_IS_EOS(obj->type)) { _handle_error_on_obj(s, SE_RN_SYNTAX, DON(ast), MB_FUNC_ERR, _exit, result); } ast = ast->next; @@ -4898,7 +5072,7 @@ _loop_begin: ast = loop_begin_node; obj = (_object_t*)(ast->data); - while(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_until)) { + while(!_IS_FUNC(obj, _core_until)) { result = _execute_statement(s, &ast); if(result == MB_LOOP_BREAK) { /* EXIT */ if(_skip_struct(s, &ast, _core_do, _core_until) != MB_FUNC_OK) @@ -4915,7 +5089,7 @@ _loop_begin: } obj = (_object_t*)(ast->data); - if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_until)) { + if(!_IS_FUNC(obj, _core_until)) { _handle_error_on_obj(s, SE_RN_UNTIL_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); } ast = ast->next; @@ -5885,13 +6059,13 @@ int _std_print(mb_interpreter_t* s, void** l) { obj = (_object_t*)(ast->data); if(_is_print_terminal(s, obj)) break; - if(obj->type == _DT_SEP && (obj->data.separator == ',' || obj->data.separator == ';')) { + if(_IS_SEP(obj, ',') || _IS_SEP(obj, ';')) { ast = ast->next; obj = (_object_t*)(ast->data); } else { _handle_error_on_obj(s, SE_RN_COMMA_OR_SEMICOLON_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); } - } while(ast && !(obj->type == _DT_SEP && obj->data.separator == ':') && (obj->type == _DT_SEP || !_is_expression_terminal(s, obj))); + } while(ast && !_IS_SEP(obj, ':') && (obj->type == _DT_SEP || !_is_expression_terminal(s, obj))); _exit: --running->no_eat_comma_mark; diff --git a/core/my_basic.h b/core/my_basic.h old mode 100755 new mode 100644 index 9a68c09..77bae60 --- a/core/my_basic.h +++ b/core/my_basic.h @@ -117,6 +117,7 @@ extern "C" { # define MB_LOOP_BREAK 5001 # define MB_LOOP_CONTINUE 5002 # define MB_SUB_RETURN 5101 +# define MB_DEBUG_ID_NOT_FOUND 7001 # define MB_EXTENDED_ABORT 9001 #endif /* MB_CODES */ @@ -212,8 +213,9 @@ typedef struct mb_value_t { mb_value_u value; } mb_value_t; -typedef void (* mb_error_handler_t)(struct mb_interpreter_t*, enum mb_error_e, char*, int, unsigned short, unsigned short, int); typedef int (* mb_func_t)(struct mb_interpreter_t*, void**); +typedef void (* mb_debug_stepped_handler_t)(struct mb_interpreter_t*, int, unsigned short, unsigned short); +typedef void (* mb_error_handler_t)(struct mb_interpreter_t*, enum mb_error_e, char*, int, unsigned short, unsigned short, int); typedef int (* mb_print_func_t)(const char*, ...); typedef int (* mb_input_func_t)(char*, int); @@ -251,6 +253,10 @@ MBAPI int mb_load_file(struct mb_interpreter_t* s, const char* f); MBAPI int mb_run(struct mb_interpreter_t* s); MBAPI int mb_suspend(struct mb_interpreter_t* s, void** l); +MBAPI int mb_debug_get(struct mb_interpreter_t* s, const char* n, mb_value_t* val); +MBAPI int mb_debug_set(struct mb_interpreter_t* s, const char* n, mb_value_t val); +MBAPI int mb_debug_set_stepped_handler(struct mb_interpreter_t* s, mb_debug_stepped_handler_t h); + MBAPI mb_error_e mb_get_last_error(struct mb_interpreter_t* s); MBAPI const char* mb_get_error_desc(mb_error_e err); MBAPI int mb_set_error_handler(struct mb_interpreter_t* s, mb_error_handler_t h); diff --git a/output/my_basic.exe b/output/my_basic.exe old mode 100755 new mode 100644 index dc5089b..bce7c67 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 10a3e6c..8b5fca4 100755 Binary files a/output/my_basic_mac and b/output/my_basic_mac differ diff --git a/resource/my_basic.aps b/resource/my_basic.aps old mode 100755 new mode 100644 index 7be1fb8..713f9c2 Binary files a/resource/my_basic.aps and b/resource/my_basic.aps differ diff --git a/resource/my_basic.rc b/resource/my_basic.rc old mode 100755 new mode 100644 index c69ddb1..4a6b859 --- a/resource/my_basic.rc +++ b/resource/my_basic.rc @@ -1,113 +1,77 @@ -// Microsoft Visual C++ generated resource script. -// #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// + #include "windows.h" -///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// 中文(中华人民共和国) resources - #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) -#ifdef _WIN32 -LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED -#pragma code_page(936) -#endif //_WIN32 +# ifdef _WIN32 + LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +# pragma code_page(936) +# endif //_WIN32 -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// +# ifdef APSTUDIO_INVOKED -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END + 1 TEXTINCLUDE + BEGIN + "resource.h\0" + END -2 TEXTINCLUDE -BEGIN - "#include ""windows.h""\r\n" - "\0" -END + 2 TEXTINCLUDE + BEGIN + "#include ""windows.h""\r\n" + "\0" + END -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END + 3 TEXTINCLUDE + BEGIN + "\r\n" + "\0" + END -#endif // APSTUDIO_INVOKED +# endif + IDI_ICON_MAIN ICON "icon.ico" -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// + VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,1,51,0 + PRODUCTVERSION 1,1,51,0 + FILEFLAGSMASK 0x17L +# ifdef _DEBUG + FILEFLAGS 0x1L +# else + FILEFLAGS 0x0L +# endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080404b0" + BEGIN + VALUE "Comments", "MY-BASIC" + VALUE "CompanyName", "W. Renxin" + VALUE "FileDescription", "MY-BASIC interpreter" + VALUE "FileVersion", "1, 1, 51, 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, 51, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x804, 1200 + END + END -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_ICON_MAIN ICON "icon.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,50 - PRODUCTVERSION 1,0,0,50 - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L #endif - FILEOS 0x4L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080404b0" - BEGIN - VALUE "Comments", "MY-BASIC" - VALUE "CompanyName", "W. Renxin" - VALUE "FileDescription", "MY-BASIC interpreter" - VALUE "FileVersion", "1, 0, 0, 50" - 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, 0, 0, 50" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x804, 1200 - END -END - -#endif // 中文(中华人民共和国) resources -///////////////////////////////////////////////////////////////////////////// - - #ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED +#endif diff --git a/resource/resource.h b/resource/resource.h old mode 100755 new mode 100644 diff --git a/shell/main.c b/shell/main.c old mode 100755 new mode 100644 index df76157..7ac6a75 --- a/shell/main.c +++ b/shell/main.c @@ -197,6 +197,13 @@ static int beep(struct mb_interpreter_t* s, void** l) { return result; } +static void _on_stepped(struct mb_interpreter_t* s, int p, unsigned short row, unsigned short col) { + mb_unrefvar(s); + mb_unrefvar(p); + mb_unrefvar(row); + mb_unrefvar(col); +} + static void _on_error(struct mb_interpreter_t* s, mb_error_e e, char* m, int p, unsigned short row, unsigned short col, int abort_code) { mb_unrefvar(s); mb_unrefvar(p); @@ -211,6 +218,7 @@ static void _on_startup(void) { mb_init(); mb_open(&bas); + mb_debug_set_stepped_handler(bas, _on_stepped); mb_set_error_handler(bas, _on_error); mb_reg_fun(bas, beep); @@ -382,10 +390,11 @@ static int _do_line(void) { } else if(_str_eq(line, "NEW")) { result = _new_program(); } else if(_str_eq(line, "RUN")) { - char* txt = _get_code(c); - result = mb_reset(&bas, false); - result = mb_load_string(bas, txt); - free(txt); + int i = 0; + mb_assert(c); + result = mb_reset(&bas, false); + for(i = 0; i < c->count; ++i) + mb_load_string(bas, c->lines[i]); result = mb_run(bas); printf("\n"); } else if(_str_eq(line, "BYE")) {