实现C语言的词法分析器文档格式.docx

上传人:b****5 文档编号:19139080 上传时间:2023-01-04 格式:DOCX 页数:14 大小:361.81KB
下载 相关 举报
实现C语言的词法分析器文档格式.docx_第1页
第1页 / 共14页
实现C语言的词法分析器文档格式.docx_第2页
第2页 / 共14页
实现C语言的词法分析器文档格式.docx_第3页
第3页 / 共14页
实现C语言的词法分析器文档格式.docx_第4页
第4页 / 共14页
实现C语言的词法分析器文档格式.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

实现C语言的词法分析器文档格式.docx

《实现C语言的词法分析器文档格式.docx》由会员分享,可在线阅读,更多相关《实现C语言的词法分析器文档格式.docx(14页珍藏版)》请在冰豆网上搜索。

实现C语言的词法分析器文档格式.docx

1)状态枚举:

枚举的最大好处在于能够用字符(状态)代替数字,而且将这些封装在一个结构中。

2)TokenString是为了存储保留字的标识符

3)以下变量是为了处理输入缓存以及当前指针位置的相关存储:

4)保留字的结构体,这一部分可以清晰的看到所有保留字:

iii.词法分析器的相关函数:

1)处理文件输入相关:

这两个函数是一对,前者是从缓存中读取下一个字符,后者则将当前读取的字符重新放回缓存。

后者存在的最大的价值在于,当用下一字符的情况判断将跳转到什么状态时,如果该字符不属于当前标示符,则放回缓存,以保证下一标示符的获取不受影响。

2)判断字符是否为保留字:

对于读入的单词,我们需要知道其到底是一个变量名还是一个保留字,这个时候就需要调用该函数。

利用for循环在所有保留字中搜寻,有匹配的就说明是一个保留字,否则就是变量名。

3)DFA实现算法:

TINY采用的是while和多层switch判断相结合的跳转形式,这种写法和EDA实验中的状态装换如出一辙,非常简便而且容易理解。

但是缺点也很明显:

不容易扩充,显得比较杂乱。

其逻辑很清楚:

从START状态开始,每获取一个字符,就根据字符情况跳转到相应的下一状态,如果跳转到接受态DONE,则输出。

输出是调用UTIL.C文件完成的。

可以看到的是,如果一个语言越复杂,其包含的字符形式越多,这种case讨论将会越复杂,至此我已经可以想象得到C语言词法分析器的“宏伟”程度了。

2.改变DFA的实现算法:

通过分析TINY的词法分析器,我们很快可以找到我们的DFA实现形式与其的差别。

我们是建立了一个状态转换表,并将其存储在了一个二维结构中,通过输入与当前状态的对应得到下一状态的,并将这一状态变成当前状态,反复进行上述操作,直到进入接受态。

如果要改变DFA的实现算法,过程很明显:

建立二维结构存储状态转移,查表进行状态转移。

接下来将进行操作和分析:

1)在修改之前,先观察原有的词法分析器正常运行的结果,以便修改后比对:

为了测试输出结果,我们在主函数(TINY_XH)中将词法分析追踪(TraceScan)赋值为TRUE,这样在进行编译的输出中就可以看到词法分析的结果,方便用来对比。

TraceScan一旦使能,这里就可以输出到屏幕上。

在修改程序之前,截屏如上,左边是源程序,右边是编译的词法分析的结果

 

2)建立状态转换表,通过分析源程序可知如下状态转换图:

(该图是我用VISIO绘制)

原程序使用while大循环下的switch和case进行状态转换,这里完全可以换成上次我们写的通用DFA形式。

所谓通用DFA就是指状态转换的核心部分不会随着状态或者输入的改变而改变,状态转换的跳转和状态存储的二维表有关,只用修改存储状态的二维表,既可以方便的修改或者扩充编译器的词法处理能力。

状态图转换成状态表可得:

通过状态转换情况,将其保存在状态转换表中,具体形式如上。

就二维表而言,有很多种写法,比如我把一些输入合并到other类型,是为了减轻状态表的冗余状态数量。

这个二维表中没有冗余状态。

判断冗余的方法很简单,如果有两列/两行完全相同,这两列/两行就可以合并成一列/一行。

3)修改状态转换代码以及附属属性部分的实现:

有了状态转换表,状态转移只用一句话就可以解决:

可以说就状态转移这一部分而言,非常简单。

但是为了方便输出,需要知道获取的标示符是什么类型的,因此需要进行赋值。

比如如下修改:

4)测试结果:

(和修改前完全一致)

c)实验问题:

1)程序进入死循环,或者一直报错:

程序不能正确执行,肯定出在细节处,我开始以为是逻辑处出错,一直在检查语句,结果很长时间都没有发现问题。

后来排除了所有可能,我检查了一下最开始制作的二维状态转移表,果然就发现了问题的所在:

状态转换中本应跳转到DONE,因为失误写成了START,结果跳转到了START。

纠正结果后,程序完全正确,但是这个错误确实消耗了我很长的时间去检查。

d)实验结果:

对SCAN.C的解释,在上面的报告中已经给出。

SCAN.C的修改版本在CODE文件夹中。

如果要运行完整的程序,在“CODE\完整的VS工程”目录中,可以用VisualStudio运行,其中sample.tny在该工程的debug文件夹下,方便用CMD运行。

e)实验心得:

