Antlr 字符串插值语法,其中格式错误的插值被视为正常字符串
下面是我要分析的语言的子集:Antlr 字符串插值语法,其中格式错误的插值被视为正常字符串,antlr,antlr4,Antlr,Antlr4,下面是我要分析的语言的子集: 程序由语句组成 语句就是赋值:A=“b” 作业的左侧是一个标识符(所有大写) 赋值的右边是一个用引号括起来的字符串 字符串通过插入括号内的标识符来支持字符串插值(A=“b[C]d”) 到目前为止,这已经足够直截了当了。以下是有效的方法: Lexer: lexer grammar string_testLexer; STRING_START: '"' -> pushMode(STRING); WS: [ \t\r\n]+ -> skip ; ID:
- 程序由语句组成
- 语句就是赋值:
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;
到目前为止还不错。但是,还有一个语言特性:
- 如果括号中没有有效标识符(即所有大写),则将其视为普通字符串李>
普通字符串替换普通字符串:~(““”)+;
,但这在ANTLR中不起作用。它会将上面的所有行作为字符串进行匹配
由于在ANTLR4中没有回溯功能,因此我不确定如何克服这一问题,并告诉ANTLR,如果它不匹配插值的\u var
规则,它应该继续匹配内部的常规的\u字符串,\u,相反,它似乎总是选择后者
我读到lexer总是匹配最长的标记,所以我尝试将REGULAR\u STRING\u INSIDE
和VAR\u 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可能会有所帮助,但我很难想出在这种情况下需要应用的方法
如何修改上述语法,使其能够匹配两个插值位,或者如果它们的格式不正确,则将它们视为字符串?
测试输入:
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
我尝试将内部的规则字符串替换为内部的规则字符串,但在ANTLR中不起作用。它会将上面的所有行作为字符串进行匹配
正确,ANTLR会尽可能多地匹配。因此~(“”)+
将过于贪婪
我还读到antlr4语义谓词可能会有所帮助
只能使用谓词作为最后手段。它会在语法中引入特定于目标的代码。如果不需要(在本例中不是),则不要使用它们
试着这样做:
REGULAR_STRING_INSIDE
: ( ~( '"' | '[' )+
| '[' [A-Z]* ~( ']' | [A-Z] )
| '[]'
)+
;
上述规则应为:
一次或多次匹配除“
或[
以外的任何字符
或者匹配[
后跟零个或多个大写字母,后跟除]
以外的任何字符或大写字母(您的[Va
和[aVd
案例)
或者匹配一个空块,[]
并将上述3个备选方案中的一个匹配一次或多次,以在
中创建一个常规字符串
如果字符串可以以一个或多个字符结尾,您也可以这样做:
DOUBLE_QUOTE_INSIDE
: '['* '"' -> popMode
;
非常感谢。就你而言,这是写这段语法的最佳方式,还是仅仅是对所呈现的内容进行了最少的修改?我这么问是因为如果我不知道这些规则背后的意图,我会发现它们很难理解,所以自然地,我想知道是否有可能用更多的成语来表达还有,我非常希望能有一个简短的解释,解释一下为什么我的尝试没有奏效,以及为什么你的建议有效(而且确实有效!)。这将有助于我(和其他人)用ANTLR编写更好的语法。
DOUBLE_QUOTE_INSIDE
: '['* '"' -> popMode
;