Now in Baidu WISE team
全部博文(150)
分类: C/C++
2013-01-31 11:42:33
(作者码字辛苦,转载请以超链接形式注明出处)
之前我们处理了不带参函数的形式,现在来考虑带参的形式。
首先,我们观察传递参数时,到底需要做哪些事情。
方便起见,我们假设方法的局部变量和全局变量共用一个变量表VarHash,我们可以通过变量的名字从该表中获得这个名字代表的具体值。
考虑一个简单的函数定义和调用
def testfun(a,b) { stmt;} //定义了有两个形参a,b的方法testfun
testfun(p1,p2); //调用上边定义的方法testfun,传递两个实参p1,p2,假设p1,p2是已经赋值过的全局变量
那么,参数传递的过程,实际上就是
1.在变量表中新建两个变量,a,b,并置为空
2.将p1,p2分别复制一份填充如a,b, 即 VarHash["a“] = dup(p1), VarHash["b"] = dup(p2);
所以我们要做的就是在调用时,复制一份实参,然后填充入形参的位置。
然后我们考虑方法的定义:
对于一个方法,我们用左节点存储其形参列表, 右结点存储要执行的语句。那么执行时,我们先要根据其左节点进行参数的传递,完成后形参在VarHash中已经有了值了,再执行右结点,那么这时候右结点就可以顺利的调用形参了。
一个方法节点建成以后,类似变量,我们可以以方法名为key ,填入方法表中FunHash. FunHash["testfun"] = &funnode.
最后,我们考虑调用方法语句:
对于一个调用语句,我们用左节点存储传入的参数列表,我们可以将其想象成一个数组。如上面的代码例子中,这个数组就有2个元素,分别为a,b,他们都是两个变量,可以从VarHash中得到实际的值。
其右节点,指向它所调用的函数,这个指针可以通过名字在FunHash中获取,即 node->right = FunHash["testfun"]
接下来,我们先给出一份函数定义和调用的语法树示意图:
最后来考虑如何执行一个函数的调用。
对于上面给出的简单代码例子,可分解如下:
记函数调用的结点为funcall,函数的结点为fundef, 那么有funcall->right = fundef
1. 获取实参列表 funcall->right, 得到的一个数组paramarr = (p1,p2);
2. 执行参数赋值 paramnode = funccall->right->left 即 fundef->left;
3. 若paramnode不为空,说明有形参需要赋值,得到形参名"a";
4. 获得paramarr[0]的值p1,复制一份,放入VarHash, VarHash["a"] = dup(p1);
5. 继续下一个个赋值, paramnode = paramnode->right;
6. 若paramnode不为空,说明有形参需要赋值,获得形参名"b"
7. 获得paramarr[1]的值p2,复制一份,放入VarHash, VarHash["b"] = dup(p2);
8. 继续下一个个赋值, paramnode = paramnode->right;
9.paramnode为空,说明2个形参赋值完毕,返回
10.执行fundef->right. 即stmt
由于在处理语句时,参数的个数是不一定的,所以采用了链表来记录实际参数列表,每次赋值完一个,下移即可。上面使用数组,仅为了表达方便。
部分参考代码如下,已测试通过。 完整的代码,请参阅
... ... Node* createPARAM(char* name, Hash localvars){ Node* ret = createEmptyNode(); ret->op = PARAMS; ret->localvars = localvars; ret->data = createStrData(name); return ret; } Node* createPARAMS(Node* param, Node* params){ param->right = params; return param; } ... ... Node* createFUN(Node* paramslist, Node* stmts, Hash localvars){ Node* ret = createEmptyNode(); ret->op = FUN; ret->localvars = localvars; ret->left = paramslist; ret->right = stmts; return ret; } ... ... typedef struct _ArrayUnit{ void* data; struct _ArrayUnit * next; } ArrayUnit; .... Data ExPARAMS(Node* node, ArrayUnit* actualParams){ //actual params should be array Data *dup = (Data*)malloc(sizeof(Data)); memcpy(dup, actualParams->data, sizeof(Data)); setItem(node->localvars,node->data->value.strValue,dup); actualParams = actualParams->next; if(node->right != NULL){ ExPARAMS(node->right, actualParams); } } ... ... Data ExFUNCALL(Node* node){ //set param Data params = ExGET(node->left); ExPARAMS(node->right->left, params.value.arrayValue); return ExSTMT(node->right); } ... ...