三引号字符串的antlr语法

问题描述 投票:0回答:2

我正在尝试更新遵循以下规范的 ANTLR 语法

https://github.com/facebook/graphql/pull/327/files

用逻辑术语来说,它的定义为

StringValue ::
   - `"` StringCharacter* `"`
   - `"""` MultiLineStringCharacter* `"""`

StringCharacter ::
  - SourceCharacter but not `"` or \ or LineTerminator
  - \u EscapedUnicode
  - \ EscapedCharacter

MultiLineStringCharacter ::
  - SourceCharacter but not `"""` or `\"""`
  - `\"""`

(以上不符合逻辑 - 不是 ANTLR 语法)

我在 ANTRL 4 中尝试了以下操作,但它无法识别三重引号字符串中的超过 1 个字符

string : triplequotedstring | StringValue ;

triplequotedstring: '"""' triplequotedstringpart?  '"""';

triplequotedstringpart : EscapedTripleQuote* | SourceCharacter*;

EscapedTripleQuote : '\\"""';

SourceCharacter :[\u0009\u000A\u000D\u0020-\uFFFF];

StringValue: '"' (~(["\\\n\r\u2028\u2029])|EscapedChar)* '"';

使用这些规则,它将识别 '"""a"""' 但一旦我添加更多字符,它就会失败

eg: '"""abc"""' 不会解析并且 ANTLR 的 IntelliJ 插件说

line 1:14 extraneous input 'abc' expecting {'"""', '\\"""', SourceCharacter}

如何在 ANTLR 中使用 '\"""' 转义来处理三重引号字符串?

java antlr antlr4 graphql graphql-java
2个回答
1
投票

您的一些解析器规则实际上应该是词法分析器规则。

SourceCharacter
可能应该是
fragment

此外,您可能需要

EscapedTripleQuote* | SourceCharacter*
,而不是
( EscapedTripleQuote | SourceCharacter )*
。第一个匹配
aaa...
bbb...
,而您可能想匹配
aababbba...

尝试这样的事情:

string
 : Triplequotedstring 
 | StringValue 
 ;

Triplequotedstring
 : '"""' TriplequotedstringPart*? '"""'
 ;

StringValue
 : '"' ( ~["\\\n\r\u2028\u2029] | EscapedChar )* '"'
 ;

// Fragments never become a token of their own: they are only used inside other lexer rules
fragment TriplequotedstringPart : EscapedTripleQuote | SourceCharacter;
fragment EscapedTripleQuote : '\\"""';
fragment SourceCharacter :[\u0009\u000A\u000D\u0020-\uFFFF];

0
投票

三重引号字符串通常用于允许字符串中存在多行字符串和未转义字符。 假设您跳过空格和换行符,解析三重引号可能非常棘手,因为存在一些极端情况,例如:

  • 由于三引号是多行的,因此解析错误应该适应这一点。如果您将三引号定义为 lexer 的一部分,并且带有换行符,则行(和列)编号将是错误的。
  • 如果是 """"""" (一个双引号被三引号包围),解析的结果应该是一个字符串文字,内容为:“

为了解决上述问题,可以使用模式语法:

词法分析器:

START_TRIPLE_QUOTE: '"""' -> pushMode(INSIDE_TRIPLE_QUOTE);

mode INSIDE_TRIPLE_QUOTE;
TRIPLE_QUOTED_STRING_CONTENT : '"' '"'? ~["]  // Match one or two quotes followed by a non-quote
                             | ~["]           // Match any character that is not a quote
                             ;
TRIPLE_QUOTE_END_2: '"""""' -> popMode;
TRIPLE_QUOTE_END_1: '""""' -> popMode;
TRIPLE_QUOTE_END_0: '"""' -> popMode;

解析器:

triple_string_literal: START_TRIPLE_QUOTE (TRIPLE_QUOTED_STRING_CONTENT)*
                              (TRIPLE_QUOTE_END_2
                              | TRIPLE_QUOTE_END_1
                              | TRIPLE_QUOTE_END_0);

在你的听众/访客中:

TripleQuotedStringConst(ctx.getText().substring(3, ctx.getText().length() - 3))

作为参考,这是我写的一篇文章:https://medium.com/@alexzerntev/parsing-multi-line-triple-quoted-strings-with-antlr4-ceca41cdeadb

© www.soinside.com 2019 - 2024. All rights reserved.