JavaCC警告的解释和解决方案“正则表达式选择:FOO永远不能匹配为:BAR”?

时间:2009-04-26 20:53:47

标签: regex parsing javacc

我正在教自己在一个爱好项目中使用JavaCC,并且有一个简单的语法来编写解析器。解析器的一部分包括以下内容:

TOKEN : { < DIGIT : (["0"-"9"]) > }
TOKEN : { < INTEGER : (<DIGIT>)+ > }
TOKEN : { < INTEGER_PAIR : (<INTEGER>){2} > }
TOKEN : { < FLOAT : (<NEGATE>)? <INTEGER> | (<NEGATE>)? <INTEGER>  "." <INTEGER>  | (<NEGATE>)? <INTEGER> "." | (<NEGATE>)? "." <INTEGER> > } 
TOKEN : { < FLOAT_PAIR : (<FLOAT>){2} > }
TOKEN : { < NUMBER_PAIR : <FLOAT_PAIR> | <INTEGER_PAIR> > }
TOKEN : { < NEGATE : "-" > }

使用JavaCC编译时,我得到输出:

Warning: Regular Expression choice : FLOAT_PAIR can never be matched as : NUMBER_PAIR

Warning: Regular Expression choice : INTEGER_PAIR can never be matched as : NUMBER_PAIR

我确信这是一个简单的概念,但我不理解这个警告,在解析器生成和正则表达式方面都是新手。

这个警告意味着什么(在新手即可获得的条款中)?

4 个答案:

答案 0 :(得分:4)

我不认识JavaCC,但我是编译工程师。

FLOAT_PAIR规则含糊不清。请考虑以下文本:

0.0

这可以是FLOAT 0,然后是FLOAT .0;或者FLOAT 0.后跟FLOAT 0;两者都导致了FLOAT_PAIR。或者它可以是单个FLOAT 0.0

更重要的是,您正在以一种永远不可能发挥作用的方式使用词法分析。考虑这个数字:

12345

这可以解析为INTEGER 12, INTEGER 345,从而产生INTEGER_PAIR。或者它可以被解析为INTEGER 123, INTEGER 45,另一个INTEGER_PAIR。或者它可能是INTEGER 12345,另一个令牌。存在问题是因为INTEGER_PAIR(或FLOAT_PAIR)的词汇元素之间不需要空格。

你几乎不应该尝试在词法分析器中处理这样的对。相反,您应该将普通数字(INTEGERFLOAT)作为标记处理,并在解析器中处理诸如否定和配对之类的事情,其中​​空白处理和剥离。

(例如,您将如何处理"----42"?这是大多数编程语言中的有效表达式,它将正确计算多个否定,但不会由词法分析器处理。)

另外,请注意词法分析器中的单位数整数将不会与INTEGER匹配,它们将显示为DIGIT。但是,我不知道JavaCC的正确语法可以为您解决这个问题。你想要的是将DIGIT定义为不是一个标记,而只是你可以在其他标记的定义中使用的东西;或者,在您的规则中使用DIGIT的任何地方直接嵌入[0-9]DIGIT)的定义。

答案 1 :(得分:0)

我没有使用过JavaCC,但NUMBER_PAIR可能不明确。

我认为问题归结为FLOAT_PAIR和INTEGER_PAIR可以匹配相同的事实,因为FLOAT可以匹配INTEGER。

但这只是猜测从未见过JavaCC语法:)

答案 2 :(得分:0)

这可能意味着,对于每个FLOAT_PAIR,您只需获得FLOAT_PAIR令牌,而不是NUMBER_PAIR令牌。 FLOAT_PAIR规则已匹配所有输入,JavaCC将不会尝试查找其他匹配规则。这将是我的解释,但我不了解JavaCC,所以请耐心等待。

也许您可以某种方式指定NUMBER_PAIR是主要产品,并且您不希望将任何其他令牌作为结果。

答案 3 :(得分:0)

感谢Barry Kelly的回答,我提出的解决方案是:

    SKIP : { < #TO_SKIP : " " | "\t" > }
    TOKEN : { < #DIGIT : (["0"-"9"]) > }
    TOKEN : { < #DIGITS : (<DIGIT>)+ > }
    TOKEN : { < INTEGER : <DIGITS> > }
    TOKEN : { < INTEGER_PAIR : (<INTEGER>) (<TO_SKIP>)+ (<INTEGER>) > }
    TOKEN : { < FLOAT : (<NEGATE>)?<DIGITS>"."<DIGITS> | (<NEGATE>)?"."<DIGITS> > } 
    TOKEN : { < FLOAT_PAIR : (<FLOAT>) (<TO_SKIP>)+ (<FLOAT>) > }
    TOKEN : { < #NUMBER : <FLOAT> | <INTEGER> > }
    TOKEN : { < NUMBER_PAIR : (<NUMBER>) (<TO_SKIP>)+ (<NUMBER>) >}
    TOKEN : { < NEGATE : "-" > }

我完全忘了包含用于分隔两个标记的空间,我还使用了'#'符号来停止匹配的标记,并且仅用于其他标记的定义。以上内容由JavaCC编译,没有任何警告或错误。

然而,正如Barry所指出的,有理由反对这样做。

相关问题