我正在尝试编写一种语法,将<<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>>
之类的内容将由两个规则匹配,func
和atom
。我希望它被识别为func
,因此我先将func
规则放在首位。
当我使用<word>
测试我的语法时,它会按预期将其视为atom
。但是,当我测试我的语法并给它<<word>>
时,它也会将其视为atom
。
我有什么遗失的吗?
PS - 我已将atom
分为PUNCT
,NEWLINE
和WORD
,并为其指定了标签#punctAtom
,#newlineAtom
和{ {1}}因为当我遍历解析树时,我想以不同的方式对待每一个。此外,#wordAtom
可以包含WORD
,因为,例如,有人可以写“Hello”,我想将其视为一个单词(以后简单介绍)。
PPS - 我尝试过的一件事是我在最后一条规则中加入了PUNCT
和<
,这是一个符号列表,我“禁止”存在于{ {1}}。这解决了一个问题,因为>
现在被识别为WORD
,但它会产生新问题,因为<<word>>
不再被func
接受。
答案 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>