+debug APIs; +improved IF statment
This commit is contained in:
parent
0b42fc2961
commit
7f6417c2a2
6
HISTORY
Executable file → Normal file
6
HISTORY
Executable file → Normal 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.
|
||||
|
BIN
MY-BASIC Quick Reference.pdf
Executable file → Normal file
BIN
MY-BASIC Quick Reference.pdf
Executable file → Normal file
Binary file not shown.
1
README.md
Executable file → Normal file
1
README.md
Executable file → Normal 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
248
core/my_basic.c
Executable file → Normal 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
8
core/my_basic.h
Executable file → Normal 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
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
BIN
resource/my_basic.aps
Executable file → Normal file
Binary file not shown.
94
resource/my_basic.rc
Executable file → Normal file
94
resource/my_basic.rc
Executable file → Normal 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
0
resource/resource.h
Executable file → Normal file
15
shell/main.c
Executable file → Normal file
15
shell/main.c
Executable file → Normal 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")) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user