本篇来描述一下 ”环境“相关的内容。

这部分内容是笔者从《两周自制脚本语言》这本书上学来的。

简单来说 环境就是一个K-V形式的Map。

  • Key 是变量名
  • Value 是 变量值
  • 一个环境表示一个作用域。 比如函数内部,类内部,脚本内部等。

这里需要提一下, 如果读者使用Java语言来实现脚本语言引擎,或者读者只是想学习一下,或者读者只是追求一个简单的脚本语言引擎,那么建议使用这种方式, 否则,不建议使用这种方式。

如果读者想实现一个复杂的, 稳定的脚本语言引擎, 那么建议使用变量表的形式来实现环境。

一个例子是使用数组或者链表来存放变量的值,对变量的引用在编译期间转换成具体的索引,而非变量名。

由于笔者还没有实现过相关的方式,所以本篇不讨论相关内容。也许后面笔者实现过了之后 会写一篇博文进行相关介绍 😂😂😂

详细说明

我们先来讨论一下 最简单的赋值行为。

先看一下下面的代码。

// 本段代码的内容都是在一个脚本文件内部的。

a = 1;
b = "hello";
c = new Test();

d = a + 1;

为了使变量这个功能得以实现, 我们需要保存变量的当前值, 以使未来在使用这个变量的时候可以获取到正确的值。

所以我们可以使用下面的方式进行实现。

  1. 新建一个新的 Map ,用于表示脚本的环境。
  2. 碰到 a = 1; 这条语句的时候, 把a的值 设置成 1
  3. 碰到 b = "hello"; 这条语句的时候, 把b的值设置成hello
  4. 碰到 c = new Test(); 的时候, 实例化 Test类,生成一个对象,并将对象的引用赋值给c
  5. 碰到 d = a + 1; 这条语句的时候, 首先取出a的值, 然后进行加法运算, 之后将结果赋值给 d

附注:

  • 新建一个Map的地方, 可以考虑使用 std::map<k,v> 或者自定义的Enviroment 类之类的。
  • 关于 new Test()d = a + 1; 的语句 在后续文章会有更加详细的说明。

当所有语句执行结束之后,我们应该会得到一个如下的一个Map。

a:   1
b:   hello
c:   一个指向 Test对象的引用 

d:   2

此时,我们追加执行一条语句 a = a + 1; 之后, a的值会被更新成2 。

现在新的Map 应该是如下这个样子的。

a:   2
b:   hello
c:   一个指向 Test对象的引用 

d:   2

本篇只是提供了一些实现上的思路,并没有提供具体的代码。 想要看代码的读者可以看看langX里的相关实现。

langX中的相关实现都在 Enviroment.hEnviroment.cpp 两个文件中。

关于节点的一些简单说明

这里说的节点表示抽象语法树上的一个节点, 将会在下一篇中进行说明。

其他

在JAVA函数的实现中,存在一个叫做 局部变量表的东西, 这个表里的每一个元素都是变量的值,在使用这个表的时候,就是根据索引来操作的。

索引应该会在编译阶段产生,并生成到字节码里面。