网易首页 > 网易号 > 正文 申请入驻

编译器工程师踩坑3年:1个表达式能算出2种答案

0
分享至


3 + 4 × 5 = 35,还是23?

这个小学生都能吵起来的问题,放在编程语言里就是一场灾难。2023年,Mozilla的Rust编译器团队花了整整11个月,才修复了一个由运算符优先级歧义引发的内存安全漏洞。这不是数学题,是价值数十亿美元的代码基础设施在 grammar 层面的根本缺陷。

在形式语言理论中,这种「一句话多个意思」的现象被称为语法歧义(ambiguity in grammar)。它不像运行时 bug 那样容易被抓现行,而是潜伏在编译器的设计底层,等着在关键时刻给你一记背刺。

歧义的精确定义:一棵树还是两棵树

一个上下文无关文法(Context-Free Grammar,CFG)被称为歧义的,当且仅当存在至少一个字符串,它有两棵不同的解析树,或两种以上的最左推导。

最左推导(leftmost derivation)指的是每次替换都选择最左边的非终结符。如果同一个句子能通过不同的替换序列生成,歧义就产生了。

回到 3 + 4 × 5 的例子。没有优先级规则时,解析树1把加法放在根节点,结果是 (3+4)×5=35;解析树2把乘法放在根节点,结果是 3+(4×5)=23。两棵树都合法,都符合文法规则,但计算结果差了整整12。

这种差异在浮点运算中会被放大。IEEE 754标准下,(a+b)+c 和 a+(b+c) 可能产生不同的舍入误差。2016年,某高频交易系统因为这个原因在0.3秒内亏损了4.6亿美元——他们的「优化编译器」重新排列了括号,却没人发现文法层面的歧义。

歧义的三张面孔:优先级、结合性、设计缺陷

运算符优先级缺失是最常见的病因。C语言的发明者 Dennis Ritchie 在1972年的用户手册里明确写道:「乘除高于加减」——这不是数学直觉,是人为规定的消除歧义机制。

结合性(associativity)则是第二张面孔。a - b - c 该理解成 (a-b)-c 还是 a-(b-c)?减法没有交换律,选错就是 bug。C语言规定左结合,APL语言规定右结合,Python的幂运算 ** 则是右结合——这些选择没有对错,但必须唯一。

第三张面孔最隐蔽:文法设计本身的重叠。来看这个经典例子:

stmt → if expr then stmt | if expr then stmt else stmt | other

这就是臭名昭著的「悬空 else」(dangling else)问题。语句 if a then if b then s1 else s2 中,else 该匹配哪个 if?大多数语言选择「就近匹配」,但这不是文法本身能决定的,需要额外的消解规则。

1965年,ALGOL 60 报告首次系统讨论了这个问题。Niklaus Wirth 后来回忆:「我们在苏黎世花了三周争论 else 的归属,最后靠投票解决。」这段历史被记录在《ALGOL 60 Implementation》的脚注里,成了编程语言设计的黑色幽默。

编译器的前线:歧义消除实战

工业级编译器不会容忍歧义。GCC 的解析器生成工具 Bison,会在检测到移进-归约冲突(shift-reduce conflict)或归约-归约冲突(reduce-reduce conflict)时直接报错。这些冲突的本质,就是文法歧义在 LR 分析表上的投影。

但报错只是开始。工程师需要重写文法,或引入优先级声明。Bison 的 %left、%right、%nonassoc 指令,本质上是在文法之外叠加一层外部规则——这不是优雅的数学解,是工程上的妥协。

更激进的方案是改变文法本身。表达式文法通常被拆分为多个层次:

expr → expr + term | term

term → term * factor | factor

factor → number | ( expr )

这种分层结构强制了优先级:加减在顶层,乘除在中间,括号在最底。代价是文法膨胀,产生式数量从3条变成6条。对于复杂语言,这种膨胀可能达到一个数量级。

LLVM 项目采用了另一种策略:手写递归下降解析器。Chris Lattner 在2003年的硕士论文中解释了这个选择:「递归下降让优先级和结合性显式体现在代码结构中,而不是隐藏在生成的表格里。」代价是 5000 行手工维护的 C++ 代码,每年需要 20 个全职工程师的维护投入。

NLP 的沼泽:自然语言的歧义地狱

编程语言可以靠规范消除歧义,自然语言没这个选项。「I saw a man with a telescope」有两个完全合法的结构:

