语法分析(5):当我们在谈论语法的时候,我们在谈论什么

本文是本人撰写的编译原理讲义。

本系列讲义适用于:被强迫学习编译原理前端,或者希望弄明白如何做科研的人。

1. The Big Four

语法分析器的工作基本上告一段落。

趁着周末,来图书馆好好充电一番。

泡在《自动机理论、语言和计算导论》、《计算理论导引》、《集异璧》等苦海之中,浮浮沉沉。

这种看不懂,但是又不自觉一页一页疯狂翻书的感觉,像极了那次在五年级用一天时间逐页翻完了《拣屎》。啊不对,是《时间简史》。

还记得简史完的晚上,躺在床上脑壳一阵一阵的疼,睡又睡不着,什么双生子谬论,什么果壳中的宇宙轮番过来问候。。。

而如今,只觉得躺在枕头上的脑壳像是被乔姆斯基的0 1 2 3四大文法轮着来敲似的,又疼,又吵。。。。

啊,原来吵闹的是好久不见的三小只,外加一个文质彬彬的小学生。

只见三小只叽叽喳喳说着:"我们仨比你个书呆子厉害多了!我们有三个人,三个臭皮匠顶个诸葛亮你懂不懂!我们敢玩泥巴射弹弓掏鸟窝,干啥都无拘无束,你敢吗?"

只见那个小学生涨红了脸,争辩道:"你们几个懂什么,乔老师说了,幼儿园小朋友的大脑还没发育完全,理解不了复杂的规则,也控制不了情绪,才会这么肆无忌惮。。。。"

三个天不怕地不怕的小不点冲着那个学生摆了个鬼脸,"王八念经,听不懂听不懂。反正百无一用就是你,略略略。。"说罢便一溜烟跑走了。

旁边一个在旁边驻足的领导摸样的中年人笑着摇头:"三弟这几个儿子天不怕地不怕的,迟早要被现实狠狠教育呐。不过亏你还是他们二堂哥,他们这初生牛犊不怕虎什么都敢做的性格,既是他们的强项也是他们的弱点,你这何必跟他们争呢,你有你自己的强项呐!"

二堂哥涨红了脸:"我。。我都不知道我有啥强项。我觉得他们说得对,我好像学了很多但是啥都不会。。"

大伯笑了:"你比他们强多了呀!你知道要做事情要有始有终,知道要目光长远多想几层,还知道不能一味贪玩,这就是你比他们多学好几年的收获呀!"

二堂哥沉默半响,"但我跟大伯你比起来我感觉自己啥也不是。我爸妈总说我太死板了,知识是学到了但不懂得变通,总让我学学你的城府。"

大伯又笑了:"我曾经也是个愣头青呐。都是被社会教育多了,才知道在什么场合做什么事,才长出了你爸经常吐槽我的八百个心眼子。

而且,你以为城府就是什么绝对的好事嘛?心眼多其实挺累的,看事情一不小心就会想得太复杂。所以我更怀念你爷爷。他那是真的大智慧,小时候总教育我大道至简,让我不要总什么东西都抓在手里,得懂舍得,放下。那时我还小,觉得什么东西都得抓在手里。现在才知道,难得糊涂啊!"

2. 人类理解的边界:递归可枚举

编辑

乔姆斯基教授

此时,乔姆斯基教授像是总导演一样,连同几位演员,一同朝观众们鞠了个躬。

"再次感谢几位演员帮我把我心中的几种主要文法给演活了。要不是你们,估计这个关于文法的公开课都没几个人看呐。请落座,接下来也请你们多给我捧个哏。"

"先问大家一个问题,你们觉得是先有文法还是先有语言?"

三小只很积极:"是文法!""是语言!"

乔姆斯基教授微笑着压了压手:"听起来,这个问题就跟先有鸡和先有鸡蛋一旦充满争议啊。但其实鸡蛋和鸡的问题早就有结论了,是先有最早的蛋再从里面生成的鸡。

同理,是先有了我们多姿多彩的语言,才有各种语言学家去总结、归纳这些语言的规律,这才有了文法。"

二堂哥小演员举手提问:"既然蛋是语言,鸡是文法;那是不是说,文法可以生出语言?"

"Very good!"乔姆斯基教授亮出大拇指。"编程用的单词串集合确实可以用正则文法来生成;编程语言本身绝大部分可以用上下文无关文法来生成。所以,我就尝试去从更加宏观的角度去分类那些语法规则有限的语言了。那小朋友你再猜猜,为什么我不去分类那些有无限条语法规则的语言呢?"

二堂哥小演员一脸困惑:"嗯。。什么是无限?我不理解。"

