我正在尝试以词法分析器形式表示BYOND DM语言字符串(请参见http://byond.com和http://byond.com/docs/ref)。这是字符串的规则:
"hello world"
的值为hello world
"hello\"world"
的值为hello"world
"hello\
world"
的值为helloworld
{"
/ "}
打开/关闭,则允许换行并输入到最终字符串中。序列\\\n
仍然被忽略"hello [ "world" ] \["
在运行时求值为hello world [
。任何表达式都可以放在花括号中(通话,数学等)@{"hello [worl\d"}
和@"hello [worl\d"
均得出hello [worl\d
我正在尝试构建ANTLR4 .g4词法分析器规则来标记这些字符串。我认为我需要4种(或更多)令牌类型:
"hello world"
,@"hello world"
,@{"hello world"}
或{"hello world"}
"hello [
或{"hello [
] world"
或] world"}
] hello world [
这是我的尝试(不完整且不成功):
LSTRING: '"' ('\\[' | ~[[\r\n])* '[';
RSTRING: ']' ('\\"' | ~["\r\n])* '"';
CSTRING: ']' ('\\[' | ~[[\r\n])* '[';
FSTRING: '"' ('\\"' | ~["\r\n])* '"';
如果这在词法分析器中无法解决,我可以自己编写带有标记@
,{"
,"}
,[
的解析器规则, ]
,\\
和"
。但是,我想我会试一试,因为它会表现得更好。
答案 0 :(得分:0)
我用下面的词法小知识解决了它。 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示例permalink
中的C#内插字符串