一个完整的语法分析、词法分析例子——Universal Pasrser

2023-11-04

需求:用户用formal notation指定语法、词法,然后可以匹配相应的文本。用法类似正则表达式,只需给出formal notation,不需要为每一种格式的文本单独写匹配器。

formal notation主要是3个部分:

1)BNF 列表 table:给出上下文无关文法的产生式规则,以及所有的符号(终端和非终端)

2)起始符号 start

3)终端符号Regular Expression Table:用RE给出每个终端符号的匹配规则

其中BNF目前只接受left factor过的,去左递归的上下文无关文法。


关于空格的处理有3种方式,本案采用第2种:

1)作为文法的一部分:

<SPACE> --> S*

<E> --> <SPACE> <E> <SPACE> + <SPACE>  <E> <SPACE>

2)作为terminal symbol的一部分

对每个terminal symbol的regular expression做处理,两头加上匹配空白的规则 re = "\\s+" + re + "\\s+"

3)如果不是用正则表达式匹配终端符号,而是自己写term(TOKEN type)函数

对于空格,skip掉就可以了


文法匹配就是 top down的 recursive descend 算法,

1)对于当前符号,如果是终结符号,到终结符号RE表找到对应的RE做匹配,匹配成功要把指针移动到后一个位置。

2)如果是非终结符号,尝试每个production, 直到某个production成功。(left factor 保证只有一个production是可行的),注意epsilon production放到最后。


下一步工作:

1)支持没有进行left factor的文法。现在是一个production失败了才回溯尝试下一个production。一般的情况是,一个符号V即使走某条production成功匹配了,但有可能导致V后面的符号无法匹配成功,这时候也要回溯,尝试V的别的production。

2)自动消除左递归,这样用户只需要自然的写BNF就行了

package excercise;
import java.util.*;
import java.util.regex.*;
class CFG {
	private Map<String, List<String[]>> BNF;
	private Map<String, String> termRegex;
	private String start, text;
	private int i = 0;
	public CFG(Map<String, List<String[]>> productions, String start, Map<String, String> termRegex) {
		this.BNF = productions;
		this.termRegex = termRegex;
		this.start = start;
	}
	public boolean recognize(String text) {
		this.text = text;
		return match(start) && i == text.length();
	}
	private boolean match(String V) {
		if (V.isEmpty()) return true; //epsilon
		List<String[]> production = BNF.get(V);
		if (production == null) { //no production for this symbol, should be terminal symbol
			String re = termRegex.get(V); //get the regex for this terminal symbol
			if (re == null) throw new RuntimeException("invalid CFG.");
			re = "\\s*" + re + "\\s*";
			Pattern pattern = Pattern.compile(re);
			Matcher matcher = pattern.matcher(text);
			if (matcher.find(i) && matcher.start() == i) {
				i = matcher.end();
				return true;
			}
			return false;
		}
		//try each production. if one matches, succeed, or recover the pointer and try next.
		int save = i;
		for (String[] p : production) {
			boolean flag = true;
			i = save;
			for (String T : p) {
				if (!match(T)) {
					flag = false;
					break; 
				}
			}
			if (flag) {
				System.out.println(V + "->" + String.join(" ", p));
				return true;
			}
		}
		return false;
	}
	public static void main(String[] args) {
	//1) E -> TE'
	//2) E'-> +TE' | -TE' | e
	//3) T -> FT'
	//3) T'-> *FT' | /FT' | e
	//4) F -> int | (E)
		//specify the BNF table, should be left factored, left recursion removed
		Map<String, List<String[]>> BNF = new HashMap<String, List<String[]>>();
		List<String[]> pE = new ArrayList<String[]>();
		pE.add(new String[]{"T", "EA"});
		BNF.put("E", pE);
		List<String[]> pEA = new ArrayList<String[]>();
		pEA.add(new String[]{"+", "T", "EA"});
		pEA.add(new String[]{"-", "T", "EA"});
		pEA.add(new String[]{""});
		BNF.put("EA", pEA);
		List<String[]> pT = new ArrayList<String[]>();
		pT.add(new String[]{"F", "TA"});
		BNF.put("T", pT);
		List<String[]> pTA = new ArrayList<String[]>();
		pTA.add(new String[]{"*", "F", "TA"});
		pTA.add(new String[]{"/", "F", "TA"});
		pTA.add(new String[]{""});
		BNF.put("TA", pTA);
		List<String[]> pF = new ArrayList<String[]>();
		pF.add(new String[]{"INT"});
		pF.add(new String[]{"(", "E", ")"});
		BNF.put("F", pF);
		
		//specify terminal symbol regular expression table
		Map<String, String> termRegex = new HashMap<String, String>();
		termRegex.put("+", "\\+");
		termRegex.put("-", "\\-");
		termRegex.put("*", "\\*");
		termRegex.put("/", "/");
		termRegex.put("(", "\\(");
		termRegex.put(")", "\\)");
		termRegex.put("INT", "[0-9]");
		
		CFG cfg = new CFG(BNF, "E", termRegex);
		boolean b = cfg.recognize("(1 + 1)*2");
		System.out.println(b);
	}
}





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一个完整的语法分析、词法分析例子——Universal Pasrser 的相关文章

  • 区块链技术对金融行业有什么冲击?

    区块链技术在经过了长达十年的发展 被越来越多的行业关注 特别是一些大型企业 对区块链技术还进行了深入的研究 区块链技术也在更多的领域被应用 区块链技术的热度虽然很高 但目前的发展还处在初级阶段 其过多的应用场景也是没有得到更大的发展 区块链
  • 蓝桥杯练习系统入门水题

    好几天没写代码了 上蓝桥杯的练习系统看了一下 做了四道巨水题之后发现有些题还要vip 无语 问题描述 Fibonacci数列的递推公式为 Fn Fn 1 Fn 2 其中F1 F2 1 当n比较大时 F
  • (计算机组成原理)指令的寻址方式

    指令寻址方式是指指令或者操作数有效地址的寻找方式 主要分为数据寻址和指令寻址 指令的地址码字段往往并不是操作数的真实地址 而是形式地址 用A表示 A 即操作数形式地址所指向的存储介质的数值 用形式地址结合指令的寻址方式可以计算出操作数的真实

