antlr4 - 根据输入流中的值设置 Lexer 规则
问题描述
我有这个简单的语法文件:
expr : ID Divider ID;
divider_stat : 'Divider' Divider;
Divider : '#';
ID : ALPHA ('_' | ALPHA | DIGIT)*;
fragment ALPHA : [a-zA-Z];
fragment DIGIT : [0-9];
SkipTokens : [ \t\r\n]+ -> skip;
在这种情况下,Divider
是固定的 ( #
)。但在实际场景中,Divider
会被定义为 char after'Divider'
关键字。
无论如何要Divider
根据中的值进行设置divider_stat
吗?
对于输入:
Divider -
id1 - id2
代币将是:
<ID>,'id1'
<Divider>,'-'
<ID>,'id2'
对于输入:
Divider $
id1$id2
代币将是:
<ID>,'id1'
<Divider>,'$'
<ID>,'id2'
分隔符始终为 1 个字符
解决方案
您可以为此使用词法模式、一些特定于目标的代码和一个predicate。每当词法分析器“看到”关键字"Divider"
时,它就会移动到DividerMode
只能匹配(并跳过)空格或匹配非空格的位置,这将成为新的分隔符字符。在Divider
词法分析器规则中,您首先检查(使用谓词)流中的下一个字符是否是当前分隔符字符。
这是一个小型 Java 演示:
DemoLexer.g4
lexer grammar DemoLexer;
@members {
private char divider = '#';
}
K_Divider : 'Divider' -> skip, pushMode(DividerMode);
Divider : {_input.LA(1) == divider}? . ;
ID : ALPHA ('_' | ALPHA | DIGIT)*;
fragment ALPHA : [a-zA-Z];
fragment DIGIT : [0-9];
SkipTokens : [ \t\r\n]+ -> skip;
mode DividerMode;
Spaces : [ \t\r\n]+ -> skip;
NewDivider : ~[ \t\r\n] {this.divider = getText().charAt(0);} -> skip, popMode;
DemoParser.g4
parser grammar DemoParser;
options {
tokenVocab=DemoLexer;
}
parse : expr+ EOF;
expr : ID Divider ID;
还有一个小的 Java 类来测试它:
String source =
"id1 # id2\n" +
"Divider -\n" +
"id3 - id4";
DemoLexer lexer = new DemoLexer(CharStreams.fromString(source));
DemoParser parser = new DemoParser(new CommonTokenStream(lexer));
ParseTree root = parser.parse();
System.out.println(root.toStringTree(parser));
将打印:
(parse (expr id1 # id2) (expr id3 - id4) <EOF>)
使用词法模式时,您需要将词法分析器和解析器语法文件分开。您也可以使用组合语法,但是您需要Divider ?
一次性匹配:
Demo.g4
grammar Demo;
@lexer::members {
private char divider = '#';
}
parse : expr+ EOF;
expr : ID Divider ID;
K_Divider : 'Divider' [ \t\r\n]+ ~[ \t\r\n] {this.divider = getText().charAt(getText().length() - 1);} -> skip;
Divider : {_input.LA(1) == divider}? . ;
ID : ALPHA ('_' | ALPHA | DIGIT)*;
fragment ALPHA : [a-zA-Z];
fragment DIGIT : [0-9];
SkipTokens : [ \t\r\n]+ -> skip;
推荐阅读
- angular - 从组件外部提交表单
- javascript - this.function.bind(this) 和 this.function() 有什么区别?
- gitlab - Gitlab 准备失败:来自守护进程的错误响应:冲突。容器名称已被容器使用
- amazon-web-services - 如何使用 Cloud Foundry 登录我的 AWS 终端节点?
- c# - 获取代表用户权限列表 - EWS Manage API
- apache-kafka - Kafka 消息内容的最佳实践?
- python - 如何在没有特定年份的情况下制作一个 numpy 范围的日期时间?
- python-3.x - 我可以写什么代码来抓取网站并带回 5 季所有剧集的结果,包括剧集标题
- javascript - 如何从 Base 64 字符串获取 MIME-TYPE?
- python-3.x - 如何将绘图(由 shap_values 生成)保存到 png?