diff --git a/HISTORY b/HISTORY index 0681834..d355df2 100755 --- a/HISTORY +++ b/HISTORY @@ -1,3 +1,8 @@ +Mar. 25 2015 +Changed _strupr macro to mb_strupr function +Added an mb_strdup function +Fixed an intermediate value disposing more than once bug + Dec. 17 2014 Fixed a calculation crash bug Fixed a memory leak with intermediate value @@ -9,8 +14,8 @@ Dec. 9 2014 Improved compatibility with BCB May. 25 2014 -Added a mb_set_inputer function which allows the user to specify an INPUT reader, thanks to Michael P. Welch for suggestion -Added a mb_remove_reserved_func function which allows the user to disable/remove a reserved statement +Added an mb_set_inputer function which allows the user to specify an INPUT reader, thanks to Michael P. Welch for suggestion +Added an mb_remove_reserved_func function which allows the user to disable/remove a reserved statement May. 22 2014 Fixed a crash bug when missing colon in a combined line, thanks to Michael P. Welch for pointing it out diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 index 14006e8..73ceea8 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2011 - 2014 W. Renxin +Copyright (c) 2011 - 2015 W. Renxin 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 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index bdec206..ffdb731 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![](resource/icon.ico) -Copyright (C) 2011 - 2014 W. Renxin +Copyright (C) 2011 - 2015 W. Renxin ## Introduction MY-BASIC is a tiny cross-platform easy extendable BASIC interpreter written in pure C with about 6000 lines of source code. Its grammar is similar to structured BASIC in early era, but without line number. It is aimed to be either an embeddable scripting language or a standalone interpreter. The core is pretty light; all in a C source file and an associated header file. You can combine MY-BASIC with an existing C/C++/Objective-C project easily, scripting driven can make your projects more powerful, elegant and neat. diff --git a/core/my_basic.c b/core/my_basic.c index 07bb8ee..cb329c1 100755 --- a/core/my_basic.c +++ b/core/my_basic.c @@ -3,7 +3,7 @@ ** ** For the latest info, see https://github.com/paladin-t/my_basic/ ** -** Copyright (C) 2011 - 2014 W. Renxin +** Copyright (C) 2011 - 2015 W. Renxin ** ** 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 @@ -78,7 +78,7 @@ extern "C" { /** Macros */ #define _VER_MAJOR 1 #define _VER_MINOR 0 -#define _VER_REVISION 45 +#define _VER_REVISION 46 #define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION)) /* Uncomment this line to treat warnings as error */ @@ -110,21 +110,6 @@ extern "C" { # define toupper(__c) ((islower(__c)) ? ((__c) - 'a' + 'A') : (__c)) #endif /* toupper */ -#ifndef _MSC_VER -# ifndef _strupr - static char* _strupr(char* __s) { - char* t = __s; - - while(*__s) { - *__s = toupper(*__s); - ++__s; - } - - return t; - } -# endif /* _strupr */ -#endif /* _MSC_VER */ - #define DON(__o) ((__o) ? ((_object_t*)((__o)->data)) : 0) /* Hash table size */ @@ -545,6 +530,32 @@ static void _ls_clear(_ls_node_t* list); static void _ls_destroy(_ls_node_t* list); static int _ls_free_extra(void* data, void* extra); +#define _LS_FOREACH(L, O, P, E) \ + do { \ + _ls_node_t* __lst = L; \ + int __opresult = _OP_RESULT_NORMAL; \ + _ls_node_t* __tmp = 0; \ + mb_assert(L && O); \ + __lst = __lst->next; \ + while(__lst) { \ + if(P != 0) { \ + P(__lst->data, __lst->extra, E); \ + } \ + __opresult = O(__lst->data, __lst->extra); \ + __tmp = __lst; \ + __lst = __lst->next; \ + if(_OP_RESULT_NORMAL == __opresult) { \ + } else if(_OP_RESULT_DEL_NODE == __opresult) { \ + __tmp->prev->next = __lst; \ + if(__lst) { \ + __lst->prev = __tmp->prev; \ + } \ + safe_free(__tmp); \ + } else { \ + } \ + } \ + } while(0) + /** Dictionary */ static unsigned int _ht_hash_string(void* ht, void* d); static unsigned int _ht_hash_int(void* ht, void* d); @@ -583,6 +594,8 @@ static void* mb_malloc(size_t s); static void* mb_realloc(void** p, size_t s); static void mb_free(void* p); +static char* mb_strupr(char* s); + #define safe_free(__p) do { if(__p) { mb_free(__p); __p = 0; } else { mb_assert(0 && "Memory already released"); } } while(0) /** Expression processing */ @@ -668,6 +681,7 @@ static int _remove_source_object(void* data, void* extra); static int _compare_numbers(const _object_t* first, const _object_t* second); 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 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); @@ -1531,6 +1545,17 @@ void mb_free(void* p) { free(p); } +char* mb_strupr(char* s) { + char* t = s; + + while(*s) { + *s = toupper(*s); + ++s; + } + + return t; +} + /** Expression processing */ bool_t _is_operator(mb_func_t op) { /* Determine whether a function is an operator */ @@ -1939,11 +1964,13 @@ int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { } } if(guard_val != c && _ls_try_remove(garbage, c, _ls_cmp_data, NULL)) { + _try_clear_intermediate_value(c, 0, s); + _destroy_object(c, 0); } _exit: - _ls_foreach(garbage, _destroy_object); + _LS_FOREACH(garbage, _destroy_object, _try_clear_intermediate_value, s); _ls_destroy(garbage); _ls_foreach(optr, _destroy_object_non_syntax); _ls_foreach(opnd, _destroy_object_non_syntax); @@ -2983,6 +3010,24 @@ int _internal_object_to_public_value(_object_t* itn, mb_value_t* pbl) { return result; } +void _try_clear_intermediate_value(void* data, void* extra, mb_interpreter_t* s) { + /* Try clear the intermediate value when destroying an object */ + _object_t* obj = 0; + _running_context_t* running = 0; + + mb_assert(s); + + if(data == 0) + return; + + obj = (_object_t*)data; + running = (_running_context_t*)(s->running_context); + + if(obj->type == _DT_STRING && running->intermediate_value.type == MB_DT_STRING && obj->data.string == running->intermediate_value.value.string) { + running->intermediate_value.type = MB_DT_NIL; + } +} + int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) { /* Execute the ast, core execution function */ int result = MB_FUNC_OK; @@ -3130,7 +3175,7 @@ int _register_func(mb_interpreter_t* s, const char* n, mb_func_t f, bool_t local size_t _sl = strlen(n); name = (char*)mb_malloc(_sl + 1); memcpy(name, n, _sl + 1); - _strupr(name); + mb_strupr(name); result += _ht_set_or_insert(scope, (void*)name, (void*)(intptr_t)f); } else { _set_current_error(s, SE_CM_FUNC_EXISTS); @@ -3158,7 +3203,7 @@ int _remove_func(mb_interpreter_t* s, const char* n, bool_t local) { size_t _sl = strlen(n); name = (char*)mb_malloc(_sl + 1); memcpy(name, n, _sl + 1); - _strupr(name); + mb_strupr(name); result += _ht_remove(scope, (void*)name, _ls_cmp_extra_string); safe_free(name); } else { @@ -4025,6 +4070,18 @@ int mb_gets(char* buf, int s) { return result; } +char* mb_strdup(char* val, unsigned size) { + /* Duplicate a string for internal use */ + char* result = 0; + + if(val != 0) { + result = (char*)mb_malloc(size); + memcpy(result, val, size); + } + + return result; +} + /* ========================================================} */ /* diff --git a/core/my_basic.h b/core/my_basic.h index 65aa68d..a0174c5 100755 --- a/core/my_basic.h +++ b/core/my_basic.h @@ -3,7 +3,7 @@ ** ** For the latest info, see https://github.com/paladin-t/my_basic/ ** -** Copyright (C) 2011 - 2014 W. Renxin +** Copyright (C) 2011 - 2015 W. Renxin ** ** 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 @@ -252,6 +252,8 @@ MBAPI int mb_set_inputer(mb_interpreter_t* s, mb_input_func_t p); MBAPI int mb_gets(char* buf, int s); +MBAPI char* mb_strdup(char* val, unsigned size); + #ifdef MB_COMPACT_MODE # pragma pack() #endif /* MB_COMPACT_MODE */ diff --git a/output/my_basic.exe b/output/my_basic.exe index ec874b1..740a3fc 100755 Binary files a/output/my_basic.exe and b/output/my_basic.exe differ diff --git a/output/my_basic_mac b/output/my_basic_mac old mode 100644 new mode 100755 index 3fd4de8..c09e1ff Binary files a/output/my_basic_mac and b/output/my_basic_mac differ diff --git a/resource/icon.ico b/resource/icon.ico old mode 100644 new mode 100755 diff --git a/resource/my_basic.aps b/resource/my_basic.aps old mode 100644 new mode 100755 diff --git a/resource/my_basic.rc b/resource/my_basic.rc index 8abc5cd..1de3c05 100755 --- a/resource/my_basic.rc +++ b/resource/my_basic.rc @@ -81,13 +81,13 @@ BEGIN VALUE "Comments", "MY-BASIC" VALUE "CompanyName", "W. Renxin" VALUE "FileDescription", "MY-BASIC interpreter" - VALUE "FileVersion", "1, 0, 0, 45" + VALUE "FileVersion", "1, 0, 0, 46" VALUE "InternalName", "my_basic" - VALUE "LegalCopyright", "Copyright (C) 2011 - 2014 W. Renxin" + 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, 45" + VALUE "ProductVersion", "1, 0, 0, 46" END END BLOCK "VarFileInfo" diff --git a/resource/resource.h b/resource/resource.h old mode 100644 new mode 100755 diff --git a/sample/sample01.bas b/sample/sample01.bas old mode 100644 new mode 100755 index 6c8d63b..73a14c9 --- a/sample/sample01.bas +++ b/sample/sample01.bas @@ -1,5 +1,5 @@ ' This script is an example of MY-BASIC -' Copyright (c) 2011 - 2014 W. Renxin. All rights reserved. +' Copyright (c) 2011 - 2015 W. Renxin. All rights reserved. ' For more information, see https://github.com/paladin-t/my_basic/ s$ = "hello " diff --git a/sample/sample02.bas b/sample/sample02.bas old mode 100644 new mode 100755 index a4a303a..2f6fa0b --- a/sample/sample02.bas +++ b/sample/sample02.bas @@ -1,5 +1,5 @@ ' This script is an example of MY-BASIC -' Copyright (c) 2011 - 2014 W. Renxin. All rights reserved. +' Copyright (c) 2011 - 2015 W. Renxin. All rights reserved. ' For more information, see https://github.com/paladin-t/my_basic/ e = 50 diff --git a/sample/sample03.bas b/sample/sample03.bas old mode 100644 new mode 100755 index 6019567..57847a9 --- a/sample/sample03.bas +++ b/sample/sample03.bas @@ -1,5 +1,5 @@ ' This script is an example of MY-BASIC -' Copyright (c) 2011 - 2014 W. Renxin. All rights reserved. +' Copyright (c) 2011 - 2015 W. Renxin. All rights reserved. ' For more information, see https://github.com/paladin-t/my_basic/ PRINT "Input: " diff --git a/sample/sample04.bas b/sample/sample04.bas old mode 100644 new mode 100755 index a2d4a16..0bc2466 --- a/sample/sample04.bas +++ b/sample/sample04.bas @@ -1,5 +1,5 @@ ' This script is an example of MY-BASIC -' Copyright (c) 2011 - 2014 W. Renxin. All rights reserved. +' Copyright (c) 2011 - 2015 W. Renxin. All rights reserved. ' For more information, see https://github.com/paladin-t/my_basic/ BEGIN: diff --git a/shell/main.c b/shell/main.c index 98cfa0a..15fdc5f 100755 --- a/shell/main.c +++ b/shell/main.c @@ -3,7 +3,7 @@ ** ** For the latest info, see https://github.com/paladin-t/my_basic/ ** -** Copyright (C) 2011 - 2014 W. Renxin +** Copyright (C) 2011 - 2015 W. Renxin ** ** 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 @@ -331,7 +331,7 @@ static void _kill_program(const char* path) { static void _show_tip(void) { printf("MY-BASIC Interpreter Shell - %s.\n", mb_ver_string()); - printf("Copyright (C) 2011 - 2014 W. Renxin. All Rights Reserved.\n"); + printf("Copyright (C) 2011 - 2015 W. Renxin. All Rights Reserved.\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"); }