Parsing ANTLR中的字符串插值解析

Parsing ANTLR中的字符串插值解析,parsing,antlr,string-interpolation,Parsing,Antlr,String Interpolation,我正在为内部目的开发一个简单的字符串操作DSL,我希望该语言能够支持Ruby中使用的字符串插值 例如: name = "Bob" msg = "Hello ${name}!" print(msg) # prints "Hello Bob!" 我正试图在ANTLRv3中实现我的解析器,但我对使用ANTLR非常缺乏经验,所以我不确定如何实现这个特性。到目前为止,我已经在lexer中指定了字符串文本,但在本例中,我显然需要在解析器中处理插值内容 我当前的字符串文字语法如下所示: STRINGLI

我正在为内部目的开发一个简单的字符串操作DSL,我希望该语言能够支持Ruby中使用的字符串插值

例如:

name = "Bob"
msg = "Hello ${name}!"
print(msg)   # prints "Hello Bob!"
我正试图在ANTLRv3中实现我的解析器,但我对使用ANTLR非常缺乏经验,所以我不确定如何实现这个特性。到目前为止,我已经在lexer中指定了字符串文本,但在本例中,我显然需要在解析器中处理插值内容

我当前的字符串文字语法如下所示:

STRINGLITERAL : '"' ( StringEscapeSeq | ~( '\\' | '"' | '\r' | '\n' ) )* '"' ;
fragment StringEscapeSeq : '\\' ( 't' | 'n' | 'r' | '"' | '\\' | '$' | ('0'..'9')) ;

将字符串文字处理移动到解析器中似乎会使其他一切停止工作。粗略的网络搜索没有产生任何信息。关于如何开始这方面的工作,有什么建议吗?

我不是ANTLR专家,但这里有一个可能的语法:

grammar Str;

parse
    :    ((Space)* statement (Space)* ';')+ (Space)* EOF
    ;

statement
    :    print | assignment
    ;

print
    :    'print' '(' (Identifier | stringLiteral) ')' 
    ;

assignment
    :    Identifier (Space)* '=' (Space)* stringLiteral
    ;

stringLiteral
    :    '"' (Identifier | EscapeSequence | NormalChar | Space | Interpolation)* '"'
    ;

Interpolation
    :    '${' Identifier '}'
    ;

Identifier
    :    ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
    ;

EscapeSequence
    :    '\\' SpecialChar
    ;

SpecialChar
    :     '"' | '\\' | '$'
    ;

Space
    :    (' ' | '\t' | '\r' | '\n')
    ;

NormalChar
    :    ~SpecialChar
    ;
正如您所注意到的,示例语法中有几个
(空格)*
-es。这是因为
stringLiteral
是解析器规则,而不是词法规则。因此,在标记源文件时,lexer无法知道空白是字符串文字的一部分,还是源文件中可以忽略的一个空格

我用一个小Java类测试了这个示例,所有这些都按预期工作:

/* the same grammar, but now with a bit of Java code in it */
grammar Str;

@parser::header {
    package antlrdemo;
    import java.util.HashMap;
}

@lexer::header {
    package antlrdemo;
}

@parser::members {
    HashMap<String, String> vars = new HashMap<String, String>();
}

parse
    :    ((Space)* statement (Space)* ';')+ (Space)* EOF
    ;

statement
    :    print | assignment
    ;

print
    :    'print' '(' 
         (    id=Identifier    {System.out.println("> "+vars.get($id.text));} 
         |    st=stringLiteral {System.out.println("> "+$st.value);}
         ) 
         ')' 
    ;

assignment
    :    id=Identifier (Space)* '=' (Space)* st=stringLiteral {vars.put($id.text, $st.value);}
    ;

stringLiteral returns [String value]
    :    '"'
        {StringBuilder b = new StringBuilder();} 
        (    id=Identifier           {b.append($id.text);}
        |    es=EscapeSequence       {b.append($es.text);}
        |    ch=(NormalChar | Space) {b.append($ch.text);}
        |    in=Interpolation        {b.append(vars.get($in.text.substring(2, $in.text.length()-1)));}
        )* 
        '"'
        {$value = b.toString();}
    ;

Interpolation
    :    '${' i=Identifier '}'
    ;

Identifier
    :    ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
    ;

EscapeSequence
    :    '\\' SpecialChar
    ;

SpecialChar
    :     '"' | '\\' | '$'
    ;

Space
    :    (' ' | '\t' | '\r' | '\n')
    ;

NormalChar
    :    ~SpecialChar
    ;
将生成以下输出:

> Hello Bob
> Bye \${for} now!
再说一遍,我不是专家,但这(至少)给了你一个解决问题的方法


嗯。

哇,看起来棒极了!让我测试一下,看看它是否适合我的设置。
> Hello Bob
> Bye \${for} now!