编译器的最后一部分,做了5个星期总算全部做完了。
这个Location class 蛮重要的 记录了在当前这个Scope 中 base 的位置和offset多少位。 比如说进入一个新的function scope里,可能有许多的变量之类的 我们需要知道变量在多少个offset。
dispatchTable这个HashMap 包含的是ClassName, _从parent到当前所有defined的方法__
这个部分很Tricky,我们最后有一个case卡了很久没过去就是在这个地方。
这个是classDispatchTable fill的过程:
首先需要往MIPS 代码里output出每个类的DispatchTables.
然后还要往HashMap里填充。这里的代码也许有点重复多余 但是由于时间限制没时间去优化。。。
大概idea就是每到一个class,从低往上一路追到Parent,把父类装入一个orderList里
然后从后往前travel这个list,就有点像是从ancestor往子孙类走。然后一路把父类的method纳入子类的dispatchTable里!<className, <methodName, count>>
这里有一个Tricky部分要注意的就是如果parent定义了一个方法,当前类也定义了同一个名字的方法,是需要改写的!!!
初始化Object。这个部分负责把一些初始值绑定给变量。
比如a= 2+3 我们在初始化阶段就要去把2+3 算出来 赋值给a。
然后如果有的变量是不需要的话,我们可以在这个部分执行辣鸡回收。
这个部分负责给方法函数生成MIPS 代码:
//setCurrentClass 应该是不需要的。。
遍历所有的classes,然后创建一层一层的scope, one scope for each class.
一个scope 其实就是放置一个新的hashMap到stack顶部。hashmap里包含了这个class里所有的变量名, 以及在object的哪个位置。【object前几个位置是用来放classTag, classSize, dispatchTable等信息】
然后对于class里的每个local Defined的方法,我们生成MIPS代码。【为什么不需要生成父类method的代码?因为我们可以refer back to 之前生成好的代码】
生成好一个class,就可以pop出一个class的scope
Assign:
这里会用到之前用到过的Location class. 赋值过程就是把expr1+expr2比如计算出来放在a0 register里的值store到变量define的地方。我们用location base+offset找到那个地方。
static Dispatch:
dispatch:
最下面if else可以替换成一行。我们其实只要用expr.get_type()就行了 它会准确告诉我们当前Type是什么。这个部分我卡了超久,主要是整个structure没想好。。
setCurclass只要在最外层调用的时候才使用到,如果一个Main class里new 一个class A.然后调用A.foo() 那么A是不知道自己的curclass是多少的,以为自己是Main。然后去Dispatch<main>里找 foo() 这个方法。expr.get_type()会知道当前type是多少。
Cool里面的Block是当有多行代码的时候使用的:例如
{
{
a=1;
b=2;
}
}
分别给每个expr 生成代码
***let
例子: 加法
expr1 + expr2 我们得分别给expr1和expr2生成MIPS代码 然后加起来。这里会用到一些register。比如expr1 结果会在a0,我们要先存到s1里 然后再去执行expr2存到a0.
最后a0 = a0+s1.
很难的一个test case.. 主要在于他这里的一个dispatch case
a.m()
(new B)@A.foo() 这个是static dispatch
意思就是B虽然是一个类型B的东西,并且继承了类型A。但是他就是想用父类A里的method foo不用继承后改写的!
有点像java里面的super。
外面一开始有会有一个x 变量,但是function内部也有一个x。
但是由于我们会有一个scope for foo() 所以 会先看看这个scope有没有x,找到location。
这个case的话,先在foo() scope里找有没有x,没有的话去parent scope里找x
网友评论