+debug APIs; +improved IF statment

This commit is contained in:
tony 2015-04-23 21:50:54 +08:00
parent 0b42fc2961
commit 7f6417c2a2
12 changed files with 294 additions and 136 deletions

6
HISTORY Executable file → Normal file
View File

@ -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.

0
LICENSE Executable file → Normal file
View File

BIN
MY-BASIC Quick Reference.pdf Executable file → Normal file

Binary file not shown.

1
README.md Executable file → Normal file
View File

@ -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)

248
core/my_basic.c Executable file → Normal file
View File

@ -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;

8
core/my_basic.h Executable file → Normal file
View File

@ -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);

BIN
output/my_basic.exe Executable file → Normal file

Binary file not shown.

Binary file not shown.

BIN
resource/my_basic.aps Executable file → Normal file

Binary file not shown.

94
resource/my_basic.rc Executable file → Normal file
View File

@ -1,79 +1,53 @@
// 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
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
END
2 TEXTINCLUDE
BEGIN
2 TEXTINCLUDE
BEGIN
"#include ""windows.h""\r\n"
"\0"
END
END
3 TEXTINCLUDE
BEGIN
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
END
#endif // APSTUDIO_INVOKED
# endif
IDI_ICON_MAIN ICON "icon.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// 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
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,51,0
PRODUCTVERSION 1,1,51,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
# ifdef _DEBUG
FILEFLAGS 0x1L
#else
# else
FILEFLAGS 0x0L
#endif
# endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080404b0"
@ -81,33 +55,23 @@ BEGIN
VALUE "Comments", "MY-BASIC"
VALUE "CompanyName", "W. Renxin"
VALUE "FileDescription", "MY-BASIC interpreter"
VALUE "FileVersion", "1, 0, 0, 50"
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, 0, 0, 50"
VALUE "ProductVersion", "1, 1, 51, 0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x804, 1200
END
END
#endif // 中文(中华人民共和国) resources
/////////////////////////////////////////////////////////////////////////////
END
#endif
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
#endif

0
resource/resource.h Executable file → Normal file
View File

15
shell/main.c Executable file → Normal file
View File

@ -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);
int i = 0;
mb_assert(c);
result = mb_reset(&bas, false);
result = mb_load_string(bas, txt);
free(txt);
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")) {