ANTLR 3内の文字列リテラル内のエスケープシーケンスを処理する方法は?

StackOverflow https://stackoverflow.com/questions/504402

  •  21-08-2019
  •  | 
  •  

質問

私はANTLR v3のドキュメント(および「確定ANTLRリファレンス」の私の信頼できるコピー)を介して見てきた、と私は文字列リテラルのエスケープシーケンスを実装するためのクリーンな方法を見つけるように見えることはできません(私は現在よ)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()));}

        )
    ;

他のヒント

文字列を変換するためにCharSupport:

ANTLR4については、Javaの目標と標準は、文字列の文法を脱出し、私は専用のシングルトンクラスを使用していました。それはANTLR APIで提供されます:

STRING          :   '"' 
                (   ESC  
                |   ~('"'|'\\'|'\n'|'\r') 
                )* 
                    '"' { 
                        setText( 
                            org.antlr.v4.misc.CharSupport.getStringFromGrammarStringLiteral(
                                getText()
                            )
                        ); 
                    }
                ;
私はV4のマニュアルおよび実験によって見たように、@Initはもはやレクサーの一部でサポートされています。

他の(おそらくより効率的な)別のルールの引数を使用することである。

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やJavaのではないでした。ここで私は誰にも似て何かを必要とする場合には、回答#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