📄 scan.c
字号:
/*** SmallBasic pseudo-compiler. Converts the source to byte-code.** 2000-05-27, 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*/#define SCAN_MODULE#include "sys.h"#include "str.h"#include "panic.h"#include "device.h"#include "kw.h"#include "bc.h"#include "smbas.h"void bc_scan_cmd(char *text) SEC(BCSCAN);int bc_scan_inline_if(char *text) SEC(BCSCAN);int bc_is_keyword(char *name) SEC(BCSCAN);word bc_search(word ip, byte code) SEC(BCSCAN);#if defined(_PalmOS) static char bc_fileName[65];#elsestatic char bc_fileName[1024];#endif#define TEXT_LINE_SIZE 512extern void expr_parser(bc_t *bc) SEC(BCSCAN);struct keyword_s { char name[16]; /* keyword */ byte code; /* byte-code */ };struct keyword_s keyword_table[] = {{ "$$$_int", kwTYPE_INT },{ "$$$_dbl", kwTYPE_NUM },{ "$$$_str", kwTYPE_STR },{ "$$$_log", kwTYPE_LOGOPR },{ "$$$_cmp", kwTYPE_CMPOPR },{ "$$$_add", kwTYPE_ADDOPR },{ "$$$_mul", kwTYPE_MULOPR },{ "$$$_pow", kwTYPE_POWOPR },{ "$$$_unr", kwTYPE_UNROPR },{ "$$$_var", kwTYPE_VAR },{ "$$$_line", kwTYPE_LINE },{ "$$$_LPAR", kwTYPE_LEVEL_BEGIN },{ "$$$_RPAR", kwTYPE_LEVEL_END },{ "$$$_CRVAR", kwTYPE_CRVAR },{ "LOCAL", kwLOCAL },{ "SUB", kwPROC },{ "FUNC", kwFUNC },{ "BYREF", kwBYREF },{ "DECLARE", kwDECLARE },{ "LET", kwLET },{ "CONST", kwCONST },{ "DIM", kwDIM },{ "STOP", kwSTOP },{ "END", kwEND },{ "PRINT", kwPRINT },{ "INPUT", kwINPUT },{ "PEN", kwPEN },{ "CLS", kwCLS },{ "REM", kwREM },{ "CHAIN", kwCHAIN },{ "ON", kwON },{ "OFF", kwOFF },{ "LABEL", kwLABEL },{ "GOTO", kwGOTO },{ "IF", kwIF },{ "THEN", kwTHEN },{ "ELSE", kwELSE },{ "ELIF", kwELIF },{ "ELSEIF", kwELIF },{ "ENDIF", kwENDIF },{ "FI", kwENDIF },{ "FOR", kwFOR },{ "TO", kwTO },{ "STEP", kwSTEP },{ "NEXT", kwNEXT },{ "WHILE", kwWHILE },{ "WEND", kwWEND },{ "REPEAT", kwREPEAT },{ "UNTIL", kwUNTIL },{ "GOSUB", kwGOSUB },{ "RETURN", kwRETURN },{ "READ", kwREAD },{ "DATA", kwDATA },{ "RESTORE", kwRESTORE },{ "EXIT", kwEXIT },{ "LOOP", kwLOOP },{ "RND", kwRND },{ "ABS", kwABS },{ "LEN", kwLEN },{ "COS", kwCOS },{ "SIN", kwSIN },{ "TAN", kwTAN },{ "ACOS", kwACOS },{ "ASIN", kwASIN },{ "ATAN", kwATAN },{ "ATN", kwATAN },{ "ACOSH", kwACOSH },{ "ASINH", kwASINH },{ "ATANH", kwATANH },{ "ATNH", kwATANH },{ "COSH", kwCOSH },{ "SINH", kwSINH },{ "TANH", kwTANH },{ "EXP", kwEXP },{ "LOG", kwLOG },{ "LOG10", kwLOG10 },{ "SQR", kwSQR },{ "INT", kwINT },{ "CINT", kwCINT },{ "CDBL", kwCDBL },{ "FIX", kwFIX },{ "SGN", kwSGN },{ "ASC", kwASC },{ "VAL", kwVAL },{ "RANDOMIZE", kwRANDOMIZE },{ "ATAN2", kwATAN2 },{ "POW", kwPOW },{ "ROUND", kwROUND },{ "DEG", kwDEG },{ "RAD", kwRAD },{ "LBOUND", kwLBOUND },{ "UBOUND", kwUBOUND },{ "ERASE", kwERASE },{ "CHR", kwCHR },{ "HEX", kwHEX },{ "OCT", kwOCT },{ "LCASE", kwLCASE },{ "UCASE", kwUCASE },{ "LTRIM", kwLTRIM },{ "RTRIM", kwRTRIM },{ "STRING" , kwSTRING },{ "STR" , kwSTR },{ "LEFT", kwLEFT },{ "RIGHT", kwRIGHT },{ "INSTR", kwINSTR },{ "MID", kwMID },{ "SPACE", kwSPACE },{ "TIME", kwTIME },{ "DATE", kwDATE },{ "SPLIT", kwWSPLIT },{ "AT", kwAT },{ "LOCATE", kwLOCATE },{ "TICKSPERSEC", kwTICKSPERSEC },{ "TICKS", kwTICKS },{ "TIMER", kwTIMER },{ "FRE", kwFRE },{ "PSET", kwPSET },{ "LINE", kwLINE },{ "RECT", kwRECT },{ "COLOR", kwCOLOR },{ "FILLED", kwFILLED },{ "CIRCLE", kwCIRCLE },{ "BEEP", kwBEEP },{ "SOUND", kwSOUND },{ "PAUSE", kwPAUSE },{ "INKEY", kwINKEY },{ "TAB", kwTAB },{ "CAT", kwCAT },{ "DELAY", kwDELAY },{ "ARC", kwARC },{ "DRAW", kwDRAW },{ "PLAY", kwPLAY },{ "RUN", kwRUN },{ "TXTW", kwTEXTWIDTH },{ "TXTH", kwTEXTHEIGHT },{ "CHART", kwCHART },{ "MAX", kwMAX },{ "MIN", kwMIN },{ "DRAWPOLY", kwDRAWPOLY },/* file I/O */{ "FREEFILE", kwFREEFILE },{ "OPEN", kwOPEN },{ "OUTPUT", kwOUTPUT }, // OPEN's args{ "APPEND", kwAPPEND }, // OPEN's args{ "AS", kwAS }, // OPEN's args{ "CLOSE", kwCLOSE },{ "LINEINPUT", kwLINEINPUT }, // The QB's keyword is "LINE INPUT"{ "EOF", kwEOF },{ "KILL", kwKILL },{ "EXIST", kwEXIST },{ "SEEK", kwSEEK },{ "LOF", kwLOF },{ "COPY", kwCOPY },{ "RENAME", kwRENAME },//{ "INPUT", kwFINPUT }, // not needed/* DEBUG */{ "TRON", kwTRON },{ "TROFF", kwTROFF },{ "LOGPRINT", kwLOGPRINT },#ifdef BC_DEBUG{ "BCDUMP", kwBCDUMP },{ "STKDUMP", kwSTKDUMP },#endif{ "", 0 }};/** Notes:* block_level = the depth of nested block* block_id = unique number of each block (based on stack use)** Example:* ? xxx ' level 0, id 0* for i=1 to 20 ' level 1, id 1* ? yyy ' level 1, id 1* if a=1 ' level 2, id 2 (our IF uses stack)* ... ' level 2, id 2* else ' level 2, id 2 // not 3* ... ' level 2, id 2* fi ' level 2, id 2* if a=2 ' level 2, id 3* ... ' level 2, id 3* fi ' level 2, id 3* ? zzz ' level 1, id 1* next ' level 1, id 1* ? ooo ' level 0, id 0*/int scan_error;int scan_line; // source line countstatic int block_level; // block level (FOR-NEXT,IF-FI,etc)static int block_id; // unique ID for blocks (FOR-NEXT,IF-FI,etc)static word first_data_ip = 0xFFFF;// ndc: 2001-03-01 static allocation (non tmp_alloc()) does not use the dynamic RAM and reduces the fragmentationstatic char *bc_name;static char *bc_parm;static char *bc_temp;static char *bc_proc;static char bc_sec[33];static int bc_proc_level = 0;static bc_t bc_prog;static bc_t bc_data;#define GROWSIZE 128/** variable node*/struct var_s { char *name; };typedef struct var_s var_t;static var_t *var_table;static word var_count;static word var_size;/** LABELS LIST*/struct label_s {// char *name; char name[33]; word ip; // instruction pointer byte level; // block level (used for GOTOs) word block_id; // block_id (FOR-NEXT,IF-FI,etc) used for GOTOs word dp; // data pointer };typedef struct label_s label_t;//static label_t *lab_table;//static word lab_count;//static word lab_size;static dbt_t lab_table;static word lab_count;/** PROCEDURES/FUNCTIONS LIST*/struct proc_s { char *name; word ip; // instruction pointer word vid; // variable index (for functions) byte level; // block level (used for GOTOs) word block_id; // block_id (FOR-NEXT,IF-FI,etc) used for GOTOs };typedef struct proc_s proc_t;static proc_t *proc_table;static word proc_count;static word proc_size;/** PASS2 - STACK*/struct pass_node_s { char sec[33]; word pos; // instruction position word line; // the source-text line byte level; // block level word block_id; // block ID };typedef struct pass_node_s pass_node_t;static dbt_t bc_stack;static word stk_count;/*** raise a compiler error*/void sc_raise(const char *fmt, ...){ char *buff; va_list ap; va_start(ap, fmt); scan_error = 1; buff = tmp_alloc(TEXT_LINE_SIZE); #if defined(_PalmOS) StrVPrintF(buff, fmt, ap); #else vsprintf(buff, fmt, ap); #endif va_end(ap); dev_printf("\n* ERROR AT %s:%d *\n> %s\n", bc_sec, scan_line, buff); tmp_free(buff);}/**/char* bc_prepname(char *dest, const char *source, int size) SEC(BCSCAN);char* bc_prepname(char *dest, const char *source, int size){ char *p = (char *) source; while ( *p == ' ' ) p ++; strncpy(dest, p, size); dest[size] = '\0'; p = dest; while ( *p && (is_alpha(*p) || is_digit(*p) || *p == '$' || *p == '/') ) p ++; *p = '\0'; str_alltrim(dest); return dest;}/** returns the ID of the label. If there is no one, then it creates one*/int bc_get_label_id(const char *label_name) SEC(BCSCAN);int bc_get_label_id(const char *label_name){ int idx = -1; int i; char name[33]; label_t label; bc_prepname(name, label_name, 32); for ( i = 0; i < lab_count; i ++ ) { dbt_read(lab_table, i, &label, sizeof(label_t)); if ( strcmp(label.name, name) == 0 ) { idx = i; break; } } if ( idx == -1 ) {/* if ( lab_count >= lab_size ) { lab_size += GROWSIZE; lab_table = (label_t *) tmp_realloc(lab_table, lab_size * sizeof(label_t)); } idx = lab_count; lab_count ++; lab_table[idx].name = tmp_alloc(strlen(name)+1); strcpy(lab_table[idx].name, name); lab_table[idx].ip = 0xFFFF; lab_table[idx].dp = 0xFFFF; lab_table[idx].level = block_level; lab_table[idx].block_id = block_id;*/ strcpy(label.name, name); label.ip = 0xFFFF; label.dp = 0xFFFF; label.level = block_level; label.block_id = block_id; dbt_write(lab_table, lab_count, &label, sizeof(label_t)); idx = lab_count; lab_count ++; } return idx;}/** set LABEL's position (IP)*/void bc_set_label_ip(int idx) SEC(BCSCAN);void bc_set_label_ip(int idx){ label_t label; dbt_read(lab_table, idx, &label, sizeof(label_t));/* lab_table[idx].ip = bc_prog.count; lab_table[idx].dp = bc_data.count; lab_table[idx].level = block_level; lab_table[idx].block_id = block_id;*/ label.ip = bc_prog.count; label.dp = bc_data.count; label.level = block_level; label.block_id = block_id; dbt_write(lab_table, idx, &label, sizeof(label_t));}/**/int bc_get_proc_id(const char *proc_name) SEC(BCSCAN);int bc_get_proc_id(const char *proc_name){ int idx = -1; int i; char tmp[33]; char *name = bc_temp; if ( bc_proc_level ) { // search the procedure's table for this LOCAL PROC bc_prepname(tmp, proc_name, 32); strcpy(name, bc_proc); strcat(name, "/"); strcat(name, tmp); for ( i = 0; i < proc_count; i ++ ) { if ( strcmp(proc_table[i].name, name) == 0 ) { idx = i; break; } } } if ( idx == -1 ) { // search the procedure's table for this GLOBAL PROC bc_prepname(name, proc_name, 32); for ( i = 0; i < proc_count; i ++ ) { if ( strcmp(proc_table[i].name, name) == 0 ) { idx = i; break; } } } return idx;}/**/int bc_addproc(const char *proc_name) SEC(BCSCAN);int bc_addproc(const char *proc_name){ char tmp[33]; char *name = bc_temp; int idx = -1, i; // bc_prepname(tmp, proc_name, 32); if ( bc_proc_level ) { strcpy(name, bc_proc); strcat(name, "/"); strcat(name, tmp); } else strcpy(name, tmp); for ( i = 0; i < proc_count; i ++ ) { if ( strcmp(proc_table[i].name, name) == 0 ) { idx = i; break; } } if ( idx == -1 ) { if ( proc_count >= proc_size ) { proc_size += GROWSIZE; proc_table = tmp_realloc(proc_table, proc_size * sizeof(proc_t)); } if ( !is_alpha(proc_name[0]) ) sc_raise("WRONG PROC NAME: %s", proc_name); else { proc_table[proc_count].name = tmp_alloc(strlen(name)+1); proc_table[proc_count].ip = 0xFFFF; //bc_prog.count; proc_table[proc_count].level = block_level; proc_table[proc_count].block_id = block_id; strcpy(proc_table[proc_count].name, name); idx = proc_count; proc_count ++; } } return idx;}int bc_proc_setip(const char *proc_name, word ip) SEC(BCSCAN);int bc_proc_setip(const char *proc_name, word ip){ int idx; idx = bc_get_proc_id(proc_name); if ( idx != -1 ) { proc_table[idx].ip = bc_prog.count; proc_table[idx].level = block_level; proc_table[idx].block_id = block_id; } return idx;}word bc_proc_getip(const char *proc_name) SEC(BCSCAN);word bc_proc_getip(const char *proc_name){ int idx; idx = bc_get_proc_id(proc_name); if ( idx != -1 ) return proc_table[idx].ip; return 0xFFFF;}/**/char *get_param_sect(char *text, const char *delim, char *dest) SEC(BCSCAN);char *get_param_sect(char *text, const char *delim, char *dest){ char *p = (char *) text; char *d = dest; int quotes = 0, level = 0, skip_ch = 0; if ( p == NULL ) { *dest = '\0'; return 0; } while ( is_space(*p) ) p ++; while ( *p ) { if ( quotes ) { if ( *p == '\"' ) quotes = 0; } else { switch ( *p ) { case '\"': quotes = 1; break; case '(': level ++; break; case ')': level --; break; case '\n': case '\r': skip_ch = 1; break; }; } // delim check if ( delim != NULL && level <= 0 && quotes == 0 ) { if ( strchr(delim, *p) != NULL ) break; } // copy if ( !skip_ch ) { *d = *p; d ++; } else skip_ch = 0; p ++; } *d = '\0'; if ( quotes ) sc_raise("MISSING (\")"); if ( level > 0 ) sc_raise("MISSING \')\'"); if ( level < 0 ) sc_raise("MISSING \'(\'"); str_alltrim(dest); return p;}/**/int bc_get_error(void) SEC(BCSCAN);int bc_get_error(){ return scan_error;}/** checking for missing labels*/void bc_check_labels(void) SEC(BCSCAN);void bc_check_labels(){ int i; label_t label; for ( i = 0; i < lab_count; i ++ ) { dbt_read(lab_table, i, &label, sizeof(label_t)); if ( label.ip == 0xFFFF ) { sc_raise("LABEL NOT DEFINED: %s", label.name); break; } }}/** returns the id of the variable 'name'*/int bc_get_var_id(const char *var_name) SEC(BCSCAN);int bc_get_var_id(const char *var_name){ int idx = -1; int i; char tmp[33]; char *name = bc_temp; if ( bc_proc_level ) { // search local name-space bc_prepname(tmp, var_name, 32); #if defined(_PalmOS) StrPrintF(name, "%s/%s", bc_proc, tmp); #else sprintf(name, "%s/%s", bc_proc, tmp); #endif for ( i = 0; i < var_count; i ++ ) { if ( strcmp(var_table[i].name, name) == 0 ) { idx = i; break; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -