diff --git a/libtry/.gitignore b/libtry/.gitignore new file mode 100644 index 0000000..f152158 --- /dev/null +++ b/libtry/.gitignore @@ -0,0 +1,69 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Linker files +*.ilk + +# Debugger Files +*.pdb + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll +*.so.* + + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Build directories +build/ +Build/ +build-*/ + +# CMake generated files +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +#Makefile +install_manifest.txt +compile_commands.json + +# Temporary files +*.tmp +*.log +*.bak +*.swp + +# vcpkg +vcpkg_installed/ + +# debug information files +*.dwo + +# test output & cache +Testing/ +.cache/ diff --git a/libtry/t.try b/libtry/t.try new file mode 100644 index 0000000..4125279 --- /dev/null +++ b/libtry/t.try @@ -0,0 +1,27 @@ +# Fibonacci sequence +func fun{ + if(x <= 2){ + return(1); + } + y = 0; + x = x - 1; + y = fun(x); + x = x - 1; + return(y + fun(x)); +}; + +# save the Fibonacci sequence of 1 to 15 in an array +array arr(15); +x = 0; +while(x<15){ + arr[x] = fun(x) + 1000; + x = x + 1; +} + +puts("Fibonacci sequence:"); +# print the Fibonacci sequence of 1 to 15 +i = 0; +while(i < 15){ + print(arr[i]); + i=i+1; +} diff --git a/libtry/test/t_assign_basic.try b/libtry/test/t_assign_basic.try new file mode 100644 index 0000000..acf209a --- /dev/null +++ b/libtry/test/t_assign_basic.try @@ -0,0 +1,5 @@ +a = 5; +b = "ok"; + +print(5); +puts(b); diff --git a/libtry/test/t_function_basic.try b/libtry/test/t_function_basic.try new file mode 100644 index 0000000..0a21c21 --- /dev/null +++ b/libtry/test/t_function_basic.try @@ -0,0 +1,6 @@ +func f_test{ + return(0); +}; + +r = f_test(); +print(r); diff --git a/libtry/test/t_output_basic.try b/libtry/test/t_output_basic.try new file mode 100644 index 0000000..bcdc20b --- /dev/null +++ b/libtry/test/t_output_basic.try @@ -0,0 +1,2 @@ +print(1); +puts("1") diff --git a/libtry/try.c b/libtry/try.c new file mode 100644 index 0000000..17d910d --- /dev/null +++ b/libtry/try.c @@ -0,0 +1,741 @@ +/* 魔改自github tryC项目。手写简易的解释器,我们 + * 将用它来作为操作界面的shell。 + * + * 也许我们可以增加一些字符串赋值、拼接的能力 + * 同时未来也需要加入系统调用的能力 + * + * + * 20250827(qing): 增加了宽字符支持。 + * 20250827(qing): 修复了Str漏匹配的BUG + * 20250827(qing): 该脚本在操作不当的情况下可能会发生内存泄漏 + * 20250827(qing): 使用longjmp()代替exit() + */ + +#include +#include +#include +#include +#include +#include "console.h" +#define POOLSIZE (1 * 128) /* 任意大小 */ +#define SYMTABSIZE (1 * 128) /* !符号表栈的大小 */ +#define MAXNAMESIZE 16 /* 变量/函数名称的长度 */ +#define RETURNFLAG DBL_MAX /* 表明函数中已经出现return语句 */ + + +typedef struct symStruct { /* 该结构体表示存储在符号表中的一个符号 */ + int type; /* 符号的类型:Num, Char, Str, Array, Func */ + wchar_t name[MAXNAMESIZE]; /* 记录符号名称 */ + double value; /* 记录符号的值,或者字符串或数组的长度 */ + union { + wchar_t *funcp; /* 指向一个数组或者一个函数 */ + struct symStruct* list; + } pointer; + int levelNum; /* 表明声明的嵌套层级 */ +} symbol; +static symbol symtab[SYMTABSIZE]; +static int symPointer = 0; /* 符号表栈指针 */ +static int currentlevel = 0; /* 当前嵌套层级 */ + +static wchar_t *src, *old_src; /* 当前正处理的文本 */ +static wchar_t *p_src; /* 用于定位释放点 */ +static int top_src = 0; + + +enum { /* 解释器状态枚举 (使用int直接接受匿名枚举) */ + debug, run +}; +static int compileState = run; /* 当前解释器状态 */ + +static double return_val = 0; /* 用于保存函数的返回值 */ + + +enum { /* 标记和类别(运算符放最后并按优先级排序) */ + Num = 128, Char, Str, Array, Func, + Else, If, Return, While, Print, Puts, Read, + Assign, OR, AND, Equal, Sym, FuncSym, ArraySym, Void, + Nequal, LessEqual, GreatEqual +}; +static int token; /* 当前标记类型 */ +union tokenValue { + symbol *ptr; /* 在返回字符串或符号地址用于赋值时使用 */ + double val; /* 用于字符或数字时标记值 */ +} ; + +static union tokenValue token_val; + +/*--------------- 函数声明 ---------------*/ +static double function(); +static double statement(); +static int boolOR(); /* 用于辅助IF和WHILE词元 */ +static int boolAND(); +static int boolexp(); +static double expression(); +static double factor(); +static double term(); +static void match(int tk); +static void next(); +///// +static void clear(int level); +static void clearThis(); /* 20260707(qing): 增加一个clearThis()函数,用于释放变量 */ +static void __exit(); +/* ------------------- 词法分析 -------------------*/ + +/* 输入字符串的下一个标记 */ +static void next() { + wchar_t *last_pos; + while(token = *src) { /* 逐字扫描 */ + ++src; + if (token == L'\n') { /* 记录新行的起点 */ + //if (compileState == debug) + // wprintf(L"%.*ls", (int)(src-old_src), old_src); + old_src = src; + } + else if (token == L'#') { /* 跳过注释 */ + while(*src != 0 && *src != L'\n') { + src++; + } + } + /* ---- 检查到标识符 ---- */ + else if ((token >= L'a' && token <= L'z') || (token >= L'A' && token <= L'Z') || (token == L'_') || (token > 0x7F)) { + last_pos = src -1; /* 程序标识符 */ + wchar_t nameBuffer[MAXNAMESIZE]; + nameBuffer[0] = token; /* 扫描标识符 */ + while ((*src >= L'a' && *src <= L'z') || (*src >= L'A' && *src <= L'Z') || (*src >= L'0' && *src <= L'9') || (*src == L'_') || (*src > 0x7f)) { + nameBuffer[src-last_pos] = *src; + src++; + } + nameBuffer[src-last_pos] = 0; /* 获取标识符名 */ + int i; + for (i=symPointer-1; i>=0; --i) { /* 在符号表中搜索符号 */ + if (wcscmp(nameBuffer, symtab[i].name) == 0) { /* 如果找到符号:根据符号类型返回标记 */ + + if (symtab[i].type == Num || symtab[i].type == Char) { + token_val.ptr = &symtab[i]; + token = Sym; + } + else if (symtab[i].type == Str) { /* 20250827(qing): 新增此分支,修复BUG */ + token = Str; + token_val.ptr = (symbol *)symtab[i].pointer.funcp; + } + else if (symtab[i].type == FuncSym) { + token_val.ptr = &symtab[i]; + token = symtab[i].type; + } + else if (symtab[i].type == ArraySym) { + token_val.ptr = &symtab[i]; + token = symtab[i].type; + } + else { + if (symtab[i].type == Void) { + token = Sym; + token_val.ptr = &symtab[i]; + } + else { // ??? + token = symtab[i].type; + token_val.ptr = NULL; /* 以防万一,为当前记号存储器赋个值! + * 因为Array记号可能到这里来,它会在检查失败后检查释放 */ + } + } + + return; + } + } + wcscpy(symtab[symPointer].name, nameBuffer); /* 如果标记未被发现,创建一个新的 */ + symtab[symPointer].levelNum = currentlevel; + symtab[symPointer].type = Void; + token_val.ptr = &symtab[symPointer]; + symPointer++; + token = Sym; + return; + } + else if (token >= L'0' && token <= L'9') { + token_val.val = (double)token - L'0'; + while (*src >= L'0' && *src <= L'9') { + token_val.val = token_val.val * 10.0 + *src++ - L'0'; + } + if (*src == L'.') { + src++; + int countDig = 1; + while (*src >= L'0' && *src <= L'9') { + token_val.val = token_val.val + ((double)(*src++) - L'0') / (10.0 * countDig++); + } + } + token = Num; + return; + } + + /* 字符 */ + else if (token == L'\'') { + token_val.val = *src++; + token = Char; + src++; + return; + } + + /* 字符串 */ + else if (token == L'"') { + last_pos = src; + int numCount = 0; + while (*src != 0 && *src != token) { + src ++; + numCount ++; + } + if (*src) { /* TODO: 解析出字符串就会创建动态内存,那么可能会有风险! */ + *src = 0; + token_val.ptr = malloc(sizeof(wchar_t) * (numCount + 1)); + *(wchar_t*)token_val.ptr = L'0'; + wcscpy((wchar_t*)token_val.ptr, last_pos); + *src = token; + src++; + } + token = Str; + return; + } + + /* == 和 = */ + else if (token == L'=') { + if (*src == L'=') { + src++; + token = Equal; + } + else {token = Assign;} + return; + } + + /* != */ + else if (token == L'!') { + if (*src == L'=') { + src++; + token = Nequal; + } + return; + } + + /* <= 或 < */ + else if (token == L'<') { + if (*src == L'=') { + src ++; + token = LessEqual; + } + return; + } + + /* >= 或 > */ + else if (token == L'>') { + if (*src == L'=') { + src++; + token = GreatEqual; + } + return; + } + + /* || */ + else if (token == L'|') { + if (*src == L'|') { + src++; + token = OR; + } + return; + } + + + /* && */ + else if (token == L'&') { + if ( *src == L'&') { + src++; + token=AND; + } + return; + } + + /* 保持以在别处解析 */ + else if ( token == L'*' || token == L'/' || token == L';' || token == L',' || token == L'+' || token == L'-' || + token == L'(' || token == L')' || token == L'{' || token == L'}' || token == L'[' || token == L']') { + return; + } + + /* 空格、制表符 */ + else if (token == L' ' || token == L'\t') { } + + /* 不认识 */ + else { + //wprintf(L"unexpected token: %d\n", token); + printtovga(L"unexpected token\n"); + } + } +} + +static void clear(int level) { + for (int i=symPointer-1; i>=0; i--) { + token_val.ptr = &symtab[i]; + if ( token_val.ptr->levelNum >= level ) { + clearThis(); + } + else { break; } + } +} + +/* 20250827(QING): 在这里检测pointer联合字段是否为空,不为空就表明有值先释放 */ +static void clearThis() { + //printf("Clear a Symbol: %s\n", token_val.ptr->name); + if (token_val.ptr->type == Str && token_val.ptr->pointer.funcp) + free(token_val.ptr->pointer.funcp); + else if (token_val.ptr->type == ArraySym && token_val.ptr->pointer.list) + free(token_val.ptr->pointer.list); +} + +/* 检查是否匹配 */ +static void match(int tk) { + if (token == tk) { + if (compileState==debug) { + if (iswprint(tk)) { /* 该字符是否能够打印 */ + //wprintf(L"match: %lc\n", tk); + } + else { + //wprintf(L"match: %d\n", tk); + ; + } + } + next(); /* 检查下一个标记 */ + } + else { /* 直接让程序死亡,在单片机上似乎不妥 */ + //wprintf(L"line %.*ls:expected token: %d\n", (int)(src - old_src), old_src, tk); + printtovga(L"unexpected token\n"); + __exit(-1); + //clearThis(); + } +} + +/*-------------------------- 语法分析与执行 --------------------------*/ +static double term() { + double temp = factor(); + while (token == L'*' || token == L'/') { + if (token == L'*') { + match(L'*'); + temp *= factor(); + } + else { + match(L'/'); + temp /= factor(); + } + } + return temp; +} + +static double factor() { + double temp = 0; + if (token == L'(') { + match(L'('); + temp = expression(); + match(L')'); + } + else if (token == Num || token == Char) { + temp = token_val.val; + match(token); + } + else if (token == Sym) { + temp = token_val.ptr->value; + match(Sym); + } + else if (token == ArraySym) { + symbol *ptr = token_val.ptr; + match(ArraySym); + match(L'['); + int index = (int)expression(); + if (index >= 0 && index < ptr->value) { + temp = ptr->pointer.list[index].value; + } + match(L']'); + } + else if (token == FuncSym) { /* 处理函数调用 */ + temp = function(); + } + else { + //printf("Unknow token: %d.\n", token); + printtovga(L"Unknow token\n"); + } + return temp; +} + +/* 加减法表达式 */ +static double expression() { + double temp = term(); + while (token == L'+' || token == L'-') { + if (token == L'+') { + match(L'+'); + temp += term(); + } + else { + match(L'-'); + temp -= term(); + } + } + return temp; +} + + +static int boolexp() { + if (token == L'(') { + match(L'('); + int result = boolOR(); + match(L')'); + return result; + } + else if (token == L'!') { + match(L'!'); + return boolexp(); + } + double temp = expression(); + if (token == L'>') { + match(L'>'); + return temp > expression(); + } + else if (token == L'<') { + match(L'<'); + return temp < expression(); + } + else if (token == GreatEqual) { + match(GreatEqual); + return temp >= expression(); + } + else if (token == LessEqual) { + match(LessEqual); + return temp <= expression(); + } + else if (token == Equal) { + match(Equal); + return temp == expression(); + } + return 0; +} + +static void skipBoolExpr() { + int count = 0; + while (token && !(token == L')' && count == 0)) { + if (token == L'(') count++; + if (token == L')') count--; + token = *src++; + } +} + + +static int boolAND() { + int val = boolexp(); + while (token == AND) { + match(AND); + if (val == 0){ + skipBoolExpr(); + return 0; // short cut + } + val = val & boolexp(); + if (val == 0) return 0; + } + return val; +} + + +static int boolOR() { + int val = boolAND(); + while (token == OR) { + match(OR); + if (val == 1){ + skipBoolExpr(); + return 1; // short cut + } + val = val | boolAND(); + if (val == 1) return 1; + } + return val; +} + + +static void skipStatments() { + if(token == L'{') + token = *src++; + int count = 0; + while (token && !(token == L'}' && count == 0)) { + if (token == L'}') count++; + if (token == L'{') count--; + token = *src++; + } + match(L'}'); +} + +/* 解析一个句子 */ +static double statement() { + if (token == L'{') { + match(L'{'); + while (token != L'}') { + if (RETURNFLAG == statement()) + return RETURNFLAG; + } + match(L'}'); + } + else if (token == If) { + match(If); + match(L'('); + int boolresult = boolOR(); + match(L')'); + if (boolresult) { + if (RETURNFLAG == statement()) + return RETURNFLAG; + } + else skipStatments(); + if (token == Else) { + match(Else); + if (!boolresult) { + if (RETURNFLAG == statement()) + return RETURNFLAG; + } + else skipStatments(); + } + } + else if (token == While) { + match(While); + wchar_t* whileStartPos = src; + wchar_t* whileStartOldPos = old_src; + int boolresult; + do { + src = whileStartPos; + old_src = whileStartOldPos; + token = L'('; /* 不加行会报错 */ + match(L'('); + boolresult = boolOR(); + match(L')'); + if (boolresult) { + if (RETURNFLAG == statement()) + return RETURNFLAG; + } + else skipStatments(); + }while (boolresult); + } + + + /* ---- 给变量赋值 ---- */ + else if (token == Sym || token == ArraySym) { + symbol* s = token_val.ptr; + //clearThis(); /* 不知为何需要注释了才能跑 */ + int tktype = token; + int index; + match(tktype); + if (tktype == ArraySym) { + match(L'['); + index = expression(); + match(L']'); + match(Assign); + if (index >= 0 && index < s->value) { + s->pointer.list[index].value = expression(); + } + /* TODO: 越界异常 */ + } + else { + match(Assign); + if (token == Str) { + s->pointer.funcp = (wchar_t*)token_val.ptr; + s->type = Str; + match(Str); + } + else if (token == Char) { + s->value = token_val.val; + s->type = Char; + match(Char); + } + else { + s->value = expression(); + s->type = Num; + } + } + match(L';'); + } + else if (token == Array) { + match(Array); + symbol* s = token_val.ptr; + //clearThis(); + match(Sym); + match(L'('); + int length = (int)expression(); + match(L')'); + s->pointer.list = malloc(sizeof(struct symStruct) * length + 1); + for (int i = 0; i < length; ++i) + s->pointer.list[i].type = Num; + s->value = length; + s->type = ArraySym; + match(L';'); + } + else if (token == Func) { + match(Func); + symbol* s = token_val.ptr; + //clearThis(); + s->type = FuncSym; + match(Sym); + s->pointer.funcp = src; + s->value = token; + skipStatments(); + match(L';'); + } + else if (token == Return) { + match(Return); + match(L'('); + return_val = expression(); + match(L')'); + match(L';'); + return RETURNFLAG; + } + else if (token == Print || token == Read || token == Puts) { + int func = token; + double temp; + match(func); + match(L'('); + switch (func) { + case Print: + temp = expression(); + wchar_t buf[16]; + swprintf(buf, 16, L"%lf\n", temp); + printtovga(buf); + break; + case Puts: + /* 这一句切换不过来 */ + //wprintf(L"%ls\n", (wchar_t*)token_val.ptr); + printtovga((wchar_t*)token_val.ptr); + match(Str); + break; + case Read: /* 单片机上等下支持 */ + //wscanf(L"%lf", &token_val.ptr->value); + token_val.ptr->value = -1; + token_val.ptr->type = Num; + match(Sym); + } + match(L')'); + match(L';'); + } + return 0; +} + + +static double function() { + currentlevel++; + return_val = 0; + + symbol* s = token_val.ptr; + match(FuncSym); + match(L'('); + while (token != L')') { + symtab[symPointer] = *token_val.ptr; + wcscpy(symtab[symPointer].name, token_val.ptr->name); + symtab[symPointer].levelNum = currentlevel; + symPointer++; + match(Sym); + if (token == L',') + match(L','); + } + match(L')'); + wchar_t* startPos = src; + wchar_t* startOldPos = old_src; + int startToken = token; + old_src = src = s->pointer.funcp; + token = (int)s->value; + statement(); + src = startPos; + old_src = startOldPos; + token = startToken; + + while (symtab[symPointer - 1].levelNum == currentlevel) { + symPointer--; + } + currentlevel--; + return return_val; +} +/*----------------------------------------------------------------*/ +int init_tryc() { + + /* 将所有字段赋值为0 */ + memset(symtab, 0, sizeof(symtab)); + + int i; /* 用于阅读定位 */ + src = L"array func else if return while print puts read"; + for (i = Array; i <= Read; ++i) { + next(); + symtab[symPointer -1].type = i; + } + + if (!(src = old_src = p_src = (wchar_t*)malloc(POOLSIZE))) { + //wprintf(L"could not malloc(%d) for source area\n", POOLSIZE); + printtovga(L"could not malloc for source aream\n"); + return -1; + } + + top_src = 0; + src[0] = L'\0'; // add EOF character +} + +void free_tryc() { + + free(p_src); +} + +int enqueue_tryc(wchar_t wc) { + + if (top_src >= POOLSIZE - 1) { + return -1; + } + src[top_src] = wc; + src[++top_src] = L'\0'; + return 0; +} + +void eval_tryc() { + + if (*src == L'\0') return; + + next(); + while (token != L'\0') { + statement(); + } + src = p_src; + + top_src = 0; + src[0]= L'\0'; + +} + +void __exit() { + while (1); +} + +#ifdef _DEBUG +#include "fcntl.h" +#include "unistd.h" +#include "locale.h" +int main(int argc, char **argv) +{ + + init_tryc(); + + + int i; + setlocale(LC_ALL, ""); + wchar_t wc; + i = 0; + FILE *file = fopen(argv[1], "r"); + if (!file) { + perror("fopen"); + return 1; + } + + while ((wc = fgetwc(file)) != WEOF) { + src[i++] = wc; + } + + + src[i] = L'\0'; // add EOF character + fclose(file); + + eval_tryc(); + + clear(0); + free_tryc(); + + return 0; +} +#endif