这两天把编译原理词法分析实验提前给做了,作品地址:http://115.159.147.250:666/Lexical/,源码:https://github.com/netcan/compilingTheory,效果图:
https://raw.githubusercontent.com/netcan/compilingTheory/master/lexical.gif

现在来记录下编写心得,这是编译原理的第一个实验,算是热身实验吧,确实很简单,花了一晚上就把词法分析器底层部分写完了,老师比较喜欢图形界面,后来又加了前端,也就是现在看到的效果。实验要求能够匹配出关键字标记符运算符分界符无符号数,后来我又添加了一部分,现在能匹配出字符/字符串行间注释

词法分析器底层部分

底层部分是用C++写的,大体思路就是,每次从stdin读取出一行,然后从这行的第一个字符开始匹配。匹配完了,读取下一行,行号+1。

匹配关键字标记符自动机

若当前匹配到的字符$i$是字母,就继续匹配下一个字符,直到下个字符$j$不是字母或者数字或者’_’为止,则截取字符串$(i, j)$,判断这个字符串是不是关键字或者标记符,否则错误处理。如果是标记符,将其存入标记符表中,其在标记符表的位置即为其Pointer。最后输出相关信息。

匹配无符号数自动机

若当前匹配到的字符$i$是数字,就继续匹配下一个字符,直到下个字符$j$不是字母或者数字或者’_’为止,则截取字符串$(i, j)$,判断这个字符串是不是无符号数。如果是无符号数,将其存入常数表中,其在常数表的位置即为其Pointer,若不是无符号数则当错误处理。最后输出相关信息。

匹配行间注释自动机

若当前匹配到的字符$i$是’/‘并且下一个字符也是’/‘,就继续匹配下一个字符,直到下个字符$j$不是空白(空格或tab)为止,则截取字符串$(j, lineEnd)$,作为注释处理。

匹配运算符分界符自动机

我将运算符分界符放到一个optrs表中,若当前匹配到的字符$i$是optrs的元素,就继续匹配下一个字符,直到下个字符$j$不是optrs的元素或者运算符类型与字符$i$不一样或者就是分界符为止,则截取字符串$(i, j)$,判断这个字符串是不是optrs的元素,并确定其类型,其Pointer为该运算符分界符optrs的位置,输出相关信息,否则当错误处理。最后输出相关信息。

匹配字符字符串自动机

若当前匹配到的字符$i$是"或者',就继续匹配下一个字符,直到下个字符$j$是字符$i$为止,则截取字符串$(i, j)$,判断这个字符串是字符还是字符串。如果是的话,将其存入字符字符串表中,其在相应表的位置即为其Pointer,若不符合则错误处理。最后输出相关信息。

词法分析器前端部分

前端部分我比较认真,我用html+js+php来实现图形界面,之所以写成网页,是因为我不想写native app,我也没GUI开发环境。在互联网时代,webapp是趋势,谁还写本地客户端啊,况且带个几十M的GUI库实在是麻烦。

于是我的分析器底层部分设计成输出json格式,然后利用管道将C++程序与php程序进行数据传送。前端只要用js输数据取数据渲染页面即可。

在这之中发现一个问题,如果输入文本一长,渲染效率大大降低,因为我用append方法一个个加元素的。解决方案是最后转换为字符串一次性输出渲染,效率提高了不少。具体可看这个优化片段:优化js运行效率