匹配Lexer中的所有文本并将其标记为一个标记,直到ANTLR4中的某个字符串

匹配Lexer中的所有文本并将其标记为一个标记,直到ANTLR4中的某个字符串,antlr4,tokenize,lexer,Antlr4,Tokenize,Lexer,在ANTLR4中,在流包含某个多字符字符串之前,匹配任意字符串的正确lexer规则是什么 例如,在CharStream中,我有: #integer12314#end #freetextFoo bar#end 我想从Foo-bar创建一个令牌类型为TEXT的令牌 每个条目都用#end标记关闭 文本由[\u001-\u007f]*组成,但现在我们先忘掉空格交互 文本可以包含、#e、#en 从上面的CharStream中,我期望令牌流为: tokenOf(#integer) Integer to

在ANTLR4中,在流包含某个多字符字符串之前,匹配任意字符串的正确lexer规则是什么

例如,在CharStream中,我有:

#integer12314#end
#freetextFoo bar#end
我想从
Foo-bar
创建一个令牌类型为
TEXT
的令牌

  • 每个条目都用
    #end
    标记关闭
  • 文本
    [\u001-\u007f]*
    组成,但现在我们先忘掉空格交互
  • 文本
    可以包含
    #e
    #en
从上面的CharStream中,我期望令牌流为:

