为什么Antlr在处理我的语法时会进入无限循环

时间:2012-03-22 16:57:30

标签: antlr antlr3 antlrworks

我创建了一个用于解析数学表达式的ANTLR语法,另一个用于评估它们。当我想构建一个AST然后重新解析以便实际评估它是一种操作太多时,我想重构我的语法以产生一个" Term"表示表达式的对象,包括执行该特定操作的逻辑。然后可以简单地将根Term对象评估为具体结果。

我不得不重写了很多语法,最后摆脱了最后一条错误信息。不幸的是,现在ANTLR似乎进入了一个无限循环。

有人可以帮我解决问题吗?我认为语法应该对某些人非常有趣,因此我发布它。 (这是基于我在google上发现的一个garmmar,我应该承认,但我已根据我的需要对其进行了很多修改)。

grammar SecurityRulesNew;

options {
language = Java;
    output=AST;
    backtrack = true;
    ASTLabelType=CommonTree;
    k=2;
}

tokens {
    POS;
    NEG;
    CALL;
}

@header {package de.cware.cweb.services.evaluator.parser;}
@lexer::header{package de.cware.cweb.services.evaluator.parser;}

formula returns [Term term]
: a=expression EOF { $term = a; }
;
expression returns [Term term]
: a=boolExpr { $term = a; }
;
boolExpr returns [Term term]
: a=sumExpr { $term = a; }
| a=sumExpr AND b=boolExpr { $term = new AndTerm(a, b); }
| a=sumExpr OR b=boolExpr { $term = new OrTerm(a, b); }
| a=sumExpr LT b=boolExpr { $term = new LessThanTerm(a, b); }
| a=sumExpr LTEQ b=boolExpr { $term = new LessThanOrEqualTerm(a, b); }
| a=sumExpr GT b=boolExpr { $term = new GreaterThanTerm(a, b); }
| a=sumExpr GTEQ b=boolExpr { $term = new GreaterThanTermOrEqual(a, b); }
| a=sumExpr EQ b=boolExpr { $term = new EqualsTerm(a, b); }
| a=sumExpr NOTEQ b=boolExpr { $term = new NotEqualsTerm(a, b); }
;
sumExpr returns [Term term]
: a=productExpr { $term = a; }
| a=productExpr SUB b=sumExpr { $term = new SubTerm(a, b); }
| a=productExpr ADD b=sumExpr { $term = new AddTerm(a, b); }
;
productExpr returns [Term term]
: a=expExpr { $term = a; }
| a=expExpr DIV productExpr { $term = new DivTerm(a, b); }
| a=expExpr MULT productExpr { $term = new MultTerm(a, b); }
;
expExpr returns [Term term]
: a=unaryOperation { $term = a; }
| a=unaryOperation EXP expExpr { $term = new ExpTerm(a, b); }
;
unaryOperation returns [Term term]
: a=operand { $term = a; }
| NOT a=operand { $term = new NotTerm(a); }
| SUB a=operand { $term = new NegateTerm(a); }
;
operand returns [Term term]
: l=literal { $term = l; }
| f=functionExpr { $term = f; }
| v=VARIABLE { $term = new VariableTerm(v); }
| LPAREN e=expression RPAREN { $term = e; }
;
functionExpr returns [Term term]
: f=FUNCNAME LPAREN! RPAREN! { $term = new CallFunctionTerm(f, null); }
| f=FUNCNAME LPAREN! a=arguments RPAREN! { $term = new CallFunctionTerm(f, a); }
;
arguments returns [List<Term> terms]
: a=expression 
    { 
        $terms = new ArrayList<Term>(); 
        $terms.add(a);
    }
| a=expression COMMA b=arguments
    { 
        $terms = new ArrayList<Term>(); 
        $terms.add(a);
        $terms.addAll(b);
    }
;
literal returns [Term term]
: n=NUMBER { $term = new NumberLiteral(n); }
| s=STRING { $term = new StringLiteral(s); }
| t=TRUE { $term = new TrueLiteral(t); }
| f=FALSE { $term = new FalseLiteral(f); }
;

STRING
:
'\"'
    ( options {greedy=false;}
    : ESCAPE_SEQUENCE
    | ~'\\'
    )*
'\"'
|
'\''
    ( options {greedy=false;}
    : ESCAPE_SEQUENCE
    | ~'\\'
    )*
