?? analyze.cpp
字號:
/******************************************************************
** 文件名: analyze.cpp
** 描 述: 這是一個完整的語義分析器,實現C-語言的語義分析功能。基本的
** 流程是:先建立一個空符號表,再建一個語法分析器,語法分析器會
** 產生一棵對于源程序的語法樹,再把語法樹中的源程序中的函數名,
** 變量名及它們的作用域,所在行數等等信息存儲在符號表中,建立
** 完畢后,再對語法樹進行后序遍歷執行語言語義檢查,主要是表達式
** 類型匹配檢查,變量有效性檢查,函數及變量作用域檢查。函數返
** 類型正確性檢查,函數調用時的參數表檢查。
** C-的所有符號都是有作用域的, 但goto語句突破了這個限制,
** 所以,必須為goto語句單獨執行第二遍語義分析。
******************************************************************/
#include "globals.h"
#include "ExternGla"
#include "scan.h"
#include "prase.h"
#include "symtab.h"
#include "analyze.h"
/*********************************************************
**靜態成員變量的聲明。
*******************************************************/
int Canalyzer::m_ilocation=1; //記錄變量或函數名出現的順序(占的內存位置)
Csymboltab* Canalyzer::m_Csymtab; //符號表。
CTreeNode *Canalyzer::m_syntaxTree; //語法樹。
CPraser *Canalyzer::m_pPraser; //語法分析器。
int Canalyzer::m_ilineno;
int Canalyzer::m_ierror=0;
/********************************************
**構造函數,完成語義分析器的所有功能。
********************************************/
Canalyzer::Canalyzer(){
try{
m_Csymtab = new Csymboltab;
CPraser *m_pPraser=new CPraser;
m_syntaxTree=m_pPraser->m_program;
cout<<"Building Symbol Table..."<<endl;
buildSymtab(m_syntaxTree); //根據語法樹建立完整的符號表。
if(AllFlags.m_iTraceAnalyze){
cout<<"\nSmybol table:\n\n";
m_Csymtab->printSymtab();}
cout<<"Checkint Types..."<<endl;
typeCheck(m_syntaxTree); //執行語義檢查。
if(m_ierror==1) exit(0); //有錯誤存在,代碼生成被阻止。
}
catch (bad_alloc){ //處理堆分配異常。
cout<<"Can't be allocated in heap, the programme must be terminated."<<endl;
exit(1);}
catch (...){
cout<<"Something error,the program was terminated.";
exit(1);}
}
Canalyzer::~Canalyzer(){
delete m_pPraser;
delete m_Csymtab;
}
/*******************************************************
**先序遍歷語法樹完成符號表的創建(當preProc=insertNode,postProc=nullProc時)
**后序遍符號表完成語義分析。(當preProc=nullProc,postProc=checdNode時)
**********************************************************/
void Canalyzer::traverse(CTreeNode* t, void(* preProc)(CTreeNode *),
void(* postProc)(CTreeNode *)){
if(t!= NULL){
preProc(t);
for(int i=0;i<3;i++)
traverse(t->m_pchild[i],preProc,postProc);
postProc(t);
traverse(t->m_pbrother,preProc,postProc);
}
}
/**********************************************
**空函數,不執行任何功能,主要是為輔助traverse
************************************************/
void Canalyzer::nullProc(CTreeNode *t){
return;
}
/***********************************************
**向符號表中插入一個變量或函數名。
***********************************************/
void Canalyzer::insertNode(CTreeNode *t){
switch(t->m_Ennodekind){
case FuncK:
if(m_Csymtab->st_lookup(t->m_strIDname,t->m_strScope)==-1)
m_Csymtab->st_insert(t->m_strIDname, t->m_strScope,
t->m_EnTypevalue,t->m_ilineno, m_ilocation++);
else{ //函數定義不可能兩次出現,否則為重定義。
cout<<"Error in line "<<t->m_ilineno<<": function: '"
<<t->m_strIDname<<"'"<<" : redefinition"<<endl;
m_ierror=1;}
break;
case DeclK:
case ParaK:
if(m_Csymtab->st_lookup(t->m_strIDname,t->m_strScope)==-1)
m_Csymtab->st_insert(t->m_strIDname, t->m_strScope, t->m_EnTypevalue,
t->m_ilineno, m_ilocation++);
else{ //同一變量的定義在同一作用域內也不能兩次出現,否則為重定義。
cout<<"Error in line "<<t->m_ilineno<<": '"<<t->m_strIDname
<<"'"<<" : redefinition"<<endl;
m_ierror=1;}
break;
case ExpK:
switch(t->kind.m_EnExpKind){
case IdK:
if(t->m_pfather->m_Ennodekind==StmtK && t->m_pfather
->kind.m_EnStmtKind==GotoK)
break; //對goto的地址符號將在第二遍進行處理。
if(m_Csymtab->st_lookup(t->m_strIDname,t->m_strScope)==-1
&& m_Csymtab->st_lookup(t->m_strIDname,"Global")==-1){
//表達式中的符號不可能在表中找不到,因為事前必須聲明。
//但一個函數中的變量可能是局部的,也可能是全局的。
cout<<"Error in line "<<t->m_ilineno<<": '"
<<t->m_strIDname<<"' : undeclared identifier"<<endl;
m_ierror=1;}
else{
//如果是局部的,插入一個局部符號。
if(m_Csymtab->st_lookup(t->m_strIDname,t->m_strScope)!=-1)
m_Csymtab->st_insert(t->m_strIDname, t->m_strScope
, t->m_EnTypevalue, t->m_ilineno, 0);
else//否則為全局的。
m_Csymtab->st_insert(t->m_strIDname, "Global"
, t->m_EnTypevalue, t->m_ilineno, 0);}
break;
default:
break;}
break;
case StmtK:
switch(t->kind.m_EnStmtKind){
case AddressK: //符號地址。
if(m_Csymtab->st_lookup(t->m_pchild[0]->m_strIDname,"Global")!=-1){
cout<<"Error in line "<<t->m_ilineno<<": '"
<<t->m_pchild[0]->m_strIDname<<"': label redefined"<<endl;
m_ierror=1;}
else
m_Csymtab->st_insert(t->m_pchild[0]->m_strIDname, "Global",
t->m_EnTypevalue,t->m_ilineno, m_ilocation++);
break;
default:
break;}
break;
default:
break;}
}
/************************************************
** 對符號表執行語義檢查。
*************************************************/
void Canalyzer::checkNode(CTreeNode *t){
CTreeNode *p=t; //為break,continue的檢查所專用。
switch(t->m_Ennodekind){
case ExpK:
switch(t->kind.m_EnExpKind){
case OpK://表達式中,表達式的類型由精度高的子表達式類型決定。
if(t->m_pchild[1]==NULL){
t->m_EnTypevalue=t->m_pchild[0]->m_EnTypevalue;
break;}
if(t->m_pchild[0]->m_EnTypevalue == VOID ||
t->m_pchild[1]->m_EnTypevalue == VOID){
cout<<"Error in line "<<t->m_ilineno<<
": illegal use of type 'void'"<<endl;
m_ierror=1;}
else if(t->m_pchild[0]->m_EnTypevalue == FLOAT ||
t->m_pchild[1]->m_EnTypevalue == FLOAT)
t->m_EnTypevalue=FLOAT;
else if(t->m_pchild[0]->m_EnTypevalue == INT ||
t->m_pchild[1]->m_EnTypevalue == INT)
t->m_EnTypevalue=INT;
else t->m_EnTypevalue=CHAR;
break;
case IdK: //變量的類型在符號表中可以找到。
if((t->m_EnTypevalue=m_Csymtab->
st_lookuptype(t->m_strIDname,t->m_strScope))==ERROR)
t->m_EnTypevalue=m_Csymtab->st_lookuptype(t->m_strIDname,"Global");
break;
default:
break;}
break;
case StmtK:
switch(t->kind.m_EnStmtKind){
case ReturnK: //函數返回類型必須精確匹配。
if(t->m_pchild[0]==NULL){ //return不帶參數,則函數返回類型必為void.
if(m_Csymtab->st_lookuptype(t->m_strScope, "Global")!=VOID){
cout<<"Error in line "<<t->m_ilineno<<": Function '"
<<t->m_strScope<<"' must return a value."<<endl;
m_ierror=1;}
}
break;
case BreakK:
//break語句的基本處理思想是沿著樹往雙親結點搜索,如果找不到for,或while
//語句,則說明該break句子位置不對,continue相同處理。
while(p->m_pfather!=NULL && (p->m_pfather->m_Ennodekind!=StmtK ||
(p->m_pfather->kind.m_EnStmtKind!=ForK
&& p->m_pfather->kind.m_EnStmtKind!=WhileK)))
p=p->m_pfather;
if(p->m_pfather==NULL){
cout<<"Error in line "<<t->m_ilineno<<": illegal break"<<endl;
m_ierror=1;}
break;
case ContinueK: //同continue語句。
while(p->m_pfather!=NULL && (p->m_pfather->m_Ennodekind!=StmtK ||
(p->m_pfather->kind.m_EnStmtKind!=ForK
&& p->m_pfather->kind.m_EnStmtKind!=WhileK)))
p=p->m_pfather;
if(p->m_pfather==NULL){
cout<<"Error in line "<<t->m_ilineno<<": illegal continue."<<endl;
m_ierror=1;}
break;
default:
break;}
break;
default:
break;}
}
/*************************************************
** 因為goto語句是突破作用域范圍的限制的,所以必須
** 為它單獨執行一遍語義檢查。
*************************************************/
void Canalyzer::checkgoto(CTreeNode *t){
switch(t->m_Ennodekind){
case StmtK:
switch(t->kind.m_EnStmtKind){
case GotoK:
if(m_Csymtab->st_lookup(t->m_pchild[0]->m_strIDname)==-1){
cout<<"Error in line "<<t->m_ilineno<<": '"<<t->m_pchild[0]->
m_strIDname<<"'"<<" was undefined."<<endl;
m_ierror=1;}
else
m_Csymtab->st_insert(t->m_pchild[0]->m_strIDname,
t->m_EnTypevalue,t->m_ilineno, 0);
break;
default:
break;}
break;
default:
break;}
}
/********************************************************
**先序遍歷語法樹構造符號表,并打印出符號表。
********************************************************/
void Canalyzer::buildSymtab(CTreeNode* syntaxTree){
traverse(syntaxTree, insertNode,nullProc);
}
/******************************************************
**后序遍歷語法樹,結合符號表執行語義分析。
** 在第二遍語義檢查結束時,確定main函數的存在。
******************************************************/
void Canalyzer::typeCheck(CTreeNode* syntaxTree){
traverse(syntaxTree,nullProc,checkNode);
traverse(syntaxTree,nullProc,checkgoto); //執行第二遍語義分析,為goto匹配符號地址。
if(m_Csymtab->st_lookup("main","Global")==-1){ //語義分析結束,確定一下main函數是否存在。
cout<<"unresolved external symbol main"<<endl;
m_ierror=1;}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -