Parboiled概述

Parboiled是一个混合的Java/ Scala库,提供了基于解析表达文法(PEGs)的轻量级、易用、功能强大的任意输入文本解析。

图形数据库Neo4j使用Parboiled解析查询语言Cypher。

特点

  1. 用户可以以某种方式指定解析语法,并使它快速,轻松地工作。
  2. 解析表达式语法的强大表达能力
  3. 支持强大而灵活的解析器操作
  4. 出色的解析错误报告和恢复
  5. 良好的性能
  6. 易于集成
  7. 轻量级,易于使用

Parboiled提供了递归下降PEG解析器的实现,该实现可对用户指定的PEG规则进行操作。

解析表达文法(PEG)

以纯公式的形式展现递归下降解析器的基础语法,对这个具体的解析器采用的实现方法没有限定。

与上下文无关文法(CFG)很像,但存在区别:

  1. PEG不存在二义性,只产生一个确定的语法分析树。
  2. PEG的选择操作符是有序的。如果第一个可能成功了,那么第二个可能就忽略。

文法的组成部分:

  • 一个有限的非终结符的集合
  • 一个有限的终结符的集合,和没有交集
  • 一个有限的解析规则的集合
  • 一个被称为起点表达式的解析表达式

中每一个解析规则以的形式出现,这里是一个非终结符,是一个解析表达式。解析表达式是类似正则表达式的层次表达式。

原子解析表达式

  • 任何的非终结符
  • 任何的终结符
  • 空字符串

解析表达式操作符

优点

  1. PEG更加严格更加强大,可以很好地成为正则表达式的替代品。
  2. PEG不存在二义性。

缺点

  1. PEG不能表达左递归的解析规则。
  2. 未能被广泛应用。

使用Parboiled的两个阶段

  • 规则构建

以Parboiled的方式构建解析器规则的树 / 有向图。该阶段与实际的输入无关,且构建的规则树可重用。

从BaseParser派生一个自定义的类,并定义返回Rule实例的方法。这些方法从其他规则、终端、预定义原语和动作表达式构建规则实例。对于Java,Parboiled采用了一种“解析器扩展”的过程来更加简洁地构造代码。

  • 规则执行

为了使解析器不仅仅是一个“识别器”(确定给定的输入是否符合语法定义的程序)。解析器需要包含解析器操作,即在规则执行期间的特定执行点的自定义代码片段。除了检查解析器状态以外,解析器操作通常还会构造解析器“值”,并且可以作为语义谓词影响解析过程。

规则针对特定的输入文本运行。该阶段的最终结果将得到以下信息:

  1. 确定输入是否匹配根规则的布尔标志
  2. 可能遇到的错误信息列表
  3. 由解析器操作构造一个或多个值的对象

值栈(The Value Stack)

在规则执行阶段,解析器操作可以利用值栈来组织AST(抽象语法树)节点等自定义对象的构造。值栈通常用作自定义对象的临时存储。

解析树(The Parse Tree)

在规则执行阶段,Parboiled可以选择构造一个解析树,其节点与识别的规则相对应。每个解析树的节点都包含一个对它的构造规则的匹配器的引用、匹配的输入文本位置和位于值栈顶部的当前元素。解析树可用来查看哪些规则已匹配给定输入,在调试期间很有用。

ParseRunner

负责监督解析运行并可选地应用额外的逻辑,最重要的是可以根据语法处理非法输入字符,即解析错误。

以下是ParserRunner的五个预定义的解析器:

  1. BasicParseRunner:不执行错误处理。(速度最快)
  2. ReportingParseRunner:为输入中的第一个分析错误创建一个适当的InvalidInputError对象
  3. RecoveringParseRunner:报告输入中所有的错误信息,并尝试恢复。(最复杂)
  4. TracingParseRunner:有选择地为每个匹配或不匹配的规则打印跟踪语句
  5. 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学习(一)相关推荐

  1. python 视频下载神器(you-get) 的安装和用法

    0x01 安装 pip3 install you-get $ pip3 install --upgrade you-get 命令行输入you-get 如果有以下回显说明安装成功 0x02 用法 Usa ...

  2. 程序员优秀学习资料整理(不断更新中)

    如果你发现自己陷入各种新技术.工具包围中,而纠结于该选择哪些学习,读读这篇文章,技术的执念. 综合资源 资源链接汇集 awesome - 各种主流语言的优秀项目汇集 :+1: lists - 资源集合 ...

  3. java入门 慕路径,Java入门基础知识总结学习教程大全【必看经典】

    类型的表达式,是循环条件,表达式3是党执行了一遍循环之后,修改控制循环的变量值. ??? for语句的执行过程是这样的:首先计算表达式1,完成必要的初始化工作:然后判断表达式2的值,如果表达式的值为t ...

  4. Java EE学习心得

    –Java EE学习心得   1.    称为编程专家的秘诀是: 思考-----编程--------思考------编程--.. 编程不能一步到位,不能一上来就编,必须先思考如何写,怎样写?然后再编程 ...

  5. FastAI 2019课程学习笔记 lesson 2:自行获取数据并创建分类器

    文章目录 数据获取 google_images_download 的安装和使用 挂载google 个人硬盘到Google colab中 删除不能打开文件 创建ImageDataBunch 训练模型 解 ...

  6. FastAI 课程学习笔记 lesson 1:宠物图片分类

    文章目录 代码解析 神奇的"%" 导入fastAI 库 下载解压数据集 untar_data 获取帮助文档 help() ? ?? doc 设置路径 get_image_files ...

  7. 深度学习学习指南-工具篇

    colab Colab是由Google提供的云计算服务,通过它可以让开发者很方便的使用google的免费资源(CPU.GPU.TPU)来训练自己的模型. 学习经验总结 如何使用命令行? 通过!+cmd ...

  8. Redis学习之路(一)--下载安装redis

    redis学习之路--下载安装redis windows安装redis 1.下载redis 2.安装 3.查看是否安装成功 windows安装redis 1.下载redis 网址:https://gi ...

  9. python内置库之学习configparser库(一)

    python内置库之学习configparser库(一) 1.引言 ini文件简介 [节] 键=值 注:节不能重复出现 2.自己封装了一个增删改查的类,可以参考一下 import configpars ...

最新文章

  1. MySQL数据类型--------字符串类型实战
  2. 皮一皮:这解释...没毛病!
  3. Opengl-几何着色器(劫持顶点的家伙)
  4. ZOJ 3829 贪心 思维题
  5. layui-概念-入门-总结
  6. Qt界面设计器中的界面预览与程序运行时界面不一样
  7. java大数输出一位小数_java大数练习 大明A+B(大数小数的高精度)
  8. 微课|中学生可以这样学Python(2.3.4节):例2-1
  9. 面向对象chapter10
  10. 组策略复制失败排错思路实例
  11. pytorchgpu测试_pytorch学习(十)—训练并测试CNN网络
  12. threadx系统_实时操作系统(RTOS)市场简报
  13. Eclipse.org上Git已经超越了CVS与SVN
  14. Spring的IoC容器实现原理(一)#loadBeanDefinition
  15. linux安装文件密码,linux安装包PGP加密验证
  16. 软件工程师为什么单身的六宗罪
  17. jsp打印去掉页眉页脚
  18. 新一代SSD接口来了 | M.2接口发福版?
  19. 3.2 电话号码对应英语单词
  20. 阿里云天池AI龙珠计划-Python训练营学习笔记task1

热门文章

  1. 趣图:不得了,日本出版社是这样吸引死宅们学编程的
  2. 没有团员证,怎么查询入团时间?
  3. Latex模版以及经验汇总
  4. 抽象数据类型:复数COMPLEX
  5. RC523读TypeB卡-----读B卡的天线调制过程
  6. uniapp实现音频播放抢占系统音频焦点
  7. 微型计算机的集成在微,微型计算机的( )集成在微处理器芯片上。
  8. 拼多多上货助手如何批量抓取商品上传?
  9. (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  10. C++ 基础之公有、私有和保护(一句话说清楚)