programacion - tipos de variables en java
¿Cómo manejar secuencias de escape en literales de cadena en ANTLR 3? (4)
He estado buscando en la documentación ANTLR v3 (y en mi fiel copia de "The Definitive ANTLR reference"), y parece que no puedo encontrar una forma clara de implementar secuencias de escape en literales de cadenas (actualmente estoy usando Java objetivo). Tenía la esperanza de poder hacer algo como:
fragment
ESCAPE_SEQUENCE
: ''//' ''/''' { setText("''"); }
;
STRING
: ''/''' (ESCAPE_SEQUENCE | ~(''/''' | ''//'))* ''/'''
{
// strip the quotes from the resulting token
setText(getText().substring(1, getText().length() - 1));
}
;
Por ejemplo, me gustaría que el token de entrada " ''Foo/'s House''
" se convierta en la cadena " Foo''s House
".
Desafortunadamente, la setText(...)
en el fragmento ESCAPE_SEQUENCE
establece el texto para ESCAPE_SEQUENCE
completo, que obviamente no es lo que quiero.
¿Hay alguna manera de implementar esta gramática sin agregar un método para volver a través de la cadena resultante y reemplazar manualmente las secuencias de escape (por ejemplo, con algo como setText(escapeString(getText()))
en la regla STRING
?
Necesitaba hacer exactamente eso, pero mi objetivo era C y no Java. Así es como lo hice basado en la respuesta n. ° 1 (y comentario), en caso de que alguien necesite algo similar:
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.
Otra alternativa (posiblemente más eficiente) es usar argumentos de reglas:
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)); }
);
Así es como logré esto en el analizador JSON que escribí.
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()));}
)
;
Para ANTLR4, objetivo de Java y gramática de cadenas escapadas estándar, utilicé una clase singleton dedicada: CharSupport para traducir cadenas. Está disponible en antlr API:
STRING : ''"''
( ESC
| ~(''"''|''//'|''/n''|''/r'')
)*
''"'' {
setText(
org.antlr.v4.misc.CharSupport.getStringFromGrammarStringLiteral(
getText()
)
);
}
;
Como vi en la documentación de V4 y por experimentos, ¡@init ya no es compatible en la parte más lexer!