ANTLR语法规则的正确排序

时间:2018-04-12 18:17:26

标签: antlr antlr4

我正在尝试编写一种语法,将<<word>>识别为特殊标记,但将<word>视为常规文字。

这是我的语法:

grammar test;

doc: item+ ;
item: func | atom ;

func: '<<' WORD '>>' ;
atom: PUNCT+            #punctAtom
    | NEWLINE+          #newlineAtom
    | WORD              #wordAtom
    ;

WS : [ \t] -> skip ;
NEWLINE : [\n\r]+ ;
PUNCT : [.,?!]+ ;
WORD : CHAR+ ;

fragment CHAR : (LETTER | DIGIT | SYMB | PUNCT) ;
fragment LETTER : [a-zA-Z] ;
fragment DIGIT : [0-9] ;
fragment SYMB : ~[a-zA-Z0-9.,?! |{}\n\r\t] ;

<<word>>之类的内容将由两个规则匹配,funcatom。我希望它被识别为func,因此我先将func规则放在首位。

当我使用<word>测试我的语法时,它会按预期将其视为atom。但是,当我测试我的语法并给它<<word>>时,它也会将其视为atom

我有什么遗失的吗?

PS - 我已将atom分为PUNCTNEWLINEWORD,并为其指定了标签#punctAtom#newlineAtom和{ {1}}因为当我遍历解析树时,我想以不同的方式对待每一个。此外,#wordAtom可以包含WORD,因为,例如,有人可以写“Hello”,我想将其视为一个单词(以后简单介绍)。

PPS - 我尝试过的一件事是我在最后一条规则中加入了PUNCT<,这是一个符号列表,我“禁止”存在于{ {1}}。这解决了一个问题,因为>现在被识别为WORD,但它会产生新问题,因为<<word>>不再被func接受。

1 个答案:

答案 0 :(得分:2)

ANTLR的词法分析器尝试匹配尽可能多的字符,因此<<WORD>><WORD>都与词法分析器WORD匹配。因此,在这些情况下,不会创建令牌<<>>(或<>)。

您可以通过运行以下代码行来查看正在创建的令牌:

Lexer lexer = new testLexer(CharStreams.fromString("<word> <<word>>"));
CommonTokenStream tokens = new CommonTokenStream(lexer);
tokens.fill();

for (Token t : tokens.getTokens()) {
  System.out.printf("%-20s %s\n", testLexer.VOCABULARY.getSymbolicName(t.getType()), t.getText());
}

将打印:

WORD                 <word>
WORD                 <<word>>
EOF                  <EOF>

你能做的是这样的事情:

func
 : '<<' WORD '>>' 
 ;

atom
 : PUNCT+   #punctAtom
 | NEWLINE+ #newlineAtom
 | word     #wordAtom
 ;

word
 : WORD
 | '<' WORD '>'
 ;

...

fragment SYMB : ~[<>a-zA-Z0-9.,?! |{}\n\r\t] ;

当然,foo<bar之类的内容不会成为单一的WORD,而之前就是这样。{/ p>