乔姆斯基教授:"对,我也理解不了,所以我才不研究。"大家都笑着鼓掌了。

"人生苦短。假如有无限条规则,那么根本就没时间看完,也就不要试图用这些规则来组织语言了。

也就是说,只要我手中握着有限条规则,我就可以通过设定好的程序,从短到长把对应的句子,一个一个枚举出来。"

"乔老师,我还是有点不理解,即使有无限条规则,难道我不能用类似的程序,每次只选择里面的一小部分规则来生成句子,这样不也可以把句子一个一个枚举出来吗?"有小观众提问。

"Good Question!这样做确实可以确保你选择的这些规则可以生成了一些句子。但是,在你选择的这些规则以外,没准有一条是禁止这个句子的生成呢?然而咱们没有办法在有限的时间内确认确认,这就是不可枚举的情况。

我在文法方面的研究成果,其实前面几位演员们已经演绎得差不多了,我就来个狗尾续貂简单介绍一下。昨晚缺乏睡眠的小观众可以趁机补补觉。"观众笑着鼓掌。

3. 四层文法

最自由的文法------0型文法

它的规则只有一条:产生式左部至少有一个非终结符。

光看这一条规则并不能看出来什么玄机,就像秋香的美貌是通过和其他三美比较得出来的。咱们姑且先看看后面的1型文法------上下文有关文法。

所谓1型文法,实际上就是在0型文法的基础上,增加了一个核心规则:产生式的右部不能比左部要短。

相比于0型文法,1型文法实际上就像是一个葛朗台,手上有的一切符号只能增加,不能减少。

由此可以反过来理解,0型文法相对于1型文法的特点就在于,它敢于丢掉认为不重要的符号。换句话来讲,0型文法就像是刚刚舞台剧中大伯口中的那个未曾出场的爷爷,懂得舍弃,适时糊涂,知道把握断舍离的度。

为什么拥有删除能力就拥有了最强的能力?因为删除操作不可逆。

在增、删、查、改四个核心操作中,增加错了可以直接删除、查错了再查一遍便是;而一旦删错了、改错了,如果没有提前设置好记忆模块,那这个操作就无法撤销。

那不可撤销又能怎?

试想一下没有删除权限的AI,它会生成一堆的Token,那么我们可以开开心心地从它的历史记录中看到它的思考过程,知道它到底有没有在糊弄人类。但如果,我们允许了它拥有删除权限,它可能就会把自己密谋谋害人类的中间思考过程隐藏起来,又或者会把人类的重要数据删掉。

光说这两点,想必绝大部分的人都宁愿把这个不受控AI的删除权收回来,都不想让这个能力很大的AI接管整台电脑。(画外音:此时此刻,在另一个平行宇宙中,一群麻瓜听说OpenClaw可以帮自己干活,一边疯狂寻找安装教程开团秒跟,一边对OpenClaw爆出来的各种删库跑路新闻充耳不闻。可能这就是知识的诅咒吧,专家们总是把人想得太理性了。)

上下文有关------1型文法

光看它前面的定义,似乎只能让人觉得它是一个非缩减文法(Non-contracting Grammar)而和上下文有关文法(Context-Sensitive Grammar, CSG)没有半毛钱关系。

实际上,后者只是多了一个小限制:一次推导只能展开产生式中的一个非终结符。

我们来看下面的一个例子:假设原来有一条"非缩减"的规则AB → CD ,现在为了达成上面的新监管要求,引入新的非终结符 X, Y 进行"接力":

  1. AB → XB

  2. XB → XY

  3. XY → CY

  4. CY → CD

通过使用这四条产生式替代原来的AB → CD,只要新引入的XY不被其他产生式使用,则整个文法的功能将完全不会发生变化。

现在来看新限制下的产生式:每次展开的非终结符能被展开并不是自由的,只有当上下文的条件被满足,才能进行展开。

基于这个特点,我们才把这个称为上下文有关文法。

如果说上文出现在非终结符的左边(前面),下文出现在非终结符的右边(后面),那么我们可以定义,满足如下产生式格式的文法就是上下文有关文法:

αAβ→αδβ

上下文不存在了------上下文无关的2型文法

与此相对的,假如上下文中这些条件并不存在,也就是说α=ε,β=ε,那么非终结符的展开不依赖上下文,我们就称呼它为上下文无关文法,也叫他做2型文法。

限制重重------无层次的3型文法

而3型文法,就是在2型文法的基础上,给产生式的右边又增加了一个限制:非终结符最多只能有一个,而且终结符要么只能出现在它的左边,要么只能出现在它的右边。

限制的意义

这个时候就出现了一个无法回避的问题:有限制好,还是没限制好?小朋友你觉得呢?

