前言说程序员的三大浪漫是:操作系统、编译原理、图形;最后一个图形确实是一个特定的专业领域,我们几乎接触不到。所以还是比较适合我转网络,最后加个数据库。如果这四项技术都能掌握,那岂不是说明IT行业已经横着走了?另外,互联网行业这几年越来越不景气,技术越低,被替代的可能性就越小;所以为了给自己30+的危机挽救一些后路,从今年上半年开始,我就逐渐开始从零开始学习编译原理。功夫不负有心人。经过将近一个月的熬夜,我每晚都是在妻子的催促下才休息的。中间几次克服了放弃的冲动,终于完成了一个GScript的预览版。预览版意味着语法结构和整体设计基本完成,后续更新不会改变这部分内容,但还是缺少一些简单易用的功能。Features先来看看保留链接,GScript是怎么写helloworld的。hello_world.gs:println("helloworld");?gscripthello_world.gshelloworld废话少说,下面重点说说GScript支持的特性。每个功能将在以下部分中突出显示。除了刚刚提到的helloworld作为例子,我们再来看一个经常被示例代码演示的打印斐波那契数列。voidfib(){inta=0;整数b=1;int斐波那契数列(){intc=a;一=b;b=a+c;返回c;}returnfibonacci;}funcint()f=fib();for(inti=0;i<5;i++){println(f());}输出结果如下:01123整体写法为与Go官方推荐的类似:https://go.dev/play/p/NeGuDahW2yP//fib返回一个函数,该函数返回//连续的斐波那契数.funcfib()func()int{a,b:=0,1returnfunc()int{a,b=b,a+breturna}}funcmain(){f:=fib()//函数调用从左到右求值。fmt.Println(f(),f(),f(),f(),f())}都是通过闭包变量实现的,也演示了GScript中闭包和函数的使用。后面会详细介绍闭包的用法。语法GScript的语法类似于普通的Java/Go,因此非常容易上手。基本类型我们先来看看基本类型。目前支持int/string/float/bool四种基本类型和nil特殊类型。变量声明语法类似于Java:inta=10;stringb,c;floate=10.1;boolf=false;个人觉得类型放在前面代码会更清晰,当然这也是个人喜好。Array//声明并初始化int[]a={1,2,3};println(a);//声明一个空数组并指定大小int[]table=[4]{};println();//向数组追加数据a=append(a,4);println(a);for(inti=0;i1][1001]Class类的支持很重要,它是实现面向对象的基础。目前还没有完全实现面向对象,只实现了数据和功能的封装。类ListNode{int值;接下来是ListNode;ListNode(intv,ListNoden){值=v;下一个=n;}}//调用构造函数时不需要使用new关键字。ListNodel1=ListNode(1,nil);//使用.调用对象属性或函数。println(l1.value);默认情况下,类具有无参数构造函数:classPerson{intage=10;字符串名称=“abc”;intgetAge(){返回100+年龄;}}//无参构造FunctionPersonxx=Person();println(xx.age);assertEqual(xx.age,10);println(xx.getAge());assertEqual(xx.getAge(),110);得益于class的实现,结合刚才的数组,还可以定义一个自定义类型的数组://Personarraywithasizeof16Person[]personList=[16]{};函数其实分为两类:普通的全局函数。类函数。本质上没有区别,只是范围不同而已。//判断链表是否有环boolhasCycle(ListNodehead){if(head==nil){returnfalse;}if(head.next==nil){返回false;}ListNodefast=head.next;ListNodeslow=head;布尔ret=假;对于(fast.next!=nil){如果(fast.next==nil){返回false;}if(fast.next.next==nil){返回false;}if(slow.next==nil){返回false;}如果(快==慢){ret=true;返回真;}fast=fast.next.next;慢=慢.next;}returnret;}ListNodel1=ListNode(1,nil);boolb1=hasCycle(l1);println(b1);assertEqual(b1,false);ListNodel4=ListNode(4,nil);ListNodel3=ListNode(3,l4);ListNodel2=ListNode(2,l3);boolb2=hasCycle(l2);println(b2);assertEqual(b2,false);l4.next=l2;boolb3=hasCycle(l2);println(b3);assertEqual(b3,true);这里有一个链表是否有环的函数,只要有使用其他语言的基础,相信读起来是没有问题的。add(inta){}当函数没有返回值时,可以声明为void或者直接忽略返回类型。Closure闭包我觉得是一个很有意思的特性,可以实现非常灵活的设计,也是函数式编程的基础。所以函数在GScript中作为一等公民存在;因此,GScript也支持函数类型的变量。函数变量声明语法如下:functypeTypeOrVoid'('typeList?')'//外部变量,全局共享。intvarExternal=10;funcint(int)f1(){//闭包变量对每个闭包单独可见intvarInner=20;intinnerFun(inta){println(a);intc=100;变量外部++;变量内部++;返回varInner;}//returnfunctionreturninnerFun;}//f2为函数类型,接收一个返回值和参数均为int的函数。funcint(int)f2=f1();for(inti=0;i<2;i++){println("varInner="+f2(i)+",varExternal="+varExternal);}println("=======");funcint(int)f3=f1();for(inti=0;i<2;i++){println("varInner="+f3(i)+",varExternal="+varExternal);}最后输出如下:0varInner=21,varExternal=111varInner=22,varExternal=12=======0varInner=21,varExternal=131varInner=22,varExternal=14funcint(int)f2=f1();以这段代码为例:f2为返回值,入参均为int函数类型;所以后续可以直接作为函数调用f2(i)。例子中,闭包分别赋值给了f2和f3变量,这两个变量中的闭包数据也相互隔离,互不影响。都是基于这个特点,甚至是面向对象的。标准库标准库源码:https://github.com/crossoverJie/gscript/tree/main/internal目前实现的标准库不多,完全是手工活;基于现有语法和基本数据类型,几乎可以实现大部分数据结构,所以也欢迎有兴趣的朋友贡献标准库代码;比如Stack、Set等数据结构。MapString以这个MapString为例:一个键值对为字符串的HashMap。intcount=100;MapStringm1=MapString();for(inti=0;i