我目前正在学习如何使用Irony创建简单的表达语言。我在找出定义函数签名的最佳方法以及确定验证这些函数输入的责任时遇到了一些麻烦。
到目前为止,我有一个简单的语法来定义我的语言的基本元素。这包括一些二元运算符、括号、数字、标识符和函数调用。我的语法的 BNF 看起来像这样:
<expression> ::= <number> | <parenexp> | <binexp> | <fncall> | <identifier>
<parenexp> ::= ( <expression> )
<fncall> ::= <identifier> ( <argumentlist> )
<binexp> ::= <expression> <binop> <expression>
<binop> ::= + - * / %
... the rest of the grammar definition
使用 Irony 解析器,我能够验证各种输入字符串的语法,以确保它们符合以下语法:
x + y / z * AVG(a + b, p) -> Valid Syntax
x +/ AVG(x -> Invalid Syntax
这一切都很好,但现在我想更进一步,定义可用的函数,以及每个函数所需的参数数量。因此,例如,我想要一个FOO
接受一个参数并BAR
接受两个参数的函数:
FOO(a + b) * BAR(x + y, p + q) -> Valid
FOO(a + b, 13) -> Invalid
解析第二条语句时,我希望能够输出一条错误消息,该消息知道此函数的预期输入:
Too many arguments specified for function 'FOO'
我实际上不需要评估任何这些语句,只需验证语句的语法并确定它们是否是有效的表达式。
我到底应该怎么做?我知道从技术上讲,我可以像这样简单地将函数添加到语法中:
<foofncall> ::= FOO( <expression> )
<barfncall> ::= BAR( <expression>, <expression> )
但是这方面的某些事情感觉不太对劲。在我看来,语法似乎应该只定义一个通用函数调用,而不是该语言可用的每个函数。
- 这通常在其他语言中是如何实现的?
- 哪些组件应该负责分析语言语法的基本语法与函数定义等更具体的元素?这两个职责应该由同一个组件处理吗?