当前位置: 首页 > 知识库问答 >
问题:

Lexer lookahead在ANTLR3和ANTLR4中如何使用贪婪和非贪婪匹配?

咸正平
2023-03-14
KEYWORD: 'keyword' ;

IDENTIFIER
: 
  (options {greedy=false;}: (LOWCHAR|HIGHCHAR))+ 
;

/** lowercase letters */
fragment LOWCHAR
:   'a'..'z';
/** uppercase letters */
fragment HIGHCHAR
:   'A'..'Z';

parse: IDENTIFIER KEYWORD EOF;

基本上,我试图为lexer指定尝试匹配(LOWCHARHIGHCHAR)的非贪婪方式,因此它停止在关键字lookahead。到目前为止,我所读到的关于ANTLR lexer的内容是,应该有某种lexer规则的优先级。如果我在lexer语法中首先指定关键字lexer规则,那么后面的任何lexer规则都不能匹配所使用的字符。

经过一番搜索,我明白了这里的问题是它不能以正确的方式标记输入,因为例如对于输入:“identifierKeyword”,“IDENTIFIER”部分是第一位的,所以它决定在还没有匹配的关键字标记时开始匹配IDENTIFIER规则。

然后我尝试在ANTLR4中编写相同的语法,以测试新的提前运行功能是否能够与我想要的匹配,看起来如下所示:

KEYWORD: 'keyword' ;

/** lowercase letters */
fragment LOWCHAR
:   'a'..'z';
/** uppercase letters */
fragment HIGHCHAR
:   'A'..'Z';

IDENTIFIER
: 
  (LOWCHAR|HIGHCHAR)+?
;

parse: IDENTIFIER KEYWORD EOF;

我想我脑子里有很多关于非贪婪/贪婪匹配的错误。谁能解释一下它是怎么工作的吗?

在这之后,我在这里发现了一个类似的问题:ANTLR试图在更长的令牌中匹配令牌,并创建了一个相应的语法:

parse
:   
  identifier 'keyword'
;

identifier
:   
  (HIGHCHAR | LOWCHAR)+
;

/** lowercase letters */
LOWCHAR
:   'a'..'z';
/** uppercase letters */
HIGHCHAR
:   'A'..'Z';

这完成了我现在想要的,但是我不明白为什么我不能将标识符规则更改为Lexer规则,将LOWCHAR和HIGHCHAR更改为片段。一个Lexer不知道“keyword”中的字母可以匹配为标识符?或者反之亦然?或者,规则的定义仅仅是为了在自身内部有一个前瞻,而不是所有可能匹配的语法?

共有1个答案

郑和泰
2023-03-14

在ANTLR3和ANTLR4中解决此问题的最简单方法是只允许identifier匹配单个输入字符,然后创建一个解析器规则来处理这些字符的序列。

identifier : IDENTIFIER+;
IDENTIFIER : HIGHCHAR | LOWCHAR;

这将导致lexer跳过输入的identifier作为10个单独的字符,然后读取keyword作为单个keyword令牌。

您在ANTLR4中观察到的使用非贪婪运算符+?的行为与此类似。这个运算符说“在创建标识符令牌的同时,尽可能少地匹配(HIGHCHARLOWCHAR)块”。显然,创建令牌的最少数字是一个,因此这实际上是一种非常低效的编写identifier以匹配单个字符的方法。parse规则无法处理此问题的原因是它只允许在keyword令牌之前出现一个identifier令牌。通过创建如上所示的解析器规则identifier,解析器将能够将identifier标记序列(每个标记都是单个字符)视为单个标识符。

 类似资料:
  • 本文向大家介绍python re模块匹配贪婪和非贪婪模式详解,包括了python re模块匹配贪婪和非贪婪模式详解的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了python re模块匹配贪婪和非贪婪模式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 python贪婪和非贪婪 正则表达式通常用于在文本中查找匹配的字符串。Pytho

  • 贪婪 vs 不贪婪 当重复一个正则表达式时,如用 a*,操作结果是尽可能多地匹配模式。当你试着匹配一对对称的定界符,如 HTML 标志中的尖括号时这个事实经常困扰你。匹配单个 HTML 标志的模式不能正常工作,因为 .* 的本质是“贪婪”的 #!python >>> s = '<html><head><title>Title</title>' >>> len(s) 32 >>> print re.

  • 据我所知,非贪婪匹配不是基本正则表达式(BRE)和扩展正则表达式(ERE)的一部分。然而,不同版本的(BSD和GNU)上的行为似乎表明了另一种明智的做法。 举个例子,我们来看下面这个例子。我有一串话要说: 以下是从字符串中提取< code>hello的一些尝试。 BRE尝试(失败): 输出产生整个字符串,这表明非贪婪量词在 BRE 上不起作用。请注意,我只是转义,因为不会失去它的意义,也不需要转义

  • 本文向大家介绍php正则表达式中贪婪与非贪婪介绍,包括了php正则表达式中贪婪与非贪婪介绍的使用技巧和注意事项,需要的朋友参考一下 一、贪婪与非贪婪 什么叫贪婪,比如说要从字符串中<td>面包一</td><td>面包二</td>吃面包,本来你只可以吃面包一,可是你贪心,于是就把第一个<td>到最后一个</td>里面的两个面包取出来了,你想多吃点,非贪婪也就是你不贪吃了,就只吃面包一。 我们来看看正

  • 效果很好。但是我也想匹配包含关键字的句子,这些关键字不会被期望终止ID+块。例如 fist显示为,然后作为第一个ID+的一部分。按照上面链接的问题的例子,我可以这样修复它: 它起作用了,而且做的正是我想要的。在我的真实语言中,我有数百个关键字列表,用于不同类型的句子,所以如果我尝试这种方法,我肯定会犯错误,当我在我的语言中创建新的结构时,我必须返回并编辑所有其他结构。 最好是从列表中进行非贪婪匹配

  • 本文向大家介绍贪婪算法相关面试题,主要包含被问及贪婪算法时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 贪婪算法(贪心算法)是指在对问题进行求解时,在每一步选择中都采取最好或者最优(即最有利)的选择,从而希望能够导致结果是最好或者最优的算法。贪婪算法所得到的结果往往不是最优的结果(有时候会是最优解),但是都是相对近似(接近)最优解的结果。贪婪算法并没有固定的算法解决框架,算法的关键是贪婪策