当前位置: 首页 > 知识库问答 >
问题:

antlr4多行字符串解析

冉丰茂
2023-03-14

如果在antlr4 lexer中有一个ONELINE_STRING片段规则标识一行上的一个简单引号字符串,那么如何在lexer中创建一个更通用的字符串规则,该规则将相邻的ONELINE_STRING连接起来(即,只要它们都在不同的行上开始,仅用空格和/或注释分隔)?

即,

"foo" "bar" 

将被解析为两个字符串标记,“foo”后跟“bar”

同时:

"foo"
"bar"

示例1:

"desc" "this sample will parse as two strings.

Sample3(注意,'output'是该语言中的关键字):

output "this is a very long line that I've explicitly made so that it does not "
       "easily fit on just one line, so it gets split up into separate ones for "
       "ease of reading, but the  parser should see it all as one long string. "
       "This example will parse as if the output command had been followed by "
       "only a single string, even though it is composed of multiple string "
       "fragments, all of which should be invisible to the parser.%n";

这两个示例都应该被解析器接受为有效。前者是声明的例子,而后者是语言中命令语句的例子。

但是,我一直在想,可以使用ONELINE_STRING作为lexer规则,并使用一个通用的'string'解析器规则来检测相邻的ONELINE_STRINGS,在字符串之间使用谓词来检测下一个ONELINE_STRING标记是否开始于与前一个不同的行,如果是,它应该不可见地将它们连接起来,这样它的文本就无法与在一行上指定的字符串区分开来。然而,我不确定这将如何实施。

好吧,我拿到了。

正如你们中的一些人所建议的那样,我需要在解析器中有字符串识别器。诀窍是在lexer中使用lexer模式。

BEGIN_STRING : '"' -> pushMode(StringMode);

mode StringMode;
END_STRING: '"'-> popMode;
STRING_LITERAL_TEXT : ~[\r\n%"];
STRING_LITERAL_ESCAPE_QUOTE : '%"' { setText("\""); }; 
STRING_LITERAL_ESCAPE_PERCENT: '%%' { setText("%"); };
STRING_LITERAL_ESCAPE_NEWLINE : '%n'{ setText("\n"); };
UNTERMINATED_STRING: { _input.LA(1) == '\n' || _input.LA(1) == '\r' || _input.LA(1) == EOF}? -> popMode;

解析文件中,我有以下内容:

string returns [String text] locals [int line] : a=stringLiteral { $line = $a.line; $text=$a.text;}
                           ({_input.LT(1)!=null && _input.LT(1).getLine()>$line}? 
                            a=stringLiteral { $line = $a.line; $text+=$a.text; })*
                         ;

stringLiteral returns [int line, String text]: BEGIN_STRING {$text = "";}
    (a=(STRING_LITERAL_TEXT
    | STRING_LITERAL_ESCAPE_NEWLINE
    | STRING_LITERAL_ESCAPE_QUOTE
    | STRING_LITERAL_ESCAPE_PERCENT
    ) {$text+=$a.text;} )*
    stringEnd { $line = $BEGIN_STRING.line; }
  ;
stringEnd: END_STRING #string_finish
         | UNTERMINATED_STRING #string_hang
         ;

因此,只要相邻的字符串字元位于不同的行上,字符串规则就会将它们串联起来。stringEnd规则需要一个事件处理程序,用于当字符串文本没有正确终止时,这样解析器就可以报告语法错误,但在其他情况下,字符串将被视为正确关闭。

共有1个答案

冯渝
2023-03-14

编辑:对不起,没有完全阅读您的要求。下面的方法将匹配两个示例,而不仅仅是所需的示例。得好好想想...

最简单的方法是在解析器中执行此操作。我认为没有必要要求在lexer中这样做。

multiString : singleString +;
singleString : ONELINE_STRING; 


ONELINE_STRING: ...; // no fragment!
WS : ... -> skip;
Comment : ... -> skip;
 类似资料:
  • 在我的作业中,我对字符串Lexer有以下描述: “字符串文字由零个或多个用双引号(”“)括起的字符组成。使用转义序列(如下所列)表示字符串中的特殊字符。在字符串文本中出现新行或EOF字符是编译时错误。 所有支持的转义序列如下: \b退格 \f formfeed \r回车 \n换行符 \t水平选项卡 \“双引号 \反斜杠 以下是字符串文字的有效示例: "这是一个包含制表符\t的字符串" "他问我:\

  • 我有一种使用模式进行字符串插值的语法:大致如下: 现在这工作和标记一切主要是我想要的,但它确实有2个缺陷。 如果RBRACES的数量过多,它会弹出第一个默认模式,这会使IDE出现故障,而不仅仅是显示错误。 关闭块和关闭插值的标记是相同的,因此我无法根据需要突出显示它们。(这是主要的) 我的IDE仅基于令牌突出显示,所以这是一个问题,我希望能够以不同的方式突出显示它们。所以基本上我想要一个解决方案,

  • null null 以下是我的(不完整和不成功的)尝试: 如果不能在lexer中解决这个问题,我可以使用标记、、、、、和自行编写解析器规则。

  • 本文向大家介绍groovy 多行字符串,包括了groovy 多行字符串的使用技巧和注意事项,需要的朋友参考一下 示例            

  • 控制字符序列以'\为前缀,以\\结尾。在控制序列中有两个数字,它们指定控制字符。 在上面的示例中,结果字符串为 ESC代表不可打印的ASCII转义字符。 输入'a string'\ctrl\''会产生错误 你知道吗?顺便说一句:我们使用的是antlr V4.5。

  • 本文向大家介绍groovy 多行字符串(多余的换行符),包括了groovy 多行字符串(多余的换行符)的使用技巧和注意事项,需要的朋友参考一下 示例