Antlr:如何在访客实现中打开令牌类型
Antlr: how to switch on token type in Visitor implementation
我正在玩 Antlr,设计一种玩具语言,我认为这是大多数人的起点! - 我有一个关于如何最好地考虑开启令牌类型的问题。
考虑语言中的 'function call',其中函数可以使用字符串、数字或变量 - 例如如下(project()
是函数调用)
project("ABC")
对比 project(123)
对比 project($SOME_VARIABLE)
我的语法中有更改运算符,所以语法解析正确的东西,但在访问者代码中,最好能说出上述三个版本之间的区别。
@Override
public ASTRoot visitCreateproj(projectmgmtParser.CreateprojContext ctx) {
try {
s1 = ctx.STRING_LITERAL().getText();
}catch(Exception e){}
try{
s2 = ctx.NUM().getText();
}catch(Exception e){}
System.out.println("Created Project via => " + ctx.getChild(1).toString());
}
上面的代码有效,取决于 s1
或 s2
是否为空,我可以推断我是如何被调用的(用文字或数字,我没有显示变量大小写上面),但我很感兴趣是否有更好或更优雅的方式 - 例如在访问者代码中打开令牌类型以实际处理语言。
上面的语法是
createproj: 'project('WS?(STRING_LITERAL|NUM)')';
并且当我使用 intellij antlr 插件时,它似乎知道 project()
函数参数的标记类型——但我似乎无法从我的代码中获取它。
你可以这样做:
createproj
: 'project' '(' WS? param ')'
;
param
: STRING_LITERAL
| NUM
;
并在您的访客代码中:
@Override
public ASTRoot visitCreateproj(projectmgmtParser.CreateprojContext ctx) {
switch(ctx.param().start.getType()) {
case YourLexerName.STRING_LITERAL:
...
case YourLexerName.NUM:
...
...
}
}
so by inlining the token in the grammar I had originally, I've lost the opportunity to inspect it in the visitor code?
不,你也可以这样做:
createproj
: 'project' '(' WS? param_token=(STRING_LITERAL | NUM) ')'
;
然后可以这样做:
@Override
public ASTRoot visitCreateproj(projectmgmtParser.CreateprojContext ctx) {
switch(ctx.param_token.getType()) {
case YourLexerName.STRING_LITERAL:
...
case YourLexerName.NUM:
...
...
}
}
只要确保您没有在您的集合中混用词法分析器规则(标记)和解析器规则 param_token=( ... )
。当它是解析器规则时,ctx.param_token.getType()
将失败(它必须是 ctx.param_token.start.getType()
)。这就是为什么我建议添加一个额外的解析器规则,因为这样仍然有效:
param
: STRING_LITERAL
| NUM
| some_parser_rule
;
我正在玩 Antlr,设计一种玩具语言,我认为这是大多数人的起点! - 我有一个关于如何最好地考虑开启令牌类型的问题。
考虑语言中的 'function call',其中函数可以使用字符串、数字或变量 - 例如如下(project()
是函数调用)
project("ABC")
对比 project(123)
对比 project($SOME_VARIABLE)
我的语法中有更改运算符,所以语法解析正确的东西,但在访问者代码中,最好能说出上述三个版本之间的区别。
@Override
public ASTRoot visitCreateproj(projectmgmtParser.CreateprojContext ctx) {
try {
s1 = ctx.STRING_LITERAL().getText();
}catch(Exception e){}
try{
s2 = ctx.NUM().getText();
}catch(Exception e){}
System.out.println("Created Project via => " + ctx.getChild(1).toString());
}
上面的代码有效,取决于 s1
或 s2
是否为空,我可以推断我是如何被调用的(用文字或数字,我没有显示变量大小写上面),但我很感兴趣是否有更好或更优雅的方式 - 例如在访问者代码中打开令牌类型以实际处理语言。
上面的语法是
createproj: 'project('WS?(STRING_LITERAL|NUM)')';
并且当我使用 intellij antlr 插件时,它似乎知道 project()
函数参数的标记类型——但我似乎无法从我的代码中获取它。
你可以这样做:
createproj
: 'project' '(' WS? param ')'
;
param
: STRING_LITERAL
| NUM
;
并在您的访客代码中:
@Override
public ASTRoot visitCreateproj(projectmgmtParser.CreateprojContext ctx) {
switch(ctx.param().start.getType()) {
case YourLexerName.STRING_LITERAL:
...
case YourLexerName.NUM:
...
...
}
}
so by inlining the token in the grammar I had originally, I've lost the opportunity to inspect it in the visitor code?
不,你也可以这样做:
createproj
: 'project' '(' WS? param_token=(STRING_LITERAL | NUM) ')'
;
然后可以这样做:
@Override
public ASTRoot visitCreateproj(projectmgmtParser.CreateprojContext ctx) {
switch(ctx.param_token.getType()) {
case YourLexerName.STRING_LITERAL:
...
case YourLexerName.NUM:
...
...
}
}
只要确保您没有在您的集合中混用词法分析器规则(标记)和解析器规则 param_token=( ... )
。当它是解析器规则时,ctx.param_token.getType()
将失败(它必须是 ctx.param_token.start.getType()
)。这就是为什么我建议添加一个额外的解析器规则,因为这样仍然有效:
param
: STRING_LITERAL
| NUM
| some_parser_rule
;