antlr4多字符串解析(antlr4 multiline string parsing)

2019-10-20 02:08发布

如果我在标识上一行简单的引用字符串的antlr4词法分析器ONELINE_STRING片段规则,我怎么可以创建词法分析器更一般的字符串规则,将串联相邻ONELINE_STRING的(即仅由空格和/或注释分隔)只要他们各自开始在另一条线路?

"foo" "bar" 

将被解析为两个STRING令牌,“富”,其次是“栏”

而:

"foo"
"bar"

将被视为一个字符串标记指定:“foobar”

为了澄清:我们的想法是,虽然我一般都希望解析器能够识别相邻的字符串作为独立的,和空白和注释被解析器忽略,我想使用的想法,如果最后一个非空白子令牌上的线是一个字符串,并在下一行的第一子令牌是不是所有的空格也是一个字符串,则单独的字符串应该被级联成一个长的字符串作为确定潜在的非常长的字符串,而不必的手段把整个事情在一行。 这是非常简单的,如果我是希望所有相邻串子令牌连在一起,因为它们是用C ...但我的目的,我只希望在串子令牌在不同线路上开始发生级联。 这种串联应当是不可见的在可能使用一个字符串解析器任何规则。 这就是为什么我想这可能是更好的宅院词法分析器,而不是语法分析器中的规则,但我并不完全反对在解析器这样做,以及可能提到一个字符串标记所有的解析规则将而是指解析器字符串规则时,他们希望有一个字符串。

样本1:

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

样本3(注意,“输出”是语言中的关键字):

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作为词法规则,并有一个大致的“字符串”分析器检测相邻ONELINE_STRINGS规则,使用字符串之间的谓词如果下一个ONELINE_STRING令牌在开始检测不同的线路比以前的一个,如果是的话,应该看不见它们连接起来,这样它的文字是从已规定所有在同一行的字符串没有区别。 我不确定如何做到这一点实现了物流的,但是。

好吧,我有它。

我必须解析器的字符串识别器,因为你们中的一些建议。 诀窍是在词法分析器中使用的词法模式。

所以在词法文件我有这样的:

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规则需要在一个字符串文字非正常终止,这样分析器可以报告语法错误的事件处理程序,但如果它已经被正确关闭该字符串以其他方式处理。

Answer 1:

编辑:对不起,还没有完全阅读你的要求。 下面的方法将匹配这两个例子中,不仅所需的一个。 要想想吧...

最简单的方法是做到这一点的解析器。 我看到在词法分析器做是没有意义的,将要求这一点。

multiString : singleString +;
singleString : ONELINE_STRING; 


ONELINE_STRING: ...; // no fragment!
WS : ... -> skip;
Comment : ... -> skip;


Answer 2:

前面已经提到的,(IMO)更好的方式是处理这种分析器内。 但这里有一个方法来处理它在词法分析器:

STRING
 : SINGLE_STRING ( LINE_CONTINUATION SINGLE_STRING )*
 ;

HIDDEN
 : ( SPACE | LINE_BREAK | COMMENT ) -> channel(HIDDEN)
 ;

fragment SINGLE_STRING
 : '"' ~'"'* '"'
 ;

fragment LINE_CONTINUATION
 : ( SPACE | COMMENT )* LINE_BREAK ( SPACE | COMMENT )*
 ;

fragment SPACE
 : [ \t]
 ;

fragment LINE_BREAK
 : [\r\n]
 | '\r\n'
 ;

fragment COMMENT
 : '//' ~[\r\n]+
 ;

符号化的输入:

"a" "b"

"c"
"d"

"e"

"f"

将创建下列5个标记:

  • "a"
  • "b"
  • "c"\n"d"
  • "e"
  • "f"

但是,如果令牌将包括评论:

"c" // comment 
"d"

那么你需要剥离这种"// comment"在稍后阶段从令牌自己。 词法分析器将不能够放在一个不同的信道这个字串,或skip它。



文章来源: antlr4 multiline string parsing
标签: antlr antlr4