PL/0语言词法及语法分析系统的设计与实现

作者:陶善文
南京航空航天大学信息与计算机科学专业

下载源代码

摘要:本文介绍了一个PL/0语言的词法及语法分析系统的设计与实现
关键词:循环分支 递归下降 管道 输出重定向

  现在的编译系统都是IDE(Integrated Development Environment)和编译器独立实现,他们之间通过管道通信,本系统也采用这一方法来实现。我首先给出本文中的PL/0语言的文法:

PL/0语言的BNF描述(扩充的巴克斯范式表示法)

<prog> → program <id>;<block>
<block> → [<condecl>][<vardecl>][<proc>]<body>
<condecl> → const <const>{,<const>}
<const> → <id>:=<integer>
<vardecl> → var <id>{,<id>}
<proc> → procedure <id>(<id>{,<id>});<block>{;<proc>}
<body> → begin <statement>{;<statement>}end
<statement> → <id> := <exp>
|if <lexp> then <statement>[else <statement>]
|while <lexp> do <statement>
|call <id>[(<exp>{,<exp>})]
|<body>
|read (<id>{,<id>})
|write (<exp>{,<exp>})
<lexp> → <exp> <lop> <exp>|odd <exp>
<exp> → [+|-]<term>{<aop><term>}
<term> → <factor>{<mop><factor>}
<factor>→<id>|<integer>|(<exp>)
<lop> → =|<>|<|<=|>|>=
<aop> → +|-
<mop> → *|/
<id> → l{l|d}   (注:l表示字母)
<integer> → d{d}      

注释:

<prog>:程序 ;<block>:块、程序体 ;<condecl>:常量说明 ;<const>:常量;
<vardecl>:变量说明 ;<proc>:分程序 ; <body>:复合语句 ;<statement>:语句;
<exp>:表达式 ;<lexp>:条件 ;<term>:项 ; <factor>:因子 ;<aop>:加法运算符;
<mop>:乘法运算符; <lop>:关系运算符
odd:判断表达式的奇偶性。      

  下面我们先来看看词法及语法分析器的设计与实现。词法分析采用循环分支方法实现,语法分析采用递归下降来实现。它们的程序流程图如下:

  下面我们来实现这个两个分析器。这两个分析器采用一个类CCompiler来实现,这个类的定义如下:
//编译类

class CCompiler
{
public:
CCompiler();
virtual ~CCompiler();
public:
void Compile(char *szFile);//编译,公共接口
vector<SYNTAXERR> 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<LEXPROPERTYVS> m_vectorSymbol;//符号表
vector<SYNTAXERR> m_vectorSyntaxErr; //语法错误代码
};      

  其中:函数bool LexAnalysis(char *szStr);是对输入字符串szStr采用循环分支方法进行词法分析,分析出来的符号放在符号表m_vectorSymbol中,这个符号表采用向量这个数据结构来表示。词法分析得出符号表后,即进入语法分析阶段,语法分析由函数void SyntaxAnalysis();完成。下面这些函数是各非终结符对应的递归子程序。

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);
}
}      

  这样就完成了整个分析系统的设计与实现。下面我们来看看整个系统是怎样运行的。我们先来看看这个系统的运行界面:

  程序运行后,出现如图所示的界面,首先设置分析程序的路径,方法是:点菜单IDE环境(I),设置,会出现如下图所示的对话框:

  在编辑框中输入分析器所在路径即可(默认分析器和源文件在一个目录下)。设置好以后,就可以在代码编辑区输入代码了,或者点“打开”打开文件,然后点击工具栏“启动”(也可按快捷键F7)按钮进行分析,分析完以后,词法分析结果会在“分析结果显示区”显示,词法和语法分析信息会在"输出信息显示区"显示。

