+implemented tail recursion optimization in sub routine; +added array length gain in len function; *fixed a crash bug when returning nothing in a sub routine; *polished document.

This commit is contained in:
tony 2015-09-21 23:51:55 +08:00
parent a956338ec0
commit b6ab676ad7
7 changed files with 216 additions and 168 deletions

View File

@ -1,3 +1,9 @@
Sep. 21 2015
Implemented tail recursion optimization in sub routine
Added array length gain in LEN function
Fixed a crash bug when returning nothing in a sub routine
Polished document
Sep. 20 2015 Sep. 20 2015
Added array manipulation ability to script, it's able to assign an array to a variable or use it as a scripting interface argument Added array manipulation ability to script, it's able to assign an array to a variable or use it as a scripting interface argument
Added recursive sub routine support Added recursive sub routine support
@ -10,7 +16,7 @@ Added directly expression evaluation shell command
Sep. 17 2015 Sep. 17 2015
Allowed string in a boolean expression Allowed string in a boolean expression
Added support for sub routine in PRINT Added support for sub routine in PRINT
Fixed a repeated disposing bug when suing sub routine Fixed a repeated disposing bug when using sub routine
Sep. 16 2015 Sep. 16 2015
Added Nil type handling, including assignment, boolean operation, serialization, etc. Added Nil type handling, including assignment, boolean operation, serialization, etc.

Binary file not shown.

View File