在旁边睡得迷迷糊糊口水直流的小朋友,刚睁开眼就被摄像头来了一个怼脸拍。看到黑洞洞的摄像机对着自己,脑子里一片迷糊。被演大伯的演员提示了好几句之后,揉着眼睛说:"那当然是没有限制的好,这样我就可以吃更多好吃的,玩更多游戏了呀!"

整个演播厅都被他逗笑了,内外充满了快活的空气。

乔姆斯基教授也笑了:确实,谁会喜欢限制呢?总感觉自己手脚施展不开。那咱们换个词,不说限制,说前提:只有你犯错了,妈妈才会批评你 这样比较好,还是妈妈随时随地不管你犯错还是表现好都批评你?

小朋友委屈巴巴:就不能不批评吗?观众又笑了。

乔姆斯基教授:好好好,那我们再换一个。那你是想只在开心的时候玩玩具,还是想在很困很困的时候被拉起来玩玩具?

小朋友:"不想在困的时候玩玩具,那时候只想睡觉。"观众都笑着鼓掌了。

乔姆斯基教授:"对了!小朋友,你说得很好。你想要的没有限制,假如真要完全落实,那么我们的世界很容易就会乱套了。爸爸妈妈会在你表现好的时候也批评你,而不是只在你做得不好的时候才批评;可能在你睡得迷迷糊糊被叫起来回答问题,而不是在你清醒的时候。所以,你还会讨厌限制吗小朋友?"

小朋友:"不会了。我现在知道了,有些限制是用来保护我的。"观众们都鼓起了掌。

"是的,小朋友你总结得非常好。好多东西看上去是负担,其实换个角度就会变成好事。

相比于一往无前的线性文法3型文法,2型文法看上去实现成本复杂多了,但他也收获了识别层次的能力;

相比于不分场合的2型文法,1型文法似乎使用起来限制多多,但他也收获了在正确场合做正确事情的能力;

相比于八百个心眼子活得很累的1型文法,0型文法可能会由于引入了错误的删除/改写导致自己无法到达终点,但他也在有限时间和空间中获得了真正的随心所欲。

更何况,每往下走一个层次,文法所精准描述语言的能力就越强。"

瑞格娜也举手了:"您好教授,请问精准描述有什么重要作用吗?我感觉三型文法本质上也可以生成很多句子的呀?另外我听您之前的介绍,似乎明明是从0到3型文法不断增加限制的,但您刚刚解释的似乎是反过来的,反而是1型文法比2型文法多了上下文的限制?"

"这位年轻的女士提了超级棒的三个问题。请容许我多啰嗦一点详细回答一下。

对于问题1、2,我举个简单的例子:在调试代码的时候,你当然是希望编译器能尽可能精确地告诉你代码中哪里有问题,对吧?同样地,我们的语言的作用本质上是在传递信息。如果可以尽可能精确地表达,那么信息就可以尽可能准确地传达到位,理解的成本就可以大幅降低。

就像我们前面讲的,讲话实际上就是在用有限的文法来生成、组织一句话。而反过来,理解一句话实际上同样是在利用有限的文法来理解这句话的语法结构。

最重要的部分来了:三型文法本质上确实可以生成很多复杂的句子,换到现实里面相当于一个人去看病,他会随机地说:'医生我这里很[酸痛、胀痛、刺痛、刀割痛、绞痛、灼烧痛、串电痛、压痛、隐痛]'的其中之一。对,我的意思是,他完全不知道自己该说哪个才能最准确表达自己的症状。但一型文法,他就可以准确表达:肚子绞痛,肌肉酸痛,从而方便医生快速断症,减少病人本身的痛苦。所以,精确的表达对双方都有重要的作用。

至于您刚刚讲到的限制问题,其实是我本场演讲中最想让大家注意的一个点:自然语言中,一个词往往会有正向反向两种理解。就像是透明这个词,"对用户透明"既可以说用户能对内部过程一览无遗,没有私藏,也可以说用户完全看不到内部。

同理,限制这个词,正如前面所说,某种程度上是一个很主观的词。有人看到的是限制,有人看到的是能力的提升。

但在客观上,0型文法到3型文法本身,确实是通过增加了书写产生式的限制,从而大幅降低产生式的应用成本,无论是组织语言还是理解这两个操作。

比如最开始的0型文法,增删查改随便操作;在增加非缩减的限制后,我们知道了信息不会凭空消失,也就不会担心重要的消息在未读之前就消失得无影无踪,再怎么样都会留下一点痕迹,从而方便溯源;当然识别1型文法的机器还是很复杂,我们就增加了左部只能有一个非终结符的限制,从而只需要栈+DFA外加一些补丁技术就可以近似实现接近1型文法的效果。最后发现我们的有些单词根本不会存在这样的层次效果,干脆就把2型文法限制为只能线性往一边增长,由此就产生了3型文法。

