自己动手构建编程语言:如何设计编译器、解释器和DSL
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.6.1 2D图形语言支持

Unicon的2D功能是Icon语言冻结前引入的最后一个主要功能。该设计强调语言语法的表面变化最小化,因为大的变化是不允许的。唯一的表面变化是添加了几个表示图形系统中特殊值的关键字。Unicon中的关键字看起来像变量名,其前面带一个“&”符号。

添加19个关键字有助于让图形功能看起来属于以字符串处理为主的语言。你可能会惊讶地发现,图形输出是其中最简单的部分功能,除了1个关键字外,其他所有关键字都用于简化输入鼠标和键盘事件的处理。其中10个关键字是整数常量,表示鼠标和调整大小事件,都是为了方便。其他8个关键字保存有关上一次接收到的事件的关键信息,这些信息将自动更新每个事件。由于使用了整数常量,因此不需要头文件或输入文件来处理鼠标输入。最后也是主要添加的关键字是&window,此关键字用于保存默认窗口,所有图形工具功能都使用此窗口,除非有其他窗口值作为可选的第一个参数提供。

将Unicon的图形与底层提供的图形进行比较很有趣,当时底层C API是X Window系统的高级工具箱(如HP和Athena组件)及其低级库Xlib。由于不可预测行为,以及当时缺少可移植性,在原型设计阶段,高级工具箱是被拒绝的。Xlib库满足行为和可移植性要求,但它是一个巨大的API,需要许多新类型(例如,在几十种不同类型的事件中,每一种都有一个单独的结构体类型),并具有近千种功能。

学习Xlib,然后使用Xlib在C语言中编写图形应用程序是一个非常复杂的任务,而Unicon的目标是提供一个非常高级易用的功能。在支持易用性方面,影响最大的是BASIC。在20世纪70年代使用TRS-80 Extended Color BASIC图形比任何X Window C API都更容易。对于非常高级的语言,如Unicon,其图形功能应与Extended Color BASIC提供的功能一样简单,并且功能更强。保持人们对Icon的喜爱的要求延伸到尝试使图形功能的设计与Icon现有的输入和输出特性保持一致。Icon的输入和输出特性包括文件类型、内置函数和执行输入/输出的运算符。

Unicon引入了一个新类型(“window”)作为Icon的文件数据类型的子类型(和扩展)。窗口是对底层C代码中十几个不同Xlib实体的抽象。但对于Unicon程序员来说,创建和绘制窗口只是一件单一、简单的事情。所有现有的对文件执行(文本)输入/输出操作都是在窗口中完成的,然后再添加图形输出功能。图2.2展示了一些底层C库实体,它们都被合并到一个Unicon窗口中。这个结构的叶子因平台而异,平台差异在Unicon层级已经被最小化或消除。

Unicon中的图形输出功能由一组大约40个内置函数组成,用于绘制不同的图形图元。输出的具体内容取决于许多状态片段,例如窗口内容的内存副本,以及字体和填充样式等抽象资源。对这些资源并没有引入新类型,而是生成了一个API,以使用字符串值对这些资源进行操作。一个窗口最终定义为两个底层实体的配对,即画布和上下文。

控制结构和程序组织是设计编程语言特性时要考虑的主要因素。当用C语言编写图形程序时,程序员立即被告知(迫使)放弃对库控制流,而把他们的程序组织成一组回调(callback)函数。这些函数是在各种事件发生时被调用的函数。围绕这种组织方式重写Unicon的字节码解释器是不可能的。字节码解释器需要拥有指令的获取-解码-执行周期的控制流。一个多线程的解决方案是可以实现的,但线程在此时会带来不可接受的可移植性和性能挑战。相反,当应用程序控制流要求时,一个单线程的、非阻塞的解决方案是通过让字节码解释器不时检查图形事件,处理常见的任务(如从后台存储中重新绘制窗口的内容,并将其他内容排队,以便稍后在Unicon语言层面上处理)实现的。

图2.2 Unicon窗口的内部结构

本来有可能将二维图形的C库原封不动地传播到Unicon语言中,但这达不到语言水平和易用性的目标。相反,我们引入了一个高级数据类型,由C库状态的多个基础部分组成。支持该高级数据类型的维护和更新操作从语言运行时系统中的多个地方嵌入,以用严格的库方法不可能实现的方式实现了一个易于使用的窗口类型。

若干年后,3D图形硬件支持变得无处不在,2.6.2节将介绍在语言中添加3D图形的设计问题。