@ -79,8 +79,12 @@ extern "C" {
/** Macros */ /** Macros */
#define _VER_MAJOR 1 #define _VER_MAJOR 1
#define _VER_MINOR 1 #define _VER_MINOR 1
#define _VER_REVISION 72 #define _VER_REVISION 73
#define _VER_SUFFIX
#define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION)) #define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION))
#define _STRINGIZE(A) _MAKE_STRINGIZE(A)
#define _MAKE_STRINGIZE(A) #A
#define _MB_VERSION_STRING _STRINGIZE(_VER_MAJOR._VER_MINOR._VER_REVISION _VER_SUFFIX)
/* Uncomment the line below to treat warning as error */ /* Uncomment the line below to treat warning as error */
/*#define _WARING_AS_ERROR*/ /*#define _WARING_AS_ERROR*/
@ -407,6 +411,7 @@ typedef struct mb_interpreter_t {
_parsing_context_t* parsing_context; _parsing_context_t* parsing_context;
_running_context_t* running_context; _running_context_t* running_context;
unsigned char jump_set; unsigned char jump_set;
_routine_t* last_routine;
_ls_node_t* sub_stack; _ls_node_t* sub_stack;
_ls_node_t* temp_values; _ls_node_t* temp_values;
_ls_node_t* suspent_point; _ls_node_t* suspent_point;
@ -985,11 +990,11 @@ static int _std_log(mb_interpreter_t* s, void** l);
static int _std_asc(mb_interpreter_t* s, void** l); static int _std_asc(mb_interpreter_t* s, void** l);
static int _std_chr(mb_interpreter_t* s, void** l); static int _std_chr(mb_interpreter_t* s, void** l);
static int _std_left(mb_interpreter_t* s, void** l); static int _std_left(mb_interpreter_t* s, void** l);
static int _std_len(mb_interpreter_t* s, void** l);
static int _std_mid(mb_interpreter_t* s, void** l); static int _std_mid(mb_interpreter_t* s, void** l);
static int _std_right(mb_interpreter_t* s, void** l); static int _std_right(mb_interpreter_t* s, void** l);
static int _std_str(mb_interpreter_t* s, void** l); static int _std_str(mb_interpreter_t* s, void** l);
static int _std_val(mb_interpreter_t* s, void** l); static int _std_val(mb_interpreter_t* s, void** l);
static int _std_len(mb_interpreter_t* s, void** l);
static int _std_print(mb_interpreter_t* s, void** l); static int _std_print(mb_interpreter_t* s, void** l);
static int _std_input(mb_interpreter_t* s, void** l); static int _std_input(mb_interpreter_t* s, void** l);
@ -1075,12 +1080,13 @@ static const _func_t _std_libs[] = {
{ "ASC", _std_asc }, { "ASC", _std_asc },
{ "CHR", _std_chr }, { "CHR", _std_chr },
{ "LEFT", _std_left }, { "LEFT", _std_left },
{ "LEN", _std_len },
{ "MID", _std_mid }, { "MID", _std_mid },
{ "RIGHT", _std_right }, { "RIGHT", _std_right },
{ "STR", _std_str }, { "STR", _std_str },
{ "VAL", _std_val }, { "VAL", _std_val },
{ "LEN", _std_len },
{ "PRINT", _std_print }, { "PRINT", _std_print },
{ "INPUT", _std_input } { "INPUT", _std_input }
}; };
@ -1839,6 +1845,8 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) {
memset(c, 0, sizeof(_object_t)); memset(c, 0, sizeof(_object_t));
_ls_pushback(garbage, c); _ls_pushback(garbage, c);
result = _public_value_to_internal_object(&running->intermediate_value, c); result = _public_value_to_internal_object(&running->intermediate_value, c);
if(c->type == _DT_STRING)
c->ref = true;
if(result != MB_FUNC_OK) if(result != MB_FUNC_OK)
goto _exit; goto _exit;
if(f) { if(f) {
@ -2018,9 +2026,27 @@ int _eval_routine(mb_interpreter_t* s, _ls_node_t** l, _routine_t* r) {
_var_t* var = 0; _var_t* var = 0;
_ls_node_t* rnode = 0; _ls_node_t* rnode = 0;
_running_context_t* running = 0; _running_context_t* running = 0;
_routine_t* lastr = 0;
mb_assert(s && l && r); mb_assert(s && l && r);
if(s->last_routine && (s->last_routine->name == r->name || !strcmp(s->last_routine->name, r->name))) {
ast = (_ls_node_t*)(*l);
_skip_to(s, &ast, 0, _DT_EOS);
if(ast && ((_object_t*)(ast->data))->type == _DT_EOS)
ast = ast->next;
if(_IS_FUNC((_object_t*)(ast->data), _core_enddef)) { /* Tail recursion optimization */
*l = r->entry;
if(*l)
*l = (*l)->next;
goto _tail;
}
}
lastr = s->last_routine;
s->last_routine = r;
running = s->running_context; running = s->running_context;
mb_check(mb_attempt_open_bracket(s, (void**)l)); mb_check(mb_attempt_open_bracket(s, (void**)l));
@ -2094,6 +2120,9 @@ int _eval_routine(mb_interpreter_t* s, _ls_node_t** l, _routine_t* r) {
s->running_context->intermediate_value = running->intermediate_value; s->running_context->intermediate_value = running->intermediate_value;
_exit: _exit:
s->last_routine = lastr;
_tail:
return result; return result;
} }
@ -3846,6 +3875,8 @@ int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) {
ast = (_ls_node_t*)_ls_popback(sub_stack); ast = (_ls_node_t*)_ls_popback(sub_stack);
} else if(obj && obj->type == _DT_FUNC && (_is_operator(obj->data.func->pointer) || _is_flow(obj->data.func->pointer))) { } else if(obj && obj->type == _DT_FUNC && (_is_operator(obj->data.func->pointer) || _is_flow(obj->data.func->pointer))) {
ast = ast->next; ast = ast->next;
} else if(obj && obj->type == _DT_FUNC) {
/* Do nothing */
} else if(obj && obj->type != _DT_FUNC) { } else if(obj && obj->type != _DT_FUNC) {
ast = ast->next; ast = ast->next;
} else { } else {
@ -4162,11 +4193,7 @@ unsigned int mb_ver(void) {
const char* mb_ver_string(void) { const char* mb_ver_string(void) {
/* Get the version text of this MY-BASIC system */ /* Get the version text of this MY-BASIC system */
static char buf[32] = { '\0' }; return _MB_VERSION_STRING;
if(!buf[0])
sprintf(buf, "%d.%d.%04d", _VER_MAJOR, _VER_MINOR, _VER_REVISION);
return buf;
} }
int mb_init(void) { int mb_init(void) {
@ -4353,6 +4380,7 @@ int mb_reset(struct mb_interpreter_t** s, bool_t clrf/* = false*/) {
mb_assert(s); mb_assert(s);
(*s)->jump_set = _JMP_NIL; (*s)->jump_set = _JMP_NIL;
(*s)->last_routine = 0;
(*s)->no_eat_comma_mark = 0; (*s)->no_eat_comma_mark = 0;
(*s)->last_error = SE_NO_ERR; (*s)->last_error = SE_NO_ERR;
(*s)->last_error_func = 0; (*s)->last_error_func = 0;
@ -6344,12 +6372,14 @@ int _core_return(mb_interpreter_t* s, void** l) {
if(running->prev) { if(running->prev) {
ast = (_ls_node_t*)(*l); ast = (_ls_node_t*)(*l);
ast = ast->next; ast = ast->next;
mb_check(mb_pop_value(s, (void**)(&ast), &arg)); if(mb_has_arg(s, (void**)(&ast))) {
mb_check(mb_push_value(s, (void**)(&ast), arg)); mb_check(mb_pop_value(s, (void**)(&ast), &arg));
mb_check(mb_push_value(s, (void**)(&ast), arg));
if(arg.type == MB_DT_STRING) { if(arg.type == MB_DT_STRING) {
_ls_foreach(s->temp_values, _destroy_object_capsule_only); _ls_foreach(s->temp_values, _destroy_object_capsule_only);
_ls_clear(s->temp_values); _ls_clear(s->temp_values);
}
} }
} }
ast = (_ls_node_t*)_ls_popback(sub_stack); ast = (_ls_node_t*)_ls_popback(sub_stack);
@ -7027,43 +7057,6 @@ _exit:
return result; return result;
} }
int _std_len(mb_interpreter_t* s, void** l) {
/* Get the length of a string */
int result = MB_FUNC_OK;
_ls_node_t* ast = 0;
mb_value_t arg;
_array_t* arr = 0;
mb_assert(s && l);
ast = (_ls_node_t*)(*l);
mb_check(mb_attempt_open_bracket(s, l));
mb_check(mb_pop_value(s, l, &arg));
mb_check(mb_attempt_close_bracket(s, l));
switch(arg.type) {
case MB_DT_STRING:
mb_check(mb_push_int(s, l, (int_t)strlen(arg.value.string)));
break;
case MB_DT_ARRAY:
arr = (_array_t*)arg.value.array;
mb_check(mb_push_int(s, l, (int_t)arr->count));
break;
default:
_handle_error_on_obj(s, SE_RN_NOT_SUPPORTED, 0, DON(ast), MB_FUNC_ERR, _exit, result);
break;
}
_exit:
return result;
}
int _std_mid(mb_interpreter_t* s, void** l) { int _std_mid(mb_interpreter_t* s, void** l) {
/* Get a number of characters from a given position of a string */ /* Get a number of characters from a given position of a string */
int result = MB_FUNC_OK; int result = MB_FUNC_OK;
@ -7194,6 +7187,43 @@ _exit:
return result; return result;
} }
int _std_len(mb_interpreter_t* s, void** l) {
/* Get the length of a string or an array */
int result = MB_FUNC_OK;
_ls_node_t* ast = 0;
mb_value_t arg;
_array_t* arr = 0;
mb_assert(s && l);
ast = (_ls_node_t*)(*l);
mb_check(mb_attempt_open_bracket(s, l));
mb_check(mb_pop_value(s, l, &arg));
mb_check(mb_attempt_close_bracket(s, l));
switch(arg.type) {
case MB_DT_STRING:
mb_check(mb_push_int(s, l, (int_t)strlen(arg.value.string)));
break;
case MB_DT_ARRAY:
arr = (_array_t*)arg.value.array;
mb_check(mb_push_int(s, l, (int_t)arr->count));
break;
default:
_handle_error_on_obj(s, SE_RN_NOT_SUPPORTED, 0, DON(ast), MB_FUNC_ERR, _exit, result);
break;
}
_exit:
return result;
}
int _std_print(mb_interpreter_t* s, void** l) { int _std_print(mb_interpreter_t* s, void** l) {
/* PRINT statement */ /* PRINT statement */
int result = MB_FUNC_OK; int result = MB_FUNC_OK;

Binary file not shown.

Binary file not shown.

View File

@ -36,8 +36,8 @@
IDI_ICON_MAIN ICON "icon.ico" IDI_ICON_MAIN ICON "icon.ico"
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,72,0 FILEVERSION 1,1,73,0
PRODUCTVERSION 1,1,72,0 PRODUCTVERSION 1,1,73,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
# ifdef _DEBUG # ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -55,13 +55,13 @@
VALUE "Comments", "MY-BASIC" VALUE "Comments", "MY-BASIC"
VALUE "CompanyName", "Wang Renxin" VALUE "CompanyName", "Wang Renxin"
VALUE "FileDescription", "MY-BASIC Interpreter for Windows" VALUE "FileDescription", "MY-BASIC Interpreter for Windows"
VALUE "FileVersion", "1, 1, 72, 0" VALUE "FileVersion", "1, 1, 73, 0"
VALUE "InternalName", "my_basic" VALUE "InternalName", "my_basic"
VALUE "LegalCopyright", "Copyright (C) 2011 - 2015 Wang Renxin" VALUE "LegalCopyright", "Copyright (C) 2011 - 2015 Wang 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, 1, 72, 0" VALUE "ProductVersion", "1, 1, 73, 0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -1,27 +1,27 @@
/* /*
** This source file is part of MY-BASIC ** This source file is part of MY-BASIC
** **
** For the latest info, see https://github.com/paladin-t/my_basic/ ** For the latest info, see https://github.com/paladin-t/my_basic/
** **
** Copyright (C) 2011 - 2015 Wang Renxin ** Copyright (C) 2011 - 2015 Wang Renxin
** **
** Permission is hereby granted, free of charge, to any person obtaining a copy of ** Permission is hereby granted, free of charge, to any person obtaining a copy of
** this software and associated documentation files (the "Software"), to deal in ** this software and associated documentation files (the "Software"), to deal in
** the Software without restriction, including without limitation the rights to ** the Software without restriction, including without limitation the rights to
** use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of ** use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
** the Software, and to permit persons to whom the Software is furnished to do so, ** the Software, and to permit persons to whom the Software is furnished to do so,
** subject to the following conditions: ** subject to the following conditions:
** **
** The above copyright notice and this permission notice shall be included in all ** The above copyright notice and this permission notice shall be included in all
** copies or substantial portions of the Software. ** copies or substantial portions of the Software.
** **
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
** FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR ** FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER ** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifdef _MSC_VER #ifdef _MSC_VER
# ifndef _CRT_SECURE_NO_WARNINGS # ifndef _CRT_SECURE_NO_WARNINGS
@ -40,6 +40,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning(disable : 4127) # pragma warning(disable : 4127)
@ -59,9 +60,9 @@
#endif /* __POCC__ */ #endif /* __POCC__ */
/* /*
** {======================================================== ** {========================================================
** Common declarations ** Common declarations
*/ */
#ifdef _MSC_VER #ifdef _MSC_VER
# define _BIN_FILE_NAME "my_basic" # define _BIN_FILE_NAME "my_basic"
@ -85,9 +86,20 @@ static struct mb_interpreter_t* bas = 0;
/* ========================================================} */ /* ========================================================} */
/* /*
** {======================================================== ** {========================================================
** Memory manipulation ** Common
*/ */
#ifndef _printf
# define _printf printf
#endif /* _printf */
/* ========================================================} */
/*
** {========================================================
** Memory manipulation
*/
#ifdef _USE_MEM_POOL #ifdef _USE_MEM_POOL
@ -251,9 +263,9 @@ static void _push_mem(char* p) {
/* ========================================================} */ /* ========================================================} */
/* /*
** {======================================================== ** {========================================================
** Code manipulation ** Code manipulation
*/ */
typedef struct _code_line_t { typedef struct _code_line_t {
char** lines; char** lines;
@ -397,9 +409,9 @@ static int _save_file(const char* path, const char* txt) {
/* ========================================================} */ /* ========================================================} */
/* /*
** {======================================================== ** {========================================================
** Interactive commands ** Interactive commands
*/ */
static void _clear_screen(void) { static void _clear_screen(void) {
#ifdef _MSC_VER #ifdef _MSC_VER
@ -426,18 +438,18 @@ static void _list_program(const char* sn, const char* cn) {
if(lsn == 0 && lcn == 0) { if(lsn == 0 && lcn == 0) {
long i = 0; long i = 0;
for(i = 0; i < c->count; ++i) { for(i = 0; i < c->count; ++i) {
printf("%ld]%s", i + 1, c->lines[i]); _printf("%ld]%s", i + 1, c->lines[i]);
} }
} else { } else {
long i = 0; long i = 0;
long e = 0; long e = 0;
if(lsn < 1 || lsn > c->count) { if(lsn < 1 || lsn > c->count) {
printf("Line number %ld out of bound.\n", lsn); _printf("Line number %ld out of bound.\n", lsn);
return; return;
} }
if(lcn < 0) { if(lcn < 0) {
printf("Invalid line count %ld.\n", lcn); _printf("Invalid line count %ld.\n", lcn);
return; return;
} }
@ -447,7 +459,7 @@ static void _list_program(const char* sn, const char* cn) {
if(i >= c->count) if(i >= c->count)
break; break;
printf("%ld]%s\n", i + 1, c->lines[i]); _printf("%ld]%s\n", i + 1, c->lines[i]);
} }
} }
} }
@ -461,13 +473,13 @@ static void _edit_program(const char* no) {
lno = atoi(no); lno = atoi(no);
if(lno < 1 || lno > c->count) { if(lno < 1 || lno > c->count) {
printf("Line number %ld out of bound.\n", lno); _printf("Line number %ld out of bound.\n", lno);
return; return;
} }
--lno; --lno;
memset(line, 0, _MAX_LINE_LENGTH); memset(line, 0, _MAX_LINE_LENGTH);
printf("%ld]", lno + 1); _printf("%ld]", lno + 1);
mb_gets(line, _MAX_LINE_LENGTH); mb_gets(line, _MAX_LINE_LENGTH);
l = (int)strlen(line); l = (int)strlen(line);
c->lines[lno] = (char*)realloc(c->lines[lno], l + 2); c->lines[lno] = (char*)realloc(c->lines[lno], l + 2);
@ -485,13 +497,13 @@ static void _insert_program(const char* no) {
lno = atoi(no); lno = atoi(no);
if(lno < 1 || lno > c->count) { if(lno < 1 || lno > c->count) {
printf("Line number %ld out of bound.\n", lno); _printf("Line number %ld out of bound.\n", lno);
return; return;
} }
--lno; --lno;
memset(line, 0, _MAX_LINE_LENGTH); memset(line, 0, _MAX_LINE_LENGTH);
printf("%ld]", lno + 1); _printf("%ld]", lno + 1);
mb_gets(line, _MAX_LINE_LENGTH); mb_gets(line, _MAX_LINE_LENGTH);
if(c->count + 1 == c->size) { if(c->count + 1 == c->size) {
c->size += _LINE_INC_STEP; c->size += _LINE_INC_STEP;
@ -512,7 +524,7 @@ static void _alter_program(const char* no) {
lno = atoi(no); lno = atoi(no);
if(lno < 1 || lno > c->count) { if(lno < 1 || lno > c->count) {
printf("Line number %ld out of bound.\n", lno); _printf("Line number %ld out of bound.\n", lno);
return; return;
} }
@ -530,24 +542,24 @@ static void _load_program(const char* path) {
_set_code(c, txt); _set_code(c, txt);
free(txt); free(txt);
if(c->count == 1) { if(c->count == 1) {
printf("Load done. %d line loaded.\n", c->count); _printf("Load done. %d line loaded.\n", c->count);
} else { } else {
printf("Load done. %d lines loaded.\n", c->count); _printf("Load done. %d lines loaded.\n", c->count);
} }
} else { } else {
printf("Cannot load file \"%s\".\n", path); _printf("Cannot load file \"%s\".\n", path);
} }
} }
static void _save_program(const char* path) { static void _save_program(const char* path) {
char* txt = _get_code(c); char* txt = _get_code(c);
if(!_save_file(path, txt)) { if(!_save_file(path, txt)) {
printf("Cannot save file \"%s\".\n", path); _printf("Cannot save file \"%s\".\n", path);
} else { } else {
if(c->count == 1) { if(c->count == 1) {
printf("Save done. %d line saved.\n", c->count); _printf("Save done. %d line saved.\n", c->count);
} else { } else {
printf("Save done. %d lines saved.\n", c->count); _printf("Save done. %d lines saved.\n", c->count);
} }
} }
free(txt); free(txt);
@ -555,41 +567,41 @@ static void _save_program(const char* path) {
static void _kill_program(const char* path) { static void _kill_program(const char* path) {
if(!unlink(path)) { if(!unlink(path)) {
printf("Delete file \"%s\" successfully.\n", path); _printf("Delete file \"%s\" successfully.\n", path);
} else { } else {
printf("Delete file \"%s\" failed.\n", path); _printf("Delete file \"%s\" failed.\n", path);
} }
} }
static void _show_tip(void) { static void _show_tip(void) {
printf("MY-BASIC Interpreter Shell - %s.\n", mb_ver_string()); _printf("MY-BASIC Interpreter Shell - %s.\n", mb_ver_string());
printf("Copyright (C) 2011 - 2015 Wang Renxin. All Rights Reserved.\n"); _printf("Copyright (C) 2011 - 2015 Wang Renxin. All Rights Reserved.\n");
printf("For more information, see https://github.com/paladin-t/my_basic/.\n"); _printf("For more information, see https://github.com/paladin-t/my_basic/.\n");
printf("Input HELP and hint enter to view help information.\n"); _printf("Input HELP and hint enter to view help information.\n");
} }
static void _show_help(void) { static void _show_help(void) {
printf("Parameters:\n"); _printf("Parameters:\n");
printf(" %s - Start interactive mode without arguments.\n", _BIN_FILE_NAME); _printf(" %s - Start interactive mode without arguments.\n", _BIN_FILE_NAME);
printf(" %s *.* - Load and run a file.\n", _BIN_FILE_NAME); _printf(" %s *.* - Load and run a file.\n", _BIN_FILE_NAME);
printf(" %s -e \"expr\" - Evaluate an expression directly.\n", _BIN_FILE_NAME); _printf(" %s -e \"expr\" - Evaluate an expression directly.\n", _BIN_FILE_NAME);
printf("Interactive commands:\n"); _printf("Interactive commands:\n");
printf(" CLS - Clear screen\n"); _printf(" CLS - Clear screen\n");
printf(" NEW - Clear current program\n"); _printf(" NEW - Clear current program\n");
printf(" RUN - Run current program\n"); _printf(" RUN - Run current program\n");
printf(" BYE - Quit interpreter\n"); _printf(" BYE - Quit interpreter\n");
printf(" LIST - List current program\n"); _printf(" LIST - List current program\n");
printf(" Usage: LIST [l [n]], l is start line number, n is line count\n"); _printf(" Usage: LIST [l [n]], l is start line number, n is line count\n");
printf(" EDIT - Edit (modify/insert/remove) a line in current program\n"); _printf(" EDIT - Edit (modify/insert/remove) a line in current program\n");
printf(" Usage: EDIT n, n is line number\n"); _printf(" Usage: EDIT n, n is line number\n");
printf(" EDIT -I n, insert a line before a given line, n is line number\n"); _printf(" EDIT -I n, insert a line before a given line, n is line number\n");
printf(" EDIT -R n, remove a line, n is line number\n"); _printf(" EDIT -R n, remove a line, n is line number\n");
printf(" LOAD - Load a file as current program\n"); _printf(" LOAD - Load a file as current program\n");
printf(" Usage: LOAD *.*\n"); _printf(" Usage: LOAD *.*\n");
printf(" SAVE - Save current program to a file\n"); _printf(" SAVE - Save current program to a file\n");
printf(" Usage: SAVE *.*\n"); _printf(" Usage: SAVE *.*\n");
printf(" KILL - Delete a file\n"); _printf(" KILL - Delete a file\n");
printf(" Usage: KILL *.*\n"); _printf(" Usage: KILL *.*\n");
} }
static int _do_line(void) { static int _do_line(void) {
@ -600,7 +612,7 @@ static int _do_line(void) {
mb_assert(bas); mb_assert(bas);
memset(line, 0, _MAX_LINE_LENGTH); memset(line, 0, _MAX_LINE_LENGTH);
printf("]"); _printf("]");
mb_gets(line, _MAX_LINE_LENGTH); mb_gets(line, _MAX_LINE_LENGTH);
memcpy(dup, line, _MAX_LINE_LENGTH); memcpy(dup, line, _MAX_LINE_LENGTH);
@ -621,7 +633,7 @@ static int _do_line(void) {
for(i = 0; i < c->count; ++i) for(i = 0; i < c->count; ++i)
mb_load_string(bas, c->lines[i]); 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")) {
result = MB_FUNC_BYE; result = MB_FUNC_BYE;
} else if(_str_eq(line, "LIST")) { } else if(_str_eq(line, "LIST")) {
@ -660,23 +672,23 @@ static int _do_line(void) {
/* ========================================================} */ /* ========================================================} */
/* /*
** {======================================================== ** {========================================================
** Parameter processing ** Parameter processing
*/ */
#define _CHECK_ARG(__c, __i, __e) \ #define _CHECK_ARG(__c, __i, __e) \
do { \ do { \
if(__c <= __i + 1) { \ if(__c <= __i + 1) { \
printf(__e); \ _printf(__e); \
return; \ return; \
} \ } \
} while(0) } while(0)
static void _run_file(char* path) { static void _run_file(char* path) {
if(mb_load_file(bas, path) == MB_FUNC_OK) { if(mb_load_file(bas, path) == MB_FUNC_OK) {
mb_run(bas); mb_run(bas);
} else { } else {
printf("Invalid file or error code.\n"); _printf("Invalid file or error code.\n");
} }
} }
@ -690,7 +702,7 @@ static void _evaluate_expression(char* p) {
const char* const print = "PRINT "; const char* const print = "PRINT ";
if(!p) { if(!p) {
printf("Invalid expression.\n"); _printf("Invalid expression.\n");
return; return;
} }
@ -713,7 +725,7 @@ static void _evaluate_expression(char* p) {
if(mb_load_string(bas, p) == MB_FUNC_OK) { if(mb_load_string(bas, p) == MB_FUNC_OK) {
mb_run(bas); mb_run(bas);
} else { } else {
printf("Invalid expression.\n"); _printf("Invalid expression.\n");
} }
if(a) { if(a) {
free(e); free(e);
@ -732,7 +744,7 @@ static void _process_parameters(int argc, char* argv[]) {
_CHECK_ARG(argc, i, "-e: Expression expected.\n"); _CHECK_ARG(argc, i, "-e: Expression expected.\n");
p = argv[++i]; p = argv[++i];
} else { } else {
printf("Unknown argument: %s.\n", argv[i]); _printf("Unknown argument: %s.\n", argv[i]);
} }
} else { } else {
p = argv[i]; p = argv[i];
@ -742,21 +754,21 @@ static void _process_parameters(int argc, char* argv[]) {
} }
switch(m) { switch(m) {
case '\0': case '\0':
_run_file(p); _run_file(p);
break; break;
case 'e': case 'e':
_evaluate_expression(p); _evaluate_expression(p);
break; break;
} }
} }
/* ========================================================} */ /* ========================================================} */
/* /*
** {======================================================== ** {========================================================
** Scripting interfaces ** Scripting interfaces
*/ */
static int beep(struct mb_interpreter_t* s, void** l) { static int beep(struct mb_interpreter_t* s, void** l) {
int result = MB_FUNC_OK; int result = MB_FUNC_OK;
@ -774,9 +786,9 @@ static int beep(struct mb_interpreter_t* s, void** l) {
/* ========================================================} */ /* ========================================================} */
/* /*
** {======================================================== ** {========================================================
** Callbacks and handlers ** Callbacks and handlers
*/ */
static void _on_stepped(struct mb_interpreter_t* s, int p, unsigned short row, unsigned short col) { static void _on_stepped(struct mb_interpreter_t* s, int p, unsigned short row, unsigned short col) {
mb_unrefvar(s); mb_unrefvar(s);
@ -790,16 +802,16 @@ static void _on_error(struct mb_interpreter_t* s, mb_error_e e, char* m, char* f
mb_unrefvar(f); mb_unrefvar(f);
mb_unrefvar(p); mb_unrefvar(p);
if(SE_NO_ERR != e) { if(SE_NO_ERR != e) {
printf("Error:\n [LINE] %d, [COL] %d,\n [CODE] %d, [MESSAGE] %s, [ABORT CODE] %d.\n", row, col, e, m, abort_code); _printf("Error:\n [LINE] %d, [COL] %d,\n [CODE] %d, [MESSAGE] %s, [ABORT CODE] %d.\n", row, col, e, m, abort_code);
} }
} }
/* ========================================================} */ /* ========================================================} */
/* /*
** {======================================================== ** {========================================================
** Initialization and disposing ** Initialization and disposing
*/ */
static void _on_startup(void) { static void _on_startup(void) {
#ifdef _USE_MEM_POOL #ifdef _USE_MEM_POOL
@ -839,9 +851,9 @@ static void _on_exit(void) {
/* ========================================================} */ /* ========================================================} */
/* /*
** {======================================================== ** {========================================================
** Entry ** Entry
*/ */
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
int status = 0; int status = 0;
@ -862,10 +874,10 @@ int main(int argc, char* argv[]) {
} else if(argc >= 2) { } else if(argc >= 2) {
_process_parameters(argc, argv); _process_parameters(argc, argv);
} else { } else {
printf("Unknown arguments.\n"); _printf("Unknown arguments.\n");
_show_tip(); _show_tip();
} }
return 0; return 0;
} }