gpt4 book ai didi

在 ANTLR 中解析字符串插值

转载 作者:行者123 更新时间:2023-12-04 17:05:37 26 4
gpt4 key购买 nike

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

例如:

name = "Bob"
msg = "Hello ${name}!"
print(msg) # prints "Hello Bob!"

我正在尝试在 ANTLRv3 中实现我的解析器,但是我对使用 ANTLR 非常缺乏经验,所以我不确定如何实现这个功能。到目前为止,我已经在词法分析器中指定了我的字符串文字,但在这种情况下,我显然需要在解析器中处理插值内容。

我当前的字符串文字语法如下所示:
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
;

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

我用一个小的 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
;

还有一个带有主要方法的类来测试它:
package antlrdemo;

import org.antlr.runtime.*;

public class ANTLRDemo {
public static void main(String[] args) throws RecognitionException {
String source = "name = \"Bob\"; \n"+
"msg = \"Hello ${name}\"; \n"+
"print(msg); \n"+
"print(\"Bye \\${for} now!\"); ";
ANTLRStringStream in = new ANTLRStringStream(source);
StrLexer lexer = new StrLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
StrParser parser = new StrParser(tokens);
parser.parse();
}
}

产生以下输出:
> Hello Bob
> Bye \${for} now!

同样,我不是专家,但这(至少)为您提供了一种解决方法。

哈。

关于在 ANTLR 中解析字符串插值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1850468/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com