字符串插值的语法,其中格式错误的插值被视为正常字符串
Grammar for string interpolation where malformed interpolations are treated as normal strings
这是我要解析的语言的一个子集:
- 一个程序由语句组成
- 一个语句就是一个赋值:
A = "b"
- 赋值的左边是标识符(全部大写)
- 赋值的右边是一个用引号括起来的字符串
- 字符串通过插入括号括起来的标识符支持字符串插值(
A = "b[C]d"
)
到目前为止,这是足够直接的。这是有效的方法:
词法分析器:
lexer grammar string_testLexer;
STRING_START: '"' -> pushMode(STRING);
WS: [ \t\r\n]+ -> skip ;
ID: [A-Z]+;
EQ: '=';
mode STRING;
VAR_START: '[' -> pushMode(INTERPOLATION);
DOUBLE_QUOTE_INSIDE: '"' -> popMode;
REGULAR_STRING_INSIDE: ~('"'|'[')+;
mode INTERPOLATION;
ID_INSIDE: [A-Z]+;
CLOSE_BRACKET_INSIDE: ']' -> popMode;
解析器:
parser grammar string_testParser;
options { tokenVocab=string_testLexer; }
mainz: stat *;
stat: ID EQ string;
string: STRING_START string_part* DOUBLE_QUOTE_INSIDE;
string_part: interpolated_var | REGULAR_STRING_INSIDE;
interpolated_var: VAR_START ID_INSIDE CLOSE_BRACKET_INSIDE;
到目前为止一切顺利。但是还有一种语言功能:
- 如果括号中没有有效标识符(即全部大写),则视为普通字符串。
例如:
A = "hello" => "hello"
B = "h[A]a" => "h", A, "a"
C="h [A] a" => "h ", A, " a"
D="h [A][V] a" => "h ", A, V, " a"
E = "h [A] [V] a" => "h ", A, " ", V, " a"
F = "h [aVd] a" => "h [aVd] a"
G = "h [Va][VC] a" => "h [Va]", VC, " a"
H = "h [V][][ff[Z]" => "h ", V, "[][ff", Z
我试图将 REGULAR_STRING_INSIDE: ~('"'|'[')+;
替换为 REGULAR_STRING_INSIDE: ~('"')+;
,但这在 ANTLR 中不起作用。它导致将上面的所有行匹配为字符串。
因为在 ANTLR4 中没有启用回溯我不确定如何克服这个问题并告诉 ANTLR 如果它不匹配 interpolated_var
规则它应该继续匹配 REGULAR_STRING_INSIDE
相反,它似乎总是选择后者。
我读到词法分析器总是匹配最长的标记,所以我尝试将 REGULAR_STRING_INSIDE
和 VAR_START
提升为解析器规则,希望解析器中的替代顺序将得到尊重:
r: REGULAR_STRING_INSIDE
v: VAR_START
string: STRING_START string_part* DOUBLE_QUOTE_INSIDE;
string_part: v ID_INSIDE CLOSE_BRACKET_INSIDE | r;
这似乎没有任何区别。
我还读到 antlr4 semantic predicates 可以提供帮助。但是我很难想出在这种情况下需要应用的那些。
如何修改上面的语法,使其可以匹配两个内插位,或者如果它们格式不正确,则将它们视为字符串?
测试输入:
A = "hello"
B = "h[A]a"
C="h [A] a"
D="h [A][V] a"
E = "h [A] [V] a"
F = "h [aVd] a"
G = "h [Va][VC] a"
H = "h [V][][ff[Z]"
我如何编译/测试:
antlr4 string_testLexer.g4
antlr4 string_testParser.g4
javac *.java
grun string_test mainz st.txt -tree
I tried to replace REGULAR_STRING_INSIDE: ~('"'|'[')+; With just REGULAR_STRING_INSIDE: ~('"')+;, but that does not work in ANTLR. It results in matching all the lines above as strings.
正确,ANTLR 尝试尽可能匹配。所以 ~('"')+
太贪心了。
I also read that antlr4 semantic predicates could help.
只有在万不得已时才使用谓词。它在您的语法中引入了目标特定代码。如果不需要(在本例中不需要),则不要使用它们。
尝试这样的事情:
REGULAR_STRING_INSIDE
: ( ~( '"' | '[' )+
| '[' [A-Z]* ~( ']' | [A-Z] )
| '[]'
)+
;
上面的规则将读作:
- 匹配
"
或 [
以外的任何字符一次或多次
- OR 匹配
[
后跟零个或多个大写字母,后跟 ]
以外的任何字符或大写字母(您的 [Va
和 [aVd
情况)
- 或匹配一个空块,
[]
并匹配以上 3 个备选方案之一或多次以创建单个 REGULAR_STRING_INSIDE
.
如果字符串可以以 one 或 mote [
结尾,您可能还想这样做:
DOUBLE_QUOTE_INSIDE
: '['* '"' -> popMode
;
这是我要解析的语言的一个子集:
- 一个程序由语句组成
- 一个语句就是一个赋值:
A = "b"
- 赋值的左边是标识符(全部大写)
- 赋值的右边是一个用引号括起来的字符串
- 字符串通过插入括号括起来的标识符支持字符串插值(
A = "b[C]d"
)
到目前为止,这是足够直接的。这是有效的方法:
词法分析器:
lexer grammar string_testLexer;
STRING_START: '"' -> pushMode(STRING);
WS: [ \t\r\n]+ -> skip ;
ID: [A-Z]+;
EQ: '=';
mode STRING;
VAR_START: '[' -> pushMode(INTERPOLATION);
DOUBLE_QUOTE_INSIDE: '"' -> popMode;
REGULAR_STRING_INSIDE: ~('"'|'[')+;
mode INTERPOLATION;
ID_INSIDE: [A-Z]+;
CLOSE_BRACKET_INSIDE: ']' -> popMode;
解析器:
parser grammar string_testParser;
options { tokenVocab=string_testLexer; }
mainz: stat *;
stat: ID EQ string;
string: STRING_START string_part* DOUBLE_QUOTE_INSIDE;
string_part: interpolated_var | REGULAR_STRING_INSIDE;
interpolated_var: VAR_START ID_INSIDE CLOSE_BRACKET_INSIDE;
到目前为止一切顺利。但是还有一种语言功能:
- 如果括号中没有有效标识符(即全部大写),则视为普通字符串。
例如:
A = "hello" => "hello"
B = "h[A]a" => "h", A, "a"
C="h [A] a" => "h ", A, " a"
D="h [A][V] a" => "h ", A, V, " a"
E = "h [A] [V] a" => "h ", A, " ", V, " a"
F = "h [aVd] a" => "h [aVd] a"
G = "h [Va][VC] a" => "h [Va]", VC, " a"
H = "h [V][][ff[Z]" => "h ", V, "[][ff", Z
我试图将 REGULAR_STRING_INSIDE: ~('"'|'[')+;
替换为 REGULAR_STRING_INSIDE: ~('"')+;
,但这在 ANTLR 中不起作用。它导致将上面的所有行匹配为字符串。
因为在 ANTLR4 中没有启用回溯我不确定如何克服这个问题并告诉 ANTLR 如果它不匹配 interpolated_var
规则它应该继续匹配 REGULAR_STRING_INSIDE
相反,它似乎总是选择后者。
我读到词法分析器总是匹配最长的标记,所以我尝试将 REGULAR_STRING_INSIDE
和 VAR_START
提升为解析器规则,希望解析器中的替代顺序将得到尊重:
r: REGULAR_STRING_INSIDE
v: VAR_START
string: STRING_START string_part* DOUBLE_QUOTE_INSIDE;
string_part: v ID_INSIDE CLOSE_BRACKET_INSIDE | r;
这似乎没有任何区别。
我还读到 antlr4 semantic predicates 可以提供帮助。但是我很难想出在这种情况下需要应用的那些。
如何修改上面的语法,使其可以匹配两个内插位,或者如果它们格式不正确,则将它们视为字符串?
测试输入:
A = "hello"
B = "h[A]a"
C="h [A] a"
D="h [A][V] a"
E = "h [A] [V] a"
F = "h [aVd] a"
G = "h [Va][VC] a"
H = "h [V][][ff[Z]"
我如何编译/测试:
antlr4 string_testLexer.g4
antlr4 string_testParser.g4
javac *.java
grun string_test mainz st.txt -tree
I tried to replace REGULAR_STRING_INSIDE: ~('"'|'[')+; With just REGULAR_STRING_INSIDE: ~('"')+;, but that does not work in ANTLR. It results in matching all the lines above as strings.
正确,ANTLR 尝试尽可能匹配。所以 ~('"')+
太贪心了。
I also read that antlr4 semantic predicates could help.
只有在万不得已时才使用谓词。它在您的语法中引入了目标特定代码。如果不需要(在本例中不需要),则不要使用它们。
尝试这样的事情:
REGULAR_STRING_INSIDE
: ( ~( '"' | '[' )+
| '[' [A-Z]* ~( ']' | [A-Z] )
| '[]'
)+
;
上面的规则将读作:
- 匹配
"
或[
以外的任何字符一次或多次 - OR 匹配
[
后跟零个或多个大写字母,后跟]
以外的任何字符或大写字母(您的[Va
和[aVd
情况) - 或匹配一个空块,
[]
并匹配以上 3 个备选方案之一或多次以创建单个 REGULAR_STRING_INSIDE
.
如果字符串可以以 one 或 mote [
结尾,您可能还想这样做:
DOUBLE_QUOTE_INSIDE
: '['* '"' -> popMode
;