我正在教自己在一个爱好项目中使用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
我确信这是一个简单的概念,但我不理解这个警告,在解析器生成和正则表达式方面都是新手。
这个警告意味着什么(在新手即可获得的条款中)?
答案 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
)的词汇元素之间不需要空格。
你几乎不应该尝试在词法分析器中处理这样的对。相反,您应该将普通数字(INTEGER
和FLOAT
)作为标记处理,并在解析器中处理诸如否定和配对之类的事情,其中空白处理和剥离。
(例如,您将如何处理"----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所指出的,有理由反对这样做。