Antlr4编写DSL可变参数函数语法及C# Visitor解析问题排查
你遇到的参数丢失问题是两个问题共同导致的:
- 现有语法规则缺少config和首个参数之间的分隔符匹配逻辑,同时argumentList规则存在歧义,解析器无法正确识别多参数场景下的后续参数
- Antlr生成的多节点访问方法使用错误,你调用的单参数重载仅能获取第一个匹配的argument节点
修复步骤
第一步:修正语法规则
将原有规则调整为如下写法,消除歧义同时统一处理参数分隔逻辑:
func : FUNCTION_START IDENTIFIER LPAREN ( firstParam (ARG_SEPARATOR argument)* )? RPAREN ; // 首个参数允许是json配置或者函数参数 firstParam : config | argument ; argument : func ; config : json ;
该规则可以覆盖你列出的所有合法表达式场景:
- 仅含config:
#func1(jsonconfig) - 含config+多个参数:
#func1(jsonconfig, #func2(...), #func3(...)) - 仅含多个函数参数:
#func1(#func2(...), #func3(...), #func_n(...)) - 空参数(如果不需要可以去掉规则中的
?来禁用)
第二步:修正Visitor访问逻辑
调整Func节点的访问代码,正确获取所有参数节点:
public class DslVisitor : JustDslBaseVisitor<Instruction> { public override Instruction VisitFunc(JustDslParser.FuncContext context) { var name = context.IDENTIFIER().GetText(); JObject config = null; var bindings = new List<Instruction>(); if (context.firstParam() != null) { var first = context.firstParam(); // 判断首个参数是配置还是函数 if (first.config() != null) { config = JObject.Parse(first.config().GetText()); } else { bindings.Add(first.argument().Accept(this)); } // 获取所有后续参数,此处context.argument()返回所有匹配的argument节点列表 foreach (var arg in context.argument()) { bindings.Add(arg.Accept(this)); } } return new Instruction { Name = name, Config = config, Bindings = bindings }; } public override Instruction VisitArgument(JustDslParser.ArgumentContext context) { return context.func().Accept(this); } }
如果你坚持沿用原有语法规则,只需要调整argument节点的获取方式:确认Antlr生成的多节点访问方法名,通常重复节点的列表方法会加s后缀,比如arguments(),直接遍历该列表即可获取所有参数。
内容的提问来源于stack exchange,提问作者Eugene Krapivin
相关产品推荐
相关产品推荐