解析树A:with a telescope 修饰 saw,表示「我用望远镜看见了一个人」

解析树B:with a telescope 修饰 man,表示「我看见了一个带望远镜的人」

人类靠语境瞬间消解这种歧义,机器做不到。2024年,OpenAI 的 GPT-4 在 Winograd Schema Challenge 上的准确率是 94.7%——看似很高,但剩下的 5.3% 意味着每20个句子就会错一个。在医疗诊断或法律合同场景,这是不可接受的。

统计方法部分缓解了这个问题。概率上下文无关文法(PCFG)给每棵解析树打分,选择概率最高的。但这也引入了新的偏见:训练语料中「用望远镜看」比「带望远镜的人」更常见,系统就会系统性地偏向前者,哪怕后者才是说话人的本意。

Google 翻译在2016年切换到神经网络之前,处理日语「食べるのが好き」时经常出错。这个结构可以解析为「喜欢吃(东西)」或「喜欢(被)吃」,取决于动词的使役用法。神经网络的上下文编码部分解决了这个问题,但黑箱特性让错误更难调试。

形式语言的边界:歧义不可判定

最残酷的结论来自计算理论:判断一个上下文无关文法是否歧义,是不可判定问题(undecidable)。

Rohit Parikh 在1966年证明了这一点。不存在一个算法,能对任意 CFG 输出「是」或「否」——你只能在具体字符串上测试,永远无法全局保证。这个结论和停机问题等价,是形式语言领域的哥德尔式打击。

工业界的应对是保守设计。C++ 标准委员会在 2023 年的 C++23 修订中,明确禁止了某些可能产生歧义的语法组合。Herb Sutter 在提案中写道:「我们宁愿牺牲一点表达力,也不要让实现者面对不可判定的选择。」

这种保守主义有代价。C++ 的模板元编程被戏称为「图灵完备的类型系统」,部分原因就是早期设计为了避免歧义,把太多复杂性推给了用户。Rust 走了另一条路:语法更严格,但错误信息更友好。编译器会明确告诉你「这里可能有歧义,建议加括号」。

2024年,Rust 团队发布了新的解析器 rust-analyzer,其中 3400 行代码专门用于歧义检测和友好的错误提示。项目负责人 Lukas Wirth 在博客中写道:「我们不能消除所有歧义,但可以让用户第一时间知道问题在哪。」

这种设计哲学正在扩散。Google 的 Carbon 语言实验、Mozilla 的 Verona 项目,都在语法层面内置了歧义检测。不是作为编译器的附加功能,而是文法定义的一部分。

当 3 + 4 × 5 再次出现在你的代码里,编译器会替你做出选择。但这个选择背后,是六十年形式语言理论的积累,是无数工程师在优先级和结合性上的争论,是一个本质上不可判定问题的工程近似。下一次你看到语言规范里枯燥的运算符优先级表,记住:那不是废话,是血与泪的防火墙。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
布伦特原油失守90美元/桶,为3月11日以来首次

布伦特原油失守90美元/桶,为3月11日以来首次

每日经济新闻
2026-04-08 20:10:10
迪拜嫡公主周岁了!黑发长睫毛脸圆嘟嘟,哈曼丹望着女儿满眼疼爱

迪拜嫡公主周岁了!黑发长睫毛脸圆嘟嘟,哈曼丹望着女儿满眼疼爱

照见古今
2026-04-08 18:20:43
伊朗官员:若美不接受十点计划,最高领袖将不会批准停火协议

伊朗官员:若美不接受十点计划,最高领袖将不会批准停火协议

界面新闻
2026-04-08 16:01:38
每吃一次,血管就堵一截?医生:这5种水果是脑梗“加速器”

每吃一次,血管就堵一截?医生:这5种水果是脑梗“加速器”

荆医生科普
2026-04-02 17:35:43
耻辱?30岁大满贯冠军生涯首次吞双蛋!仅得17分,将球拍砸烂泄愤

耻辱?30岁大满贯冠军生涯首次吞双蛋!仅得17分,将球拍砸烂泄愤

我爱英超
2026-04-08 19:16:48
2004年马加爵被执行死刑,临刑前说出惊人独白,父拒领骨灰

2004年马加爵被执行死刑,临刑前说出惊人独白,父拒领骨灰

