在Swift中实现编程语言—第8部分:函数

注意:这是“用Swift编写编程语言”教程系列的第八部分。一定要检查一下 以前的内容

在先前的教程中,我们已经实现了一个小计算器解释器,该解释器支持变量声明和表达式。

下一个要添加的功能是对功能的支持,在本教程中,我们将介绍功能支持的陷阱,并讨论如何实现它。

设计功能声明

过去,某些编程语言在函数定义方面颇具创意。 从Objective-C:

  //实例 
-(无效)myMethod:(字符串)参数
  // 静态的 
+(无效)myStaticMethod:(字符串)参数

要使用JavaScript的箭头功能:

  (参数)=> {...} 

但是自C语言以来,大多数编程语言都是相当传统的语言,并遵循C样式定义:

   :: =  (){} 

其中, 导致某些字符序列(一个单词)。

那么……我们的功能应该如何?

通常,在实现一种语言时,我们希望在创造性和传统方法之间找到一个甜头。 我们希望使用我们的语言的程序员可以谈论一些话题,同时又希望我们的语言直观易读。

但是,由于我们出于教学目的而设计语言,因此我们只是希望事物尽可能直接和传统。 因此,我们语言中的函数看起来与传统的C样式函数定义非常相似:

 函数someFunction(firstArgument,secondArgument){...} 

我们的语言没有类型检查,因此我们将使用关键字“ function”来标记函数定义的开始,而不是在参数列表中使用传统的返回类型和跳过类型规范。 最后,我们在函数的代码块周围使用匹配的大括号。

实施思路

在上一教程中,我们讨论了添加对变量的支持,事实证明这很简单,只需四个简单步骤:

  1. 我们为变量声明添加了一个struct
  2. 我们在解析器中添加了一个parse方法来创建该结构的实例
  3. 我们为变量及其值添加了全局内存存储(一个简单的字典)
  4. 我们实现了该结构的解释过程,该过程简单地存储了变量声明的表达式的解释值,并使用变量名作为键将其存储在我们的全局变量字典中。

我们可以用不到50行的代码来完成所有这些工作。 添加功能是一个相似的过程,但是在内存存储方面有两个主要区别(3)。

  1. 我们将需要字典将其映射到Node值而不是当前Float ,以便可以懒惰地评估该节点。
  2. 处理变量时,我们的内存存储区必须牢记范围。

范围处理

当涉及范围处理时,有两种方法值得一提。 我们可以有词汇范围动态范围

词汇范围
这是大多数编程语言所使用的。 在词法作用域中 ,变量的解析取决于它们在源代码中的位置。

动态范围
对于动态范围,变量的解析取决于运行时的用法:

  var x = 1 
 函数getX(){ 
 返回x 
  } 
 函数some(){ 
  var x = 3 
 返回getX() 
  } 
  //使用动态范围设定,应输出3。 
//但是具有词法作用域1。
一些()

总有捷径
我们可以选择词法作用域还是动态作用域,但是为了使事情简单起初,我们将采用仅支持全局变量的第三种选择,如果用户(程序员)试图声明一个变量,则只会引发运行时错误。与现有的标识符。

敬请期待下周,我们终于可以脏手了,写些雨燕!