现代编译原理——第四章:语义分析以及源码
转自: http://www.cnblogs.com/BlackWalnut/p/4527845.html
写完语义分析的代码后感觉语义分析只是为了进行类型检测(后来才发现,这只是语义分析的一部分)。词法分析注重的是每个单词是否合法,以及这个单词属于语言中的哪些部分。语法分析的上下文无关文法注重的是一个一个的推导式,是将词法分析中得到的单词按照语法规则进行组合。那么,语义分析就是要了解各个推导式之间的关系是否合法,主要体现在推导式中使用的终结符和非终结符之间的关系,也就是它们的类型。所以语义分析注重的一个方面是类型检测。
为了将上下文无关文法中各种终结符和非终结符联系起来,以及在想要使用它们的时候得到它们相应的类型,我们使用了一种叫做符号表的东西,又称为环境。环境可以理解为对每一个ID建立一个栈,栈中存放的和这个ID相关的一些信息,这些信息称为绑定。使用栈的好处是,可以解决作用域的问题。ID始终对应于栈顶的绑定,每次进入一个新的作用域就将一个作用域标示符压入栈中。这样,在一个新的作用域中定义了一个和老作用域ID相同的变量,类型或者函数时,将新的绑定压入栈中,那么老的绑定就会失效。当出作用域时,将作用域标示符以上的所有绑定都弹出,这样就完成了老绑定的恢复。
上面介绍的栈式环境,我们称为命令式风格。还有一种称为函数式风格,它的特点是每次都将原来的环境复制一份,将老的保存起来,对新的进行更改。当出作用域时,直接将新的抛弃,然后使用老的。
为什么只存放变量,类型以及函数的相关信息呢?我们可以看到,一种语言其实包含四个部分类型声明,函数声明,变量声明以及表达式, 前三个就利用内置类型来创造新的东西,而表达式则是使用这些东西所要遵守的规则,这些规则都是由上下文无关文法定义好的。声明和表达式就组成了一个语言的基本部分,我们只能使用这些规则来组织我们创造的东西,最终形成我们的程序。所以在语义分析阶段,我们只用注重各种类型的检测,看看在特定的规则下是否符合要求。
下面我们来看看tiger中语义分析时要注意的事项。
在tiger的语义分析过程中,我们使用了两个环境,值环境和类型环境。其中,值环境用来存放函数声明,变量声明的,类型环境是用来存放类型声明的。之所以使用两个符号表是因为在tiger中我们允许类型和变量,函数名使用相同的ID,但是不允许变量和函数使用相同的ID。并且,在tiger中,为了更快的找到ID所对应的绑定,我们使用了hash表来存储每个ID对应的栈。但是这里有个问题要解决,就是hash可能会造成冲突。例如ID1和ID2同时hash到同一个表项中,那么这个表项对应的栈是谁的?这个时候,我们要在绑定中存放这个绑定对应的ID。我们只要从栈顶开始比较,找到第一个和我们hash的ID相同的绑定,就是我们需要的绑定。
但是,这样的话,每次查找hash表都要进行字符串的比较,是十分低效的。所以,tiger中symbol.h文件给了另一个hash表,这个hash表的作用是将一个ID映射到一个指针(就是在语法分析中使用函数S_symbol)。那么我们只要将这个指针和绑定压入栈总,比较这个指针就可以确定这个绑定是不是我需要查找的绑定。这是一个十分精巧的设计。
知道了如何根据ID查找相应的绑定,那么我们来看看这些绑定究竟是什么。
首先,我们向栈中压入绑定时,绑定其实使用一个void*类型的指针指向的,也就是说,我们不关心压入的绑定是什么,我们只关心压入绑定的地址以及压入到哪个表中(函数s_enter)。在读出(函数s_look)绑定的时候,我们只要把这个地址转换为我们需要的绑定(值绑定或者类型绑定)就可以了。
对于类型环境,每一个类型ID对应一个Ty_ty_结构体定义的绑定,这个Ty_ty_在Types.h中定义。可以看出这个结构体包含的类型(kind 枚举)是很多,其中要注意的是TY_name这个枚举,这个枚举是所有由 type id = id 这种语句定义的类型。根据不同的类型,我们使用联合中不同变量来解读。后面的几个函数都是根据不同kind来创建不同Ty_ty。但是要注意到,在新建一个类型环境的时候,我们要把int和string两个ID以及对应的绑定压入(S_enter)栈中,这两个是内置类型,必须先入栈。这里的int和string是类型,也就是终结符ID。和词法分析时的INT STRING的概念不同,这两个INT STRING是整型常量和字符型常量,它们的类型是int和string。
对于值环境,我们使用env.h中的E_enventry 结构体。这个就相对简单许多。
知道tiger中使用的绑定是什么样子的,就来说说这里面的一些坑。注意到我们使用到很多指针,大部分都是由指针引起的。
首先,我们在进行类型比较的时候,使用的指针。这里说说为什么,对于 type intary = array of int 以及 type strary = array of string ,如果只intary和strary所对应的绑定的kind来判断,两个都是Ty_array,但是两个的类型确实是不一样的,所以这种只使用kind判断的方式是失效的。所以这个时候我们要看看绑定中联合里的array(这是一个指针)是否一致。我们查看内置类型(int vaid nil sting),它们都是由函数(Ty_Int等)直接返回的指针,查看函数后发现,这些内置类型使用的都是相同的地址。但是其他类型的地址却有可能不同,这时就是下面这个注意事项。
另外一个需要注意的是,因为在tiger中存在这样的类型定义 type ID1 = ID2 也就是说ID1 是 ID2 的别名,此时ID1中的绑定指向由 Ty_Name 函数返回的一个地址,该函数申请了一块新的内存。如果我们再定义type ID3 = ID2 ,此时使用指针比较ID1 和 ID3,这个时候判断两个类型是不一致的。这显然和tiger的要求的相违背。这个时候我们定义了一个新的函数actrulyTy,这个函数将返回绑定的“真实类型”,这些真是类型只可能是四个内置类型 ,数组类型或者记录类型,同时书中要求返回的任何expty中的Ty_ty必须是“真实类型”。那么,对一下代码进行类型检测就可以得到正确的结果。
type recd = { a : int , b : string }
type recd1 = recd
type recd2 = recd
//测试 recd1 和 recd2 是否相等
recd1 == recd2
这里提醒一下,我提供的代码实不支持一下类型检测的
type recd = { a : int , b : string }
type recd1 = recd
type recd2 = recd
type recd1ary = array of recd1
type recd2ary = array of recd2
//以下此时将返回false
recd1ary == recd2ary
其实就是将recd1和recd2 再次进行一次actrulyTy就可以了。总之,两类型比较时,一定要求时“真实类型”。
还有一个,可能是虎书的作者没有注意到的一个地方(或许是我的代码有问题??)。在使用词法分析器向语法分析器传送ID以及相应的字符串时,我们使用一个变量(在我上一篇文章中讲述bison和flex传值)yylval.sval ,注意,这个sval是一个指针,指向一个字符串的开头,被指向的这个字符串是yytext。这个yytext字符串在进行词法分析时是会改变的。所以当你在语法分析器中将词法分析器传出的sval作为参数调用S_symbol时,这个sval指向的字符串yytext可能已经改变了(因为语法分析器存在移进以及规约,所以并不是和词法分析器同步工作的)。因此在使用s_symbol时要进行一些调整,如下:
S_symbol S_Symbol(string Id)
{
int i = 0 ;
for ( ; (Id[i] >= '0' && Id[i] <= '9') || ( Id[i] >= 'a' && Id[i] <= 'z')||( Id[i] >= 'A' && Id[i] <= 'Z') ;++i) ;
string name = (string)checked_malloc( sizeof(*name) * (i+1)) ;
int b = sizeof(*name) * (i+1) ;
memcpy(name , Id , sizeof(*name)*(i)) ;
name[i] = '\0' ;
int index= hash(name) % SIZE;
S_symbol syms = hashtable[index], sym;
for(sym=syms; sym; sym=sym->next)
if (streq(sym->name,name)) return sym;
sym = mksymbol(name,syms);
hashtable[index]=sym;
return sym;
}
代码比较渣渣。。。。同样的调整还出现在处理字符串常量的函数中。
对于要处理的函数以及记录类型的递归,可以看成时c++中先处理头文件,在处理cpp。也不算太难,但是要注意,保持指针指向正确的位置。
以下就是这次的部分代码,没有实现当有错误时,显示错误位置的功能。有些代码比较简单,就没有贴出来。这份代码已经经过随书附带的前六个测试用例测试过,没有问题:
env.h
#ifndef ENV_H_
#define ENV_H_
#include "types.h"
typedef struct E_enventry_ *E_enventry ;
struct E_enventry_ {
enum { E_varEntry , E_funEntry } kind;
union
{
struct { Ty_ty ty ; } var;
struct { Ty_tyList formals ; Ty_ty result ;} fun ;
}u;
};
E_enventry E_VarEntry(Ty_ty ty) ;
E_enventry E_FunEntry(Ty_tyList formals , Ty_ty reslut) ;
S_table E_base_tenv() ;
S_table E_base_venv() ;
Ty_ty actrulyTy(Ty_ty) ;
bool isTyequTy( const Ty_ty ,const Ty_ty) ;
void tyCpy(Ty_ty dec , const Ty_ty src );
#endif
env.cpp
#include "env.h"
#include <stdio.h>
#include <string.h>
E_enventry E_VarEntry(Ty_ty ty)
{
E_enventry p = (E_enventry) checked_malloc(sizeof(*p)) ;
p->kind = E_enventry_::E_varEntry ;
p->u.var.ty = ty ;
return p ;
}
E_enventry E_FunEntry(Ty_tyList formals , Ty_ty reslut)
{
E_enventry p = (E_enventry)checked_malloc(sizeof(*p)) ;
p->kind = E_enventry_::E_funEntry ;
p->u.fun.formals = formals ;
p->u.fun.result = reslut ;
return p ;
}
Ty_ty actrulyTy(Ty_ty ty)
{
if (ty == NULL )
{
return NULL ;
}
while(ty->kind == Ty_ty_::Ty_name)
{
ty = ty->u.name.ty ;
}
return ty ;
}
bool isTyequTy(const Ty_ty s1 , const Ty_ty s2)
{
Ty_ty tmp1 = actrulyTy(s1) ;
Ty_ty tmp2 = actrulyTy(s2) ;
bool aryOrRec = (tmp1->kind == Ty_ty_::Ty_array || tmp2->kind == Ty_ty_::Ty_record) ;
bool isnil = (tmp1->kind == Ty_ty_::Ty_nil || tmp2->kind == Ty_ty_::Ty_nil) ;
if ( tmp1->kind != tmp2->kind)
{
if ( isnil && aryOrRec )
{
return true ;
}
return false ;
}
if (aryOrRec)
{
if (tmp1 != tmp2 )
{
return false ;
}
}
return true ;
}
void tyCpy(Ty_ty dec , const Ty_ty src)
{
if (dec == NULL || src == NULL )
{
assert(0) ;
}
memcpy(dec , src , sizeof(*src)) ;
}
sement.h
#ifndef SENMANT_H_
#define SENMANT_H_
#include "types.h"
#include "translate.h"
#include "absyn.h"
struct expty { Tr_exp exp ; Ty_ty ty; };
expty expTy(Tr_exp exp , Ty_ty ty) ;
expty transVar(S_table venv , S_table tenv , A_var var) ;
expty transExp(S_table venv , S_table tenv , A_exp exp) ;
void transDec(S_table venv , S_table tenv , A_dec dec) ;
Ty_ty transTy( S_table tenv , A_ty ty) ;
bool innerIdentifiers( S_symbol sym);
#endif
sement.cpp
#include "semant.h"
#include <assert.h>
#include "env.h"
expty expTy(Tr_exp exp , Ty_ty ty)
{
expty e ;
e.exp = exp ; e.ty = ty ;
return e ;
}
expty transExp(S_table venv , S_table tenv , A_exp exp)
{
if (exp == NULL )
{
assert(0);
}
switch(exp->kind)
{
case A_varExp :
return transVar(venv , tenv , exp->u.var) ;
case A_nilExp :
return expTy(NULL ,Ty_Nil());
case A_intExp :
return expTy(NULL , Ty_Int()) ;
case A_stringExp :
return expTy(NULL , Ty_String()) ;
case A_callExp :
{
E_enventry tmp = (E_enventry)S_look(venv, exp->u.call.func) ;
if (tmp == NULL)
{
assert(0) ;
}
Ty_tyList tylist = tmp->u.fun.formals ;
A_expList explist = exp->u.call.args ;
while (tylist != NULL && explist != NULL)
{
expty exptyp = transExp(venv , tenv , explist->head) ;
if (exptyp.ty->kind == Ty_ty_::Ty_nil)
{
continue ;
}
if (!isTyequTy(tylist->head , exptyp.ty))
{
assert(0) ;
}
tylist = tylist->tail ; explist = explist->tail ;
}
if (tylist != NULL || explist != NULL )
{
assert(0);
}
return expTy(NULL , actrulyTy(tmp->u.fun.result)) ;
}
case A_opExp :
{
switch(exp->u.op.oper)
{
case A_plusOp :
case A_minusOp :
case A_timesOp :
case A_divideOp :
case A_ltOp :
case A_leOp :
case A_gtOp :
case A_geOp :
{
if (transExp(venv , tenv, exp->u.op.left).ty->kind != Ty_ty_::Ty_int)
assert(0);
if (transExp(venv , tenv, exp->u.op.right).ty->kind != Ty_ty_::Ty_int)
assert(0);
return expTy(NULL , Ty_Int()) ;
}
case A_eqOp :
case A_neqOp:
{
expty tmpleft = transExp(venv , tenv, exp->u.op.left) ;
expty tmpright = transExp(venv , tenv, exp->u.op.right) ;
if (tmpleft.ty->kind == Ty_ty_::Ty_int
&& tmpright.ty->kind == Ty_ty_::Ty_int)
return expTy(NULL , Ty_Int()) ;
if (tmpleft.ty->kind == tmpright.ty->kind)
{
if (tmpleft.ty->kind == Ty_ty_::Ty_record || tmpleft.ty->kind == Ty_ty_::Ty_array)
{
if ( tmpleft.ty == tmpright.ty )
{
return expTy(NULL , Ty_Int()) ;
}
}
}
assert(0);
}
}
assert(0);
}
case A_recordExp :
{
Ty_ty tmpty = (Ty_ty)S_look(tenv , exp->u.record.typ) ;
tmpty = actrulyTy(tmpty) ;
if (tmpty == NULL )
{
assert(0) ;
}
if (tmpty->kind != Ty_ty_::Ty_record )
{
assert(0) ;
}
A_efieldList tmpefield = exp->u.record.fields ;
Ty_fieldList tmpfieldlist = tmpty->u.record ;
while(tmpefield && tmpfieldlist)
{
if (tmpefield->head->name != tmpfieldlist->head->name )
{
assert(0) ;
}
if (!isTyequTy(transExp(venv , tenv , tmpefield->head->exp).ty
,tmpfieldlist->head->ty))
{
assert(0) ;
}
tmpefield = tmpefield->tail ; tmpfieldlist = tmpfieldlist->tail ;
}
if (tmpfieldlist!= NULL || tmpefield != NULL )
{
assert(0) ;
}
return expTy(NULL ,tmpty);
}
case A_seqExp :
{
A_expList explist = exp->u.seq ;
if (explist)
{
while(explist->tail)
{
transExp( venv , tenv , explist->head);
explist = explist->tail ;
}
}
else
{
return expTy(NULL , Ty_Void());
}
return transExp(venv , tenv , explist->head);
}
case A_assignExp :
{
expty tmpV = transVar(venv , tenv , exp->u.assign.var) ;
expty tmpE = transExp(venv , tenv , exp->u.assign.exp);
if (tmpE.ty->kind != tmpV.ty->kind)
{
assert(0);
}
return expTy(NULL , Ty_Void());
}
case A_ifExp :
{
expty tmptest = transExp(venv ,tenv , exp->u.iff.test) ;
if(tmptest.ty->kind != Ty_ty_::Ty_int)
{
assert(0);
}
expty tmpthen = transExp(venv , tenv , exp->u.iff.then) ;
if (exp->u.iff.elsee != NULL)
{
expty tmpelse = transExp(venv , tenv , exp->u.iff.elsee) ;
if ( tmpthen.ty != tmpelse.ty )
{
assert(0);
}
return expTy(NULL , tmpelse.ty);
}
if (tmpthen.ty->kind != Ty_ty_::Ty_void)
{
assert(0);
}
return expTy(NULL , Ty_Void());
}
case A_whileExp :
{
expty test = transExp(venv , tenv , exp->u.whilee.test);
if (test.ty->kind != Ty_ty_::Ty_int)
{
assert(0) ;
}
expty body = transExp(venv , tenv , exp->u.whilee.body);
if (body.ty->kind != Ty_ty_::Ty_void)
{
assert(0);
}
return expTy(NULL , Ty_Void());
}
case A_forExp :
{
expty tmplo = transExp(venv , tenv , exp->u.forr.lo);
expty tmphi = transExp(venv , tenv , exp->u.forr.hi);
S_beginScope(venv);
S_enter(venv , exp->u.forr.var , E_VarEntry(Ty_Int()));
expty tmpbody = transExp(venv , tenv, exp->u.forr.body);
if (tmplo.ty->kind != Ty_ty_::Ty_int || tmphi.ty->kind != Ty_ty_::Ty_int || tmpbody.ty->kind != Ty_ty_::Ty_void)
{
assert(0);
}
S_endScope(venv);
return expTy(NULL , Ty_Void());
}
case A_breakExp :
return expTy(NULL , Ty_Void());
case A_letExp :
{
S_beginScope(venv);
S_beginScope(tenv);
A_decList declist = exp->u.let.decs ;
while(declist != NULL)
{
transDec(venv , tenv , declist->head);
declist = declist->tail;
}
expty tmp ;
if (exp->u.let.body)
{
tmp = transExp(venv , tenv , exp->u.let.body);
}
else
{
tmp = expTy(NULL , Ty_Void()) ;
}
S_endScope(venv);
S_endScope(tenv);
return tmp ;
}
case A_arrayExp :
{
Ty_ty ty = (Ty_ty)S_look(tenv , exp->u.array.typ);
ty = actrulyTy(ty);
if (ty == NULL || ty->kind != Ty_ty_::Ty_array)
{
assert(0);
}
expty tynum = transExp(venv , tenv , exp->u.array.size);
if (tynum.ty->kind != Ty_ty_::Ty_int)
{
assert(0);
}
expty tyinit = transExp(venv , tenv, exp->u.array.init) ;
if (tyinit.ty != ty->u.array )
{
assert(0) ;
}
return expTy(NULL , ty);
}
}
assert(0);
}
expty transVar(S_table venv , S_table tenv , A_var var)
{
switch(var->kind)
{
case A_simpleVar :
{
E_enventry tmp = (E_enventry) S_look(venv , var->u.simple) ;
if (tmp != NULL && tmp->kind == E_enventry_::E_varEntry)
{
return expTy(NULL , actrulyTy(tmp->u.var.ty)) ;
}
assert(0) ;
}
case A_fieldVar :
{
expty tmpty = transVar(venv , tenv , var->u.field.var) ;
if (tmpty.ty->kind != Ty_ty_::Ty_record)
{
assert(0);
}
Ty_fieldList fieldList = tmpty.ty->u.record ;
while( fieldList )
{
if ( fieldList->head->name == var->u.field.sym )
{
return expTy(NULL , actrulyTy(fieldList->head->ty)) ;
}
fieldList = fieldList->tail ;
}
assert(0);
}
case A_subscriptVar :
{
expty tmp = transVar(venv , tenv , var->u.subscript.var) ;
if (tmp.ty->kind != Ty_ty_::Ty_array )
{
assert(0) ;
}
expty tmpexp = transExp(venv , tenv , var->u.subscript.exp) ;
if (tmpexp.ty->kind != Ty_ty_::Ty_int)
{
assert(0) ;
}
return tmp ;
}
}
assert(0) ;
}
void transDec(S_table venv , S_table tenv , A_dec dec)
{
switch(dec->kind)
{
case A_functionDec :
{
A_fundecList tmpfun = dec->u.function ;
while(tmpfun)
{
A_fieldList tmpfeldList = tmpfun->head->params ;
Ty_tyList tylist = NULL ;
while(tmpfeldList)
{
Ty_ty ty = (Ty_ty)S_look(tenv,tmpfeldList->head->typ);
tylist = Ty_TyList(ty , tylist) ;
tmpfeldList = tmpfeldList->tail ;
}
if (innerIdentifiers(tmpfun->head->name))
{
assert(0) ;
}
//¿‡À∆”⁄…˘√˜“ª∏ˆ∫Ø ˝ ªπ√ª”–∂®“ÂÀ¸
S_enter(venv , tmpfun->head->name , E_FunEntry(tylist , (Ty_ty)S_look(tenv ,tmpfun->head->result))) ;
tmpfun = tmpfun->tail ;
}
tmpfun = dec->u.function ;
while(tmpfun)
{
S_beginScope(venv) ;
A_fieldList tmpfeldList = tmpfun->head->params ;
while(tmpfeldList)
{
Ty_ty ty = (Ty_ty)S_look(tenv,tmpfeldList->head->typ);
if (innerIdentifiers(tmpfeldList->head->name))
{
assert(0);
}
S_enter(venv ,tmpfeldList->head->name, E_VarEntry(ty)) ;
tmpfeldList = tmpfeldList->tail ;
}
transExp(venv , tenv , tmpfun->head->body) ;
S_endScope(venv) ;
tmpfun = tmpfun->tail ;
}
return ;
}
case A_typeDec :
{
A_nametyList namelist = dec->u.type ;
while(namelist)
{
if (innerIdentifiers(namelist->head->name))
{
assert(0) ;
}
// ¥¶¿Ìµ›πÈ ¿‡À∆”⁄ …˘√˜“ª∏ˆ¿‡–Õ µ´ «ªπ√ª”–∂®“ÂÀ¸
S_enter(tenv , namelist->head->name ,Ty_Name(namelist->head->name , NULL)) ;
namelist = namelist->tail ;
}
namelist = dec->u.type ;
while(namelist)
{
// ¥¶¿Ìµ›πÈ
Ty_ty tmp1 = transTy(tenv , namelist->head->ty ) ;
Ty_ty tmp2 = (Ty_ty)S_look(tenv , namelist->head->name) ;
if ( tmp1->kind == Ty_ty_::Ty_int
|| tmp1->kind == Ty_ty_::Ty_string
|| tmp1->kind == Ty_ty_::Ty_nil
|| tmp1->kind == Ty_ty_::Ty_void)
{
//如果是内置类型 绑定指向的地方是一个固定的地方 所以 这个时候就不是替换内容那么简单了
tmp2 = (Ty_ty)S_changeBind(tenv , namelist->head->name , tmp1);
tmp2 = (Ty_ty)freeTy(tmp2) ;
}
else
{
tyCpy(tmp2 , tmp1) ;
tmp1 = (Ty_ty)freeTy(tmp1) ;
}
namelist = namelist->tail ;
}
namelist = dec->u.type;
while(namelist)
{ // 避免出现 type a = b type b = a 这种没有真实类型的类型定义
Ty_ty tmp = (Ty_ty)S_look(tenv , namelist->head->name) ;
if (!actrulyTy(tmp))
{
assert(0) ;
}
namelist = namelist->tail ;
}
return;
}
case A_varDec :
{
if(dec->u.var.init == NULL)
{
assert(0) ;
}
expty tmp = transExp(venv , tenv , dec->u.var.init) ;
if( (dec->u.var.typ != NULL) )
{
if ( actrulyTy((Ty_ty)S_look(tenv ,dec->u.var.typ)) != tmp.ty)
{
assert(0) ;
}
}
if (innerIdentifiers(dec->u.var.var))
{
assert(0) ;
}
S_enter(venv , dec->u.var.var ,E_VarEntry(tmp.ty)) ;
return;
}
}
assert(0) ;
}
Ty_ty transTy(S_table tenv , A_ty ty)
{
switch(ty->kind)
{
case A_nameTy :
{
if (S_Symbol("int") == ty->u.name)
{
return Ty_Int();
}
if (S_Symbol("string") == ty->u.name)
{
return Ty_String();
}
Ty_ty tmp = (Ty_ty)S_look(tenv , ty->u.name) ;
if ( tmp == NULL )
{
assert(0) ;
}
return Ty_Name(ty->u.name , tmp) ;
}
case A_recordTy :
{
A_fieldList tmpfeldList = ty->u.record ;
Ty_fieldList tyfdlist = NULL ;
while(tmpfeldList)
{
Ty_ty tmp = (Ty_ty)S_look(tenv , tmpfeldList->head->typ) ;
if ( tmp == NULL )
{
assert(0) ;
}
if (innerIdentifiers(tmpfeldList->head->name))
{
assert(0);
}
tyfdlist = Ty_FieldList(Ty_Field( tmpfeldList->head->name , tmp ) , tyfdlist) ;
tmpfeldList = tmpfeldList->tail ;
}
return Ty_Record(tyfdlist);
}
case A_arrayTy :
{
Ty_ty tmp = (Ty_ty)S_look(tenv , ty->u.array);
if ( tmp == NULL )
{
assert(0);
}
return Ty_Array(tmp) ;
}
}
assert(0) ;
}
bool innerIdentifiers( S_symbol sym)
{
if (sym == S_Symbol("int") || sym == S_Symbol("string") )
{
return true ;
}
return false ;
}
函数 S_changeBind 相关代码
S_symbol.cpp
void* S_changeBind(S_table t , S_symbol sym , void *value)
{
return TAB_changeBind(t , sym , value) ;
}
S_table.cpp
void* TAB_changeBind( TAB_table t , void * key , void *value )
{
int index ;
assert(t&&key) ;
binder b ;
void * tmp ;
index = ((unsigned)key) % TABSIZE ;
for ( b = t->table[index] ; b ; b = b->next)
{
if (b->key == key )
{
tmp = b->value ;
b->value = value ;
return tmp ;
}
}
return NULL ;
}
posted on 2018-12-02 11:47 jacksplwxy 阅读(2636) 评论(0) 收藏 举报

浙公网安备 33010602011771号