'\''
;
WHITESPACE
: (' ' | '\n' | '\t' | '\r')+ {skip();};
TRUE
: ('t'|'T')('r'|'R')('u'|'U')('e'|'E')
;
FALSE
: ('f'|'F')('a'|'A')('l'|'L')('s'|'S')('e'|'E')
;

NOTEQ           : '!=';
LTEQ            : '<=';
GTEQ            : '>=';
AND             : '&&';
OR              : '||';
NOT             : '!';
EQ              : '=';
LT              : '<';
GT              : '>';

EXP             : '^';
MULT            : '*';
DIV             : '/';
ADD             : '+';
SUB             : '-';

LPAREN          : '(';
RPAREN          : ')';
COMMA           : ',';
PERCENT         : '%';

VARIABLE
: '[' ~('[' | ']')+ ']'
;
FUNCNAME
: (LETTER)+
;
NUMBER
: (DIGIT)+ ('.' (DIGIT)+)?
;

fragment
LETTER 
: ('a'..'z') | ('A'..'Z')
;
fragment
DIGIT
: ('0'..'9')
;
fragment
ESCAPE_SEQUENCE
: '\\' 't'
| '\\' 'n'
| '\\' '\"'
| '\\' '\''
| '\\' '\\'
;

非常感谢帮助。

克里斯

2 个答案:

答案 0 :(得分:1)

因为你的语法非常模糊,所以ANTLR在创建解析器时遇到了问题。显然ANTLR 3.3+扼流圈,但ANTLR 3.2(时间少于3.3+)产生以下错误:

  

错误(10):内部错误:org.antlr.tool.Grammar.createLookaheadDFA(Grammar.java:1279):   决定1甚至不能做k = 1;原因:超时(&gt; 1000毫秒)

对于简单的表达式解析器,你真的不应该使用backtrack=true

除了您的语法不明确之外,您的大部分嵌入代码都包含错误。

让我们看看您的formula规则:

formula returns [Term term]
: a=expression EOF { $term = $a; }
;

此外,应明确定义规则的返回类型。 a中的{ $term = a; }前面应该有一个$

formula returns [Term term]
: a=expression EOF { $term = $a; }
;

然后$a指的是整个&#34;&#34; expression返回。然后你必须告诉&#34;您想要Termexpression创建的ANTLR。这可以这样做:

formula returns [Term term]
: a=expression EOF { $term = $a.term; }
;
expression returns [Term term]
: a=boolExpr { $term = $a.term; }
;

看起来你已经将一些LR语法转换为ANTLR语法(请注意,虽然ANTLR以LR结尾,但ANTLR 3.x是LL解析器生成器)并且没有在它们之间进行测试,你曾希望它应该全部工作:不幸的是,它没有。基于你的语法生成一个小的工作示例有太多错误:我要看一下基于ANTLR语法的现有表达式解析器,然后再试一次。看看这些Q&amp; A&#39:

答案 1 :(得分:0)

首先,谢谢您的详细解释。这真的有帮助:-) ...所有的“$ a.term”和类似的东西现在整理出来并生成实际编译的代码(我只是破解了那些想要解决问题的代码完全生成)。我简单地评论了很多选项并保留了生成,直到我找到了一个似乎打破了构建的片段。我打开了这个回溯功能,因为我得到了一些错误,建议我打开它。

编辑: 好吧,我实际上重构了语法,以摆脱错误而不激活回溯,现在我的解析器生成得非常快,似乎很好地完成了它的工作。这是当前版本:

grammar SecurityRulesNew;

options {
language = Java;
    output=AST;
ASTLabelType=CommonTree;
/*  backtrack = true;*/
}

tokens {
POS;
NEG;
CALL;
}

@header {package de.cware.cweb.services.evaluator.parser;

import de.cware.cweb.services.evaluator.terms.*;}
@lexer::header{package de.cware.cweb.services.evaluator.parser;}

