【SEU&SE】编译原理 - 词法分析器实验报告
README本篇文章仅供参考,严禁直接抄袭!实验目的
【SEU&SE】编译原理 - 词法分析器实验报告
README
本篇文章仅供参考,严禁直接抄袭!
一、 实验目的
- 巩固有限自动机理论与正规文法、正规式三者之间的关系和相关的知识点;
- 了解词法分析器具体的实现方法及所用算法的原理;
- 编写相关的词法分析程序实现对C++语言程序文件的部分词法分析;
二、 实验环境
1. 开发环境:
- OS:macOS Sierra 10.12.5
- 语言:C++
- 编译器:Xcode 8.3.3
- 作图:ProccessOn
2. 运行环境
- Windows、macOS或者Linux;
三、 实验内容
1. 主要内容
编写代码实现一个词法分析程序,可以对C++语言中的 .cpp 或者 .h 文件中的部分单词,如关键字、操作运算符、界符、标识符、字符串、整数、浮点数、注释等进行识别并提取出相关的单词,形成token序列,并对一些可能出现的错误进行相应的处理。
2. 主要功能
- 读写文件:该词法分析器可以读取指定的文件,进行词法分析过程,并将得到的词法分析的token流在控制台中打印出来并写到词法分析程序根目录下的输出文件中;
- 程序预处理:删除无用的空白字符、回车字符以及其他非实质性字符,删除两种形式的注释;
- 词法分析:该词法分析器逐个扫描读进的文件字符流,然后进行相应的词法分析。通过扫描,找出相应的单词以及其相应的种别码,形成token序列,为输出到语法分析器中做准备;
- 错误报告:报告词法检查中遇到的错误以及错误出现的行数,错误包括浮点数小数点错误、数字中混杂字母、字符位数过多、字符丢失单引号、字符串丢失双引号、注释格式不正确、标识符命名错误等等;
3. 种别码
| 单词符号 | 种别码 |
|---|---|
| main | 1 |
| if | 2 |
| else | 3 |
| while | 4 |
| do | 5 |
| for | 6 |
| int | 7 |
| double | 8 |
| float | 9 |
| char | 10 |
| long | 11 |
| short | 12 |
| enum | 13 |
| static | 14 |
| bool | 15 |
| void | 16 |
| switch | 17 |
| case | 18 |
| break | 19 |
| continue | 20 |
| signed | 21 |
| unsigned | 22 |
| return | 23 |
| default | 24 |
| const | 25 |
| union | 26 |
| struct | 27 |
| auto | 28 |
| include | 29 |
| define | 30 |
| class | 31 |
| virtual | 32 |
| friend | 33 |
| public | 34 |
| private | 35 |
| protected | 36 |
| this | 37 |
| false | 38 |
| true | 39 |
| try | 40 |
| catch | 41 |
| throw | 42 |
| goto | 43 |
| using | 44 |
| template | 45 |
| new | 46 |
| namespace | 47 |
| operator | 48 |
| register | 49 |
| inline | 50 |
| + | 51 |
| - | 52 |
| ++ | 53 |
| – | 54 |
| * | 55 |
| / | 56 |
| % | 57 |
| < | 58 |
| <= | 59 |
| > | 60 |
| >= | 61 |
| = | 62 |
| == | 63 |
| != | 64 |
| << | 65 |
| >> | 66 |
| && | 67 |
|| |
68 |
| ! | 69 |
| ^ | 70 |
| , | 71 |
| ; | 72 |
| . | 73 |
| { | 74 |
| } | 75 |
| [ | 76 |
| ] | 77 |
| ( | 78 |
| ) | 79 |
| # | 80 |
| \ | 81 |
| ? | 82 |
| 标识符表 | 83 |
| 字符常量表 | 84 |
| 字符串常量表 | 85 |
| 整数常量表 | 86 |
| 浮点数常量表 | 87 |
其中,1~50为基本关键字、51~70为操作运算符、71~82为界符。
4. DFA


5. 设计思路
- 打开源文件,读取文件内容,直至遇上‘$’文件结束符,然后读取结束。
- 对读取的文件进行预处理,从头到尾进行扫描,去除 // 和 /* */ 的内容,以及一些无用的、影响程序执行的符号如换行符、回车符、制表符等。
- 接下来对源文件从头到尾进行扫描。从头开始扫描,这个时候分析程序首先去除开头的所有空格,直到扫描出的字符不是空格。然后判断当前字符是不是字母,若是则进行标识符和保留字的识别;若这个字符是数字,则进行数字的判断;若是界符则直接收集;若是操作运算符则进行操作运算符的判断;若是单引号则进行字符判断;若是双引号则进行字符串判断。若是将所有可能都走了一遍还是没有知道它是谁,则认定为错误符号,输出该错误符号,然后结束。每次成功识别了一个单词后,单词都会存在token[ ]中。然后确定这个单词的种别码,最后进行下一个单词的识别。
- 主控程序主要负责对每次识别的种别码syn进行判断,对于不同的种别做出不同的反应。如对于识别符则将其插入标识符表中;对于保留字则输出该保留字的种别码等等。直至遇到 syn = 0 ,程序结束。
6. 主要数据结构
| 名称 | 类型 | 描述 |
|---|---|---|
| reserveWords | const static string* |
存放C++部分关键字 |
| operators | const static string* |
存放C++部分操作运算符 |
| delimiters | const static string* |
存放C++部分界符 |
| identitierTable | vector<string> |
存放标识符 |
| charTable | vector<string> |
存放字符常量 |
| stringTable | vector<int> |
存放字符串常量 |
| intTable | vector<int> |
存放整数常量 |
| floatTable | vector<float> |
存放浮点数常量 |
7. 主要算法
RE to NFA to DFA to DFA’
四、 实验结果
程序1:
include <iostream>
/*
让n+1并返回
*/
int inc(int n)
{
return ++n;
}
int main()
{
//声明三个变量
int x = inc(0);
string y = "test!";
float z = 6.66;
return 0;
}
输出1:
<include , 29> ----- 关键字
<< , 58> ----- 操作运算符
<iostream , 83> ----- 标识符
<> , 60> ----- 操作运算符
<int , 7> ----- 关键字
<inc , 83> ----- 标识符
<( , 78> ----- 界符
<int , 7> ----- 关键字
<n , 83> ----- 标识符
<) , 79> ----- 界符
<{ , 74> ----- 界符
<return , 23> ----- 关键字
<++ , 53> ----- 操作运算符
<n , 83> ----- 标识符
<; , 72> ----- 界符
<} , 75> ----- 界符
<int , 7> ----- 关键字
五、 遇到的问题及解决方法
问题:程序预处理之后进行词法分析的时候,一直提示“错误的数字”等错误。
解决方法:经过排查之后发现是程序在预处理的时候将所有空格都删除了,导致所有词素都连在了一起,所以一直报错。修改预处理部分使得空格不会被删除之后发现程序即可正常运行了。
六、 实验感想
在本次实验中,我使用C++实现了C++语言的子集的词法分析器。通过本次实验,我对词法分析的流程有了更为清晰的认识,也对课本上所学的知识有了更为深刻的理解,同时也懂得了许多在课堂上没有学到的关于编译的新知识。但总体来看本次完成的词法分析器还是比较低级的,本想可以做到提示错误并作出相应的错误处理,可是写到一半的时候才发现预处理的时候已经吧所有换行符删除了,所以这部分功能无法实现,以后若有机会的话我会将本次实验结果加以改善!
更多推荐


所有评论(0)