如何解决根据输入流中的值设置词法分析器规则 DemoLexer.g4DemoParser.g4Demo.g4
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
将被定义为 'Divider'
关键字之后的字符。
是否可以根据 Divider
中的值设置 divider_stat
?
对于输入:
Divider -
id1 - id2
代币将是:
<ID>,'id1'
<Divider>,'-'
<ID>,'id2'
对于输入:
Divider $
id1$id2
代币将是:
<ID>,'$'
<ID>,'id2'
分隔符总是 1 个字符
解决方法
您可以为此使用 lexical mode、一些特定于目标的代码和一个 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;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。