由于有了第一次的实验的基础,转化成一个DFA的思想是非常清晰而简单的,然而实现的过程不是一帆风顺的,中间任何一个环节都可能会出现很多小问题,一个小细节没有处理好,可能会导致整个程序的崩溃,所以需要耐心和细心。

我在做的过程中,曾经因为一个状态打错,导致跳转时有误,开始一直怀疑是逻辑问题,不曾检查状态表的错误,导致延误了很久。

我觉得纠错的过程就像是推理和演绎,虽然有DEBUG,不过我使用的比较少,单纯通过输出推测出错的地方会是哪里,我喜欢这个过程。

当一个完整的词法分析结果出现在CMD中时,突然觉得这是最美的文字。

二.实现一门语言的词法分析器

通过上面的实验我们已经了解了简单的词法分析器,实战莫过于新编一个语言的编译器。

而一个语言的词法分析器,我们首先要知道它含有什么关键字,有哪些专用符号,什么是特殊标记,以及其他符号或者注释情况。

1.语言确定:

我选择C-语言,因为要在以后的实验中继续完善其他部分,所以我希望按照一个完整的工程制作。

因此仿照TINY编译器的形式,将每一部分的功能集中在一个文件中,有globals文件对全局变量进行定义,有util专职输出,有C_XH文件作为主函数,调用其他的函数。

然后定义SCAN函数进行词法分析。

我希望这种高耦合低聚的形式成为我以后编码的风格和习惯。

2.编写词法分析器:

1)确定C-语言的惯用词法,并在globals.c文件中定义:

一、定义关键字,关键字都是保留字:

elseifintreturnvoidwhile

1.在globals.h里面写入保留字信息

2.在scan里面选择关键字信息更改

二、专用符号:

+-*/<

<

=>

>

===!

==;

()[]{}/**/

三、其他标记是ID和NUM,通过下列正则表达式定义:

四、空格由空白、换行符和制表符组成。

当然这些是要被忽略的。

五、注释用符号/*...*/围起来。

完成了常量的定义之后,应该是如下图的形式(在GLOBALS.C文件中)。

其中,尤其需要注意,MAXRESERVED变量必须有一个值,否则在检查保留字的时候,会出现循环访问围有误。

由于我们一共有6个保留字,所以赋值为6。

2)状态转移分析:

由于C-的词法更加复杂,所以状态也比TINY多很多,我定义了11个状态。

主要因为以下标示符是由多字符组成,所以不得不为每一种生成状态记录:

字母,数字,<

=,>

=,==,!

=,/*,*/

在SCAN.C中的状态定义如下:

状态图大致如上,这个图只有大致的轮廓,限于篇幅,这里有很多自环没有画出,而且一些状态转移可能看不清楚。

其中最下面的一串状态转移,与上次试验中的下图类似:

事实上,这个正是用来判断注释部分的状态转移。

/*ooooooooooooooo*/

(注:

除了这图是从老师的文档中拷来,其他全部是自己创作,工具是VISIO)

3)DFA实现代码:

这一次采用TINY的switch-case格式,因为这种形式更加方便。

部分代码如上。

由于无论是字符还是状态都增加了很多,代码量也稍有增加。

4)加上主函数,调用词法分析器:

由于只做了词法分析器,所以只调用了getToken()

5)修改输出函数:

UTIL.C文件中的关键语句关系到词法分析的输出,因此需要重新写。

以便能够在CMD中看到词法分析的结果。

由于篇幅比较长,因此只截取部分如下:

3.至此C-的一个编译器C_XH制作好了,运行结果如下:

左图是一个C-语言的源程序。

词法分析结果如下,正确性已经得到了我的验证:

有一个有趣的测试数据:

(注释代码中含有中文)

结果表明注释中出现的中文对结果没有影响。

1.其实原本可以自己写一个简单的主函数调用Scan和一些有用的参数即可。

但是为了试验的可延续性,我保持TINY的风格,将数据变量全部储存在Globals中,util用来输出,scan进行词法分析。

不过这样做也是有代价的,就是写起来工程量比较大,于是我参考着TINY,经过多次修改错误,才算完成。

2.就词法分析器本身而言,并不一定要按照TINY的形式写,其实可以自己创造数据存储格式,自己逐单词判断,比如用hash表来实现存储,以此实现DFA。

只不过不好继续扩展。

我本想自己重新用一种方法,后来发现时间有限,就放弃了。

3.不该显示的部分显示在结果中,原因在注释的DFA状态跳转错误。

为了方便看,我故意用了中文,注释部分总是会有输出。

开始我百思不得其解,还以为是输出部分没有写好,后来才发现是跳转错误。

得到注释结束后,不应该跳往DONE,这样表示找到一个标示符,需要输出。

由于注释是完全屏蔽的,所以应该在注释结束后直接跳往start而是不是done状态。

接受到“注释部分”结束的代码

实验的代码详见运行文件。

实验工程在“CODE\完整的VS工程”目录下的C-工程里面。

因为除了SCAN有改变,还将涉及到主函数(C_XH),GLOBALS,UTIL文件,所以单独给一个文件不能运行,必须将他们连接起来,于是我将整个工程也附在文件夹中,可以在VisualStudio中运行。

输入数据,我提供了三种,在debug文件夹下,方便运行。

运行格式为:

进入dubug的路径,输入C-data1.c-即可。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 理化生

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1