2009-02-02 13 views
19

Tôi đã xem qua tài liệu ANTLR v3 (và bản sao đáng tin cậy của tôi về "Tham chiếu ANTLR Definitive"), và dường như tôi không thể tìm ra một cách rõ ràng để thực hiện các chuỗi thoát trong chuỗi ký tự (Tôi hiện đang sử dụng mục tiêu Java). Tôi đã hy vọng để có thể làm điều gì đó như:Làm thế nào để xử lý các chuỗi thoát trong chuỗi ký tự trong ANTLR 3?

fragment 
ESCAPE_SEQUENCE 
    : '\\' '\'' { setText("'"); } 
    ; 

STRING 
    : '\'' (ESCAPE_SEQUENCE | ~('\'' | '\\'))* '\'' 
     { 
     // strip the quotes from the resulting token 
     setText(getText().substring(1, getText().length() - 1)); 
     } 
    ; 

Ví dụ, tôi muốn token đầu vào "'Foo\'s House'" để trở thành String "Foo's House".

Thật không may, cuộc gọi setText(...) trong đoạn ESCAPE_SEQUENCE đặt văn bản cho toàn bộ mã thông báo STRING, điều này rõ ràng không phải là thứ tôi muốn.

Có cách nào để thực hiện ngữ pháp này mà không thêm phương thức quay lại chuỗi kết quả và thay thế chuỗi thoát theo cách thủ công (ví dụ: với số setText(escapeString(getText())) trong quy tắc STRING)?

Trả lời

14

Đây là cách tôi thực hiện điều này trong trình phân tích cú pháp JSON mà tôi đã viết.

STRING  
@init{StringBuilder lBuf = new StringBuilder();} 
    : 
      '"' 
      (escaped=ESC {lBuf.append(getText());} | 
      normal=~('"'|'\\'|'\n'|'\r')  {lBuf.appendCodePoint(normal);})* 
      '"'  
      {setText(lBuf.toString());} 
    ; 

fragment 
ESC 
    : '\\' 
     ( 'n' {setText("\n");} 
     | 'r' {setText("\r");} 
     | 't' {setText("\t");} 
     | 'b' {setText("\b");} 
     | 'f' {setText("\f");} 
     | '"' {setText("\"");} 
     | '\'' {setText("\'");} 
     | '/' {setText("/");} 
     | '\\' {setText("\\");} 
     | ('u')+ i=HEX_DIGIT j=HEX_DIGIT k=HEX_DIGIT l=HEX_DIGIT 
        {setText(ParserUtil.hexToChar(i.getText(),j.getText(), 
               k.getText(),l.getText()));} 

     ) 
    ; 
+4

Tôi đã sử dụng phương pháp này, nhưng lưu ý rằng tôi phải thêm "getText()" thay vì "escaped.getText()" ở mỗi bước. Đoạn này viết văn bản chưa thoát gốc cho toàn bộ mã thông báo STRING, mà getText() trả về. Đối với tôi, escaped.getText() trả về đoạn ban đầu với các dấu gạch chéo ngược nguyên vẹn. –

3

Tôi cần làm điều đó, nhưng mục tiêu của tôi là C chứ không phải Java. Dưới đây là cách tôi đã làm điều đó dựa trên câu trả lời số 1 (và nhận xét), trong trường hợp ai đó cần một cái gì đó tương tự:

QUOTE :  '\''; 
STR 
@init{ pANTLR3_STRING unesc = GETTEXT()->factory->newRaw(GETTEXT()->factory); } 
     :  QUOTE (reg = ~('\\' | '\'') { unesc->addc(unesc, reg); } 
         | esc = ESCAPED { unesc->appendS(unesc, GETTEXT()); })+ QUOTE { SETTEXT(unesc); }; 

fragment 
ESCAPED :  '\\' 
       ('\\' { SETTEXT(GETTEXT()->factory->newStr8(GETTEXT()->factory, (pANTLR3_UINT8)"\\")); } 
       | '\'' { SETTEXT(GETTEXT()->factory->newStr8(GETTEXT()->factory, (pANTLR3_UINT8)"\'")); } 
       ) 
     ; 

HTH.

4

Một (có thể hiệu quả hơn) thay thế là sử dụng lập luận quy tắc:

STRING 
@init { final StringBuilder buf = new StringBuilder(); } 
: 
    '"' 
    (
    ESCAPE[buf] 
    | i = ~('\\' | '"') { buf.appendCodePoint(i); } 
    )* 
    '"' 
    { setText(buf.toString()); }; 

fragment ESCAPE[StringBuilder buf] : 
    '\\' 
    ('t' { buf.append('\t'); } 
    | 'n' { buf.append('\n'); } 
    | 'r' { buf.append('\r'); } 
    | '"' { buf.append('\"'); } 
    | '\\' { buf.append('\\'); } 
    | 'u' a = HEX_DIGIT b = HEX_DIGIT c = HEX_DIGIT d = HEX_DIGIT { buf.append(ParserUtil.hexChar(a, b, c, d)); } 
    ); 
+0

Ý tưởng hay, nó hoạt động tốt. Cám ơn vì đã chia sẻ. –

4

Đối ANTLR4, Java mục tiêu và tiêu chuẩn thoát chuỗi ngữ pháp, tôi đã sử dụng một lớp singleton chuyên dụng: CharSupport dịch chuỗi. Nó có sẵn trong API antlr:

STRING   : '"' 
       ( ESC 
       | ~('"'|'\\'|'\n'|'\r') 
       )* 
        '"' { 
         setText( 
          org.antlr.v4.misc.CharSupport.getStringFromGrammarStringLiteral(
           getText() 
          ) 
         ); 
        } 
       ; 

Như tôi đã thấy trong tài liệu V4 và bằng thử nghiệm, @init không còn được hỗ trợ trong phần lexer nữa!

+0

Định nghĩa của ESC trong ví dụ của bạn là gì? – Jaap