ANTLR4(十三)解决歧义性总结
写在之前
之前我们已经通过两个例子尝试着解决过歧义性的问题:
运算符优先性
我们通过语法分析器
优先匹配靠前的规则
这一准则,将乘法设置在加法规则之前,来解决这个问题。
但问题是,这种优先性的歧义是在语法分析树遍历
时产生的,如果我们在词法分析
或者语法分析
过程就遇到歧义的规则呢?词法分析时的歧义
在Keywords.g4中,我们设置了IF、WHILE等多个
关键字
。但在词法分析
过程中,它们会与ID:[a-zA-z]
这种常见的标识符
词法规则产生歧义。后来我们通过在ID规则的内嵌动作中多添加了一次判定,判定ID是否为关键字
,是的话将ID类型
换成对应的关键字类型
,再进行文法规则匹配。ID: [a-zA-Z]+ {if(keywords.containsKey(getText())){setType(keywords.get(getText()));}};
词法分析时的歧义改进版
在之前的词法分析歧义中,我们通过在词法分析器中加入map< 关键字,Token类型 >
的方式,在ID的词法分析中检测有无
已存的关键字,并将该关键字的类型从ID
转换成关键字Token
类型。
T__0=1
T__1=2
ID=3
CHAR=4
INT=5
WS=6
BEGIN=7
END=8
IF=9
THEN=10
WHILE=11
'='=1
';'=2
我们可以看到,由于BEGIN、END、IF、THEN、WHILE是通过tokens{}
的方式添加的,因此在显式的词法规则之后。而=
和;
是在文法规则中隐式添加的,其类型排在最前面。
接下来我们将介绍如何去掉这些内嵌动作和预成员,直接通过隐式的先后顺序
解决词法歧义性。
预想效果
来看一下一个让人头疼的输入吧:
if if then call call;
我们想让第一个if匹配成关键字,第二个if匹配成标识符,第一个call匹配成关键字,第二个call匹配成标识符。
语法文件
让我们来看看做了什么。
if
then
call
直接在文法规则stat中出现了,这意味着它们隐式地生成了token。让我们看看tokens表:
T__0=1
T__1=2
T__2=3
T__3=4
ID=5
WS=6
'if'=1
'then'=2
'call'=3
';'=4
果然它们的类型在显式词法规则之前了。接下去我们观察id,它包含了3个隐式token和1个词法规则。
id : 'if' | 'call' | 'then' | ID ;
这意味着“if”
、"then"
、“call”
从ID规则中剥离
了出来,lexer
会把它们单独的作为token类型
来看,而且还在ID标识符token类型之前。
由于ANTLR4的分析顺序为 字符输入流->词法分析->tokens流->语法分析,这几个关键字token类型会提前被匹配。
grammar IDKeyword;prog: stat+ ;stat: 'if' expr 'then' stat| 'call' id ';'| ';';expr: id ;id : 'if' | 'call' | 'then' | ID ;ID : [a-z]+ ;
WS : [ \r\n]+ -> skip ;
运行结果
语法分析时的歧义
接下来我们通过一个C++中简单的例子来演示如何解决语法分析时的歧义。
语法文件
我们可以发现,decl
规则中的第二条分支和expr
规则中的第三条分支会造成歧义:
比如输入T(i),它会被匹配成T类型的变量声明
,也会被匹配成T函数调用
(i作为实参)。
我们可以通过ANTL4的优先匹配靠前规则
的机制,使得这种歧义总是调用decl规则。
但有时我们也可以通过自定义的方法来精准匹配。
grammar CppStat;stat: decl ';' {System.out.println("decl "+$decl.text);}| expr ';' {System.out.println("expr "+$expr.text);};decl: ID ID // E.g., "Point p"| ID '(' ID ')' // E.g., "Point (p)", same as ID ID;expr: INT // integer literal| ID // identifier| ID '(' expr ')' // function call;ID : [a-zA-Z]+ ;
INT : [0-9]+ ;
WS : [ \t\n\r]+ -> skip ;
自定义布尔判断动作
我们的想法很简单:在进行到decl、expr有歧义的分支之前
,判断它们第一个ID
的内容的实际类型。如果是我们预设的类型,就当作是变量类型,不然就当成函数名。
需要注意的几点:
- 由于是语法分析过程中的歧义,我们只在parser中引进member。
- 我们需要在具体的
歧义分支中找到产生歧义的点
,并在前面通过{}?
的方式,引进一个布尔类型的值
(或者返回布尔类型的方法
)。
grammar PredCppStat;@parser::header{import java.util.*;
}@parser::members{Set<String> types=new HashSet<String>();{types.add("T");}boolean isType(){return types.contains(getCurrentToken().getText());}
}
stat: decl ';' {System.out.println("decl "+$decl.text);}| expr ';' {System.out.println("expr "+$expr.text);};decl: ID ID // E.g., "Point p"| {isType()}? ID '(' ID ')' // E.g., "Point (p)", same as ID ID;expr: INT // integer literal| ID // identifier| {!isType()}? ID '(' expr ')' // function call;ID : [a-zA-Z]+ ;
INT : [0-9]+ ;
WS : [ \t\n\r]+ -> skip ;
运行结果
我们首先输入:
T(i);
语法分析器判断出来是T类型变量的声明。
再输入:
f(i);
由于f并不在我们预设的变量类型里,因此语法分析器判定它是一个函数T的调用。
ANTLR4(十三)解决歧义性总结相关推荐
- Spring学习之旅(二):Bean的高级装配之解决装配歧义性
一:装配的歧义性: 发生原因:装配的接口有多个实现,例如:FirstClass,SecondClass,ThirdClass皆实现了接口SupperClass,当装配SupperCLass时就会出现歧 ...
- 中国人民大学张静:知识图谱融合中歧义性与异质性问题的讨论
⬆⬆⬆ 点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 2020 年 9 月 25 日,在由中国科协主办,清华大学计算机科学与技术系.AI TIME 论道承办的<2020 中国科 ...
- Spring实战之bean重复、指定bean的名字、消除bean的歧义性
Spring实战之bean重复.指定bean的名字.消除bean的歧义性 自动装配的歧义性示例 解决方案 @Primary标示首选bean @Primary注解与@Component注解配合使用 @P ...
- spring自动装配的歧义性
错误提示:Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bea ...
- Spring框架(二) ---- bean的歧义性
自动装配bean时,如果符合条件的bean超过一个,就会出现歧义性,抛出NoUniqueBeanDefinitionException异常,有如下两种方法保证bean的唯一性: 一.使用@Primar ...
- Spring实战(六)自动装配的歧义性
1.Spring进行自动装配时碰到的bean歧义性问题. 在进行自动装配时,只有仅有一个bean匹配所需结果时,才是可行的. 如果不仅仅一个bean能够匹配结果,例如一个接口有多个实现,这种歧义性会阻 ...
- 【计算理论】上下文无关语法 CFG ( CFG 设计示例 | CFG 歧义性 | Chomsky 范式 | 上下文无关语法 转为 Chomsky 范式 )
文章目录 一.上下文无关语法 设计 示例 二.上下文无关语法 的歧义性 三.Chomsky 范式 四.上下文无关语法 转为 Chomsky 范式 五.上下文无关语法 转为 Chomsky 范式 示例 ...
- RN系列之五十三解决Android上图片圆角的终级解决方案
RN上Android画图角有问题,主要存在几种情况 1.随机性,在页面有多图的情况下,偶现有的图需要画圆角的没有画圆角,有的不需要画圆角的确画了圆角 2.画圆角的不规则性,有时候想画10px的圆角,结 ...
- Spring实战(第四版)读书笔记08——处理自动装配的歧义性
1.标示首选的bean 组件扫描方式例子: @Component @Primary public class IceCream implements Dessert {...} Java配置例子: @ ...
最新文章
- Java运行作业控制语言_Java安全——语言本身的设计
- 关于scrollTop为0以及解决方法
- react 逆地理 高德地图_高德地图又出逆天黑科技!全国各大城市模型直接获取...
- CSS学习-网页导航栏
- MATLAB 优化程序【profile简明用法】
- c++ ——第一个MFC界面
- 利用Tushare合成期货主力连续数据
- VideoEdit+ User Manual
- 随着员工转为远程办公,Diligent在所有董事会管理平台中提供无缝视频会议接入,确保安全的虚拟董事会议
- 专家:苹果手机换电池对系统速度几乎没影响
- Rstudio与R的绑定和更新
- 百万调音师—Audition多轨编辑
- Java 利用Graphics2D 合并图片(png格式可设置透明)
- python3.8与pyinstaller_pyinstaller 3.5 在python 3.8 环境下出现不兼容的问题
- 16g电脑内存有什么好处_电脑内存4G/8G/16G有什么区别?
- 计算机维修工试题及答案,计算机维修工初级工试题和参考答案
- vue官网学习笔记(九)组件基础
- java o2o_全渠道java b2b b2c o2o平台
- 设计模式之-适配器模式
- 清除系统LJ-批处理.bat 源代码