然而天下没有免费的午餐,这边的成本降低了,换来的就是表达与理解的精度都大幅度下降。因此三型文法表达不了句子,二型文法表达不了层次的文章,一型文法无法隐藏自己的小心思。但反过来,当我们在做单词识别的时候无需用栈;当我们在做语法分析的时候无需罗列所有的复杂上下文;当我们在做语义分析的时候,无需费神思考会不会有语义在不经意间流失了。

所以总括来讲,我构建出来的四层文法,从0到3确实是依次在增加限制,为的是降低使用成本。然而由于使用者的主观感受,可能会觉得1型文法反而是限制了2型文法的发挥;2型文法的层层嵌套还限制了3型文法的无拘无束。但实际上,我们并不能直接从文法对应的语言集合大小来比较两个不同层级文法的能力差异,因为实际上这些语言集合都是无穷大的,并不能直接比较大小。

因此只要我们记住,假设M<N,那么N级文法肯定符合M级文法的限制,N级文法肯定就是M级文法的特例。"

4. 彩蛋:1型文法的补丁

"说到这里我就要介绍四大文法中最丑陋的一个补丁了。

既然1型文法是一个非缩减文法,那么从开始符号出发开始推导,就不应该能推导出空串才对。但我们现实中又很容易定义出包含空串的2型文法和3型文法。这下子,如果我坚持1型文法无法包含空串,就会导致上面的包含关系不再成立。难道刚建好的文法大厦就要这样崩塌了?

然后我赶紧给这个摇摇欲坠的大楼打了补丁:允许在有需要的时候,让1型文法对应的语言集合可以包含空串。

但文法不像是集合运算,它只能用产生式来表示。于是我用了一个巧妙的方法:首先借助于拓广文法,让S不会出现在产生式的右边,同时允许S生成出空串。这样,就能确保这个空串不会影响其他产生式,也尽可能地不违反不缩减的原则了。"

5. 尾声

如果观众朋友们对计算理论了解得更加深入,你会发现:0型文法实际上对应了目前最强的计算模型图灵机。因此,在你深入了解文法和语言的时候,实际上你同时也在了解我们当今最重要的计算模型。

然而一个模型强,并不代表就好用,因为我们要考虑成本。

对于无穷的宇宙而言,人类的生命是有限的。我们只能用有限的成本去尽可能理解这个世界。

只由当简单的模型无法准确描述事物,我们才要再去考虑更复杂的模型。

能正确根据你的成本、预算以及要达成的效果,正确地选择你的计算模型,这才是智能的体现。

这也是我在0型文法以外,还开发出另外三层文法的原因。

有辣有唔辣,任君选择。

什么乱七八糟的?怎么还能梦到这么久远的广告。。。

睡了一晚上,感觉一群人在脑海里面闹哄哄开过一场会。。。头还是痛得要死。。

啊怎么就到八点了,该死要迟到了,待会儿到公司又要开会讨论语义计算了。。

忙碌的一周又要开始了救命!

**画外音:**词法分析对应的是三型文法,语法分析对应二型文法,而一型文法又太重。

所以,整个编译原理中最华丽而又硬核的部分实际上已经结束了。

接下来将会把这些浮在天空中的理论,通过工程的实践原理与技巧,让他们真正落地。

感谢读者朋友的支持,我们下一季再见!

相关推荐
搞笑僵尸思考时间1 天前
语法分析(4):以听众为中心的自底向上语法分析
编译原理
牛奶2 天前
你不知道的 JS(上):原型与行为委托
前端·javascript·编译原理
牛奶2 天前
你不知道的JS(上):this指向与对象基础
前端·javascript·编译原理
Mintopia6 天前
Web 安全与反编译源码下的权限设计:构建前后端一体的信任防线
前端·安全·编译原理
搞笑僵尸思考时间6 天前
词法分析(1):从demo代码中抽象
编译原理
搞笑僵尸思考时间6 天前
词法分析(2):万法归一的正则文法
编译原理
zfj32117 天前
好书分享:《两周自制脚本语言》-用java实现一个脚本语言
java·开发语言·python·编译原理
1900ch19 天前
flex添加块注释处理规则
编译原理
DeepVis Research1 个月前
【NLP/Microservices】2026年度语义逻辑编译与分布式微服务架构基准索引 (Benchmark Index)
算法·微服务·自然语言处理·架构·数据集·编译原理