문제

나는 Antlr V3 문서 (그리고 "The Definitive Antlr Reference"의 신뢰할 수있는 사본)를 살펴보고 있었고 문자 그럴드에서 탈출 시퀀스를 구현할 수있는 깨끗한 방법을 찾을 수없는 것 같습니다 (현재 Java를 사용하고 있습니다. 표적). 나는 다음과 같은 일을 할 수 있기를 바랐다.

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

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

예를 들어, 입력 토큰을 원할 것입니다. "'Foo\'s House'"줄이되기 위해"Foo's House".

불행히도, setText(...) 전화로 전화하십시오 ESCAPE_SEQUENCE 파편은 전체의 텍스트를 설정합니다 STRING 토큰, 그것은 분명히 내가 원하는 것이 아닙니다.

결과 문자열을 다시 돌아가서 수동으로 이스케이프 시퀀스를 대체하는 방법을 추가하지 않고이 문법을 구현할 수있는 방법이 있습니까 (예 : setText(escapeString(getText())) 에서 STRING 규칙)?

도움이 되었습니까?

해결책

내가 쓴 JSON 파서에서 이것을 어떻게 달성했는지는 다음과 같습니다.

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()));}

        )
    ;

다른 팁

Antlr4, Java Target 및 Standard Escaped Strammar의 경우 전용 Singleton Class : Charsupport를 사용하여 String을 번역했습니다. Antlr API에서 사용할 수 있습니다.

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

v4 문서와 실험에서 본 것처럼 @init은 더 이상 Lexer 부분에서 지원되지 않습니다!

또 다른 (더 효율적인) 대안은 규칙 인수를 사용하는 것입니다.

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)); }
    );

나는 그 일을해야했지만 내 목표는 자바가 아니라 C였다. 다음은 답변 #1 (및 댓글)을 기반으로 한 방법입니다.

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top