2012-03-22 85 views
2

我創建瞭解析數學表達式的ANTLR語法和用於評估它們的第二個語法。正如我認爲構建一個AST然後重新解析以實際評估它只是一種操作,我想重構我的語法以產生表示表達式的「Term」對象的層次結構,包括執行該特定的邏輯操作。根術語對象然後可以簡單地評估爲具體的結果。爲什麼Antlr在處理我的語法時進入無限循環

我不得不重寫很多我的語法,最後擺脫了最後的錯誤信息。不幸的是,現在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' 
| '\\' '\"' 
| '\\' '\'' 
| '\\' '\\' 
; 

非常感謝幫助。

克里斯

+0

您是否嘗試過在所有調試呢? – 2012-03-22 17:49:28

+0

爲什麼你既啓用了全局回溯又定義了一個常量k? – 2012-03-22 18:28:01

+0

是的......好吧,我用帽子的k參數,因爲舊版本有它。我不得不承認,對於這樣複雜的(至少對我來說)語法來說,我很新。我離開了,什麼沒有造成傷害:-) – 2012-03-22 22:10:12

回答

1

因爲你的語法是如此令人難以置信的曖昧,ANTLR具有創建解析器的問題。顯然ANTLR 3.3+扼流圈,但ANTLR 3.2(比3.3+時間少)產生以下錯誤:

error(10): internal error: org.antlr.tool.Grammar.createLookaheadDFA(Grammar.java:1279): could not even do k=1 for decision 1; reason: timed out (>1000ms)

對於一個簡單的表達式解析器,你真的不應該使用backtrack=true

除了語法不明確之外,大部分嵌入式代碼都包含錯誤。

讓我們看看你的formula規則:

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

此外,規則的返回類型進行明確定義。在{ $term = a; }a應該有一個$在它的前面:

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

但隨後$a指的是整個「東西」 expression回報。然後你必須「告訴」你想要Term這個expression創建的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語法的現有表達式解析器,然後再試一次。看看這些問與答& A的:所有的

+0

是的......我已經發現了自己的一部分東西。所有的「$ a.term」和類似的東西現在被整理出來,代碼被生成,實際編譯。我簡單地評論了很多選項,並且直接生成直到看起來破壞構建的一個片段。我打開了回溯功能,因爲我收到了一些錯誤,提示我打開它。我只是發佈更新的語法,這應該工作...除了真正importang語言功能被diabled :( – 2012-03-22 22:15:13

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' 
| '\\' '\"' 
| '\\' '\'' 
| '\\' '\\' 
; 

再次感謝你的解釋......它讓我在正確的軌道上:-)

克里斯