从零开始写一个Jison解析器(6/10):解析,而不是定义语法

解析,而不是定义语法
如果所述,和之前的代码相比,在词法分析 lexical analysis 部分中可以视为把 LINE 拆分成了 UNKNOWN、LBRACE、RBRACE,然而在语义分析 semantic analyse 部分中并没有枚举 UNKNOWN、LBRACE 和 RBRACE 的各种排列组合,而只是列出了五种:UNKNOWN、UNKNOWN LBRACE、UNKNOWN RBRACE、LBRACE、RBRACE。

这是因为数据中只有这五种情况,只需要设置这五种规则即可满足解析要求。这也就是本篇讲解的核心内容,针对已有的数据设计解析器 parser 不同于从头设计一种标记语言的语法。针对已有的数据设计解析器 parser 是因为数据通过程序生成,然而格式并不便于直接使用,因此需要借助解析器 parser 将数据转化成易于处理的形式。在绝大多数情况下可以默认程序输出的内容遵循一定的格式,因此,只需要按照输出中存在的情况解析即可,而并不是定义一个有广泛适用场景的语法。

解析,而不是定义语法。是初学使用解析器生成器 parser generator 编写解析程序时需要牢记的事情。在看到程序生成的内容时,应当忠实于输出的内容,避免人为因素引入额外的解析语法,尽管这样看起来不够灵活,或者缺乏扩展性,然而在解析已有程序的输出结果时,并不需要这种灵活或者扩展性。


因此可以很直观的得到结论,等号 = 和花括号 { 和 } 是解析格式的关键符号,也就可以得到在前一篇的基础上需要进一步解析等号 = 和花括号 { 和 } 的结论。

为什么从花括号 { 和 } 开始?
本例的结论是增加花括号 { 和 } ,通过直观观察也能得到这样的结论。那么是否说明编写解析器生成器 parser generator 的过程就是这么简单?或者说通过直观观察得到增加花括号 { 和 } 的结论,是普遍适用于各种编写解析器生成器 parser generator 的过程,还是本例比较特殊呢?

普遍性和特殊性都对,也都不对。先看特殊性,由于等号 = 和花括号 { 和 } 是经常使用的用来赋值符号和包含其他内容的符号,因此在看到等号 = 和花括号 { 和 } 时很自然的就会联想到这几个符号的习惯使用方式,然后再稍加检验就会发现和习惯使用方式差不多,自然就可以得到结论。反之,如果使用其他符号,那么直观观察就没有那么快的得到相同结论了,因此,本例通过直观观察得到结论的特殊性在于所使用的符号有着习惯上的特殊含义。

标点符号在长期的生产生活使用过程中,已经约定了一些使用方式,例如 ( 和 )、[ 和 ]、{ 和 }都是成对出现,而且都意味着包裹开口方向的内容。类似的,< 和 >在英文中用于书名号,也意味着包裹开口方向的内容。单引号 ' 和双引号 “ 虽然没有开口方向,但是本来就是用来包裹引文的符号,所以找到配对的符号即可。在微博中,成对的 # 号表示 tag,对于长期使用微博的用户来说,也能很直观的联想到,而 twitter 中使用单独的 # 表示 tag,对于没有使用过微博的 twitter 用户来说,就不那么习惯把成对的 # 号识别为包裹内容的符号了。微博和 twitter 中都使用单独的 @ 符号指示后续为站内用户名,因此用户看到成对的 @ 就不会识别为包裹内容的符号,而会习惯的把 @ 符号和紧接着的字词看成一个整体。

另一方面,从普遍性的角度看,程序生成数据也会考虑便于人类阅读,因此也会遵循这些约定俗称符号使用方式。因此几乎所有的程序生成的数据通过直观观察都可以发现这些遵循约定俗称的符号。

怎么从零开始发现应该从花括号 { 和 } 开始?
标题并不是在说绕口令,得到前面的结论似乎非常直观,直接通过观察就可以得到这样的结论。然而本系列文章定位于从零开始,借助生产生活经验的约定就不是那么严格的从零开始,如果抛开生产生活经验的约定,或者说,仅从数据来看,就需要回答这样的问题:

是怎么发现应该从花括号 { 和 } 开始的?

解析的过程是一个把连续的数据拆解成层次化结构的过程,最大的结构就是整个数据文件,最小的结构就是字符,如果最小的结构比字符还小,例如单个 bit 位,那么就不适合使用Jison解析器生成器 parser generator 了。

在开始分析时,需要观察结构的特点,这并非是另一种遵循约定俗称的经验,而是寻找入手点,例如有着明显的分行时,那么就可以从行开始分析,尽管最终的结果不一定按行解析,但是找到一个尺度适中的分析起点要好过逐个字符分析。如果忽略换行符在文本编辑器中渲染成换行这个视觉特点,假设是使用十六进制的方式打开数据文件,并没有明显的类似于换行的视觉特点,那么仍旧可以通过分析文件中各种字符出现的频率找规律,尽管这种方式有点像字符替换加密文件通过频率分析出 a、e、i、o、u 几个元音字符,然而实际中远远没有那么复杂,通常是通过各种标点符号发现规律,当标点符号不明显的时候,可以对照常见字符集合,例如0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F词频高说明像是十六进制,那么其他字母可能就是分隔符号。A、B、C、D、E、F、G词频高说明像是乐谱,那么其他字母和数字可能就是分隔符号或者修饰字符。

找到可能用于分析结构的一个或者几个分隔符号后,先初步观察这个分隔符号的颗粒度,例如像是XML中成对的< 和 >,就可以初步判断出< 和 >构成一对,进一步发现其中包裹的内容比较少,据此就可以在第一个层次的分析过程中,把< 和 >包裹的内容视为一体。

本例中观察按行解析的颗粒度,会发现行内的结构一般都比较简单,在第一个层次的分析过程中,可以把每一行视为一体。然后再看从行到整个数据文件的结构,就会发现成对的花括号 { 和 } ,即使不是花括号这种约定俗称的符号,把行视为一体时,通过和前面类似的分析,也会发现 { 和 } 成对出现,而且出现的位置有一定的规律。

从花括号 { 和 } 开始分析
发现了花括号 { 和 } 后,很自然的想法就是写一个按照花括号 { 和 } 解析文件的解析器生成器 parser generator,此时仍旧应当遵循本篇的主旨————解析,而不是定义语法。尽管写一个按照花括号 { 和 } 解析文件的解析器生成器 parser generator 很有可能能解析样例文件,然而编写解析器生成器 parser generator 的目标并非是定义一个使用花括号 { 和 } 包裹内容的语法,编写解析器生成器 parser generator 的目标是解析程序生成的数据文件。

通过前述的分析和观察发现程序生成的数据文件中使用花括号 { 和 } 体现文件中的结构。因此,先直观观察一下样例文件中的花括号 { 和 },搜索左花括号 {
————————————————
版权声明:本文为CSDN博主「胡争辉」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hu_zhenghui/article/details/107075877

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值