第一:你有一个WS
将空格字符放置在隐藏通道上的规则,但在语法的后面,您有一个SPACES
规则。鉴于这种SPACES
规则放置在WS
并且匹配完全相同,SPACES
规则永远不会被匹配。
例如,“嗨你好,你好吗?”需要是单个标记,而不是由该语法生成的多个标记。
在当前的设置中您无法执行此操作。你能做的就是利用词汇模式 https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md#lexical-modes。一个快速演示:
// Must be in a separate file called DemoLexer.g4
lexer grammar DemoLexer;
START_1_TAG : '<%' -> pushMode(IN_TAG);
START_2_TAG : '<<' -> pushMode(IN_TAG);
TEXT : ( ~[<] | '<' ~[<%] )+;
mode IN_TAG;
ID : [A-Za-z_][A-Za-z0-9_]*;
INT_NUMBER : [0-9]+;
END_1_TAG : '%>' -> popMode;
END_2_TAG : '>>' -> popMode;
SPACE : [ \t\r\n] -> channel(HIDDEN);
要测试此词法分析器语法,请运行此类:
import org.antlr.v4.runtime.*;
public class Main {
public static void main(String[] args) {
String source = "<%FOO%>FOO BAR<<123>>456 mu!";
DemoLexer lexer = new DemoLexer(CharStreams.fromString(source));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
tokenStream.fill();
for (Token t : tokenStream.getTokens()) {
System.out.printf("%-20s %s\n", DemoLexer.VOCABULARY.getSymbolicName(t.getType()), t.getText());
}
}
}
这将打印:
START_1_TAG <%
ID FOO
END_1_TAG %>
TEXT FOO BAR
START_2_TAG <<
INT_NUMBER 123
END_2_TAG >>
TEXT 456 mu!
EOF <EOF>
在单独的解析器语法中使用词法分析器语法,如下所示:
// Must be in a separate file called DemoParser.g4
parser grammar DemoParser;
options {
tokenVocab=DemoLexer;
}
code
: codeBlock* EOF
;
...
EDIT
[...]但我对文本有点困惑:( ~[规则。你能进一步详细说明它的作用吗?
细分( ~[<] | '<' ~[<%] )+
:
( # start group
~[<] # match any char other than '<'
| # OR
'<' ~[<%] # match a '<' followed by any char other than '<' and '%'
)+ # end group, and repeat it once or more
并且,词汇模式可以被视为语义谓词的替代吗?
有点。语义谓词更强大:您可以通过纯代码检查其中您喜欢的任何内容。然而,一个很大的缺点是你在语法中混合了目标特定的代码,而词法模式适用于所有目标。因此,经验法则是尽可能避免谓词。