ANTLR:规则令牌具有非LL(*)决策,因为递归规则调用可以从alts 1,2到达

时间:2010-07-14 19:22:12

标签: antlr

grammar AdifyMapReducePredicate;

PREDICATE 
    :   PREDICATE_BRANCH
    |   EXPRESSION
    ;

PREDICATE_BRANCH
    :   '(' PREDICATE (('&&' PREDICATE)+ | ('||' PREDICATE)+) ')'
    ;

EXPRESSION 
    :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

尝试在ANTLRWorks 1.4中解释这一点,并收到以下错误:

[12:18:21] error(211): <notsaved>:1:8: [fatal] rule Tokens has non-LL(*) decision due to recursive rule invocations reachable from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
[12:18:21] Interpreting...

当我解释时,我正试图解释一个预测,我的测试用例是(A || B)

我错过了什么?

2 个答案:

答案 0 :(得分:5)

根据ANTLR的约定,解析器规则名称以小写字母开头,而词法分析器规则以大写字母开头。所以语法就像你写的一样,有三个词法规则,定义了令牌。这可能不是你想要的。

错误消息的原因显然是这些令牌之间存在歧义:您的输入模式与PREDICATE和PREDICATE_BRANCH的定义相匹配。

只使用以小写字母开头的名称而不是PREDICATE和PREDICATE_BRANCH。您可能还需要为目标符号添加一个额外的规则,该规则不直接参与递归。

顺便说一句,这个语法是递归的,但不是左递归的,当使用解析器规则时,它绝对是LL(1)。

答案 1 :(得分:1)

你没有解析器规则(解析器规则以小写字母开头),虽然在解释ANTLRWorks中的一些测试用例时我不确定最后一部分是否必要。

无论如何,尝试这样的事情:

grammar AdifyMapReducePredicate;

parse
  :  (p=predicate {System.out.println("parsed :: "+$p.text);})+ EOF
  ;

predicate 
  :  expression
  ;

expression
  :  booleanExpression
  ;

booleanExpression
  :  atom ((AND | OR) atom)*
  ;

atom
  :  ID
  |  '(' predicate ')'
  ;

AND
  :  '&&'
  ;

OR
  :  '||'
  ;

ID 
  :  ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
  ;

SPACE
  :  (' ' | '\t' | '\r' | '\n') {skip();}
  ;

使用以下测试类:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("(A || B) (C && (D || F || G))");
        AdifyMapReducePredicateLexer lexer = new AdifyMapReducePredicateLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        AdifyMapReducePredicateParser parser = new AdifyMapReducePredicateParser(tokens);
        parser.parse();
    }
}

在生成词法分析器&amp;解析器(a),编译所有.java个文件(b)并运行测试类(c),产生以下输出:

parsed :: (A||B)
parsed :: (C&&(D||F||G))

java -cp antlr-3.2.jar org.antlr.Tool AdifyMapReducePredicate.g 

B'/ H2>
javac -cp antlr-3.2.jar *.java

c(* nix / MacOS)

java -cp .:antlr-3.2.jar Main

c(Windows)

java -cp .;antlr-3.2.jar Main

HTH