如何使antlr4完全标记终端节点

时间:2017-09-16 17:53:02

标签: antlr4

我试图使用Antlr创建一个非常简单的解析器,它基本上标记了一系列.分隔的标识符。

我做了一个简单的语法:

r  : STRUCTURE_SELECTOR ;
STRUCTURE_SELECTOR: '.' (ID STRUCTURE_SELECTOR?)? ;
ID : [_a-z0-9$]* ;             
WS : [ \t\r\n]+ -> skip ;

生成解析器时,我最终会得到一个代表字符串的终端节点,而不是能够找到更多的STRUCTURE_SELECTOR。我想改为查看序列(可能表示为当前节点的子节点)。我怎么能做到这一点?

举个例子:

  • .将生成一个文本为.
  • 的终端节点
  • .foobar将产生两个节点,一个文本为.的父级和一个文本为foobar
  • 的子级
  • .foobar.baz将产生四个节点,一个文本为.的父级,一个文本为foobar的子级,一个文本为.的二级子级,另一个为具有文字baz的等级儿童。

1 个答案:

答案 0 :(得分:0)

以大写字母开头的规则是Lexer规则。

使用以下输入文件t.text

.
.foobar
.foobar.baz

你的语法(在文件Question.g4中)产生以下标记

$ grun Question r -tokens -diagnostics t.text
[@0,0:0='.',<STRUCTURE_SELECTOR>,1:0]
[@1,2:8='.foobar',<STRUCTURE_SELECTOR>,2:0]
[@2,10:20='.foobar.baz',<STRUCTURE_SELECTOR>,3:0]
[@3,22:21='<EOF>',<EOF>,4:0]

词法分析器(解析器)很贪心。它尝试使用规则读取尽可能多的输入字符(标记)。词法分析器STRUCTURE_SELECTOR: '.' (ID STRUCTURE_SELECTOR?)?可以读取点,ID,再次点和ID(由于重复标记?),直到NL。这就是为什么每一行都以一个令牌结束。

编译语法时,错误

warning(146): Question.g4:5:0: non-fragment lexer rule ID can match the empty string

是因为ID的重复标记是*(表示0次或更多次)而不是+(一次或多次)。

现在试试这个语法:

grammar Question;

r  
@init {System.out.println("Question last update 2135");}
    :   ( structure_selector NL )+ EOF
    ;

structure_selector
    :   '.'
    |   '.' ID structure_selector*
    ;

ID  : [_a-z0-9$]+ ;   
NL  : [\r\n]+ ;          
WS  : [ \t]+ -> skip ;

$ grun Question r -tokens -diagnostics t.text
[@0,0:0='.',<'.'>,1:0]
[@1,1:1='\n',<NL>,1:1]
[@2,2:2='.',<'.'>,2:0]
[@3,3:8='foobar',<ID>,2:1]
[@4,9:9='\n',<NL>,2:7]
[@5,10:10='.',<'.'>,3:0]
[@6,11:16='foobar',<ID>,3:1]
[@7,17:17='.',<'.'>,3:7]
[@8,18:20='baz',<ID>,3:8]
[@9,21:21='\n',<NL>,3:11]
[@10,22:21='<EOF>',<EOF>,4:0]
Question last update 2135
line 3:7 reportAttemptingFullContext d=1 (structure_selector), input='.'
line 3:7 reportContextSensitivity d=1 (structure_selector), input='.'

$ grun Question r -gui t.text显示您期望的分层树结构。