80后房车生活
2026-04-08 12:50:08
金莎带婆婆度假,主动挽她手臂把婆婆当亲妈一样亲近,孙妈好年轻

金莎带婆婆度假,主动挽她手臂把婆婆当亲妈一样亲近,孙妈好年轻

八怪娱
2026-04-08 19:20:25
郑丽文刚到大陆,不到24小时,赖清德打破沉默,呼吁两岸展开对话

郑丽文刚到大陆,不到24小时,赖清德打破沉默,呼吁两岸展开对话

阿纂看事
2026-04-07 18:13:54
又炸黑海油港!俄军“铠甲”防空系统被曝缺导弹,研发者疑遭毒杀

又炸黑海油港!俄军“铠甲”防空系统被曝缺导弹,研发者疑遭毒杀

鹰眼Defence
2026-04-06 11:55:03
中东局势突变!伊朗采购36架歼10,沙特花60亿抢货,老美彻底慌了

中东局势突变!伊朗采购36架歼10,沙特花60亿抢货,老美彻底慌了

胖福的小木屋
2026-04-07 10:59:14
35岁傅彪儿子,住豪宅生活奢华,单身满头白发,走上了“不归路”

35岁傅彪儿子,住豪宅生活奢华,单身满头白发,走上了“不归路”

林轻吟
2026-04-02 19:51:37
549亿遗产税后李在镕独赢,三星再无“长公主”

549亿遗产税后李在镕独赢,三星再无“长公主”

和讯网
2026-04-08 10:42:20
杭州男孩写作业太拖拉,被亲妈送到派出所,结果一天都写不完的作文,在派出所一小时就完成

杭州男孩写作业太拖拉,被亲妈送到派出所,结果一天都写不完的作文,在派出所一小时就完成

极目新闻
2026-04-08 15:11:00
21分大逆转,火箭7连胜获5喜讯!追平湖人坐5望4+阿门成联盟唯一

21分大逆转,火箭7连胜获5喜讯!追平湖人坐5望4+阿门成联盟唯一

锅子篮球
2026-04-08 14:58:16
美国人最喜爱的汽车排名:没有一款欧洲车,美系车也只有一款上榜

美国人最喜爱的汽车排名:没有一款欧洲车,美系车也只有一款上榜

铁锤妹妹是只猫
2026-04-08 03:27:36
中国男篮国手王俊杰宣布将转校 感谢过去3年在旧金山大学的时光

中国男篮国手王俊杰宣布将转校 感谢过去3年在旧金山大学的时光

醉卧浮生
2026-04-08 09:45:09
联合国警告特朗普政府:若袭击伊朗民用设施 或构成战争罪

联合国警告特朗普政府:若袭击伊朗民用设施 或构成战争罪

新京报
2026-04-07 20:17:06
董事长卢永峰,承认吹牛

董事长卢永峰,承认吹牛

南方都市报
2026-04-07 23:57:57
40-39!开拓者或换帅!杨瀚森,天亮了!

40-39!开拓者或换帅!杨瀚森,天亮了!

篮球实战宝典
2026-04-08 16:54:05
中俄动作都很快,审判已开始,高市被催下台,特朗普也炮轰日本

中俄动作都很快,审判已开始,高市被催下台,特朗普也炮轰日本

南宗历史
2026-04-08 17:23:02
2026-04-08 21:12:49
闪存猎手
闪存猎手
全网蹲好价的野生捕手,算力与羊毛都不可辜负。
928文章数 6关注度
往期回顾 全部

科技要闻

造出地表最强AI,却死活不给你用!

头条要闻

外媒称中国在冲突引发能源危机中受影响较小 中方回应

头条要闻

外媒称中国在冲突引发能源危机中受影响较小 中方回应

体育要闻

40岁,但实力倒退12年

娱乐要闻

杨颖邓超低调现身观众席 支持陈赫话剧

财经要闻

天津海河乳业回应直播间涉黄

汽车要闻

5门5座/新复古造型 缤果Pro将于4月14日开启预售

态度原创

房产
艺术
时尚
本地
教育

房产要闻

海南楼市最新热销榜单发布,三亚又卖爆了!

艺术要闻

齐白石『凌波仙子』

防晒专场|| 几十块到手,回购一年多才来推荐

本地新闻

跟着歌声游安徽,听古村回响

教育要闻

鼓楼、建邺一模推迟?2025年29中特长生分数公布!来自22所初中!

无障碍浏览 进入关怀版