📄 brun.c
字号:
/*** SmallBasic byte-code executor** Nicholas Christopoulos** This program is distributed under the terms of the GPL v2.0 or later* Download the GNU Public License (GPL) from www.gnu.org*/#include "sys.h"#include "panic.h"#include "blib.h"#include "device.h"#include "str.h"#include "kw.h"#include "var.h"#include "smbas.h"#define BRUN_MODULE#include "pproc.h"byte opt_graphics = 1;#if defined(_PalmOS)#define idSmBa 0x536D4261#define idDATA 0x44415441#endif//#define _CHECK_STACKword prog_line; // The current source lineint prog_error; // The last error code (its work as flag)word prog_length; // The byte-code length (program length in bytes)word prog_ip; // The instruction pointerbyte *prog_source; // The byte-codeword data_ip; // READ/DATA positionvar_t **tvar; // The table of variableslab_t *tlab; // The table of labelsstknode_t *prog_stack; // The program stack word prog_stack_alloc; // The stack sizeword prog_stack_count; // The stack pointerword prog_varcount;word prog_labcount;char *prog_file;static dword evt_check_every;#if defined(_PalmOS) static char fileName[65];#elsestatic char fileName[1024];#endifmem_t bytecode_h;#if defined(_PalmOS)DmOpenRef bytecode_fp;word bytecode_recidx;#define fatal(c,m) ErrNonFatalDisplayIf((c), (m))#endif/*** run-time error*/void rt_raise(const char *fmt, ...){ char *buff; va_list ap; va_start(ap, fmt); prog_error = 1; buff = tmp_alloc(256); #if defined(_PalmOS) StrVPrintF(buff, fmt, ap); #else vsprintf(buff, fmt, ap); #endif va_end(ap); dev_printf("* ERROR AT %s:%d *\n", prog_file, prog_line); dev_printf("> %s\n", buff); tmp_free(buff);}/* ERROR MESSAGES */void err_stackoverflow() SEC(TRASH);void err_stackoverflow() { rt_raise("STACK OVERFLOW"); }void err_stackunderflow() SEC(TRASH);void err_stackunderflow() { rt_raise("STACK UNDERFLOW"); }void err_arrmis_lp() SEC(TRASH);void err_arrmis_lp() { rt_raise("ARRAY: MISSING '('"); }void err_arrmis_rp() SEC(TRASH);void err_arrmis_rp() { rt_raise("ARRAY: MISSING ')'"); }void err_arridx() SEC(TRASH);void err_arridx() { rt_raise("ARRAY: INDEX OUT OF RANGE"); }void err_typemismatch() SEC(TRASH);void err_typemismatch() { rt_raise("TYPE MISMATCH"); }void err_varisnotarray() SEC(TRASH);/** returns the code of the next commandbyte code_peek(){ return prog_source[prog_ip];}*//** moves the instruction pointer to the next instructionbyte code_getnext(){ byte v; v = prog_source[prog_ip]; prog_ip ++; return v;}*//** returns the next 16bit and moves the instruction pointer to the next instructionword code_getnext16(){ word v; memcpy(&v, prog_source+prog_ip, 2); prog_ip += 2; return v;}*//** returns the next 32bit and moves the instruction pointer to the next instruction*/dword code_getnext32(){ dword v; memcpy(&v, prog_source+prog_ip, 4); prog_ip += 4; return v;}/** returns the next 64bit and moves the instruction pointer to the next instruction*/double code_getnext64f(){ double v; memcpy(&v, prog_source+prog_ip, 8); prog_ip += 8; return v;}/** jump to label*/void code_jump_label(word label_id){ prog_ip = tlab[label_id].ip;}/** jump to IPvoid code_jump(word ip){ prog_ip = ip;}*//** Put the node 'node' in stack (PUSH)*/void code_push(stknode_t *node){#if defined(_UnixOS) && defined(_CHECK_STACK) int i;#endif if ( prog_stack_count + 1 >= prog_stack_alloc ) { err_stackoverflow(); return; } prog_stack[prog_stack_count] = *node;#if defined(_UnixOS) && defined(_CHECK_STACK) for ( i = 0; keyword_table[i].name[0] != '\0'; i ++ ) { if ( node->type == keyword_table[i].code ) { printf("%3d: PUSH %s (%d)\n", prog_stack_count, keyword_table[i].name, prog_line); break; } }#endif prog_stack_count ++;}/** Returns and deletes the topmost node from stack (POP)*/void code_pop(stknode_t *node){#if defined(_UnixOS) && defined(_CHECK_STACK) int i;#endif if ( prog_stack_count ) { prog_stack_count --; if ( node ) *node = prog_stack[prog_stack_count];#if defined(_UnixOS) && defined(_CHECK_STACK) for ( i = 0; keyword_table[i].name[0] != '\0'; i ++ ) { if ( prog_stack[prog_stack_count].type == keyword_table[i].code ) { printf("%3d: POP %s (%d)\n", prog_stack_count, keyword_table[i].name, prog_line); break; } }#endif } else { if ( node ) { err_stackunderflow(); node->type = 0xFF; } }}/** Peek the topmost node of stack*/stknode_t* code_stackpeek(){ if ( prog_stack_count ) return &prog_stack[prog_stack_count-1]; return NULL;}/** Returns the varptr of the next variable* if the variable is an array returns the element ptr*/var_t *code_getvarptr(){ var_t *basevar_p, *var_p = NULL; long array_index; basevar_p = tvar[code_getnext16()]; if ( basevar_p->type == V_ARRAY ) { /* * Variable is an array */ if ( code_peek() != kwTYPE_LEVEL_BEGIN ) err_arrmis_lp(); else { code_skipnext(); // '(' array_index = getarrayidx(basevar_p); if ( !prog_error ) { if ( array_index < basevar_p->size ) { var_p = (var_t*) (basevar_p->ptr + (array_index * sizeof(var_t))); if ( code_peek() == kwTYPE_SEP ) code_skipnext(); // ',' else if ( code_peek() == kwTYPE_LEVEL_END ) code_skipnext(); // ')', ')' level else err_arrmis_rp(); } else err_arridx(); } } } else { var_p = basevar_p; if ( code_peek() == kwTYPE_LEVEL_BEGIN ) err_varisnotarray(); } return var_p;}/** returns true if the next element is a null-array i.e. v() keyword** example:* v() --- true* v(1) --- false*/int code_isnullarray_nc(int start){ var_t *basevar_p; int16 idx; memcpy(&idx, prog_source+prog_ip+start, 2); if ( idx < prog_varcount ) { basevar_p = tvar[idx]; if ( basevar_p->type == V_ARRAY ) { if ( prog_source[prog_ip+start+2] != kwTYPE_LEVEL_BEGIN ) return 1; } } return 0;}int code_isnullarray(){ if ( prog_source[prog_ip] == kwTYPE_VAR ) return code_isnullarray_nc(1); return 0;}/**/void setsysvar_int(int index, long value){ var_t *var_p = tvar[index]; var_p->type = V_INT; var_p->const_flag = 1; var_p->i = value;}/**/void setsysvar_num(int index, double value){ var_t *var_p = tvar[index]; var_p->type = V_NUM; var_p->const_flag = 1; var_p->n = value;}/**/void setsysvar_str(int index, const char *value){ var_t *var_p = tvar[index]; int l = strlen(value)+1; if ( var_p->type == V_STR ) tmp_free(var_p->ptr); var_p->type = V_STR; var_p->const_flag = 1; var_p->ptr = tmp_alloc(l); strcpy(var_p->ptr, value); var_p->size = l;}/** RUN byte-code* * source structure:* [word] number_of_variables* [word] number_of_labels* for each label:* [word] ... label-ip* [word] bytecode_length* ...** brun_init(source)* brun()* brun_close()*/void brun_init(byte *source){ word i; memcpy(&prog_varcount, source , 2); memcpy(&prog_labcount, source+2, 2); if ( prog_varcount == 0 ) prog_varcount ++; tvar = tmp_alloc(sizeof(var_t *) * prog_varcount); for ( i = 0; i < prog_varcount; i ++ ) tvar[i] = v_new(); if ( prog_labcount == 0 ) tlab = tmp_alloc(sizeof(lab_t)); else { tlab = tmp_alloc(sizeof(lab_t) * prog_labcount); for ( i = 0; i < prog_labcount; i ++ ) memcpy(&tlab[i].ip, source+(i<<1)+4, 2); } prog_stack_alloc = 256; prog_stack = tmp_alloc(sizeof(stknode_t) * prog_stack_alloc); prog_stack_count = 0; prog_error = 0; prog_line = 0; memcpy(&data_ip, &source[(prog_labcount<<1)+4], 2); memcpy(&prog_length, &source[(prog_labcount<<1)+6], 2); prog_source = &source[(prog_labcount << 1) + 8]; prog_ip = 0; // predefined variables setsysvar_int(SYSVAR_OSVER, os_ver); #if defined(_PalmOS) setsysvar_str(SYSVAR_OSNAME, "PalmOS"); #else #if !defined(_Win32) setsysvar_str(SYSVAR_OSNAME, "Unix"); #else setsysvar_str(SYSVAR_OSNAME, "Win32"); #endif #endif setsysvar_int(SYSVAR_SBVER, SB_DWORD_VER); setsysvar_num(SYSVAR_PI, 3.14159265358979323846); setsysvar_int(SYSVAR_XMAX, 160); setsysvar_int(SYSVAR_YMAX, 160); setsysvar_int(SYSVAR_BPP, 1); setsysvar_int(SYSVAR_TRUE, 1); setsysvar_int(SYSVAR_FALSE, 0); setsysvar_int(SYSVAR_LINECHART, 1); setsysvar_int(SYSVAR_BARCHART, 2); // cmd_play_reset();}/** load & compile the source file 'fileName'*/void brun_load(char *fileName){ char *ptr;#if defined(_PalmOS) DmOpenRef fp; LocalID lid;#endif bc_init(); prog_file = fileName; /* * compile - pass1 */ bc_load(fileName); /* * compile - pass2 & binary */ bytecode_h = 0; if ( !bc_get_error() ) { bc_pass2(); if ( !bc_get_error() ) { bc_check_labels(); if ( !bc_get_error() ) bytecode_h = bc_createbin(); } } bc_close(); /* * run */ if ( bytecode_h ) { #if defined(_PalmOS) /* * PalmOS - Memory optimization * * We'll free 'bytecode' memory by using a database record handle * Because 'bytecode' it is working as read-only we have no problems * using record's memory handle instead of a dynamic-RAM handle */ word recIndex; mem_t rec_h; char *prevrec, *newrec; lid = DmFindDatabase(0, (char *) "SBVM.BIN"); if ( lid ) DmDeleteDatabase(0, lid); DmCreateDatabase(0, "SBVM.BIN", idSmBa, idDATA, 0); lid = DmFindDatabase(0, (char *) "SBVM.BIN"); fp = DmOpenDatabase(0, lid, dmModeReadWrite); // save bytecode_h recIndex = dmMaxRecordIndex; rec_h = DmNewRecord(fp, &recIndex, MemHandleSize(bytecode_h)); newrec = mem_lock(bytecode_h); prevrec = mem_lock(rec_h); DmWrite(prevrec, 0, newrec, MemHandleSize(bytecode_h)); mem_unlock(rec_h); mem_unlock(bytecode_h); DmReleaseRecord(fp, recIndex, 1); // free bytecode_h mem_free(bytecode_h); bytecode_h = DmGetRecord(fp, recIndex); bytecode_fp = fp; bytecode_recidx = recIndex; /* * Try to defrag dynamic memory */ MemHeapCompact(0); #endif ptr = mem_lock(bytecode_h); brun_init(ptr); #if defined(_PalmOS) EvtWakeup(); // !@$!@#$@#!$#@#$$! #endif } else prog_error = -32;}int brun_close(void){ word i; if ( bytecode_h ) { // clean up for ( i = 0; i < prog_varcount; i ++ ) { v_free(tvar[i]); tmp_free(tvar[i]); } tmp_free(tvar); tmp_free(tlab); tmp_free(prog_stack); mem_unlock(bytecode_h); #if defined(_PalmOS) DmReleaseRecord(bytecode_fp, bytecode_recidx, 1); DmRemoveRecord(bytecode_fp, bytecode_recidx); DmCloseDatabase(bytecode_fp); #else mem_free(bytecode_h); #endif bytecode_h = 0; } // if ( prog_error != -1 && prog_error != 0 ) return 1; return 0;}/** BREAK*/void brun_stop(){ prog_error = -3;}/** returns the status of executor (runing or stopped)*/ int brun_status(){ if ( prog_error ) return BRUN_STOPPED; return BRUN_RUNNING;}/** BREAK - display message, too*/void brun_break(){ if ( brun_status() == BRUN_RUNNING ) { if ( os_graphics ) dev_settextcolor(0, 15); dev_printf("\n\a* BREAK AT LINE %d *\n", prog_line); } brun_stop();}/**/void cmd_chain(void){ var_t var; v_init(&var); eval(&var); if ( prog_error ) return; else { if ( var.type != V_STR ) { err_typemismatch(); return; } else { strcpy(fileName, var.ptr); if ( !basFileExist(fileName) ) { rt_raise("CHAIN: FILE '%s' DOES NOT EXIST", fileName); v_free(&var); return; } v_free(&var); } } brun_close(); #if defined(_PalmOS) dev_cls(); #endif brun_load(fileName);}/** RUN "program"** For PalmOS use RUN CreatorID (i.e. run "calc")*/void cmd_run(void){ var_t var; v_init(&var); eval(&var); if ( prog_error ) return; else { if ( var.type != V_STR ) { err_typemismatch(); return; } else { strcpy(fileName, var.ptr); v_free(&var); } }// brun_close(); if ( !dev_run(fileName) ) rt_raise("RUN \"%s\" FAILED", fileName);}/*static void run_events(){ static dword next_check; register dword now; #if defined(_PalmOS) now = TimGetTicks(); #else now = clock(); #endif // events if ( now >= next_check ) { next_check = now + evt_check_every; switch ( dev_events(0) ) { case -1: break; // break event case -2: prog_error=-2; if ( os_graphics ) dev_settextcolor(0, 15); dev_printf("\n\a* BREAK AT LINE %d *\n", prog_line); break; }; }}*//**/void bc_loop(int isf){ byte code, pops; byte trace_flag = 0; word next_ip; stknode_t node; int udf_level = 0; static dword next_check; register dword now; /** * DO NOT CREATE FUNCTION-PTR-TABLE * function tables does not works with multiseg * * For commands witch changes the IP use * * case mycommand: * command(); * if ( prog_error ) break; * continue; */ while ( prog_ip < prog_length ) {// run_events(); #if defined(_PalmOS) now = TimGetTicks(); #else now = clock(); #endif // events if ( now >= next_check ) { next_check = now + evt_check_every; switch ( dev_events(0) ) { case -1:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -