Java CC问题 - “扩展内”(...)*“可以用空字符串匹配”

时间:2013-11-29 10:28:51

标签: java compiler-construction javacc

我们已经使用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
}

如何解决这个问题的任何想法都将非常感激。

1 个答案:

答案 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 必须以声明块开头,但该块本身允许是空的。