tokenOf(#integer) Integer tokenOf(#end) tokenOf(#freetext) TEXT tokenOf(#end)
显然,我可以尝试在lexer语法中以以下方式解决此问题:

TEXT : [\u0001-\u007f]+? '#end'
但它也将包含结束标记,解析器语法更难看

(奖金问题:

  • 如何正确捕获
    文本中的空白,但可能需要lexer模式来拯救
  • 如何避免来自
    标识符:[a-zA-Z\[a-zA-Z0-9\$]*
    和其他lexer定义的干扰。 )

作为一个临时解决方案,我选择将所有非端点放入Lexer规则:

TEXT : (NOT_END1 | NOT_END2 | NOT_END3 | NOT_END4)+ ;

fragment NOT_END1 :       [\u0001-"$-\u007f] ;  // # is between # and $ in ASCII
fragment NOT_END2 : '#'   [\u0001-df-\u007f] ;  // e is between d and f
fragment NOT_END3 : '#e'  [\u0001-mo-\u007f] ;  // n is between m and o
fragment NOT_END4 : '#en' [\u0001-ce-\u007f] ;  // d is between c and e

END : '#end'
由于这简直是丑恶至极,我对这种可耻的行为感到很难过:-),我希望有更优雅的解决方案。

编辑 在lexer规则中添加+的任何尝试,例如

TEXT : (NOT_END1 ...)+ ;
fragment NOT_END1 : [\u0001-"$-\u007f] ;
消耗太多

有关
OTHER:;

使用此文件
input.txt

#integer12314#end
#freetext x'010203' #end
#freetext##end
#freetext#e#end
#freetext#en e n d # en nd##end
#freetext#e x'040506' #en  #end
其中,我插入了010203和040506,使用:

文件问题_any.g4:

grammar Question_any;

prog
@init {System.out.println("Question_any last update 0901");}
    :   ( line
            {System.out.println("Found line " + $line.source_line + " `" + $line.text + "`");}
        )+ EOF
    ;

line returns [int source_line]
@init {$source_line = getCurrentToken().getLine();}
    :   SHARP_INT INTEGER SHARP_END
    |   SHARP_FREE ANY+ SHARP_END
    ;

SHARP_INT  : '#integer' ;
SHARP_FREE : '#freetext' ;
SHARP_END  : '#end' ;
INTEGER    : [0-9]+ ;
NL         : [\r\n]+ -> skip ;
WS         : [ \t]+ -> channel(HIDDEN) ;

ANY        : [\u0001-\u007f] ; // must be after WS
执行:

$ grun Question_any prog -tokens input.txt 
[@0,0:7='#integer',<'#integer'>,1:0]
[@1,8:12='12314',<INTEGER>,1:8]
[@2,13:16='#end',<'#end'>,1:13]
[@3,18:26='#freetext',<'#freetext'>,2:0]
[@4,27:27='',<ANY>,2:9]
[@5,28:28='',<ANY>,2:10]
[@6,29:29='',<ANY>,2:11]
[@7,30:33='#end',<'#end'>,2:12]
...
[@35,98:106='#freetext',<'#freetext'>,6:0]
[@36,107:107='#',<ANY>,6:9]
[@37,108:108='e',<ANY>,6:10]
[@38,109:109=' ',<WS>,channel=1,6:11]
[@39,110:110='',<ANY>,6:12]
[@40,111:111='',<ANY>,6:13]
[@41,112:112='',<ANY>,6:14]
[@42,113:113='#',<ANY>,6:15]
[@43,114:114='e',<ANY>,6:16]
[@44,115:115='n',<ANY>,6:17]
[@45,116:117='  ',<WS>,channel=1,6:18]
[@46,118:121='#end',<'#end'>,6:20]
[@47,123:122='<EOF>',<EOF>,7:0]
Question_any last update 0901
Found line 1 `#integer12314#end`
Found line 2 `#freetext#end`
Found line 3 `#freetext##end`
Found line 4 `#freetext#e#end`
Found line 5 `#freetext#en e n d # en nd##end`
Found line 6 `#freetext#e #en  #end`
$grun Question\u any prog-tokens input.txt
[@0,0:7='#整数',1:0]
[@1,8:12='12314',,1:8]
[@2,13:16='#end',1:13]
[@3,18:26='#freetext',2:0]
[@4,27:27='',,2:9]
[@5,28:28='',,2:10]
[@6,29:29='',,2:11]
[@7,30:33='#end',2:12]
...
[@35,98:106='#freetext',6:0]
[@36,107:107='#',,6:9]
[@37108:108='e',6:10]
[@38109:109='',频道=1,6:11]
[@39,110:110='',,6:12]
[@40,111:111='',,6:13]
[@41,112:112='',,6:14]
[@42,113:113='#',,6:15]
[@43114:114='e',6:16]
[@44115:115='n',6:17]
[@45116:117='',频道=1,6:18]
[@46118:121='#end',6:20]
[@47,123:122='',,7:0]
问题\u任何最新更新0901
找到第1行`#整数12314#结束`
找到第2行“#freetext#end”`
找到第3行“#freetext###end”`
找到第4行“#freetext#e#end”`
找到第5行“#freetext#en en n d#en nd#end”`
找到第6行“#freetext#e#en#end”`

特殊字符没有打印出来。

Hi@BernardK,谢谢你的回答!这是一个很好的解决方案,我将对此进行投票,如果没有更好的答案,我将接受它,因为它是我原来问题的解决方案,而且我似乎有点过度设计了我的语法:D。但是,请注意,你通过u使用解析器规则(最初的问题是关于在Lexer中执行此操作)。@t我知道理想的Lexer规则是
TEXT:[\u0001-\u007f]+?~'#end'
,但这是不允许的。让我们拭目以待,看看专家们是否有更好的想法。@TFuto-Edited。由于lexer规则是贪婪的,我看不到其他解决方案,只能逐个使用字符。由于“Foo-bar”可以包含所有ASCII字符,因此规则+优先于
SHARP#end:“#end”
$ grun Question_any prog -tokens input.txt 
[@0,0:7='#integer',<'#integer'>,1:0]
[@1,8:12='12314',<INTEGER>,1:8]
[@2,13:16='#end',<'#end'>,1:13]
[@3,18:26='#freetext',<'#freetext'>,2:0]
[@4,27:27='',<ANY>,2:9]
[@5,28:28='',<ANY>,2:10]
[@6,29:29='',<ANY>,2:11]
[@7,30:33='#end',<'#end'>,2:12]
...
[@35,98:106='#freetext',<'#freetext'>,6:0]
[@36,107:107='#',<ANY>,6:9]
[@37,108:108='e',<ANY>,6:10]
[@38,109:109=' ',<WS>,channel=1,6:11]
[@39,110:110='',<ANY>,6:12]
[@40,111:111='',<ANY>,6:13]
[@41,112:112='',<ANY>,6:14]
[@42,113:113='#',<ANY>,6:15]
[@43,114:114='e',<ANY>,6:16]
[@44,115:115='n',<ANY>,6:17]
[@45,116:117='  ',<WS>,channel=1,6:18]
[@46,118:121='#end',<'#end'>,6:20]
[@47,123:122='<EOF>',<EOF>,7:0]
Question_any last update 0901
Found line 1 `#integer12314#end`
Found line 2 `#freetext#end`
Found line 3 `#freetext##end`
Found line 4 `#freetext#e#end`
Found line 5 `#freetext#en e n d # en nd##end`
Found line 6 `#freetext#e #en  #end`