+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:
parent
a956338ec0
commit
b6ab676ad7
8
HISTORY
8
HISTORY
@ -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.
130
core/my_basic.c
130
core/my_basic.c
@ -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.
@ -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"
|
||||||
|
238
shell/main.c
238
shell/main.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user