字符串插值语法,其中格式错误的插值被视为正常字符串



下面是我想要解析的语言的子集:

  • 程序由语句组成
  • 语句就是赋值:A = "b"
  • 赋值的左侧是一个标识符(全部大写)
  • 赋值的右侧是一个用引号括起来的字符串
  • 字符串支持通过插入带括号的标识符(A = "b[C]d")进行字符串插值

到目前为止,这已经足够直接了。以下是有效的:

Lexer:

lexer grammar string_testLexer;
STRING_START: '"' -> pushMode(STRING);
WS: [ trn]+  -> 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,它似乎总是选择后者。

我读到lexer总是匹配最长的令牌,所以我尝试将REGULAR_STRING_INSIDEVAR_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

我试图用REGULARSTRING_INSIDE:~('"'|'[')+;替换REGULAR_STRING_INSIDE:~(")+;,但这在ANTLR中不起作用。这导致上面的所有行都匹配为字符串。

正确,ANTLR尽量匹配。所以~('"')+太贪婪了。

我还读到antlr4语义谓词可能会有所帮助。

只能在万不得已的情况下使用谓词。它在语法中引入了特定于目标的代码。如果不需要(在这种情况下是不需要的),那么就不要使用它们。

试试这样的东西:

REGULAR_STRING_INSIDE
: ( ~( '"' | '[' )+ 
| '[' [A-Z]* ~( ']' | [A-Z] ) 
| '[]'
)+
;

上面的规则是:

  1. 匹配"[以外的任何字符一次或多次
  2. 或匹配一个[,后跟零个或多个大写字母,后跟除]或大写字母以外的任何字符(您的[Va[aVd情况)
  3. OR匹配空块[]

并将上述3个备选方案中的一个匹配一次或多次,以创建单个REGULAR_STRING_INSIDE

如果一个字符串可以以一个或多个[结尾,您可能还想这样做:

DOUBLE_QUOTE_INSIDE
: '['* '"' -> popMode
;

相关内容

  • 没有找到相关文章

最新更新