【问题标题】:Defining Function Signatures in a Simple Language Grammar用简单的语言语法定义函数签名
【发布时间】:2012-11-07 00:48:22
【问题描述】:

我目前正在学习如何使用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> )

但是这件事感觉不太对劲。在我看来,语法似乎应该只定义一个通用函数调用,而不是该语言可用的每个函数。

  • 这在其他语言中通常是如何实现的?
  • 哪些组件应该负责分析语言语法的基本句法而不是函数定义等更具体的元素?这两个职责应该由同一个组件处理吗?

【问题讨论】:

    标签: parsing compiler-construction syntax bnf irony


    【解决方案1】:

    虽然您可以直接在语法中进行类型检查,以便在解析器中强制执行,但这样做通常是个坏主意。相反,解析器应该只解析基本语法,并且应该使用单独的类型检查代码进行类型检查。

    在编译器的正常情况下,解析器只生成抽象语法树或程序的某种等效表示。然后,在 AST 上运行类型检查传递,以确保所有类型正确匹配——确保函数具有正确数量的参数并且这些参数具有正确的类型,并确保变量具有正确的类型以分配给它们以及它们的使用方式。

    除了通常更简单之外,这通常可以让您提供更好的错误消息——而不仅仅是“无效”,您可以说“FOO 的参数太多”或者你有什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-17
      • 2016-02-12
      • 1970-01-01
      • 1970-01-01
      • 2023-01-20
      • 2010-09-07
      • 2012-03-27
      • 1970-01-01
      相关资源
      最近更新 更多