木兰编程语言重现:优先级,一个过不去的坎
注:项目目标见码云代码库
上周就复现了一个语法,支持了这样的乘法6/2(1+2)
,结果为 1。
实现中,用到了针对语法规则的优先级设置。虽然 rply 有文档说明,但死磕过后仍然不明所以然。将调试过程记录在此,最后有问题请教各位。
演示
先举个例子(熟悉者请跳过直接看“正题”部分)。很早就复现了四则运算,比如:
10 + 3 * 6 / 5 => 13
相关的优先级(precedence)设置是开头针对词(token)的部分,从低到高排列:
分析器母机 = ParserGenerator( 规则, precedence=[ ... ('left', [不等于, 等于]), ... ('left', [加, 减]), ('left', [星号, 除]), ... ('right', [乘方])
注:上面的“除”代表的是原本支持的/
除法符号。
比方说,现在想扩展一个语法,支持÷
这个除法符号,除了添加一个词“除法”——分词器母机.add(除法, '÷')
、增加一个语法规则——@分析器母机.production(语法.二元表达式.成分(语法.表达式, 除法, 语法.表达式))
之外,还需要照样把除法
添加到优先级设置:
('left', [星号, 除, 除法]),
于是就可以支持:
10 + 3 * 6 ÷ 5 => 13
假如不慎将除法
的优先级设置高了,比如和乘方
一样:
('right', [乘方, 除法])
那么像10 + 3 * 4 ÷ 5
原本应该是 12,但现在会是 10,因为 4÷5 先执行后结果为 0。
假如干脆不设置除法
的优先级,那么10 + 3 * 6 ÷ 5
就会输出这样的玩意:
.../木兰/prototype/分析器/语法分析器.py:884: ParserGeneratorWarning: 19 shift/reduce conflicts 分析器 = LRParser(分析器母机.build()) 5
可以看到最后输出了 5,应该是解析为了(10 + 3 * 6) ÷ 5
。
但报警告有shift/reduce
冲突,要是能提示冲突细节多好。
那么如果在这个语法规则添加设置,使之优先级与“除”相同,是否能达到正确效果呢?
@分析器母机.production(语法.二元表达式.成分(语法.表达式, 除法, 语法.表达式), precedence=除)
上面的shift/reduce
冲突倒是没了,但结果仍为 5。而且,即使这里优先级设最低、最高,都是同样效果。
恢复到precedence=除
后作更多测试:
10 + 3 ÷ 2 * 6 => 36,((10+3)/2)*6 10 + 3 ^ 2 ÷ 2 => 9, (10+(3^2))/2 10 + 3 ÷ 2 ^ 2 => 3, (10+3)/(2^2) 10 + 3 ÷ 2 / 2 => 3, ((10+3)/2)/2 10 + 3 ÷ 2 + 2 => 8, ((10+3)/2)+2
如果改为比“除”优先级低的precedence=加
,两个结果变了:
10 + 3 ÷ 2 * 6 => 1,(10+3)/(2*6) 10 + 3 ^ 2 ÷ 2 => 9 10 + 3 ÷ 2 ^ 2 => 3 10 + 3 ÷ 2 / 2 => 13, (10+3)/(2/2) 10 + 3 ÷ 2 + 2 => 8
如果改为比“加”更低的precedence=等于
,一个结果又变了:
10 + 3 ÷ 2 + 2 => 3, (10+3)/(2+2)
尚未看 rply 实现,个人的推测是,由于这个优先级是针对的这条语法规则,而非“÷”这个词,因此,在“÷”左边所有部分会被解析为一个“表达式”,而右边高于设定优先级的运算部分会合在一个“表达式”。
正题
前不久支持的范围表达式,格式为:-1..4 by 2
,范围表达式的三个规则如下:
@分析器母机.production(语法.范围表达式.成分(语法.表达式, 点点, 语法.表达式)) @分析器母机.production(语法.范围表达式.成分(语法.表达式, 点点小于, 语法.表达式)) @分析器母机.production(语法.范围表达式.成分(语法.范围表达式, 连词_每隔, 语法.表达式))
需要在下面的表达式语法规则中设置优先级为“等于”,比“连词_每隔”(by)低一级。
@分析器母机.production(语法.表达式.成分(语法.范围表达式), precedence=等于)
否则会报错:
分析器.错误.语法错误: 文件 "测试/数据结构/范围.ul", 第4行, 第13列, 没认出这个词 "by" print(-1..4 by 2) ^
看来只有比 by 低,才会将整个识别为“范围表达式”(下面规则),而不是将前半段识别为“表达式”
@分析器母机.production(语法.范围表达式.成分(语法.范围表达式, 连词_每隔, 语法.表达式))
那么为何不设置为优先级更低呢?
最近的这个省乘号乘法,除了下面三个语法规则:
@分析器母机.production(语法.表达式.成分(语法.多项式乘法)) @分析器母机.production(语法.多项式乘法.成分(语法.数, 语法.表达式前缀)) @分析器母机.production(语法.多项式乘法.成分(语法.数, 语法.首要表达式))
还需要在这条看似不搭嘎的规则添加优先级设置:
@分析器母机.production(语法.表达式.成分(语法.数), precedence=等于)
否则也会报警告ParserGeneratorWarning: 1 shift/reduce conflict
。
应该,也是为了不把2a
中的2
解析为“表达式”,而是将整体解析为“多项式乘法”。
这个优先级设置与上面的范围表达式的设置相同,有何用意吗?
请不吝赐教!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Flink SQL CDC 上线!我们总结了 13 条生产实践经验
摘要: 7月,Flink 1.11 新版发布,在生态及易用性上有大幅提升,其中 Table & SQL 开始支持 Change Data Capture(CDC)。CDC 被广泛使用在复制数据、更新缓存、微服务间同步数据、审计日志等场景,本文由社区由曾庆东同学分享,主要介绍 Flink SQL CDC 在生产环境的落地实践以及总结的实战经验,文章分为以下几部分: 项目背景 解决方案 项目运行环境与现状 具体实现 踩过的坑和学到的经验 总结 Tips: 点击下方链接可查看社区直播的 Flink SQL CDC 相关视频~https://flink-learning.org.cn/developers/flink-training-course3/ 01 项目背景 本人目前参与的项目属于公司里面数据密集、计算密集的一个重要项目,需要提供高效且准确的 OLAP 服务,提供灵活且实时的报表。业务数据存储在 MySQL 中,通过主从复制同步到报表库。作为集团级公司,数据增长多而且快,出现了多个千万级、亿级的大表。为了实现各个维度的各种复杂的报表业务,有些千万级大表仍然需要进行 Join,...
- 下一篇
法律要求,伊朗开源项目维护者拒绝合并以色列开发者的 PR
GitHub 上有来自伊朗的项目维护者拒绝合并以色列开发者的代码。 来自以色列的 Yiddishe-Kop 提交了某一个特性的 PR,随后项目维护者,来自伊朗的 armancodes 回复道: ……I'm SO SORRY to tell you that I cannot merge this PR. There is a law in my country that we MUST NOT have any relationship with people from Israel or the Israel government.…… 我很抱歉地跟你说我不能合并这一PR,我们国家有法律规定决不能与以色列人或以色列政府有任何联系。 大家应该了解,伊以之间素来是有严重军政冲突的。 事件的具体情况可以查看这个 PR:https://github.com/armancodes/laravel-download-link/pull/9 该事件目前已经在 Reddit 上引起热议,评论者从人权、语言、冷战聊到政策对技术/进出口等的影响,其中有人提到了谷歌与华为: Maintainer has ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- MySQL8.0.19开启GTID主从同步CentOS8
- Hadoop3单机部署,实现最简伪集群
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker使用Oracle官方镜像安装(12C,18C,19C)