编译器与编程语言的实现

本文是关于编译器和编程语言实现的深入探讨。在开始之前,建议读者先阅读之前关于此主题的文章。正如之前提到的,输入程序是通过一个名为program.txt的文件提供的,附件中提供了一系列程序,以展示这种语言的语法。这些程序利用了其函数调用、数组和自动变量的能力。

由于语言的输出是汇编语言,因此需要有较强的汇编语言编程背景。为了便于查看结果,已经生成了一个包含内联汇编的C文件。将扩展语言以支持一些简单的概念(通常认为是理所当然的)。和以前一样,语法必须支持编译器和解释器两种版本,这允许使用这种语言的用户保持代码的一致性。

数组支持

通过数组索引访问数组是支持的,使用以下语法:

z=1 s=20 ARRAY:a1:1+z=24+3*s

在这里,可以看到数组'a1'在索引1+z处被写入,写入的值是24+3*s。同样地:

d=ARRAY:a1:z*2

在这里,读取数组a1在索引z*2处的值。

自动变量(堆栈上的变量)

这些变量的作用域仅限于函数调用,即它们的作用域从它们被定义的标签下开始,直到程序遇到RETURN。使用自动变量:

AUTO:a=10*20

这将创建一个自动变量'a',并将值200与之关联。

c=AUTO:a

这将从自动变量'a'中读取值,这个变量必须存在于函数调用的作用域内,否则生成的汇编代码将是错误的(总是可以放置一个简单的检查来确保这一点)。

这种优化是为VS2012发布版构建和gcc -o3优化启用的。这是一种简单的优化,它检查是否可以忽略额外的堆栈帧创建,并且可以替换'call'生成的代码为'jmp'(这节省了将返回地址推送到堆栈的麻烦),这种优化的'return'迫使代码返回到先前的函数。

使用代码

和之前的文章一样,代码必须始终参考并调试,以更好地理解其工作原理。让看看数组支持。首先通过声明数组来开始:

DIM:a1:10

这创建了一个大小为10的一维数组,这在编译阶段是必需的,因为必须全局声明这个数组的大小,对于解释器,这被忽略了。

为了使用数组,需要两个临时变量:

__TarrayIndexProcessing_, __TarrayValueProcessing_.

这些变量用于计算和保存数组索引和该索引处的值。会发现编译器的索引处理有一个额外的步骤:乘以4,因为int的大小是4个字节,以正确访问所需的元素。对于解释器来说,这不是必需的,因为它使用结构体来保存值:

struct arrayvar{ string m_name; int index; DWORD sz; }; map arrayList;

请注意,arrayvar(由解释器使用)使用索引和名称来唯一标识一个元素,请参考代码以查看map所需的比较函数。

对于解释器来说,堆栈上的变量相当简单,必须为每个函数调用维护堆栈帧。这是通过以下代码行完成的:

stack> *> stackFrame; map> &autoStack=*stackFrame.top();

这维护了当前的堆栈帧。在程序开始时创建堆栈帧,并且始终指向堆栈的顶部,当遇到函数调用时,会创建一个新的堆栈帧,并且堆栈顶部会更新,这确保了当前堆栈始终得到维护。

请参考解释器的CALL功能实现。同样地,RETURN功能会弹出堆栈并更新堆栈顶部。编译器的堆栈实现并不那么简单,因为代码需要多次解析以找到当前标签作用域中这个变量的定义。

如果变量在标签作用域内没有找到,那么通过调用push element创建一个变量。下面的函数从源代码中查找自动变量,由于处于编译阶段,源代码是可用的,以找到与LABEL关键字相关的索引。

int getVariablesIndex(string varName, UINT uiLineNumber)

如果变量没有找到,它返回-1,否则返回堆栈帧中的索引,如果找到了变量。例如:

AUTO:a=10 b=20 AUTO:c=30

自动变量'a'将在索引1处,自动变量'c'将在索引2处。通过EBP(这个寄存器用于持有帧指针)访问这些变量。从不使用ESP,因为它的值在遇到push/pop/call时可能会改变。

a将通过EBP-4访问,c将通过EBP-8访问。

对于编译器和解释器来说,这种优化是相似的。在处理CALL之后解析文件,寻找立即的RETURN,忽略使用'#'生成的注释。如果RETURN立即在CALL之后找到(忽略注释),知道这段代码可以通过放置一个'JMP'而不是'call'来尾调用优化,如果使用了AUTOs,那么在RETURN之前需要额外的代码进行堆栈清理,并且不会执行尾调用优化。

如果没有立即遇到RETURN,那么代码必须返回到CALL之后的某个点以执行RETURN之前找到的语句,因此将使用'call'而不是'jmp'。这种优化在评估'CALL'语言关键字的地方编码,请参考代码。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485