+added a duplicate sub routine error handling; +added optional argument support for INPUT statement; *fixed a variable multiple freeing bug in sub routine; *polished document.
This commit is contained in:
parent
3b7a983871
commit
c6d7dcae8f
17
HISTORY
17
HISTORY
@ -1,7 +1,14 @@
|
||||
Sep. 11 2015
|
||||
Added a duplicate sub routine error handling
|
||||
Added optional argument support for INPUT statement
|
||||
Fixed a variable multiple freeing bug in sub routine
|
||||
Polished document
|
||||
|
||||
Sep. 8 2015
|
||||
Fixed a type parsing of sub routine bug
|
||||
Fixed a scope processing bug
|
||||
Fixed a sub routine invoking bug without leading CALL statement or result receiver
|
||||
Added a makefile
|
||||
|
||||
Sep. 6 2015
|
||||
Improved sub routine
|
||||
@ -12,7 +19,7 @@ Prompted more friendly dummy function message
|
||||
Polished code and document
|
||||
|
||||
Sep. 1 2015
|
||||
Added support for user customized routine by DEF/ENDDEF
|
||||
Added support for user customized sub routine by DEF/ENDDEF
|
||||
|
||||
Aug. 26 2015
|
||||
Added a memory pool to interpreter shell in main.c
|
||||
@ -56,7 +63,7 @@ Changed mb_dispose_value as public
|
||||
|
||||
Apr. 23 2015 Version 1.1
|
||||
Added debug APIs
|
||||
Added (nestable) multi line IF statement support
|
||||
Added (nestable) multiple line IF statement support
|
||||
|
||||
Apr. 15 2015
|
||||
Added mb_pop_usertype, mb_push_usertype to support user defined type
|
||||
@ -102,12 +109,12 @@ Added an mb_remove_reserved_func function which allows a user to disable/remove
|
||||
|
||||
May. 22 2014
|
||||
Fixed a crash bug when missing colon in a combined line, thanks to Michael P. Welch for pointing it out
|
||||
Fixed a missing lexical cursor stepping bug in INPUT function
|
||||
Fixed a missing lexical cursor stepping bug in INPUT statement
|
||||
|
||||
Mar. 17 2014
|
||||
Added an XCode project
|
||||
Added a safe stdin reader function mb_gets
|
||||
Fixed a crash bug in INPUT function
|
||||
Fixed a crash bug in INPUT statement
|
||||
|
||||
Feb. 17 2014
|
||||
Added mod by zero processing
|
||||
@ -119,7 +126,7 @@ Jul. 19 2013
|
||||
Fixed a crash bug in _execute_statement, thanks to Jon Mayo for pointing it out
|
||||
|
||||
Feb. 25 2013
|
||||
Fixed a cross routine multi-statement execution bug, thanks to Bruce Kendall for pointing it out
|
||||
Fixed a cross routine multiple statement execution bug, thanks to Bruce Kendall for pointing it out
|
||||
Fixed a memory corruption bug when loading a script file
|
||||
|
||||
Jan. 9 2013
|
||||
|
24
README.md
24
README.md
@ -1,18 +1,18 @@
|
||||

