From 4d87b74c8eefbe4ed98f72751bfe57c24a9c2f55 Mon Sep 17 00:00:00 2001 From: tony Date: Thu, 20 Nov 2014 00:51:18 +0800 Subject: [PATCH] added files --- .DS_Store | Bin 0 -> 6148 bytes HISTORY | 135 + LICENSE | 20 + README | 25 + clean.cmd | 21 + core/my_basic.c | 5922 +++++++++++++++++ core/my_basic.h | 249 + my_basic.sln | 20 + my_basic.vcproj | 310 + my_basic_mac.xcodeproj/project.pbxproj | 254 + .../contents.xcworkspacedata | 7 + output/my_basic.exe | Bin 0 -> 59392 bytes output/my_basic_mac | Bin 0 -> 77088 bytes resource/icon.ico | Bin 0 -> 6006 bytes resource/my_basic.aps | Bin 0 -> 40468 bytes resource/my_basic.rc | 113 + resource/resource.h | 16 + sample/sample01.bas | 7 + sample/sample02.bas | 17 + sample/sample03.bas | 22 + sample/sample04.bas | 23 + shell/main.c | 433 ++ 22 files changed, 7594 insertions(+) create mode 100644 .DS_Store create mode 100644 HISTORY create mode 100644 LICENSE create mode 100644 README create mode 100644 clean.cmd create mode 100644 core/my_basic.c create mode 100644 core/my_basic.h create mode 100644 my_basic.sln create mode 100644 my_basic.vcproj create mode 100644 my_basic_mac.xcodeproj/project.pbxproj create mode 100644 my_basic_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 output/my_basic.exe create mode 100755 output/my_basic_mac create mode 100644 resource/icon.ico create mode 100644 resource/my_basic.aps create mode 100644 resource/my_basic.rc create mode 100644 resource/resource.h create mode 100644 sample/sample01.bas create mode 100644 sample/sample02.bas create mode 100644 sample/sample03.bas create mode 100644 sample/sample04.bas create mode 100644 shell/main.c diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 +# include +#else /* _MSC_VER */ +# include +#endif /* _MSC_VER */ +#include +#include +#include +#include +#include +#include +#include +#include "my_basic.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4127) +# pragma warning(disable : 4996) +#endif /* _MSC_VER */ + +#ifdef __APPLE__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +# pragma clang diagnostic ignored "-Wunused-variable" +#endif /* __APPLE__ */ + +#ifdef MB_COMPACT_MODE +# pragma pack(1) +#endif /* MB_COMPACT_MODE */ + +/* +** {======================================================== +** Data type declarations +*/ + +/** Macros */ +#define _VER_MAJOR 1 +#define _VER_MINOR 0 +#define _VER_REVISION 42 +#define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION)) +#define _MB_VERSION_STRING "1.0.0042" + +/* Uncomment this line to treat warnings as error */ +/*#define _WARING_AS_ERROR*/ + +/* Uncomment this line to use a comma to PRINT a new line as compatibility */ +/*#define _COMMA_AS_NEWLINE*/ + +#define _NO_EAT_COMMA 2 + +#if (defined _DEBUG && !defined NDEBUG) +# define _MB_ENABLE_ALLOC_STAT +#endif /* (defined _DEBUG && !defined NDEBUG) */ + +/* Helper */ +#ifndef sgn +# define sgn(__v) ((__v) ? ((__v) > 0 ? 1 : -1) : (0)) +#endif /* sgn */ + +#ifndef _countof +# define _countof(__a) (sizeof(__a) / sizeof(*(__a))) +#endif /* _countof */ + +#ifndef islower +# define islower(__c) ((__c) >= 'a' && (__c) <= 'z') +#endif /* islower */ + +#ifndef toupper +# 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 */ +#define _HT_ARRAY_SIZE_SMALL 193 +#define _HT_ARRAY_SIZE_MID 1543 +#define _HT_ARRAY_SIZE_BIG 12289 +#define _HT_ARRAY_SIZE_DEFAULT _HT_ARRAY_SIZE_SMALL + +/* Max length of a single symbol */ +#define _SINGLE_SYMBOL_MAX_LENGTH 128 +/* Max dimension of an array */ +#define _MAX_DIMENSION_COUNT 4 + +typedef int (* _common_compare)(void*, void*); + +/* Container operation */ +#define _OP_RESULT_NORMAL 0 +#define _OP_RESULT_DEL_NODE -1 +typedef int (* _common_operation)(void*, void*); + +/** List */ +typedef _common_compare _ls_compare; +typedef _common_operation _ls_operation; + +typedef struct _ls_node_t { + void* data; + struct _ls_node_t* prev; + struct _ls_node_t* next; + void* extra; +} _ls_node_t; + +/** Dictionary */ +typedef unsigned int (* _ht_hash)(void*, void*); +typedef _common_compare _ht_compare; +typedef _common_operation _ht_operation; + +typedef struct _ht_node_t { + _ls_operation free_extra; + _ht_compare compare; + _ht_hash hash; + unsigned int array_size; + unsigned int count; + _ls_node_t** array; +} _ht_node_t; + +/** enum / struct / union / const */ +/* Error description text */ +static const char* _ERR_DESC[] = { + "No error", + /** Common */ + "Open MY-BASIC failed", + "A function with the same name already exists", + "A function with the name does not exists", + /** Parsing */ + "Open file failed", + "Symbol too long", + "Invalid character", + /** Running */ + "Not supported", + "Empty program", + "Syntax error", + "Invalid data type", + "Type does not match", + "Illegal bound", + "Too much dimensions", + "Operation failed", + "Dimension count out of bound", + "Out of bound", + "Label does not exist", + "No return point", + "Colon expected", + "Comma or semicolon expected", + "Array identifier expected", + "Open bracket expected", + "Close bracket expected", + "Array subscript expected", + "Structure not completed", + "Function expected", + "String expected", + "Variable or array identifier expected", + "Assign operator expected", + "Integer expected", + "ELSE statement expected", + "TO statement expected", + "NEXT statement expected", + "UNTIL statement expected", + "Loop variable expected", + "Jump label expected", + "Variable expected", + "Invalid identifier usage", + "Calculation error", + "Divide by zero", + "MOD by zero", + "Invalid expression", + "Out of memory", + /** Extended abort */ + "Extended abort", +}; + +/* Data type */ +#define _EOS '\n' +#define _NULL_STRING "(empty)" + +#define _FNAN 0xffc00000 +#define _FINF 0x7f800000 + +typedef enum _data_e { + _DT_NIL = -1, + _DT_ANY = 0, + _DT_INT, + _DT_REAL, + _DT_STRING, + _DT_USERTYPE, + _DT_FUNC, + _DT_VAR, + _DT_ARRAY, + _DT_LABEL, /* Label type, used for GOTO, GOSUB statement */ + _DT_SEP, /* Separator */ + _DT_EOS, /* End of statement */ +} _data_e; + +typedef struct _func_t { + char* name; + mb_func_t pointer; +} _func_t; + +typedef struct _var_t { + char* name; + struct _object_t* data; +} _var_t; + +typedef struct _array_t { + char* name; + _data_e type; + unsigned int count; + void* raw; + int dimension_count; + int dimensions[_MAX_DIMENSION_COUNT]; +} _array_t; + +typedef struct _label_t { + char* name; + _ls_node_t* node; +} _label_t; + +typedef struct _object_t { + _data_e type; + union { + int_t integer; + real_t float_point; + char* string; + void* usertype; + _func_t* func; + _var_t* variable; + _array_t* array; + _label_t* label; + char separator; + } data; + bool_t ref; + int source_pos; + unsigned short source_row; + unsigned short source_col; +} _object_t; + +static const _object_t _OBJ_INT_UNIT = { _DT_INT, 1, false, 0 }; +static const _object_t _OBJ_INT_ZERO = { _DT_INT, 0, false, 0 }; + +static _object_t* _OBJ_BOOL_TRUE = 0; +static _object_t* _OBJ_BOOL_FALSE = 0; + +/* Parsing context */ +typedef enum _parsing_state_e { + _PS_NORMAL = 0, + _PS_STRING, + _PS_COMMENT, +} _parsing_state_e; + +typedef enum _symbol_state_e { + _SS_IDENTIFIER = 0, + _SS_OPERATOR, +} _symbol_state_e; + +typedef struct _parsing_context_t { + char current_char; + char current_symbol[_SINGLE_SYMBOL_MAX_LENGTH + 1]; + int current_symbol_nonius; + _object_t* last_symbol; + _parsing_state_e parsing_state; + _symbol_state_e symbol_state; +} _parsing_context_t; + +/* Running context */ +typedef struct _running_context_t { + _ls_node_t* temp_values; + _ls_node_t* suspent_point; + _ls_node_t* sub_stack; + _var_t* next_loop_var; + mb_value_t intermediate_value; + int_t no_eat_comma_mark; + _ls_node_t* skip_to_eoi; +} _running_context_t; + +/* Expression processing */ +typedef struct _tuple3_t { + void* e1; + void* e2; + void* e3; +} _tuple3_t; + +static const char _PRECEDE_TABLE[19][19] = { + /* + - * / MOD ^ ( ) = > < >= <= == <> AND OR NOT NEG */ + { '>', '>', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* + */ + { '>', '>', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* - */ + { '>', '>', '>', '>', '>', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* * */ + { '>', '>', '>', '>', '>', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* / */ + { '>', '>', '<', '<', '>', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* MOD */ + { '>', '>', '>', '>', '>', '>', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* ^ */ + { '<', '<', '<', '<', '<', '<', '<', '=', ' ', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<' }, /* ( */ + { '>', '>', '>', '>', '>', '>', ' ', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* ) */ + { '<', '<', '<', '<', '<', '<', '<', ' ', '=', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<' }, /* = */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* > */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* < */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* >= */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* <= */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* == */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* <> */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '<', '>' }, /* AND */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '<', '>' }, /* OR */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '>', '>' }, /* NOT */ + { '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '<', '<', '<', '=' } /* NEG */ +}; + +static _object_t* _exp_assign = 0; + +#define _instruct_fun_num_num(__optr, __tuple) \ + do { \ + _object_t opndv1; \ + _object_t opndv2; \ + _tuple3_t* tpptr = (_tuple3_t*)(*__tuple); \ + _object_t* opnd1 = (_object_t*)(tpptr->e1); \ + _object_t* opnd2 = (_object_t*)(tpptr->e2); \ + _object_t* val = (_object_t*)(tpptr->e3); \ + opndv1.type = \ + (opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \ + _DT_INT : _DT_REAL; \ + opndv1.data = opnd1->type == _DT_VAR ? opnd1->data.variable->data->data : opnd1->data; \ + opndv2.type = \ + (opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \ + _DT_INT : _DT_REAL; \ + opndv2.data = opnd2->type == _DT_VAR ? opnd2->data.variable->data->data : opnd2->data; \ + if(opndv1.type == _DT_INT && opndv2.type == _DT_INT) { \ + val->type = _DT_REAL; \ + val->data.float_point = (real_t)__optr((real_t)opndv1.data.integer, (real_t)opndv2.data.integer); \ + } else { \ + val->type = _DT_REAL; \ + val->data.float_point = (real_t)__optr( \ + opndv1.type == _DT_INT ? opndv1.data.integer : opndv1.data.float_point, \ + opndv2.type == _DT_INT ? opndv2.data.integer : opndv2.data.float_point); \ + } \ + if(val->type == _DT_REAL && (real_t)(int_t)val->data.float_point == val->data.float_point) { \ + val->type = _DT_INT; \ + val->data.integer = (int_t)val->data.float_point; \ + } \ + } while(0) +#define _instruct_num_op_num(__optr, __tuple) \ + do { \ + _object_t opndv1; \ + _object_t opndv2; \ + _tuple3_t* tpptr = (_tuple3_t*)(*__tuple); \ + _object_t* opnd1 = (_object_t*)(tpptr->e1); \ + _object_t* opnd2 = (_object_t*)(tpptr->e2); \ + _object_t* val = (_object_t*)(tpptr->e3); \ + opndv1.type = \ + (opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \ + _DT_INT : _DT_REAL; \ + opndv1.data = opnd1->type == _DT_VAR ? opnd1->data.variable->data->data : opnd1->data; \ + opndv2.type = \ + (opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \ + _DT_INT : _DT_REAL; \ + opndv2.data = opnd2->type == _DT_VAR ? opnd2->data.variable->data->data : opnd2->data; \ + if(opndv1.type == _DT_INT && opndv2.type == _DT_INT) { \ + if((real_t)(opndv1.data.integer __optr opndv2.data.integer) == (real_t)opndv1.data.integer __optr (real_t)opndv2.data.integer) { \ + val->type = _DT_INT; \ + val->data.integer = opndv1.data.integer __optr opndv2.data.integer; \ + } else { \ + val->type = _DT_REAL; \ + val->data.float_point = (real_t)((real_t)opndv1.data.integer __optr (real_t)opndv2.data.integer); \ + } \ + } else { \ + val->type = _DT_REAL; \ + val->data.float_point = (real_t) \ + ((opndv1.type == _DT_INT ? opndv1.data.integer : opndv1.data.float_point) __optr \ + (opndv2.type == _DT_INT ? opndv2.data.integer : opndv2.data.float_point)); \ + } \ + if(val->type == _DT_REAL && (real_t)(int_t)val->data.float_point == val->data.float_point) { \ + val->type = _DT_INT; \ + val->data.integer = (int_t)val->data.float_point; \ + } \ + } while(0) +#define _instruct_int_op_int(__optr, __tuple) \ + do { \ + _object_t opndv1; \ + _object_t opndv2; \ + _tuple3_t* tpptr = (_tuple3_t*)(*__tuple); \ + _object_t* opnd1 = (_object_t*)(tpptr->e1); \ + _object_t* opnd2 = (_object_t*)(tpptr->e2); \ + _object_t* val = (_object_t*)(tpptr->e3); \ + opndv1.type = \ + (opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \ + _DT_INT : _DT_REAL; \ + opndv1.data = opnd1->type == _DT_VAR ? opnd1->data.variable->data->data : opnd1->data; \ + opndv2.type = \ + (opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \ + _DT_INT : _DT_REAL; \ + opndv2.data = opnd2->type == _DT_VAR ? opnd2->data.variable->data->data : opnd2->data; \ + if(opndv1.type == _DT_INT && opndv2.type == _DT_INT) { \ + val->type = _DT_INT; \ + val->data.integer = opndv1.data.integer __optr opndv2.data.integer; \ + } else { \ + val->type = _DT_INT; \ + val->data.integer = \ + ((opndv1.type == _DT_INT ? opndv1.data.integer : (int_t)(opndv1.data.float_point)) __optr \ + (opndv2.type == _DT_INT ? opndv2.data.integer : (int_t)(opndv2.data.float_point))); \ + } \ + } while(0) +#define _instruct_connect_strings(__tuple) \ + do { \ + char* _str1 = 0; \ + char* _str2 = 0; \ + _tuple3_t* tpptr = (_tuple3_t*)(*__tuple); \ + _object_t* opnd1 = (_object_t*)(tpptr->e1); \ + _object_t* opnd2 = (_object_t*)(tpptr->e2); \ + _object_t* val = (_object_t*)(tpptr->e3); \ + val->type = _DT_STRING; \ + if(val->data.string) { \ + safe_free(val->data.string); \ + } \ + _str1 = _extract_string(opnd1); \ + _str2 = _extract_string(opnd2); \ + val->data.string = (char*)mb_malloc(strlen(_str1) + strlen(_str2) + 1); \ + memset(val->data.string, 0, strlen(_str1) + strlen(_str2) + 1); \ + strcat(val->data.string, _str1); \ + strcat(val->data.string, _str2); \ + } while(0) +#define _instruct_compare_strings(__optr, __tuple) \ + do { \ + char* _str1 = 0; \ + char* _str2 = 0; \ + _tuple3_t* tpptr = (_tuple3_t*)(*__tuple); \ + _object_t* opnd1 = (_object_t*)(tpptr->e1); \ + _object_t* opnd2 = (_object_t*)(tpptr->e2); \ + _object_t* val = (_object_t*)(tpptr->e3); \ + val->type = _DT_INT; \ + _str1 = _extract_string(opnd1); \ + _str2 = _extract_string(opnd2); \ + val->data.integer = strcmp(_str1, _str2) __optr 0; \ + } while(0) + +#define _proc_div_by_zero(__s, __tuple, __exit, __result, __kind) \ + do { \ + _object_t opndv1; \ + _object_t opndv2; \ + _tuple3_t* tpptr = (_tuple3_t*)(*__tuple); \ + _object_t* opnd1 = (_object_t*)(tpptr->e1); \ + _object_t* opnd2 = (_object_t*)(tpptr->e2); \ + _object_t* val = (_object_t*)(tpptr->e3); \ + opndv1.type = \ + (opnd1->type == _DT_INT || (opnd1->type == _DT_VAR && opnd1->data.variable->data->type == _DT_INT)) ? \ + _DT_INT : _DT_REAL; \ + opndv1.data = opnd1->type == _DT_VAR ? opnd1->data.variable->data->data : opnd1->data; \ + opndv2.type = \ + (opnd2->type == _DT_INT || (opnd2->type == _DT_VAR && opnd2->data.variable->data->type == _DT_INT)) ? \ + _DT_INT : _DT_REAL; \ + opndv2.data = opnd2->type == _DT_VAR ? opnd2->data.variable->data->data : opnd2->data; \ + if((opndv2.type == _DT_INT && opndv2.data.integer == 0) || (opndv2.type == _DT_REAL && opndv2.data.float_point == 0.0f)) { \ + if((opndv1.type == _DT_INT && opndv1.data.integer == 0) || (opndv1.type == _DT_REAL && opndv1.data.float_point == 0.0f)) { \ + val->type = _DT_REAL; \ + val->data.integer = _FNAN; \ + } else { \ + val->type = _DT_REAL; \ + val->data.integer = _FINF; \ + } \ + _handle_error_on_obj((__s), __kind, ((__tuple) && *(__tuple)) ? ((_object_t*)(((_tuple3_t*)(*(__tuple)))->e1)) : 0, MB_FUNC_WARNING, __exit, __result); \ + } \ + } while(0) + +#define _set_tuple3_result(__l, __r) \ + do { \ + _object_t* val = (_object_t*)(((_tuple3_t*)(*(__l)))->e3); \ + val->type = _DT_INT; \ + val->data.integer = __r; \ + } while(0) + +/* ========================================================} */ + +/* +** {======================================================== +** Private function declarations +*/ + +/** List */ +static int _ls_cmp_data(void* node, void* info); +static int _ls_cmp_extra(void* node, void* info); +static int _ls_cmp_extra_string(void* node, void* info); + +static _ls_node_t* _ls_create_node(void* data); +static _ls_node_t* _ls_create(void); +static _ls_node_t* _ls_front(_ls_node_t* node); +static _ls_node_t* _ls_back(_ls_node_t* node); +static _ls_node_t* _ls_at(_ls_node_t* list, int pos); +static _ls_node_t* _ls_pushback(_ls_node_t* list, void* data); +static _ls_node_t* _ls_pushfront(_ls_node_t* list, void* data); +static _ls_node_t* _ls_insert(_ls_node_t* list, int pos, void* data); +static void* _ls_popback(_ls_node_t* list); +static void* _ls_popfront(_ls_node_t* list); +static unsigned int _ls_remove(_ls_node_t* list, int pos); +static unsigned int _ls_try_remove(_ls_node_t* list, void* info, _ls_compare cmp, _ls_operation op); +static unsigned int _ls_count(_ls_node_t* list); +static unsigned int _ls_foreach(_ls_node_t* list, _ls_operation op); +static bool_t _ls_empty(_ls_node_t* list); +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); + +/** Dictionary */ +static unsigned int _ht_hash_string(void* ht, void* d); +static unsigned int _ht_hash_int(void* ht, void* d); +static unsigned int _ht_hash_real(void* ht, void* d); +static unsigned int _ht_hash_ptr(void* ht, void* d); + +static int _ht_cmp_string(void* d1, void* d2); +static int _ht_cmp_int(void* d1, void* d2); +static int _ht_cmp_real(void* d1, void* d2); +static int _ht_cmp_ptr(void* d1, void* d2); + +static _ht_node_t* _ht_create(unsigned int size, _ht_compare cmp, _ht_hash hs, _ls_operation freeextra); +static _ls_node_t* _ht_find(_ht_node_t* ht, void* key); +static unsigned int _ht_count(_ht_node_t* ht); +static unsigned int _ht_get(_ht_node_t* ht, void* key, void** value); +static unsigned int _ht_set(_ht_node_t* ht, void* key, void* value); +static unsigned int _ht_set_or_insert(_ht_node_t* ht, void* key, void* value); +static unsigned int _ht_remove(_ht_node_t* ht, void* key, _ls_compare cmp); +static unsigned int _ht_foreach(_ht_node_t* ht, _ht_operation op); +static bool_t _ht_empty(_ht_node_t* ht); +static void _ht_clear(_ht_node_t* ht); +static void _ht_destroy(_ht_node_t* ht); + +/** Memory operations */ +#define _MB_POINTER_SIZE (sizeof(intptr_t)) +#define _MB_WRITE_CHUNK_SIZE(t, s) (*((size_t*)((char*)(t) - _MB_POINTER_SIZE)) = s) +#define _MB_READ_CHUNK_SIZE(t) (*((size_t*)((char*)(t) - _MB_POINTER_SIZE))) + +#ifdef _MB_ENABLE_ALLOC_STAT +static volatile size_t _mb_allocated = 0; +#else /* _MB_ENABLE_ALLOC_STAT */ +static volatile size_t _mb_allocated = (size_t)(~0); +#endif /* _MB_ENABLE_ALLOC_STAT */ + +static void* mb_malloc(size_t s); +static void* mb_realloc(void** p, size_t s); +static void mb_free(void* p); + +#define safe_free(__p) do { if(__p) { mb_free(__p); __p = 0; } else { mb_assert(0 && "Memory already released"); } } while(0) + +/** Expression processing */ +static bool_t _is_operator(mb_func_t op); +static bool_t _is_flow(mb_func_t op); +static char _get_priority(mb_func_t op1, mb_func_t op2); +static int _get_priority_index(mb_func_t op); +static _object_t* _operate_operand(mb_interpreter_t* s, _object_t* optr, _object_t* opnd1, _object_t* opnd2, int* status); +static bool_t _is_expression_terminal(mb_interpreter_t* s, _object_t* obj); +static int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val); +static bool_t _is_print_terminal(mb_interpreter_t* s, _object_t* obj); + +/** Others */ +#ifdef _WARING_AS_ERROR +# define _handle_error(__s, __err, __pos, __row, __col, __ret, __exit, __result) \ + do { \ + _set_current_error(__s, __err); \ + _set_error_pos(__s, __pos, __row, __col); \ + __result = __ret; \ + goto __exit; \ + } while(0) +#else /* _WARING_AS_ERROR */ +# define _handle_error(__s, __err, __pos, __row, __col, __ret, __exit, __result) \ + do { \ + _set_current_error(__s, __err); \ + _set_error_pos(__s, __pos, __row, __col); \ + if(__ret != MB_FUNC_WARNING) { \ + __result = __ret; \ + } \ + goto __exit; \ + } while(0) +#endif /* _WARING_AS_ERROR */ +#define _handle_error_on_obj(__s, __err, __obj, __ret, __exit, __result) \ + do { \ + if(__obj) { \ + _handle_error(__s, __err, (__obj)->source_pos, (__obj)->source_row, (__obj)->source_col, __ret, __exit, __result); \ + } else { \ + _handle_error(__s, __err, 0, 0, 0, __ret, __exit, __result); \ + } \ + } while(0) + +static void _set_current_error(mb_interpreter_t* s, mb_error_e err); +static const char* _get_error_desc(mb_error_e err); + +static mb_print_func_t _get_printer(mb_interpreter_t* s); +static mb_input_func_t _get_inputer(mb_interpreter_t* s); + +static bool_t _is_blank(char c); +static bool_t _is_newline(char c); +static bool_t _is_separator(char c); +static bool_t _is_bracket(char c); +static bool_t _is_quotation_mark(char c); +static bool_t _is_comment(char c); +static bool_t _is_identifier_char(char c); +static bool_t _is_operator_char(char c); + +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 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); + +static int_t _get_size_of(_data_e type); +static bool_t _try_get_value(_object_t* obj, mb_value_u* val, _data_e expected); + +static int _get_array_index(mb_interpreter_t* s, _ls_node_t** l, unsigned int* index); +static bool_t _get_array_elem(mb_interpreter_t* s, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type); +static bool_t _set_array_elem(mb_interpreter_t* s, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type); + +static void _init_array(_array_t* arr); +static void _clear_array(_array_t* arr); +static void _destroy_array(_array_t* arr); +static bool_t _is_string(void* obj); +static char* _extract_string(_object_t* obj); +static bool_t _is_internal_object(_object_t* obj); +static int _dispose_object(_object_t* obj); +static int _destroy_object(void* data, void* extra); +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 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); +static int _skip_struct(mb_interpreter_t* s, _ls_node_t** l, mb_func_t open_func, mb_func_t close_func); + +static int _register_func(mb_interpreter_t* s, const char* n, mb_func_t f, bool_t local); +static int _remove_func(mb_interpreter_t* s, const char* n, bool_t local); + +static int _open_constant(mb_interpreter_t* s); +static int _close_constant(mb_interpreter_t* s); +static int _open_core_lib(mb_interpreter_t* s); +static int _close_core_lib(mb_interpreter_t* s); +static int _open_std_lib(mb_interpreter_t* s); +static int _close_std_lib(mb_interpreter_t* s); + +/* ========================================================} */ + +/* +** {======================================================== +** Lib declarations +*/ + +/** Macro */ +#ifdef _MSC_VER +# if _MSC_VER < 1300 +# define _do_nothing do { static int i = 0; ++i; printf("Unaccessable function called %d times\n", i); } while(0) +# else /* _MSC_VER < 1300 */ +# define _do_nothing do { printf("Unaccessable function: %s\n", __FUNCTION__); } while(0) +# endif /* _MSC_VER < 1300 */ +#else /* _MSC_VER */ +# define _do_nothing do { printf("Unaccessable function: %s\n", __FUNCTION__); } while(0) +#endif /* _MSC_VER */ + +/** Core lib */ +static int _core_dummy_assign(mb_interpreter_t* s, void** l); +static int _core_add(mb_interpreter_t* s, void** l); +static int _core_min(mb_interpreter_t* s, void** l); +static int _core_mul(mb_interpreter_t* s, void** l); +static int _core_div(mb_interpreter_t* s, void** l); +static int _core_mod(mb_interpreter_t* s, void** l); +static int _core_pow(mb_interpreter_t* s, void** l); +static int _core_open_bracket(mb_interpreter_t* s, void** l); +static int _core_close_bracket(mb_interpreter_t* s, void** l); +static int _core_neg(mb_interpreter_t* s, void** l); +static int _core_equal(mb_interpreter_t* s, void** l); +static int _core_less(mb_interpreter_t* s, void** l); +static int _core_greater(mb_interpreter_t* s, void** l); +static int _core_less_equal(mb_interpreter_t* s, void** l); +static int _core_greater_equal(mb_interpreter_t* s, void** l); +static int _core_not_equal(mb_interpreter_t* s, void** l); +static int _core_and(mb_interpreter_t* s, void** l); +static int _core_or(mb_interpreter_t* s, void** l); +static int _core_not(mb_interpreter_t* s, void** l); +static int _core_let(mb_interpreter_t* s, void** l); +static int _core_dim(mb_interpreter_t* s, void** l); +static int _core_if(mb_interpreter_t* s, void** l); +static int _core_then(mb_interpreter_t* s, void** l); +static int _core_else(mb_interpreter_t* s, void** l); +static int _core_for(mb_interpreter_t* s, void** l); +static int _core_to(mb_interpreter_t* s, void** l); +static int _core_step(mb_interpreter_t* s, void** l); +static int _core_next(mb_interpreter_t* s, void** l); +static int _core_while(mb_interpreter_t* s, void** l); +static int _core_wend(mb_interpreter_t* s, void** l); +static int _core_do(mb_interpreter_t* s, void** l); +static int _core_until(mb_interpreter_t* s, void** l); +static int _core_exit(mb_interpreter_t* s, void** l); +static int _core_goto(mb_interpreter_t* s, void** l); +static int _core_gosub(mb_interpreter_t* s, void** l); +static int _core_return(mb_interpreter_t* s, void** l); +static int _core_end(mb_interpreter_t* s, void** l); +#ifdef _MB_ENABLE_ALLOC_STAT +static int _core_mem(mb_interpreter_t* s, void** l); +#endif /* _MB_ENABLE_ALLOC_STAT */ + +/** Std lib */ +static int _std_abs(mb_interpreter_t* s, void** l); +static int _std_sgn(mb_interpreter_t* s, void** l); +static int _std_sqr(mb_interpreter_t* s, void** l); +static int _std_floor(mb_interpreter_t* s, void** l); +static int _std_ceil(mb_interpreter_t* s, void** l); +static int _std_fix(mb_interpreter_t* s, void** l); +static int _std_round(mb_interpreter_t* s, void** l); +static int _std_rnd(mb_interpreter_t* s, void** l); +static int _std_sin(mb_interpreter_t* s, void** l); +static int _std_cos(mb_interpreter_t* s, void** l); +static int _std_tan(mb_interpreter_t* s, void** l); +static int _std_asin(mb_interpreter_t* s, void** l); +static int _std_acos(mb_interpreter_t* s, void** l); +static int _std_atan(mb_interpreter_t* s, void** l); +static int _std_exp(mb_interpreter_t* s, void** l); +static int _std_log(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_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_right(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_print(mb_interpreter_t* s, void** l); +static int _std_input(mb_interpreter_t* s, void** l); + +/** Lib information */ +static const _func_t _core_libs[] = { + { "#", _core_dummy_assign }, + { "+", _core_add }, + { "-", _core_min }, + { "*", _core_mul }, + { "/", _core_div }, + { "MOD", _core_mod }, + { "^", _core_pow }, + { "(", _core_open_bracket }, + { ")", _core_close_bracket }, + { 0, _core_neg }, + + { "=", _core_equal }, + { "<", _core_less }, + { ">", _core_greater }, + { "<=", _core_less_equal }, + { ">=", _core_greater_equal }, + { "<>", _core_not_equal }, + + { "AND", _core_and }, + { "OR", _core_or }, + { "NOT", _core_not }, + + { "LET", _core_let }, + { "DIM", _core_dim }, + + { "IF", _core_if }, + { "THEN", _core_then }, + { "ELSE", _core_else }, + + { "FOR", _core_for }, + { "TO", _core_to }, + { "STEP", _core_step }, + { "NEXT", _core_next }, + { "WHILE", _core_while }, + { "WEND", _core_wend }, + { "DO", _core_do }, + { "UNTIL", _core_until }, + + { "EXIT", _core_exit }, + { "GOTO", _core_goto }, + { "GOSUB", _core_gosub }, + { "RETURN", _core_return }, + + { "END", _core_end }, + +#ifdef _MB_ENABLE_ALLOC_STAT + { "MEM", _core_mem }, +#endif /* _MB_ENABLE_ALLOC_STAT */ +}; + +static const _func_t _std_libs[] = { + { "ABS", _std_abs }, + { "SGN", _std_sgn }, + { "SQR", _std_sqr }, + { "FLOOR", _std_floor }, + { "CEIL", _std_ceil }, + { "FIX", _std_fix }, + { "ROUND", _std_round }, + { "RND", _std_rnd }, + { "SIN", _std_sin }, + { "COS", _std_cos }, + { "TAN", _std_tan }, + { "ASIN", _std_asin }, + { "ACOS", _std_acos }, + { "ATAN", _std_atan }, + { "EXP", _std_exp }, + { "LOG", _std_log }, + + { "ASC", _std_asc }, + { "CHR", _std_chr }, + { "LEFT", _std_left }, + { "LEN", _std_len }, + { "MID", _std_mid }, + { "RIGHT", _std_right }, + { "STR", _std_str }, + { "VAL", _std_val }, + + { "PRINT", _std_print }, + { "INPUT", _std_input }, +}; + +/* ========================================================} */ + +/* +** {======================================================== +** Private function definitions +*/ + +/** List */ +int _ls_cmp_data(void* node, void* info) { + _ls_node_t* n = (_ls_node_t*)node; + + return (n->data == info) ? 0 : 1; +} + +int _ls_cmp_extra(void* node, void* info) { + _ls_node_t* n = (_ls_node_t*)node; + + return (n->extra == info) ? 0 : 1; +} + +int _ls_cmp_extra_string(void* node, void* info) { + _ls_node_t* n = (_ls_node_t*)node; + char* s1 = (char*)n->extra; + char* s2 = (char*)info; + + return strcmp(s1, s2); +} + +_ls_node_t* _ls_create_node(void* data) { + _ls_node_t* result = 0; + + result = (_ls_node_t*)mb_malloc(sizeof(_ls_node_t)); + mb_assert(result); + memset(result, 0, sizeof(_ls_node_t)); + result->data = data; + + return result; +} + +_ls_node_t* _ls_create(void) { + _ls_node_t* result = 0; + + result = _ls_create_node(0); + + return result; +} + +_ls_node_t* _ls_front(_ls_node_t* node) { + _ls_node_t* result = node; + + result = result->next; + + return result; +} + +_ls_node_t* _ls_back(_ls_node_t* node) { + _ls_node_t* result = node; + + result = result->prev; + + return result; +} + +_ls_node_t* _ls_at(_ls_node_t* list, int pos) { + _ls_node_t* result = list; + int i = 0; + + mb_assert(result && pos >= 0); + + for(i = 0; i <= pos; ++i) { + if(!result->next) { + result = 0; + + break; + } else { + result = result->next; + } + } + + return result; +} + +_ls_node_t* _ls_pushback(_ls_node_t* list, void* data) { + _ls_node_t* result = 0; + _ls_node_t* tmp = 0; + + mb_assert(list); + + result = _ls_create_node(data); + + tmp = _ls_back(list); + if(!tmp) { + tmp = list; + } + tmp->next = result; + result->prev = tmp; + list->prev = result; + + return result; +} + +_ls_node_t* _ls_pushfront(_ls_node_t* list, void* data) { + _ls_node_t* result = 0; + _ls_node_t* head = 0; + + mb_assert(list); + + result = _ls_create_node(data); + + head = list; + list = _ls_front(list); + head->next = result; + result->prev = head; + if(list) { + result->next = list; + list->prev = result; + } + + return result; +} + +_ls_node_t* _ls_insert(_ls_node_t* list, int pos, void* data) { + _ls_node_t* result = 0; + _ls_node_t* tmp = 0; + + mb_assert(list && pos >= 0); + + list = _ls_at(list, pos); + mb_assert(list); + if(list) { + result = _ls_create_node(data); + tmp = list->prev; + + tmp->next = result; + result->prev = tmp; + + result->next = list; + list->prev = result; + } + + return result; +} + +void* _ls_popback(_ls_node_t* list) { + void* result = 0; + _ls_node_t* tmp = 0; + + mb_assert(list); + + tmp = _ls_back(list); + if(tmp) { + result = tmp->data; + + if(list != tmp->prev) { + list->prev = tmp->prev; + } else { + list->prev = 0; + } + + tmp->prev->next = 0; + safe_free(tmp); + } + + return result; +} + +void* _ls_popfront(_ls_node_t* list) { + void* result = 0; + _ls_node_t* tmp = 0; + + mb_assert(list); + + tmp = _ls_front(list); + if(tmp) { + result = tmp->data; + + if(!tmp->next) { + list->prev = 0; + } + + tmp->prev->next = tmp->next; + if(tmp->next) { + tmp->next->prev = tmp->prev; + } + safe_free(tmp); + } + + return result; +} + +unsigned int _ls_remove(_ls_node_t* list, int pos) { + unsigned int result = 0; + _ls_node_t* tmp = 0; + + mb_assert(list && pos >= 0); + + tmp = _ls_at(list, pos); + if(tmp) { + if(tmp->prev) { + tmp->prev->next = tmp->next; + } + if(tmp->next) { + tmp->next->prev = tmp->prev; + } else { + list->prev = tmp->prev; + } + + safe_free(tmp); + + ++result; + } + + return result; +} + +unsigned int _ls_try_remove(_ls_node_t* list, void* info, _ls_compare cmp, _ls_operation op) { + unsigned int result = 0; + _ls_node_t* tmp = 0; + + mb_assert(list && cmp); + + tmp = list->next; + while(tmp) { + if(cmp(tmp, info) == 0) { + if(tmp->prev) { + tmp->prev->next = tmp->next; + } + if(tmp->next) { + tmp->next->prev = tmp->prev; + } + if(list->prev == tmp) { + list->prev = 0; + } + if(op) { + op(tmp->data, tmp->extra); + } + safe_free(tmp); + ++result; + + break; + } + tmp = tmp->next; + } + + return result; +} + +unsigned int _ls_count(_ls_node_t* list) { + unsigned int result = 0; + + mb_assert(list); + + while(list->next) { + ++result; + list = list->next; + } + + return result; +} + +unsigned int _ls_foreach(_ls_node_t* list, _ls_operation op) { + unsigned int idx = 0; + int opresult = _OP_RESULT_NORMAL; + _ls_node_t* tmp = 0; + + mb_assert(list && op); + + list = list->next; + while(list) { + opresult = op(list->data, list->extra); + ++idx; + tmp = list; + list = list->next; + + if(_OP_RESULT_NORMAL == opresult) { + /* Do nothing */ + } else if(_OP_RESULT_DEL_NODE == opresult) { + tmp->prev->next = list; + if(list) { + list->prev = tmp->prev; + } + safe_free(tmp); + } else { + /* Do nothing */ + } + } + + return idx; +} + +bool_t _ls_empty(_ls_node_t* list) { + bool_t result = false; + + mb_assert(list); + + result = 0 == list->next; + + return result; +} + +void _ls_clear(_ls_node_t* list) { + _ls_node_t* tmp = 0; + + mb_assert(list); + + tmp = list; + list = list->next; + tmp->next = 0; + tmp->prev = 0; + + while(list) { + tmp = list; + list = list->next; + safe_free(tmp); + } +} + +void _ls_destroy(_ls_node_t* list) { + _ls_clear(list); + + safe_free(list); +} + +int _ls_free_extra(void* data, void* extra) { + int result = _OP_RESULT_NORMAL; + mb_unrefvar(data); + + mb_assert(extra); + + safe_free(extra); + + result = _OP_RESULT_DEL_NODE; + + return result; +} + +/** Dictionary */ +unsigned int _ht_hash_string(void* ht, void* d) { + unsigned int result = 0; + _ht_node_t* self = (_ht_node_t*)ht; + char* s = (char*)d; + unsigned int h = 0; + + mb_assert(ht); + + for( ; *s; ++s) { + h = 5 * h + *s; + } + + result = h % self->array_size; + + return result; +} + +unsigned int _ht_hash_int(void* ht, void* d) { + unsigned int result = 0; + _ht_node_t* self = (_ht_node_t*)ht; + int_t i = *(int_t*)d; + + mb_assert(ht); + + result = (unsigned int)i; + result %= self->array_size; + + return result; +} + +unsigned int _ht_hash_real(void* ht, void* d) { + real_t r = *(real_t*)d; + union { + real_t r; + int_t i; + } u; + u.r = r; + + return _ht_hash_int(ht, &u.i); +} + +unsigned int _ht_hash_ptr(void* ht, void* d) { + union { + int_t i; + void* p; + } u; + u.p = d; + + return _ht_hash_int(ht, &u.i); +} + +int _ht_cmp_string(void* d1, void* d2) { + char* s1 = (char*)d1; + char* s2 = (char*)d2; + + return strcmp(s1, s2); +} + +int _ht_cmp_int(void* d1, void* d2) { + int_t i1 = *(int_t*)d1; + int_t i2 = *(int_t*)d2; + int_t i = i1 - i2; + int result = 0; + if(i < 0) { + result = -1; + } else if(i > 0) { + result = 1; + } + + return result; +} + +int _ht_cmp_real(void* d1, void* d2) { + real_t r1 = *(real_t*)d1; + real_t r2 = *(real_t*)d2; + real_t r = r1 - r2; + int result = 0; + if(r < 0.0f) { + result = -1; + } else if(r > 0.0f) { + result = 1; + } + + return result; +} + +int _ht_cmp_ptr(void* d1, void* d2) { + int_t i1 = *(int_t*)d1; + int_t i2 = *(int_t*)d2; + int_t i = i1 - i2; + int result = 0; + if(i < 0) { + result = -1; + } else if(i > 0) { + result = 1; + } + + return result; +} + +_ht_node_t* _ht_create(unsigned int size, _ht_compare cmp, _ht_hash hs, _ls_operation freeextra) { + const unsigned int array_size = size ? size : _HT_ARRAY_SIZE_DEFAULT; + _ht_node_t* result = 0; + unsigned int ul = 0; + + if(!cmp) { + cmp = _ht_cmp_int; + } + if(!hs) { + hs = _ht_hash_int; + } + + result = (_ht_node_t*)mb_malloc(sizeof(_ht_node_t)); + result->free_extra = freeextra; + result->compare = cmp; + result->hash = hs; + result->array_size = array_size; + result->count = 0; + result->array = (_ls_node_t**)mb_malloc(sizeof(_ls_node_t*) * result->array_size); + for(ul = 0; ul < result->array_size; ++ul) { + result->array[ul] = _ls_create(); + } + + return result; +} + +_ls_node_t* _ht_find(_ht_node_t* ht, void* key) { + _ls_node_t* result = 0; + _ls_node_t* bucket = 0; + unsigned int hash_code = 0; + + mb_assert(ht && key); + + hash_code = ht->hash(ht, key); + bucket = ht->array[hash_code]; + bucket = bucket->next; + while(bucket) { + if(ht->compare(bucket->extra, key) == 0) { + result = bucket; + + break; + } + bucket = bucket->next; + } + + return result; +} + +unsigned int _ht_count(_ht_node_t* ht) { + unsigned int result = 0; + + mb_assert(ht); + + result = ht->count; + + return result; +} + +unsigned int _ht_get(_ht_node_t* ht, void* key, void** value) { + unsigned int result = 0; + _ls_node_t* bucket = 0; + + mb_assert(ht && key && value); + + bucket = _ht_find(ht, key); + if(bucket) { + *value = bucket->data; + ++result; + } + + return result; +} + +unsigned int _ht_set(_ht_node_t* ht, void* key, void* value) { + unsigned int result = 0; + _ls_node_t* bucket = 0; + + mb_assert(ht && key); + + bucket = _ht_find(ht, key); + if(bucket) { + bucket->data = value; + ++result; + } + + return result; +} + +unsigned int _ht_set_or_insert(_ht_node_t* ht, void* key, void* value) { + unsigned int result = 0; + _ls_node_t* bucket = 0; + unsigned int hash_code = 0; + + mb_assert(ht && key); + + bucket = _ht_find(ht, key); + if(bucket) { /* Update */ + bucket->data = value; + ++result; + } else { /* Insert */ + hash_code = ht->hash(ht, key); + bucket = ht->array[hash_code]; + bucket = _ls_pushback(bucket, value); + mb_assert(bucket); + bucket->extra = key; + ++ht->count; + ++result; + } + + return result; +} + +unsigned int _ht_remove(_ht_node_t* ht, void* key, _ls_compare cmp) { + unsigned int result = 0; + unsigned int hash_code = 0; + _ls_node_t* bucket = 0; + + mb_assert(ht && key); + + if(!cmp) { + cmp = _ls_cmp_extra; + } + + bucket = _ht_find(ht, key); + hash_code = ht->hash(ht, key); + bucket = ht->array[hash_code]; + result = _ls_try_remove(bucket, key, cmp, ht->free_extra); + ht->count -= result; + + return result; +} + +unsigned int _ht_foreach(_ht_node_t* ht, _ht_operation op) { + unsigned int result = 0; + _ls_node_t* bucket = 0; + unsigned int ul = 0; + + for(ul = 0; ul < ht->array_size; ++ul) { + bucket = ht->array[ul]; + if(bucket) { + result += _ls_foreach(bucket, op); + } + } + + return result; +} + +bool_t _ht_empty(_ht_node_t* ht) { + return 0 == _ht_count(ht); +} + +void _ht_clear(_ht_node_t* ht) { + unsigned int ul = 0; + + mb_assert(ht && ht->array); + + for(ul = 0; ul < ht->array_size; ++ul) { + _ls_clear(ht->array[ul]); + } + ht->count = 0; +} + +void _ht_destroy(_ht_node_t* ht) { + unsigned int ul = 0; + + mb_assert(ht && ht->array); + + if(ht->free_extra) { + _ht_foreach(ht, ht->free_extra); + } + + for(ul = 0; ul < ht->array_size; ++ul) { + _ls_destroy(ht->array[ul]); + } + safe_free(ht->array); + safe_free(ht); +} + +/** Memory operations */ +void* mb_malloc(size_t s) { + char* ret = NULL; + size_t rs = s; +#ifdef _MB_ENABLE_ALLOC_STAT + rs += _MB_POINTER_SIZE; +#endif /* _MB_ENABLE_ALLOC_STAT */ + ret = (char*)malloc(rs); + mb_assert(ret); +#ifdef _MB_ENABLE_ALLOC_STAT + _mb_allocated += s; + ret += _MB_POINTER_SIZE; + _MB_WRITE_CHUNK_SIZE(ret, s); +#endif /* _MB_ENABLE_ALLOC_STAT */ + + return (void*)ret; +} + +void* mb_realloc(void** p, size_t s) { + char* ret = NULL; + size_t rs = s; + size_t os = 0; (void)os; + mb_assert(p); +#ifdef _MB_ENABLE_ALLOC_STAT + if(*p) { + os = _MB_READ_CHUNK_SIZE(*p); + *p = (char*)(*p) - _MB_POINTER_SIZE; + } + rs += _MB_POINTER_SIZE; +#endif /* _MB_ENABLE_ALLOC_STAT */ + ret = (char*)realloc(*p, rs); + mb_assert(ret); +#ifdef _MB_ENABLE_ALLOC_STAT + _mb_allocated -= os; + _mb_allocated += s; + ret += _MB_POINTER_SIZE; + _MB_WRITE_CHUNK_SIZE(ret, s); + *p = (void*)ret; +#endif /* _MB_ENABLE_ALLOC_STAT */ + + return (void*)ret; +} + +void mb_free(void* p) { + mb_assert(p); + +#ifdef _MB_ENABLE_ALLOC_STAT + do { + size_t os = _MB_READ_CHUNK_SIZE(p); + _mb_allocated -= os; + p = (char*)p - _MB_POINTER_SIZE; + } while(0); +#endif /* _MB_ENABLE_ALLOC_STAT */ + + free(p); +} + +/** Expression processing */ +bool_t _is_operator(mb_func_t op) { + /* Determine whether a function is an operator */ + bool_t result = false; + + result = + (op == _core_dummy_assign) || + (op == _core_add) || + (op == _core_min) || + (op == _core_mul) || + (op == _core_div) || + (op == _core_mod) || + (op == _core_pow) || + (op == _core_open_bracket) || + (op == _core_close_bracket) || + (op == _core_equal) || + (op == _core_less) || + (op == _core_greater) || + (op == _core_less_equal) || + (op == _core_greater_equal) || + (op == _core_not_equal) || + (op == _core_and) || + (op == _core_or); + + return result; +} + +bool_t _is_flow(mb_func_t op) { + /* Determine whether a function is for flow control */ + bool_t result = false; + + result = + (op == _core_if) || + (op == _core_then) || + (op == _core_else) || + (op == _core_for) || + (op == _core_to) || + (op == _core_step) || + (op == _core_next) || + (op == _core_while) || + (op == _core_wend) || + (op == _core_do) || + (op == _core_until) || + (op == _core_exit) || + (op == _core_goto) || + (op == _core_gosub) || + (op == _core_return) || + (op == _core_end); + + return result; +} + +char _get_priority(mb_func_t op1, mb_func_t op2) { + /* Get the priority of two operators */ + char result = '\0'; + int idx1 = 0; + int idx2 = 0; + + mb_assert(op1 && op2); + + idx1 = _get_priority_index(op1); + idx2 = _get_priority_index(op2); + mb_assert(idx1 < _countof(_PRECEDE_TABLE) && idx2 < _countof(_PRECEDE_TABLE[0])); + result = _PRECEDE_TABLE[idx1][idx2]; + + return result; +} + +int _get_priority_index(mb_func_t op) { + /* Get the index of an operator in the priority table */ + int result = 0; + + mb_assert(op); + + if(op == _core_dummy_assign) { + result = 8; + } else if(op == _core_add) { + result = 0; + } else if(op == _core_min) { + result = 1; + } else if(op == _core_mul) { + result = 2; + } else if(op == _core_div) { + result = 3; + } else if(op == _core_mod) { + result = 4; + } else if(op == _core_pow) { + result = 5; + } else if(op == _core_open_bracket) { + result = 6; + } else if(op == _core_close_bracket) { + result = 7; + } else if(op == _core_equal) { + result = 13; + } else if(op == _core_greater) { + result = 9; + } else if(op == _core_less) { + result = 10; + } else if(op == _core_greater_equal) { + result = 11; + } else if(op == _core_less_equal) { + result = 12; + } else if(op == _core_not_equal) { + result = 14; + } else if(op == _core_and) { + result = 15; + } else if(op == _core_or) { + result = 16; + } else if(op == _core_not) { + result = 17; + } else if(op == _core_neg) { + result = 18; + } else { + mb_assert(0 && "Unknown operator"); + } + + return result; +} + +_object_t* _operate_operand(mb_interpreter_t* s, _object_t* optr, _object_t* opnd1, _object_t* opnd2, int* status) { + /* Operate two operands */ + _object_t* result = 0; + _tuple3_t tp; + _tuple3_t* tpptr = 0; + int _status = 0; + + mb_assert(s && optr); + mb_assert(optr->type == _DT_FUNC); + + if(!opnd1) { + return result; + } + + result = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(result, 0, sizeof(_object_t)); + + memset(&tp, 0, sizeof(_tuple3_t)); + tp.e1 = opnd1; + tp.e2 = opnd2; + tp.e3 = result; + tpptr = &tp; + + _status = (optr->data.func->pointer)(s, (void**)(&tpptr)); + if(status) { + *status = _status; + } + if(_status != MB_FUNC_OK) { + if(_status != MB_FUNC_WARNING) { + safe_free(result); + result = 0; + } + _set_current_error(s, SE_RN_OPERATION_FAILED); + _set_error_pos(s, optr->source_pos, optr->source_row, optr->source_col); + } + + return result; +} + +bool_t _is_expression_terminal(mb_interpreter_t* s, _object_t* obj) { + /* Determine whether an object is an expression termination */ + bool_t result = false; + + mb_assert(s && obj); + + result = + (obj->type == _DT_EOS) || + (obj->type == _DT_SEP) || + (obj->type == _DT_FUNC && + (obj->data.func->pointer == _core_then || + obj->data.func->pointer == _core_else || + obj->data.func->pointer == _core_to || + obj->data.func->pointer == _core_step) + ); + + return result; +} + +int _calc_expression(mb_interpreter_t* s, _ls_node_t** l, _object_t** val) { + /* Calculate an expression */ + int result = 0; + _ls_node_t* ast = 0; + _running_context_t* running = 0; + _ls_node_t* garbage = 0; + _ls_node_t* optr = 0; + _ls_node_t* opnd = 0; + _object_t* c = 0; + _object_t* x = 0; + _object_t* a = 0; + _object_t* b = 0; + _object_t* r = 0; + _object_t* theta = 0; + char pri = '\0'; + + unsigned int arr_idx = 0; + mb_value_u arr_val; + _data_e arr_type; + _object_t* arr_elem = 0; + + _object_t* guard_val = 0; + int bracket_count = 0; + bool_t hack = false; + _ls_node_t* errn = 0; + + mb_assert(s && l); + + running = (_running_context_t*)(s->running_context); + ast = *l; + garbage = _ls_create(); + optr = _ls_create(); + opnd = _ls_create(); + + c = (_object_t*)(ast->data); + do { + if(c->type == _DT_STRING) { + if(ast->next) { + _object_t* _fsn = (_object_t*)ast->next->data; + if(_fsn->type == _DT_FUNC && _fsn->data.func->pointer == _core_add) { + break; + } + } + + (*val)->type = _DT_STRING; + (*val)->data.string = c->data.string; + (*val)->ref = true; + ast = ast->next; + + goto _exit; + } + } while(0); + guard_val = c; + ast = ast->next; + _ls_pushback(optr, _exp_assign); + while( + !(c->type == _DT_FUNC && + strcmp(c->data.func->name, "#") == 0) || + !(((_object_t*)(_ls_back(optr)->data))->type == _DT_FUNC && + strcmp(((_object_t*)(_ls_back(optr)->data))->data.func->name, "#") == 0)) { + if(!hack) { + if(c->type == _DT_FUNC && c->data.func->pointer == _core_open_bracket) { + ++bracket_count; + } else if(c->type == _DT_FUNC && c->data.func->pointer == _core_close_bracket) { + --bracket_count; + if(bracket_count < 0) { + c = _exp_assign; + ast = ast->prev; + + continue; + } + } + } + hack = false; + if(!(c->type == _DT_FUNC && _is_operator(c->data.func->pointer))) { + if(_is_expression_terminal(s, c)) { + c = _exp_assign; + if(ast) { + ast = ast->prev; + } + if(bracket_count) { + _object_t _cb; + _func_t _cbf; + memset(&_cb, 0, sizeof(_object_t)); + _cb.type = _DT_FUNC; + _cb.data.func = &_cbf; + _cb.data.func->name = ")"; + _cb.data.func->pointer = _core_close_bracket; + while(bracket_count) { + _ls_pushback(optr, &_cb); + bracket_count--; + } + errn = ast; + } + } else { + if(c->type == _DT_ARRAY) { + ast = ast->prev; + result = _get_array_index(s, &ast, &arr_idx); + if(result != MB_FUNC_OK) { + _handle_error_on_obj(s, SE_RN_CALCULATION_ERROR, DON(ast), MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + _get_array_elem(s, c->data.array, arr_idx, &arr_val, &arr_type); + arr_elem = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(arr_elem, 0, sizeof(_object_t)); + _ls_pushback(garbage, arr_elem); + arr_elem->type = arr_type; + if(arr_type == _DT_REAL) { + arr_elem->data.float_point = arr_val.float_point; + } else if(arr_type == _DT_STRING) { + arr_elem->data.string = arr_val.string; + } else { + mb_assert(0 && "Unsupported"); + } + _ls_pushback(opnd, arr_elem); + } else if(c->type == _DT_FUNC) { + ast = ast->prev; + result = (c->data.func->pointer)(s, (void**)(&ast)); + if(result != MB_FUNC_OK) { + _handle_error_on_obj(s, SE_RN_CALCULATION_ERROR, DON(ast), MB_FUNC_ERR, _exit, result); + } + c = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(c, 0, sizeof(_object_t)); + _ls_pushback(garbage, c); + result = _public_value_to_internal_object(&running->intermediate_value, c); + if(result != MB_FUNC_OK) { + goto _exit; + } + _ls_pushback(opnd, c); + } else { + if(c->type == _DT_VAR && ast) { + _object_t* _err_var = (_object_t*)(ast->data); + if(_err_var->type == _DT_FUNC && _err_var->data.func->pointer == _core_open_bracket) { + _handle_error_on_obj(s, SE_RN_INVALID_ID_USAGE, DON(ast), MB_FUNC_ERR, _exit, result); + } + } + _ls_pushback(opnd, c); + } + if(ast) { + c = (_object_t*)(ast->data); + if(c->type == _DT_FUNC && !_is_operator(c->data.func->pointer) && !_is_flow(c->data.func->pointer)) { + _ls_foreach(opnd, _remove_source_object); + + _handle_error_on_obj(s, SE_RN_COLON_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + } else { + c = _exp_assign; + } + } + } else { + pri = _get_priority(((_object_t*)(_ls_back(optr)->data))->data.func->pointer, c->data.func->pointer); + switch(pri) { + case '<': + _ls_pushback(optr, c); + c = (_object_t*)(ast->data); + ast = ast->next; + + break; + case '=': + x = (_object_t*)_ls_popback(optr); + c = (_object_t*)(ast->data); + ast = ast->next; + + break; + case '>': + theta = (_object_t*)_ls_popback(optr); + b = (_object_t*)_ls_popback(opnd); + a = (_object_t*)_ls_popback(opnd); + r = _operate_operand(s, theta, a, b, &result); + if(!r) { + _ls_clear(optr); + _handle_error_on_obj(s, SE_RN_OPERATION_FAILED, DON(errn), MB_FUNC_ERR, _exit, result); + } + _ls_pushback(opnd, r); + _ls_pushback(garbage, r); + if(c->type == _DT_FUNC && c->data.func->pointer == _core_close_bracket) { + hack = true; + } + + break; + } + } + } + + if(errn) { + _handle_error_on_obj(s, SE_RN_CLOSE_BRACKET_EXPECTED, DON(errn), MB_FUNC_ERR, _exit, result); + } + + c = (_object_t*)(_ls_popback(opnd)); + if(!c || !(c->type == _DT_INT || c->type == _DT_REAL || c->type == _DT_STRING || c->type == _DT_VAR)) { + _set_current_error(s, SE_RN_INVALID_DATA_TYPE); + result = MB_FUNC_ERR; + + goto _exit; + } + if(c->type == _DT_VAR) { + (*val)->type = c->data.variable->data->type; + (*val)->data = c->data.variable->data->data; + if(_is_string(c)) { + (*val)->ref = true; + } + } else { + (*val)->type = c->type; + if(_is_string(c)) { + size_t _sl = strlen(_extract_string(c)); + (*val)->data.string = (char*)mb_malloc(_sl + 1); + (*val)->data.string[_sl] = '\0'; + memcpy((*val)->data.string, c->data.string, _sl + 1); + } else { + (*val)->data = c->data; + } + } + if(guard_val != c && _ls_try_remove(garbage, c, _ls_cmp_data, NULL)) { + _destroy_object(c, 0); + } + +_exit: + _ls_foreach(garbage, _destroy_object); + _ls_destroy(garbage); + _ls_foreach(optr, _destroy_object); + _ls_foreach(opnd, _destroy_object); + _ls_destroy(optr); + _ls_destroy(opnd); + *l = ast; + + return result; +} + +bool_t _is_print_terminal(mb_interpreter_t* s, _object_t* obj) { + /* Determine whether an object is a PRINT termination */ + bool_t result = false; + + mb_assert(s && obj); + + result = + (obj->type == _DT_EOS) || + (obj->type == _DT_SEP && obj->data.separator == ':') || + (obj->type == _DT_FUNC && + (obj->data.func->pointer == _core_else) + ); + + return result; +} + +/** Others */ +void _set_current_error(mb_interpreter_t* s, mb_error_e err) { + /* Set current error information */ + mb_assert(s && err >= 0 && err < _countof(_ERR_DESC)); + + if(s->last_error == SE_NO_ERR) { + s->last_error = err; + } +} + +const char* _get_error_desc(mb_error_e err) { + /* Get the description text of an error information */ + mb_assert(err >= 0 && err < _countof(_ERR_DESC)); + + return _ERR_DESC[err]; +} + +mb_print_func_t _get_printer(mb_interpreter_t* s) { + /* Get a print functor according to an interpreter */ + mb_assert(s); + + if(s->printer) { + return s->printer; + } + + return printf; +} + +mb_input_func_t _get_inputer(mb_interpreter_t* s) { + /* Get an input functor according to an interpreter */ + mb_assert(s); + + if(s->inputer) { + return s->inputer; + } + + return mb_gets; +} + +bool_t _is_blank(char c) { + /* Determine whether a char is a blank */ + return (' ' == c) || ('\t' == c); +} + +bool_t _is_newline(char c) { + /* Determine whether a char is a newline */ + return ('\r' == c) || ('\n' == c) || (EOF == c); +} + +bool_t _is_separator(char c) { + /* Determine whether a char is a separator */ + return (',' == c) || (';' == c) || (':' == c); +} + +bool_t _is_bracket(char c) { + /* Determine whether a char is a bracket */ + return ('(' == c) || (')' == c); +} + +bool_t _is_quotation_mark(char c) { + /* Determine whether a char is a quotation mark */ + return ('"' == c); +} + +bool_t _is_comment(char c) { + /* Determine whether a char is a comment mark */ + return ('\'' == c); +} + +bool_t _is_identifier_char(char c) { + /* Determine whether a char is an identifier char */ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c == '_') || + (c >= '0' && c <= '9') || + (c == '$') || + (c == '.'); +} + +bool_t _is_operator_char(char c) { + /* Determine whether a char is an operator char */ + return (c == '+') || (c == '-') || (c == '*') || (c == '/') || + (c == '^') || + (c == '(') || (c == ')') || + (c == '=') || + (c == '>') || (c == '<'); +} + +int _append_char_to_symbol(mb_interpreter_t* s, char c) { + /* Parse a char and append it to current parsing symbol */ + int result = MB_FUNC_OK; + _parsing_context_t* context = 0; + + mb_assert(s); + + context = (_parsing_context_t*)(s->parsing_context); + + if(context->current_symbol_nonius + 1 >= _SINGLE_SYMBOL_MAX_LENGTH) { + _set_current_error(s, SE_PS_SYMBOL_TOO_LONG); + + ++result; + } else { + context->current_symbol[context->current_symbol_nonius] = c; + ++context->current_symbol_nonius; + } + + return result; +} + +int _cut_symbol(mb_interpreter_t* s, int pos, unsigned short row, unsigned short col) { + /* Current symbol parsing done and cut it */ + int result = MB_FUNC_OK; + _parsing_context_t* context = 0; + char* sym = 0; + int status = 0; + bool_t delsym = false; + + mb_assert(s); + + context = (_parsing_context_t*)(s->parsing_context); + if(context->current_symbol_nonius && context->current_symbol[0] != '\0') { + sym = (char*)mb_malloc(context->current_symbol_nonius + 1); + memcpy(sym, context->current_symbol, context->current_symbol_nonius + 1); + + status = _append_symbol(s, sym, &delsym, pos, row, col); + if(status || delsym) { + safe_free(sym); + } + result = status; + } + memset(context->current_symbol, 0, sizeof(context->current_symbol)); + context->current_symbol_nonius = 0; + + return result; +} + +int _append_symbol(mb_interpreter_t* s, char* sym, bool_t* delsym, int pos, unsigned short row, unsigned short col) { + /* Append cut current symbol to AST list */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + _ls_node_t** assign = 0; + _ls_node_t* node = 0; + _parsing_context_t* context = 0; + + mb_assert(s && sym); + + ast = (_ls_node_t*)(s->ast); + result = _create_symbol(s, ast, sym, &obj, &assign, delsym); + if(obj) { + obj->source_pos = pos; + obj->source_row = row; + obj->source_col = col; + + node = _ls_pushback(ast, obj); + if(assign) { + *assign = node; + } + + context = (_parsing_context_t*)s->parsing_context; + context->last_symbol = obj; + } + + return result; +} + +int _create_symbol(mb_interpreter_t* s, _ls_node_t* l, char* sym, _object_t** obj, _ls_node_t*** asgn, bool_t* delsym) { + /* 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; + unsigned int ul = 0; + _parsing_context_t* context = 0; + _ls_node_t* glbsyminscope = 0; + mb_unrefvar(l); + + mb_assert(s && sym && obj); + + context = (_parsing_context_t*)s->parsing_context; + + *obj = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(*obj, 0, sizeof(_object_t)); + (*obj)->source_pos = -1; + (*obj)->source_row = (*obj)->source_col = 0xffff; + + type = _get_symbol_type(s, sym, &value); + (*obj)->type = type; + switch(type) { + case _DT_INT: + tmp.any = value; + (*obj)->data.integer = tmp.integer; + safe_free(sym); + + break; + case _DT_REAL: + tmp.any = value; + (*obj)->data.float_point = tmp.float_point; + safe_free(sym); + + break; + case _DT_STRING: { + size_t _sl = strlen(sym); + (*obj)->data.string = (char*)mb_malloc(_sl - 2 + 1); + memcpy((*obj)->data.string, sym + sizeof(char), _sl - 2); + (*obj)->data.string[_sl - 2] = '\0'; + *delsym = true; + } + + break; + case _DT_FUNC: + 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; + (*obj)->data.func = tmp.func; + + break; + case _DT_ARRAY: + glbsyminscope = _ht_find((_ht_node_t*)s->global_var_dict, sym); + if(glbsyminscope && ((_object_t*)(glbsyminscope->data))->type == _DT_ARRAY) { + (*obj)->data.array = ((_object_t*)(glbsyminscope->data))->data.array; + (*obj)->ref = true; + *delsym = true; + } else { + 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; + (*obj)->data.array = tmp.array; + + ul = _ht_set_or_insert((_ht_node_t*)s->global_var_dict, sym, *obj); + mb_assert(ul); + + *obj = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(*obj, 0, sizeof(_object_t)); + (*obj)->type = type; + (*obj)->data.array = tmp.array; + (*obj)->ref = true; + } + + break; + case _DT_VAR: + glbsyminscope = _ht_find((_ht_node_t*)s->global_var_dict, sym); + if(glbsyminscope && ((_object_t*)(glbsyminscope->data))->type == _DT_VAR) { + (*obj)->data.variable = ((_object_t*)(glbsyminscope->data))->data.variable; + (*obj)->ref = true; + *delsym = true; + } else { + tmp.var = (_var_t*)mb_malloc(sizeof(_var_t)); + memset(tmp.var, 0, sizeof(_var_t)); + tmp.var->name = sym; + tmp.var->data = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(tmp.var->data, 0, sizeof(_object_t)); + tmp.var->data->type = (sym[strlen(sym) - 1] == '$') ? _DT_STRING : _DT_INT; + tmp.var->data->data.integer = 0; + (*obj)->data.variable = tmp.var; + + ul = _ht_set_or_insert((_ht_node_t*)s->global_var_dict, sym, *obj); + mb_assert(ul); + + *obj = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(*obj, 0, sizeof(_object_t)); + (*obj)->type = type; + (*obj)->data.variable = tmp.var; + (*obj)->ref = true; + } + + break; + case _DT_LABEL: + if(context->current_char == ':') { + if(value) { + (*obj)->data.label = value; + (*obj)->ref = true; + *delsym = true; + } else { + tmp.label = (_label_t*)mb_malloc(sizeof(_label_t)); + memset(tmp.label, 0, sizeof(_label_t)); + tmp.label->name = sym; + *asgn = &(tmp.label->node); + (*obj)->data.label = tmp.label; + + ul = _ht_set_or_insert((_ht_node_t*)s->global_var_dict, sym, *obj); + mb_assert(ul); + + *obj = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(*obj, 0, sizeof(_object_t)); + (*obj)->type = type; + (*obj)->data.label = tmp.label; + (*obj)->ref = true; + } + } else { + (*obj)->data.label = (_label_t*)mb_malloc(sizeof(_label_t)); + memset((*obj)->data.label, 0, sizeof(_label_t)); + (*obj)->data.label->name = sym; + } + + break; + case _DT_SEP: + (*obj)->data.separator = sym[0]; + safe_free(sym); + + break; + case _DT_EOS: + safe_free(sym); + + break; + default: + break; + } + + return result; +} + +_data_e _get_symbol_type(mb_interpreter_t* s, char* sym, void** 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; + char* conv_suc = 0; + _parsing_context_t* context = 0; + _ls_node_t* lclsyminscope = 0; + _ls_node_t* glbsyminscope = 0; + size_t _sl = 0; + + mb_assert(s && sym); + _sl = strlen(sym); + mb_assert(_sl > 0); + + context = (_parsing_context_t*)s->parsing_context; + + /* int_t */ + tmp.integer = (int_t)strtol(sym, &conv_suc, 0); + if(*conv_suc == '\0') { + *value = tmp.any; + + result = _DT_INT; + + goto _exit; + } + /* real_t */ + tmp.float_point = (real_t)strtod(sym, &conv_suc); + if(*conv_suc == '\0') { + *value = tmp.any; + + result = _DT_REAL; + + goto _exit; + } + /* string */ + if(sym[0] == '"' && sym[_sl - 1] == '"' && _sl >= 2) { + result = _DT_STRING; + + goto _exit; + } + /* _array_t */ + 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); + + result = _DT_ARRAY; + + goto _exit; + } + 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); + + result = _DT_ARRAY; + + goto _exit; + } + } + /* _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(strcmp("-", sym) == 0) { + *value = (void*)(intptr_t)(_core_neg); + + result = _DT_FUNC; + + goto _exit; + } + } + 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; + + result = _DT_FUNC; + + goto _exit; + } + /* _EOS */ + if(_sl == 1 && sym[0] == _EOS) { + result = _DT_EOS; + + goto _exit; + } + /* separator */ + if(_sl == 1 && _is_separator(sym[0])) { + result = _DT_SEP; + + goto _exit; + } + /* _var_t */ + glbsyminscope = _ht_find((_ht_node_t*)s->global_var_dict, sym); + if(glbsyminscope) { + if(((_object_t*)glbsyminscope->data)->type != _DT_LABEL) { + *value = glbsyminscope->data; + + result = _DT_VAR; + + goto _exit; + } + } + /* _label_t */ + if(context->current_char == ':') { + 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; + } + + result = _DT_LABEL; + + goto _exit; + } + } + if(context->last_symbol && context->last_symbol->type == _DT_FUNC) { + if(context->last_symbol->data.func->pointer == _core_goto || context->last_symbol->data.func->pointer == _core_gosub) { + result = _DT_LABEL; + + goto _exit; + } + } + /* else */ + result = _DT_VAR; + +_exit: + return result; +} + +int _parse_char(mb_interpreter_t* s, char c, int pos, unsigned short row, unsigned short col) { + /* Parse a char */ + int result = MB_FUNC_OK; + _parsing_context_t* context = 0; + + mb_assert(s && s->parsing_context); + + context = (_parsing_context_t*)(s->parsing_context); + + context->current_char = c; + + if(context->parsing_state == _PS_NORMAL) { + if(c >= 'a' && c <= 'z') { + c += 'A' - 'a'; + } + + if(_is_blank(c)) { /* \t ' ' */ + result += _cut_symbol(s, pos, row, col); + } else if(_is_newline(c)) { /* \r \n EOF */ + result += _cut_symbol(s, pos, row, col); + result += _append_char_to_symbol(s, _EOS); + result += _cut_symbol(s, pos, row, col); + } else if(_is_separator(c) || _is_bracket(c)) { /* , ; : ( ) */ + result += _cut_symbol(s, pos, row, col); + result += _append_char_to_symbol(s, c); + result += _cut_symbol(s, pos, row, col); + } else if(_is_quotation_mark(c)) { /* " */ + result += _cut_symbol(s, pos, row, col); + result += _append_char_to_symbol(s, c); + context->parsing_state = _PS_STRING; + } else if(_is_comment(c)) { /* ' */ + result += _cut_symbol(s, pos, row, col); + result += _append_char_to_symbol(s, _EOS); + result += _cut_symbol(s, pos, row, col); + context->parsing_state = _PS_COMMENT; + } else { + if(context->symbol_state == _SS_IDENTIFIER) { + 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); + } else { + _handle_error(s, SE_PS_INVALID_CHAR, pos, row, col, MB_FUNC_ERR, _exit, result); + } + } else if(context->symbol_state == _SS_OPERATOR) { + if(_is_identifier_char(c)) { + context->symbol_state = _SS_IDENTIFIER; + result += _cut_symbol(s, pos, row, col); + result += _append_char_to_symbol(s, c); + } else if(_is_operator_char(c)) { + if(c == '-') { + 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); + } + } else { + mb_assert(0 && "Impossible here"); + } + } + } else if(context->parsing_state == _PS_STRING) { + if(_is_quotation_mark(c)) { /* " */ + result += _append_char_to_symbol(s, c); + result += _cut_symbol(s, pos, row, col); + context->parsing_state = _PS_NORMAL; + } else { + result += _append_char_to_symbol(s, c); + } + } else if(context->parsing_state == _PS_COMMENT) { + if(_is_newline(c)) { /* \r \n EOF */ + context->parsing_state = _PS_NORMAL; + } else { + /* Do nothing */ + } + } else { + mb_assert(0 && "Unknown parsing state"); + } + +_exit: + return result; +} + +void _set_error_pos(mb_interpreter_t* s, int pos, unsigned short row, unsigned short col) { + /* Set the position of a parsing error */ + mb_assert(s); + + s->last_error_pos = pos; + s->last_error_row = row; + s->last_error_col = col; +} + +int_t _get_size_of(_data_e type) { + /* Get the size of a data type */ + int_t result = 0; + + if(type == _DT_INT) { + result = sizeof(int_t); + } else if(type == _DT_REAL) { + result = sizeof(real_t); + } else if(type == _DT_STRING) { + result = sizeof(char*); + } else { + mb_assert(0 && "Unsupported"); + } + + return result; +} + +bool_t _try_get_value(_object_t* obj, mb_value_u* val, _data_e expected) { + /* Try to get a value(typed as int_t, real_t or char*) */ + bool_t result = false; + + mb_assert(obj && val); + if(obj->type == _DT_INT && (expected == _DT_ANY || expected == _DT_INT)) { + val->integer = obj->data.integer; + result = true; + } else if(obj->type == _DT_REAL && (expected == _DT_ANY || expected == _DT_REAL)) { + val->float_point = obj->data.float_point; + result = true; + } else if(obj->type == _DT_VAR) { + result = _try_get_value(obj->data.variable->data, val, expected); + } + + return result; +} + +int _get_array_index(mb_interpreter_t* s, _ls_node_t** l, unsigned int* index) { + /* Calculate the index */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* arr = 0; + _object_t* len = 0; + _object_t subscript; + _object_t* subscript_ptr = 0; + mb_value_u val; + int dcount = 0; + unsigned int idx = 0; + + mb_assert(s && l && index); + + subscript_ptr = &subscript; + + /* Array name */ + ast = (_ls_node_t*)(*l); + if(!ast || ((_object_t*)(ast->data))->type != _DT_ARRAY) { + _handle_error_on_obj(s, SE_RN_ARRAY_IDENTIFIER_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + arr = (_object_t*)(ast->data); + /* ( */ + if(!ast->next || ((_object_t*)(ast->next->data))->type != _DT_FUNC || ((_object_t*)(ast->next->data))->data.func->pointer != _core_open_bracket) { + _handle_error_on_obj(s, SE_RN_OPEN_BRACKET_EXPECTED, + (ast && ast->next) ? ((_object_t*)(ast->next->data)) : 0, + MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + /* Array subscript */ + if(!ast->next) { + _handle_error_on_obj(s, SE_RN_ARRAY_SUBSCRIPT_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + while(((_object_t*)(ast->data))->type != _DT_FUNC || ((_object_t*)(ast->data))->data.func->pointer != _core_close_bracket) { + /* Calculate an integer value */ + result = _calc_expression(s, &ast, &subscript_ptr); + if(result != MB_FUNC_OK) { + goto _exit; + } + len = subscript_ptr; + if(!_try_get_value(len, &val, _DT_INT)) { + _handle_error_on_obj(s, SE_RN_TYPE_NOT_MATCH, DON(ast), MB_FUNC_ERR, _exit, result); + } + if(val.integer < 0) { + _handle_error_on_obj(s, SE_RN_ILLEGAL_BOUND, DON(ast), MB_FUNC_ERR, _exit, result); + } + if(dcount + 1 > arr->data.array->dimension_count) { + _handle_error_on_obj(s, SE_RN_DIMENSION_OUT_OF_BOUND, DON(ast), MB_FUNC_ERR, _exit, result); + } + if(val.integer > arr->data.array->dimensions[dcount]) { + _handle_error_on_obj(s, SE_RN_ARRAY_OUT_OF_BOUND, DON(ast), MB_FUNC_ERR, _exit, result); + } + if(idx) { + idx *= (unsigned int)val.integer; + } else { + idx += (unsigned int)val.integer; + } + /* Comma? */ + if(((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ',') { + ast = ast->next; + } + + ++dcount; + } + *index = idx; + +_exit: + *l = ast; + + return result; +} + +bool_t _get_array_elem(mb_interpreter_t* s, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type) { + /* Get the value of an element in an array */ + bool_t result = true; + int_t elemsize = 0; + unsigned int pos = 0; + void* rawptr = 0; + + mb_assert(s && arr && val && type); + + mb_assert(index < arr->count); + elemsize = _get_size_of(arr->type); + pos = (unsigned int)(elemsize * index); + rawptr = (void*)((intptr_t)arr->raw + pos); + if(arr->type == _DT_REAL) { + val->float_point = *((real_t*)rawptr); + *type = _DT_REAL; + } else if(arr->type == _DT_STRING) { + val->string = *((char**)rawptr); + *type = _DT_STRING; + } else { + mb_assert(0 && "Unsupported"); + } + + return result; +} + +bool_t _set_array_elem(mb_interpreter_t* s, _array_t* arr, unsigned int index, mb_value_u* val, _data_e* type) { + /* Set the value of an element in an array */ + bool_t result = true; + int_t elemsize = 0; + unsigned int pos = 0; + void* rawptr = 0; + + mb_assert(s && arr && val); + + mb_assert(index < arr->count); + elemsize = _get_size_of(arr->type); + pos = (unsigned int)(elemsize * index); + rawptr = (void*)((intptr_t)arr->raw + pos); + if(*type == _DT_INT) { + *((real_t*)rawptr) = (real_t)val->integer; + } else if(*type == _DT_REAL) { + *((real_t*)rawptr) = val->float_point; + } else if(*type == _DT_STRING) { + size_t _sl = strlen(val->string); + *((char**)rawptr) = (char*)mb_malloc(_sl + 1); + memcpy(*((char**)rawptr), val->string, _sl + 1); + } else { + mb_assert(0 && "Unsupported"); + } + + return result; +} + +void _init_array(_array_t* arr) { + /* Initialize an array */ + int elemsize = 0; + + mb_assert(arr); + + elemsize = (int)_get_size_of(arr->type); + mb_assert(arr->count > 0); + mb_assert(!arr->raw); + arr->raw = (void*)mb_malloc(elemsize * arr->count); + if(arr->raw) { + memset(arr->raw, 0, elemsize * arr->count); + } +} + +void _clear_array(_array_t* arr) { + /* Clear an array */ + char** strs = 0; + unsigned int ul = 0; + + mb_assert(arr); + + if(arr->raw) { + switch(arr->type) { + case _DT_INT: /* Fall through */ + case _DT_REAL: + safe_free(arr->raw); + + break; + case _DT_STRING: + strs = (char**)arr->raw; + for(ul = 0; ul < arr->count; ++ul) { + if(strs[ul]) { + safe_free(strs[ul]); + } + } + safe_free(arr->raw); + + break; + default: + mb_assert(0 && "Unsupported"); + + break; + } + arr->raw = 0; + } +} + +void _destroy_array(_array_t* arr) { + /* Destroy an array */ + mb_assert(arr); + + _clear_array(arr); + safe_free(arr->name); + safe_free(arr); +} + +bool_t _is_string(void* obj) { + /* Determine whether an object is a string value or a string variable */ + bool_t result = false; + _object_t* o = 0; + + mb_assert(obj); + + o = (_object_t*)obj; + if(o->type == _DT_STRING) { + result = true; + } else if(o->type == _DT_VAR) { + result = o->data.variable->data->type == _DT_STRING; + } + + return result; +} + +char* _extract_string(_object_t* obj) { + /* Extract a string inside an object */ + char* result = 0; + + mb_assert(obj); + + if(obj->type == _DT_STRING) { + result = obj->data.string; + } else if(obj->type == _DT_VAR && obj->data.variable->data->type == _DT_STRING) { + result = obj->data.variable->data->data.string; + } + + return result; +} + +bool_t _is_internal_object(_object_t* obj) { + /* Determine whether an object is an internal one */ + bool_t result = false; + + mb_assert(obj); + + result = (_exp_assign == obj) || + (_OBJ_BOOL_TRUE == obj) || (_OBJ_BOOL_FALSE == obj); + + return result; +} + +int _dispose_object(_object_t* obj) { + /* Dispose a syntax object */ + int result = 0; + _var_t* var = 0; + + mb_assert(obj); + + if(_is_internal_object(obj)) { + goto _exit; + } + switch(obj->type) { + case _DT_VAR: + if(!obj->ref) { + var = (_var_t*)(obj->data.variable); + safe_free(var->name); + mb_assert(var->data->type != _DT_VAR); + _destroy_object(var->data, 0); + safe_free(var); + } + + break; + case _DT_STRING: + if(!obj->ref) { + if(obj->data.string) { + safe_free(obj->data.string); + } + } + + break; + case _DT_FUNC: + safe_free(obj->data.func->name); + safe_free(obj->data.func); + + break; + case _DT_ARRAY: + if(!obj->ref) { + _destroy_array(obj->data.array); + } + + break; + case _DT_LABEL: + if(!obj->ref) { + safe_free(obj->data.label->name); + safe_free(obj->data.label); + } + + break; + case _DT_NIL: /* Fall through */ + case _DT_INT: /* Fall through */ + case _DT_REAL: /* Fall through */ + case _DT_SEP: /* Fall through */ + case _DT_EOS: /* Fall through */ + case _DT_USERTYPE: /* Do nothing */ + break; + default: + mb_assert(0 && "Invalid type"); + + break; + } + obj->ref = false; + obj->type = _DT_NIL; + memset(&obj->data, 0, sizeof(obj->data)); + obj->source_pos = 0; + obj->source_row = 0; + obj->source_col = 0; + ++result; + +_exit: + return result; +} + +int _destroy_object(void* data, void* extra) { + /* Destroy a syntax object */ + int result = _OP_RESULT_NORMAL; + _object_t* obj = 0; + mb_unrefvar(extra); + + mb_assert(data); + + obj = (_object_t*)data; + if(!_dispose_object(obj)) { + goto _exit; + } + safe_free(obj); + +_exit: + result = _OP_RESULT_DEL_NODE; + + return result; +} + +int _remove_source_object(void* data, void* extra) { + /* Remove an object referenced from source code */ + int result = _OP_RESULT_DEL_NODE; + mb_unrefvar(extra); + + mb_assert(data); + + return result; +} + +int _compare_numbers(const _object_t* first, const _object_t* second) { + /* Compare two numbers inside two _object_t */ + int result = 0; + + mb_assert(first && second); + mb_assert((first->type == _DT_INT || first->type == _DT_REAL) && (second->type == _DT_INT || second->type == _DT_REAL)); + + if(first->type == _DT_INT && second->type == _DT_INT) { + if(first->data.integer > second->data.integer) { + result = 1; + } else if(first->data.integer < second->data.integer) { + result = -1; + } + } else if(first->type == _DT_REAL && second->type == _DT_REAL) { + if(first->data.float_point > second->data.float_point) { + result = 1; + } else if(first->data.float_point < second->data.float_point) { + result = -1; + } + } else { + if((first->type == _DT_INT ? (real_t)first->data.integer : first->data.float_point) > (second->type == _DT_INT ? (real_t)second->data.integer : second->data.float_point)) { + result = 1; + } else if((first->type == _DT_INT ? (real_t)first->data.integer : first->data.float_point) > (second->type == _DT_INT ? (real_t)second->data.integer : second->data.float_point)) { + result = -1; + } + } + + return result; +} + +int _public_value_to_internal_object(mb_value_t* pbl, _object_t* itn) { + /* Assign a public mb_value_t to an internal _object_t */ + int result = MB_FUNC_OK; + + mb_assert(pbl && itn); + + switch(pbl->type) { + case MB_DT_INT: + itn->type = _DT_INT; + itn->data.integer = pbl->value.integer; + + break; + case MB_DT_REAL: + itn->type = _DT_REAL; + itn->data.float_point = pbl->value.float_point; + + break; + case MB_DT_STRING: + itn->type = _DT_STRING; + itn->data.string = pbl->value.string; + + break; + default: + result = MB_FUNC_ERR; + + break; + } + + return result; +} + +int _internal_object_to_public_value(_object_t* itn, mb_value_t* pbl) { + /* Assign an internal _object_t to a public mb_value_t */ + int result = MB_FUNC_OK; + + mb_assert(pbl && itn); + + switch(itn->type) { + case _DT_INT: + pbl->type = MB_DT_INT; + pbl->value.integer = itn->data.integer; + + break; + case _DT_REAL: + pbl->type = MB_DT_REAL; + pbl->value.float_point = itn->data.float_point; + + break; + case _DT_STRING: + pbl->type = MB_DT_STRING; + pbl->value.string = itn->data.string; + + break; + default: + result = MB_FUNC_ERR; + + break; + } + + return result; +} + +int _execute_statement(mb_interpreter_t* s, _ls_node_t** l) { + /* Execute the ast, core execution function */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + _running_context_t* running = 0; + bool_t skip_to_eoi = true; + + mb_assert(s && l); + + running = (_running_context_t*)(s->running_context); + + ast = *l; + + obj = (_object_t*)(ast->data); + switch(obj->type) { + case _DT_FUNC: + result = (obj->data.func->pointer)(s, (void**)(&ast)); + + break; + case _DT_VAR: /* Fall through */ + case _DT_ARRAY: + result = _core_let(s, (void**)(&ast)); + + break; + case _DT_INT: /* Fall through */ + case _DT_REAL: /* Fall through */ + case _DT_STRING: + _handle_error_on_obj(s, SE_RN_INVALID_EXPRESSION, DON(ast), MB_FUNC_ERR, _exit, result); + + break; + default: + break; + } + if(result != MB_FUNC_OK && result != MB_FUNC_SUSPEND && result != MB_SUB_RETURN) { + goto _exit; + } + if(ast) { + obj = (_object_t*)(ast->data); + if(obj && obj->type == _DT_EOS) { + ast = ast->next; + } else if(obj && obj->type == _DT_SEP && obj->data.separator == ':') { + skip_to_eoi = false; + ast = ast->next; + } else if(obj && obj->type == _DT_VAR) { + _handle_error_on_obj(s, SE_RN_COLON_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } else if( + (obj && obj->type != _DT_FUNC) || ( + obj && obj->type == _DT_FUNC && ( + _is_operator(obj->data.func->pointer) || + _is_flow(obj->data.func->pointer) + ) + ) + ) { + ast = ast->next; + } else { + _handle_error_on_obj(s, SE_RN_COLON_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + } + if(skip_to_eoi && running->skip_to_eoi && running->skip_to_eoi == _ls_back(running->sub_stack)) { + running->skip_to_eoi = 0; + obj = (_object_t*)(ast->data); + if(obj->type != _DT_EOS) { + result = _skip_to(s, &ast, 0, _DT_EOS); + if(result != MB_FUNC_OK) { + goto _exit; + } + } + } + +_exit: + *l = ast; + + return result; +} + +int _skip_to(mb_interpreter_t* s, _ls_node_t** l, mb_func_t f, _data_e t) { + /* Skip current execution flow to a specific function */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _ls_node_t* tmp = 0; + _object_t* obj = 0; + + mb_assert(s && l); + + ast = *l; + mb_assert(ast && ast->prev); + do { + if(!ast) { + _handle_error_on_obj(s, SE_RN_SYNTAX, DON(tmp), MB_FUNC_ERR, _exit, result); + } + tmp = ast; + obj = (_object_t*)(ast->data); + *l = ast; + ast = ast->next; + } while(!(obj->type == _DT_FUNC && obj->data.func->pointer == f) && obj->type != t); + +_exit: + return result; +} + +int _skip_struct(mb_interpreter_t* s, _ls_node_t** l, mb_func_t open_func, mb_func_t close_func) { + /* Skip current structure */ + int result = MB_FUNC_OK; + int count = 0; + _ls_node_t* ast = 0; + _object_t* obj = 0; + _object_t* obj_prev = 0; + + mb_assert(s && l && open_func && close_func); + + ast = (_ls_node_t*)(*l); + + count = 1; + do { + if(!ast->next) { + _handle_error_on_obj(s, SE_RN_STRUCTURE_NOT_COMPLETED, DON(ast), MB_FUNC_ERR, _exit, result); + } + obj_prev = (_object_t*)(ast->data); + ast = ast->next; + obj = (_object_t*)(ast->data); + if(obj->type == _DT_FUNC && obj->data.func->pointer == open_func) { + ++count; + } else if(obj->type == _DT_FUNC && obj->data.func->pointer == close_func && + (obj_prev && obj_prev->type == _DT_EOS)) { + --count; + } + } while(count); + +_exit: + *l = ast; + + return result; +} + +int _register_func(mb_interpreter_t* s, const char* n, mb_func_t f, bool_t local) { + /* Register a function to a MY-BASIC environment */ + int result = 0; + _ht_node_t* scope = 0; + _ls_node_t* exists = 0; + char* name = 0; + + mb_assert(s); + + if(!n) { + return result; + } + + scope = (_ht_node_t*)(local ? s->local_func_dict : s->global_func_dict); + exists = _ht_find(scope, (void*)n); + if(!exists) { + size_t _sl = strlen(n); + name = (char*)mb_malloc(_sl + 1); + memcpy(name, n, _sl + 1); + _strupr(name); + result += _ht_set_or_insert(scope, (void*)name, (void*)(intptr_t)f); + } else { + _set_current_error(s, SE_CM_FUNC_EXISTS); + } + + return result; +} + +int _remove_func(mb_interpreter_t* s, const char* n, bool_t local) { + /* Remove a function from a MY-BASIC environment */ + int result = 0; + _ht_node_t* scope = 0; + _ls_node_t* exists = 0; + char* name = 0; + + mb_assert(s); + + if(!n) { + return result; + } + + scope = (_ht_node_t*)(local ? s->local_func_dict : s->global_func_dict); + exists = _ht_find(scope, (void*)n); + if(exists) { + size_t _sl = strlen(n); + name = (char*)mb_malloc(_sl + 1); + memcpy(name, n, _sl + 1); + _strupr(name); + result += _ht_remove(scope, (void*)name, _ls_cmp_extra_string); + safe_free(name); + } else { + _set_current_error(s, SE_CM_FUNC_NOT_EXISTS); + } + + return result; +} + +int _open_constant(mb_interpreter_t* s) { + /* Open global constant */ + int result = MB_FUNC_OK; + unsigned long ul = 0; + + mb_assert(s); + + ul = _ht_set_or_insert((_ht_node_t*)(s->global_var_dict), "TRUE", (_OBJ_BOOL_TRUE)); + mb_assert(ul); + ul = _ht_set_or_insert((_ht_node_t*)(s->global_var_dict), "FALSE", (_OBJ_BOOL_FALSE)); + mb_assert(ul); + + return result; +} + +int _close_constant(mb_interpreter_t* s) { + /* Close global constant */ + int result = MB_FUNC_OK; + + mb_assert(s); + + return result; +} + +int _open_core_lib(mb_interpreter_t* s) { + /* Open the core functional libraries */ + int result = 0; + int i = 0; + + mb_assert(s); + + for(i = 0; i < _countof(_core_libs); ++i) { + result += _register_func(s, _core_libs[i].name, _core_libs[i].pointer, true); + } + + return result; +} + +int _close_core_lib(mb_interpreter_t* s) { + /* Close the core functional libraries */ + int result = 0; + int i = 0; + + mb_assert(s); + + for(i = 0; i < _countof(_core_libs); ++i) { + result += _remove_func(s, _core_libs[i].name, true); + } + + return result; +} + +int _open_std_lib(mb_interpreter_t* s) { + /* Open the standard functional libraries */ + int result = 0; + int i = 0; + + mb_assert(s); + + for(i = 0; i < _countof(_std_libs); ++i) { + result += _register_func(s, _std_libs[i].name, _std_libs[i].pointer, true); + } + + return result; +} + +int _close_std_lib(mb_interpreter_t* s) { + /* Close the standard functional libraries */ + int result = 0; + int i = 0; + + mb_assert(s); + + for(i = 0; i < _countof(_std_libs); ++i) { + result += _remove_func(s, _std_libs[i].name, true); + } + + return result; +} + +/* ========================================================} */ + +/* +** {======================================================== +** Public functions definitions +*/ + +unsigned int mb_ver(void) { + /* Get the version number of this MY-BASIC system */ + return _MB_VERSION; +} + +const char* mb_ver_string(void) { + /* Get the version text of this MY-BASIC system */ + return _MB_VERSION_STRING; +} + +int mb_init(void) { + /* Initialize the MY-BASIC system */ + int result = MB_FUNC_OK; + + mb_assert(!_exp_assign); + _exp_assign = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(_exp_assign, 0, sizeof(_object_t)); + _exp_assign->type = _DT_FUNC; + _exp_assign->data.func = (_func_t*)mb_malloc(sizeof(_func_t)); + memset(_exp_assign->data.func, 0, sizeof(_func_t)); + _exp_assign->data.func->name = (char*)mb_malloc(strlen("#") + 1); + memcpy(_exp_assign->data.func->name, "#\0", strlen("#") + 1); + _exp_assign->data.func->pointer = _core_dummy_assign; + + mb_assert(!_OBJ_BOOL_TRUE); + if(!_OBJ_BOOL_TRUE) { + _OBJ_BOOL_TRUE = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(_OBJ_BOOL_TRUE, 0, sizeof(_object_t)); + + _OBJ_BOOL_TRUE->type = _DT_VAR; + _OBJ_BOOL_TRUE->data.variable = (_var_t*)mb_malloc(sizeof(_var_t)); + memset(_OBJ_BOOL_TRUE->data.variable, 0, sizeof(_var_t)); + _OBJ_BOOL_TRUE->data.variable->name = (char*)mb_malloc(strlen("TRUE") + 1); + memset(_OBJ_BOOL_TRUE->data.variable->name, 0, strlen("TRUE") + 1); + strcpy(_OBJ_BOOL_TRUE->data.variable->name, "TRUE"); + + _OBJ_BOOL_TRUE->data.variable->data = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(_OBJ_BOOL_TRUE->data.variable->data, 0, sizeof(_object_t)); + _OBJ_BOOL_TRUE->data.variable->data->type = _DT_INT; + _OBJ_BOOL_TRUE->data.variable->data->data.integer = 1; + } + mb_assert(!_OBJ_BOOL_FALSE); + if(!_OBJ_BOOL_FALSE) { + _OBJ_BOOL_FALSE = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(_OBJ_BOOL_FALSE, 0, sizeof(_object_t)); + + _OBJ_BOOL_FALSE->type = _DT_VAR; + _OBJ_BOOL_FALSE->data.variable = (_var_t*)mb_malloc(sizeof(_var_t)); + memset(_OBJ_BOOL_FALSE->data.variable, 0, sizeof(_var_t)); + _OBJ_BOOL_FALSE->data.variable->name = (char*)mb_malloc(strlen("FALSE") + 1); + memset(_OBJ_BOOL_FALSE->data.variable->name, 0, strlen("FALSE") + 1); + strcpy(_OBJ_BOOL_FALSE->data.variable->name, "FALSE"); + + _OBJ_BOOL_FALSE->data.variable->data = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(_OBJ_BOOL_FALSE->data.variable->data, 0, sizeof(_object_t)); + _OBJ_BOOL_FALSE->data.variable->data->type = _DT_INT; + _OBJ_BOOL_FALSE->data.variable->data->data.integer = 0; + } + + return result; +} + +int mb_dispose(void) { + /* Close the MY-BASIC system */ + int result = MB_FUNC_OK; + + mb_assert(_exp_assign); + safe_free(_exp_assign->data.func->name); + safe_free(_exp_assign->data.func); + safe_free(_exp_assign); + _exp_assign = 0; + + mb_assert(_OBJ_BOOL_TRUE); + if(_OBJ_BOOL_TRUE) { + safe_free(_OBJ_BOOL_TRUE->data.variable->data); + safe_free(_OBJ_BOOL_TRUE->data.variable->name); + safe_free(_OBJ_BOOL_TRUE->data.variable); + safe_free(_OBJ_BOOL_TRUE); + _OBJ_BOOL_TRUE = 0; + } + mb_assert(_OBJ_BOOL_FALSE); + if(_OBJ_BOOL_FALSE) { + safe_free(_OBJ_BOOL_FALSE->data.variable->data); + safe_free(_OBJ_BOOL_FALSE->data.variable->name); + safe_free(_OBJ_BOOL_FALSE->data.variable); + safe_free(_OBJ_BOOL_FALSE); + _OBJ_BOOL_FALSE = 0; + } + + return result; +} + +int mb_open(mb_interpreter_t** s) { + /* Initialize a MY-BASIC environment */ + int result = MB_FUNC_OK; + _ht_node_t* local_scope = 0; + _ht_node_t* global_scope = 0; + _ls_node_t* ast = 0; + _parsing_context_t* context = 0; + _running_context_t* running = 0; + + *s = (mb_interpreter_t*)mb_malloc(sizeof(mb_interpreter_t)); + memset(*s, 0, sizeof(mb_interpreter_t)); + + local_scope = _ht_create(0, _ht_cmp_string, _ht_hash_string, _ls_free_extra); + (*s)->local_func_dict = local_scope; + + global_scope = _ht_create(0, _ht_cmp_string, _ht_hash_string, _ls_free_extra); + (*s)->global_func_dict = global_scope; + + global_scope = _ht_create(0, _ht_cmp_string, _ht_hash_string, 0); + (*s)->global_var_dict = global_scope; + + ast = _ls_create(); + (*s)->ast = ast; + + context = (_parsing_context_t*)mb_malloc(sizeof(_parsing_context_t)); + memset(context, 0, sizeof(_parsing_context_t)); + (*s)->parsing_context = context; + + running = (_running_context_t*)mb_malloc(sizeof(_running_context_t)); + memset(running, 0, sizeof(_running_context_t)); + + running->temp_values = _ls_create(); + + running->sub_stack = _ls_create(); + (*s)->running_context = running; + + _open_core_lib(*s); + _open_std_lib(*s); + + result = _open_constant(*s); + mb_assert(MB_FUNC_OK == result); + + return result; +} + +int mb_close(mb_interpreter_t** s) { + /* Close a MY-BASIC environment */ + int result = MB_FUNC_OK; + _ht_node_t* local_scope = 0; + _ht_node_t* global_scope = 0; + _ls_node_t* ast; + _parsing_context_t* context = 0; + _running_context_t* running = 0; + + mb_assert(s); + + _close_std_lib(*s); + _close_core_lib(*s); + + running = (_running_context_t*)((*s)->running_context); + + _ls_foreach(running->temp_values, _destroy_object); + _ls_destroy(running->temp_values); + + _ls_destroy(running->sub_stack); + safe_free(running); + + context = (_parsing_context_t*)((*s)->parsing_context); + safe_free(context); + + ast = (_ls_node_t*)((*s)->ast); + _ls_foreach(ast, _destroy_object); + _ls_destroy(ast); + + global_scope = (_ht_node_t*)((*s)->global_var_dict); + _ht_foreach(global_scope, _destroy_object); + _ht_destroy(global_scope); + + global_scope = (_ht_node_t*)((*s)->global_func_dict); + _ht_foreach(global_scope, _ls_free_extra); + _ht_destroy(global_scope); + + local_scope = (_ht_node_t*)((*s)->local_func_dict); + _ht_foreach(local_scope, _ls_free_extra); + _ht_destroy(local_scope); + + _close_constant(*s); + + safe_free(*s); + *s = 0; + + return result; +} + +int mb_reset(mb_interpreter_t** s, bool_t clrf/* = false*/) { + /* Reset a MY-BASIC environment */ + int result = MB_FUNC_OK; + _ht_node_t* global_scope = 0; + _ls_node_t* ast; + _parsing_context_t* context = 0; + _running_context_t* running = 0; + + mb_assert(s); + + (*s)->last_error = SE_NO_ERR; + + running = (_running_context_t*)((*s)->running_context); + _ls_clear(running->sub_stack); + running->suspent_point = 0; + running->next_loop_var = 0; + running->no_eat_comma_mark = 0; + memset(&(running->intermediate_value), 0, sizeof(mb_value_t)); + + context = (_parsing_context_t*)((*s)->parsing_context); + memset(context, 0, sizeof(_parsing_context_t)); + + ast = (_ls_node_t*)((*s)->ast); + _ls_foreach(ast, _destroy_object); + _ls_clear(ast); + + global_scope = (_ht_node_t*)((*s)->global_var_dict); + _ht_foreach(global_scope, _destroy_object); + _ht_clear(global_scope); + + if(clrf) { + global_scope = (_ht_node_t*)((*s)->global_func_dict); + _ht_foreach(global_scope, _ls_free_extra); + _ht_clear(global_scope); + } + + result = _open_constant(*s); + mb_assert(MB_FUNC_OK == result); + + return result; +} + +int mb_register_func(mb_interpreter_t* s, const char* n, mb_func_t f) { + /* Register a remote function to a MY-BASIC environment */ + return _register_func(s, n, f, false); +} + +int mb_remove_func(mb_interpreter_t* s, const char* n) { + /* Remove a remote function from a MY-BASIC environment */ + return _remove_func(s, n, false); +} + +int mb_remove_reserved_func(mb_interpreter_t* s, const char* n) { + /* Remove a reserved remote function from a MY-BASIC environment */ + return _remove_func(s, n, true); +} + +int mb_attempt_func_begin(mb_interpreter_t* s, void** l) { + /* Try attempting to begin a function */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + _running_context_t* running = 0; + + mb_assert(s && l); + + ast = (_ls_node_t*)(*l); + obj = (_object_t*)(ast->data); + if(!(obj->type == _DT_FUNC)) { + _handle_error_on_obj(s, SE_RN_STRUCTURE_NOT_COMPLETED, DON(ast), MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + + running = (_running_context_t*)(s->running_context); + ++running->no_eat_comma_mark; + +_exit: + *l = ast; + + return result; +} + +int mb_attempt_func_end(mb_interpreter_t* s, void** l) { + /* Try attempting to end a function */ + int result = MB_FUNC_OK; + _running_context_t* running = 0; + + mb_assert(s && l); + + running = (_running_context_t*)(s->running_context); + --running->no_eat_comma_mark; + + return result; +} + +int mb_attempt_open_bracket(mb_interpreter_t* s, void** l) { + /* Try attempting an open bracket */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + + mb_assert(s && l); + + ast = (_ls_node_t*)(*l); + ast = ast->next; + obj = (_object_t*)(ast->data); + if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_open_bracket)) { + _handle_error_on_obj(s, SE_RN_OPEN_BRACKET_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + +_exit: + *l = ast; + + return result; +} + +int mb_attempt_close_bracket(mb_interpreter_t* s, void** l) { + /* Try attempting a close bracket */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + + mb_assert(s && l); + + ast = (_ls_node_t*)(*l); + obj = (_object_t*)(ast->data); + if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_close_bracket)) { + _handle_error_on_obj(s, SE_RN_CLOSE_BRACKET_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + +_exit: + *l = ast; + + return result; +} + +int mb_pop_int(mb_interpreter_t* s, void** l, int_t* val) { + /* Pop an integer argument */ + int result = MB_FUNC_OK; + mb_value_t arg; + int_t tmp = 0; + + mb_assert(s && l && val); + + mb_check(mb_pop_value(s, l, &arg)); + + switch(arg.type) { + case MB_DT_INT: + tmp = arg.value.integer; + + break; + case MB_DT_REAL: + tmp = (int_t)(arg.value.float_point); + + break; + default: + result = MB_FUNC_ERR; + + goto _exit; + } + + *val = tmp; + +_exit: + return result; +} + +int mb_pop_real(mb_interpreter_t* s, void** l, real_t* val) { + /* Pop a float point argument */ + int result = MB_FUNC_OK; + mb_value_t arg; + real_t tmp = 0; + + mb_assert(s && l && val); + + mb_check(mb_pop_value(s, l, &arg)); + + switch(arg.type) { + case MB_DT_INT: + tmp = (real_t)(arg.value.integer); + + break; + case MB_DT_REAL: + tmp = arg.value.float_point; + + break; + default: + result = MB_FUNC_ERR; + + goto _exit; + } + + *val = tmp; + +_exit: + return result; +} + +int mb_pop_string(mb_interpreter_t* s, void** l, char** val) { + /* Pop a string argument */ + int result = MB_FUNC_OK; + mb_value_t arg; + char* tmp = 0; + + mb_assert(s && l && val); + + mb_check(mb_pop_value(s, l, &arg)); + + switch(arg.type) { + case MB_DT_STRING: + tmp = arg.value.string; + + break; + default: + result = MB_FUNC_ERR; + + goto _exit; + } + + *val = tmp; + +_exit: + return result; +} + +int mb_pop_value(mb_interpreter_t* s, void** l, mb_value_t* val) { + /* Pop an argument */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t val_obj; + _object_t* val_ptr = 0; + _running_context_t* running = 0; + + mb_assert(s && l && val); + + running = (_running_context_t*)(s->running_context); + + val_ptr = &val_obj; + memset(val_ptr, 0, sizeof(_object_t)); + + ast = (_ls_node_t*)(*l); + result = _calc_expression(s, &ast, &val_ptr); + if(result != MB_FUNC_OK) { + goto _exit; + } + + if(val_ptr->type == _DT_STRING && !val_ptr->ref) { + val_ptr = (_object_t*)mb_malloc(sizeof(_object_t)); + memcpy(val_ptr, &val_obj, sizeof(_object_t)); + _ls_pushback(running->temp_values, val_ptr); + } + + if(running->no_eat_comma_mark < _NO_EAT_COMMA) { + if(ast && ((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ',') { + ast = ast->next; + } + } + + result = _internal_object_to_public_value(val_ptr, val); + if(result != MB_FUNC_OK) { + goto _exit; + } + +_exit: + *l = ast; + + return result; +} + +int mb_push_int(mb_interpreter_t* s, void** l, int_t val) { + /* Push an integer argument */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && l); + + arg.type = MB_DT_INT; + arg.value.integer = val; + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int mb_push_real(mb_interpreter_t* s, void** l, real_t val) { + /* Push a float point argument */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && l); + + arg.type = MB_DT_REAL; + arg.value.float_point = val; + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int mb_push_string(mb_interpreter_t* s, void** l, char* val) { + /* Push a string argument */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && l); + + arg.type = MB_DT_STRING; + arg.value.string = val; + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int mb_push_value(mb_interpreter_t* s, void** l, mb_value_t val) { + /* Push an argument */ + int result = MB_FUNC_OK; + _running_context_t* running = 0; + + mb_assert(s && l); + + running = (_running_context_t*)(s->running_context); + running->intermediate_value = val; + + return result; +} + +int mb_load_string(mb_interpreter_t* s, const char* l) { + /* Load a script string */ + int result = MB_FUNC_OK; + char ch = 0; + int status = 0; + int i = 0; + unsigned short row = 1; + unsigned short col = 0; + unsigned short _row = 0; + unsigned short _col = 0; + char wrapped = '\0'; + _parsing_context_t* context = 0; + + mb_assert(s && s->parsing_context); + + context = (_parsing_context_t*)(s->parsing_context); + + while(l[i]) { + ch = l[i]; + if((ch == '\n' || ch == '\r') && (!wrapped || wrapped == ch)) { + wrapped = ch; + ++row; + col = 0; + } else { + wrapped = '\0'; + ++col; + } + status = _parse_char(s, ch, i, _row, _col); + result = status; + if(status) { + _set_error_pos(s, i, _row, _col); + if(s->error_handler) { + (s->error_handler)(s, s->last_error, (char*)mb_get_error_desc(s->last_error), + s->last_error_pos, + s->last_error_row, + s->last_error_col, + result); + } + + goto _exit; + } + _row = row; + _col = col; + ++i; + }; + status = _parse_char(s, _EOS, i, row, col); + +_exit: + context->parsing_state = _PS_NORMAL; + + return result; +} + +int mb_load_file(mb_interpreter_t* s, const char* f) { + /* Load a script file */ + int result = MB_FUNC_OK; + FILE* fp = 0; + char* buf = 0; + long curpos = 0; + long l = 0; + _parsing_context_t* context = 0; + + mb_assert(s && s->parsing_context); + + context = (_parsing_context_t*)(s->parsing_context); + + fp = fopen(f, "rb"); + if(fp) { + curpos = ftell(fp); + fseek(fp, 0L, SEEK_END); + l = ftell(fp); + fseek(fp, curpos, SEEK_SET); + buf = (char*)mb_malloc((size_t)(l + 1)); + mb_assert(buf); + fread(buf, 1, l, fp); + fclose(fp); + buf[l] = '\0'; + + result = mb_load_string(s, buf); + mb_free(buf); + + if(result) { + goto _exit; + } + } else { + _set_current_error(s, SE_PS_FILE_OPEN_FAILED); + + ++result; + } + +_exit: + context->parsing_state = _PS_NORMAL; + + return result; +} + +int mb_run(mb_interpreter_t* s) { + /* Run loaded and parsed script */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _running_context_t* running = 0; + + running = (_running_context_t*)(s->running_context); + + if(running->suspent_point) { + ast = running->suspent_point; + ast = ast->next; + running->suspent_point = 0; + } else { + mb_assert(!running->no_eat_comma_mark); + ast = (_ls_node_t*)(s->ast); + ast = ast->next; + if(!ast) { + _set_current_error(s, SE_RN_EMPTY_PROGRAM); + _set_error_pos(s, 0, 0, 0); + result = MB_FUNC_ERR; + (s->error_handler)(s, s->last_error, (char*)mb_get_error_desc(s->last_error), + s->last_error_pos, + s->last_error_row, + s->last_error_col, + result); + + goto _exit; + } + } + + do { + result = _execute_statement(s, &ast); + if(result != MB_FUNC_OK && result != MB_SUB_RETURN) { + if(result != MB_FUNC_SUSPEND && s->error_handler) { + if(result >= MB_EXTENDED_ABORT) { + s->last_error = SE_EA_EXTENDED_ABORT; + } + (s->error_handler)(s, s->last_error, (char*)mb_get_error_desc(s->last_error), + s->last_error_pos, + s->last_error_row, + s->last_error_col, + result); + } + + goto _exit; + } + } while(ast); + +_exit: + _ls_foreach(running->temp_values, _destroy_object); + _ls_clear(running->temp_values); + + return result; +} + +int mb_suspend(mb_interpreter_t* s, void** l) { + /* Suspend current execution and save the context */ + int result = MB_FUNC_OK; + _ls_node_t* ast; + + mb_assert(s && l && *l); + + ast = (_ls_node_t*)(*l); + ((_running_context_t*)(s->running_context))->suspent_point = ast; + + return result; +} + +mb_error_e mb_get_last_error(mb_interpreter_t* s) { + /* Get last error information */ + mb_error_e result = SE_NO_ERR; + + mb_assert(s); + + result = s->last_error; + s->last_error = SE_NO_ERR; + + return result; +} + +const char* mb_get_error_desc(mb_error_e err) { + /* Get error description text */ + return _get_error_desc(err); +} + +int mb_set_error_handler(mb_interpreter_t* s, mb_error_handler_t h) { + /* Set an error handler to an interpreter instance */ + int result = MB_FUNC_OK; + + mb_assert(s); + + s->error_handler = h; + + return result; +} + +int mb_set_printer(mb_interpreter_t* s, mb_print_func_t p) { + /* Set a print functor to an interpreter instance */ + int result = MB_FUNC_OK; + + mb_assert(s); + + s->printer = p; + + return result; +} + +int mb_set_inputer(mb_interpreter_t* s, mb_input_func_t p) { + /* Set an input functor to an interpreter instance */ + int result = MB_FUNC_OK; + + mb_assert(s); + + s->inputer = p; + + return result; +} + +int mb_gets(char* buf, int s) { + /* Safe stdin reader function */ + int result = 0; + if(fgets(buf, s, stdin) == 0) { + fprintf(stderr, "Error reading.\n"); + exit(1); + } + result = (int)strlen(buf); + if(buf[result - 1] == '\n') + buf[result - 1] = '\0'; + + return result; +} + +/* ========================================================} */ + +/* +** {======================================================== +** Lib definitions +*/ + +/** Core lib */ +int _core_dummy_assign(mb_interpreter_t* s, void** l) { + /* Operator #, dummy assignment */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + +int _core_add(mb_interpreter_t* s, void** l) { + /* Operator + */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + if(_is_string(((_tuple3_t*)(*l))->e1) || _is_string(((_tuple3_t*)(*l))->e2)) { + if(_is_string(((_tuple3_t*)(*l))->e1) && _is_string(((_tuple3_t*)(*l))->e2)) { + _instruct_connect_strings(l); + } else { + _handle_error_on_obj(s, SE_RN_STRING_EXPECTED, (l && *l) ? ((_object_t*)(((_tuple3_t*)(*l))->e1)) : 0, MB_FUNC_ERR, _exit, result); + } + } else { + _instruct_num_op_num(+, l); + } + +_exit: + return result; +} + +int _core_min(mb_interpreter_t* s, void** l) { + /* Operator - */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + _instruct_num_op_num(-, l); + + return result; +} + +int _core_mul(mb_interpreter_t* s, void** l) { + /* Operator * */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + _instruct_num_op_num(*, l); + + return result; +} + +int _core_div(mb_interpreter_t* s, void** l) { + /* Operator / */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + _proc_div_by_zero(s, l, _exit, result, SE_RN_DIVIDE_BY_ZERO); + _instruct_num_op_num(/, l); + +_exit: + return result; +} + +int _core_mod(mb_interpreter_t* s, void** l) { + /* Operator MOD */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + _proc_div_by_zero(s, l, _exit, result, SE_RN_MOD_BY_ZERO); + _instruct_int_op_int(%, l); + +_exit: + return result; +} + +int _core_pow(mb_interpreter_t* s, void** l) { + /* Operator ^ */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + _instruct_fun_num_num(pow, l); + + return result; +} + +int _core_open_bracket(mb_interpreter_t* s, void** l) { + /* Operator ( */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + +int _core_close_bracket(mb_interpreter_t* s, void** l) { + /* Operator ) */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + +int _core_neg(mb_interpreter_t* s, void** l) { + /* Operator - (negative) */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && l); + + mb_check(mb_attempt_func_begin(s, l)); + + mb_check(mb_pop_value(s, l, &arg)); + + mb_check(mb_attempt_func_end(s, l)); + + switch(arg.type) { + case MB_DT_INT: + arg.value.integer = -(arg.value.integer); + + break; + case MB_DT_REAL: + arg.value.float_point = -(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _core_equal(mb_interpreter_t* s, void** l) { + /* Operator = */ + int result = MB_FUNC_OK; + _tuple3_t* tpr = 0; + + mb_assert(s && l); + + if(_is_string(((_tuple3_t*)(*l))->e1) || _is_string(((_tuple3_t*)(*l))->e2)) { + if(_is_string(((_tuple3_t*)(*l))->e1) && _is_string(((_tuple3_t*)(*l))->e2)) { + _instruct_compare_strings(==, l); + } else { + _set_tuple3_result(l, 0); + _handle_error_on_obj(s, SE_RN_STRING_EXPECTED, (l && *l) ? ((_object_t*)(((_tuple3_t*)(*l))->e1)) : 0, MB_FUNC_WARNING, _exit, result); + } + } else { + _instruct_num_op_num(==, l); + tpr = (_tuple3_t*)(*l); + if(((_object_t*)(tpr->e3))->type != _DT_INT) { + ((_object_t*)(tpr->e3))->type = _DT_INT; + ((_object_t*)(tpr->e3))->data.integer = ((_object_t*)(tpr->e3))->data.float_point != 0.0f; + } + } + +_exit: + return result; +} + +int _core_less(mb_interpreter_t* s, void** l) { + /* Operator < */ + int result = MB_FUNC_OK; + _tuple3_t* tpr = 0; + + mb_assert(s && l); + + if(_is_string(((_tuple3_t*)(*l))->e1) || _is_string(((_tuple3_t*)(*l))->e2)) { + if(_is_string(((_tuple3_t*)(*l))->e1) && _is_string(((_tuple3_t*)(*l))->e2)) { + _instruct_compare_strings(<, l); + } else { + if(_is_string(((_tuple3_t*)(*l))->e1)) { + _set_tuple3_result(l, 0); + } else { + _set_tuple3_result(l, 1); + } + _handle_error_on_obj(s, SE_RN_STRING_EXPECTED, (l && *l) ? ((_object_t*)(((_tuple3_t*)(*l))->e1)) : 0, MB_FUNC_WARNING, _exit, result); + } + } else { + _instruct_num_op_num(<, l); + tpr = (_tuple3_t*)(*l); + if(((_object_t*)(tpr->e3))->type != _DT_INT) { + ((_object_t*)(tpr->e3))->type = _DT_INT; + ((_object_t*)(tpr->e3))->data.integer = ((_object_t*)(tpr->e3))->data.float_point != 0.0f; + } + } + +_exit: + return result; +} + +int _core_greater(mb_interpreter_t* s, void** l) { + /* Operator > */ + int result = MB_FUNC_OK; + _tuple3_t* tpr = 0; + + mb_assert(s && l); + + if(_is_string(((_tuple3_t*)(*l))->e1) || _is_string(((_tuple3_t*)(*l))->e2)) { + if(_is_string(((_tuple3_t*)(*l))->e1) && _is_string(((_tuple3_t*)(*l))->e2)) { + _instruct_compare_strings(>, l); + } else { + if(_is_string(((_tuple3_t*)(*l))->e1)) { + _set_tuple3_result(l, 1); + } else { + _set_tuple3_result(l, 0); + } + _handle_error_on_obj(s, SE_RN_STRING_EXPECTED, (l && *l) ? ((_object_t*)(((_tuple3_t*)(*l))->e1)) : 0, MB_FUNC_WARNING, _exit, result); + } + } else { + _instruct_num_op_num(>, l); + tpr = (_tuple3_t*)(*l); + if(((_object_t*)(tpr->e3))->type != _DT_INT) { + ((_object_t*)(tpr->e3))->type = _DT_INT; + ((_object_t*)(tpr->e3))->data.integer = ((_object_t*)(tpr->e3))->data.float_point != 0.0f; + } + } + +_exit: + return result; +} + +int _core_less_equal(mb_interpreter_t* s, void** l) { + /* Operator <= */ + int result = MB_FUNC_OK; + _tuple3_t* tpr = 0; + + mb_assert(s && l); + + if(_is_string(((_tuple3_t*)(*l))->e1) || _is_string(((_tuple3_t*)(*l))->e2)) { + if(_is_string(((_tuple3_t*)(*l))->e1) && _is_string(((_tuple3_t*)(*l))->e2)) { + _instruct_compare_strings(<=, l); + } else { + if(_is_string(((_tuple3_t*)(*l))->e1)) { + _set_tuple3_result(l, 0); + } else { + _set_tuple3_result(l, 1); + } + _handle_error_on_obj(s, SE_RN_STRING_EXPECTED, (l && *l) ? ((_object_t*)(((_tuple3_t*)(*l))->e1)) : 0, MB_FUNC_WARNING, _exit, result); + } + } else { + _instruct_num_op_num(<=, l); + tpr = (_tuple3_t*)(*l); + if(((_object_t*)(tpr->e3))->type != _DT_INT) { + ((_object_t*)(tpr->e3))->type = _DT_INT; + ((_object_t*)(tpr->e3))->data.integer = ((_object_t*)(tpr->e3))->data.float_point != 0.0f; + } + } + +_exit: + return result; +} + +int _core_greater_equal(mb_interpreter_t* s, void** l) { + /* Operator >= */ + int result = MB_FUNC_OK; + _tuple3_t* tpr = 0; + + mb_assert(s && l); + + if(_is_string(((_tuple3_t*)(*l))->e1) || _is_string(((_tuple3_t*)(*l))->e2)) { + if(_is_string(((_tuple3_t*)(*l))->e1) && _is_string(((_tuple3_t*)(*l))->e2)) { + _instruct_compare_strings(>=, l); + } else { + if(_is_string(((_tuple3_t*)(*l))->e1)) { + _set_tuple3_result(l, 1); + } else { + _set_tuple3_result(l, 0); + } + _handle_error_on_obj(s, SE_RN_STRING_EXPECTED, (l && *l) ? ((_object_t*)(((_tuple3_t*)(*l))->e1)) : 0, MB_FUNC_WARNING, _exit, result); + } + } else { + _instruct_num_op_num(>=, l); + tpr = (_tuple3_t*)(*l); + if(((_object_t*)(tpr->e3))->type != _DT_INT) { + ((_object_t*)(tpr->e3))->type = _DT_INT; + ((_object_t*)(tpr->e3))->data.integer = ((_object_t*)(tpr->e3))->data.float_point != 0.0f; + } + } + +_exit: + return result; +} + +int _core_not_equal(mb_interpreter_t* s, void** l) { + /* Operator <> */ + int result = MB_FUNC_OK; + _tuple3_t* tpr = 0; + + mb_assert(s && l); + + if(_is_string(((_tuple3_t*)(*l))->e1) || _is_string(((_tuple3_t*)(*l))->e2)) { + if(_is_string(((_tuple3_t*)(*l))->e1) && _is_string(((_tuple3_t*)(*l))->e2)) { + _instruct_compare_strings(!=, l); + } else { + _set_tuple3_result(l, 1); + _handle_error_on_obj(s, SE_RN_STRING_EXPECTED, (l && *l) ? ((_object_t*)(((_tuple3_t*)(*l))->e1)) : 0, MB_FUNC_WARNING, _exit, result); + } + } else { + _instruct_num_op_num(!=, l); + tpr = (_tuple3_t*)(*l); + if(((_object_t*)(tpr->e3))->type != _DT_INT) { + ((_object_t*)(tpr->e3))->type = _DT_INT; + ((_object_t*)(tpr->e3))->data.integer = ((_object_t*)(tpr->e3))->data.float_point != 0.0f; + } + } + +_exit: + return result; +} + +int _core_and(mb_interpreter_t* s, void** l) { + /* Operator AND */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + _instruct_num_op_num(&&, l); + + return result; +} + +int _core_or(mb_interpreter_t* s, void** l) { + /* Operator OR */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + _instruct_num_op_num(||, l); + + return result; +} + +int _core_not(mb_interpreter_t* s, void** l) { + /* Operator NOT */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && l); + + mb_check(mb_attempt_func_begin(s, l)); + + mb_check(mb_pop_value(s, l, &arg)); + + mb_check(mb_attempt_func_end(s, l)); + + switch(arg.type) { + case MB_DT_INT: + arg.value.integer = (int_t)(!arg.value.integer); + + break; + case MB_DT_REAL: + arg.value.integer = (int_t)(!((int_t)arg.value.float_point)); + arg.type = MB_DT_INT; + + break; + default: + break; + } + mb_check(mb_push_int(s, l, arg.value.integer)); + + return result; +} + +int _core_let(mb_interpreter_t* s, void** l) { + /* LET statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + _var_t* var = 0; + _array_t* arr = 0; + unsigned int arr_idx = 0; + _object_t* val = 0; + + mb_assert(s && l); + + ast = (_ls_node_t*)(*l); + obj = (_object_t*)(ast->data); + if(obj->type == _DT_FUNC) { + ast = ast->next; + } + if(!ast || !ast->data) { + _handle_error_on_obj(s, SE_RN_SYNTAX, DON(ast), MB_FUNC_ERR, _exit, result); + } + obj = (_object_t*)(ast->data); + if(obj->type == _DT_VAR) { + var = obj->data.variable; + } else if(obj->type == _DT_ARRAY) { + arr = obj->data.array; + result = _get_array_index(s, &ast, &arr_idx); + if(result != MB_FUNC_OK) { + goto _exit; + } + } else { + _handle_error_on_obj(s, SE_RN_VAR_OR_ARRAY_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + + ast = ast->next; + if(!ast || !ast->data) { + _handle_error_on_obj(s, SE_RN_SYNTAX, DON(ast), MB_FUNC_ERR, _exit, result); + } + obj = (_object_t*)(ast->data); + if(obj->type != _DT_FUNC || strcmp(obj->data.func->name, "=") != 0) { + _handle_error_on_obj(s, SE_RN_ASSIGN_OPERATOR_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + + ast = ast->next; + val = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(val, 0, sizeof(_object_t)); + result = _calc_expression(s, &ast, &val); + + if(var) { + if(val->type != _DT_ANY) { + _dispose_object(var->data); + var->data->type = val->type; + var->data->data = val->data; + var->data->ref = val->ref; + } + } else if(arr) { + mb_value_u _val; + if(val->type == _DT_INT) { + _val.integer = val->data.integer; + } else if(val->type == _DT_REAL) { + _val.float_point = val->data.float_point; + } else if(val->type == _DT_STRING) { + _val.string = val->data.string; + } else { + mb_assert(0 && "Unsupported"); + } + _set_array_elem(s, arr, arr_idx, &_val, &val->type); + } + safe_free(val); + +_exit: + *l = ast; + + return result; +} + +int _core_dim(mb_interpreter_t* s, void** l) { + /* DIM statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* arr = 0; + _object_t* len = 0; + mb_value_u val; + _array_t dummy; + + mb_assert(s && l); + + /* Array name */ + ast = (_ls_node_t*)(*l); + if(!ast->next || ((_object_t*)(ast->next->data))->type != _DT_ARRAY) { + _handle_error_on_obj(s, SE_RN_ARRAY_IDENTIFIER_EXPECTED, (ast && ast->next) ? ((_object_t*)(ast->next->data)) : 0, MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + arr = (_object_t*)(ast->data); + memset(&dummy, 0, sizeof(_array_t)); + dummy.type = arr->data.array->type; + dummy.name = arr->data.array->name; + /* ( */ + if(!ast->next || ((_object_t*)(ast->next->data))->type != _DT_FUNC || ((_object_t*)(ast->next->data))->data.func->pointer != _core_open_bracket) { + _handle_error_on_obj(s, SE_RN_OPEN_BRACKET_EXPECTED, (ast && ast->next) ? ((_object_t*)(ast->next->data)) : 0, MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + /* Array subscript */ + if(!ast->next) { + _handle_error_on_obj(s, SE_RN_ARRAY_SUBSCRIPT_EXPECTED, (ast && ast->next) ? ((_object_t*)(ast->next->data)) : 0, MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + while(((_object_t*)(ast->data))->type != _DT_FUNC || ((_object_t*)(ast->data))->data.func->pointer != _core_close_bracket) { + /* Get an integer value */ + len = (_object_t*)(ast->data); + if(!_try_get_value(len, &val, _DT_INT)) { + _handle_error_on_obj(s, SE_RN_TYPE_NOT_MATCH, DON(ast), MB_FUNC_ERR, _exit, result); + } + if(val.integer <= 0) { + _handle_error_on_obj(s, SE_RN_ILLEGAL_BOUND, DON(ast), MB_FUNC_ERR, _exit, result); + } + if(dummy.dimension_count >= _MAX_DIMENSION_COUNT) { + _handle_error_on_obj(s, SE_RN_DIMENSION_TOO_MUCH, DON(ast), MB_FUNC_ERR, _exit, result); + } + dummy.dimensions[dummy.dimension_count++] = (int)val.integer; + if(dummy.count) { + dummy.count *= (unsigned int)val.integer; + } else { + dummy.count += (unsigned int)val.integer; + } + ast = ast->next; + /* Comma? */ + if(((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ',') { + ast = ast->next; + } + } + /* Create or modify raw data */ + _clear_array(arr->data.array); + *(arr->data.array) = dummy; + _init_array(arr->data.array); + if(!arr->data.array->raw) { + arr->data.array->dimension_count = 0; + arr->data.array->dimensions[0] = 0; + arr->data.array->count = 0; + _handle_error_on_obj(s, SE_RN_OUT_OF_MEMORY, DON(ast), MB_FUNC_ERR, _exit, result); + } + +_exit: + *l = ast; + + return result; +} + +int _core_if(mb_interpreter_t* s, void** l) { + /* IF statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* val = 0; + _object_t* obj = 0; + _running_context_t* running = 0; + + mb_assert(s && l); + + running = (_running_context_t*)(s->running_context); + + ast = (_ls_node_t*)(*l); + ast = ast->next; + + val = (_object_t*)mb_malloc(sizeof(_object_t)); + memset(val, 0, sizeof(_object_t)); + result = _calc_expression(s, &ast, &val); + if(result != MB_FUNC_OK) { + goto _exit; + } + mb_assert(val->type == _DT_INT); + + obj = (_object_t*)(ast->data); + if(val->data.integer) { + if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_then)) { + _handle_error_on_obj(s, SE_RN_INTEGER_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + + running->skip_to_eoi = _ls_back(running->sub_stack); + do { + ast = ast->next; + result = _execute_statement(s, &ast); + if(result != MB_FUNC_OK) { + goto _exit; + } + if(ast) { + ast = ast->prev; + } + } while(ast && ((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ':'); + + if(!ast) { + goto _exit; + } + + obj = (_object_t*)(ast->data); + if(obj->type != _DT_EOS) { + running->skip_to_eoi = 0; + result = _skip_to(s, &ast, 0, _DT_EOS); + if(result != MB_FUNC_OK) { + goto _exit; + } + } + } else { + result = _skip_to(s, &ast, _core_else, _DT_EOS); + if(result != MB_FUNC_OK) { + goto _exit; + } + + obj = (_object_t*)(ast->data); + if(obj->type != _DT_EOS) { + if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_else)) { + _handle_error_on_obj(s, SE_RN_ELSE_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + + do { + ast = ast->next; + result = _execute_statement(s, &ast); + if(result != MB_FUNC_OK) { + goto _exit; + } + if(ast) { + ast = ast->prev; + } + } while(ast && ((_object_t*)(ast->data))->type == _DT_SEP && ((_object_t*)(ast->data))->data.separator == ':'); + } + } + +_exit: + _destroy_object(val, 0); + + *l = ast; + + return result; +} + +int _core_then(mb_interpreter_t* s, void** l) { + /* THEN statement */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + +int _core_else(mb_interpreter_t* s, void** l) { + /* ELSE statement */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + +int _core_for(mb_interpreter_t* s, void** l) { + /* FOR statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _ls_node_t* to_node = 0; + _object_t* obj = 0; + _object_t to_val; + _object_t step_val; + _object_t* to_val_ptr = 0; + _object_t* step_val_ptr = 0; + _var_t* var_loop = 0; + _tuple3_t ass_tuple3; + _tuple3_t* ass_tuple3_ptr = 0; + _running_context_t* running = 0; + + mb_assert(s && l); + + running = (_running_context_t*)(s->running_context); + ast = (_ls_node_t*)(*l); + ast = ast->next; + + to_val_ptr = &to_val; + step_val_ptr = &step_val; + ass_tuple3_ptr = &ass_tuple3; + + obj = (_object_t*)(ast->data); + if(obj->type != _DT_VAR) { + _handle_error_on_obj(s, SE_RN_LOOP_VAR_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + var_loop = obj->data.variable; + + result = _execute_statement(s, &ast); + if(result != MB_FUNC_OK) { + goto _exit; + } + ast = ast->prev; + + obj = (_object_t*)(ast->data); + if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_to)) { + _handle_error_on_obj(s, SE_RN_TO_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + + ast = ast->next; + if(!ast) { + _handle_error_on_obj(s, SE_RN_SYNTAX, DON(ast), MB_FUNC_ERR, _exit, result); + } + to_node = ast; + +_to: + ast = to_node; + + result = _calc_expression(s, &ast, &to_val_ptr); + if(result != MB_FUNC_OK) { + goto _exit; + } + + obj = (_object_t*)(ast->data); + if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_step)) { + step_val = _OBJ_INT_UNIT; + } else { + ast = ast->next; + if(!ast) { + _handle_error_on_obj(s, SE_RN_SYNTAX, DON(ast), MB_FUNC_ERR, _exit, result); + } + + result = _calc_expression(s, &ast, &step_val_ptr); + if(result != MB_FUNC_OK) { + goto _exit; + } + } + + if((_compare_numbers(step_val_ptr, &_OBJ_INT_ZERO) == 1 && _compare_numbers(var_loop->data, to_val_ptr) == 1) || + (_compare_numbers(step_val_ptr, &_OBJ_INT_ZERO) == -1 && _compare_numbers(var_loop->data, to_val_ptr) == -1)) { + /* End looping */ + if(_skip_struct(s, &ast, _core_for, _core_next) != MB_FUNC_OK) { + goto _exit; + } + _skip_to(s, &ast, 0, _DT_EOS); + + goto _exit; + } else { + /* Keep looping */ + obj = (_object_t*)(ast->data); + while(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_next)) { + result = _execute_statement(s, &ast); + if(result == MB_LOOP_CONTINUE) { /* NEXT */ + if(!running->next_loop_var || running->next_loop_var == var_loop) { /* This loop */ + running->next_loop_var = 0; + result = MB_FUNC_OK; + + break; + } else { /* Not this loop */ + if(_skip_struct(s, &ast, _core_for, _core_next) != MB_FUNC_OK) { + goto _exit; + } + _skip_to(s, &ast, 0, _DT_EOS); + + goto _exit; + } + } else if(result == MB_LOOP_BREAK) { /* EXIT */ + if(_skip_struct(s, &ast, _core_for, _core_next) != MB_FUNC_OK) { + goto _exit; + } + _skip_to(s, &ast, 0, _DT_EOS); + result = MB_FUNC_OK; + + goto _exit; + } else if(result != MB_FUNC_OK && result != MB_SUB_RETURN) { /* Normally */ + goto _exit; + } + + if(!ast) { + _handle_error_on_obj(s, SE_RN_NEXT_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + obj = (_object_t*)(ast->data); + } + + ass_tuple3.e1 = var_loop->data; + ass_tuple3.e2 = step_val_ptr; + ass_tuple3.e3 = var_loop->data; + _instruct_num_op_num(+, &ass_tuple3_ptr); + + goto _to; + } + +_exit: + *l = ast; + + return result; +} + +int _core_to(mb_interpreter_t* s, void** l) { + /* TO statement */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + +int _core_step(mb_interpreter_t* s, void** l) { + /* STEP statement */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + +int _core_next(mb_interpreter_t* s, void** l) { + /* NEXT statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + _running_context_t* running = 0; + + mb_assert(s && l); + + running = (_running_context_t*)(s->running_context); + ast = (_ls_node_t*)(*l); + + result = MB_LOOP_CONTINUE; + + ast = ast->next; + if(ast && ((_object_t*)(ast->data))->type == _DT_VAR) { + obj = (_object_t*)(ast->data); + running->next_loop_var = obj->data.variable; + } + + *l = ast; + + return result; +} + +int _core_while(mb_interpreter_t* s, void** l) { + /* WHILE statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _ls_node_t* loop_begin_node = 0; + _object_t* obj = 0; + _object_t loop_cond; + _object_t* loop_cond_ptr = 0; + + mb_assert(s && l); + + ast = (_ls_node_t*)(*l); + ast = ast->next; + + loop_cond_ptr = &loop_cond; + + loop_begin_node = ast; + +_loop_begin: + ast = loop_begin_node; + + result = _calc_expression(s, &ast, &loop_cond_ptr); + if(result != MB_FUNC_OK) { + goto _exit; + } + mb_assert(loop_cond_ptr->type == _DT_INT); + + if(loop_cond_ptr->data.integer) { + /* Keep looping */ + obj = (_object_t*)(ast->data); + while(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_wend)) { + result = _execute_statement(s, &ast); + if(result == MB_LOOP_BREAK) { /* EXIT */ + if(_skip_struct(s, &ast, _core_while, _core_wend) != MB_FUNC_OK) { + goto _exit; + } + _skip_to(s, &ast, 0, _DT_EOS); + result = MB_FUNC_OK; + + goto _exit; + } else if(result != MB_FUNC_OK && result != MB_SUB_RETURN) { /* Normally */ + goto _exit; + } + + obj = (_object_t*)(ast->data); + } + + goto _loop_begin; + } else { + /* End looping */ + if(_skip_struct(s, &ast, _core_while, _core_wend) != MB_FUNC_OK) { + goto _exit; + } + _skip_to(s, &ast, 0, _DT_EOS); + + goto _exit; + } + +_exit: + *l = ast; + + return result; +} + +int _core_wend(mb_interpreter_t* s, void** l) { + /* WEND statement */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + +int _core_do(mb_interpreter_t* s, void** l) { + /* DO statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _ls_node_t* loop_begin_node = 0; + _object_t* obj = 0; + _object_t loop_cond; + _object_t* loop_cond_ptr = 0; + + mb_assert(s && l); + + ast = (_ls_node_t*)(*l); + ast = ast->next; + + obj = (_object_t*)(ast->data); + if(!(obj->type == _DT_EOS)) { + _handle_error_on_obj(s, SE_RN_SYNTAX, DON(ast), MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + + loop_cond_ptr = &loop_cond; + + loop_begin_node = ast; + +_loop_begin: + ast = loop_begin_node; + + obj = (_object_t*)(ast->data); + while(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_until)) { + result = _execute_statement(s, &ast); + if(result == MB_LOOP_BREAK) { /* EXIT */ + if(_skip_struct(s, &ast, _core_do, _core_until) != MB_FUNC_OK) { + goto _exit; + } + _skip_to(s, &ast, 0, _DT_EOS); + result = MB_FUNC_OK; + + goto _exit; + } else if(result != MB_FUNC_OK && result != MB_SUB_RETURN) { /* Normally */ + goto _exit; + } + + obj = (_object_t*)(ast->data); + } + + obj = (_object_t*)(ast->data); + if(!(obj->type == _DT_FUNC && obj->data.func->pointer == _core_until)) { + _handle_error_on_obj(s, SE_RN_UNTIL_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + ast = ast->next; + + result = _calc_expression(s, &ast, &loop_cond_ptr); + if(result != MB_FUNC_OK) { + goto _exit; + } + mb_assert(loop_cond_ptr->type == _DT_INT); + + if(loop_cond_ptr->data.integer) { + /* End looping */ + _skip_to(s, &ast, 0, _DT_EOS); + + goto _exit; + } else { + /* Keep looping */ + goto _loop_begin; + } + +_exit: + *l = ast; + + return result; +} + +int _core_until(mb_interpreter_t* s, void** l) { + /* UNTIL statement */ + int result = MB_FUNC_OK; + mb_unrefvar(s); + mb_unrefvar(l); + + mb_assert(0 && "Do nothing, impossible here"); + _do_nothing; + + return result; +} + +int _core_exit(mb_interpreter_t* s, void** l) { + /* EXIT statement */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + result = MB_LOOP_BREAK; + + return result; +} + +int _core_goto(mb_interpreter_t* s, void** l) { + /* GOTO statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + _label_t* label = 0; + _ls_node_t* glbsyminscope = 0; + + mb_assert(s && l); + + ast = (_ls_node_t*)(*l); + ast = ast->next; + + obj = (_object_t*)(ast->data); + if(obj->type != _DT_LABEL) { + _handle_error_on_obj(s, SE_RN_JUMP_LABEL_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + + label = (_label_t*)(obj->data.label); + if(!label->node) { + glbsyminscope = _ht_find((_ht_node_t*)s->global_var_dict, label->name); + if(!(glbsyminscope && ((_object_t*)(glbsyminscope->data))->type == _DT_LABEL)) { + _handle_error_on_obj(s, SE_RN_LABEL_NOT_EXISTS, DON(ast), MB_FUNC_ERR, _exit, result); + } + label->node = ((_object_t*)(glbsyminscope->data))->data.label->node; + } + + mb_assert(label->node && label->node->prev); + ast = label->node->prev; + +_exit: + *l = ast; + + return result; +} + +int _core_gosub(mb_interpreter_t* s, void** l) { + /* GOSUB statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _running_context_t* running = 0; + + mb_assert(s && l); + + running = (_running_context_t*)(s->running_context); + ast = (_ls_node_t*)(*l); + result = _core_goto(s, l); + if(result == MB_FUNC_OK) { + _ls_pushback(running->sub_stack, ast); + } + + return result; +} + +int _core_return(mb_interpreter_t* s, void** l) { + /* RETURN statement */ + int result = MB_SUB_RETURN; + _ls_node_t* ast = 0; + _running_context_t* running = 0; + + mb_assert(s && l); + + running = (_running_context_t*)(s->running_context); + ast = (_ls_node_t*)_ls_popback(running->sub_stack); + if(!ast) { + _handle_error_on_obj(s, SE_RN_NO_RETURN_POINT, DON(ast), MB_FUNC_ERR, _exit, result); + } + *l = ast; + +_exit: + return result; +} + +int _core_end(mb_interpreter_t* s, void** l) { + /* END statement */ + int result = MB_FUNC_OK; + + mb_assert(s && l); + + result = MB_FUNC_END; + + return result; +} + +#ifdef _MB_ENABLE_ALLOC_STAT +int _core_mem(mb_interpreter_t* s, void** l) { + /* MEM statement */ + 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)); + + mb_check(mb_push_int(s, l, (int_t)_mb_allocated)); + + return result; +} +#endif /* _MB_ENABLE_ALLOC_STAT */ + +/** Std lib */ +int _std_abs(mb_interpreter_t* s, void** l) { + /* Get the absolute value of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.integer = (int_t)abs(arg.value.integer); + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)fabs(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_sgn(mb_interpreter_t* s, void** l) { + /* Get the sign of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.integer = sgn(arg.value.integer); + + break; + case MB_DT_REAL: + arg.value.integer = sgn(arg.value.float_point); + arg.type = MB_DT_INT; + + break; + default: + break; + } + mb_check(mb_push_int(s, l, arg.value.integer)); + + return result; +} + +int _std_sqr(mb_interpreter_t* s, void** l) { + /* Get the square root of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.float_point = (real_t)sqrt((real_t)arg.value.integer); + arg.type = MB_DT_REAL; + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)sqrt(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_floor(mb_interpreter_t* s, void** l) { + /* Get the greatest integer not greater than a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.integer = (int_t)(arg.value.integer); + + break; + case MB_DT_REAL: + arg.value.integer = (int_t)floor(arg.value.float_point); + arg.type = MB_DT_INT; + + break; + default: + break; + } + mb_check(mb_push_int(s, l, arg.value.integer)); + + return result; +} + +int _std_ceil(mb_interpreter_t* s, void** l) { + /* Get the least integer not less than a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.integer = (int_t)(arg.value.integer); + + break; + case MB_DT_REAL: + arg.value.integer = (int_t)ceil(arg.value.float_point); + arg.type = MB_DT_INT; + + break; + default: + break; + } + mb_check(mb_push_int(s, l, arg.value.integer)); + + return result; +} + +int _std_fix(mb_interpreter_t* s, void** l) { + /* Get the integer format of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.integer = (int_t)(arg.value.integer); + + break; + case MB_DT_REAL: + arg.value.integer = (int_t)(arg.value.float_point); + arg.type = MB_DT_INT; + + break; + default: + break; + } + mb_check(mb_push_int(s, l, arg.value.integer)); + + return result; +} + +int _std_round(mb_interpreter_t* s, void** l) { + /* Get the rounded integer of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.integer = (int_t)(arg.value.integer); + + break; + case MB_DT_REAL: + arg.value.integer = (int_t)(arg.value.float_point + (real_t)0.5f); + arg.type = MB_DT_INT; + + break; + default: + break; + } + mb_check(mb_push_int(s, l, arg.value.integer)); + + return result; +} + +int _std_rnd(mb_interpreter_t* s, void** l) { + /* Get a random value among 0 ~ 1 */ + int result = MB_FUNC_OK; + real_t rnd = (real_t)0.0f; + + mb_assert(s && l); + + mb_check(mb_attempt_func_begin(s, l)); + mb_check(mb_attempt_func_end(s, l)); + + rnd = (real_t)(((real_t)(rand() % 101)) / 100.0f); + mb_check(mb_push_real(s, l, rnd)); + + return result; +} + +int _std_sin(mb_interpreter_t* s, void** l) { + /* Get the sin value of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.float_point = (real_t)sin((real_t)arg.value.integer); + arg.type = MB_DT_REAL; + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)sin(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_cos(mb_interpreter_t* s, void** l) { + /* Get the cos value of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.float_point = (real_t)cos((real_t)arg.value.integer); + arg.type = MB_DT_REAL; + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)cos(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_tan(mb_interpreter_t* s, void** l) { + /* Get the tan value of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.float_point = (real_t)tan((real_t)arg.value.integer); + arg.type = MB_DT_REAL; + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)tan(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_asin(mb_interpreter_t* s, void** l) { + /* Get the asin value of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.float_point = (real_t)asin((real_t)arg.value.integer); + arg.type = MB_DT_REAL; + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)asin(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_acos(mb_interpreter_t* s, void** l) { + /* Get the acos value of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.float_point = (real_t)acos((real_t)arg.value.integer); + arg.type = MB_DT_REAL; + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)acos(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_atan(mb_interpreter_t* s, void** l) { + /* Get the atan value of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.float_point = (real_t)atan((real_t)arg.value.integer); + arg.type = MB_DT_REAL; + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)atan(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_exp(mb_interpreter_t* s, void** l) { + /* Get the exp value of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.float_point = (real_t)exp((real_t)arg.value.integer); + arg.type = MB_DT_REAL; + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)exp(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_log(mb_interpreter_t* s, void** l) { + /* Get the log value of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + + mb_assert(s && 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_INT: + arg.value.float_point = (real_t)log((real_t)arg.value.integer); + arg.type = MB_DT_REAL; + + break; + case MB_DT_REAL: + arg.value.float_point = (real_t)log(arg.value.float_point); + + break; + default: + break; + } + mb_check(mb_push_value(s, l, arg)); + + return result; +} + +int _std_asc(mb_interpreter_t* s, void** l) { + /* Get the ASCII code of a character */ + int result = MB_FUNC_OK; + char* arg = 0; + + mb_assert(s && l); + + mb_check(mb_attempt_open_bracket(s, l)); + + mb_check(mb_pop_string(s, l, &arg)); + + mb_check(mb_attempt_close_bracket(s, l)); + + if(arg[0] == '\0') { + result = MB_FUNC_ERR; + + goto _exit; + } + mb_check(mb_push_int(s, l, (int_t)arg[0])); + +_exit: + return result; +} + +int _std_chr(mb_interpreter_t* s, void** l) { + /* Get the character of an ASCII code */ + int result = MB_FUNC_OK; + int_t arg = 0; + char* chr = 0; + + mb_assert(s && l); + + mb_check(mb_attempt_open_bracket(s, l)); + + mb_check(mb_pop_int(s, l, &arg)); + + mb_check(mb_attempt_close_bracket(s, l)); + + chr = (char*)mb_malloc(2); + memset(chr, 0, 2); + chr[0] = (char)arg; + mb_check(mb_push_string(s, l, chr)); + + return result; +} + +int _std_left(mb_interpreter_t* s, void** l) { + /* Get a number of characters from the left of a string */ + int result = MB_FUNC_OK; + char* arg = 0; + int_t count = 0; + char* sub = 0; + + mb_assert(s && l); + + mb_check(mb_attempt_open_bracket(s, l)); + + mb_check(mb_pop_string(s, l, &arg)); + mb_check(mb_pop_int(s, l, &count)); + + mb_check(mb_attempt_close_bracket(s, l)); + + if(count <= 0) { + result = MB_FUNC_ERR; + + goto _exit; + } + + sub = (char*)mb_malloc(count + 1); + memcpy(sub, arg, count); + sub[count] = '\0'; + mb_check(mb_push_string(s, l, sub)); + +_exit: + return result; +} + +int _std_len(mb_interpreter_t* s, void** l) { + /* Get the length of a string */ + int result = MB_FUNC_OK; + char* arg = 0; + + mb_assert(s && l); + + mb_check(mb_attempt_open_bracket(s, l)); + + mb_check(mb_pop_string(s, l, &arg)); + + mb_check(mb_attempt_close_bracket(s, l)); + + mb_check(mb_push_int(s, l, (int_t)strlen(arg))); + + return result; +} + +int _std_mid(mb_interpreter_t* s, void** l) { + /* Get a number of characters from a given position of a string */ + int result = MB_FUNC_OK; + char* arg = 0; + int_t start = 0; + int_t count = 0; + char* sub = 0; + + mb_assert(s && l); + + mb_check(mb_attempt_open_bracket(s, l)); + + mb_check(mb_pop_string(s, l, &arg)); + mb_check(mb_pop_int(s, l, &start)); + mb_check(mb_pop_int(s, l, &count)); + + mb_check(mb_attempt_close_bracket(s, l)); + + if(count <= 0 || start < 0 || start >= (int_t)strlen(arg)) { + result = MB_FUNC_ERR; + + goto _exit; + } + + sub = (char*)mb_malloc(count + 1); + memcpy(sub, arg + start, count); + sub[count] = '\0'; + mb_check(mb_push_string(s, l, sub)); + +_exit: + return result; +} + +int _std_right(mb_interpreter_t* s, void** l) { + /* Get a number of characters from the right of a string */ + int result = MB_FUNC_OK; + char* arg = 0; + int_t count = 0; + char* sub = 0; + + mb_assert(s && l); + + mb_check(mb_attempt_open_bracket(s, l)); + + mb_check(mb_pop_string(s, l, &arg)); + mb_check(mb_pop_int(s, l, &count)); + + mb_check(mb_attempt_close_bracket(s, l)); + + if(count <= 0) { + result = MB_FUNC_ERR; + + goto _exit; + } + + sub = (char*)mb_malloc(count + 1); + memcpy(sub, arg + (strlen(arg) - count), count); + sub[count] = '\0'; + mb_check(mb_push_string(s, l, sub)); + +_exit: + return result; +} + +int _std_str(mb_interpreter_t* s, void** l) { + /* Get the string format of a number */ + int result = MB_FUNC_OK; + mb_value_t arg; + char* chr = 0; + + mb_assert(s && 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)); + + chr = (char*)mb_malloc(32); + memset(chr, 0, 32); + if(arg.type == MB_DT_INT) { + sprintf(chr, "%d", arg.value.integer); + } else if(arg.type == MB_DT_REAL) { + sprintf(chr, "%g", arg.value.float_point); + } else { + result = MB_FUNC_ERR; + + goto _exit; + } + mb_check(mb_push_string(s, l, chr)); + +_exit: + return result; +} + +int _std_val(mb_interpreter_t* s, void** l) { + /* Get the number format of a string */ + int result = MB_FUNC_OK; + char* conv_suc = 0; + mb_value_t val; + char* arg = 0; + + mb_assert(s && l); + + mb_check(mb_attempt_open_bracket(s, l)); + + mb_check(mb_pop_string(s, l, &arg)); + + mb_check(mb_attempt_close_bracket(s, l)); + + val.value.integer = (int_t)strtol(arg, &conv_suc, 0); + if(*conv_suc == '\0') { + val.type = MB_DT_INT; + mb_check(mb_push_value(s, l, val)); + + goto _exit; + } + val.value.float_point = (real_t)strtod(arg, &conv_suc); + if(*conv_suc == '\0') { + val.type = MB_DT_REAL; + mb_check(mb_push_value(s, l, val)); + + goto _exit; + } + result = MB_FUNC_ERR; + +_exit: + return result; +} + +int _std_print(mb_interpreter_t* s, void** l) { + /* PRINT statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + _running_context_t* running = 0; + + _object_t val_obj; + _object_t* val_ptr = 0; + + mb_assert(s && l); + + val_ptr = &val_obj; + memset(val_ptr, 0, sizeof(_object_t)); + + running = (_running_context_t*)(s->running_context); + ++running->no_eat_comma_mark; + ast = (_ls_node_t*)(*l); + ast = ast->next; + if(!ast || !ast->data) { + _handle_error_on_obj(s, SE_RN_SYNTAX, DON(ast), MB_FUNC_ERR, _exit, result); + } + + obj = (_object_t*)(ast->data); + do { + switch(obj->type) { + case _DT_INT: /* Fall through */ + case _DT_REAL: /* Fall through */ + case _DT_STRING: /* Fall through */ + case _DT_VAR: /* Fall through */ + case _DT_ARRAY: /* Fall through */ + case _DT_FUNC: + result = _calc_expression(s, &ast, &val_ptr); + if(val_ptr->type == _DT_INT) { + _get_printer(s)("%d", val_ptr->data.integer); + } else if(val_ptr->type == _DT_REAL) { + _get_printer(s)("%g", val_ptr->data.float_point); + } else if(val_ptr->type == _DT_STRING) { + _get_printer(s)("%s", (val_ptr->data.string ? val_ptr->data.string : _NULL_STRING)); + if(!val_ptr->ref) { + safe_free(val_ptr->data.string); + } + } + if(result != MB_FUNC_OK) { + goto _exit; + } + /* Fall through */ + case _DT_SEP: + if(!ast) { + break; + } + obj = (_object_t*)(ast->data); +#ifdef _COMMA_AS_NEWLINE + if(obj->data.separator == ',') { +#else /* _COMMA_AS_NEWLINE */ + if(obj->data.separator == ';') { +#endif /* _COMMA_AS_NEWLINE */ + _get_printer(s)("\n"); + } + + break; + default: + _handle_error_on_obj(s, SE_RN_NOT_SUPPORTED, DON(ast), MB_FUNC_ERR, _exit, result); + + break; + } + + if(!ast) { + break; + } + obj = (_object_t*)(ast->data); + if(_is_print_terminal(s, obj)) { + break; + } + if(obj->type == _DT_SEP && (obj->data.separator == ',' || obj->data.separator == ';')) { + ast = ast->next; + obj = (_object_t*)(ast->data); + } else { + _handle_error_on_obj(s, SE_RN_COMMA_OR_SEMICOLON_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + } while(ast && !(obj->type == _DT_SEP && obj->data.separator == ':') && (obj->type == _DT_SEP || !_is_expression_terminal(s, obj))); + +_exit: + --running->no_eat_comma_mark; + + *l = ast; + if(result != MB_FUNC_OK) { + _get_printer(s)("\n"); + } + + return result; +} + +int _std_input(mb_interpreter_t* s, void** l) { + /* INPUT statement */ + int result = MB_FUNC_OK; + _ls_node_t* ast = 0; + _object_t* obj = 0; + char line[256]; + char* conv_suc = 0; + + mb_assert(s && l); + + mb_check(mb_attempt_func_begin(s, l)); + mb_check(mb_attempt_func_end(s, l)); + + ast = (_ls_node_t*)(*l); + obj = (_object_t*)(ast->data); + + if(!obj || obj->type != _DT_VAR) { + _handle_error_on_obj(s, SE_RN_VARIABLE_EXPECTED, DON(ast), MB_FUNC_ERR, _exit, result); + } + if(obj->data.variable->data->type == _DT_INT || obj->data.variable->data->type == _DT_REAL) { + _get_inputer(s)(line, sizeof(line)); + obj->data.variable->data->type = _DT_INT; + obj->data.variable->data->data.integer = (int_t)strtol(line, &conv_suc, 0); + if(*conv_suc != '\0') { + obj->data.variable->data->type = _DT_REAL; + obj->data.variable->data->data.float_point = (real_t)strtod(line, &conv_suc); + if(*conv_suc != '\0') { + result = MB_FUNC_ERR; + + goto _exit; + } + } + ast = ast->next; + } else if(obj->data.variable->data->type == _DT_STRING) { + if(obj->data.variable->data->data.string) { + safe_free(obj->data.variable->data->data.string); + } + obj->data.variable->data->data.string = (char*)mb_malloc(256); + memset(obj->data.variable->data->data.string, 0, 256); + _get_inputer(s)(line, sizeof(line)); + strcpy(obj->data.variable->data->data.string, line); + ast = ast->next; + } else { + result = MB_FUNC_ERR; + + goto _exit; + } + +_exit: + *l = ast; + + return result; +} + +/* ========================================================} */ + +#ifdef MB_COMPACT_MODE +# pragma pack() +#endif /* MB_COMPACT_MODE */ + +#ifdef __APPLE__ +# pragma clang diagnostic pop +#endif /* __APPLE__ */ + +#ifdef _MSC_VER +# pragma warning(pop) +#endif /* _MSC_VER */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/core/my_basic.h b/core/my_basic.h new file mode 100644 index 0000000..8630873 --- /dev/null +++ b/core/my_basic.h @@ -0,0 +1,249 @@ +/* +** This source file is part of MY-BASIC +** +** For the latest info, see https://github.com/paladin-t/my_basic/ +** +** Copyright (c) 2011 - 2014 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 +# define _strcmpi strcasecmp +# endif /* _strcmpi */ +#endif /* _MSC_VER */ + +#ifndef mb_assert +# define mb_assert(__a) do { ((void)(__a)); assert(__a); } while(0) +#endif /* mb_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_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, +} 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); + +#ifdef MB_COMPACT_MODE +# pragma pack() +#endif /* MB_COMPACT_MODE */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MY_BASIC_H__ */ diff --git a/my_basic.sln b/my_basic.sln new file mode 100644 index 0000000..3c8c83e --- /dev/null +++ b/my_basic.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "my_basic", "my_basic.vcproj", "{6BBDF068-C7EB-4422-B5AF-8666948A02DE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + debug|Win32 = debug|Win32 + release|Win32 = release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6BBDF068-C7EB-4422-B5AF-8666948A02DE}.debug|Win32.ActiveCfg = debug|Win32 + {6BBDF068-C7EB-4422-B5AF-8666948A02DE}.debug|Win32.Build.0 = debug|Win32 + {6BBDF068-C7EB-4422-B5AF-8666948A02DE}.release|Win32.ActiveCfg = release|Win32 + {6BBDF068-C7EB-4422-B5AF-8666948A02DE}.release|Win32.Build.0 = release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/my_basic.vcproj b/my_basic.vcproj new file mode 100644 index 0000000..e8d94cd --- /dev/null +++ b/my_basic.vcproj @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/my_basic_mac.xcodeproj/project.pbxproj b/my_basic_mac.xcodeproj/project.pbxproj new file mode 100644 index 0000000..29af3b7 --- /dev/null +++ b/my_basic_mac.xcodeproj/project.pbxproj @@ -0,0 +1,254 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 03F4D7391A1D00A1009F920C /* my_basic.c in Sources */ = {isa = PBXBuildFile; fileRef = 03F4D7351A1D00A1009F920C /* my_basic.c */; }; + 03F4D73A1A1D00A1009F920C /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 03F4D7381A1D00A1009F920C /* main.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 03F4D7281A1D0081009F920C /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 03F4D72A1A1D0081009F920C /* my_basic_mac */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = my_basic_mac; sourceTree = BUILT_PRODUCTS_DIR; }; + 03F4D7351A1D00A1009F920C /* my_basic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = my_basic.c; sourceTree = ""; }; + 03F4D7361A1D00A1009F920C /* my_basic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = my_basic.h; sourceTree = ""; }; + 03F4D7381A1D00A1009F920C /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 03F4D7271A1D0081009F920C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 03F4D7211A1D0081009F920C = { + isa = PBXGroup; + children = ( + 03F4D7341A1D00A1009F920C /* core */, + 03F4D7371A1D00A1009F920C /* shell */, + 03F4D72B1A1D0081009F920C /* Products */, + ); + sourceTree = ""; + }; + 03F4D72B1A1D0081009F920C /* Products */ = { + isa = PBXGroup; + children = ( + 03F4D72A1A1D0081009F920C /* my_basic_mac */, + ); + name = Products; + sourceTree = ""; + }; + 03F4D7341A1D00A1009F920C /* core */ = { + isa = PBXGroup; + children = ( + 03F4D7351A1D00A1009F920C /* my_basic.c */, + 03F4D7361A1D00A1009F920C /* my_basic.h */, + ); + path = core; + sourceTree = ""; + }; + 03F4D7371A1D00A1009F920C /* shell */ = { + isa = PBXGroup; + children = ( + 03F4D7381A1D00A1009F920C /* main.c */, + ); + path = shell; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 03F4D7291A1D0081009F920C /* my_basic_mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 03F4D7311A1D0081009F920C /* Build configuration list for PBXNativeTarget "my_basic_mac" */; + buildPhases = ( + 03F4D7261A1D0081009F920C /* Sources */, + 03F4D7271A1D0081009F920C /* Frameworks */, + 03F4D7281A1D0081009F920C /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = my_basic_mac; + productName = my_basic_mac; + productReference = 03F4D72A1A1D0081009F920C /* my_basic_mac */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 03F4D7221A1D0081009F920C /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = "W. Renxin"; + TargetAttributes = { + 03F4D7291A1D0081009F920C = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 03F4D7251A1D0081009F920C /* Build configuration list for PBXProject "my_basic_mac" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 03F4D7211A1D0081009F920C; + productRefGroup = 03F4D72B1A1D0081009F920C /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 03F4D7291A1D0081009F920C /* my_basic_mac */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 03F4D7261A1D0081009F920C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 03F4D73A1A1D00A1009F920C /* main.c in Sources */, + 03F4D7391A1D00A1009F920C /* my_basic.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 03F4D72F1A1D0081009F920C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 03F4D7301A1D0081009F920C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + 03F4D7321A1D0081009F920C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 03F4D7331A1D0081009F920C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 03F4D7251A1D0081009F920C /* Build configuration list for PBXProject "my_basic_mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 03F4D72F1A1D0081009F920C /* Debug */, + 03F4D7301A1D0081009F920C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 03F4D7311A1D0081009F920C /* Build configuration list for PBXNativeTarget "my_basic_mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 03F4D7321A1D0081009F920C /* Debug */, + 03F4D7331A1D0081009F920C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 03F4D7221A1D0081009F920C /* Project object */; +} diff --git a/my_basic_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/my_basic_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..b301a29 --- /dev/null +++ b/my_basic_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/output/my_basic.exe b/output/my_basic.exe new file mode 100644 index 0000000000000000000000000000000000000000..03c38a57e60a11a15eb4395e337592ef6e640c6a GIT binary patch literal 59392 zcmeFa3w%`7wLg9)ISE4;m;oj_NR$yrjS?^#s2L`~33;M{Ofq?Z5Mm$+lNgeaoWo1x z;bdA4$F#QBwt8<{rS`VgzG$z%icbPT0!kH8k@#qH@8#d$NrP>?S_o>H-*@eO&dekP zsS?X}ikd+oLNS$yXMLcAadBCc>)5cVRZKQH^e^v^I}Pnz+} zB;m>Nzqxv^srWZnmj@a;`YJJ+_>)z6tY zG0CMD{r>K6{@ahcKj}BFNB0K$pTM*IYin8f=-w7R+}OVl@sIA^*8dZPUrpT3!XI~k z-2Z=Bd^>x7>Km>7kF)0{7M3-x4p7;nTjI+Xgkn>I@Wi3!a^qdU5NDcT8ZQWsA|{W= z#{U?h4c8ue_VW8UK}euS{28HOGchFY&ou#`-W@C<<)h3jj06-Z)a@69EV}6zgwCtz zX7ry)aE=p%yM8GMDWhM-Jg0Y$>MOwM1t=H$n9>qnSAM@u#wR76* zYNc91xaxAeK$(IA*AH;T{CQE;9G*;AN@X0w1>6YF;fne53PSgs_Kx<|h+}Q-$Bh%$ z3%Fwbyi{I$eRC@kUS*~iXh;%*-_m{b&npNEqfh_1`&%%e7P~~X)RNKdDR-Hz-|X%= zI`U7=!+X3^i!6ijU5kWWrulL5w9am6%B~#K{DmfYVsL+4@IYK=w|pw2yJvcL@MJi) z4E1&~qdRm&N>g*hO7-R{_2XH?XMZ<6e9f@3SwviEub1_7IQjG*uMj*a)~JV8#uPyH zS5&HP=8X44XQZhQ_$$M21rM4--I7IJZw{T2|F}|pvARbs5D}HAE-@=bX0?FcC#sdA z;uBGT#oZ>#@k)U1Z7k;!i+WjUS@;-As*KdUaxd{sbxh?z1yx;@5k}qF73yq)QPnfQ zj?9JXD+EQiG(9*RmM=qllr{i`x=Tf+QY;O>i53CKm#fv@8rCfJaIo84siya`PV3EK ztcM(zSE<>o^g}4nM{T5hAMi{uU4kZ1eM!Cu*ulfG2&cZn!R4-cBk{6)uR5)X4fCnLca3qdZYHQ?6M_Y%JL%5`dv2 zTN4<1M`HKrQGZ3{Ugs3AP_^&aWUuf%-G;j5gy(&@d77d^N92Tk0-n?>HDJHV5q=$| zJJg|oh;d7~Olc97t>)eW%YI7Xrtgt(NwFBDw12Iz9@`6_x&~jQ7LG)DpXD-=VgfQ51UUN=E-`fkiD5{l4&P z6dR#JjZ-1Y8P!10Vujl5GFO3ckD*>FaWgA1EKLVLsf8AGNlbag>NayIENg0|899zq zj;tMMKr%Hxwh^fSBY4mP^u(#JDmiGFs1%CIQVT<~slZlK-4hB+PboLm#L~52Jz25W zX(NQwFX4KhfE#cQ>U&MCw5#HMYJfrbzBKItb+H9}9KA7>oyVbHji|C&^G3Cc(yx&`uy$@ubUGPiG&y-782P*+UdGXFs|GL49_A34)c`wo(LD*^l}W__B{x zAXt<=REc0=wyg?*CwmVCbF+QR5zNlE)gZVo``9W3GqN9OK;X#sH6fUsJ+u}^&4jD@XrkbniGvD3BBPnt_|19p?xW zGNsvZjKxXmHR<9Z7n)Hv%?`BSVR|5qzu#73%5Wso~)1 z6>2`ld^=LAaegj(D=`i>*_15+V~fj+%Y|z$u5^G^MDRj1A4bzK3PK*`Sdh5bm8Q56 zO)WOsi)ab?7K}=*xY2BCVX6x0V+p$Bac`Fk-5br)WhzGX@j-WjY{AI7W3$NEElth0 zv9ZhE3!NLX1B0$lghD|Chr(>gg)(dd5-0+LhF$fVQF*zmm;)OlPSuI&Z+Hb786Z?e z&#MrsujoRxKvX3ZRc%Izb~Q5?PLMaM&@1AeKKd)Ku*)`ovV2A7ap*%n)BIACJSo^6 z2bHMvIO#)!2}~h^l+8!(RJBM{O~K3r`PR=}fVK0FV22=(Ey!094AU4mC@@E4BE=f| z1)3esb2&kJ=|F&hRMyZPU^gS>GEwc(?)W4e4s}~QZ=x4l08{}DwR5e06Z((yNOmRZE*WRgv6-F|(o8ju zN>CSy>Z`L3pY5A|K2!a#Ss$GJ?esI(e4w<8 zi1GF2kVL^?9+UhGNZm!r(`UVQ_U-A%uOUWA!4Lw3`g#|}WB}k`ABV3>z1Li-{#IK} ztr;SgIb-c~Lzw9L1at$y;*6mMB^@k=I@!?r5~l)?%|el-O#LewC#*q9o@+Zt6PKruFGac$8uJ|*;3n}gvb z2`n&P%3#!W6#YZ3CAhpIAAqLu0cZ*zc_y%t#~S)RrQ}Qoupp(zQTxy~khD{VU*@8W(_?rMNHtDR>Z}k5EkGJ=*zJO#2``ml|Bn z`tucr=Ll=duM%?ujdEpUzr9rb5Vbk9b&&d`Rf4L(K%o-I zceLH6E;NG%Np9O9fY^K|c+Mmx1<%Dv3Bhym7$9gQu>Jz&#V@oVTAtJ=sC|7aAOu&q zyn|CIQIbl6X)gNAt0I!40RzTcqXr8QVgZ_niqm46sgtZZmSjPQ%2mNn;^gstd9JyA zE5$)e@RN9X9Qt-HWHBKMrCglw(c1%86O)q|d6l|v38QS1sMOy+k%p#HzpfctLkl2- z|2}X7t~_<2E#t_n{nBhm8|e!A8Ta%cY8XuIO=QA;p&hLlyrMUe6pFrucGkk)M8;ud zcFev2s3Ua58d{I!qsT%@A9M%9iSl%sd8vscl5HU19UDbbHmsdbpiF~fV$h6!c7U3I zwF@N#@jXZh1-e;*pa;7=6NQqr+ONIwXA-;e%$h)P%OhK9xyoU|sxehYOQ1`2G)~AXvocjQ|Maji*?#FO`$IOAPD0M{Y zj3XJxdvlo;2?>zMKXYIiRSg-eEgwQf!trj82^o21m>aGZ2aa5!GNDma`dT?IWL zxX~e4L)Rlmuh&89)WCGAVmML03DSdz9^-I2WPYOl2vod<&e5!PC_vp(U2g#!k_VTo z&^>O(JIR%&Bx*xb+3VZ1%aN|jXCnUHW%gp8dT!PMb*O8l30gUc1K_;~TE!tTU7+DA zNAzR9v8#*N(KbkxDoaH77FUtAa~JV$xyuEnBn01sM|UPn1ztSLe;&A-UKc^yVTSHA zE2U6zz%%q9(il?ga=CLvs7riWu512HLY4MsK!~wp;6^F{Be^!0(8l}cX6m0b_0`}e z)(wPJO)P21ir7z+hC?(Zw;Ax773<18TQGxbI7hX?q zgn>ykNPq~ep)}m}<~k^Tz)7(SVv}D-$rA^D2cgfC{{?qQPVoaD;Qm?Pm%M^{K)d=+ ztO-=(O;qEJs%#E!Wo;;MpleWREQJ-I4V7ral9_`ubfN&JyeuVAScBr5*`O3T6<-Pj zvV(XP`i1LRC)L)g{o5Z=+Xi#SJ4%gNsS!ONN|&?w8K3VNQ!&qn^80EpH-*3o0**=p zukbPsX{}TSltlKd)zZ^?Qp-|N>Qb|^luEVglRL7Ypfs|0q?V#2C`K615E)4sTYn@q zN~e1BEubPANo!UrHtLq;>i@^4_Nq6P=FGd_09lg8oRua`$nr?zvgVJR7wOZ1qgl0E z#H`I*XJq9dymRa2SvAtstaRMFw@%1%A>W*l`Lbq7*JsU^uF1Mlnvr#rG(Bsjba_@P z^4uUdzQ9pUYG*kX6LIaqJe*vSn7D|>e3 zxhy;Ll1$+plz|)GO8u4U$tv|8oB9=sWGbBnI@*fu+e|`5SF1@X^@1-LR}S$sUSCC} z_NjvI#+-ynCiF;YnXeKfXu5U>N>NV+4>~auN^}F0(xj1d6!pXEzz!tpDls()rP|L> z5IC)uRgY)}*K$7DM*D)NEtLSz;v+g>0}wO?TbZ9oj#49Jf==te1IWh#5kW&U>b#S( zGyq6v1BnRCyg!GMXTsIMvUU?>|< zXom`WNIM0It4>F5rxIU;%7Vk=H>8AJp%tlK!n;km1NOq$sb9^?>WuE?1Qr@gx`hjB zfU9r0IQW)&h=eV-w?yUba93g27k;y=N}&^w;Q@0hFI1Ez=hD3P+^0^>UHvr?T0jzwn$*$ZQeiP+E$&2kA3;G8rE8^pm&5Nns zISfOy_GcW~z9l{EvOc)Kt9ZOgNm2m{h7f@4?DewQKOocL`e@LAi?l^bV^>V1T2SdQ zf^CGPF%V(&8%TP4=6v~HqA+0aDr6*#0l~ewY(VWb#bS(ig-hkFL8dgIN>Mx(^_;WP<^^lIZAZ`TOdXTgA%8AM@$c+%8VlFTCeb*xIV(whwHZMyh1;&6}bN8dasZJ+I<=EvGR-a4-6>ao|9l2C;E_d1D#G) z*#^~MxJdwGxO{#XA5x%9xWdWray0>?g=M>2kf##e02U>VS)UjmAdAxnjp9=zh4P(( zhNq&dDf#7$BG4z4#l}ojEX#J!OnKV&Ei=M1C`4XC^DoSofN>qXUe(ovIMb z9EV9c@I%B^O5KT)#sPYs_SYmUXzsZWVQ@i$Tt)iy_`TadhY`U=ltAQ@aeVt0N7z+k zeeeJP;*}hTQzjF;Lk!eF105z?NhR4z*z7X_0z)oTU*3E0bJWMsf`;@8Wa(n|IKAP5 z_PU1A_g+yQ(vIK`4GWPrLldLp)W9t+n@PTYSA15IJfWtmAPL4)0!}+R%<#n!Np`vj zB7;;)w{!&|(hL(VTB(=_-HDM@(7w03=gaBp4u(tEe1n-u^3|B&Yxz94S*5|+r9dE8 zGkYX2-blZP6#bu2AHitC44mVbfm8nW$n=R(>Y?$H7sB*PqytGsB99&|RV!`keY=oq zSFwwk`t2~2LEM^mCJ{2KA-8w!Ppi$Ewqe}%{rx*3s<)qWN(tM~jR)01a{4PuA>Knk z3-F^3*Hka-*?w-Kl(hX^5~T{ub4gbCE6R|n2B|>&Nw~G+Hh!2I>#y+PIgb^Pf~a0z zL>gu>kPh3=d90ng+0A@w=R@o!)!O+rc5{QZ^ULgJrhH2jmUCxWEwBq}Kc`#FeIfo? z$-S(l$RaQ>ua_4B0su!49N^gqxD9lR4)n(lv)28H7vl;ZKe4G62OTxJw~`K2 z;2?@3xN8*BXZBb(mI!_^`;(JL5@4e84CUd3 zg)E|q^~Fk>?843=PlLQk2%a}#0*z@OX-Fm}a#!|{rNe=@qUQtI)`yqnE=%7Pk(Y@w z^{@pqX-LaTUzxTW!!dXucJ-I^y;KyMMtTtO6=g6%>XQ{l^z>RglQGUR&B7WwMl%kd z*-!I+&s)~cZ_x8g>a?H-28`?JVY#^D9zMelT~5#YQHmM%Ww{ZP#9NI{B0W+yTc0Y$ z^lg((T?938D`=#0CK@nzAJK`jBxSi02ZRI5fb+X#wV9*v+iI5WOQZ_7*VZe!xv|qIk~%Da&n>GToJ&vuQo&^AsMN z59~;j*h(igBjX4MWmM;lQ6()CeUU0D-xsXX_64h?e4n98&s)-+?)g%s!4H>Fbwy^+ ztFV*2rd}}^m+_8%KLz*4aUZ9;txuKNtWVuBMcrnJVSzCiAhy)M&MqkYOGb|5OEf#( zAe;->l5)k?1HCr_RU|PZ@{!c5E2R)mm1Kggx|mJZ0-G)qxLArJSv>BY#J(AD+aN(| z>Enx^dPKZ@gI~Q$?TMO`bE(c+N|At5^&_ zRIznA%H6t%$}LrygNwVvy#5MRdcW{5^m5< zhJyh-b1RlRRVr1@WPyT3`o_V9l-j4R6t#9pW;LEC;&qS_N}1&kzcrXfscwudW1=dM zU22J_+<;WPw(*F8`wO0H;APRRw3vGnA&|p}YfuWNC@mPdDs5d0P0Oo$4xx3iSFZlN z6yYRX>u`NrkE3)3!O%Ew)_w?B(dnZsH*oA3IanjpNN*$>zu_mM-jeYSsR(KAo8?rs zjQY>>+SZBBqI-muY7g{lbC0#_89W7F4jU1{^KtUc$S@nKLtl>g+rHoRpE;Ot&r7k7 zIo43;s9Xm`s!4n&ZZNJdt_t%!i|P*U7lUDnG$GQ2I9neiIWC)C>gGu`BY=r1f>Mvn z%ra5|M&@`xU1NZ4AWjcU;c&x;P^cxaRH(L!%G*JsXJEv#2R}~S@TIWpn@inZGE0M; zxiJfVHCU-Md;TohcbtD8Bfexo2$QTe^Z<=~G(!Kz+F42WCeMr3&iQm_3x1r$Z-XC? zw}!qB#BARv&bNlXf;)8)ty?<CNxhdm3N7(bDEav;8{g?^gHSG=}CnZlu&EvRsn| z8*2*w9afrPefm}75nCTUaYwxXILBVxSzhX&* zIfto>VJw7pi%Bz#i`S`>mBoU3i+T>w1kWePX29=WC`!%2^GWh=K}|HhCFib;;BB!h zLo}aO$Hmy}$ymfXfYych45ufutU#&9SQ+X?@yvFwR}%{??qS?)21_j#su;sOpq84k zFnz1)hNeB47QJWiwL!R(+U5A%K^txyauR?|4BnO`o9=)a_~jb3kBo#pLAM~?9MSNm z5&WQqjZwSSrzM6HrH0lADt3d)diyau8VJzXg}AO8xQDy!wXwt!9!cRIKT4bU7Dl;p$$StWcB zx$j?$x1jES$ovH>BL0VYhQHv8WYdLzuCadBwb6v3m=p^b(klGg@^(Rh@r#-Qc1$bN zR=q_t1BZHYa56~BNh?xpg@C5z#2jjm2_z8Q&wK!OoJ)m>vEIiNeoh(8Dl%64wm(hn z>%{MWXZ!A1H>!R2o%mesJBDVD(LU%)%p)PP6mNJjVHv*3tT08RH<1iN%eC6xZ!AVug-@ugPw4SV%IEn+Dxjt2g_O{OgvdfK zmx{Pyuc5ZE&rcmI4G0&5~gvS-Dl?WCAwifIzywxDf{q=0ux zj(LOw4QQ67415EqRu)>qZ?QXds7a{QOsHfxE61s{*+B9aI5xrsTPbjm(@M&yViA`( zDhlq998hJQo!45XJ@;`q%&G_;^!l`~!g)>2rW)0Wgxp}SS-rLNSt5Du8?04?BK6j? zXNknLZHNND#i9)U<{%9!A>#~NfBrIwt19gc_*(=I(faU?^CSu|&(TwfL+ZO_=@zauL8V#g^|nLqrHvU5;yagtAaz>y=F??O|(EOT;!f?tYDMh z8|?u=vI?YRU8v^3!J7Qe6Zw>cqe6!mEOV6n7Xf%CkgsfCIFFr*L zt5qofSJCv}iKf3A=@~@yR-Z@#GAJ>#slS-QaFiwRW0t1`92_O+&rNo|72iba}j>LsFM%tL*-Eg-60%K&h3DejJa{u%jhTI5h zlhK|F%QyPO%o`2qfF|#WqV&foh54!fUj3c+?y->+jlKg>>me)x11@WI(HSJ4C14{B_ml@p{6<}M<;i?^_P#4+NGIKb`K@ad}xC~EzqfXhb))+Qi zQj5(s%4N%Y0LL7o;L89gc}8u7@m2?8(@X}&GG~nr1~fGtYDzr!F#c z_J7s@4N&6Xr@&*`95gmUZ=d1s?NS$;{c5#Eol2%>GVsF2Pn?C@6kJYRE?lX&m^B_t zTs9x3tM;-|%v)Sq&udK9(mKw65gH^+uNK71tK0==cg{}6j=Ra27o-T#CHfVz&3g@xh8YQAztRYU!D^r&I1I!?_vPWam;j@yYo%1V;N ztckLD{!7xN`G=(>c!b+`mb<17T5#t;im6l?DoH`PuF|S9%}sS^r~wm^tE^8U72c*< zp8^bp+q109Wkvq>KpjnwmyqW|if-Yh)hoo$bP)AqI5`Uu^ejO6)A(c8VpFMZR;|E_DNTirvQ)`lDlE@cRCP$aNzkfc*s4;8 z_)HE>D~Fm`n6owqQG3s(<8s+Ug_v6aL9?h z0=c-W0yAM(`7@6D;l{C&EjiIrh295nk5mg>*q$|*g_6mBbSrw!^Rkq_BYeX(a0jDR z&@>ceeG02u1&*pR+&IhB$`qp)Bb{idHXj`VxcP!H$o3*LW-!t1i`-Tk84nHJg|YOpAy>FDRcppMajjyxa^>pPr9beP|Cl{nCe+<}Lvh-C87!&r%}NKu*#o=#^fAiPCk;I+XV{SM60*3Qjf zLo!ESLFh?nCvS?F#Ko=4)vl=yt2>_kfZM<*2-_G@Io6J;SC5kB;= zK5aC^as&(h<>WFuL0u<8egqf5q4{}|IfDsoJ&@id!U9OOpwu`R3yN^1#AL*_2tDHq zJmU+fg8AW2APX1l=w5L!9wAW;uJqtvOmep8&$9a+M8qFParU3k(V&RYB?Tr?J6T96%EqG75miJPk>(^y z@4KomQM>WpN*C>-Bb*k`|kC(1yij8%Y)_t}z) z+9JXcAAK;1&wzuOw7w9)Dgb135hbN$<1sU%-X3IKIR*1c^cW=_M;^rGpeZuLLg7zOuHuMkW<;LS5$IWE$Z47iFviF_+}GZ%=zYB zfc8c3h;^#3VGGFlB|P7gaZw{KD*RGA;hGyPI)$#`;vr6m`9Y)&Xmj zwv?5y$N8Yy73oGhD*J*mv23vtE3Lg=-8X%72Cyyi(EeoNBVt{MkBf5Cvz#fIT@q9g z%TUBkdAJ;3kee*%^t9k7COHeUw@i?8-Yg<)+uL<63o(JgO*Ul)_=&hlN9S0~gkp$u z@)+khz&UvaGg(+v8lo(mnetAe0>(_Is?h~hXC7sZGLu=Eq_dMzWmMMD-G4X!Ac#2P zA&nSISilwxb=g222_lR27q7id-2r{+Lfln-PTbip#9f|&J9H4k-Qz1hJMI|1Ag{5S z0&-KA!4eCBT^0P8#5Wc%CXh(kCI)XCExz%Nwh@pNMv6peFX=JF2CEtnGas3r;Z*tz zL==f`Sj3PIJ{w-K?~kCe6x1Zo0~h9~ruR;Q?oX(nVCmV~NsEp&Kv^-<!ynA4zTVdnaLfpE5W-_?I}@esYB?oxhyWOY*NfJUITnlk9f; zHj+HO@dTY}A~zAq2hWOPjM90AmqaRihd0>a50*cIyEv6RQ(9i1k zIlY;nUSvRI?=T>;ksJf!?X(q$_M)Z`3wuF_Sr3Eqiq4*UTf(Xi8yE2$9TOv5Y)HjR zurVJK*#KyeA|DfJn6z5ylHtOVj97~U>e;YkwXHP^2`ONf) zHOkTSICx2V+(#5Nf*$RcqQ}%r(W7@vddxED@rJ*N9#d&N$};GY%DMC9P7BJHdwwTRefaEo`kna*Q$445qQikd5wo z0WtP87h_NBVhqeUS_7pqGnH7v?s-KfNpI%LBFcMa zfdnn;Hf&aWpBpVO0)ip6Ab1?H}o(RiN3XD#llj7dwJ zIvA^9=`$7*vd(Cpb{eTD4=1xY^+U>YA*qm&X|89`8rq4T^L)rXfzhonnRpJv$DJgp z`Vz`^AkqQs*x4Zhu`(T*N17$J!WX>;w=lvR2r2G8|bL8$K{2 zno+LPEN@4IW<_O^G6TI{jPbtIT{I5GsHEiA_5BWC?{PqApC65-^7vOs2kOYl{$^m?9+* z5r)}0LN~;mA9ZES`B6u3R8%*rXBsqX5j#F1;|Pm|s3Xmqx73TBgnTCwt;vl8&H1q` zSHjelm84=6IM}R(-Wci%-Pxe19A|NtR9STNqEGVNOS#5E#gVe2EQPs+t1G&iKlh^c z1u!V)m&BrfBEB1oMLlm~$HWL0J$Nw|rKCR^&7x6mV|Inl!l5bAJQs2(gaT)5LxCs5 zWIEVj3kZKBV=FKLF~DfjKlvIFX^up^$oL3{ioIn0PB&Aqn5s{?3^{FiuMgd+Gvjaj zMlxeeA&k|=Vn(K4jbKJn!bUJ7chDMDn8A$S@afEGXN?)fj8KNv@nAjT#W#WT3wd#J zjoPzPeW}`D#`GQ{2Oa?$#dMdk80SVh!EUs0Mt61|qIg|6>qd=#qo`5BnUeks#e*NA z{=fEj=Eoaj`0=Wd{0Q%|?{I!3?IfKa@CMbNqIHJkFL-OG5sl9rEqCBxH3=3_onHgu z;6yyJ0Y-6f_I*(*hohvAv2V)=_I)wJzI4agm+mgfzJ?CX_%|?$e*-c6Yb1?wIh z|6Vf&|5`_I>>!<}5MgHwzyILh&!Hjz|2qDfMvcGU`y%`sQ^?=WzoQB>_;<>pfAFua z4_|ux{odI8`@M_u??1-hv8TBIGxX<3p3;EmmcT`~p|CZ(dgMU90|9*FD z{{8Mn`S*YJ`1`-kKK0GNlYQ!*OWUV5N9NTRW$DjupBh=1!P47ube8_>_9?PMTsSBG zUtyp6Cg}=SlV&}J5Bdefo&}@Pm*}lRJRBZi>t*5a&HpBhvYicnDsu9cd zY)6l=o<4?^3Nzxr(|S5>XZh>v=@*!jXx*3AgZVy7GWPxmh7IgUeMK^pRo8PuX6HhJ z$Sttvu;q0aS1pDix9^YSwvvU{dHSmRJvU(ulNtTrJBd<~aRBLL=9UF_>c~Po`TBC> zVR}zrH@7xL&BxQJIKy;ngZ(NGi^3OGvZ{Ua|XVTYTrA_acWdHfHMMx_xe~gqYzq(0)@f3HA)T_(8|bO zj`7oAz0CV@bEKD}P8-o)-pqO#bqhu>8xR@2Y|r{Uy&N%59UW`^DFDZLc+OQA>rbg~ z80$|9_4Ow(J*_?^)9TZ7;wJ4uk06{qIlbFEXoZ(IVzBpmkj^f$z-g(_PKQI;6rbH# zl8OL;^R1D{p$g0g9|zlG=?3RRRFVT$LY2~t12UUkDaI)gcG{eJA6BQ_ICEw*LM(7h zhLO)jX2Jw@nK+mp{1`{B4gozdI-mh5bmXd|6hgwO3D0pCNweoK*3djk0{bxx52%tA zybDoO@O|_uHF&Rpb3SI$eFfYF_C5Y9uK@jQ^8Cy7^O;Lc^Q-85W_+)rm!Hpk1m`m! z3HHIC$r>6!XQ6By0*2;s4=t((h@g$Lb_GkHc%-jOuqRr%!;=lr+DqA48YxCTzPbor3dDaJ&g+FpfRpM=QkS9+6Yuaye*q>vr4mC{Ag? zSsEEfm`f@vsnU5tDKH9q)D!L|vd%7akOvq6vCcSjMY&xEVlzBL+Gk#nU46yfNLh1O zRxHaj!mL}0w52l%_zTm+;oQhUApZ3njOJkv1_Cp&jWiX9US_;gS;Ypa9&4uwPK9(Z z3dr|$qHGO2e;`&s!nknkAASvo`E=aR#g&OG3oe9Y@n>$;C=!lB4#==HqIeIAl^K_S znXI8{bi0TSkY=aShQ{-1^3CuFz8X+PmZlu6J%n%WK{v32rR<{bALQdaEjnPvXB-8F z!=D(g;k#g*A7dY!1xE#IXc93GU|T5S{1{?GpJv(1WC=kwMA<-0xc{mhDTC)lYu5tY zD0xq&gQ?SicUJ+m1)j#^t-m1KtZR_`C0+Pv1Oo)y((i^FIXUNBL$%~kzScajjKUgG zt9>5fHt}idoi53h0#`=hM#ZB4SrP;#SjcpjTA()&l>2cwBBGR1Z2iHh?`C%ec0vPy zJa;Llidh70{>4sVT}@>W26cBNN)1-`u_Iu(+B9$*(zvSy9H~LYE_29xKx`9`aPUVu z@~t5Y(!iUEVh6}=gVHA(>9-?29gZ;|Q44v0Swnq@K^FGnH@K%P)ATIX&>|#7wuzK2 zJ2u<*c{cXqTe!y>-eRnHF4D_oPF1v>1^YOFe%(=%-7!Z^b{BEfWL{e9E%4JcNM?|E ze9~HH7J#FI1~X8_3{){awu4q<$K!qgW_~eq(GVFT&o4R3ta^nVwOJ4v%;g6zlzQq8rK1AhF zdzjM*V4+hXf*&WycVOV9FDg*eZ+iekAaOqWz(I$PWfM=bT?&7Zm+_|JI1{6p*dxoD zcpGct!NFT0)2A8@m_Zc^1M|b-aBLK(kV+gCyu^uNg2`!gy$$espJ99Qou2okBy3gJ zH`g`iAdxM8?7-QAFV$4y09=yh zCWtjUCZ3#{%p6B)=*R#)f-cDKg`JX>SS78)9K_@9ASsmVz-9|JtkGFw>-bq>I6UJ) z7dg7nxf&ocK2p(XV&vK&^~7c+X2S6qJiXG9LL&YSeJqUT;F^;Kr||VKy=mvOMyH*( zhSt$A1@}kzPy$#|DQIZvqgdAO^nDn(cGEM{tZbe`a)to|8z>n|GpO$e)PRBx5ob{2 zEW`-dC_J4}AJd5Z+Q0n^2g2e35T`L74JOiflyQau!@hzspEDhOnns>uY<4+h?YtMM zQIwsZzVFupu|@5sqSDpm?q7R_-3RfbPCSfXG<>d_e3b4m&h9=&H^r_jM0*jDN5bXl zHz@T9tr4f}(kEKr*M=h)!PKh_M0y}DRn4Kpm&~3+d>HJ_p<#qR6+tI{M!Y+*udbAP8;{;$ zGJ)^)S2vL_BF;F1_R7xFb3zR%jwylpk&WrEjPucTmt5eL6r8)r&v>rqO*tJiI9Hb? z6L?RahOFf5eMtKwu*f-_>ujCZXOz&OPtK1su)VHlYCBT0uAk<4;3KF zMHvx+%_Yvh8GYllH|C((q+z5{HGSiZ`Jh>`>fZo>*GddMf)G-)84v3;iIem?+y8z=rm$*FtNbE8TaL@4{4N0n#aLgwo>gdQ58}E@&^DI$SWfp z3qAx;mchYJBruMrixoiB+64`QlB9wj$=blV!fUP~ zq$19uo-AWs1O%qgSu82q)Ne;=A*7*Y70=u5^Ri8|!A&Aq^k;};8Ur?z(iuEn(H#(_ zS*!~%GG6m*o*%4DEG^}NosSvp{B7hNJP?&(m6$Z7Xpep?Ql<25Mk2+oxz&7JgXmA` zsbJ(qALlC5{)sEz5D1HP;=%~|%2RsJ&EQ#+R4i;c@Guqhd>uRzz@)uHF)=l@}J zlfi{0l@^oxXuxr4df7|NF~UERnJAc}s~U%M9B|rmC9r3fHbMKn4ba++S-OkbkFET% zpV0u~9Bhh@9P~+z=h<2ghCiFf zP<-ioaVpJ4(UmydAKz;!V3P~|xKRMMWacQKMr1`5)DGy&$e}l7$>_#2E(QV#!6L+A zo4rbPV+yZek28IN!Hfg2Zo&sM#`v&}lF2`O#y^py@2&rOu-pLDIU|=9uYkX*+&L)2;;nW?Yr1322hUyFfs5>z~kb^^C-!!zrmZ6rS}$_ATK z5@|0%!Rqf0p3aQfpRpJ7A=JMH^=A@2m?QOkdUbL>iK>~4*$F`{*pj0I0BhbLgbvk?$*d{h9QUHt9s20ZBm&#Wjs z;p8E{uU$KK&F2Sbtp0fj3MTNg%;+Bt5O8=30MEz#Ejw_8@N+f6lLB}wTFFHLz(;Z~ zKorBsSoJ%24K+snfk^$usDCqmn`7_V8r25}YNbSanHAgVqjZq!aUlaZtlRj;MbZe>-;jf98y||NFT8g6)TrH=_M)WMmwVY5v7;4|5Ei&kJfMdT=mvqZcO?hJQ(F@Q5nBiK=0PpMCD<}#eAkweCta&-SMG)=ycEYw1DC#PV zoWlVf6M1k7P-&$$4~wCP#03IOzpOp93f^W%^-e$&gT}}JVzkdPx_>QN&cCt#rD4@Z z{rhzW9I;se3WSm~qJL?j!=h6ErlNmC$cx)6kNqb~?T`_WO^Xp?h=iNjUu!Cz?sK zqr)83Rq@BLyt51LQ)6}&KI&w2RV-8RE;IUTOnS5sel+Em95=r-S_0g>3CMNa{4>W5 z=g%l^h(9eV(c_jVUKX%yM2~CG{5>cbw<~zFN6}+JgdXV(ES&Nv;)`SOU*KoG%-TQe zP&{a%(g!-af*OA72pZjZF&bsvfTy?d2h_$_ zwXmLw9Z>7kkFB}L8J~Pcix0(7YiB`VWt9e8unpjFr;q5gn{9UXSuLEnh&q%FI9^z1 zCo;pQ_eIq0Kxfm%T!i`b+c7eR5-MJPfcYpi~;>$?ene6>DS{mE-OUPeq z=su2}e@8iJ>jvshItkBKhPLY8Ap@COGN<7S(A&s^1P4HZ!m-0!Z!!~DNUVQ}j6UlH z5oF$;DS+eI%qB&5N+M?)WW;yL7^_26+x5e_ji{KmNBE!mTU~7NL-LS?9>*-A^T|d> z_R%z45r+g!SOrPeY6!>PL=M!t^jd56FoMG*piBPqwrlR1m+4_}NOjy16 z_4Xe;g!8prp@$H_?B*f|7#CP_-ws$BaPSF^ydMVyP|seD<#`_?1lUaX-48q1F|>3r zK%d7*>BFJAY>ve`9SOdtC$J0_(mvva!EK@-C7_7GguQ8?3twO^evwc%N(yc>3-T2# zogMxF5EuHgVQ-;`ZlX_+;>(lP&^-X0to|Jc)yubU7CrLhKqfCNRWA(th+*VAhqY05 zz!$#ImBbFv?_7XP!E+HW3R)`VE4)FZ*|N(k;wzwHmPcMkUmFCj2!}y@Z_P^UqSnwp z7+?lI1~9>4l>Gs_8Lyw{GK|HzN60_}MZ`iMEjj+hY#!1Hs{VJyT)TQ{&|i?Lcv$qcuh3Ya_7MwT+}Ql&&sYo}yJ zDOQ|M2U~9ev-RRUy4Xct&Z?j+ItU@(qGZB5>T-2`Dvq{IROitdZLA;ISX$0iIXH5lvl>xw9fS7^Te8n*7CsY57ax#9rJz%5r^0UHt)V+8 zKR#aZvNTnvG<7jsYlGTzrx+j)5M4^LX!<5JFR+xq^p|PB0ru5xIMC7N`2=5bX}cXP z1oeXDr7wKIca8152A6=foV!dr<8l_x?~%{IayRfg072$xPNZNt>H8uqr=KzrKc<)Q z{du}bioipMavZd0I^dzk;!rs=V!KLv;|R+UspLd~5X(-0(}ykg&_DqaWZLZjWN@)( zP`b`tL!DmefPDl9sl~b~6v9qf1+pudIXFEw6*FSi;AIJ3R?UPsGu%T`@CkD~Rjc>A zQh-IsyNsjSpOXY($3g1w$b6bUnpj}Y@f?;@g59<*dkA$4bZ~TH8O~K(3TgtB?08X< z1;Q`A^eK0Bk|KURTtFvoM+(yACVi|m^9`iR7aO~2$5Eej<$9{cE#GHH>oSP&;Y3mJt5*_C6)NbH#$Nh3g!>+`t3%vsSL0R7UY+;~ z0itKYmeUY&_TEIo!~?r#Z2x4UG=BRhI0m%y9oc_qoPY><96sNRuP+qhINf~nLeDXI zIvNB7D*5L4?)YvW3N&zsLmr`QmFdWvq*e%uxC;$MUExHG5cWcp`;Y-~WfecIGb23m zoX%2yPAB|&K$)}YgihnQ&Nq#tI)~|Fvxb5P44-VG?|sJ{(-}ONS$#;HA>d#_obO1U z20cf~Sc7v{pwUA=Y5fr!fv0koZWCKs8$GUjXS)W#FfgWk#@RTCuW5lZz4G zJJx$awc=~C_FsB^Aa|mF)vAcUR4-TO{tC^ZYHA>V6LShM!9KGRqKTk|T&f1I?Knsc z8PQfGAb&t)U5P}Q(L~YagMNFp!=F@2j!Ln5rBpc z%8f!pr$EUzU*Im(H8{y1D55aY7uXV8w|=ZVy3b(0qbNv(5JprbbY*Mcq1g02fxROh ziN1A};K}FF$PTjd)^Qa0oH%6Blp@w|0im1OQ|U97Z(0T>)YOFjr|RDW7>RHe6sMcWV{-Y&P|cGe1{m(N zSWsq+?p<{3WS=%bIsTKnmM}9Ei)zu4vS=D2WQILaTfT z1M~;~tW!^~*VX?Wl+ph^4jhTDa$T<6Mea#&kkmO580JAHmnvIW0Nq#{239ckoy}%P zXAfon0n{T6WYff3`j70>6uiT}Izy9K`YJnpzO_ud8Cn9`2V8lyKjWSy(W^BBm8kKr z*Y04sJQHbxBgcK%GY~*^P4<9>0<;alKzLp`sUY(tFktw^G9~{M`6gPzvN@dGhPY*e zYnt#qY@}Qktp8L`9zKC|;dwsfL>^@7@5=A@b>*M(A)h)gz{~P!W@JJ0FC{9~~G_fIw^N<<|lA2~{e86UC;C#L}h_m#znmZk+L(3Vo`P<)cVDGnMi z#qB1fs1qMRTE!HeM^E8-gro30LX!3-_zn#4n1%=UmG9zLz7^^dJ0m^+G`wrZD~tPm zrCL3;4SiFusrmgZb;dh-`f*6Va}Q;wCdi55%qmlvvAwBog#K*`tk)q9>Czz-+yLG4YLMG!GATgC{ElVI{s5u;9Y0WAuM{Bic=WKX+) zKo7!WUP9w+)T)_)%V4(sm=_RO0&o75N`4fHmTAuc6~Sy9-h}1xRMB@R8i&Jc^x^1% zM@VTV65er|Mykh#Uqf{hKce5{A^N@YH2u!g=r{WmejDyjwjHNnqR4_P`&nedyDYf& zBnxK0f#5q|OE4n|wxc}uDIV2)@i76M$36w5y$M73 z9WM&qy$K)T4*2C-i4r=AEW1U-DWP|98&02^d0w)~Q?;J|G# zn-T~z4%BB{v@Aenhm%wA4&>lOaHQvG_}aU06TY^N{Wjwlet|ol@CtR|c>sV!w+$OK zY+bl!^@Hb_qI7fqrx`E$lzJ_Uqsa3=)d@+-AMVN@s(Xy`^{9)7>J-|+A}p)n7R^#a zY}muHjf=6sxBe9{ll;?YUsdp+10xA_3}&t>2yS)9+J5=Q;6_`#>{7k%DcS~_FQud0T^X(r%kEK-ol!|^Xnkszl{R~eW(#2+-YfQv3fIlZIe!tEue}bEV0Vpn+%P&W(o5(;^c^J% z5Ql3wg1FeQCRLyZW>cJxzwxm*P!8bl>2>YbW}H11>^JEhAKTaZhgO(i!r9W?g z5ltt-q^HMrm>BBdIY5aI0;}O`AL6}*YU2qi6SfglYP|pvG7!~ItfW6}4~wv`#CMB0 z#bC24Bh6s_ut0;MziQu--+Q0Mq6e+;NE1W&2;A9Yj}aFQ-c{L^KMWp7r>f*nGi1z_ z1l(r~VFsgzW)=cdNN1sR`5$HE4`mE_&dTFnC_%}C6G9(ibLOG_{k921$~+?CvnP~! zRKd!cT#TvZjfyBR$5u z$-&cNUzTfWL$H5aLvVPT^g2uI44xXo)@fKaeurhO-+?*F%0bKu6lMK(Aas1wRedQg z)#BPgHt6j;uqidXEqILCdxFP>!8H9Xk3Y%d-xdb#WDq)gfKtnQ;p;*>-W^O%m`So+ zYhk}O_KV3hVjS!@h5b6&uZ#VrvfniJo6dgcvfoVnHdz8iAX4oc(7vd%8my`Nd-G3` z$Q!&y1?@o4Gs=;YvabXIN%83BjBYQ{P_X`#F>MuY7F#jk16~n~&C0y6xvfvti5l7?VdI8rHxW0vJBd#`Fcj8)w zH1t=81~=o9aBao)Wn5py^$@P_jbV-xX$1@kIQ^e5U#*=9j+C4&O^8a zS0%1GTy40v;M#@jQCv^rI*98HT>pXVBV0*<#f2*q*X_8Sw8U3I@xHP}ODL?& zDHiG7fF6b1qB0@JpDPrX6bkuEeL_xo&Jv2x$u04-(7%X1 zQ#3`o>Nw z*LQR@wzjacoU1lDH`lkf3VDs|8|&&Lk3w#3^J=-dRzgB&eS3RrdrTQf*djGHG}gB} z<&N4l^>`&z*0wj+u4=BQ3hGx&^>v85U0&PfY_45Z-yDrCZf$LIuD>ub!>hAHs+H>3 zqV#A6ltXwO>s5KlSh2tb@IBU>MJ-bO8UP&wqL2eztZ8w!w$-=SO06T`McRb;+V=L^ zP0pB>#}wk1+8bNeM2jtuTUK+#MR9>N@@h$LuXnbzO3u}-YulRZ2}?Pw+zxqF$LjXR zwvp}5ZEo#Am$cWezPmp5O-WmQ%NWsmS!2VP+q!mbtrHFDs9)Q-y0w|Q)qpN{%wqp|Mr1atn1gXb4?Lq=oj$=)+b{gOT@u z8%U=24YiHUj6{U;)>h|Qd3C^9XJqaW7Bx55uc>Wz8X3zswbeT#)vv9URtF;VTvsdA zIwd4P{r*iYQtieFxeEDf+oVm-w)WOF?X_$1ehDz&A-A=GL0IJmPpl5q0>@H4(YSxp z+EuO1P6=QEM{5Lz>jpp@19OhE!RX-)jZ(lV1<y9EoJ?2l6acSZ4fP+zphOGL%Mr2~lO z>K$?PS6+d>ZhaWx5W<59A6?=Vx)Ju5c!lQ>+Dg5`UW)g7g(ndntMCeY5YlNEKc)9o zURGKlN-t*xic7R)l-j zd4*1d>Fr)&J3^=I6}BMUzR@d42x<3!GeYw32q2_=o^=Sx{bB_|^1UcW_yEFUgtXNz z525Woui!YTcXNrFi_@(fh zz$?N%@YN_Ut6*b%K@K16Z=RDrCp~@cEdu^%d~RQbaf!xJh}POV3>R~fgqqc@?e#Tv z^4hhVYHHaygx#1ewX0WSfM#QJa{x=<3h7^?4+=)yY8ojbkvtuw62^Fb zU*FsT0jbBg5={KQL#l5x?l(YxFzz9}8=Hk|@qFzX=pOYXNN*6X?STG?yc6-W0qvnb z)~5MM#IehLCH`vXwRLIE>+s8V1pY?>d~u%e;Eh3!+6~z+&{!AU8K}0-P7T=R+xLXk^$RMW-El9)6wvKz(zw zb2iY-(&V-Fx2vwjbnj}w8o!aC(DX%iI&PahvBWbBqxu-Po!MS zDXq5S!j=$@jX$F;l=a3rH?ng4Ih8=tY$v1UQAnhY? ziL2+Yr~s#RtjMWb+t>oqV$+codG#H4ORa4y4E|XGof^y&d7jf&#|80@C&mVg7Ov>c zQ9U%CbAIS$8I0#+G4GH6$SeFF7yTLUPsY5z`=?%E8?M;*Z^XR+(a*g?53ZB@SrYa` zhN8?puxrG`Z8?Njh#TwgANHBQ%|5d#0VE`~VgxTp=xD?IRB8}j6j#?{SQk!-4G@-s zFg;;yZF6($YFb;VscCFoRYM8~>{szM$Sk+D3-!Ddnfm9LU zKd7|YI^kWhL4TE*&hZ zX{c*lF9DXgVY3CTY={e zf_-&;n^Y4(uQk`V&*dey2)V*-1TR`E)qB0ma+WT=Q(XP>h+ zgIS6d(s93(v+9S8)P0F|4d4{QU9fqWnX7zPXgLI8i@@c0 zJo;v0bEOb+_UyL4M!AV_JEq;W$XUJ5>X2WlMegTM#P)jl$kV=wm^`QsIai0gS1oeH zK~Oa0qdv!XAPoLXPXpv%i9Fiy<=3Ng!RUl9e;D~VIL(*ujxXo2aE3461-cwC3NR52 zF>2&t#*y^}$Q(P99?dE+M5_je(#i)zX+?A>&5gW=UKtVsbfQ&*JJYHmov9eS7&>pH z_Mx>8-%YQ@22%;J=AnCl5Sr_XrZ*qy0Nh1y#CN21aY6JtP&%S5Z64kZXipo52GYi1 z9cWuZYkGTB8`=t#j%-Ui$Fu5#*6!oQ} zFZ7~{;)m$UwyE^f_9y5l?%w5@_@zxjAMm_ZioTSBpKzlu6HRm!{BV|u-WzM8ZOJC+ zpr63&*z;2|6d14tPOAQr*8|o)A@oP;0$3@F`uLJ^8m(Q zV&Lig0xO-G#kfcng%VXPlIeUQuuw)?rHaKm;Gpy17hZ-hUv|=kCB5mw(g>!j-XFY|DArh_7AGS@~INI3?NvSegY7;O8C-F2tOi3Pq8%;^~*R* zNtv4wVDWFt#$!uHMh3ZDE=ov9pi!en;aO}X4Ie(7h7KKyD6e>mi;JsvG5q%?&HvwN zbJ_2p&E|kxqy~mwnYrmL>U-46%mJ^g^U|7<5?``bUb60$0O;3RR)-M!&Fd(tRowhf z)^Ag0Ze44`bqJv!h$8QlV+p3nj)usa_T*SepiiG=pjM@CBs}#zC7z<2^*v?{^VQV6 zRv>|XTW^7{8y*f}ErNAz%gi0?(#Hs@)nWD5t?O83?gUmfUL=kGhRD#U8iSGRzgypD+pxe|URTq;rxjmYRgHQRRr^GS@M>s%D%_0r=#93 z)n?!i=!d`#>>AzuP5U8b=0B#-EPFlT8A@%vU$?Hxes%q-dNu1nznjs2=4#e}ajd(A zZe`}sDn*aJXUv`>Gjaok`t&_gX!#U<{08-Pzgxf5=+BKtekB)LYSwTx?xQ}*5zNeP7MNj z0afc%?;02)kI&)vX<5%0+4#YOXvM%_S`I7&iU)LFdIc*wn!8_ChM0anVnkE0x< zv-*ZnZWK??#`mUSG0_x?e_t?#mh~pW(uFp=B-;B@CheJ@Me)#0966j;^uu?RzC=s=01*JvOOP&07ideG zNQ+Y(^znjp`fx!u4MkAms{@EuM*;nbiothf_n`N)!sy)$jDc12v}5K-I#M)_ z$`_^4fraDg5!8D-9_`#u^lVf!`Y5L>eK@H*om!GgCth~Ze!Rusi1LylSerf?f|!!d zv@aLy*cHiiW_b#g8k~Z2U-3gRlb%;|9CZtzF3(^p8@+}Z#&k+<(XzG z&#H$tXMOtW@dkA6$;NbcdQ+@7n_}$=fFGICj1Ej}N~iK#(&@ZbKx;bv1jAqH^mO3K zHsEdP%#-ct%#3z)8aOkfJ)LUFZHAg3wqLb3$0XHXr=F$2voU9qzj7#x>STQ8IY-Ru^r>n>C#ds9ey6`*H>cc zi#IZ8P4N;MF?=YUEia)n2RG62{ciz`Z>FRBHqwcMTj*r@RyuiTE1dv8ai|nP{>b03 zetn-#fBG@~h?`1XYu2!_KO5`Syu3VeyWPe*)tKbB4>des`txbauaU{rJfJbC*-aGC zl&uguZ!!JFzg}JBU$4a$Q{V;nU zxDLamOox^CV2SHxp0xMKp}d2)oK>pQ^Oox|+3|l6M^5 z`uAOL|F_Cnbx$p3!(0D>>-Cw;S6)z6%bb2au1# zu^-Zm{^ob_7gm#@t0D35zZz-JHx5=>o!B3-Gr^vlvdBg0GzQjOl!osdQOKnb3o4vv z=x`+C&A-h+qVWx&D_;DY@HKe?jmN)a=(`E8u<`XW9(x#iQ@GJjJg|Ulh%of&W>5lj zC!^;HMm<*kFojVNM#ik<8a-iOGVeqkUw_|19WqHK}LNy^s^`f zNQO2`Gm@!EHJh=9JiD4Lp1PwST(zT(Sg@zX7%TIM$5uM}o>pxH<1wC*ln5!amSnV* zM(hu)3_u%W3~lDA4CpaWkHJ?cH?(TXg0Lr~5B7!xp-ql>{0o9NeK{LawfRal`ggsp z7_^c=qtW(w@GKf8_OIY?_k$Na&}c=_2Ry{sLFyQ1|(0yZk#lB)PobUu>%6399h9Z6J6m(n5iC| zl7Lv@V29ST%Jz+wtL#_PsL{IC^M<}^J*x)o@xkb1L=IsWQIc;gnor`!h8)A!*W2-V zKg!s4gdH6$nne%Jaiv==!NxucJ$Rt+EQH1OK~zwm!7;%>lYG8c5Q}Z$Ig2Gs4rYO% zEUsiiR(MuYDq?etO*wjSt}LQ#Vq%&r>Hg%&G4KjIX(>r^qBT)T;FEbd*_z1Qa&vFI z{nUEaK7#9VW31QfJEFs*!y_W19=ITk0w4QigO)3YE9WjTB9JO!+_wRU_4FYO?)t`%CtZ?C0$R zwHR%vmZ+s`bG04XZf&9dpreKJF6WC*-11rM0xjn{@|XEUOTJ|R#`2a$wo0}~ZH*Z> zo7-Y+$82Y97i|H;UBX~^VY;v!<2)}^3YUc|!Zm?JKha-oBDN4)iGui)6sHVRMk%9} zR3%NxP+HkL*&X(5`(*p4_DcH@Ena&^JD`Q=z4S5qBz>B`OfT0@>Kz@u9TOeX9ETmJ z90AUj&f(4^=j+Z7oQIreoadYs&Z|!LqGm1n6u^aWy}3EuB5oD8iF=#-fIGk)=YHVK zd>|jf>wF|Xj?d*^?J8HS4?9eb(=+SFH_gO>A%3tU{_dP@W;rmy6|%@=p1Xd`A98z9joA zvC2WErFxIrUv;a`s0Hd$wM0Fr9#v1Pm$XSbI~lFe*Gu9L;x+LOskIa+;fEb@S=e7| zX=6QQT`gP?UXhzAN0dftk*}uu1J1Weds5q~ZP#{cA8W_7^I97{TJPqxIn$jv&biJa zCwusmVdp_EmK(-pa+A2JTob;4Kgi!AF#9JMsGh1>es2H1WST;e8WyV}VfZbyaL zo@ZB?`-NL+dBNJlHrzJaHrKY$7A-s`h@vj0V0M;>>&0^MXVE6TC@qp!N$aIN`6;^)K|V^{aYg#~qHY4hznCtYerX$MK?Lg=3dvuj4AteQ#%^bCz?C zbA@w_bE9*sbEk6;X22yUEknGTiKr#lj_b&AoXqv&`f<@*5|;rVJkCAE6>x>zQf@W( zI_56EmcoKgEB?-(#^@WJ^Cw zj%BW8spVD6VT->t%sSFK$9mKnXd7WGur0B@Yde7J;9Faz?R(obTRkB_NEF5h=|Z+J zMR-EU7YcfBlM}J4Oajp{`sg87q+cCwF=Xl!jyrZ|11yQj$rwBfpkKyC^sW>-rwce>_$ocXt zdA2;yn2*Ks8hNd}UfzVUZf9~wl@G{=<>T^c`7`+8oO~X>xGZ0hugRqNDgH_m zrG?T;X`=)xK}v|yMd_|^icOJmzwM<&D3S0|v=XD-c>i+4UsK_+8A?99Hd~pe6e^41 zxngCFvQ}BIY*I>xdFH$Vz@Zm8AfrVxm1o>adWx2N91ucxO{FFH=CP> l>tr#vj4S5WaBI2sxLQiNZQKrSC%2n}@!NFU1OLGu_#Y8UfFu9_ literal 0 HcmV?d00001 diff --git a/output/my_basic_mac b/output/my_basic_mac new file mode 100755 index 0000000000000000000000000000000000000000..3fd4de80fe7f72854702db11aea3965ea9567d26 GIT binary patch literal 77088 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 QHk28K+Rb*E?-zCd2DR#LGXMYp literal 0 HcmV?d00001 diff --git a/resource/icon.ico b/resource/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..9d6d1ad6ee2042c5b699cbbe03a61c8e6a647286 GIT binary patch literal 6006 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 +# include +#else /* _MSC_VER */ +# include +#endif /* _MSC_VER */ +#include +#include +#include +#include +#include "../core/my_basic.h" + +#ifdef _MSC_VER +# pragma warning(disable : 4127) +# pragma warning(disable : 4996) +#endif /* _MSC_VER */ + +#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 - 2014 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; +}