轉自: 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 ;
}