|
||||
|
||||
Copyright (C) 2011 - 2015 [Wang Renxin](https://twitter.com/wangrenxin)
|
||||
Copyright (C) 2011 - 2015 [Wang Renxin](https://twitter.com/wangrenxin). All rights reserved.
|
||||
|
||||
[LinkedIn](https://cn.linkedin.com/pub/wang-renxin/43/494/20)
|
||||
|
||||
Why are existing script interpreters so complex? Why is it so difficult to integrate with them? Why not try MY-BASIC today!
|
||||
Why are existing script interpreters so complex? Why is it so difficult to integrate with them? Why not try MY-BASIC today! Scripting should be simple and enjoyable.
|
||||
|
||||
## Introduction
|
||||
|
||||
MY-BASIC is a tiny cross-platform easy extendable BASIC interpreter written in pure C with about 7000 lines of source code. Its grammar is similar to structured BASIC. 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, etc. project easily, scripting driven can make your projects more powerful, elegant and neat.
|
||||
MY-BASIC is a tiny cross-platform easy extendable BASIC interpreter written in pure C with about 7000 lines of source code. Its grammar is similar to structured BASIC. 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 are able to easily combine MY-BASIC with an existing project in C, C++, Objective-C, etc. Scripting driven can make your projects more powerful, elegant and neat.
|
||||
|
||||
## Main features
|
||||
|
||||
* It is free
|
||||
* It is totally free to use MY-BASIC for individual or commercial purpose under the MIT license
|
||||
* Written in clean ANSI C, source code portable
|
||||
* With most common BASIC syntax
|
||||
* Small (within memory usage less than 128KB) and fast
|
||||
@ -26,11 +26,23 @@ MY-BASIC is a tiny cross-platform easy extendable BASIC interpreter written in p
|
||||
* Standard string functions
|
||||
* Debug APIs
|
||||
* High expansibility, easy to use APIs, easy to write customized scripting interfaces
|
||||
* It's able to use it as a standalone interpreter, or integrate it with existing C, C++, Objective-C, etc. projects
|
||||
* It's able to use it as a standalone interpreter, or integrate it with existing projects in C, C++, Objective-C, etc.
|
||||
* It's able to learn how to build an interpreter from scratch from MY-BASIC
|
||||
* It's able to build your own dialect based on MY-BASIC
|
||||
* More features/modules under developing
|
||||
|
||||
## Scripting at a glance
|
||||
|
||||
Come along with a traditional "hello world" script in MY-BASIC:
|
||||
|
||||
def foo(a, b)
|
||||
print a + " " + b;
|
||||
enddef
|
||||
|
||||
foo("Hello", "world!")
|
||||
|
||||
input
|
||||
|
||||
## [Interpreter workflow diagram](https://github.com/paladin-t/my_basic/wiki/Interpreter-workflow-diagram)
|
||||
|
||||

|
||||
@ -57,7 +69,7 @@ You can definitely [link with MY-BASIC as a lib](https://github.com/paladin-t/my
|
||||
|
||||
For more details about using MY-BASIC when it's already integrated with exist projects, please see [MY-BASIC Quick Reference](MY-BASIC%20Quick%20Reference.pdf).
|
||||
|
||||
## [WIKI](https://github.com/paladin-t/my_basic/wiki)
|
||||
## [Wiki](https://github.com/paladin-t/my_basic/wiki)
|
||||
|
||||
* [Passes](https://github.com/paladin-t/my_basic/wiki/Passes)
|
||||
* [Interpreter workflow diagram](https://github.com/paladin-t/my_basic/wiki/Interpreter-workflow-diagram)
|
||||
|
160
core/my_basic.c
160
core/my_basic.c
@ -52,6 +52,7 @@ extern "C" {
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4127)
|
||||
# pragma warning(disable : 4305)
|
||||
# pragma warning(disable : 4996)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef __APPLE__
|
||||
@ -78,7 +79,7 @@ extern "C" {
|
||||
/** Macros */
|
||||
#define _VER_MAJOR 1
|
||||
#define _VER_MINOR 1
|
||||
#define _VER_REVISION 68
|
||||
#define _VER_REVISION 69
|
||||
#define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION))
|
||||
|
||||
/* Uncomment the line below to treat warning as error */
|
||||
@ -211,6 +212,7 @@ static const char* _ERR_DESC[] = {
|
||||
"Don't suspend in a routine",
|
||||
"Don't mix instructional and structured sub routines",
|
||||
"Routine expected",
|
||||
"Duplicate routine",
|
||||
/** Extended abort */
|
||||
"Extended abort"
|
||||
};
|
||||
@ -365,6 +367,7 @@ typedef struct _parsing_context_t {
|
||||
_object_t* last_symbol;
|
||||
_parsing_state_e parsing_state;
|
||||
_symbol_state_e symbol_state;
|
||||
unsigned short class_state;
|
||||
unsigned short routine_state;
|
||||
unsigned short routine_params_state;
|
||||
int parsing_pos;
|
||||
@ -776,7 +779,9 @@ static bool_t _is_array(void* obj);
|
||||
static bool_t _is_string(void* obj);
|
||||
static char* _extract_string(_object_t* obj);
|
||||
|
||||
static void _init_instance(mb_interpreter_t* s, _class_t* instance, char* n);
|
||||
static void _init_class(mb_interpreter_t* s, _class_t* instance, char* n);
|
||||
static void _begin_class(mb_interpreter_t* s);
|
||||
static void _end_class(mb_interpreter_t* s);
|
||||
static void _init_routine(mb_interpreter_t* s, _routine_t* routine, char* n);
|
||||
static void _begin_routine(mb_interpreter_t* s);
|
||||
static void _end_routine(mb_interpreter_t* s);
|
||||
@ -843,11 +848,21 @@ static int _close_std_lib(mb_interpreter_t* s);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# if _MSC_VER < 1300
|
||||
# define _do_nothing(__s, __l, __exit, __result) do { static int i = 0; ++i; printf("Unaccessable function called %d times\n", i); mb_unrefvar(__s); mb_unrefvar(__l); mb_unrefvar(__result); goto _exit; } while(0)
|
||||
# define _do_nothing(__s, __l, __exit, __result) \
|
||||
do { \
|
||||
_ls_node_t* ast = 0; static int i = 0; ++i; \
|
||||
printf("Unaccessable function called %d times\n", i); \
|
||||
ast = (_ls_node_t*)(*(__l)); \
|
||||
_handle_error_on_obj((__s), SE_RN_WRONG_FUNCTION_REACHED, 0, DON(ast), MB_FUNC_ERR, __exit, __result); \
|
||||
} while(0)
|
||||
# endif /* _MSC_VER < 1300 */
|
||||
#endif /* _MSC_VER */
|
||||
#ifndef _do_nothing
|
||||
# define _do_nothing(__s, __l, __exit, __result) do { _ls_node_t* ast = (_ls_node_t*)(*(__l)); _handle_error_on_obj((__s), SE_RN_WRONG_FUNCTION_REACHED, (char*)MB_FUNC, DON(ast), MB_FUNC_ERR, __exit, __result); } while(0);
|
||||
# define _do_nothing(__s, __l, __exit, __result) \
|
||||
do { \
|
||||
_ls_node_t* ast = (_ls_node_t*)(*(__l)); \
|
||||
_handle_error_on_obj((__s), SE_RN_WRONG_FUNCTION_REACHED, (char*)MB_FUNC, DON(ast), MB_FUNC_ERR, __exit, __result); \
|
||||
} while(0);
|
||||
#endif /* _do_nothing */
|
||||
|
||||
/** Core lib */
|
||||
@ -1971,6 +1986,7 @@ int _eval_routine(mb_interpreter_t* s, _ls_node_t** l, _routine_t* r) {
|
||||
_pop_scope(s);
|
||||
|
||||
result = _public_value_to_internal_object(&arg, var->data);
|
||||
var->data->ref = true;
|
||||
if(result != MB_FUNC_OK)
|
||||
goto _exit;
|
||||
}
|
||||
@ -2302,9 +2318,15 @@ int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** ob
|
||||
(*obj)->data.instance = ((_object_t*)(glbsyminscope->data))->data.instance;
|
||||
(*obj)->ref = true;
|
||||
*delsym = true;
|
||||
if(running != (*obj)->data.instance->scope &&
|
||||
context->class_state &&
|
||||
_IS_FUNC(context->last_symbol, _core_class)) {
|
||||
_push_scope(s, (*obj)->data.instance->scope);
|
||||
}
|
||||
} else {
|
||||
tmp.instance = (_class_t*)mb_malloc(sizeof(_class_t));
|
||||
_init_instance(s, tmp.instance, sym);
|
||||
_init_class(s, tmp.instance, sym);
|
||||
_push_scope(s, tmp.instance->scope);
|
||||
(*obj)->data.instance = tmp.instance;
|
||||
|
||||
ul = _ht_set_or_insert(running->var_dict, sym, *obj);
|
||||
@ -2492,23 +2514,43 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, _raw_t* value) {
|
||||
goto _exit;
|
||||
}
|
||||
/* _class_t */
|
||||
if(context->last_symbol && _IS_FUNC(context->last_symbol, _core_class)) {
|
||||
if(context->last_symbol) {
|
||||
glbsyminscope = _search_var_in_scope_chain(s, 0, sym);
|
||||
if(glbsyminscope && ((_object_t*)(glbsyminscope->data))->type == _DT_VAR) {
|
||||
tmp.obj = (_object_t*)(glbsyminscope->data);
|
||||
if(!tmp.obj->ref) {
|
||||
_ht_remove(running->var_dict, sym, _ls_cmp_extra_string);
|
||||
_dispose_object(tmp.obj);
|
||||
}
|
||||
tmp.obj->type = _DT_CLASS;
|
||||
tmp.obj->data.instance = (_class_t*)mb_malloc(sizeof(_class_t));
|
||||
_init_instance(s, tmp.obj->data.instance, sym);
|
||||
_ht_set_or_insert(running->var_dict, sym, tmp.obj);
|
||||
if(glbsyminscope && ((_object_t*)glbsyminscope->data)->type == _DT_CLASS) {
|
||||
if(_IS_FUNC(context->last_symbol, _core_class))
|
||||
_begin_class(s);
|
||||
result = _DT_CLASS;
|
||||
|
||||
goto _exit;
|
||||
}
|
||||
if(_IS_FUNC(context->last_symbol, _core_class)) {
|
||||
if(_IS_FUNC(context->last_symbol, _core_class))
|
||||
_begin_class(s);
|
||||
if(!_is_identifier_char(sym[0])) {
|
||||
result = _DT_NIL;
|
||||
|
||||
result = _DT_CLASS;
|
||||
goto _exit;
|
||||
}
|
||||
if(glbsyminscope && ((_object_t*)(glbsyminscope->data))->type == _DT_VAR) {
|
||||
tmp.obj = (_object_t*)(glbsyminscope->data);
|
||||
if(!tmp.obj->ref) {
|
||||
_ht_remove(running->var_dict, sym, _ls_cmp_extra_string);
|
||||
_dispose_object(tmp.obj);
|
||||
}
|
||||
tmp.obj->type = _DT_CLASS;
|
||||
tmp.obj->data.instance = (_class_t*)mb_malloc(sizeof(_class_t));
|
||||
_init_class(s, tmp.obj->data.instance, sym);
|
||||
_init_class(s, tmp.obj->data.instance, sym);
|
||||
_ht_set_or_insert(running->var_dict, sym, tmp.obj);
|
||||
}
|
||||
|
||||
goto _exit;
|
||||
result = _DT_CLASS;
|
||||
|
||||
goto _exit;
|
||||
} else if(_IS_FUNC(context->last_symbol, _core_endclass)) {
|
||||
_end_class(s);
|
||||
_pop_scope(s);
|
||||
}
|
||||
}
|
||||
/* _routine_t */
|
||||
if(context->last_symbol) {
|
||||
@ -3108,14 +3150,39 @@ char* _extract_string(_object_t* obj) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void _init_instance(mb_interpreter_t* s, _class_t* instance, char* n) {
|
||||
void _init_class(mb_interpreter_t* s, _class_t* instance, char* n) {
|
||||
/* Initialize an instance */
|
||||
_running_context_t* running = 0;
|
||||
|
||||
mb_assert(s && instance && n);
|
||||
|
||||
running = s->running_context;
|
||||
|
||||
memset(instance, 0, sizeof(_class_t));
|
||||
instance->name = n;
|
||||
instance->scope = (_running_context_t*)mb_malloc(sizeof(_running_context_t));
|
||||
memset(instance->scope, 0, sizeof(_running_context_t));
|
||||
instance->scope->var_dict = _ht_create(0, _ht_cmp_string, _ht_hash_string, 0);
|
||||
}
|
||||
|
||||
void _begin_class(mb_interpreter_t* s) {
|
||||
/* Begin parsing a class */
|
||||
_parsing_context_t* context = 0;
|
||||
|
||||
mb_assert(s);
|
||||
|
||||
context = s->parsing_context;
|
||||
context->class_state++;
|
||||
}
|
||||
|
||||
void _end_class(mb_interpreter_t* s) {
|
||||
/* End parsing a class */
|
||||
_parsing_context_t* context = 0;
|
||||
|
||||
mb_assert(s);
|
||||
|
||||
context = s->parsing_context;
|
||||
context->class_state--;
|
||||
}
|
||||
|
||||
void _init_routine(mb_interpreter_t* s, _routine_t* routine, char* n) {
|
||||
@ -3279,6 +3346,16 @@ int _dispose_object(_object_t* obj) {
|
||||
safe_free(obj->data.label);
|
||||
}
|
||||
|
||||
break;
|
||||
case _DT_CLASS:
|
||||
if(!obj->ref) {
|
||||
safe_free(obj->data.instance->name);
|
||||
_ht_foreach(obj->data.instance->scope->var_dict, _destroy_object);
|
||||
_ht_destroy(obj->data.instance->scope->var_dict);
|
||||
safe_free(obj->data.instance->scope);
|
||||
safe_free(obj->data.instance);
|
||||
}
|
||||
|
||||
break;
|
||||
case _DT_ROUTINE:
|
||||
if(!obj->ref) {
|
||||
@ -3291,13 +3368,6 @@ int _dispose_object(_object_t* obj) {
|
||||
safe_free(obj->data.routine);
|
||||
}
|
||||
|
||||
break;
|
||||
case _DT_CLASS:
|
||||
if(!obj->ref) {
|
||||
safe_free(obj->data.instance->scope);
|
||||
safe_free(obj->data.instance);
|
||||
}
|
||||
|
||||
break;
|
||||
case _DT_NIL: /* Fall through */
|
||||
case _DT_ANY: /* Fall through */
|
||||
@ -3599,6 +3669,10 @@ int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) {
|
||||
case _DT_STRING:
|
||||
_handle_error_on_obj(s, SE_RN_INVALID_EXPRESSION, 0, DON(ast), MB_FUNC_ERR, _exit, result);
|
||||
|
||||
break;
|
||||
case _DT_CLASS:
|
||||
mb_assert(0 && "Not implemented");
|
||||
|
||||
break;
|
||||
case _DT_ROUTINE:
|
||||
ast = ast->prev;
|
||||
@ -6161,6 +6235,7 @@ int _core_def(mb_interpreter_t* s, void** l) {
|
||||
/* DEF statement */
|
||||
int result = MB_FUNC_OK;
|
||||
_ls_node_t* ast = 0;
|
||||
_running_context_t* running = 0;
|
||||
_object_t* obj = 0;
|
||||
_var_t* var = 0;
|
||||
_ls_node_t* rnode = 0;
|
||||
@ -6168,6 +6243,8 @@ int _core_def(mb_interpreter_t* s, void** l) {
|
||||
|
||||
mb_assert(s && l);
|
||||
|
||||
running = s->running_context;
|
||||
|
||||
ast = (_ls_node_t*)(*l);
|
||||
ast = ast->next;
|
||||
|
||||
@ -6177,6 +6254,9 @@ int _core_def(mb_interpreter_t* s, void** l) {
|
||||
if(!_IS_ROUTINE(obj)) {
|
||||
_handle_error_on_obj(s, SE_RN_ROUTINE_EXPECTED, 0, DON(ast), MB_FUNC_ERR, _exit, result);
|
||||
}
|
||||
if(obj->data.routine->entry) {
|
||||
_handle_error_on_obj(s, SE_RN_DUPLICATE_ROUTINE, 0, DON(ast), MB_FUNC_ERR, _exit, result);
|
||||
}
|
||||
routine = (_routine_t*)(((_object_t*)(ast->data))->data.routine);
|
||||
ast = ast->next;
|
||||
obj = (_object_t*)(ast->data);
|
||||
@ -6233,17 +6313,32 @@ _exit:
|
||||
}
|
||||
|
||||
int _core_class(mb_interpreter_t* s, void** l) {
|
||||
/* OBJ statement */
|
||||
/* CLASS statement */
|
||||
int result = MB_FUNC_OK;
|
||||
_ls_node_t* ast = 0;
|
||||
_running_context_t* running = 0;
|
||||
|
||||
_do_nothing(s, l, _exit, result);
|
||||
mb_assert(s && l);
|
||||
|
||||
running = s->running_context;
|
||||
|
||||
ast = (_ls_node_t*)(*l);
|
||||
ast = ast->next;
|
||||
|
||||
_using_jump_set_of_structured(s, ast, _exit, result);
|
||||
|
||||
_skip_to(s, &ast, _core_endclass, _DT_NIL);
|
||||
|
||||
ast = ast->next;
|
||||
|
||||
_exit:
|
||||
*l = ast;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int _core_endclass(mb_interpreter_t* s, void** l) {
|
||||
/* ENDOBJ statement */
|
||||
/* ENDCLASS statement */
|
||||
int result = MB_FUNC_OK;
|
||||
|
||||
_do_nothing(s, l, _exit, result);
|
||||
@ -7132,7 +7227,12 @@ int _std_input(mb_interpreter_t* s, void** l) {
|
||||
ast = (_ls_node_t*)(*l);
|
||||
obj = (_object_t*)(ast->data);
|
||||
|
||||
if(!obj || obj->type != _DT_VAR) {
|
||||
if(!obj || obj->type == _DT_EOS) {
|
||||
_get_inputer(s)(line, sizeof(line));
|
||||
|
||||
goto _exit;
|
||||
}
|
||||
if(obj->type != _DT_VAR) {
|
||||
_handle_error_on_obj(s, SE_RN_VARIABLE_EXPECTED, 0, DON(ast), MB_FUNC_ERR, _exit, result);
|
||||
}
|
||||
if(obj->data.variable->data->type == _DT_INT || obj->data.variable->data->type == _DT_REAL) {
|
||||
|
@ -219,6 +219,7 @@ typedef enum mb_error_e {
|
||||
SE_RN_DONT_SUSPEND_IN_A_ROUTINE,
|
||||
SE_RN_DONT_MIX_INSTRUCTIONAL_AND_STRUCTURED,
|
||||
SE_RN_ROUTINE_EXPECTED,
|
||||
SE_RN_DUPLICATE_ROUTINE,
|
||||
/** Extended abort */
|
||||
SE_EA_EXTENDED_ABORT,
|
||||
/** Extra */
|
||||
|
4
makefile
Normal file → Executable file
4
makefile
Normal file → Executable file
@ -5,7 +5,7 @@ main.o : shell/main.c core/my_basic.h
|
||||
cc -Os -c shell/main.c
|
||||
|
||||
my_basic.o : core/my_basic.c core/my_basic.h
|
||||
cc -Os -c core/my_basic.c
|
||||
cc -Os -c core/my_basic.c -Wno-multichar -Wno-overflow
|
||||
|
||||
clean :
|
||||
rm edit $(objects)
|
||||
rm -f main.o my_basic.o output/my_basic_bin output/my_basic_bin.exe
|
||||
|
Binary file not shown.
Binary file not shown.
@ -36,8 +36,8 @@
|
||||
IDI_ICON_MAIN ICON "icon.ico"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,1,68,0
|
||||
PRODUCTVERSION 1,1,68,0
|
||||
FILEVERSION 1,1,69,0
|
||||
PRODUCTVERSION 1,1,69,0
|
||||
FILEFLAGSMASK 0x17L
|
||||
# ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -55,13 +55,13 @@
|
||||
VALUE "Comments", "MY-BASIC"
|
||||
VALUE "CompanyName", "Wang Renxin"
|
||||
VALUE "FileDescription", "MY-BASIC Interpreter for Windows"
|
||||
VALUE "FileVersion", "1, 1, 68, 0"
|
||||
VALUE "FileVersion", "1, 1, 69, 0"
|
||||
VALUE "InternalName", "my_basic"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2011 - 2015 Wang Renxin"
|
||||
VALUE "LegalTrademarks", "MY-BASIC"
|
||||
VALUE "OriginalFilename", "my_basic.exe"
|
||||
VALUE "ProductName", "MY-BASIC"
|
||||
VALUE "ProductVersion", "1, 1, 68, 0"
|
||||
VALUE "ProductVersion", "1, 1, 69, 0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
Loading…
x
Reference in New Issue
Block a user