ANTLR 语法规则的正确排序
ANTLR proper ordering of grammar rules
我正在尝试编写一种将 <<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
, 和 #wordAtom
因为我想在遍历解析树时区别对待它们中的每一个。此外,WORD
可以包含 PUNCT
因为,例如,有人可以写 "Hello," 并且我想将其视为一个单词(稍后为简单起见)。
PPS - 我试过的一件事是我在最后一条规则中包含了 <
和 >
,这是我 "disallowing" 存在于 WORD
中。这解决了一个问题,因为 <<word>>
现在被识别为 func
,但它产生了一个新问题,因为 <word>
不再被接受为 atom
.
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
。
我正在尝试编写一种将 <<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
, 和 #wordAtom
因为我想在遍历解析树时区别对待它们中的每一个。此外,WORD
可以包含 PUNCT
因为,例如,有人可以写 "Hello," 并且我想将其视为一个单词(稍后为简单起见)。
PPS - 我试过的一件事是我在最后一条规则中包含了 <
和 >
,这是我 "disallowing" 存在于 WORD
中。这解决了一个问题,因为 <<word>>
现在被识别为 func
,但它产生了一个新问题,因为 <word>
不再被接受为 atom
.
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
。