java - 如何有效区分 ANTLR4 规则中的不同标记?
问题描述
我有一个简单的语法规则:
expr : expr (EQUALS | NOT_EQUALS) expr
| literal;
literal : ...; // omitted here
词法分析器识别EQUALS
和NOT_EQUALS
:
EQUALS : '=';
NOT_EQUALS : '!=';
在我的代码中,我想区分等于和不等于的情况。我想知道如何有效地做到这一点。目前,我将访问者实现如下:
public Expression visitExpr(ExprContext ctx) {
if (ctx.EQUALS() != null) {
return EqualsExpression.construct(ctx.expr());
} else if (ctx.NOT_EQUALS() != null) {
return NotEqualsExpression.construct(ctx.expr());
} else if (ctx.literal() != null) {
return LiteralExpression.construct(ctx.literal());
}
throw new IllegalStateException();
}
我不确定这是否非常有效,因为EQUALS()
/ NOT_EQUALS()
callsgetToken()
基本上循环遍历所有子项。这是多次完成,所以我不确定这是否聪明。另外,我打literal()
了两次电话。关于后者,我知道我可以缓存在一个局部变量中,但是如果要考虑多个子规则,这将很快变成非常丑陋的代码。
有没有办法更有效地做到这一点?基于某种令牌标识符或分支标识符的 switch/case 语句会更理想吗?
边注
我可以将expr
规则拆分为多个规则,如下所示:
expr : expr_eq | expr_not_eq | expr_literal
expr_eq : expr EQUALS expr
expr_not_eq : expr NOT_EQUALS expr
expr_literal : literal
现在,访问者将分别访问每个可能的分支:
public Expression visitExprEx(ExprEqContext ctx) {
return EqualsExpression.construct(ctx.expr());
}
public Expression visitExprNotEq(ExprNotEqContext ctx) {
return NotEqualsExpression.construct(ctx.expr());
}
public Expression visitExprLiteral(ExprLiteralContext ctx) {
return LiteralExpression.construct(ctx.literal());
}
但是看看 Github ( https://github.com/antlr/grammars-v4 ) 上的 G4 语法,很少有人这样做。所以我不确定这是否是前进的道路。
解决方案
永远不要仅仅通过查看代码来猜测性能。测量它!
子列表非常短,这意味着在找到orgetToken
之前只执行 1-2 个循环。代码的其他部分可能需要比查找更多的时间。EQUALS
NOT_EQUALS
但是,如果您想获得每一项性能,请避免使用方便的方法并手动执行操作,因为您可以根据您对语法的了解来优化访问。在这种特殊情况下,您的 expr 规则只能有一个或 3 个孩子。查看第一个变体,它可以获得单个literal
规则子节点或expr
规则子节点、内部 alt 的标记子节点和另一个expr
规则子节点。您所要做的就是检查:
if (ctx.getChildCount() > 1 && ((TerminalNode)ctx.getChild(1)).getSymbol().getType() == YourParser.EQUALS)
推荐阅读
- java - 传递给持久化的分离实体:JPA 错误
- powershell - Powershell 日志记录动态
- python - 如何通过python将Web抓取数据导出为csv
- excel - 如何在 VBA 中导入多个 .txt 文件
- typo3 - TYPO3 9.5.x 创建一个指向 xml 站点地图的链接
- c++ - 如何在 C++ 中释放类实例数组?
- java - 如何使用 Solr 进行部分搜索?
- php - 如何在 laravel 中创建类似示例的数组
- android - 如何在本机反应中添加背景图像,以便它占用屏幕的整个高度但只占用部分宽度?
- javascript - 随机图像打印javascript