如何设计脚本语言 实现自己的脚本语言(一)
程序员对编程语言的实现的好奇,大概就类似于人类对自己起源吧,从一段文本,变成可执行的代码,计算出结果,这整个过程确实是相当神奇,这几个步骤的实现过程别样吸引人。
大学时,半路决定出家当程序员去(单身到现在,确实是出家呀),自己一个人胡乱摸索,没人指路,心又静不下来,于是乎成功避开了所有编程基本功的训练。当时对编译原理一窍不通,还连找本书来稍微了解一下的意愿都没有。
出来工作后,有次想找一个Vim的插件,做括号匹配。偶然在StackOverflow上看到一个人说到正则文法是无法做到括号匹配判定的,当时没太懂,也就没有多去了解了。
后来某个孤独的夜晚,突然想,我是不是该学点什么呢?可是也不知道学什么好,“正则文法无法做到括号匹配判定”这个说法一直以来萦绕心头,中央决定,就是你了。
当时因为编程能力实在太差,收入也低,前途极其暗淡(现在收入也低,前途也很暗淡),那种迷茫的恐惧,驱使着自己前行。然后就从正则文法了解起,了解到有形式语言这个方向的研究,上下文相关文法,上下文无关文法。由于内容相当复杂,所以买了几本书,找了一些中英文的视频教程来看。糊里糊涂,一知半解,终于知道根据泵引理可以证明正则文法无法做括号匹配的判定。
后来就在想,能否自己实现正则表达式呢?搞着搞着,看到网上的教程,都是C语言配Lex和Yacc工具的,顿时没了兴趣。在很长的一段时间里,我都偏执得拒绝学习Lex和Yacc工具,总觉得不是自己实现的语法解析,没有什么意义,或者说没有什么成就感。
后来还强行去看了Go语言的正则表达式实现代码,不知道那些代码是不是机器生成的,感觉好难懂了,于是乎第一阶段的编译原理学习告一段落。
从北京回到广州之后,又不知道该学习什么,于是乎对编译原理的好奇心又来了,然后再买了几本编译原理方面的书籍,翻看了一部分之后,再次作罢。。。。如果能有多点恒心的话。。。。
不过,强迫自己读了下Go语言内置模板解析的代码,没想到这次强迫自己读的代码,真的有用了。
然后又停滞了,看到微博上热论Rust语言,本来挺不喜欢的,后来就想着学一学试试。看完了教程,这语言还真的是好复杂呀,于是想,做个什么小玩意来深入掌握语法,于是乎,就想去模仿Go解析模板的那段代码。
这次弄了我非常久的时间,特别是Rust语言真的很不好用呀,后来就写了一份Rustparse如何设计脚本语言,写完我就放弃了Rust语言了,不是我的菜,而且我认为将来也流行不起来。
于是岁月蹉跎了又一年,工作上有个任务,要做文本解析,其实主要是提取URI辅助卡盟,然后根据URI的头部判断对应的资源类型。当时心中觉得压力山大,蹉跎了好几天都没敢去完成这个任务。然后有天突然来了蜜汁自信,我居然写出来了!!!!
接着看到腾讯游戏的那位大神在知乎上分享他的fastjson的实现,C写的,我不懂C,也就没去细看文章和代码。微博时间线上出现了好几次他的文章之后,我突然就想,我能否也实现一个JSON的解析器呢?
首先,Lex该怎么实现呢?有了Rustparse的代码经历,我知道怎么去解析字符串,数字,符号,以及如何构建一个状态机。当时横亘在我心里的一个主要问题,就是JSON语法和Lex的关系。Lex解析出来字符串,语法错误怎么办?基本元素和符号的组合如何确定是符合语法要求的呢?从数字、字符串,符号,怎么最后变成字典或者数组呢?
当时内心的那种不知道该怎么做的阻塞感,很难准确描写出来。
思前想后好几天,我突然意识到,Lex不应该管语法的事情,Lex只需要把文本中所有的基本元素提取出来就可以了,语法的事情留个语法解析器去做就好了,虽然还不知道语法解析器该如何实现,但是不管了,先把Lex的代码做好了再说。
Lex实现完之后,该如何实现语法解析呢?JSON的语法规则很简单,要么是个字典,要么是个数组。可是这字典里嵌套字典,字典里嵌套数组,数组里嵌套字典,数组里嵌套数组的,我该怎么做呢?突然灵光一现,递归啊(于是乎你明白我编程水平有多菜了吧)。
然后终于实现了一个简单的JSON解析器 jsonbee(不能支持完整语法),当时心情那个兴奋激动啊。
一激动,信心就爆棚了。于是乎想,之前不是粗略翻过《自制编程语言》么,不如就来用Go实现一番吧。首先练手的便是实现一个简单的计算器,照着他的C代码,实现了一份Go语言的 gocalc
后来,作者就都全部用Lex和Yacc工具来实现语法解析了,本来也觉得挺不情愿的,但是还是耐着头皮去模仿。万万没想到,这些个Lex和Yacc工具并不支持Go语言,看来是上天不让我学习呀。然后一个没想到,Go语言居然自带了Yacc工具,再一想想,自己实现Lex的代码,也是可以的嘛,于是乎,说干就干。
首先就是先用yacc把之前的那个计算器给重写了,写完yacc之后,我才从偏执中醒悟,原来yacc极好的体现了归约的思想,语法表现很清晰,对于编程语言的实现有莫大的促进理解之功效, 重写代码 yaccalc.
《自制编程语言》的第一个脚本语言,是用C语言实现的,我很不熟悉C语言,不过还是要先大致了解下代码结构。然后就开始用Go语言撸Lex部分的代码,确实是花了不少时间呐。Go的yacc工具文档很少如何设计脚本语言,甚少人使用,Lex该返回什么,返回什么值表示结束,怎么表示错误,如何把结果和yacc连接起来,真的是耗费了很多的时间。
Lex搞好之后,yacc部分花了更多的时间,yacc与lex结果的结合,yacc与解释器代码的结合,Go语言的yacc工具该如何使用,真的花费了很多很多时间。
后面解析器部分的代码,倒主要是仿抄C语言部分的代码,如何和yacc的结果结合起来,确实是一个很大的难点。
搞了将近三个月,终于是把结果给搞出来了,growbar, 虽然还不完整,不过至少把所有的测试代码跑过了。
来源:【九爱网址导航www.fuzhukm.com】 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!