Antlr4 如何使用序列化,但不能作为结果返回

Antlr4 如何使用序列化,但不能作为结果返回,antlr4,Antlr4,我想使用规则或序列作为分隔符来标记文件,但不返回分隔符 我尝试使用->channel(hidden),但这会把解析搞砸 我的语法是这样的 grammar test; file : l1 l2? l3 ; l1 : 'L1:' STRING_LITERAL '\n' ; l2 : 'L2:'(NUMBER)+ '\n' ; l3 :'L3:' WORD|NUMBER '\n' ; NUMBER : [0-9]+ ; STRING_LITERAL : '"' (~

我想使用规则或序列作为分隔符来标记文件,但不返回分隔符

我尝试使用
->channel(hidden)
,但这会把解析搞砸

我的语法是这样的

grammar test;

file
 : l1 l2? l3
;

l1
 : 'L1:' STRING_LITERAL '\n'
;
l2
 : 'L2:'(NUMBER)+ '\n'
;
l3
 :'L3:' WORD|NUMBER '\n'
;


NUMBER          : [0-9]+ ;
STRING_LITERAL  : '"' (~["\\\r\n] | EscapeSequence)* '"';
WORD            : ('a'..'z' | 'A'..'Z')+;
fragment EscapeSequence
    : '\\' [btnfr"'\\]
    | '\\' ([0-3]? [0-7])? [0-7]
    ;
和一个输入文件,如

L1: "SO LONG"
L2: 42
L3: FISH
我不想返回
L1:
L2:
L3:
,但一定要返回“这么长”
42
FISH

我得到了我正在寻找的代币,但我也得到了
\n
L1:
L2:
L3:


我还注意到,如果将l1规则设置为l1:(~[“\\r\n])*;我可以匹配到行尾没有问题,但我将每个单词作为单独的标记。这对我来说很有意义,但有没有办法将其作为单个标记?

如果您希望能够在解析器中使用这些
L1:
标记,那么就没有办法删除它们。无论如何,我看不到真正的用例。但是,我不明白您为什么要这样做不能在lexer期间跳过(或隐藏)这些标记。这似乎很好:

parse
 : NL* line ( NL+ line )* NL* EOF
 ;

line
 : l1
 | l2
 | l3
 ;

l1 : STRING_LITERAL;
l2 : NUMBER+;
l3 : ( WORD | NUMBER );

NUMBER         : [0-9]+;
STRING_LITERAL : '"' ( ~["\\\r\n] | EscapeSequence )* '"';
WORD           : [a-zA-Z]+;

IGNORED
 : 'L' [0-9] ':' -> skip
 ;

SPACES
 : [ \t]+ -> skip
 ;

NL
 : '\r'? '\n'
 ;

fragment EscapeSequence
 : '\\' [btnfr"'\\]
 | '\\' ([0-3]? [0-7])? [0-7]
 ;
导致:

[…]所以我应该能够做一些类似于if(parser.l1()=“so LONG”)的事情,然后做一些事情

这不是ANTLR的工作方式。解析器生成一个解析树(包含您定义的所有标记)。然后可以使用该解析树从中提取值。可以通过手动遍历解析树或使用ANTLR的listener(或visitor)类来提取值:


这是我给您的建议:不要从lexer中跳过换行符和L1:标记,使用侦听器或访问者从解析树中检索数据。

如果您希望能够在解析器中使用这些
L1:
标记,则无法删除它们。无论如何,我看不到一个真正的用例。但是,我不明白为什么不能在lexer期间跳过(或隐藏)这些标记。这似乎很管用:

parse
 : NL* line ( NL+ line )* NL* EOF
 ;

line
 : l1
 | l2
 | l3
 ;

l1 : STRING_LITERAL;
l2 : NUMBER+;
l3 : ( WORD | NUMBER );

NUMBER         : [0-9]+;
STRING_LITERAL : '"' ( ~["\\\r\n] | EscapeSequence )* '"';
WORD           : [a-zA-Z]+;

IGNORED
 : 'L' [0-9] ':' -> skip
 ;

SPACES
 : [ \t]+ -> skip
 ;

NL
 : '\r'? '\n'
 ;

fragment EscapeSequence
 : '\\' [btnfr"'\\]
 | '\\' ([0-3]? [0-7])? [0-7]
 ;
导致:

[…]所以我应该能够做一些类似于if(parser.l1()=“so LONG”)的事情,然后做一些事情

这不是ANTLR的工作方式。解析器生成一个解析树(包含您定义的所有标记)。然后可以使用该解析树从中提取值。提取值可以通过手动遍历解析树或使用ANTLR的侦听器(或访问者)类来完成:


这是我给你的建议:不要
跳过
换行符和
L1:
从lexer中的标记,并使用侦听器或访问者从解析树中检索数据。

我还注意到,如果将L1规则设置为L1:(~[“\\\r\n])*;我可以匹配到行尾没问题,但我把每个单词都作为单独的标记。这对我来说是有意义的,但是有没有办法把它作为一个单一的标记呢?嗨,德米安,不要把其他信息作为评论发布,而是把它们放在问题=)谢谢你的建议!DoneAlso我注意到,如果将l1规则设置为l1:(~[“\\\r\n])*;我可以匹配到行尾没有问题,但我将每个单词作为单独的标记。这对我来说很有意义,但有没有办法将其作为单个标记?嗨,Demian,不要将其他信息作为注释发布,而是将它们放在问题=)谢谢你的建议!DoneThanks Bart。用例是解析器已经有了
解析器.l1()然后做一些类似的事情\n我希望它完全不被返回您需要解析器中的
\n
:它表示一行的结尾。没有它,你就无法分辨
L2:123\nL2:456\n
L2:123 456\n
之间的区别。啊,我现在明白了。非常感谢@BartKiers!谢谢你,巴特。用例是解析器已经有了
parser.l1()
方法,我希望它只返回值。本质上,我认为这是一个键值字典(也许这是一个错误的方式来看待它?),所以我应该能够做一些类似if(parser.l1()=“so LONG”)的事情然后做一些类似的事情\n我希望它根本不被返回你需要解析器中的
\n
:它表示一行的结尾。没有它,你就无法分辨
L2:123\nL2:456\n
L2:123456\n
之间的区别。啊,我现在明白了。非常感谢@BartKiers!