2012-11-15 31 views
1

好了,對於在兩天我的第三個ANTLR問題:遞歸處理規則在ANTLR

我的語法是爲了解析布爾語句,像這樣:

AGE > 21 AND AGE < 35 

由於這是一個比較簡單的語法,我嵌入代碼而不是使用AST。規則是這樣的:

: a=singleEvaluation { $evalResult = $a.evalResult;} 
(('AND') b=singleEvaluation {$evalResult = $evalResult && $b.evalResult;})+ 
{ 
// code 
} 
; 

現在我需要實現使用括號運算順序,來解析這樣的事情:

AGE >= 21 AND (DEPARTMENT=1000 OR DEPARTMENT=1001) 

甚至更​​糟:

AGE >= 21 AND (DEPARTMENT=1000 OR (EMPID=1000 OR EMPID=1001)) 

人建議一種實現遞歸所需的方法?我寧願不在這個晚期階段轉向AST,而且我仍然是一個相對的菜鳥。

傑森

回答

1

由於某些規則評估爲布爾值,和其他人一個整數(或僅比較整數),你最好讓你的規則返回一個通用對象,並進行相應的轉換。

這裏有一個快速的演示(包括括號表達式的情況下進行遞歸調用):

grammar T; 

@parser::members { 
    private java.util.Map<String, Integer> memory = new java.util.HashMap<String, Integer>(); 
} 

parse 
@init{ 
    // initialize some test values 
    memory.put("AGE", 42); 
    memory.put("DEPARTMENT", 999); 
    memory.put("EMPID", 1001); 
} 
: expression EOF {System.out.println($text + " -> " + $expression.value);} 
; 

expression returns [Object value] 
: logical {$value = $logical.value;} 
; 

logical returns [Object value] 
: e1=equality {$value = $e1.value;} ('AND' e2=equality {$value = (Boolean)$value && (Boolean)$e2.value;} 
            | 'OR' e2=equality {$value = (Boolean)$value || (Boolean)$e2.value;} 
            )* 
; 

equality returns [Object value] 
: r1=relational {$value = $r1.value;} ('=' r2=relational {$value = $value.equals($r2.value);} 
             | '!=' r2=relational {$value = !$value.equals($r2.value);} 
             )* 
; 

relational returns [Object value] 
: a1=atom {$value = $a1.value;} ('>=' a2=atom {$value = (Integer)$a1.value >= (Integer)$a2.value;} 
           | '>' a2=atom {$value = (Integer)$a1.value > (Integer)$a2.value;} 
           | '<=' a2=atom {$value = (Integer)$a1.value <= (Integer)$a2.value;} 
           | '<' a2=atom {$value = (Integer)$a1.value < (Integer)$a2.value;} 
           )? 
; 

atom returns [Object value] 
: INTEGER   {$value = Integer.valueOf($INTEGER.text);} 
| ID     {$value = memory.get($ID.text);} 
| '(' expression ')' {$value = $expression.value;} 
; 

INTEGER : '0'..'9'+; 
ID  : ('a'..'z' | 'A'..'Z')+; 
SPACE : ' ' {$channel=HIDDEN;}; 

分析輸入"AGE >= 21 AND (DEPARTMENT=1000 OR (EMPID=1000 OR EMPID=1001))"會導致下面的輸出:

AGE >= 21 AND (DEPARTMENT=1000 OR (EMPID=1000 OR EMPID=1001)) -> true 
+0

我不得不做出一些調整,特別是在原子規則。我使用Apache Commons BeanUtils對Java POJO進行了驗證,並在語法中定義了字段爲字符串/日期等的定義。但總的來說,這太棒了。再次感謝。 – Jason

1

我會做這樣的:

program : a=logicalExpression {System.out.println($a.evalResult);} 
     ; 

logicalExpression returns [boolean evalResult] : a=andExpression { $evalResult = $a.evalResult;} (('OR') b=andExpression {$evalResult = $evalResult || $b.evalResult;})* 
               ; 

andExpression returns [boolean evalResult]  : a=atomicExpression { $evalResult = $a.evalResult;} (('AND') b=atomicExpression {$evalResult = $evalResult && $b.evalResult;})* 
               ; 

atomicExpression returns [boolean evalResult] : a=singleEvaluation {$evalResult = $a.evalResult;} 
               | '(' b=logicalExpression ')' {$evalResult = $b.evalResult;} 
               ; 

singleEvaluation returns [boolean evalResult ] : 'TRUE' {$evalResult = true;} 
               | 'FALSE' {$evalResult = false;} 
               ;