我们已经使用Java CC对语法进行修补和解析。其中一个问题是"(...)*"可以用空字符串匹配。我理解这个错误是因为某些东西可以匹配零次或多次 in 其他可以匹配零次或多次的东西。
我不明白的是如何解决它。 (我们的导师没有多说,"你必须小心你的说法。"
语法的问题区域及其相关的Java CC代码如下所示。任何想法或建议将不胜感激。
program := ( decl )*
( function ) *
main_prog
decl := ( var_decl | const_decl )*
var_decl := var ident_list : type ( , ident_list : type)* ;
const_decl := const identifier : type = expression ( , identifier : type = expression)* ;
function :=
type identifier ( param_list)
( decl )*
( statement ; )*
return ( expression | e ); //e is greek epsilon character
main_prog :=
main
( decl ) *
(statement ; )*
问题在于我认为decl的声明方式。它在实际的Java CC代码中声明:
void decl():{}
{
( var_decl() | const_decl())*
}
如果我将上面的Kleene闭包更改为+,则由此引起的所有其他错误都会消失。然而,教练说明星应该留下来,我们需要小心我们如何说出来。我在左保理因子,左递归删除等方面找到了很多资源,但在这个特定问题上却很少。上面的代码在Java CC中实际上没有错误,但是导致进一步的错误如下:
void program():{}
{
( decl() )* //error here - Expansion within "(...)*" can be matched by empty string
( function() )*
main_prog()
}
void main_prog(): {}
{
< MAIN >
( decl() )* //same error on this line
(statement() < SCOLON >)*
}
void function(): {}
{
type() < ID > <LPARENT > param_list() < RPARENT >
( decl() )* //same error on this line
( statement() < SCOLON > )*
< RET> ( expression() | {} ) <SCOLON > // {} is epsilon
}
如何解决这个问题的任何想法都将非常感激。
答案 0 :(得分:1)
目前你的语法含糊不清 - 它表示decl
表示零或多个声明,并且有许多地方允许零或多个decl
s。在这两个地方你都不需要*
,只需选择其中一种,任何一种方法都会解析相同的程序,但它们在概念上略有不同。
您可以在*
中取出decl
:
decl := ( var_decl | const_decl )
program := ( decl )*
( function ) *
main_prog
所以decl
表示单个声明,而program
可能以decl
s序列开头,但不是'必须。或者,您可以将*
保留在decl
中,但可以从您引用它的地方取出:
decl := ( var_decl | const_decl )*
program := decl
( function ) *
main_prog
所以现在decl
表示类似“声明块”而不是单个声明 - 每个program
必须以声明块开头,但该块本身允许是空的。