从输入流中的值设置 Lexer 规则
Set Lexer rule from value in input stream
我有这个简单的语法文件:
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_stat
中的值设置Divider
?
输入:
Divider -
id1 - id2
代币将是:
<ID>,'id1'
<Divider>,'-'
<ID>,'id2'
输入:
Divider $
id1$id2
代币将是:
<ID>,'id1'
<Divider>,'$'
<ID>,'id2'
分隔符始终为 1 个字符
您可以使用 lexical mode for this, a bit of target specific code and a predicate。每当词法分析器“看到”关键字 "Divider"
时,它就会在 DividerMode
中移动,其中只能匹配(并跳过)space 或匹配非 space ,这将成为新的分隔符。在 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 class 来测试它:
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;
我有这个简单的语法文件:
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_stat
中的值设置Divider
?
输入:
Divider -
id1 - id2
代币将是:
<ID>,'id1'
<Divider>,'-'
<ID>,'id2'
输入:
Divider $
id1$id2
代币将是:
<ID>,'id1'
<Divider>,'$'
<ID>,'id2'
分隔符始终为 1 个字符
您可以使用 lexical mode for this, a bit of target specific code and a predicate。每当词法分析器“看到”关键字 "Divider"
时,它就会在 DividerMode
中移动,其中只能匹配(并跳过)space 或匹配非 space ,这将成为新的分隔符。在 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 class 来测试它:
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;