分类:
2008-10-13 16:46:01
PL/0语言词法及语法分析系统的设计与实现
作者:
南京航空航天大学信息与计算机科学专业
摘要:本文介绍了一个PL/0语言的词法及语法分析系统的设计与实现
关键词:循环分支 递归下降 管道 输出重定向
现在的编译系统都是IDE(Integrated Development
Environment)和编译器独立实现,他们之间通过管道通信,本系统也采用这一方法来实现。我首先给出本文中的PL/0语言的文法:
PL/0语言的BNF描述(扩充的巴克斯范式表示法)
注释:→ program ; → [ ][ ][ ] → const {, } → := → var {, } → procedure ( {, }); {; } → begin {; }end → := |if then [else ] |while do |call [( {, })] | |read ( {, }) |write ( {, }) → |odd → [+|-] { } → { } → | |( ) → =|<>|<|<=|>|>= → +|- → *|/ → l{l|d} (注:l表示字母) → d{d}
下面我们先来看看词法及语法分析器的设计与实现。词法分析采用循环分支方法实现,语法分析采用递归下降来实现。它们的程序流程图如下::程序 ; :块、程序体 ; :常量说明 ; :常量; :变量说明 ; :分程序 ; :复合语句 ; :语句; :表达式 ; :条件 ; :项 ; :因子 ; :加法运算符; :乘法运算符; :关系运算符 odd:判断表达式的奇偶性。
class CCompiler { public: CCompiler(); virtual ~CCompiler(); public: void Compile(char *szFile);//编译,公共接口 vector其中:函数bool LexAnalysis(char *szStr);是对输入字符串szStr采用循环分支方法进行词法分析,分析出来的符号放在符号表m_vectorSymbol中,这个符号表采用向量这个数据结构来表示。词法分析得出符号表后,即进入语法分析阶段,语法分析由函数void SyntaxAnalysis();完成。下面这些函数是各非终结符对应的递归子程序。GetSyntaxErr(){return m_vectorSyntaxErr;};//得到语法错误 protected: bool LexAnalysis(char *szStr); //词法分析 bool IsOprSym(char *szStr); //是否为运算符 bool IsBndSym(char *szStr); //是否为界符 bool IsKeyWord(char *szStr); //是否为关键字 bool IsInSymbolTab(char *szStr); //是否已在符号表中 char* JumpNoMatterChar(char *szStr);//跳过空格,回车,换行符,Tab void OutSymbolTab(char *szFile);//输出符号表到文件 void SyntaxAnalysis();//语法分析 void SyntaxAnalysis_Prog(); bool SyntaxAnalysis_Mop(); bool SyntaxAnalysis_Integer(); bool SyntaxAnalysis_Aop(); bool SyntaxAnalysis_Lop(); int SyntaxAnalysis_Id(); int SyntaxAnalysis_Block(); int SyntaxAnalysis_Body(); int SyntaxAnalysis_Factor(); int SyntaxAnalysis_Term(); int SyntaxAnalysis_Lexp(); int SyntaxAnalysis_Exp(); int SyntaxAnalysis_Statement(); int SyntaxAnalysis_Const(); int SyntaxAnalysis_Proc(); int SyntaxAnalysis_Vardecl(); int SyntaxAnalysis_Condecl(); protected: int m_iVecotrSymbolSize; //符号表大小 int m_iCurPointer; //符号表中当前指针 vector m_vectorSymbol;//符号表 vector m_vectorSyntaxErr; //语法错误代码 };
bool SyntaxAnalysis_Mop(); bool SyntaxAnalysis_Integer(); bool SyntaxAnalysis_Aop(); bool SyntaxAnalysis_Lop(); int SyntaxAnalysis_Id(); int SyntaxAnalysis_Block(); int SyntaxAnalysis_Body(); int SyntaxAnalysis_Factor(); int SyntaxAnalysis_Term(); int SyntaxAnalysis_Lexp(); int SyntaxAnalysis_Exp(); int SyntaxAnalysis_Statement(); int SyntaxAnalysis_Const(); int SyntaxAnalysis_Proc(); int SyntaxAnalysis_Vardecl(); int SyntaxAnalysis_Condecl();
以上我介绍了词法及语法分析核心的设计实现,下面我简单介绍下IDE的实现和IDE与分析核心之间的通信。本系统的IDE与分析核心之间采用管道通信,代码如下:
DWORD dwThreadID; ::CreateThread(0,0,CompileThread,this,0,&dwThreadID);//创建进程
进程创建后调用进程函数,
//进程函数
DWORD WINAPI CompileThread(LPVOID pParam) { CCompileSysView *pView=(CCompileSysView*)pParam; pView->GetCompileResult(); return 0; }进程函数调用类的自身函数GetCompileResult();得到分析核心的输出结果,这个函数的实现如下:
void CCompileSysView::GetCompileResult() { SECURITY_ATTRIBUTES sa; HANDLE hRead,hWrite; CString strFile; CString strOut; strFile.Format("..\\pl\\pl.exe ");//指定分析核心程序的路径 //当前文件作为参数传给分析核心程序,防止这个文件名中含有空格,故用双引号""将文件名括住 strFile=strFile+(char)34+m_szCurFile+(char)34; sa。nLength=sizeof(SECURITY_ATTRIBUTES); sa。lpSecurityDescriptor=NULL; sa。bInheritHandle=TRUE; if(!CreatePipe(&hRead,&hWrite,&sa,0))//创建管道进行通信 { MessageBox("Error On CreatePipe()"); return; } STARTUPINFO si; PROCESS_INFORMATION pi; si。cb=sizeof(STARTUPINFO); GetStartupInfo(&si); si。hStdError=hWrite; si。hStdOutput=hWrite;//输出重定向到文件 si。wShowWindow=SW_HIDE; si。dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; //创建进程启动分析核心程序 if(!CreateProcess(NULL,(LPSTR)(LPCTSTR)strFile,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)) { MessageBox("Error on CreateProcess()"); return; } CloseHandle(hWrite); char buffer[4096]={0}; DWORD bytesRead; while(true) { if(!ReadFile(hRead,buffer,4095,&bytesRead,NULL)) break; strOut+=buffer; m_pwndOutBar->SetColorRichEditText(strOut);//将输出结果显示出来 Sleep(500); } }这样就完成了整个分析系统的设计与实现。下面我们来看看整个系统是怎样运行的。我们先来看看这个系统的运行界面:
CCompiler::~CCompiler()
{
//下面这段释放内存的代码不知道为什么出错
// for(int i=0;i// delete m_vectorSymbol[i].szStr;
}
pDoc->SetPathName(strFile,1);这段代码的意思就是在启动分析程序之前先保存文件并把窗口上做未保存标记的星号去掉。
pDoc->SetModifiedFlag(0);
pDoc->OnSaveDocument((LPSTR)(LPCSTR)strFile);//先保存该文件
str=pDoc->GetTitle();
pDoc->SetTitle(str);
if(str.Right(1)=="*")
{
str=str.Left(str.GetLength()-1);
pDoc->SetTitle(str);
}
UpdateWindow();
参考文献
作者联系方式