Fixed a double precision float parsing bug on all 32bit systems, thanks to Pito for pointing it out; Fixed a exponential number parsing bug, thanks to Pito for pointing it out; Fixed a crash bug when a script begins with a meaningless negtive number.
This commit is contained in:
parent
eb5cd615ce
commit
e872d26513
6
HISTORY
6
HISTORY
@ -1,3 +1,9 @@
|
||||
Apr. 10 2015
|
||||
Improved compatibility with PellesC
|
||||
Fixed a double precision float parsing bug on all 32bit systems, thanks to Pito for pointing it out
|
||||
Fixed a exponential number parsing bug, thanks to Pito for pointing it out
|
||||
Fixed a crash bug when a script begins with a meaningless negtive number
|
||||
|
||||
Mar. 25 2015
|
||||
Changed _strupr macro to mb_strupr function
|
||||
Added an mb_strdup function
|
||||
|
@ -78,7 +78,7 @@ extern "C" {
|
||||
/** Macros */
|
||||
#define _VER_MAJOR 1
|
||||
#define _VER_MINOR 0
|
||||
#define _VER_REVISION 46
|
||||
#define _VER_REVISION 47
|
||||
#define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION))
|
||||
|
||||
/* Uncomment this line to treat warnings as error */
|
||||
@ -258,6 +258,8 @@ typedef struct _label_t {
|
||||
_ls_node_t* node;
|
||||
} _label_t;
|
||||
|
||||
typedef unsigned char _raw_t[sizeof(union { int_t i; real_t r; void* p; })];
|
||||
|
||||
typedef struct _object_t {
|
||||
_data_e type;
|
||||
union {
|
||||
@ -270,6 +272,7 @@ typedef struct _object_t {
|
||||
_array_t* array;
|
||||
_label_t* label;
|
||||
char separator;
|
||||
_raw_t raw;
|
||||
} data;
|
||||
bool_t ref;
|
||||
int source_pos;
|
||||
@ -594,6 +597,8 @@ static void* mb_malloc(size_t s);
|
||||
static void* mb_realloc(void** p, size_t s);
|
||||
static void mb_free(void* p);
|
||||
|
||||
static size_t mb_memtest(void*p, size_t s);
|
||||
|
||||
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)
|
||||
@ -656,7 +661,7 @@ static int _append_char_to_symbol(mb_interpreter_t* s, char c);
|
||||
static int _cut_symbol(mb_interpreter_t* s, int pos, unsigned short row, unsigned short col);
|
||||
static int _append_symbol(mb_interpreter_t* s, char* sym, bool_t* delsym, int pos, unsigned short row, unsigned short col);
|
||||
static int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** obj, _ls_node_t*** asgn, bool_t* delsym);
|
||||
static _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value);
|
||||
static _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, _raw_t* value);
|
||||
|
||||
static int _parse_char(mb_interpreter_t* s, char c, int pos, unsigned short row, unsigned short col);
|
||||
static void _set_error_pos(mb_interpreter_t* s, int pos, unsigned short row, unsigned short col);
|
||||
@ -722,6 +727,8 @@ MBAPI int mb_dispose_value(mb_interpreter_t* s, mb_value_t val);
|
||||
# endif /* _MSC_VER < 1300 */
|
||||
#elif defined __BORLANDC__
|
||||
# define _do_nothing do { printf("Unaccessable function: %s\n", __FUNC__); } while(0)
|
||||
#elif defined __POCC__
|
||||
# define _do_nothing do { printf("Unaccessable function: %s\n", __func__); } while(0)
|
||||
#else /* _MSC_VER */
|
||||
# define _do_nothing do { printf("Unaccessable function: %s\n", __FUNCTION__); } while(0)
|
||||
#endif /* _MSC_VER */
|
||||
@ -1545,6 +1552,16 @@ void mb_free(void* p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
size_t mb_memtest(void*p, size_t s) {
|
||||
size_t result = 0;
|
||||
size_t i = 0;
|
||||
for(i = 0; i < s; i++) {
|
||||
result += ((unsigned char*)p)[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
char* mb_strupr(char* s) {
|
||||
char* t = s;
|
||||
|
||||
@ -2165,8 +2182,8 @@ int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** ob
|
||||
/* Create a syntax symbol */
|
||||
int result = MB_FUNC_OK;
|
||||
_data_e type;
|
||||
union { _func_t* func; _array_t* array; _var_t* var; _label_t* label; real_t float_point; int_t integer; void* any; } tmp;
|
||||
void* value = 0;
|
||||
union { _func_t* func; _array_t* array; _var_t* var; _label_t* label; real_t float_point; int_t integer; _raw_t any; } tmp;
|
||||
_raw_t value;
|
||||
unsigned int ul = 0;
|
||||
_parsing_context_t* context = 0;
|
||||
_ls_node_t* glbsyminscope = 0;
|
||||
@ -2174,6 +2191,8 @@ int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** ob
|
||||
|
||||
mb_assert(s && sym && obj);
|
||||
|
||||
memset(value, 0, sizeof(_raw_t));
|
||||
|
||||
context = (_parsing_context_t*)s->parsing_context;
|
||||
|
||||
*obj = (_object_t*)mb_malloc(sizeof(_object_t));
|
||||
@ -2185,13 +2204,13 @@ int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** ob
|
||||
(*obj)->type = type;
|
||||
switch(type) {
|
||||
case _DT_INT:
|
||||
tmp.any = value;
|
||||
memcpy(tmp.any, value, sizeof(_raw_t));
|
||||
(*obj)->data.integer = tmp.integer;
|
||||
safe_free(sym);
|
||||
|
||||
break;
|
||||
case _DT_REAL:
|
||||
tmp.any = value;
|
||||
memcpy(tmp.any, value, sizeof(_raw_t));
|
||||
(*obj)->data.float_point = tmp.float_point;
|
||||
safe_free(sym);
|
||||
|
||||
@ -2209,7 +2228,7 @@ int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** ob
|
||||
tmp.func = (_func_t*)mb_malloc(sizeof(_func_t));
|
||||
memset(tmp.func, 0, sizeof(_func_t));
|
||||
tmp.func->name = sym;
|
||||
tmp.func->pointer = (mb_func_t)(intptr_t)value;
|
||||
memcpy(&tmp.func->pointer, value, sizeof(tmp.func->pointer));
|
||||
(*obj)->data.func = tmp.func;
|
||||
|
||||
break;
|
||||
@ -2223,7 +2242,7 @@ int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** ob
|
||||
tmp.array = (_array_t*)mb_malloc(sizeof(_array_t));
|
||||
memset(tmp.array, 0, sizeof(_array_t));
|
||||
tmp.array->name = sym;
|
||||
tmp.array->type = (_data_e)(int)(long)(intptr_t)value;
|
||||
memcpy(&tmp.array->type, value, sizeof(tmp.array->type));
|
||||
(*obj)->data.array = tmp.array;
|
||||
|
||||
ul = _ht_set_or_insert((_ht_node_t*)s->global_var_dict, sym, *obj);
|
||||
@ -2266,8 +2285,8 @@ int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** ob
|
||||
break;
|
||||
case _DT_LABEL:
|
||||
if(context->current_char == ':') {
|
||||
if(value) {
|
||||
(*obj)->data.label = value;
|
||||
if(mb_memtest(value, sizeof(_raw_t))) {
|
||||
memcpy(&((*obj)->data.label), value, sizeof((*obj)->data.label));
|
||||
(*obj)->ref = true;
|
||||
*delsym = true;
|
||||
} else {
|
||||
@ -2309,15 +2328,17 @@ int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** ob
|
||||
return result;
|
||||
}
|
||||
|
||||
_data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value) {
|
||||
_data_e _get_symbol_type(mb_interpreter_t* s, char* sym, _raw_t* value) {
|
||||
/* Get the type of a syntax symbol */
|
||||
_data_e result = _DT_NIL;
|
||||
union { real_t float_point; int_t integer; _object_t* obj; void* any; } tmp;
|
||||
union { real_t float_point; int_t integer; _object_t* obj; _raw_t any; } tmp;
|
||||
char* conv_suc = 0;
|
||||
_parsing_context_t* context = 0;
|
||||
_ls_node_t* lclsyminscope = 0;
|
||||
_ls_node_t* glbsyminscope = 0;
|
||||
size_t _sl = 0;
|
||||
_data_e en = _DT_ANY;
|
||||
intptr_t ptr = 0;
|
||||
|
||||
mb_assert(s && sym);
|
||||
_sl = strlen(sym);
|
||||
@ -2328,7 +2349,7 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value) {
|
||||
/* int_t */
|
||||
tmp.integer = (int_t)strtol(sym, &conv_suc, 0);
|
||||
if(*conv_suc == '\0') {
|
||||
*value = tmp.any;
|
||||
memcpy(*value, tmp.any, sizeof(_raw_t));
|
||||
|
||||
result = _DT_INT;
|
||||
|
||||
@ -2337,7 +2358,7 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value) {
|
||||
/* real_t */
|
||||
tmp.float_point = (real_t)strtod(sym, &conv_suc);
|
||||
if(*conv_suc == '\0') {
|
||||
*value = tmp.any;
|
||||
memcpy(*value, tmp.any, sizeof(_raw_t));
|
||||
|
||||
result = _DT_REAL;
|
||||
|
||||
@ -2353,7 +2374,7 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value) {
|
||||
glbsyminscope = _ht_find((_ht_node_t*)s->global_var_dict, sym);
|
||||
if(glbsyminscope && ((_object_t*)(glbsyminscope->data))->type == _DT_ARRAY) {
|
||||
tmp.obj = (_object_t*)(glbsyminscope->data);
|
||||
*value = (void*)(intptr_t)(tmp.obj->data.array->type);
|
||||
memcpy(*value, &(tmp.obj->data.array->type), sizeof(tmp.obj->data.array->type));
|
||||
|
||||
result = _DT_ARRAY;
|
||||
|
||||
@ -2361,7 +2382,8 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value) {
|
||||
}
|
||||
if(context->last_symbol && context->last_symbol->type == _DT_FUNC) {
|
||||
if(strcmp("DIM", context->last_symbol->data.func->name) == 0) {
|
||||
*value = (void*)(intptr_t)(sym[_sl - 1] == '$' ? _DT_STRING : _DT_REAL);
|
||||
en = (sym[_sl - 1] == '$' ? _DT_STRING : _DT_REAL);
|
||||
memcpy(*value, &en, sizeof(en));
|
||||
|
||||
result = _DT_ARRAY;
|
||||
|
||||
@ -2369,10 +2391,12 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value) {
|
||||
}
|
||||
}
|
||||
/* _func_t */
|
||||
if(context->last_symbol && ((context->last_symbol->type == _DT_FUNC && context->last_symbol->data.func->pointer != _core_close_bracket) ||
|
||||
context->last_symbol->type == _DT_SEP)) {
|
||||
if(!context->last_symbol ||
|
||||
(context->last_symbol && ((context->last_symbol->type == _DT_FUNC && context->last_symbol->data.func->pointer != _core_close_bracket) ||
|
||||
context->last_symbol->type == _DT_SEP))) {
|
||||
if(strcmp("-", sym) == 0) {
|
||||
*value = (void*)(intptr_t)(_core_neg);
|
||||
ptr = (intptr_t)_core_neg;
|
||||
memcpy(*value, &ptr, sizeof(intptr_t));
|
||||
|
||||
result = _DT_FUNC;
|
||||
|
||||
@ -2382,7 +2406,8 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value) {
|
||||
lclsyminscope = _ht_find((_ht_node_t*)s->local_func_dict, sym);
|
||||
glbsyminscope = _ht_find((_ht_node_t*)s->global_func_dict, sym);
|
||||
if(lclsyminscope || glbsyminscope) {
|
||||
*value = lclsyminscope ? lclsyminscope->data : glbsyminscope->data;
|
||||
ptr = lclsyminscope ? (intptr_t)lclsyminscope->data : (intptr_t)glbsyminscope->data;
|
||||
memcpy(*value, &ptr, sizeof(intptr_t));
|
||||
|
||||
result = _DT_FUNC;
|
||||
|
||||
@ -2404,7 +2429,7 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value) {
|
||||
glbsyminscope = _ht_find((_ht_node_t*)s->global_var_dict, sym);
|
||||
if(glbsyminscope) {
|
||||
if(((_object_t*)glbsyminscope->data)->type != _DT_LABEL) {
|
||||
*value = glbsyminscope->data;
|
||||
memcpy(*value, &glbsyminscope->data, sizeof(glbsyminscope->data));
|
||||
|
||||
result = _DT_VAR;
|
||||
|
||||
@ -2416,7 +2441,7 @@ _data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** value) {
|
||||
if(!context->last_symbol || context->last_symbol->type == _DT_EOS) {
|
||||
glbsyminscope = _ht_find((_ht_node_t*)s->global_var_dict, sym);
|
||||
if(glbsyminscope) {
|
||||
*value = glbsyminscope->data;
|
||||
memcpy(*value, &glbsyminscope->data, sizeof(glbsyminscope->data));
|
||||
}
|
||||
|
||||
result = _DT_LABEL;
|
||||
@ -2442,11 +2467,13 @@ int _parse_char(mb_interpreter_t* s, char c, int pos, unsigned short row, unsign
|
||||
/* Parse a char */
|
||||
int result = MB_FUNC_OK;
|
||||
_parsing_context_t* context = 0;
|
||||
char last_char = '\0';
|
||||
|
||||
mb_assert(s && s->parsing_context);
|
||||
|
||||
context = (_parsing_context_t*)(s->parsing_context);
|
||||
|
||||
last_char = context->current_char;
|
||||
context->current_char = c;
|
||||
|
||||
if(context->parsing_state == _PS_NORMAL) {
|
||||
@ -2478,9 +2505,13 @@ int _parse_char(mb_interpreter_t* s, char c, int pos, unsigned short row, unsign
|
||||
if(_is_identifier_char(c)) {
|
||||
result += _append_char_to_symbol(s, c);
|
||||
} else if(_is_operator_char(c)) {
|
||||
context->symbol_state = _SS_OPERATOR;
|
||||
result += _cut_symbol(s, pos, row, col);
|
||||
result += _append_char_to_symbol(s, c);
|
||||
if((last_char == 'e' || last_char == 'E') && c == '-') {
|
||||
result += _append_char_to_symbol(s, c);
|
||||
} else {
|
||||
context->symbol_state = _SS_OPERATOR;
|
||||
result += _cut_symbol(s, pos, row, col);
|
||||
result += _append_char_to_symbol(s, c);
|
||||
}
|
||||
} else {
|
||||
_handle_error(s, SE_PS_INVALID_CHAR, pos, row, col, MB_FUNC_ERR, _exit, result);
|
||||
}
|
||||
@ -4217,9 +4248,13 @@ int _core_neg(mb_interpreter_t* s, void** l) {
|
||||
|
||||
running = (_running_context_t*)(s->running_context);
|
||||
|
||||
inep = (int*)_ls_back(running->in_neg_expr)->data;
|
||||
if(!_ls_empty(running->in_neg_expr)) {
|
||||
inep = (int*)_ls_back(running->in_neg_expr)->data;
|
||||
}
|
||||
|
||||
(*inep)++;
|
||||
if(inep) {
|
||||
(*inep)++;
|
||||
}
|
||||
|
||||
mb_check(mb_attempt_func_begin(s, l));
|
||||
|
||||
@ -4227,7 +4262,9 @@ int _core_neg(mb_interpreter_t* s, void** l) {
|
||||
|
||||
mb_check(mb_attempt_func_end(s, l));
|
||||
|
||||
(*inep)--;
|
||||
if(inep) {
|
||||
(*inep)--;
|
||||
}
|
||||
|
||||
switch(arg.type) {
|
||||
case MB_DT_INT:
|
||||
|
532
core/my_basic.h
532
core/my_basic.h
@ -1,265 +1,267 @@
|
||||
/*
|
||||
** This source file is part of MY-BASIC
|
||||
**
|
||||
** For the latest info, see https://github.com/paladin-t/my_basic/
|
||||
**
|
||||
** 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
|
||||
** the Software without restriction, including without limitation the rights to
|
||||
** 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,
|
||||
** subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in all
|
||||
** copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
** 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
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#ifndef __MY_BASIC_H__
|
||||
#define __MY_BASIC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifndef MBAPI
|
||||
# define MBAPI
|
||||
#endif /* MBAPI */
|
||||
|
||||
#ifndef MB_COMPACT_MODE
|
||||
# define MB_COMPACT_MODE
|
||||
#endif /* MB_COMPACT_MODE */
|
||||
|
||||
#ifdef MB_COMPACT_MODE
|
||||
# pragma pack(1)
|
||||
#endif /* MB_COMPACT_MODE */
|
||||
|
||||
#ifndef true
|
||||
# define true (!0)
|
||||
#endif
|
||||
#ifndef false
|
||||
# define false (0)
|
||||
#endif
|
||||
|
||||
#ifndef bool_t
|
||||
# define bool_t int
|
||||
#endif
|
||||
#ifndef byte_t
|
||||
# define byte_t unsigned char
|
||||
#endif
|
||||
#ifndef int_t
|
||||
# define int_t int
|
||||
#endif
|
||||
#ifndef real_t
|
||||
# define real_t float
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# ifndef _strcmpi
|
||||
# ifdef __BORLANDC__
|
||||
# define _strcmpi stricmp
|
||||
# else /* __BORLANDC__*/
|
||||
# define _strcmpi strcasecmp
|
||||
# endif /* __BORLANDC__ */
|
||||
# endif /* _strcmpi */
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifndef mb_assert
|
||||
# define mb_assert(__a) do { ((void)(__a)); assert(__a); } while(0)
|
||||
#endif /* mb_assert */
|
||||
|
||||
#ifndef mb_static_assert
|
||||
# define _static_assert_impl(cond, msg) typedef char static_assertion_##msg[(!!(cond)) * 2 - 1]
|
||||
# define _compile_time_assert3(x, l) _static_assert_impl(x, static_assertion_at_line_##l)
|
||||
# define _compile_time_assert2(x, l) _compile_time_assert3(x, l)
|
||||
# define mb_static_assert(x) _compile_time_assert2(x, __LINE__)
|
||||
#endif /* mb_static_assert */
|
||||
|
||||
#ifndef mb_unrefvar
|
||||
# define mb_unrefvar(__v) ((void)(__v))
|
||||
#endif /* mb_unrefvar */
|
||||
|
||||
#ifndef MB_CODES
|
||||
# define MB_CODES
|
||||
# define MB_FUNC_OK 0
|
||||
# define MB_FUNC_BYE 1001
|
||||
# define MB_FUNC_WARNING 1002
|
||||
# define MB_FUNC_ERR 1003
|
||||
# define MB_FUNC_END 1004
|
||||
# define MB_FUNC_SUSPEND 1005
|
||||
# define MB_PARSING_ERR 3001
|
||||
# define MB_LOOP_BREAK 5001
|
||||
# define MB_LOOP_CONTINUE 5002
|
||||
# define MB_SUB_RETURN 5101
|
||||
# define MB_EXTENDED_ABORT 9001
|
||||
#endif /* MB_CODES */
|
||||
|
||||
#ifndef mb_check
|
||||
# define mb_check(__r) { int __hr = __r; if(__hr != MB_FUNC_OK) { return __hr; } }
|
||||
#endif /* mb_check */
|
||||
|
||||
#ifndef mb_reg_fun
|
||||
# define mb_reg_fun(__s, __f) mb_register_func(__s, #__f, __f)
|
||||
#endif /* mb_reg_fun */
|
||||
#ifndef mb_rem_fun
|
||||
# define mb_rem_fun(__s, __f) mb_remove_func(__s, #__f)
|
||||
#endif /* mb_rem_fun */
|
||||
#ifndef mb_rem_res_fun
|
||||
# define mb_rem_res_fun(__s, __f) mb_remove_reserved_func(__s, #__f)
|
||||
#endif /* mb_rem_res_fun */
|
||||
|
||||
struct mb_interpreter_t;
|
||||
|
||||
typedef enum mb_error_e {
|
||||
SE_NO_ERR = 0,
|
||||
/** Common */
|
||||
SE_CM_MB_OPEN_FAILED,
|
||||
SE_CM_FUNC_EXISTS,
|
||||
SE_CM_FUNC_NOT_EXISTS,
|
||||
/** Parsing */
|
||||
SE_PS_FILE_OPEN_FAILED,
|
||||
SE_PS_SYMBOL_TOO_LONG,
|
||||
SE_PS_INVALID_CHAR,
|
||||
/** Running */
|
||||
SE_RN_NOT_SUPPORTED,
|
||||
SE_RN_EMPTY_PROGRAM,
|
||||
SE_RN_SYNTAX,
|
||||
SE_RN_INVALID_DATA_TYPE,
|
||||
SE_RN_TYPE_NOT_MATCH,
|
||||
SE_RN_ILLEGAL_BOUND,
|
||||
SE_RN_DIMENSION_TOO_MUCH,
|
||||
SE_RN_OPERATION_FAILED,
|
||||
SE_RN_DIMENSION_OUT_OF_BOUND,
|
||||
SE_RN_ARRAY_OUT_OF_BOUND,
|
||||
SE_RN_LABEL_NOT_EXISTS,
|
||||
SE_RN_NO_RETURN_POINT,
|
||||
SE_RN_COLON_EXPECTED,
|
||||
SE_RN_COMMA_OR_SEMICOLON_EXPECTED,
|
||||
SE_RN_ARRAY_IDENTIFIER_EXPECTED,
|
||||
SE_RN_OPEN_BRACKET_EXPECTED,
|
||||
SE_RN_CLOSE_BRACKET_EXPECTED,
|
||||
SE_RN_ARRAY_SUBSCRIPT_EXPECTED,
|
||||
SE_RN_STRUCTURE_NOT_COMPLETED,
|
||||
SE_RN_FUNCTION_EXPECTED,
|
||||
SE_RN_STRING_EXPECTED,
|
||||
SE_RN_VAR_OR_ARRAY_EXPECTED,
|
||||
SE_RN_ASSIGN_OPERATOR_EXPECTED,
|
||||
SE_RN_INTEGER_EXPECTED,
|
||||
SE_RN_ELSE_EXPECTED,
|
||||
SE_RN_TO_EXPECTED,
|
||||
SE_RN_NEXT_EXPECTED,
|
||||
SE_RN_UNTIL_EXPECTED,
|
||||
SE_RN_LOOP_VAR_EXPECTED,
|
||||
SE_RN_JUMP_LABEL_EXPECTED,
|
||||
SE_RN_VARIABLE_EXPECTED,
|
||||
SE_RN_INVALID_ID_USAGE,
|
||||
SE_RN_OPERATOR_EXPECTED,
|
||||
SE_RN_CALCULATION_ERROR,
|
||||
SE_RN_DIVIDE_BY_ZERO,
|
||||
SE_RN_MOD_BY_ZERO,
|
||||
SE_RN_INVALID_EXPRESSION,
|
||||
SE_RN_OUT_OF_MEMORY,
|
||||
/** Extended abort */
|
||||
SE_EA_EXTENDED_ABORT,
|
||||
/** Extra */
|
||||
SE_COUNT
|
||||
} mb_error_e;
|
||||
|
||||
typedef enum mb_data_e {
|
||||
MB_DT_NIL = -1,
|
||||
MB_DT_INT = 0,
|
||||
MB_DT_REAL,
|
||||
MB_DT_STRING
|
||||
} mb_data_e;
|
||||
|
||||
typedef union mb_value_u {
|
||||
int_t integer;
|
||||
real_t float_point;
|
||||
char* string;
|
||||
} mb_value_u;
|
||||
|
||||
typedef struct mb_value_t {
|
||||
mb_data_e type;
|
||||
mb_value_u value;
|
||||
} mb_value_t;
|
||||
|
||||
typedef void (* mb_error_handler_t)(struct mb_interpreter_t*, enum mb_error_e, char*, int, unsigned short, unsigned short, int);
|
||||
typedef int (* mb_func_t)(struct mb_interpreter_t*, void**);
|
||||
typedef int (* mb_print_func_t)(const char*, ...);
|
||||
typedef int (* mb_input_func_t)(char*, int);
|
||||
|
||||
typedef struct mb_interpreter_t {
|
||||
void* local_func_dict;
|
||||
void* global_func_dict;
|
||||
void* global_var_dict;
|
||||
void* ast;
|
||||
void* parsing_context;
|
||||
void* running_context;
|
||||
mb_error_e last_error;
|
||||
int last_error_pos;
|
||||
unsigned short last_error_row;
|
||||
unsigned short last_error_col;
|
||||
mb_error_handler_t error_handler;
|
||||
mb_print_func_t printer;
|
||||
mb_input_func_t inputer;
|
||||
void* userdata;
|
||||
} mb_interpreter_t;
|
||||
|
||||
MBAPI unsigned int mb_ver(void);
|
||||
MBAPI const char* mb_ver_string(void);
|
||||
|
||||
MBAPI int mb_init(void);
|
||||
MBAPI int mb_dispose(void);
|
||||
MBAPI int mb_open(mb_interpreter_t** s);
|
||||
MBAPI int mb_close(mb_interpreter_t** s);
|
||||
MBAPI int mb_reset(mb_interpreter_t** s, bool_t clrf);
|
||||
|
||||
MBAPI int mb_register_func(mb_interpreter_t* s, const char* n, mb_func_t f);
|
||||
MBAPI int mb_remove_func(mb_interpreter_t* s, const char* n);
|
||||
MBAPI int mb_remove_reserved_func(mb_interpreter_t* s, const char* n);
|
||||
|
||||
MBAPI int mb_attempt_func_begin(mb_interpreter_t* s, void** l);
|
||||
MBAPI int mb_attempt_func_end(mb_interpreter_t* s, void** l);
|
||||
MBAPI int mb_attempt_open_bracket(mb_interpreter_t* s, void** l);
|
||||
MBAPI int mb_attempt_close_bracket(mb_interpreter_t* s, void** l);
|
||||
MBAPI int mb_pop_int(mb_interpreter_t* s, void** l, int_t* val);
|
||||
MBAPI int mb_pop_real(mb_interpreter_t* s, void** l, real_t* val);
|
||||
MBAPI int mb_pop_string(mb_interpreter_t* s, void** l, char** val);
|
||||
MBAPI int mb_pop_value(mb_interpreter_t* s, void** l, mb_value_t* val);
|
||||
MBAPI int mb_push_int(mb_interpreter_t* s, void** l, int_t val);
|
||||
MBAPI int mb_push_real(mb_interpreter_t* s, void** l, real_t val);
|
||||
MBAPI int mb_push_string(mb_interpreter_t* s, void** l, char* val);
|
||||
MBAPI int mb_push_value(mb_interpreter_t* s, void** l, mb_value_t val);
|
||||
|
||||
MBAPI int mb_load_string(mb_interpreter_t* s, const char* l);
|
||||
MBAPI int mb_load_file(mb_interpreter_t* s, const char* f);
|
||||
MBAPI int mb_run(mb_interpreter_t* s);
|
||||
MBAPI int mb_suspend(mb_interpreter_t* s, void** l);
|
||||
|
||||
MBAPI mb_error_e mb_get_last_error(mb_interpreter_t* s);
|
||||
MBAPI const char* mb_get_error_desc(mb_error_e err);
|
||||
MBAPI int mb_set_error_handler(mb_interpreter_t* s, mb_error_handler_t h);
|
||||
MBAPI int mb_set_printer(mb_interpreter_t* s, mb_print_func_t p);
|
||||
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 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __MY_BASIC_H__ */
|
||||
/*
|
||||
** This source file is part of MY-BASIC
|
||||
**
|
||||
** For the latest info, see https://github.com/paladin-t/my_basic/
|
||||
**
|
||||
** 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
|
||||
** the Software without restriction, including without limitation the rights to
|
||||
** 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,
|
||||
** subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in all
|
||||
** copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
** 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
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#ifndef __MY_BASIC_H__
|
||||
#define __MY_BASIC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifndef MBAPI
|
||||
# define MBAPI
|
||||
#endif /* MBAPI */
|
||||
|
||||
#ifndef MB_COMPACT_MODE
|
||||
# define MB_COMPACT_MODE
|
||||
#endif /* MB_COMPACT_MODE */
|
||||
|
||||
#ifdef MB_COMPACT_MODE
|
||||
# pragma pack(1)
|
||||
#endif /* MB_COMPACT_MODE */
|
||||
|
||||
#ifndef true
|
||||
# define true (!0)
|
||||
#endif
|
||||
#ifndef false
|
||||
# define false (0)
|
||||
#endif
|
||||
|
||||
#ifndef bool_t
|
||||
# define bool_t int
|
||||
#endif
|
||||
#ifndef byte_t
|
||||
# define byte_t unsigned char
|
||||
#endif
|
||||
#ifndef int_t
|
||||
# define int_t int
|
||||
#endif
|
||||
#ifndef real_t
|
||||
# define real_t float
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# ifndef _strcmpi
|
||||
# ifdef __BORLANDC__
|
||||
# define _strcmpi stricmp
|
||||
# elif defined __POCC__
|
||||
# define _strcmpi _stricmp
|
||||
# else /* __BORLANDC__*/
|
||||
# define _strcmpi strcasecmp
|
||||
# endif /* __BORLANDC__ */
|
||||
# endif /* _strcmpi */
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifndef mb_assert
|
||||
# define mb_assert(__a) do { ((void)(__a)); assert(__a); } while(0)
|
||||
#endif /* mb_assert */
|
||||
|
||||
#ifndef mb_static_assert
|
||||
# define _static_assert_impl(cond, msg) typedef char static_assertion_##msg[(!!(cond)) * 2 - 1]
|
||||
# define _compile_time_assert3(x, l) _static_assert_impl(x, static_assertion_at_line_##l)
|
||||
# define _compile_time_assert2(x, l) _compile_time_assert3(x, l)
|
||||
# define mb_static_assert(x) _compile_time_assert2(x, __LINE__)
|
||||
#endif /* mb_static_assert */
|
||||
|
||||
#ifndef mb_unrefvar
|
||||
# define mb_unrefvar(__v) ((void)(__v))
|
||||
#endif /* mb_unrefvar */
|
||||
|
||||
#ifndef MB_CODES
|
||||
# define MB_CODES
|
||||
# define MB_FUNC_OK 0
|
||||
# define MB_FUNC_BYE 1001
|
||||
# define MB_FUNC_WARNING 1002
|
||||
# define MB_FUNC_ERR 1003
|
||||
# define MB_FUNC_END 1004
|
||||
# define MB_FUNC_SUSPEND 1005
|
||||
# define MB_PARSING_ERR 3001
|
||||
# define MB_LOOP_BREAK 5001
|
||||
# define MB_LOOP_CONTINUE 5002
|
||||
# define MB_SUB_RETURN 5101
|
||||
# define MB_EXTENDED_ABORT 9001
|
||||
#endif /* MB_CODES */
|
||||
|
||||
#ifndef mb_check
|
||||
# define mb_check(__r) { int __hr = __r; if(__hr != MB_FUNC_OK) { return __hr; } }
|
||||
#endif /* mb_check */
|
||||
|
||||
#ifndef mb_reg_fun
|
||||
# define mb_reg_fun(__s, __f) mb_register_func(__s, #__f, __f)
|
||||
#endif /* mb_reg_fun */
|
||||
#ifndef mb_rem_fun
|
||||
# define mb_rem_fun(__s, __f) mb_remove_func(__s, #__f)
|
||||
#endif /* mb_rem_fun */
|
||||
#ifndef mb_rem_res_fun
|
||||
# define mb_rem_res_fun(__s, __f) mb_remove_reserved_func(__s, #__f)
|
||||
#endif /* mb_rem_res_fun */
|
||||
|
||||
struct mb_interpreter_t;
|
||||
|
||||
typedef enum mb_error_e {
|
||||
SE_NO_ERR = 0,
|
||||
/** Common */
|
||||
SE_CM_MB_OPEN_FAILED,
|
||||
SE_CM_FUNC_EXISTS,
|
||||
SE_CM_FUNC_NOT_EXISTS,
|
||||
/** Parsing */
|
||||
SE_PS_FILE_OPEN_FAILED,
|
||||
SE_PS_SYMBOL_TOO_LONG,
|
||||
SE_PS_INVALID_CHAR,
|
||||
/** Running */
|
||||
SE_RN_NOT_SUPPORTED,
|
||||
SE_RN_EMPTY_PROGRAM,
|
||||
SE_RN_SYNTAX,
|
||||
SE_RN_INVALID_DATA_TYPE,
|
||||
SE_RN_TYPE_NOT_MATCH,
|
||||
SE_RN_ILLEGAL_BOUND,
|
||||
SE_RN_DIMENSION_TOO_MUCH,
|
||||
SE_RN_OPERATION_FAILED,
|
||||
SE_RN_DIMENSION_OUT_OF_BOUND,
|
||||
SE_RN_ARRAY_OUT_OF_BOUND,
|
||||
SE_RN_LABEL_NOT_EXISTS,
|
||||
SE_RN_NO_RETURN_POINT,
|
||||
SE_RN_COLON_EXPECTED,
|
||||
SE_RN_COMMA_OR_SEMICOLON_EXPECTED,
|
||||
SE_RN_ARRAY_IDENTIFIER_EXPECTED,
|
||||
SE_RN_OPEN_BRACKET_EXPECTED,
|
||||
SE_RN_CLOSE_BRACKET_EXPECTED,
|
||||
SE_RN_ARRAY_SUBSCRIPT_EXPECTED,
|
||||
SE_RN_STRUCTURE_NOT_COMPLETED,
|
||||
SE_RN_FUNCTION_EXPECTED,
|
||||
SE_RN_STRING_EXPECTED,
|
||||
SE_RN_VAR_OR_ARRAY_EXPECTED,
|
||||
SE_RN_ASSIGN_OPERATOR_EXPECTED,
|
||||
SE_RN_INTEGER_EXPECTED,
|
||||
SE_RN_ELSE_EXPECTED,
|
||||
SE_RN_TO_EXPECTED,
|
||||
SE_RN_NEXT_EXPECTED,
|
||||
SE_RN_UNTIL_EXPECTED,
|
||||
SE_RN_LOOP_VAR_EXPECTED,
|
||||
SE_RN_JUMP_LABEL_EXPECTED,
|
||||
SE_RN_VARIABLE_EXPECTED,
|
||||
SE_RN_INVALID_ID_USAGE,
|
||||
SE_RN_OPERATOR_EXPECTED,
|
||||
SE_RN_CALCULATION_ERROR,
|
||||
SE_RN_DIVIDE_BY_ZERO,
|
||||
SE_RN_MOD_BY_ZERO,
|
||||
SE_RN_INVALID_EXPRESSION,
|
||||
SE_RN_OUT_OF_MEMORY,
|
||||
/** Extended abort */
|
||||
SE_EA_EXTENDED_ABORT,
|
||||
/** Extra */
|
||||
SE_COUNT
|
||||
} mb_error_e;
|
||||
|
||||
typedef enum mb_data_e {
|
||||
MB_DT_NIL = -1,
|
||||
MB_DT_INT = 0,
|
||||
MB_DT_REAL,
|
||||
MB_DT_STRING
|
||||
} mb_data_e;
|
||||
|
||||
typedef union mb_value_u {
|
||||
int_t integer;
|
||||
real_t float_point;
|
||||
char* string;
|
||||
} mb_value_u;
|
||||
|
||||
typedef struct mb_value_t {
|
||||
mb_data_e type;
|
||||
mb_value_u value;
|
||||
} mb_value_t;
|
||||
|
||||
typedef void (* mb_error_handler_t)(struct mb_interpreter_t*, enum mb_error_e, char*, int, unsigned short, unsigned short, int);
|
||||
typedef int (* mb_func_t)(struct mb_interpreter_t*, void**);
|
||||
typedef int (* mb_print_func_t)(const char*, ...);
|
||||
typedef int (* mb_input_func_t)(char*, int);
|
||||
|
||||
typedef struct mb_interpreter_t {
|
||||
void* local_func_dict;
|
||||
void* global_func_dict;
|
||||
void* global_var_dict;
|
||||
void* ast;
|
||||
void* parsing_context;
|
||||
void* running_context;
|
||||
mb_error_e last_error;
|
||||
int last_error_pos;
|
||||
unsigned short last_error_row;
|
||||
unsigned short last_error_col;
|
||||
mb_error_handler_t error_handler;
|
||||
mb_print_func_t printer;
|
||||
mb_input_func_t inputer;
|
||||
void* userdata;
|
||||
} mb_interpreter_t;
|
||||
|
||||
MBAPI unsigned int mb_ver(void);
|
||||
MBAPI const char* mb_ver_string(void);
|
||||
|
||||
MBAPI int mb_init(void);
|
||||
MBAPI int mb_dispose(void);
|
||||
MBAPI int mb_open(mb_interpreter_t** s);
|
||||
MBAPI int mb_close(mb_interpreter_t** s);
|
||||
MBAPI int mb_reset(mb_interpreter_t** s, bool_t clrf);
|
||||
|
||||
MBAPI int mb_register_func(mb_interpreter_t* s, const char* n, mb_func_t f);
|
||||
MBAPI int mb_remove_func(mb_interpreter_t* s, const char* n);
|
||||
MBAPI int mb_remove_reserved_func(mb_interpreter_t* s, const char* n);
|
||||
|
||||
MBAPI int mb_attempt_func_begin(mb_interpreter_t* s, void** l);
|
||||
MBAPI int mb_attempt_func_end(mb_interpreter_t* s, void** l);
|
||||
MBAPI int mb_attempt_open_bracket(mb_interpreter_t* s, void** l);
|
||||
MBAPI int mb_attempt_close_bracket(mb_interpreter_t* s, void** l);
|
||||
MBAPI int mb_pop_int(mb_interpreter_t* s, void** l, int_t* val);
|
||||
MBAPI int mb_pop_real(mb_interpreter_t* s, void** l, real_t* val);
|
||||
MBAPI int mb_pop_string(mb_interpreter_t* s, void** l, char** val);
|
||||
MBAPI int mb_pop_value(mb_interpreter_t* s, void** l, mb_value_t* val);
|
||||
MBAPI int mb_push_int(mb_interpreter_t* s, void** l, int_t val);
|
||||
MBAPI int mb_push_real(mb_interpreter_t* s, void** l, real_t val);
|
||||
MBAPI int mb_push_string(mb_interpreter_t* s, void** l, char* val);
|
||||
MBAPI int mb_push_value(mb_interpreter_t* s, void** l, mb_value_t val);
|
||||
|
||||
MBAPI int mb_load_string(mb_interpreter_t* s, const char* l);
|
||||
MBAPI int mb_load_file(mb_interpreter_t* s, const char* f);
|
||||
MBAPI int mb_run(mb_interpreter_t* s);
|
||||
MBAPI int mb_suspend(mb_interpreter_t* s, void** l);
|
||||
|
||||
MBAPI mb_error_e mb_get_last_error(mb_interpreter_t* s);
|
||||
MBAPI const char* mb_get_error_desc(mb_error_e err);
|
||||
MBAPI int mb_set_error_handler(mb_interpreter_t* s, mb_error_handler_t h);
|
||||
MBAPI int mb_set_printer(mb_interpreter_t* s, mb_print_func_t p);
|
||||
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 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __MY_BASIC_H__ */
|
||||
|
Binary file not shown.
Binary file not shown.
@ -81,13 +81,13 @@ BEGIN
|
||||
VALUE "Comments", "MY-BASIC"
|
||||
VALUE "CompanyName", "W. Renxin"
|
||||
VALUE "FileDescription", "MY-BASIC interpreter"
|
||||
VALUE "FileVersion", "1, 0, 0, 46"
|
||||
VALUE "FileVersion", "1, 0, 0, 47"
|
||||
VALUE "InternalName", "my_basic"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2011 - 2015 W. Renxin"
|
||||
VALUE "LegalTrademarks", "MY-BASIC"
|
||||
VALUE "OriginalFilename", "my_basic.exe"
|
||||
VALUE "ProductName", "MY-BASIC"
|
||||
VALUE "ProductVersion", "1, 0, 0, 46"
|
||||
VALUE "ProductVersion", "1, 0, 0, 47"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
883
shell/main.c
883
shell/main.c
@ -1,439 +1,444 @@
|
||||
/*
|
||||
** This source file is part of MY-BASIC
|
||||
**
|
||||
** For the latest info, see https://github.com/paladin-t/my_basic/
|
||||
**
|
||||
** 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
|
||||
** the Software without restriction, including without limitation the rights to
|
||||
** 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,
|
||||
** subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in all
|
||||
** copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
** 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
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# ifndef _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# endif /* _CRT_SECURE_NO_WARNINGS */
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#include "../core/my_basic.h"
|
||||
#ifdef _MSC_VER
|
||||
# include <crtdbg.h>
|
||||
# include <conio.h>
|
||||
#elif !defined __BORLANDC__
|
||||
# include <unistd.h>
|
||||
#endif /* _MSC_VER */
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable : 4127)
|
||||
# pragma warning(disable : 4996)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# pragma warn -8004
|
||||
# pragma warn -8008
|
||||
# pragma warn -8066
|
||||
#endif /* __BORLANDC__ */
|
||||
|
||||
#define _MAX_LINE_LENGTH 256
|
||||
#define _str_eq(__str1, __str2) (_strcmpi(__str1, __str2) == 0)
|
||||
|
||||
#define _LINE_INC_STEP 16
|
||||
|
||||
#define _NO_END(s) (MB_FUNC_OK == s || MB_FUNC_SUSPEND == s || MB_FUNC_WARNING == s || MB_FUNC_ERR == s || MB_FUNC_END == s)
|
||||
|
||||
typedef struct _code_line_t {
|
||||
char** lines;
|
||||
int count;
|
||||
int size;
|
||||
} _code_line_t;
|
||||
|
||||
static mb_interpreter_t* bas = 0;
|
||||
|
||||
static _code_line_t* c = 0;
|
||||
|
||||
static _code_line_t* _create_code(void) {
|
||||
_code_line_t* result = (_code_line_t*)malloc(sizeof(_code_line_t));
|
||||
result->count = 0;
|
||||
result->size = _LINE_INC_STEP;
|
||||
result->lines = (char**)malloc(sizeof(char*) * result->size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _destroy_code(_code_line_t* code) {
|
||||
int i = 0;
|
||||
mb_assert(code);
|
||||
for(i = 0; i < code->count; ++i) {
|
||||
free(code->lines[i]);
|
||||
}
|
||||
free(code->lines);
|
||||
free(code);
|
||||
}
|
||||
|
||||
static void _clear_code(_code_line_t* code) {
|
||||
int i = 0;
|
||||
mb_assert(code);
|
||||
for(i = 0; i < code->count; ++i) {
|
||||
free(code->lines[i]);
|
||||
}
|
||||
code->count = 0;
|
||||
}
|
||||
|
||||
static void _append_line(_code_line_t* code, char* txt) {
|
||||
mb_assert(code && txt);
|
||||
if(code->count + 1 == code->size) {
|
||||
code->size += _LINE_INC_STEP;
|
||||
code->lines = (char**)realloc(code->lines, sizeof(char*) * code->size);
|
||||
}
|
||||
code->lines[code->count++] = strdup(txt);
|
||||
}
|
||||
|
||||
static char* _get_code(_code_line_t* code) {
|
||||
char* result = 0;
|
||||
int i = 0;
|
||||
mb_assert(code);
|
||||
result = (char*)malloc((_MAX_LINE_LENGTH + 2) * code->count + 1);
|
||||
result[0] = '\0';
|
||||
for(i = 0; i < code->count; ++i) {
|
||||
result = strcat(result, code->lines[i]);
|
||||
if(i != code->count - 1) {
|
||||
result = strcat(result, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _set_code(_code_line_t* code, char* txt) {
|
||||
char* cursor = 0;
|
||||
char _c = '\0';
|
||||
mb_assert(code);
|
||||
if(!txt) {
|
||||
return;
|
||||
}
|
||||
_clear_code(code);
|
||||
cursor = txt;
|
||||
do {
|
||||
_c = *cursor;
|
||||
if(_c == '\r' || _c == '\n' || _c == '\0') {
|
||||
cursor[0] = '\0';
|
||||
if(_c == '\r' && *(cursor + 1) == '\n') {
|
||||
++cursor;
|
||||
}
|
||||
_append_line(code, txt);
|
||||
txt = cursor + 1;
|
||||
}
|
||||
++cursor;
|
||||
} while(_c);
|
||||
}
|
||||
|
||||
static char* _load_file(const char* path) {
|
||||
FILE* fp = 0;
|
||||
char* result = 0;
|
||||
long curpos = 0;
|
||||
long l = 0;
|
||||
mb_assert(path);
|
||||
fp = fopen(path, "rb");
|
||||
if(fp) {
|
||||
curpos = ftell(fp);
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
l = ftell(fp);
|
||||
fseek(fp, curpos, SEEK_SET);
|
||||
result = (char*)malloc((size_t)(l + 1));
|
||||
mb_assert(result);
|
||||
fread(result, 1, l, fp);
|
||||
fclose(fp);
|
||||
result[l] = '\0';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int _save_file(const char* path, const char* txt) {
|
||||
FILE* fp = 0;
|
||||
mb_assert(path && txt);
|
||||
fp = fopen(path, "wb");
|
||||
if(fp) {
|
||||
fwrite(txt, sizeof(char), strlen(txt), fp);
|
||||
fclose(fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int beep(mb_interpreter_t* s, void** l) {
|
||||
int result = MB_FUNC_OK;
|
||||
|
||||
mb_assert(s && l);
|
||||
|
||||
mb_check(mb_attempt_func_begin(s, l));
|
||||
mb_check(mb_attempt_func_end(s, l));
|
||||
|
||||
putchar('\a');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _on_error(mb_interpreter_t* s, mb_error_e e, char* m, int p, unsigned short row, unsigned short col, int abort_code) {
|
||||
mb_unrefvar(s);
|
||||
if(SE_NO_ERR != e) {
|
||||
printf("Error:\n [POS] %d, [ROW] %d, [COL] %d,\n [CODE] %d, [MESSAGE] %s, [ABORT CODE] %d\n", p, row, col, e, m, abort_code);
|
||||
}
|
||||
}
|
||||
|
||||
static void _on_startup(void) {
|
||||
c = _create_code();
|
||||
|
||||
mb_init();
|
||||
|
||||
mb_open(&bas);
|
||||
mb_set_error_handler(bas, _on_error);
|
||||
|
||||
mb_reg_fun(bas, beep);
|
||||
}
|
||||
|
||||
static void _on_exit(void) {
|
||||
mb_close(&bas);
|
||||
|
||||
mb_dispose();
|
||||
|
||||
_destroy_code(c);
|
||||
c = 0;
|
||||
|
||||
#if defined _MSC_VER && !defined _WIN64
|
||||
if(0 != _CrtDumpMemoryLeaks()) { _asm { int 3 } }
|
||||
#endif /* _MSC_VER && !_WIN64 */
|
||||
}
|
||||
|
||||
static void _clear_screen(void) {
|
||||
#ifdef _MSC_VER
|
||||
system("cls");
|
||||
#else /* _MSC_VER */
|
||||
system("clear");
|
||||
#endif /* _MSC_VER */
|
||||
}
|
||||
|
||||
static int _new_program(void) {
|
||||
_clear_code(c);
|
||||
|
||||
return mb_reset(&bas, false);
|
||||
}
|
||||
|
||||
static void _list_program(const char* sn, const char* cn) {
|
||||
long lsn = 0;
|
||||
long lcn = 0;
|
||||
mb_assert(sn && cn);
|
||||
lsn = atoi(sn);
|
||||
lcn = atoi(cn);
|
||||
if(lsn == 0 && lcn == 0) {
|
||||
char* txt = _get_code(c);
|
||||
printf("%s\n", txt);
|
||||
free(txt);
|
||||
} else {
|
||||
long i = 0;
|
||||
long e = 0;
|
||||
if(lsn < 1 || lsn > c->count) {
|
||||
printf("Line number %ld out of bound.\n", lsn);
|
||||
|
||||
return;
|
||||
}
|
||||
if(lcn < 0) {
|
||||
printf("Invalid line count %ld.\n", lcn);
|
||||
|
||||
return;
|
||||
}
|
||||
--lsn;
|
||||
e = lcn ? lsn + lcn : c->count;
|
||||
for(i = lsn; i < e; ++i) {
|
||||
if(i >= c->count) {
|
||||
break;
|
||||
}
|
||||
printf("%s\n", c->lines[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _edit_program(const char* no) {
|
||||
char line[_MAX_LINE_LENGTH];
|
||||
long lno = 0;
|
||||
mb_assert(no);
|
||||
lno = atoi(no);
|
||||
if(lno < 1 || lno > c->count) {
|
||||
printf("Line number %ld out of bound.\n", lno);
|
||||
|
||||
return;
|
||||
}
|
||||
--lno;
|
||||
memset(line, 0, _MAX_LINE_LENGTH);
|
||||
printf("%ld]", lno + 1);
|
||||
mb_gets(line, _MAX_LINE_LENGTH);
|
||||
c->lines[lno] = (char*)realloc(c->lines[lno], strlen(line) + 1);
|
||||
strcpy(c->lines[lno], line);
|
||||
}
|
||||
|
||||
static void _load_program(const char* path) {
|
||||
char* txt = _load_file(path);
|
||||
if(txt) {
|
||||
_new_program();
|
||||
_set_code(c, txt);
|
||||
free(txt);
|
||||
if(c->count == 1) {
|
||||
printf("Load done. %d line loaded.\n", c->count);
|
||||
} else {
|
||||
printf("Load done. %d lines loaded.\n", c->count);
|
||||
}
|
||||
} else {
|
||||
printf("Cannot load file \"%s\"\n", path);
|
||||
}
|
||||
}
|
||||
|
||||
static void _save_program(const char* path) {
|
||||
char* txt = _get_code(c);
|
||||
if(!_save_file(path, txt)) {
|
||||
printf("Cannot save file \"%s\"\n", path);
|
||||
} else {
|
||||
if(c->count == 1) {
|
||||
printf("Save done. %d line saved.\n", c->count);
|
||||
} else {
|
||||
printf("Save done. %d lines saved.\n", c->count);
|
||||
}
|
||||
}
|
||||
free(txt);
|
||||
}
|
||||
|
||||
static void _kill_program(const char* path) {
|
||||
if(!unlink(path)) {
|
||||
printf("Delete file \"%s\" successfully.\n", path);
|
||||
} else {
|
||||
printf("Delete file \"%s\" failed.\n", path);
|
||||
}
|
||||
}
|
||||
|
||||
static void _show_tip(void) {
|
||||
printf("MY-BASIC Interpreter Shell - %s.\n", mb_ver_string());
|
||||
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");
|
||||
}
|
||||
|
||||
static void _show_help(void) {
|
||||
printf("Commands:\n");
|
||||
printf(" CLS - Clear screen\n");
|
||||
printf(" NEW - Clear current program\n");
|
||||
printf(" RUN - Run current program\n");
|
||||
printf(" BYE - Quit interpreter\n");
|
||||
printf(" LIST - List current program\n");
|
||||
printf(" Usage: LIST [l [n]], l is start line number, n is line count\n");
|
||||
printf(" EDIT - Edit a line in current program\n");
|
||||
printf(" Usage: EDIT n, n is line number\n");
|
||||
printf(" LOAD - Load a file as current program\n");
|
||||
printf(" Usage: LOAD *.*\n");
|
||||
printf(" SAVE - Save current program to a file\n");
|
||||
printf(" Usage: SAVE *.*\n");
|
||||
printf(" KILL - Delete a file\n");
|
||||
printf(" Usage: KILL *.*\n");
|
||||
}
|
||||
|
||||
static int _do_line(void) {
|
||||
int result = MB_FUNC_OK;
|
||||
char line[_MAX_LINE_LENGTH];
|
||||
char dup[_MAX_LINE_LENGTH];
|
||||
|
||||
mb_assert(bas);
|
||||
|
||||
memset(line, 0, _MAX_LINE_LENGTH);
|
||||
printf("]");
|
||||
mb_gets(line, _MAX_LINE_LENGTH);
|
||||
|
||||
memcpy(dup, line, _MAX_LINE_LENGTH);
|
||||
strtok(line, " ");
|
||||
|
||||
if(_str_eq(line, "")) {
|
||||
/* Do nothing */
|
||||
} else if(_str_eq(line, "HELP")) {
|
||||
_show_help();
|
||||
} else if(_str_eq(line, "CLS")) {
|
||||
_clear_screen();
|
||||
} else if(_str_eq(line, "NEW")) {
|
||||
result = _new_program();
|
||||
} else if(_str_eq(line, "RUN")) {
|
||||
char* txt = _get_code(c);
|
||||
result = mb_reset(&bas, false);
|
||||
result = mb_load_string(bas, txt);
|
||||
free(txt);
|
||||
result = mb_run(bas);
|
||||
printf("\n");
|
||||
} else if(_str_eq(line, "BYE")) {
|
||||
result = MB_FUNC_BYE;
|
||||
} else if(_str_eq(line, "LIST")) {
|
||||
char* sn = line + strlen(line) + 1;
|
||||
char* cn = 0;
|
||||
strtok(sn, " ");
|
||||
cn = sn + strlen(sn) + 1;
|
||||
_list_program(sn, cn);
|
||||
} else if(_str_eq(line, "EDIT")) {
|
||||
char* no = line + strlen(line) + 1;
|
||||
_edit_program(no);
|
||||
} else if(_str_eq(line, "LOAD")) {
|
||||
char* path = line + strlen(line) + 1;
|
||||
_load_program(path);
|
||||
} else if(_str_eq(line, "SAVE")) {
|
||||
char* path = line + strlen(line) + 1;
|
||||
_save_program(path);
|
||||
} else if(_str_eq(line, "KILL")) {
|
||||
char* path = line + strlen(line) + 1;
|
||||
_kill_program(path);
|
||||
} else {
|
||||
_append_line(c, dup);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int status = 0;
|
||||
|
||||
#if defined _MSC_VER && !defined _WIN64
|
||||
_CrtSetBreakAlloc(0);
|
||||
#endif /* _MSC_VER && !_WIN64 */
|
||||
|
||||
atexit(_on_exit);
|
||||
|
||||
_on_startup();
|
||||
|
||||
if(argc == 1) {
|
||||
_show_tip();
|
||||
do {
|
||||
status = _do_line();
|
||||
} while(_NO_END(status));
|
||||
} else if(argc == 2) {
|
||||
if(mb_load_file(bas, argv[1]) == MB_FUNC_OK) {
|
||||
mb_run(bas);
|
||||
}
|
||||
} else {
|
||||
printf("Unknown arguments\n");
|
||||
_show_tip();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
** This source file is part of MY-BASIC
|
||||
**
|
||||
** For the latest info, see https://github.com/paladin-t/my_basic/
|
||||
**
|
||||
** 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
|
||||
** the Software without restriction, including without limitation the rights to
|
||||
** 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,
|
||||
** subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in all
|
||||
** copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
** 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
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# ifndef _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# endif /* _CRT_SECURE_NO_WARNINGS */
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#include "../core/my_basic.h"
|
||||
#ifdef _MSC_VER
|
||||
# include <crtdbg.h>
|
||||
# include <conio.h>
|
||||
#elif !defined __BORLANDC__
|
||||
# include <unistd.h>
|
||||
#endif /* _MSC_VER */
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable : 4127)
|
||||
# pragma warning(disable : 4996)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# pragma warn -8004
|
||||
# pragma warn -8008
|
||||
# pragma warn -8066
|
||||
#endif /* __BORLANDC__ */
|
||||
|
||||
#ifdef __POCC__
|
||||
# define unlink _unlink
|
||||
# define strdup _strdup
|
||||
#endif /* __POCC__ */
|
||||
|
||||
#define _MAX_LINE_LENGTH 256
|
||||
#define _str_eq(__str1, __str2) (_strcmpi(__str1, __str2) == 0)
|
||||
|
||||
#define _LINE_INC_STEP 16
|
||||
|
||||
#define _NO_END(s) (MB_FUNC_OK == s || MB_FUNC_SUSPEND == s || MB_FUNC_WARNING == s || MB_FUNC_ERR == s || MB_FUNC_END == s)
|
||||
|
||||
typedef struct _code_line_t {
|
||||
char** lines;
|
||||
int count;
|
||||
int size;
|
||||
} _code_line_t;
|
||||
|
||||
static mb_interpreter_t* bas = 0;
|
||||
|
||||
static _code_line_t* c = 0;
|
||||
|
||||
static _code_line_t* _create_code(void) {
|
||||
_code_line_t* result = (_code_line_t*)malloc(sizeof(_code_line_t));
|
||||
result->count = 0;
|
||||
result->size = _LINE_INC_STEP;
|
||||
result->lines = (char**)malloc(sizeof(char*) * result->size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _destroy_code(_code_line_t* code) {
|
||||
int i = 0;
|
||||
mb_assert(code);
|
||||
for(i = 0; i < code->count; ++i) {
|
||||
free(code->lines[i]);
|
||||
}
|
||||
free(code->lines);
|
||||
free(code);
|
||||
}
|
||||
|
||||
static void _clear_code(_code_line_t* code) {
|
||||
int i = 0;
|
||||
mb_assert(code);
|
||||
for(i = 0; i < code->count; ++i) {
|
||||
free(code->lines[i]);
|
||||
}
|
||||
code->count = 0;
|
||||
}
|
||||
|
||||
static void _append_line(_code_line_t* code, char* txt) {
|
||||
mb_assert(code && txt);
|
||||
if(code->count + 1 == code->size) {
|
||||
code->size += _LINE_INC_STEP;
|
||||
code->lines = (char**)realloc(code->lines, sizeof(char*) * code->size);
|
||||
}
|
||||
code->lines[code->count++] = strdup(txt);
|
||||
}
|
||||
|
||||
static char* _get_code(_code_line_t* code) {
|
||||
char* result = 0;
|
||||
int i = 0;
|
||||
mb_assert(code);
|
||||
result = (char*)malloc((_MAX_LINE_LENGTH + 2) * code->count + 1);
|
||||
result[0] = '\0';
|
||||
for(i = 0; i < code->count; ++i) {
|
||||
result = strcat(result, code->lines[i]);
|
||||
if(i != code->count - 1) {
|
||||
result = strcat(result, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _set_code(_code_line_t* code, char* txt) {
|
||||
char* cursor = 0;
|
||||
char _c = '\0';
|
||||
mb_assert(code);
|
||||
if(!txt) {
|
||||
return;
|
||||
}
|
||||
_clear_code(code);
|
||||
cursor = txt;
|
||||
do {
|
||||
_c = *cursor;
|
||||
if(_c == '\r' || _c == '\n' || _c == '\0') {
|
||||
cursor[0] = '\0';
|
||||
if(_c == '\r' && *(cursor + 1) == '\n') {
|
||||
++cursor;
|
||||
}
|
||||
_append_line(code, txt);
|
||||
txt = cursor + 1;
|
||||
}
|
||||
++cursor;
|
||||
} while(_c);
|
||||
}
|
||||
|
||||
static char* _load_file(const char* path) {
|
||||
FILE* fp = 0;
|
||||
char* result = 0;
|
||||
long curpos = 0;
|
||||
long l = 0;
|
||||
mb_assert(path);
|
||||
fp = fopen(path, "rb");
|
||||
if(fp) {
|
||||
curpos = ftell(fp);
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
l = ftell(fp);
|
||||
fseek(fp, curpos, SEEK_SET);
|
||||
result = (char*)malloc((size_t)(l + 1));
|
||||
mb_assert(result);
|
||||
fread(result, 1, l, fp);
|
||||
fclose(fp);
|
||||
result[l] = '\0';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int _save_file(const char* path, const char* txt) {
|
||||
FILE* fp = 0;
|
||||
mb_assert(path && txt);
|
||||
fp = fopen(path, "wb");
|
||||
if(fp) {
|
||||
fwrite(txt, sizeof(char), strlen(txt), fp);
|
||||
fclose(fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int beep(mb_interpreter_t* s, void** l) {
|
||||
int result = MB_FUNC_OK;
|
||||
|
||||
mb_assert(s && l);
|
||||
|
||||
mb_check(mb_attempt_func_begin(s, l));
|
||||
mb_check(mb_attempt_func_end(s, l));
|
||||
|
||||
putchar('\a');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _on_error(mb_interpreter_t* s, mb_error_e e, char* m, int p, unsigned short row, unsigned short col, int abort_code) {
|
||||
mb_unrefvar(s);
|
||||
if(SE_NO_ERR != e) {
|
||||
printf("Error:\n [POS] %d, [ROW] %d, [COL] %d,\n [CODE] %d, [MESSAGE] %s, [ABORT CODE] %d\n", p, row, col, e, m, abort_code);
|
||||
}
|
||||
}
|
||||
|
||||
static void _on_startup(void) {
|
||||
c = _create_code();
|
||||
|
||||
mb_init();
|
||||
|
||||
mb_open(&bas);
|
||||
mb_set_error_handler(bas, _on_error);
|
||||
|
||||
mb_reg_fun(bas, beep);
|
||||
}
|
||||
|
||||
static void _on_exit(void) {
|
||||
mb_close(&bas);
|
||||
|
||||
mb_dispose();
|
||||
|
||||
_destroy_code(c);
|
||||
c = 0;
|
||||
|
||||
#if defined _MSC_VER && !defined _WIN64
|
||||
if(0 != _CrtDumpMemoryLeaks()) { _asm { int 3 } }
|
||||
#endif /* _MSC_VER && !_WIN64 */
|
||||
}
|
||||
|
||||
static void _clear_screen(void) {
|
||||
#ifdef _MSC_VER
|
||||
system("cls");
|
||||
#else /* _MSC_VER */
|
||||
system("clear");
|
||||
#endif /* _MSC_VER */
|
||||
}
|
||||
|
||||
static int _new_program(void) {
|
||||
_clear_code(c);
|
||||
|
||||
return mb_reset(&bas, false);
|
||||
}
|
||||
|
||||
static void _list_program(const char* sn, const char* cn) {
|
||||
long lsn = 0;
|
||||
long lcn = 0;
|
||||
mb_assert(sn && cn);
|
||||
lsn = atoi(sn);
|
||||
lcn = atoi(cn);
|
||||
if(lsn == 0 && lcn == 0) {
|
||||
char* txt = _get_code(c);
|
||||
printf("%s\n", txt);
|
||||
free(txt);
|
||||
} else {
|
||||
long i = 0;
|
||||
long e = 0;
|
||||
if(lsn < 1 || lsn > c->count) {
|
||||
printf("Line number %ld out of bound.\n", lsn);
|
||||
|
||||
return;
|
||||
}
|
||||
if(lcn < 0) {
|
||||
printf("Invalid line count %ld.\n", lcn);
|
||||
|
||||
return;
|
||||
}
|
||||
--lsn;
|
||||
e = lcn ? lsn + lcn : c->count;
|
||||
for(i = lsn; i < e; ++i) {
|
||||
if(i >= c->count) {
|
||||
break;
|
||||
}
|
||||
printf("%s\n", c->lines[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _edit_program(const char* no) {
|
||||
char line[_MAX_LINE_LENGTH];
|
||||
long lno = 0;
|
||||
mb_assert(no);
|
||||
lno = atoi(no);
|
||||
if(lno < 1 || lno > c->count) {
|
||||
printf("Line number %ld out of bound.\n", lno);
|
||||
|
||||
return;
|
||||
}
|
||||
--lno;
|
||||
memset(line, 0, _MAX_LINE_LENGTH);
|
||||
printf("%ld]", lno + 1);
|
||||
mb_gets(line, _MAX_LINE_LENGTH);
|
||||
c->lines[lno] = (char*)realloc(c->lines[lno], strlen(line) + 1);
|
||||
strcpy(c->lines[lno], line);
|
||||
}
|
||||
|
||||
static void _load_program(const char* path) {
|
||||
char* txt = _load_file(path);
|
||||
if(txt) {
|
||||
_new_program();
|
||||
_set_code(c, txt);
|
||||
free(txt);
|
||||
if(c->count == 1) {
|
||||
printf("Load done. %d line loaded.\n", c->count);
|
||||
} else {
|
||||
printf("Load done. %d lines loaded.\n", c->count);
|
||||
}
|
||||
} else {
|
||||
printf("Cannot load file \"%s\"\n", path);
|
||||
}
|
||||
}
|
||||
|
||||
static void _save_program(const char* path) {
|
||||
char* txt = _get_code(c);
|
||||
if(!_save_file(path, txt)) {
|
||||
printf("Cannot save file \"%s\"\n", path);
|
||||
} else {
|
||||
if(c->count == 1) {
|
||||
printf("Save done. %d line saved.\n", c->count);
|
||||
} else {
|
||||
printf("Save done. %d lines saved.\n", c->count);
|
||||
}
|
||||
}
|
||||
free(txt);
|
||||
}
|
||||
|
||||
static void _kill_program(const char* path) {
|
||||
if(!unlink(path)) {
|
||||
printf("Delete file \"%s\" successfully.\n", path);
|
||||
} else {
|
||||
printf("Delete file \"%s\" failed.\n", path);
|
||||
}
|
||||
}
|
||||
|
||||
static void _show_tip(void) {
|
||||
printf("MY-BASIC Interpreter Shell - %s.\n", mb_ver_string());
|
||||
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");
|
||||
}
|
||||
|
||||
static void _show_help(void) {
|
||||
printf("Commands:\n");
|
||||
printf(" CLS - Clear screen\n");
|
||||
printf(" NEW - Clear current program\n");
|
||||
printf(" RUN - Run current program\n");
|
||||
printf(" BYE - Quit interpreter\n");
|
||||
printf(" LIST - List current program\n");
|
||||
printf(" Usage: LIST [l [n]], l is start line number, n is line count\n");
|
||||
printf(" EDIT - Edit a line in current program\n");
|
||||
printf(" Usage: EDIT n, n is line number\n");
|
||||
printf(" LOAD - Load a file as current program\n");
|
||||
printf(" Usage: LOAD *.*\n");
|
||||
printf(" SAVE - Save current program to a file\n");
|
||||
printf(" Usage: SAVE *.*\n");
|
||||
printf(" KILL - Delete a file\n");
|
||||
printf(" Usage: KILL *.*\n");
|
||||
}
|
||||
|
||||
static int _do_line(void) {
|
||||
int result = MB_FUNC_OK;
|
||||
char line[_MAX_LINE_LENGTH];
|
||||
char dup[_MAX_LINE_LENGTH];
|
||||
|
||||
mb_assert(bas);
|
||||
|
||||
memset(line, 0, _MAX_LINE_LENGTH);
|
||||
printf("]");
|
||||
mb_gets(line, _MAX_LINE_LENGTH);
|
||||
|
||||
memcpy(dup, line, _MAX_LINE_LENGTH);
|
||||
strtok(line, " ");
|
||||
|
||||
if(_str_eq(line, "")) {
|
||||
/* Do nothing */
|
||||
} else if(_str_eq(line, "HELP")) {
|
||||
_show_help();
|
||||
} else if(_str_eq(line, "CLS")) {
|
||||
_clear_screen();
|
||||
} else if(_str_eq(line, "NEW")) {
|
||||
result = _new_program();
|
||||
} else if(_str_eq(line, "RUN")) {
|
||||
char* txt = _get_code(c);
|
||||
result = mb_reset(&bas, false);
|
||||
result = mb_load_string(bas, txt);
|
||||
free(txt);
|
||||
result = mb_run(bas);
|
||||
printf("\n");
|
||||
} else if(_str_eq(line, "BYE")) {
|
||||
result = MB_FUNC_BYE;
|
||||
} else if(_str_eq(line, "LIST")) {
|
||||
char* sn = line + strlen(line) + 1;
|
||||
char* cn = 0;
|
||||
strtok(sn, " ");
|
||||
cn = sn + strlen(sn) + 1;
|
||||
_list_program(sn, cn);
|
||||
} else if(_str_eq(line, "EDIT")) {
|
||||
char* no = line + strlen(line) + 1;
|
||||
_edit_program(no);
|
||||
} else if(_str_eq(line, "LOAD")) {
|
||||
char* path = line + strlen(line) + 1;
|
||||
_load_program(path);
|
||||
} else if(_str_eq(line, "SAVE")) {
|
||||
char* path = line + strlen(line) + 1;
|
||||
_save_program(path);
|
||||
} else if(_str_eq(line, "KILL")) {
|
||||
char* path = line + strlen(line) + 1;
|
||||
_kill_program(path);
|
||||
} else {
|
||||
_append_line(c, dup);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int status = 0;
|
||||
|
||||
#if defined _MSC_VER && !defined _WIN64
|
||||
_CrtSetBreakAlloc(0);
|
||||
#endif /* _MSC_VER && !_WIN64 */
|
||||
|
||||
atexit(_on_exit);
|
||||
|
||||
_on_startup();
|
||||
|
||||
if(argc == 1) {
|
||||
_show_tip();
|
||||
do {
|
||||
status = _do_line();
|
||||
} while(_NO_END(status));
|
||||
} else if(argc == 2) {
|
||||
if(mb_load_file(bas, argv[1]) == MB_FUNC_OK) {
|
||||
mb_run(bas);
|
||||
}
|
||||
} else {
|
||||
printf("Unknown arguments\n");
|
||||
_show_tip();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user