随机推荐

  • 快速调整毕业论文格式:调整参考文献的引用样式和段落格式

    在撰写毕业论文的过程 我们需要参考并引用大量的参考文献 之前有介绍了如何在Word中使用Endnote插入参考文献 但是从Endnote样式网站下载的样式可能和学校要求的参考文献的引用格式和段落样式有些出入 我们需要根据需求在下载样式上进行
  • 二叉树 Binary Tree

    二叉树 二叉树的基本概念 1 什么是二叉树 2 二叉树的优点和缺点 3 二叉树的基本名词 4 二叉树的性质 5 特别的二叉树 满二叉树 Full Binary Tree 完全二叉树 Complete Binary Tree 平衡二叉树 Ba
  • 【C++】多态

    文章目录 1 多态的基本概念 2 动态联编和静态联编 2 多态的原理剖析 3 计算器案例 4 抽象类与纯虚函数 5 虚析构和纯虚析构函数 6 向上类型转换和向下类型转换 1 多态的基本概念 多态性提法接口和具体实现之间的另一层隔离 多态改善
  • 计算机硬件结构简略介绍

    前言 计算机硬件结构简略介绍 一 计算机硬件 从软件开发者的角度来看 计算机硬件有三个部件最为关键 分别是中央处理器CPU 内存 I O控制芯片 二 早期 早期计算机 CPU的核心频率不高 和内存的频率一样 他们都是直接连接在同一个总线 b
  • 面试之设计模式(简单工厂模式)

    案例 在面试时 面试官让你通过面对对象语言 用Java实现计算器控制台程序 要求输入两个数和运算符号 得出结果 大家可能想到是如下 public static void main String args Scanner scanner ne
  • GDB print 详解

    GDB print 详解 分类 Linux GDB 2013 04 08 11 07 145人阅读 评论 0 收藏 举报 Linux GDB 察看变量 目录 print命令的格式是 print xxx p xxx 1 print 操作符 是
  • 请说出三种减少页面加载时间的方法

    1 尽量减少页面中重复的HTTP请求数量 2 服务器开启gzip压缩 3 css样式的定义放置在文件头部 4 Javascript脚本放在文件末尾 5 压缩合并Javascript CSS代码 6 使用多域名负载网页内的多个文件 图片
  • 在Windows 11 中安装和使用 WSL 2

    文章目录 列出可安装的发行版 分发 安装WSL 2 常用命令 显示帮助 启动分发 从powershell中退出分发 关闭正在运行的分发 立即终止所有正在运行的分发和 WSL 2轻型虚拟机 更新wsl 使用VSCode连接WSL 设置代理 换
  • QEMU-从buildroot里面编译kernel(7)

    上面是我的微信和QQ群 欢迎新朋友的加入 下载交叉编译工具 https snapshots linaro org gnu toolchain 选一个最新的 选择压缩包 解压 sudo apt get install g sudo mv gc
  • 网狐棋牌:数据库

    jeefwtwo 账号数据库 QPAccountsDB 账号账号数据库 QPGamescoreDB 游戏积分数据库 QPGameMatchDB 比赛数据库 QPPlatformDB 平台数据库 QPRecordDB 记录数据库 QPTrea
  • vue-video-player基本使用

    下载 npm install vue video player 如果不使用vue的话 可以直接去官网 或者cdn获取对应js即可 在vue中的基本使用 main js中 全局 import Vue from vue import VueVi
  • 线程与进程的对比、互斥锁和条件变量的使用-多线程编程

    线程与进程的对比 线程的概念是共享CPU的需要 进程概念是共享内存的需要 一个进程里代码段 数据段 堆是共享的 但是进程中的每个线程中的栈 寄存器内容独立 进程都是独立的 通常的IPC 管道 共享内存都可以通讯 处于一个线程的代码觉得它拥有
  • Redis基础知识(二):事务机制

    文章目录 一 什么是事务机制 二 Redis模式下如何实现事务机制 2 1 显式开启一个事务 2 2 将命令入队列Queue 2 3 执行事务或丢弃 2 4 EXEC命令执行示例 2 5 DISCARD命令 放弃事务 2 6 因为命令错误导
  • RabbitMQ用途及问题

    转自 https blog csdn net u013871100 column info 27053 1 用途 1 解耦 系统A在代码中直接调用系统B和系统C的代码 如果将来D系统接入 系统A还需要修改代码 过于麻烦 2 异步 将消息写入
  • ROS学习笔记(五)---话题发布

    1 话题通信是什么 在ROS 机器人操作系统 中 话题通信是一种常用的通信机制 用于在不同的ROS节点之间传递消息 话题通信基于发布者 订阅者模式 其中一个节点 发布者 发布消息到一个特定的话题 而其他节点 订阅者 可以订阅该话题以接收消息
  • 一篇文章让你深入了解RGB数据格式和互转(YUV数据组成)

    我们日常看到的图片 视频由RGB或YUV数据组成 说明 1 RGB分为RGB16 RGB24 RGB32 RGB RGB16 RGB24 RGB32 一 RGB分RGB16 RGB24 RGB32 1 RGB16格式分为RGB565 RGB
  • 某市财政收入预测分析:GM模型+神经网络

    from numpy random import seed seed 1 import tensorflow tensorflow random set seed 2 import numpy as np import pandas as
  • openssl生成椭圆曲线的私钥是如何做到每次不同的?

    目录 例子 排查 随机算法 小结 例子 生成一个私钥只需要3步 1 获得指定曲线的group 如比特币的secp256k1 2 group和key绑定 3 用key来生成私钥 先上一段代码例子 key1 EC KEY new if key1
  • 2021.11.9

    把数据结构 第一章的课后写了一下 有点难哎 第二章的1 12题 对空间复杂度有了进一步的了解 假设法和最深层语句执行次数 但是涉及到 log 什么的我就不咋会了 如何去设计一个抽象数据类型 基本能将算法的功能看出来 如何设置更加高效的算法
  • 一个完整的语法分析、词法分析例子——Universal Pasrser

    需求 用户用formal notation指定语法 词法 然后可以匹配相应的文本 用法类似正则表达式 只需给出formal notation 不需要为每一种格式的文本单独写匹配器 formal notation主要是3个部分 1 BNF 列