ANTLR:“缺少对规则范围的属性访问”问题

时间:2009-11-02 00:10:40

标签: java antlr

我正在尝试构建一个解析标记句子的ANTLR语法,例如:

DT The NP cat VB ate DT a NP rat

并且有语法:

fragment TOKEN  :   (('A'..'Z') | ('a'..'z'))+;
fragment WS :   (' ' | '\t')+;
WSX :   WS;
DTTOK   :   ('DT' WS TOKEN);
NPTOK   :   ('NP' WS TOKEN);
nounPhrase:  (DTTOK WSX NPTOK);
chunker : nounPhrase {System.out.println("chunk found "+"("+$nounPhrase+")");};

语法生成器在最后一行生成“missing attribute access on rule scope: nounPhrase”。

[我还是ANTLR的新手,虽然有些语法工作但它仍然是反复试验的。我还经常在运行这么小的语法时遇到“OutOfMemory”错误 - 欢迎任何帮助。]

我正在使用ANTLRWorks 1.3生成代码,并且正在Java 1.6下运行。

4 个答案:

答案 0 :(得分:9)

“缺少属性访问权限”表示您引用了范围($nounPhrase)而不是范围的属性(例如$nounPhrase.text)。

通常,解决属性问题的一种好方法是查看所讨论规则的生成解析器方法。

例如,当我有点生锈时,我最初尝试创建新规则:

multiple_names returns [List<Name> names]
@init {
    names = new ArrayList<Name>(4);
}
 : a=fullname ' AND ' b=fullname { names.add($a.value); names.add($b.value); };

导致“规则全名的未知属性”。所以我试过

multiple_names returns [List<Name> names]
@init {
    names = new ArrayList<Name>(4);
}
 : a=fullname ' AND ' b=fullname { names.add($a); names.add($b); };

导致“缺少属性访问”。查看生成的解析器方法,清楚地说明了我需要做什么。虽然有一些神秘的部分,但与范围(变量)相关的部分很容易理解:

public final List<Name> multiple_names() throws RecognitionException {
    List<Name> names = null;        // based on "returns" clause of rule definition
    Name a = null;                  // based on scopes declared in rule definition
    Name b = null;                  // based on scopes declared in rule definition
    names = new ArrayList<Name>(4); // snippet inserted from `@init` block

    try {
        pushFollow(FOLLOW_fullname_in_multiple_names42);
        a=fullname();
        state._fsp--;
        match(input,189,FOLLOW_189_in_multiple_names44); 
        pushFollow(FOLLOW_fullname_in_multiple_names48);
        b=fullname();
        state._fsp--;
        names.add($a); names.add($b);// code inserted from {...} block
    }
    catch (RecognitionException re) {
        reportError(re);
        recover(input,re);
    }
    finally {
        // do for sure before leaving
    }
    return names;                    // based on "returns" clause of rule definition
}

在查看生成的代码之后,很容易看到fullname规则正在返回Name类的实例,因此在这种情况下我需要的只是:

multiple_names returns [List<Name> names]
@init {
    names = new ArrayList<Name>(4);
}
 : a=fullname ' AND ' b=fullname { names.add(a); names.add(b); };

您所需的版本可能会有所不同,但您通常可以通过查看生成的代码轻松搞清楚。

答案 1 :(得分:3)

在原始语法中,为什么不包括它要求的属性,最有可能:

chunker : nounPhrase {System.out.println("chunk found "+"("+$nounPhrase.text+")");};

您的每个规则(chunker是我能够快速发现的规则)都具有与之关联的属性(额外信息)。您可以在http://www.antlr.org/wiki/display/ANTLR3/Attribute+and+Dynamic+Scopes找到不同类型规则的不同属性的快速列表,如果在网页上为每个属性添加了描述(例如解析器的start和stop属性),那将会很好规则是指你的词法分析器中的标记 - 这将允许你回到你的行号和位置。

我认为您的chunker规则应该略有改动,而不是$nounPhrase您应该使用$nounPhrase.texttextnounPhrase规则的属性。

你可能也希望做一些其他的格式化,通常解析器规则(以小写字母开头)出现在词法分析器规则之前(以大写字母开头)

PS。当我在框中输入时,chunker规则从一个新行开始,但在我的原始答案中,它并没有从一个新行开始。

答案 2 :(得分:1)

如果你不小心做了$thing.$attribute,你的意思是$thing.attribute,你也会看到missing attribute access on rule scope错误消息。 (我知道很久以前这个问题得到了解答,但这一点琐事可能会帮助那些看到错误信息的人!)

答案 3 :(得分:0)

找到更好的方法后回答问题......

WS  :    (' '|'\t')+;
TOKEN   :   (('A'..'Z') | ('a'..'z'))+;
dttok   :   'DT' WS TOKEN;
nntok   :   'NN' WS TOKEN; 
nounPhrase :    (dttok WS nntok);
chunker :  nounPhrase ;

问题是我在词法分析器和解析器之间变得混乱(这显然很常见)。大写的项是词法,解析器中的小写。这似乎现在有效。 (注意我已将NP更改为NN)。