已知的 bug 说明
  由于时间关系,现有如下Bug本人未能调试出来,若有高手调试出来的话,还望告知。

  1. PL.exe 有大量内存泄漏,但是本人在 CCompiler 的析构函数中用如下代码释放内存,不知为何出错:

            CCompiler::~CCompiler()        {            //下面这段释放内存的代码不知道为什么出错            // for(int i=0;i<m_iVecotrSymbolSize;i++)            // delete m_vectorSymbol[i].szStr;        }
  2. 用测试源文件中的 Test3.pas 测试 PL.exe 时,不知道为什么在Debug状态下不出错,而在Release状态下出错。
  3. 用测试源文件中的Test3.pas测试 IDE.exe 时,输出信息栏会多出一些前面已经显示过的信息,不知道为什么,估计读管道信息时,又把原来的已经读过了的信息又读了一遍 。
  4. 源码编辑区的行和列显示问题:我目前只显示了行,列还不能显示。
  5. 工作区间栏:点击右键,再选“展开”。有时候会出现不了你想要的效果,再用右键点击时,必须先用左键点击,这样才能得到你想要的效果,原因是:函数GetSelectedItem()得到的选中的项必须先用左键点击 ,不知道怎样才能解决这个问题。
  6. 双击工作空间的最子节点时,应该使该节点对应的单词进入用户的视区范围内。
  7. 类CIDEView中的函数GetCompileResult()中的一段代码,在Release版本中运行没有出错,在Debug版本中出错.代码如下 :
            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();

    这段代码的意思就是在启动分析程序之前先保存文件并把窗口上做未保存标记的星号去掉。

参考文献

  1. 陈火旺等,程序设计语言编译原理,国防工业出版社,2001.1
  2. 王咏刚,《编写自己的IDE》,2005-1-10

作者联系方式

  • http://home.pudn.com/ahei
  • http://AIfan.54sc.com
  • QQ:8261525 计算机博弈QQ群:5620663
  • ahei080210114@hotmail.com
  • ahei0802@126.com
最新评论 [发表评论] [文章投稿] 查看所有评论 推荐给好友 打印

好了,你的程序问题我帮你解决了:)
原因是你在给字符串分配内存时没有考虑'/0'占用的空间,低级错误啊!!
将程序中所有new char[xxx]的地方改为new char[xxx + 1],就好了,释放内存不会出错了:)

还有一个函数bool CCompiler::LexAnalysis(char *szStr)
...
中szTemp=new char[nLen + 1];
szTemp没有释放!!!

然后就没有泄漏问题了。 ( wuhuaqiang 发表于 2005-1-20 13:44:00)
 
刚刚调试一下你的代码,肯定要加上释放内存语句,总不能因为出错就不释放内存了:)
出错是因为代码存在缓冲区溢出漏洞,程序存在多处数组越界访问,篡改了不属于你的内存区,释放内存时系统会检查这些东西,当然会出错了。
编码的基本功和细心程度有待提高。 ( wuhuaqiang 发表于 2005-1-20 13:30:00)
 
大概浏览了一下你的代码,释放内存那块好像应该改为
CCompiler::~CCompiler()
{   
    //下面这段释放内存的代码不知道为什么出错
    // for(int i=0;i<m_iVecotrSymbolSize;i++)
    // delete [] m_vectorSymbol[i].szStr;
}
感觉这种简单类型用malloc和free分配和释放方便一些 ( wuhuaqiang 发表于 2005-1-20 13:05:00)

