Parboiled学习(一)
Parboiled概述
Parboiled是一个混合的Java/ Scala库,提供了基于解析表达文法(PEGs)的轻量级、易用、功能强大的任意输入文本解析。
图形数据库Neo4j使用Parboiled解析查询语言Cypher。
特点
- 用户可以以某种方式指定解析语法,并使它快速,轻松地工作。
- 解析表达式语法的强大表达能力
- 支持强大而灵活的解析器操作
- 出色的解析错误报告和恢复
- 良好的性能
- 易于集成
- 轻量级,易于使用
Parboiled提供了递归下降PEG解析器的实现,该实现可对用户指定的PEG规则进行操作。
解析表达文法(PEG)
以纯公式的形式展现递归下降解析器的基础语法,对这个具体的解析器采用的实现方法没有限定。
与上下文无关文法(CFG)很像,但存在区别:
- PEG不存在二义性,只产生一个确定的语法分析树。
- PEG的选择操作符是有序的。如果第一个可能成功了,那么第二个可能就忽略。
文法的组成部分:
- 一个有限的非终结符的集合
- 一个有限的终结符的集合
,和
没有交集
- 一个有限的解析规则的集合
- 一个被称为起点表达式的解析表达式
中每一个解析规则以
的形式出现,这里
是一个非终结符,
是一个解析表达式。解析表达式是类似正则表达式的层次表达式。
原子解析表达式
- 任何的非终结符
- 任何的终结符
- 空字符串
解析表达式操作符
优点
- PEG更加严格更加强大,可以很好地成为正则表达式的替代品。
- PEG不存在二义性。
缺点
- PEG不能表达左递归的解析规则。
- 未能被广泛应用。
使用Parboiled的两个阶段
规则构建
以Parboiled的方式构建解析器规则的树 / 有向图。该阶段与实际的输入无关,且构建的规则树可重用。
从BaseParser派生一个自定义的类,并定义返回Rule实例的方法。这些方法从其他规则、终端、预定义原语和动作表达式构建规则实例。对于Java,Parboiled采用了一种“解析器扩展”的过程来更加简洁地构造代码。
规则执行
为了使解析器不仅仅是一个“识别器”(确定给定的输入是否符合语法定义的程序)。解析器需要包含解析器操作,即在规则执行期间的特定执行点的自定义代码片段。除了检查解析器状态以外,解析器操作通常还会构造解析器“值”,并且可以作为语义谓词影响解析过程。
规则针对特定的输入文本运行。该阶段的最终结果将得到以下信息:
- 确定输入是否匹配根规则的布尔标志
- 可能遇到的错误信息列表
- 由解析器操作构造一个或多个值的对象
值栈(The Value Stack)
在规则执行阶段,解析器操作可以利用值栈来组织AST(抽象语法树)节点等自定义对象的构造。值栈通常用作自定义对象的临时存储。
解析树(The Parse Tree)
在规则执行阶段,Parboiled可以选择构造一个解析树,其节点与识别的规则相对应。每个解析树的节点都包含一个对它的构造规则的匹配器的引用、匹配的输入文本位置和位于值栈顶部的当前元素。解析树可用来查看哪些规则已匹配给定输入,在调试期间很有用。
ParseRunner
负责监督解析运行并可选地应用额外的逻辑,最重要的是可以根据语法处理非法输入字符,即解析错误。
以下是ParserRunner的五个预定义的解析器:
- BasicParseRunner:不执行错误处理。(速度最快)
- ReportingParseRunner:为输入中的第一个分析错误创建一个适当的InvalidInputError对象
- RecoveringParseRunner:报告输入中所有的错误信息,并尝试恢复。(最复杂)
- TracingParseRunner:有选择地为每个匹配或不匹配的规则打印跟踪语句
- ProfilingParseRunner:产生关于解析器如何处理一个或多个输入
Parboiled for Java
安装
jdk 1.8
parboiled-core-1.3.1.jar
asm-all-5.2.jar
Maven配置
<dependency><groupId>org.parboiled</groupId><artifactId>parboiled-java</artifactId><version>1.1.8</version>
</dependency>
具体步骤
1. 决定使用哪种类型V来参数化解析器value栈,并创建一个从BaseParser派生的自定义解析器类使用返回类型规则添加一个或多个规则方法。
2. 通过调用Parboiled.createParser来创建解析器的实例。
3. 调用语法分析器的规则方法,该方法构建语法的根规则来创建规则树。
4. 选择一个标准的ParseRunner实现,并调用它的“run”方法来传递根规则和要解析的输入文本。
5. 检查返回的ParsingResult对象的不同成员。
示例:AbcParser
AbcParser算法能够描述经典的非上下文无关文法
。
AbcParser.java
package com.parboiledlearn.demo;import org.parboiled.BaseParser;
import org.parboiled.Rule;
import org.parboiled.annotations.BuildParseTree;/*** S <- &(A c) a+ B !(a|b|c)* A <- a A? b* B <- b B? c*/@SuppressWarnings({"InfiniteRecursion"})
@BuildParseTreepublic class AbcParser extends BaseParser<Object> {public Rule S() {return Sequence(Test(A(), 'c'),OneOrMore('a'),B(),TestNot(AnyOf("abc")));}public Rule A() {return Sequence('a', Optional(A()), 'b');}public Rule B() {return Sequence('b', Optional(B()), 'c');}
}
AbcMain.java
package com.parboiledlearn.demo;import org.parboiled.Parboiled;
import org.parboiled.common.StringUtils;
import org.parboiled.errors.ErrorUtils;
import static org.parboiled.support.ParseTreeUtils.printNodeTree;
import org.parboiled.parserunners.ReportingParseRunner;
import org.parboiled.support.ParsingResult;
import java.util.Scanner;public class AbcMain {public static void main(String[] args) {AbcParser parser = Parboiled.createParser(AbcParser.class);while (true) {System.out.print("Enter an a^n b^n c^n expression (single RETURN to exit)!\n");String input = new Scanner(System.in).nextLine();if (StringUtils.isEmpty(input)) break;ParsingResult<?> result = new ReportingParseRunner(parser.S()).run(input);if (!result.parseErrors.isEmpty())System.out.println(ErrorUtils.printParseError(result.parseErrors.get(0)));elseSystem.out.println(printNodeTree(result) + '\n');}}
}
运行结果
对于无效输入,ReportingParseRunner会报告第一个错误位置。
参考资料:
https://github.com/sirthias/parboiled/wiki
https://zh.wikipedia.org/wiki/%E8%A7%A3%E6%9E%90%E8%A1%A8%E8%BE%BE%E6%96%87%E6%B3%95
Parboiled学习(一)相关推荐
- python 视频下载神器(you-get) 的安装和用法
0x01 安装 pip3 install you-get $ pip3 install --upgrade you-get 命令行输入you-get 如果有以下回显说明安装成功 0x02 用法 Usa ...
- 程序员优秀学习资料整理(不断更新中)
如果你发现自己陷入各种新技术.工具包围中,而纠结于该选择哪些学习,读读这篇文章,技术的执念. 综合资源 资源链接汇集 awesome - 各种主流语言的优秀项目汇集 :+1: lists - 资源集合 ...
- java入门 慕路径,Java入门基础知识总结学习教程大全【必看经典】
类型的表达式,是循环条件,表达式3是党执行了一遍循环之后,修改控制循环的变量值. ??? for语句的执行过程是这样的:首先计算表达式1,完成必要的初始化工作:然后判断表达式2的值,如果表达式的值为t ...
- Java EE学习心得
–Java EE学习心得 1. 称为编程专家的秘诀是: 思考-----编程--------思考------编程--.. 编程不能一步到位,不能一上来就编,必须先思考如何写,怎样写?然后再编程 ...
- FastAI 2019课程学习笔记 lesson 2:自行获取数据并创建分类器
文章目录 数据获取 google_images_download 的安装和使用 挂载google 个人硬盘到Google colab中 删除不能打开文件 创建ImageDataBunch 训练模型 解 ...
- FastAI 课程学习笔记 lesson 1:宠物图片分类
文章目录 代码解析 神奇的"%" 导入fastAI 库 下载解压数据集 untar_data 获取帮助文档 help() ? ?? doc 设置路径 get_image_files ...
- 深度学习学习指南-工具篇
colab Colab是由Google提供的云计算服务,通过它可以让开发者很方便的使用google的免费资源(CPU.GPU.TPU)来训练自己的模型. 学习经验总结 如何使用命令行? 通过!+cmd ...
- Redis学习之路(一)--下载安装redis
redis学习之路--下载安装redis windows安装redis 1.下载redis 2.安装 3.查看是否安装成功 windows安装redis 1.下载redis 网址:https://gi ...
- python内置库之学习configparser库(一)
python内置库之学习configparser库(一) 1.引言 ini文件简介 [节] 键=值 注:节不能重复出现 2.自己封装了一个增删改查的类,可以参考一下 import configpars ...
最新文章
- MySQL数据类型--------字符串类型实战
- 皮一皮:这解释...没毛病!
- Opengl-几何着色器(劫持顶点的家伙)
- ZOJ 3829 贪心 思维题
- layui-概念-入门-总结
- Qt界面设计器中的界面预览与程序运行时界面不一样
- java大数输出一位小数_java大数练习 大明A+B(大数小数的高精度)
- 微课|中学生可以这样学Python(2.3.4节):例2-1
- 面向对象chapter10
- 组策略复制失败排错思路实例
- pytorchgpu测试_pytorch学习(十)—训练并测试CNN网络
- threadx系统_实时操作系统(RTOS)市场简报
- Eclipse.org上Git已经超越了CVS与SVN
- Spring的IoC容器实现原理(一)#loadBeanDefinition
- linux安装文件密码,linux安装包PGP加密验证
- 软件工程师为什么单身的六宗罪
- jsp打印去掉页眉页脚
- 新一代SSD接口来了 | M.2接口发福版?
- 3.2 电话号码对应英语单词
- 阿里云天池AI龙珠计划-Python训练营学习笔记task1