我一直在研究基于别人写的非常大的语法的语言实现。我正在使用 Antlr 4.12 并以 C# 为目标。一切进展顺利,我取得了很大进步。我正在使用监听器,因为我认为这是将语法树转换为适合我的语言的操作的最简单方法。
困扰我的一件事是某种结构似乎比在 C# 中更难解析。例如,我可能正在解析表达式,其中涉及文字、运算符和函数——所有常见的东西。对于函数,有几种不同类型的函数,组合在一起作为
function_call
.
function_call
: ranking_windowed_function #RANKING_WINDOWED_FUNC
| aggregate_windowed_function #AGGREGATE_WINDOWED_FUNC
| analytic_windowed_function #ANALYTIC_WINDOWED_FUNC
| built_in_functions #BUILT_IN_FUNC
| scalar_function_name '(' expression_list? ')' #SCALAR_FUNCTION
| freetext_function #FREE_TEXT
| partition_function #PARTITION_FUNC
| hierarchyid_static_method #HIERARCHYID_METHOD
;
我可能会实现
EnterSomeExpression_Context()
并在语法树中获取表达式的根。当我遍历它时,我最终会找到一个function_callContext
。该上下文本身并不是特别有用,因为我需要知道我正在使用这些类型中的哪一种。
我如何在 C# 中发现它?我现在唯一的方法是使用
is
比较运行时类型:
if (obj is RANKING_WINDOWEDFUNCTContext)
{
// handle a ranking windowing function ...
}
else if (obj is BUILT_IN_FUNCContext)
{
// handle a built-in ...
}
else if (obj is FREE_TEXTContext)
{
// handle a free-text query ...
}
// and so on ...
适用于少量选择,但经过几次之后,我渴望有一种查找表的方法。而且我总是想要更直接的比较(比如与整数或枚举)而不是检查类型和转换。
这段代码应该怎么写?或者我实际上是在以正确的方式做事吗?
如果有帮助,语法是针对 T-SQL 的,在这里:https://github.com/antlr/grammars-v4/tree/master/sql/tsql 我所有的代码都在我的 JankSQL 项目中: https://github.com/mikeblas/JankSQL
“评论”使用替代标签语法。该链接详细说明了它是如何工作的,但简而言之,您应该为语法规则中的每个替代方案设置
enterRANKING_WINDOWED_FUNC
exitRANKING_WINDOWED_FUNC
等的侦听器。每个方法都会收到一个特定于替代方案的上下文,这将更容易使用。
(注意:不确定为什么他们全部使用大写字母,这会产生奇怪的名字......)