Antlr4 DM 字符串词法分析器规则

Antlr4 DM string lexer rules

我正在尝试以词法分析器形式表示 BYOND DM 语言字符串(参见 http://byond.com and http://byond.com/docs/ref)。以下是字符串的规则:

我正在尝试构建 ANTLR4 .g4 词法分析器规则来标记这些字符串。我认为我需要 4 种(或更多)令牌类型:

这是我的(不完整且不成功的)尝试:

LSTRING: '"' ('\[' | ~[[\r\n])* '[';
RSTRING: ']' ('\"' | ~["\r\n])* '"'; 
CSTRING: ']' ('\[' | ~[[\r\n])* '['; 
FSTRING: '"' ('\"' | ~["\r\n])* '"';

如果在词法分析器中无法解决这个问题,我可以用标记 @{""}、[=37= 自己编写解析器规则]、]\"。但是,我想我会试一试,因为它的性能会更好。

我用以下词法分析器花絮解决了这个问题。 Permalink

...
@lexer::members
{
ulong regularAccessLevel;
System.Collections.Generic.Stack<bool> multiString = new System.Collections.Generic.Stack<bool>();
}
...
VERBATIUM_STRING: '@"' (~["\r\n])* '"';
MULTILINE_VERBATIUM_STRING: '@{"' (~'"')* '"}';
MULTI_STRING_START: '{"' { multiString.Push(true); } -> pushMode(INTERPOLATION_STRING);
STRING_START: '"' { multiString.Push(false); } -> pushMode(INTERPOLATION_STRING);
...
LBRACE: '[' { ++regularAccessLevel; };
RBRACE: ']' { if(regularAccessLevel > 0) --regularAccessLevel; else if(multiString.Count > 0) { PopMode(); } };
...
mode INTERPOLATION_STRING;
CHAR_INSIDE: '\\''
    | '\"'
    | '\['
    | '\\'
    | '\0'
    | '\a'
    | '\b'
    | '\f'
    | '\n'
    | '\r'
    | '\t'
    | '\v'
    ;

EMBED_START: '[' -> pushMode(DEFAULT_MODE);
MULTI_STRING_CLOSE: {multiString.Peek()}? '"}' { multiString.Pop(); PopMode(); };
STRING_CLOSE: {!multiString.Peek()}? '"' { multiString.Pop(); PopMode(); };
STRING_INSIDE: {!multiString.Peek()}? ~('[' | '\' | '"' | '\r' | '\n')+;
MULTI_STRING_INSIDE: {multiString.Peek()}? ~('[' | '\' | '"')+;

某些字符串可能会导致它按顺序发出多个 STRING_INSIDE/MULTI_STRING_INSIDE 标记,但这是可以接受的,因为解析器无论如何都会吃掉它。

其中很多来自阅读 antlr4 示例中的 C# 内插字符串 permalink