当我创建这个项目的时候,绝对想不到过了两年还没有出正式版...
无聊的国庆
因为很多原因,我国庆的时候基本上是没出过学校的。整天就是在学校里头遛弯啊什么的。实在是太无聊了。为数不多的几次,要么是去取快递,要么是去学校外面和社团的人一起吃饭。
实在无聊啊!
于是我便看了看我还有什么项目没有完工。我看了看Gitee,翻了翻我的个人项目,发现了尘封两年的一个项目——
Old8Lang
Old8Lang是个什么东西
Old8Lang,这是一个类似于Js和Python的语言。你也可以说是一个超级缝合怪——函数类型使用的是大驼峰(例如Print Line , 使用大驼峰的话就是PrintLine,而小驼峰的话就是printLine),而在函数上面则原生支持函数变量,或者说函数本身就是一种数据类型。在类方面我们不支持那些比较复杂的oop操作——例如泛型、继承、多态等等等等。同样也没有C#里头的什么接口,抽象类什么的。对于类来说支持力度并不是很大,或者说只保留最简单的那一部分,就是围绕着存数据这种来的。
现在来看看Old8Lang的语言风格吧:
PrintLine("测试Json")
test <- Test(2,3)
PrintLine(Json(test))
a <- ToObj("{\"a\" : 1,\"b\" : {\"c\" : 3}}")
PrintLine(a.a)
class Test{
a <- 1
b <- 2
func init(c,d)
{
a <- c
b <- d
}
func Add()
return a+b
}
PrintLine("测试类型转换")
a <- {"a":1,"b":3}
a <- a as Test
PrintLine(a.Add())
是的,这个语言的赋值语句是使用箭头来表示的。因为总有新手会把=和==给搞混。有的时候bug就是在这些'小小的细节'中被搞出来的。
那么这个语言,他为什么要被开发出来呢?是为了解决什么特定的场景吗?
故事的开始
怎么说呢?要回答这个问题其实也很简单。各位可以移步到Old8Lang的项目页,然后翻到最下面。
是的,真就是看到别人做了一个,然后我就想着做了。
不过有些小细节吧,首先这个视频我高二的时候就看到了,当时就想写了。但是后面嘛,高三嘛,就没这个想法了。直到后面大学了,加入了iOS Club之后,也就是跟社团的一些人(比如说云妈)聊着天聊着天,突然就想试一下了。
所以真的就是玩吧,或者说就是看到别人搞了一个,觉得很酷很好玩,就自己也试试了。
这里也贴出来我的学习资料吧:
-
视频:B站上面的,用C#写一个脚本语言 www.bilibili.com/video/BV15v…
-
书籍:《两周自制脚本语言》
后来我买了书,然后就12月了。当时我们是12月初就“放假”了——准确来说是让我们回家,然后上网课这种。
然后我当时在家进行的开发。依稀记得当时我用的还是Arch Linux(这个我单开一个文章讲讲)。就上完课之后就开始设计Old8Lang。
当时是想写一个类似于Python的语言,当时感觉Python这种语言方便大家去学嘛,这样的话大家用Old8Lang也没什么学习路径什么的。
不过接下来就犯难了,该怎么去把那些文本解析好呢?
非常艰难的开局
如果对解释器这里比较熟悉的,应该知道一个解释器大概分为 词法分析、语义分析、AST解析和内存管理机制。最难的其实是这里头的语义分析。我来给各位讲讲这些都是干什么的就知道为什么了。
-
词法分析
词法分析就是把词这些换成Token。这里说实在的有点抽象了。我举个例子吧:
就例如这段话:
a = 1。这里就可以解析成:标识(a) 赋值(=) 整数(1) -
语义分析
语义解析就是将词法解析的东西进行结合,然后生成抽象语法树(AST)。就比如说拿刚才的赋值语句吧,那一整个最后就会被解析成对应的AST类。
-
AST解析
这个就是把从语义解析的东西给逐个运行一下。就比如说前面的赋值语句,就是把一个值存到内存管理类中,然后用变量名来指向他。
所以各位也都看出来了,最难的部分其实是语义分析这里。因为我们要把那些符号什么的都给和到一块儿去。
这里也是我最头疼的,然后,救星出现了。
C#居然还有这种框架
是的,其实到现在我还没有实现完全的解释器,因为我使用到了一个框架——csly。
这个项目可以帮助你完成词法和语义解析,这样的话就可以帮你少写很多的代码。
你只需要提供一个token枚举,一堆ebnf语句还有规定还怎么生成AST就可以了。
非常简单对吧,我也这么觉得。
不过还是要惊叹一句,C#居然有这种框架?!
于是我便写了一堆的ebnf语句,期间也踩了很多的坑,也提了很多的issue。不过这里真的要感谢作者,他真的很敬业,或者说很爱这个框架。我发issue他基本上是秒回。要知道,他在美国。
这里也正好科普一下ebnf语句吧
ebnf语句,其实就是用来描述一个编程语言的语法的东西。
就比如说前面的赋值语句,Old8Lang的ebnf语句是
set: IDENTIFIER SET[d] expressions翻译过来就是 标识符 赋值符号(=,->) 各种值(表达式)
轻舟已过万重山,还有一重又一重
是的,虽然csly已经帮了我很多了,但是对于AST解析和内存管理机制,对于当时的我来说还是很难的——一个高三一整年没有碰过一点点电脑的人。真的感觉有很多关于C#的细节都忘了。而且我感觉有很多地方都没有学过的样子......
比如对于抽象类和接口,他们的使用场景有什么区别。其实对于我现在来说,我也能答点了,也体会到很多了。不过对于当时的我来说,真的不知道。只知道有这么个东西。甚至很长一段时间,基础类这些全用的接口——无他,因为我不知道抽象类该怎么用。
还有关于内存管理机制这些。当时对类这一块儿的了解程度真的非常的不熟,有一次有个bug我搞了一天,最后问云妈,他两下子就告诉我该怎么办了。只能说真的得需要大佬帮忙呀。
而且其实这个的工作量我自认为是比较大的。就这个项目目前而言,AST的树干,OldTree这个类一共派生了43个类,其中语句模块是20个,值相关的是23个。而且很多类是写了很多很多行代码的。真的需要考虑的情况太多了。
所以那个时候我真的感觉自己每天是在写Bug,也算是一种自嘲吧。正好讲个小插曲:
我当时其实是很开心的,就是自己写的终于有个雏形了。但是一测试发现这个不行,那个出bug。当时真的人都麻了。当时正好是跨年,就很麻。我就在我房间里头,一个人和代码一起跨了年。当时是真的希望明年别这样了。然后23年12月31日,是的,当天晚上我还在提交代码。
最后我整个寒假,包括后面回了湖南老家也是,一个人闷在房间里头,然后一直写代码。最后才完成到0.3版本。
还是搞点别的吧
写这个项目,包括Json解析器和Old8Down(我写的一个Markdown解析器,不过是拿正则表达式写的),真的有点写累了。
于是后面3月份我就开始学习写GUI,包括后面6月份开始写网站什么的。当时自己还写了很多的小项目,还有社团的官网。我当时也是第一次学会搞服务器,搞docker,搞交互什么的。不得不说,这些经历也同样锻炼人。但是是的,这些东西我也写烂了。
这也是收回这篇文章的开头了。因为很多原因,我国庆节基本上是在寝室度过的(主要是因为自己懒)。于是我想着完善一下Old8Lang吧。
是的,真就是因为无聊。
重新看这个项目,发现...
于是我又开始写起了Old8Lang。有很多时候我感觉真的...有一种割裂感。
就是感觉自己以前代码怎么能这样?null满天飞。你都不知道你会传入什么样的东西。而且还有一些bug...
改呗。
不过好在我bug不是很多,写的其实也能看的下去。很快就改完了。
不过不得不说,别人总是能给我点灵感。就在国庆的时候,我和我室友的中学同学吧,现在在西邮。我跟他聊天的时候,突然给了我灵感——对于oop这一块,也不用太学C#什么的,反而别最后类型体操了。
于是我连夜支持了Json互操作和类型转换。这样的话对于类型这里就可以更简单的使用了。也就是现在,Old8Lang 0.8版本终于发布了。我打算最后把词法和语义给写了,再看看能不能优化一下代码,就正式发布1.0版本吧。
我还写了点注释什么的,各位要是感兴趣也可以一起来写。放心,现在的代码没那么烂了。
最后,写点感谢的话吧
不得不说,Old8Lang这个项目确实是伴随着我大学这两年的,也是我搞过的最久的项目。这个项目也是见证了我不断的成长。从一个项目菜鸟变成了会点东西的菜鸟。
这里真的很感谢iOS Club,云妈和csly的开发者吧。iOS Club给了我一个平台,或者说成了我代码学习成长的平台,应该可以这么说吧。而云妈等一众大佬也一直在帮助我成长,帮助我解决了很多的问题。csly也是让我体会到了开源的力量。
真的,由衷感谢!