Antlr 3의 문자열 리터럴에서 탈출 시퀀스를 처리하는 방법?
문제
나는 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.