formula returns [Term term]
: a=expression EOF { $term = $a.term; }
;
expression returns [Term term]
: a=boolExpr { $term = $a.term; }
;
boolExpr returns [Term term]
: a=sumExpr (AND! b=boolExpr | OR! c=boolExpr | LT! d=boolExpr | LTEQ! e=boolExpr | GT! f=boolExpr | GTEQ! g=boolExpr | EQ! h=boolExpr | NOTEQ! i=boolExpr)? {
        if(b != null) {
            $term = new AndTerm($a.term, $b.term);
        } else if(c != null) {
            $term = new OrTerm($a.term, $c.term);
        } else if(d != null) {
            $term = new LessThanTerm($a.term, $d.term);
        } else if(e != null) {
            $term = new LessThanOrEqualTerm($a.term, $e.term);
        } else if(f != null) {
            $term = new GreaterThanTerm($a.term, $f.term);
        } else if(g != null) {
            $term = new GreaterThanOrEqualTerm($a.term, $g.term);
        } else if(h != null) {
            $term = new EqualsTerm($a.term, $h.term);
        } else if(i != null) {
            $term = new NotEqualsTerm($a.term, $i.term);
        } else {
            $term = $a.term;
        }
    }
;
sumExpr returns [Term term]
: a=productExpr (SUB! b=sumExpr | ADD! c=sumExpr)?
    {
        if(b != null) {
            $term = new SubTerm($a.term, $b.term);
        } else if(c != null) {
            $term = new AddTerm($a.term, $c.term);
        } else {
            $term = $a.term;
        }
    }
;
productExpr returns [Term term]
: a=expExpr (DIV! b=productExpr | MULT! c=productExpr)?
    {
        if(b != null) {
            $term = new DivTerm($a.term, $b.term);
        } else if(c != null) {
            $term = new MultTerm($a.term, $c.term);
        } else {
            $term = $a.term;
        }
    }
;
expExpr returns [Term term]
: a=unaryOperation (EXP! b=expExpr)?
    {
        if(b != null) {
            $term = new ExpTerm($a.term, $b.term);
        } else {
            $term = $a.term;
        }
    }
;
unaryOperation returns [Term term]
: a=operand { $term = $a.term; }
| NOT! a=operand { $term = new NotTerm($a.term); }
| SUB! a=operand { $term = new NegateTerm($a.term); }
| LPAREN! e=expression RPAREN! { $term = $e.term; }
;
operand returns [Term term]
: l=literal { $term = $l.term; }
| v=VARIABLE { $term = new VariableTerm($v.text); }
| f=functionExpr { $term = $f.term; }
;
functionExpr returns [Term term]
: f=FUNCNAME LPAREN! (a=arguments)? RPAREN! { $term = new CallFunctionTerm($f.text, $a.terms); }
;
arguments returns [List<Term> terms]
: a=expression (COMMA b=arguments)?
    { 
        $terms = new ArrayList<Term>(); 
        $terms.add($a.term);
        if(b != null) {
            $terms.addAll($b.terms);
        }
    }
;
literal returns [Term term]
: n=NUMBER { $term = new NumberLiteral(Double.valueOf($n.text)); }
| s=STRING { $term = new StringLiteral($s.text.substring(1, s.getText().length() - 1)); }
| TRUE! { $term = new TrueLiteral(); }
| FALSE! { $term = new FalseLiteral(); }
;

STRING
:
'\"'
    ( options {greedy=false;}
    : ESCAPE_SEQUENCE
    | ~'\\'
    )*
'\"'
|
'\''
    ( options {greedy=false;}
    : ESCAPE_SEQUENCE
    | ~'\\'
    )*
'\''
;
WHITESPACE
: (' ' | '\n' | '\t' | '\r')+ {skip();};
TRUE
: ('t'|'T')('r'|'R')('u'|'U')('e'|'E')
;
FALSE
: ('f'|'F')('a'|'A')('l'|'L')('s'|'S')('e'|'E')
;

NOTEQ   : '!=';
LTEQ    : '<=';
GTEQ    : '>=';
AND     : '&&';
OR      : '||';
NOT     : '!';
EQ      : '=';
LT      : '<';
GT      : '>';

EXP     : '^';
MULT    : '*';
DIV     : '/';
ADD     : '+';
SUB     : '-';

LPAREN  : '(';
RPAREN  : ')';
COMMA   : ',';
PERCENT : '%';

VARIABLE
: '[' ~('[' | ']')+ ']'
;
FUNCNAME
: (LETTER)+
;
NUMBER
: (DIGIT)+ ('.' (DIGIT)+)?
;

fragment
LETTER 
: ('a'..'z') | ('A'..'Z')
;
fragment
DIGIT
: ('0'..'9')
;
fragment
ESCAPE_SEQUENCE
: '\\' 't'
| '\\' 'n'
| '\\' '\"'
| '\\' '\''
| '\\' '\\'
;

再次感谢您的解释......它让我走上正轨: - )

克里斯