原题 | Adding Actions to a PEG Grammar

作者 | Guido van Rossum(Python之父)

译者 | 豌豆花下猫(“Python猫”公众号作者)

声明 | 本翻译是出于交流学习的目的,基于 CC BY-NC-SA 4.0 授权协议。为便于阅读,内容略有改动。

如果你在语法规则中还可以添加(某些)语义,那么语法就会更好。特别是对于我正在构建的 Python 解析器,我需要控制每个备选项返回的 AST 节点,因为 AST 的格式已经规定好。

【这是我的 PEG 系列的第 6 部分。其余部分请参阅系列概述 】(译注:本系列的译文已在 Github 开源,项目地址:https://github.com/chinesehuazhou/guido_blog_translation

许多语法都有支持给规则添加动作的约定,通常是 { 花括号 } 内的一段代码块。更确切地说,行动与备选项相关联。动作块中的代码通常与编写编译器的语言相同,如 C 语言,增加一些工具,用于引用备选项中的条目。在 Python 原始的 pgen 中,我没有添加此功能,但对于这个新项目,我希望使用它。

对于在这一系列博客文章中开发的简化版解析器生成器,下面是我们采用的做法。

一般而言,动作的语法如下:

rule: item item item { action 1 } | item item { action 2 }

因为它会使语法变得冗长,所以解析器生成器通常支持跨行分割规则,例如:

rule: item item item { action 1 }
| item item { action 2}

它会使语法分析器变得复杂,但可读性更重要,所以我会使用这种方式。

一个永恒的问题是何时执行动作块。在 Yacc / Bison 中,因为没有回溯,一旦规则被解析器识别到,就会执行动作块。每个动作会立即执行,这意味着即使操作具有全局副作用,还是会顺利执行(例如更新符号表或其它编译器数据结构)。

在 PEG 解析器中,因为有无限回溯,我们有其它的选择:

  • 延迟所有动作,直到解析完所有内容。这对我的目的没有用,因为我想在解析期间构造一个 AST。
  • 只要识别出动作所对应的备选项就执行之,但要求操作代码是幂等的(即无论执行多少次,都具有相同的效果)。这意味着可以执行某个动作,但其结果最终会被丢弃。
  • 缓存动作的结果,因此只有第一次在给定位置识别到备选项时,对应的动作才执行。

我要采用第三个选项——正好我们用 packrat 算法缓存东西,所以我们也可以缓存动作的结果。

关于 {花括号} 里面的内容,传统上是使用 C 语言,它约定用 $ 符号来引用已识别的备选项(例如,$1 引用第一个条目),并赋值给 $$ 以指示动作的结果。

在我看来这太老古董了(我记得曾在 Algol-60 中使用对函数名的赋值,来指定返回值),所以我会用一些更 Pythonic 的方式:在括号内,你需要放置一个单一的表达式,它的值是动作的值,而条目的引用则是一些简单的名称,给出着条目的文本。

举个例子,这是一个简单的计算器,可以作加减法:

start: expr NEWLINE { expr }
expr: expr '+' term { expr + term }
| expr '-' term { expr - term }
| term { term }
term: NUMBER { float(number.string) }

当我们运行时,给定输入 100+50-38-70 ,它会识别出各部分并计算答案,计算成((100+50)-38)-70 ,当然得出结果为 42。

一个小细节:在term 的动作中,变量number 保存了一个TokenInfo 对象,因此该动作必须使用其.string 属性来获取字符串形式的标识符。

当一个备选项中多次出现相同的规则名称时,我们该怎么办?对同一备选项中出现的规则,解析器生成器会给出唯一的名称,即在随后出现的规则上添加 1、2 等等。例如:

factor: atom '**' atom { atom ** atom1 }
| atom { atom }

它的实现很无聊,所以我请你们 check out 代码 ,自己看看。试试这个:

python3.8 -m story5.driver story5/calc.txt -g story5.calc.CalcParser

可视化功能现在支持使用左右箭头键来回移动!

本文内容与示例代码的授权协议:CC BY-NC-SA 4.0

公众号【Python猫】, 本号连载优质的系列文章,有喵星哲学猫系列、Python进阶系列、好书推荐系列、技术写作、优质英文推荐与翻译等等,欢迎关注哦。

Python 之父的解析器系列之六:给 PEG 语法添加动作的更多相关文章

  1. Python 之父的解析器系列之七:PEG 解析器的元语法

    原题 | A Meta-Grammar for PEG Parsers 作者 | Guido van Rossum(Python之父) 译者 | 豌豆花下猫("Python猫"公众 ...

  2. Python 之父的解析器系列之五:左递归 PEG 语法

    原题 | Left-recursive PEG grammars 作者 | Guido van Rossum(Python之父) 译者 | 豌豆花下猫("Python猫"公众号作者 ...

  3. Python 之父的解析器系列之三:生成一个 PEG 解析器

    原题 | Generating a PEG Parser 作者 | Guido van Rossum(Python之父) 译者 | 豌豆花下猫("Python猫"公众号作者) 声明 ...

  4. Python爬虫——使用 lxml 解析器爬取汽车之家二手车信息

    本次爬虫的目标是汽车之家的二手车销售信息,范围是全国,不过很可惜,汽车之家只显示100页信息,每页48条,也就是说最多只能够爬取4800条信息. 由于这次爬虫的主要目的是使用lxml解析器,所以在信息 ...

  5. 语法解析器续:case..when..语法解析计算

    之前写过一篇博客,是关于如何解析类似sql之类的解析器实现参考:https://www.cnblogs.com/yougewe/p/13774289.html 之前的解析器,更多的是是做语言的翻译转换 ...

  6. 非标准的xml解析器的C++实现:二、解析器的基本构造:语法表

    解析器的目的:一次从头到尾的文本遍历,文本数据 转换为 xml节点数据. 这其实是全世界所有编程语言编译或者转换为虚拟代码的基础,学会这种方法,发明一种编程语言其实只是时间问题,当然了,时间也是世界上 ...

  7. Python模块:配置文件解析器configparser

    版权声明:本文为博主皮皮http://blog.csdn.net/pipisorry原创文章,未经博主同意不得转载. https://blog.csdn.net/pipisorry/article/d ...

  8. Python之父新发文,将替换现有解析器

    花下猫语: Guido van Rossum 是 Python 的创造者,虽然他现在放弃了"终身仁慈独裁者"的职位,但却成为了指导委员会的五位成员之一,其一举一动依然备受瞩目.近日 ...

  9. Python爬虫零基础入门(系列)

    一.前言上一篇演示了如何使用requests模块向网站发送http请求,获取到网页的HTML数据.这篇来演示如何使用BeautifulSoup模块来从HTML文本中提取我们想要的数据. update ...

随机推荐

  1. Netty学习(十)-Netty文件上传

    今天我们来完成一个使用netty进行文件传输的任务.在实际项目中,文件传输通常采用FTP或者HTTP附件的方式.事实上通过TCP Socket+File的方式进行文件传输也有一定的应用场景,尽管不是主 ...

  2. 2月9日 《Java 8实战》读后感

    第一部分 基础知识 第3章 Lambda表达式 使用函数式接口 Predicate Consumer Function 第二部分 函数式数据处理 第4章 引入流 第5章 使用流 第6章 用流收集数据 ...

  3. [Spring cloud 一步步实现广告系统] 17. 根据流量类型查询广告

    广告检索服务 功能介绍 媒体方(手机APP打开的展示广告,走在路上看到的大屏幕广告等等) 请求数据对象实现 从上图我们可以看出,在媒体方向我们的广告检索系统发起请求的时候,请求中会有很多的请求参数信息 ...

  4. Logback配置文件这么写,TPS提高10倍

    通过阅读本篇文章将了解到 1.日志输出到文件并根据LEVEL级别将日志分类保存到不同文件 2.通过异步输出日志减少磁盘IO提高性能 3.异步输出日志的原理 配置文件logback-spring.xml ...

  5. java 计算器

    初识java:利用swing制作一个简单的计算器,仿造window10内置计算器标准模式下的界面. 涉及学习内容: 设置窗口 设计界面按键 设置文本框:只读 String字符串操作:与double类型 ...

  6. tomcat启动nio,apr详解以及配置

    tomcat启动nio,apr详解以及配置 前言 在正文开始之前,我们先在idea工具中看看启动的信息,顺便看下启动的基本信息 在这里插入图片描述可以看到信息有tomcat版本操作系统版本java版本 ...

  7. ubuntu安装后的基本配置及常用软件的安装

    文章作者:foochane  原文链接:https://foochane.cn/article/2019061501.html 内容简介 当前Ubuntu版本:ubuntu 18.04,具体操作如下: ...

  8. python 25 类的成员

    目录 1. 类的私有成员 -- __ 1.1 类的私有静态属性 1.2 类的私有方法 1.3 对象的私有方法 2. 类的其他方法 2.1 类方法 @classmethod 2.2 静态方法 @stat ...

  9. Python Web Flask源码解读(一)——启动流程

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

  10. 11 python与redis交互

    安装:pip install redis 导入模块:from redis import * 创建StrictRedis 通过init创建对象,指定参数host.port与指定的服务器和端口连接. ho ...