具有可变参数列表的函数的Antlr4语法



我正在尝试使用antlr4为我的DSL编写语法。从本质上讲,我正在尝试创建一种DSL,用于在树结构中描述函数应用程序。

目前,我在创建正确的语法(或在c#中正确使用访问者)失败解析表达式,如

#func1(jsonconfig)
#func1(jsonconfig, #func2(...))
#func1(#func2(...), #func3(...), ..., #func_n(...))
#func1(jsonconfig, #func2(...), #func3(...), ..., #func_n(...))

我的语法(为了简洁,删除了一些部分)

func
: FUNCTION_START IDENTIFIER LPAREN (config?) (argumentList?) RPAREN
;
argument
: func
;
argumentList
: (ARG_SEPARATOR argument)+
| ARG_SEPARATOR? argument
;
config
: json
;

但是,当尝试解析表达式时,我只得到第一个参数,而不是其余的。

这是我的访客:

public class DslVisitor : JustDslBaseVisitor<Instruction>
{
public override Instruction VisitFunc(JustDslParser.FuncContext context)
{
var name = context.IDENTIFIER().GetText();
var conf = context.config()?.GetText();
var arguments = context.argumentList()?.argument() ?? Array.Empty<JustDslParser.ArgumentContext>();
var instruction = new Instruction
{
Name = name,
Config = conf == null ? null : JObject.Parse(conf),
Bindings = arguments.Select(x => x.Accept(this)).ToList()
};
return instruction;
}
public override Instruction VisitArgument(JustDslParser.ArgumentContext context)
{
return context.func().Accept(this);
}
}

我认为antlr定义中可能存在一些语法错误,因为它无法解析列表,但成功解析了单个项目。在过去,我有一个稍微不同的语法,但它要求我总是传递一个不符合我需要的配置对象。

谢谢!

试试这样写:

func
: FUNCTION_START IDENTIFIER LPAREN functionArgs RPAREN
;
functionArgs :
: config (ARG_SEPARATOR argument)*
| argument (ARG_SEPARATOR argument)*
;
argument
: func
;
config
: json
;

或者(如果您确实需要argumentList节点)

func
: FUNCTION_START IDENTIFIER LPAREN functionArgs RPAREN
;
functionArgs :
: config (ARG_SEPARATOR argumentList)?
| argumentList
;
argumentList :
: argument (ARG_SEPARATOR argument)*
;
argument
: func
;
config
: json
;

你的代码有几个问题。

首先,在解析之后,您没有在代码中实际测试解析结果。您应该添加一个ErrorListener,并测试词法分析器和/或解析器是否真的发现了错误。您还可以使用它将输出分流到您喜欢的任何位置。

public class ErrorListener<S> : ConsoleErrorListener<S>
{
public bool had_error;
public override void SyntaxError(TextWriter output, IRecognizer recognizer, S offendingSymbol, int line,
int col, string msg, RecognitionException e)
{
had_error = true;
base.SyntaxError(output, recognizer, offendingSymbol, line, col, msg, e);
}
}

简单地创建一个侦听器,为解析器调用AddErrorListener(),调用解析方法,然后为侦听器测试had_error。注意,您还应该向词法分析器添加一个侦听器。

。为了得到人们期望的输入,我们对c#代码进行了大量的编辑。我删除了c#转义并重新格式化了它,以获得以下输入:

#obj(
#property(
#unit(
{"value":"phoneNumbers"}
),
#agr_obj(
#valueof(
{"path":"$.phone_numbers"}
),
#current(
#valueof(
{"path":"$.type"}
) ),
#current(
#valueof(
{"path":"$.number"}
) ) ) ),
#property(
#unit(
{"value":"addrs"}
),
#agr_obj(
#valueof(
{"path":"$.addresses"}
),
#current(
#valueof(
{"path":"$.type"}
) ),
#current(
#obj(
#property(
#unit(
{"value":"city"}
),
#valueof(
{"path":"$.city"}
) ),
#property(
#unit(
{"value":"country"}
),
#valueof(
{"path":"$.country"}
) ),
#property(
#unit(
{"value":"street"}
),
#str_join(
{"separator":", "},
#valueof(
{"path":"$.street1"}
),
#valueof(
{"path":"$.street2"}
) ) ) ) ) ) ) )

第三。您不能使用在规则末尾有EOF的条目规则来扩展语法。eof增强规则强制解析器使用所有输入。这里,我只是添加了"start":

的规则
start : func EOF ;

您需要将入口点更改为start()而不是func()

最后,您的语法不能识别json参数后面跟着可选的func参数。由于func的第一个参数可以是jsonjson , funcfunc,因此需要对第一个参数进行异常处理。这个语法修复了:

grammar JustDsl;
LPAREN:             '(';
RPAREN:             ')';
FUNCTION_START:     '#';
ARG_SEPARATOR:      ',';
IDENTIFIER
: [a-zA-Z] [a-zA-Z-_] *
;
start : func EOF ;
func
: FUNCTION_START IDENTIFIER LPAREN argumentList? RPAREN
;
argument
: func
;
argumentList
: (config config_rest)?
| no_config_rest?
;
config_rest
: (ARG_SEPARATOR argument)*
;
no_config_rest
: argument (ARG_SEPARATOR argument)*
;
config
: json
;
json
: value
;
obj
: '{' pair (',' pair)* '}'
| '{' '}'
;
pair
: STRING ':' value
;
arr
: '[' value (',' value)* ']'
| '[' ']'
;
value
: STRING
| NUMBER
| obj
| arr
| 'true'
| 'false'
| 'null'
;

STRING
: '"' (ESC | SAFECODEPOINT)* '"'
;

fragment ESC
: '\' (["\/bfnrt] | UNICODE)
;
fragment UNICODE
: 'u' HEX HEX HEX HEX
;
fragment HEX
: [0-9a-fA-F]
;
fragment SAFECODEPOINT
: ~ ["\u0000-u001F]
;

NUMBER
: '-'? INT ('.' [0-9] +)? EXP?
;

fragment INT
: '0' | [1-9] [0-9]*
;
// no leading zeros
fragment EXP
: [Ee] [+-]? INT
;
// - since - means "range" inside [...]
WS
: [ tnr] + -> skip
; 

Mike在正确的轨道上(但是在functionArgs规则上有一个打字错误)。但是如果没有输入,这个问题很难解决。

相关内容

  • 没有找到相关文章

最新更新