Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 莱克斯';对于前瞻运算符,s的算法不正确_Regex_Parsing_Lex_Lexical Analysis_Lookahead - Fatal编程技术网

Regex 莱克斯';对于前瞻运算符,s的算法不正确

Regex 莱克斯';对于前瞻运算符,s的算法不正确,regex,parsing,lex,lexical-analysis,lookahead,Regex,Parsing,Lex,Lexical Analysis,Lookahead,在Andrew Appel的“Java中的现代编译器实现”中,他在一次练习中声称: Lex有一个lookahead运算符,因此正则表达式abc/def仅在后跟def时匹配abc(但def不是匹配字符串的一部分,并且将是下一个标记的一部分)。Aho等人[1986]描述了,Lex[Lesk 1975]使用了一种不正确的算法来实现前瞻(它在(a | ab)/ba上失败,输入aba,在它应该匹配a的地方匹配ab)。Flex[Paxson 1995]使用了一种更好的机制,它可以正确地用于(a | ab)/

在Andrew Appel的“Java中的现代编译器实现”中,他在一次练习中声称:

Lex有一个lookahead运算符,因此正则表达式abc/def仅在后跟def时匹配abc(但def不是匹配字符串的一部分,并且将是下一个标记的一部分)。Aho等人[1986]描述了,Lex[Lesk 1975]使用了一种不正确的算法来实现前瞻(它在(a | ab)/ba上失败,输入aba,在它应该匹配a的地方匹配ab)。Flex[Paxson 1995]使用了一种更好的机制,它可以正确地用于(a | ab)/ba,但失败了(在zx*/xy*上有一条警告消息)。设计一种更好的前瞻机制

有人知道他所描述的问题的解决方案吗?

“不符合我的想法”和“不正确”并不总是一回事

aba
模式呢

(ab|a)/ab
(ab | a)贪婪地匹配,然后分别应用
/ab
约束,这在一定程度上是有意义的。您认为它应该像以下正则表达式一样工作:

(ab|a)(ab)
有一个约束条件,即与
(ab)
匹配的部分不会被使用。这可能更好,因为它消除了一些限制,但由于在编写
lex
时没有任何外部要求,因此不能将行为称为正确或不正确

这种简单的方法的优点是,添加尾随上下文不会改变标记的含义,而只是添加了一个关于它后面可能发生的事情的完全独立的约束。但这确实会导致限制/意外:

 {IDENT}  /* original code */

 {IDENT}/ab   /* ident, only when followed by ab */
糟糕的是,它不起作用,因为“ab”被吞没在IDENT中,正是因为它的含义没有被后面的上下文改变。这变成了一个限制,但可能是作者愿意接受的一个限制,以换取简单性。(无论如何,让它更上下文化的用例是什么?)

另一种方式呢?那也可能会有惊喜:

 {IDENT}/ab  /* input is bracadabra:123 */
假设用户希望此项不匹配,因为
bracadabra
不是后跟(或以)
ab
结尾的标识符。但是{IDENT}/ab将匹配
bracad
,然后在输入中保留
abra:123

无论您如何确定语义,用户的期望都可能被挫败

lex
现在由单一Unix规范标准化,该规范规定:

r/x
只有在正则表达式r后面出现正则表达式x时,才应匹配正则表达式r(x是尾随上下文的实例,进一步定义如下)。yytext中返回的标记应仅与r匹配。如果r的尾随部分与x的开头匹配,则结果未指定。r表达式不能包含进一步的尾随上下文或“$”(匹配行尾)运算符;x不能包含“^”(匹配行尾)运算符,也不是尾随上下文,也不是“$”运算符。也就是说,在lex正则表达式中只允许出现一次尾随上下文,并且“^”运算符只能在此类表达式的开头使用

所以你可以看到这里有解释的空间。r和x可以被视为单独的正则表达式,以正常的方式计算r的匹配,就像它是单独的一样,然后x作为一个特殊的约束被应用

规范中也讨论了这个问题(你很幸运):

以下示例阐明了lex正则表达式与IEEE Std 1003.1-2001本卷其他地方出现的正则表达式之间的区别。对于“r/x”形式的正则表达式,始终返回与r匹配的字符串;当x的开头与r的结尾部分匹配时,可能会出现混淆。例如,给定正则表达式“a*b/cc”和输入“aaabcc”,yytext将包含此匹配的字符串“aaab”。但给定正则表达式“x*/xy”和输入“xxxy”,某些实现返回标记xxx,而不是xx,因为xxx匹配“x*”

在规则“ab*/bc”中,r结尾的“b*”将r的匹配扩展到尾随上下文的开头,因此结果未指定。但是,如果此规则为“ab/bc”,则当后跟文本“bc”时,该规则与文本“ab”匹配。在后一种情况下,r的匹配不能延伸到x的开头,因此指定了结果。 如您所见,此功能中存在一些限制


未指定的行为意味着有一些关于行为应该是什么的选择,其中没有一个比其他选择更正确(如果你希望你的lex程序是可移植的,就不要编写这样的模式)。“正如你所看到的,这个特性有一些限制。”

我已经用flex和
(a | ab)进行了测试/ba
如您所指出的那样工作,但是
zx*/xy*
也适用于输入
zxy
zx
。对于该表达式,什么输入在
flex
中失败,您能提供一个例子吗?不知道Appel可能暗示了什么,如果有的话,特定的解决方案,但请参阅,例如,@Birei可能是一个打字错误。试试表达式“ab*/ba*”。Flex会抱怨“警告,危险的拖尾上下文”,并会继续为“aba”或“abba”等输入生成不正确的匹配。Flex 2.6.4,Ubuntu 20.04.Hmm,实际上“zx*/xy*”在“zxy”上失败,原因与AFAICT相同(它匹配“zx”)。不知道在匹配后要备份多远,尾部上下文与前面的表达式共享状态。我想它警告您它会出错是很好的。我想,人们总是可以讲述一个故事,说明为什么不良行为不是一个bug。挖掘我古老的原始Lex手册,我明白了“表达式ab/cd与字符串ab匹配,但仅当后跟cd时才匹配。“如果不匹配,则算法将被破坏。”通过在一个标准中重新定义它来修复它,该标准说“嘿,有时这不起作用”,这并不能使它正确,只是一个记录在案的错误。除了