+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 Apr. 15 2015
Added mb_pop_usertype, mb_push_usertype to support user defined type Added mb_pop_usertype, mb_push_usertype to support user defined type
Polished code Polished code
@ -169,5 +173,5 @@ Fixed a suspend / resume bug
Feb. 9 2011 Feb. 9 2011
Fixed struct mb_interpreter_t declaration warnings on gcc Fixed struct mb_interpreter_t declaration warnings on gcc
Feb. 1 2011 Feb. 1 2011 Version 1.0
First release. 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) * [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) * [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) * [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) * [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) * [File module](https://github.com/paladin-t/my_basic/wiki/File-module)
* [FAQ](https://github.com/paladin-t/my_basic/wiki/FAQ) * [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 #ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4127) # pragma warning(disable : 4127)
# pragma warning(disable : 4996)
#endif /* _MSC_VER */ #endif /* _MSC_VER */
#ifdef __APPLE__ #ifdef __APPLE__
@ -77,8 +76,8 @@ extern "C" {
/** Macros */ /** Macros */
#define _VER_MAJOR 1 #define _VER_MAJOR 1
#define _VER_MINOR 0 #define _VER_MINOR 1
#define _VER_REVISION 50 #define _VER_REVISION 51
#define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION)) #define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION))
/* Uncomment this line to treat warnings as error */ /* Uncomment this line to treat warnings as error */
@ -108,6 +107,10 @@ extern "C" {
#define DON(__o) ((__o) ? ((_object_t*)((__o)->data)) : 0) #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 */ /* Hash table size */
#define _HT_ARRAY_SIZE_SMALL 193 #define _HT_ARRAY_SIZE_SMALL 193
#define _HT_ARRAY_SIZE_MID 1543 #define _HT_ARRAY_SIZE_MID 1543
@ -342,6 +345,7 @@ typedef struct mb_interpreter_t {
int last_error_pos; int last_error_pos;
unsigned short last_error_row; unsigned short last_error_row;
unsigned short last_error_col; unsigned short last_error_col;
mb_debug_stepped_handler_t debug_stepped_handler;
mb_error_handler_t error_handler; mb_error_handler_t error_handler;
mb_print_func_t printer; mb_print_func_t printer;
mb_input_func_t inputer; 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 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 _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 _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_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 _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); 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_dim(mb_interpreter_t* s, void** l);
static int _core_if(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_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_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_for(mb_interpreter_t* s, void** l);
static int _core_to(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); static int _core_step(mb_interpreter_t* s, void** l);
@ -840,7 +848,9 @@ static const _func_t _core_libs[] = {
{ "IF", _core_if }, { "IF", _core_if },
{ "THEN", _core_then }, { "THEN", _core_then },
{ "ELSEIF", _core_elseif },
{ "ELSE", _core_else }, { "ELSE", _core_else },
{ "ENDIF", _core_endif },
{ "FOR", _core_for }, { "FOR", _core_for },
{ "TO", _core_to }, { "TO", _core_to },
@ -1351,7 +1361,9 @@ bool_t _is_flow(mb_func_t op) {
result = result =
(op == _core_if) || (op == _core_if) ||
(op == _core_then) || (op == _core_then) ||
(op == _core_elseif) ||
(op == _core_else) || (op == _core_else) ||
(op == _core_endif) ||
(op == _core_for) || (op == _core_for) ||
(op == _core_to) || (op == _core_to) ||
(op == _core_step) || (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_SEP) ||
(obj->type == _DT_FUNC && (obj->type == _DT_FUNC &&
(obj->data.func->pointer == _core_then || (obj->data.func->pointer == _core_then ||
obj->data.func->pointer == _core_elseif ||
obj->data.func->pointer == _core_else || obj->data.func->pointer == _core_else ||
obj->data.func->pointer == _core_endif ||
obj->data.func->pointer == _core_to || obj->data.func->pointer == _core_to ||
obj->data.func->pointer == _core_step)); 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(c->type == _DT_STRING) {
if(ast->next) { if(ast->next) {
_object_t* _fsn = (_object_t*)ast->next->data; _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; 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) || !(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)) { !(((_object_t*)(_ls_back(optr)->data))->type == _DT_FUNC && strcmp(((_object_t*)(_ls_back(optr)->data))->data.func->name, "#") == 0)) {
if(!hack) { if(!hack) {
if(c->type == _DT_FUNC && c->data.func->pointer == _core_open_bracket) { if(_IS_FUNC(c, _core_open_bracket)) {
++bracket_count; ++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; --bracket_count;
if(bracket_count < 0) { if(bracket_count < 0) {
c = _exp_assign; c = _exp_assign;
@ -1642,7 +1656,7 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
} else { } else {
if(c->type == _DT_VAR && ast) { if(c->type == _DT_VAR && ast) {
_object_t* _err_var = (_object_t*)(ast->data); _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); _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(opnd, r);
_ls_pushback(garbage, 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; hack = true;
break; break;
@ -1751,10 +1765,11 @@ bool_t _is_print_terminal(mb_interpreter_t* s, _object_t* obj) {
mb_assert(s && obj); mb_assert(s && obj);
result = result = _IS_EOS(obj) ||
(obj->type == _DT_EOS) || _IS_SEP(obj, ':') ||
(obj->type == _DT_SEP && obj->data.separator == ':') || _IS_FUNC(obj, _core_elseif) ||
(obj->type == _DT_FUNC && (obj->data.func->pointer == _core_else)); _IS_FUNC(obj, _core_else) ||
_IS_FUNC(obj, _core_endif);
return result; 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_row = row;
obj->source_col = col; obj->source_col = col;
#else /* MB_ENABLE_SOURCE_TRACE */ #else /* MB_ENABLE_SOURCE_TRACE */
mb_unrefvar(row);
mb_unrefvar(col);
obj->source_pos = (char)pos; obj->source_pos = (char)pos;
#endif /* MB_ENABLE_SOURCE_TRACE */ #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 */ /* _label_t */
if(context->current_char == ':') { 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); glbsyminscope = _ht_find(s->global_var_dict, sym);
if(glbsyminscope) { if(glbsyminscope) {
memcpy(*value, &glbsyminscope->data, sizeof(glbsyminscope->data)); 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 else
idx += (unsigned int)val.integer; idx += (unsigned int)val.integer;
/* Comma? */ /* Comma? */
if(((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ',') if(_IS_SEP(ast->data, ','))
ast = ast->next; ast = ast->next;
++dcount; ++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; 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) { int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) {
/* Execute the ast, core execution function */ /* Execute the ast, core execution function */
int result = MB_FUNC_OK; int result = MB_FUNC_OK;
@ -2886,9 +2923,9 @@ int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) {
goto _exit; goto _exit;
if(ast) { if(ast) {
obj = (_object_t*)(ast->data); obj = (_object_t*)(ast->data);
if(obj && obj->type == _DT_EOS) { if(_IS_EOS(obj)) {
ast = ast->next; ast = ast->next;
} else if(obj && obj->type == _DT_SEP && obj->data.separator == ':') { } else if(_IS_SEP(obj, ':')) {
skip_to_eoi = false; skip_to_eoi = false;
ast = ast->next; ast = ast->next;
} else if(obj && obj->type == _DT_VAR) { } else if(obj && obj->type == _DT_VAR) {
@ -2912,6 +2949,8 @@ int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) {
_exit: _exit:
*l = ast; *l = ast;
_stepped(s, ast);
return result; return result;
} }
@ -2940,6 +2979,31 @@ _exit:
return result; 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) { int _skip_struct(mb_interpreter_t* s, _ls_node_t** l, mb_func_t open_func, mb_func_t close_func) {
/* Skip current structure */ /* Skip current structure */
int result = MB_FUNC_OK; 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); obj_prev = (_object_t*)(ast->data);
ast = ast->next; ast = ast->next;
obj = (_object_t*)(ast->data); obj = (_object_t*)(ast->data);
if(obj->type == _DT_FUNC && obj->data.func->pointer == open_func) { if(_IS_FUNC(obj, open_func)) {
++count; ++count;
} else if(obj->type == _DT_FUNC && obj->data.func->pointer == close_func && } else if(_IS_FUNC(obj, close_func) && _IS_EOS(obj_prev)) {
(obj_prev && obj_prev->type == _DT_EOS)) {
--count; --count;
} }
} while(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 = (_ls_node_t*)(*l);
ast = ast->next; ast = ast->next;
obj = (_object_t*)(ast->data); 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); _handle_error_on_obj(s, SE_RN_OPEN_BRACKET_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
} }
ast = ast->next; 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); _handle_error_on_obj(s, SE_RN_CLOSE_BRACKET_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
} }
obj = (_object_t*)(ast->data); 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); _handle_error_on_obj(s, SE_RN_CLOSE_BRACKET_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
} }
ast = ast->next; ast = ast->next;
@ -3483,7 +3546,7 @@ int mb_has_arg(struct mb_interpreter_t* s, void** l) {
ast = (_ls_node_t*)(*l); ast = (_ls_node_t*)(*l);
if(ast) { if(ast) {
obj = (_object_t*)(ast->data); 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; 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(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; ast = ast->next;
} }
@ -3884,6 +3947,58 @@ int mb_suspend(struct mb_interpreter_t* s, void** l) {
return result; 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) { mb_error_e mb_get_last_error(struct mb_interpreter_t* s) {
/* Get last error information */ /* Get last error information */
mb_error_e result = SE_NO_ERR; 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; dummy.count += (unsigned int)val.integer;
ast = ast->next; ast = ast->next;
/* Comma? */ /* Comma? */
if(((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ',') if(_IS_SEP(ast->data, ','))
ast = ast->next; ast = ast->next;
} }
/* Create or modify raw data */ /* Create or modify raw data */
@ -4527,6 +4642,7 @@ int _core_if(mb_interpreter_t* s, void** l) {
_ls_node_t* ast = 0; _ls_node_t* ast = 0;
_object_t* val = 0; _object_t* val = 0;
_object_t* obj = 0; _object_t* obj = 0;
bool_t multi_line = false;
_running_context_t* running = 0; _running_context_t* running = 0;
mb_assert(s && l); mb_assert(s && l);
@ -4537,6 +4653,8 @@ int _core_if(mb_interpreter_t* s, void** l) {
ast = ast->next; ast = ast->next;
val = (_object_t*)mb_malloc(sizeof(_object_t)); val = (_object_t*)mb_malloc(sizeof(_object_t));
_elseif:
memset(val, 0, sizeof(_object_t)); memset(val, 0, sizeof(_object_t));
result = _calc_expression(s, &ast, &val); result = _calc_expression(s, &ast, &val);
if(result != MB_FUNC_OK) if(result != MB_FUNC_OK)
@ -4545,10 +4663,13 @@ int _core_if(mb_interpreter_t* s, void** l) {
obj = (_object_t*)(ast->data); obj = (_object_t*)(ast->data);
if(val->data.integer) { 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); _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); running->skip_to_eoi = _ls_back(running->sub_stack);
do { do {
ast = ast->next; ast = ast->next;
@ -4557,7 +4678,16 @@ int _core_if(mb_interpreter_t* s, void** l) {
goto _exit; goto _exit;
if(ast) if(ast)
ast = ast->prev; 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) if(!ast)
goto _exit; goto _exit;
@ -4570,28 +4700,48 @@ int _core_if(mb_interpreter_t* s, void** l) {
goto _exit; goto _exit;
} }
} else { } 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); result = _skip_to(s, &ast, _core_else, _DT_EOS);
if(result != MB_FUNC_OK) if(result != MB_FUNC_OK)
goto _exit; goto _exit;
obj = (_object_t*)(ast->data); obj = (_object_t*)(ast->data);
if(obj->type != _DT_EOS) { 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); _handle_error_on_obj(s, SE_RN_ELSE_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
} }
do { do {
ast = ast->next; ast = ast->next;
while(_IS_EOS(ast->data))
ast = ast->next;
result = _execute_statement(s, &ast); result = _execute_statement(s, &ast);
if(result != MB_FUNC_OK) if(result != MB_FUNC_OK)
goto _exit; goto _exit;
if(ast) if(ast)
ast = ast->prev; 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: _exit:
if(multi_line)
result = _skip_to(s, &ast, _core_endif, _DT_NIL);
_destroy_object(val, 0); _destroy_object(val, 0);
*l = ast; *l = ast;
@ -4611,6 +4761,18 @@ int _core_then(mb_interpreter_t* s, void** l) {
return result; 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) { int _core_else(mb_interpreter_t* s, void** l) {
/* ELSE statement */ /* ELSE statement */
int result = MB_FUNC_OK; int result = MB_FUNC_OK;
@ -4623,6 +4785,18 @@ int _core_else(mb_interpreter_t* s, void** l) {
return result; 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) { int _core_for(mb_interpreter_t* s, void** l) {
/* FOR statement */ /* FOR statement */
int result = MB_FUNC_OK; int result = MB_FUNC_OK;
@ -4660,7 +4834,7 @@ int _core_for(mb_interpreter_t* s, void** l) {
ast = ast->prev; ast = ast->prev;
obj = (_object_t*)(ast->data); 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); _handle_error_on_obj(s, SE_RN_TO_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
} }
@ -4678,7 +4852,7 @@ _to:
goto _exit; goto _exit;
obj = (_object_t*)(ast->data); 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; step_val = _OBJ_INT_UNIT;
} else { } else {
ast = ast->next; ast = ast->next;
@ -4702,7 +4876,7 @@ _to:
} else { } else {
/* Keep looping */ /* Keep looping */
obj = (_object_t*)(ast->data); 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); result = _execute_statement(s, &ast);
if(result == MB_LOOP_CONTINUE) { /* NEXT */ if(result == MB_LOOP_CONTINUE) { /* NEXT */
if(!running->next_loop_var || running->next_loop_var == var_loop) { /* This loop */ 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) { if(loop_cond_ptr->data.integer) {
/* Keep looping */ /* Keep looping */
obj = (_object_t*)(ast->data); 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); result = _execute_statement(s, &ast);
if(result == MB_LOOP_BREAK) { /* EXIT */ if(result == MB_LOOP_BREAK) { /* EXIT */
if(_skip_struct(s, &ast, _core_while, _core_wend) != MB_FUNC_OK) 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; ast = ast->next;
obj = (_object_t*)(ast->data); 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); _handle_error_on_obj(s, SE_RN_SYNTAX, DON(ast), MB_FUNC_ERR, _exit, result);
} }
ast = ast->next; ast = ast->next;
@ -4898,7 +5072,7 @@ _loop_begin:
ast = loop_begin_node; ast = loop_begin_node;
obj = (_object_t*)(ast->data); 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); result = _execute_statement(s, &ast);
if(result == MB_LOOP_BREAK) { /* EXIT */ if(result == MB_LOOP_BREAK) { /* EXIT */
if(_skip_struct(s, &ast, _core_do, _core_until) != MB_FUNC_OK) if(_skip_struct(s, &ast, _core_do, _core_until) != MB_FUNC_OK)
@ -4915,7 +5089,7 @@ _loop_begin:
} }
obj = (_object_t*)(ast->data); 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); _handle_error_on_obj(s, SE_RN_UNTIL_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result);
} }
ast = ast->next; ast = ast->next;
@ -5885,13 +6059,13 @@ int _std_print(mb_interpreter_t* s, void** l) {
obj = (_object_t*)(ast->data); obj = (_object_t*)(ast->data);
if(_is_print_terminal(s, obj)) if(_is_print_terminal(s, obj))
break; break;
if(obj->type == _DT_SEP && (obj->data.separator == ',' || obj->data.separator == ';')) { if(_IS_SEP(obj, ',') || _IS_SEP(obj, ';')) {
ast = ast->next; ast = ast->next;
obj = (_object_t*)(ast->data); obj = (_object_t*)(ast->data);
} else { } else {
_handle_error_on_obj(s, SE_RN_COMMA_OR_SEMICOLON_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); _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: _exit:
--running->no_eat_comma_mark; --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_BREAK 5001
# define MB_LOOP_CONTINUE 5002 # define MB_LOOP_CONTINUE 5002
# define MB_SUB_RETURN 5101 # define MB_SUB_RETURN 5101
# define MB_DEBUG_ID_NOT_FOUND 7001
# define MB_EXTENDED_ABORT 9001 # define MB_EXTENDED_ABORT 9001
#endif /* MB_CODES */ #endif /* MB_CODES */
@ -212,8 +213,9 @@ typedef struct mb_value_t {
mb_value_u value; mb_value_u value;
} mb_value_t; } 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 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_print_func_t)(const char*, ...);
typedef int (* mb_input_func_t)(char*, int); 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_run(struct mb_interpreter_t* s);
MBAPI int mb_suspend(struct mb_interpreter_t* s, void** l); 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 mb_error_e mb_get_last_error(struct mb_interpreter_t* s);
MBAPI const char* mb_get_error_desc(mb_error_e err); 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); 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" #include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS #define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h" #include "windows.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS #undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// 中文(中华人民共和国) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
#ifdef _WIN32 # ifdef _WIN32
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936) # pragma code_page(936)
#endif //_WIN32 # endif //_WIN32
#ifdef APSTUDIO_INVOKED # ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE 1 TEXTINCLUDE
BEGIN BEGIN
"resource.h\0" "resource.h\0"
END END
2 TEXTINCLUDE 2 TEXTINCLUDE
BEGIN BEGIN
"#include ""windows.h""\r\n" "#include ""windows.h""\r\n"
"\0" "\0"
END END
3 TEXTINCLUDE 3 TEXTINCLUDE
BEGIN BEGIN
"\r\n" "\r\n"
"\0" "\0"
END END
#endif // APSTUDIO_INVOKED # endif
IDI_ICON_MAIN ICON "icon.ico"
///////////////////////////////////////////////////////////////////////////// VS_VERSION_INFO VERSIONINFO
// FILEVERSION 1,1,51,0
// Icon PRODUCTVERSION 1,1,51,0
//
// 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 FILEFLAGSMASK 0x17L
#ifdef _DEBUG # ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
#else # else
FILEFLAGS 0x0L FILEFLAGS 0x0L
#endif # endif
FILEOS 0x4L FILEOS 0x4L
FILETYPE 0x1L FILETYPE 0x1L
FILESUBTYPE 0x0L FILESUBTYPE 0x0L
BEGIN BEGIN
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
BEGIN BEGIN
BLOCK "080404b0" BLOCK "080404b0"
@ -81,33 +55,23 @@ BEGIN
VALUE "Comments", "MY-BASIC" VALUE "Comments", "MY-BASIC"
VALUE "CompanyName", "W. Renxin" VALUE "CompanyName", "W. Renxin"
VALUE "FileDescription", "MY-BASIC interpreter" VALUE "FileDescription", "MY-BASIC interpreter"
VALUE "FileVersion", "1, 0, 0, 50" VALUE "FileVersion", "1, 1, 51, 0"
VALUE "InternalName", "my_basic" VALUE "InternalName", "my_basic"
VALUE "LegalCopyright", "Copyright (C) 2011 - 2015 W. Renxin" VALUE "LegalCopyright", "Copyright (C) 2011 - 2015 W. Renxin"
VALUE "LegalTrademarks", "MY-BASIC" VALUE "LegalTrademarks", "MY-BASIC"
VALUE "OriginalFilename", "my_basic.exe" VALUE "OriginalFilename", "my_basic.exe"
VALUE "ProductName", "MY-BASIC" VALUE "ProductName", "MY-BASIC"
VALUE "ProductVersion", "1, 0, 0, 50" VALUE "ProductVersion", "1, 1, 51, 0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
BEGIN BEGIN
VALUE "Translation", 0x804, 1200 VALUE "Translation", 0x804, 1200
END END
END END
#endif // 中文(中华人民共和国) resources
/////////////////////////////////////////////////////////////////////////////
#endif
#ifndef APSTUDIO_INVOKED #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; 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) { 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(s);
mb_unrefvar(p); mb_unrefvar(p);
@ -211,6 +218,7 @@ static void _on_startup(void) {
mb_init(); mb_init();
mb_open(&bas); mb_open(&bas);
mb_debug_set_stepped_handler(bas, _on_stepped);
mb_set_error_handler(bas, _on_error); mb_set_error_handler(bas, _on_error);
mb_reg_fun(bas, beep); mb_reg_fun(bas, beep);
@ -382,10 +390,11 @@ static int _do_line(void) {
} else if(_str_eq(line, "NEW")) { } else if(_str_eq(line, "NEW")) {
result = _new_program(); result = _new_program();
} else if(_str_eq(line, "RUN")) { } else if(_str_eq(line, "RUN")) {
char* txt = _get_code(c); int i = 0;
mb_assert(c);
result = mb_reset(&bas, false); result = mb_reset(&bas, false);
result = mb_load_string(bas, txt); for(i = 0; i < c->count; ++i)
free(txt); mb_load_string(bas, c->lines[i]);
result = mb_run(bas); result = mb_run(bas);
printf("\n"); printf("\n");
} else if(_str_eq(line, "BYE")) { } else if(_str_eq(line, "BYE")) {