【问题标题】:Problems with LL(1) grammarLL(1) 语法问题
【发布时间】:2012-06-30 19:42:57
【问题描述】:

我有一个 Mini Java 子语法的 26 条规则语法。该语法应该是非面向对象的。无论如何,我一直在尝试对它进行左分解并删除左递归。但是,我用 JFLAP 对其进行了测试,但它告诉我它不是 LL(1)。我遵循了 Aho-Sethi 书中算法的每一步。

你能给我一些建议吗?

Goal ::= MainClass $
MainClass ::= class <IDENTIFIER> { MethodDeclarations public static void main ( ) {
    VarDeclarations Statements } }
    VarDeclarations ::= VarDeclaration VarDeclarations | e
VarDeclaration ::= Type <IDENTIFIER> ;
MethodDeclarations ::= MethodDeclaration MethodDeclarations | e
MethodDeclaration ::= public static Type <IDENTIFIER> ( Parameters ) {
    VarDeclarations Statements return GenExpression ; }
Parameters ::= Type <IDENTIFIER> Parameter | e
Parameter ::= , Type <IDENTIFIER> Parameter | e
Type ::= boolean | int
Statements ::= Statement Statements | e
Statement ::= { Statements }
        |   if ( GenExpression ) Statement else Statement
        |   while ( GenExpression ) Statement
        |   System.out.println ( GenExpression ) ;
        |   <IDENTIFIER> = GenExpression ;
GenExpression ::= Expression | RelExpression
Expression ::= Term ExpressionRest
ExpressionRest ::= e | + Term ExpressionRest | - Term ExpressionRest
Term ::= Factor TermRest
TermRest ::= e | * Factor TermRest
Factor ::= ( Expression )
        |   true
        |   false
        |   <INTEGER-LITERAL>
        |   <IDENTIFIER> ArgumentList
ArgumentList ::= e | ( Arguments )
RelExpression ::= RelTerm RelExpressionRest
RelExpressionRest ::= e | && RelTerm RelExpressionEnd
RelExpressionEnd ::= e | RelExpressionRest
RelTerm ::= Term RelTermRest
RelTermRest ::= == Expression | < Expression | ExpressionRest RelTermEnding
RelTermEnding ::= == Expression | < Expression
Arguments ::= Expression Argument | RelExpression Argument | e
Argument ::= , GenExpression Argument | e 

每个&lt;IDENTIFIER&gt; 都是一个有效的Java 标识符,&lt;INTEGER-LITERAL&gt; 是一个简单的整数。每个e 产生式代表一个epsilon 产生式,第一条规则中的$ 是文件结束标记。

【问题讨论】:

    标签: parsing grammar ambiguity ll left-recursion


    【解决方案1】:

    我想我发现了两个问题(可能还有更多):

    问题 #1

    在 MainClass 你有

    MethodDeclarations public static void main
    

    一个 MethodDeclaration 是

    public static Type | e
    

    这不是 LL(1),因为当解析器看到“public”时,它无法判断它是 MethodDeclaration 还是“public static void main”方法。

    问题 #2

    Arguments ::= Expression Argument | RelExpression Argument | e
    

    两个表达式:

    Expression ::= Term ExpressionRest
    

    ... 和 RelExpression:

    RelExpression ::= RelTerm RelExpressionRest
    RelTerm ::= Term RelTermRest
    

    ...以“Term”开头,所以也不是 LL(1)。

    我会选择 LL(k) 或 LL(*),因为它们允许您编写更易于维护的语法。

    【讨论】:

    • 谢谢。嗯,这是两个,我想还有更多。难道没有一种有条不紊的方法可以检查这些漏洞吗?
    • 最快和最可靠的方法可能是让您的解析器生成器进行 LL(1) 条件检查。自己检查基本上需要您找出每个规则可以开始的所有终端符号。如果规则的某些条件以相同的终端符号开头,您就知道它不是 LL(1)。这与您的解析器生成器所做的以及我在查看您的语法时所做的几乎相同。使用语法一段时间后,您会对此有很好的感觉,但可以肯定的是,请询问解析器生成器:)
    • Constructing an LL(1) parsing table 上的维基百科条目提供了此方法的详细描述。最后一句很重要:“如果表格的每个单元格中最多包含一个规则,那么解析器将始终知道它必须使用哪个规则,因此可以解析字符串而无需回溯。正是在这个该文法称为 LL(1) 文法的情况。"
    • 谢谢。我会做的。我知道这类问题没有准确的“答案”,所以我会接受你的,并做更多的工作。
    • 最后,我使用 ANTLRWorks 修复语法并生成正确的解析器,虽然结果不是 LL(1),而是 LL(*)。
    【解决方案2】:

    有什么可以防止 IDENTIFIER 与您的保留字之一相同吗?如果不是,那么您的语法将是模棱两可的。不过我没有看到其他任何东西。

    如果一切都失败了,我会删除除最后一行之外的所有语法,并对其进行测试。如果通过了,我会一次添加每一行,直到找到问题行。

    【讨论】:

    • IDENTIFIER 保证不是关键字。将其视为{所有不以数字开头的单词} - {Java 关键字}。
    猜你喜欢
    • 2015-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多