2010-01-11 36 views
12

Tôi vẫn đang ở trên my quest for a really simple language và bây giờ tôi biết rằng không có biến nào. Vì vậy, tôi đang viết một bản thân mình bằng cách sử dụng ANTLR3.Mở rộng ngữ pháp ANTLR đơn giản để hỗ trợ các biến đầu vào

Tôi tìm thấy một ví dụ thực sự tuyệt vời trong this answer:

Exp.g:

grammar Exp; 

eval returns [double value] 
    : exp=additionExp {$value = $exp.value;} 
    ; 

additionExp returns [double value] 
    : m1=multiplyExp  {$value = $m1.value;} 
     ('+' m2=multiplyExp {$value += $m2.value;} 
     | '-' m2=multiplyExp {$value -= $m2.value;} 
     )* 
    ; 

multiplyExp returns [double value] 
    : a1=atomExp  {$value = $a1.value;} 
     ('*' a2=atomExp {$value *= $a2.value;} 
     | '/' a2=atomExp {$value /= $a2.value;} 
     )* 
    ; 

atomExp returns [double value] 
    : n=Number    {$value = Double.parseDouble($n.text);} 
    | '(' exp=additionExp ')' {$value = $exp.value;} 
    ; 

Number 
    : ('0'..'9')+ ('.' ('0'..'9')+)? 
    ; 

WS 
    : (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;} 
    ; 

Java Code:

public Double evaluate(String string, Map<String, Double> input) throws RecognitionException { 
    ANTLRStringStream in = new ANTLRStringStream(string); 
    ExpLexer lexer = new ExpLexer(in); 
    CommonTokenStream tokens = new CommonTokenStream(lexer); 
    return new ExpParser(tokens).eval(); 
} 

Sử dụng ngữ pháp ANTLR này tôi có thể đánh giá biểu thức như

(12+14)/2 

và nhận kết quả là 13. Bây giờ điều duy nhất còn thiếu trong trường hợp sử dụng của tôi là một cách để tiêm biến kép đơn giản vào điều này, để tôi có thể đánh giá những điều sau bằng cách cung cấp {"A": 12.0, "B": 14.0} làm đầu vào bản đồ:

(A+B)/2 

Bất kỳ ý tưởng nào?

Trả lời

19

Bạn có thể tạo một Map<String, Double> memory trong phân tích cú pháp của bạn và giới thiệu một Identifier trong ngữ pháp của bạn:

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

Sau đó atomExp quy tắc phân tích cú pháp của bạn sẽ trông như thế này:

atomExp returns [double value] 
    : n=Number    {$value = Double.parseDouble($n.text);} 
    | i=Identifier   {$value = memory.get($i.text);} // <- added! 
    | '(' exp=additionExp ')' {$value = $exp.value;} 
    ; 

Dưới đây là một nhỏ (đầy đủ) demo:

grammar Exp; 

@parser::members { 

    private java.util.HashMap<String, Double> memory = new java.util.HashMap<String, Double>(); 

    public static Double eval(String expression) throws Exception { 
    return eval(expression, new java.util.HashMap<String, Double>()); 
    } 

    public static Double eval(String expression, java.util.Map<String, Double> vars) throws Exception { 
    ANTLRStringStream in = new ANTLRStringStream(expression); 
    ExpLexer lexer = new ExpLexer(in); 
    CommonTokenStream tokens = new CommonTokenStream(lexer); 
    ExpParser parser = new ExpParser(tokens); 
    parser.memory.putAll(vars); 
    return parser.parse(); 
    } 
} 

parse returns [double value] 
    : exp=additionExp {$value = $exp.value;} 
    ; 

additionExp returns [double value] 
    : m1=multiplyExp  {$value = $m1.value;} 
     ('+' m2=multiplyExp {$value += $m2.value;} 
     | '-' m2=multiplyExp {$value -= $m2.value;} 
     )* 
    ; 

multiplyExp returns [double value] 
    : a1=atomExp  {$value = $a1.value;} 
     ('*' a2=atomExp {$value *= $a2.value;} 
     | '/' a2=atomExp {$value /= $a2.value;} 
     )* 
    ; 

atomExp returns [double value] 
    : n=Number    {$value = Double.parseDouble($n.text);} 
    | i=Identifier   {$value = memory.get($i.text);} 
    | '(' exp=additionExp ')' {$value = $exp.value;} 
    ; 

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

Number 
    : ('0'..'9')+ ('.' ('0'..'9')+)? 
    ; 

WS 
    : (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;} 
    ; 

Và tại theres không cần phải nhanh chóng phân tích cú pháp/lexer chính mình, bạn chỉ có thể làm:

import org.antlr.runtime.*; 
import java.util.*; 

public class ANTLRDemo { 
    public static void main(String[] args) throws Exception { 
     Map<String, Double> vars = new HashMap<String, Double>(); 
     vars.put("two", 2.0); 
     vars.put("pi", Math.PI); 
     System.out.println(ExpParser.eval("two * pi", vars)); 
    } 
} 

mà sẽ tạo ra:

6.283185307179586 

Chúc may mắn!

+0

cảm ơn một lần nữa !!! – arturh

+0

Không sao, một lần nữa! :) –

8

Bah, mất thời gian để thực hiện điều này vì thế cũng có thể đăng nó, mặc dù tôi đã đánh bại với cú đấm :)

Trong ngữ pháp dưới đây tôi đã thực hiện định dạng của biến gán bạn đang tìm kiếm để làm .

grammar Exp; 



eval returns [double value] 
scope 
{ 
    java.util.Hashtable varMap; 
} 
@init 
{ 
    $eval::varMap = new java.util.Hashtable(); 
} 
: exp=additionExp {$value = $exp.value;} 
    | varList 
; 

additionExp returns [double value] 
    : m1=multiplyExp  {$value = $m1.value;} 
     ('+' m2=multiplyExp {$value += $m2.value;} 
     | '-' m2=multiplyExp {$value -= $m2.value;} 
     )* 
    ; 

multiplyExp returns [double value] 
    : a1=atomExp  {$value = $a1.value;} 
     ('*' a2=atomExp {$value *= $a2.value;} 
     | '/' a2=atomExp {$value /= $a2.value;} 
     )* 
    ; 

atomExp returns [double value] 
    : n=Number    {$value = Double.parseDouble($n.text);} 
    | v=ID   {$value = $eval::varMap.get($v);} 
    | '(' exp=additionExp ')' {$value = $exp.value;} 
    ; 

varList 
    : 
    OPEN_BRACE assignVar (COMMA assignVar)+ CLOSE_BRACE 
    ; 

assignVar 
    :QUOTE var=ID n=Number QUOTE COLON { $eval::varMap.put($var, $n); } 
    ; 


Number 
    : ('0'..'9')+ ('.' ('0'..'9')+)? 
    ; 

WS 
    : (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;} 
    ; 



fragment LETTER: LOWER | UPPER; 
fragment LOWER: 'a'..'z'; 
fragment UPPER: 'A'..'Z'; 

OPEN_BRACE 
    : '{' 
    ; 

CLOSE_BRACE 
    : '}' 
    ; 

COLON : ';'; 
COMMA : ','; 

QUOTE : '"'; 

ID 
: LETTER*; 
+0

Xin lỗi về điều đó Darien :). Vâng, tôi đã viết nghệ thuật ngữ pháp được đăng ở nơi đầu tiên, vì vậy tôi đã có một chút khởi đầu. 1 từ tôi tuy nhiên! –

+0

Không phải lo lắng, đó là một phần của những nguy hiểm khi đóng góp cho SO :) –

Các vấn đề liên quan