转:PL/0语言词法及语法分析系统的设计与实现相关推荐

  1. PL/0语言编译程序分析

    PL/0语言是Pascal语言的一个子集,我们这里分析的PL/0的编译程序包括了对PL/0语言源程序进行分析处理.编译生成类PCODE代码,并在虚拟机上解释运行生成的类PCODE代码的功能. PL/0 ...

  2. PL/0语言编译器扩展 编译原理课程实践(1)

    转眼大学生活就要结束,编译原理课程学的东西很多都忘记了.当时我们编译原理课程实践是PL/0语言编译器扩展,在原有PL/0语言文法进行扩展.我写这次博文一是为了回忆以前学的知识,加深记忆:二是和大家分享 ...

  3. PL/0 语言简介、PL/0 文法

    PL/0 语言简介 A. PL/0 语言是 Pascal 语言的子集- 数据类型只有整型- 标识符的有效长度是 10 ,以字母开头的字母数字串- 数最多 14 位- 过程无参,可嵌套(最多三层),可递 ...

  4. 单片机c语言 课程设计报告,C语言编写单片机万年历系统课程设计报告98分

    <C语言编写单片机万年历系统课程设计报告98分>由会员分享,可在线阅读,更多相关<C语言编写单片机万年历系统课程设计报告98分(30页珍藏版)>请在人人文库网上搜索. 1.多功 ...

  5. 编好c语言网上自动评测,C语言程序自动评测系统的设计与实现

    摘要: 随着计算机技术的发展和提高,计算机辅助评价(CAA)已成为当前计算机教育应用的热点研究问题之一.已有的研究成果已能很好的解决客观题测评问题,而主观题的评测问题则仍处于发展阶段.C语言程序设计课 ...

  6. 语法分析实验ll算法c语言,实验5LL语法分析程序的设计与实现(C语言).doc

    实验5LL语法分析程序的设计与实现(C语言) 实验五 LL(1)文法识别程序设计 一.实验目的 通过LL(1)文法识别程序的设计理解自顶向下的语法分析思想. E+T|T TT*F|F Fi|(E) 参 ...

  7. 语法分析实验ll算法c语言,实验5-LL语法分析程序的设计与实现(C语言)

    实验5-LL语法分析程序的设计与实现(C语言) 袄没阮掉曼劲酮杀咱旷壤恰恨煤幼襄殊杀种见丈农疫甚肚斯迟纵屯胞掘棒粉茎峦噶记殖闲蒂白赐右圣铁廖屏圈赁愿钾玲妨者申佣饺臻鸵综志叫辨宵霄萎润簧凳挥渠励泊淡鲤荐 ...

  8. petshop4.0 详解之一(系统架构设计)

    前言:PetShop是一个范例,微软用它来展示.Net企业系统开发的能力.业界有许多.Net与J2EE之争,许多数据是从微软的PetShop和Sun的PetStore而来.这种争论不可避免带有浓厚的商 ...

  9. petshop4.0 详解之一(系统架构设计)(转载)

    前言:PetShop是一个范例,微软用它来展示.Net企业系统开发的能力.业界有许多.Net与J2EE之争,许多数据是从微软的PetShop和Sun的PetStore而来.这种争论不可避免带有浓厚的商 ...

最新文章

  1. cent卸载mysql_centos 7.x 安装/卸载MySQL
  2. RDB和AOF的持久化配置
  3. moss 与SAP iView web part 整合
  4. 嵩天-Python语言程序设计程序题--第二周:基本图形绘制
  5. 从零开始,手把手交给你vue如何新建一个项目
  6. Linux Shell编程之脚本执行方式
  7. 每半个小时执行一次_活动执行主要做些工作?
  8. Python 文件编码问题解决
  9. mysql.server的路径_WindowsMysqlServer重启,log-bin路径配置
  10. linux mysql 5.7 配置_Linux环境下详细讲解部署MySQL5.7版本
  11. MATLAB神经网络工具箱学习
  12. 今天通过了QCC评审
  13. hibernate的注解属性mappedBy详解
  14. 2020-06-15
  15. ESP8266-Arduino网络编程实例-HightCharts实时图表显示BME280数据
  16. 库卡机器人bco运动_库卡工业机器人编程运动教程
  17. Adobe Acrobat 裁剪pdf
  18. 图卷积神经网络代码讲解,卷积神经网络python实例
  19. Python(17)python使用tkinter实现一个简单的CSGO幸运转盘抽奖游戏
  20. Spring注解开发以及基于java的容器配置

热门文章

  1. 执着的数字思想者——Pascal之父
  2. 网络编程------IP地址,端口号,套接字,网络字节序
  3. Google电话面试都问什么问题?
  4. 证券基金行业本地异地容灾备份查询一体化方案
  5. 台式电脑远程计算机或设备将不接受连接,win7远程计算机或设备将不接受连接导致IE无法上网怎么办?...
  6. java泛型(360°无死角讲解)
  7. SAP SEGW 事物码里的 Association 建模方式
  8. VScode神仙插件,程序员必备
  9. python 最小外接矩形笔记
  10. 经济学概念:货币倍增、债务证券市场、股票市场、大宗商品、期权