900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > C++:编译原理实验之词法分析器

C++:编译原理实验之词法分析器

时间:2021-06-05 12:28:03

相关推荐

C++:编译原理实验之词法分析器

一、实验目的

学会针对DFA转换图实现相应的高级语言源程序。深刻领会状态转换图的含义,逐步理解有限自动机。掌握手工生成词法分析器的方法,了解词法分析器的内部工作原理。加强对C语言的掌握

二、实验内容

C计算机语言的编译程序的词法分析部分实现。

从左到右扫描每行该语言源程序的符号,拼成单词,换成统一的内部表示(token)送给语法分析程序。

为了简化程序的编写,有具体的要求如下:

空白符仅仅是空格、回车符、制表符。代码是自由格式。注释应放在花括号之内,并且不允许嵌套

C语言的单词

三、实验要求

要求实现编译器的以下功能:

按规则拼单词,并转换成二元式形式删除注释行删除空白符 (空格、回车符、制表符)显示源程序,在每行的前面加上行号,并且打印出每行包含的记号的二元形式发现并定位错误。

词法分析进行具体的要求:

详细给出标识符、数字、字符和字符串的状态转换图画出空白间隔符的状态转换图、换行符的状态装换图、注释(//、/* */)的状态转换图。词法分析的具体功能实现是一个函数GetToken(),每次调用都对剩余的字符串分析得到一个单词或记号识别其种类,收集该记号的符号串属性,当识别一个单词完毕,采用返回值的形式返回符号的种类,同时采用程序变量的形式提供当前识别出记号的属性值。标识符和保留字的词法构成相同,为了更好的实现,把语言的保留字建立一个表格存储,这样可以把保留字的识别放在标示符之后,用识别出的标示符对比该表格,如果存在该表格中则是保留字,否则是一般标识符。

四、算法分析

词法分析中识别下一个单词的过程,简单来看就是逐个读取字符,然后将他们拼在一起的过程。词法分析程序的作用就是在这个拼单词的过程中如何获得想爱一个有意义的单词符号,即识别出单词中别以及单词自身的值。

本实验使用C++语言,在主函数main()中利用fopen()函数打开文件test.txt ,并用fgetc()函数读入预先写好的测试样例,将其存入prog字符串。定义关键字数组keyword,用以存储常见的保留字。(只存储了部分保留字,仍可扩展)。定义全局变量line,记录当前的行数,以便于词法分析错误的时候快速定位错误位置。然后按序读取字符,依据程序设计语言的词法规则描述,识别出有意义的单词符号,即调用GetToken()函数:如果当前字符为空格、回车符、制表符时,不进行操作、读取下一个字符,返回-1;如果当前字符为‘/’时,进一步判断是‘//’,还是‘/**/’;如果当前字符为字母时,默认为标识符后,与Keyword数组进行比较,若匹配则为关键字;如果当前字符是数字,默认为整数型,若遇到‘.’,则将其修改为浮点型;其他字符使用switch()实现判断匹配,匹配不成功则返回-2,以提示词法分析错误。直至字符串为空。

代码:

#include<iostream>#include<string.h>using namespace std;//prog存放从文件读取的程序,token存放单词自身的字符串char token[8], prog[1000], ch;//columns为列数 ,sym表示单词的种别码 int p = 0, sym = 0, n = 0, line = 1; //要读取的文件名 char filename[30];/*FLE系统定义的结构体,*fpincontent是指向文件结构体的指针变量,通过fp可找到存放某个文件信息的结构变量,根据这个结构变量的信息找到该文件,实施对文件的操作 */FILE *fpincontent; //关键字 char *keyword[22] = {"if", "else", "while", "do", "main", "int", "float", "double", "return", "const", "void", "continue", "break", "char", "unsigned", "enum", "long", "switch", "case", "unsigned", "auto", "static"};void GetToken(){// 清空token数组for(n = 0; n < 8; n++) token[n] = '\0';n = 0;//读取字符 ch = prog[p++];// 删除输入的空白字符,顺便判断是否换行,增加列数while(ch == ' ' || ch == '\n' || ch == '\t') {//遇到‘\n’(回车换行) ,增加行数if (ch == '\n') { line++;} //遇到‘\t’(横向跳到下一制表符位置)、‘ ’、‘\n’对其忽略,读取下一个字符 ch = prog[p++];}//删除注释行 if (ch == '/'){ch=prog[p++];if(ch=='/') // “//” {do {ch = prog[p++];} while(ch != '\n');}sym = -1;if(ch=='*') // “/**/” {do {ch = prog[p++];} while(ch != '*');ch = prog[p++];if(ch!='/'){sym=-2;}}} //识别标识符 、关键字 else if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {sym = 22; //标识符 do {token[n++] = ch;ch = prog[p++];} while((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'));for(n = 0; n < 22; n++) //保留字 {if(strcmp(token, keyword[n]) == 0) sym = 23;}p--;}//识别数字 else if (ch >= '0' && ch <= '9'){sym = 24; //整数 do {token[n++] = ch;ch = prog[p++];} while(ch >= '0' && ch <= '9');if(ch=='.') //小数 {do {token[n++] = ch;ch = prog[p++];} while(ch >= '0' && ch <= '9');sym = 25;}p--;}else {switch(ch) {case '+': sym = 0; token[0] = ch; break; //加 case '-': sym = 1; token[0] = ch; break; //减 case '*': sym = 2; token[0] = ch; break; //乘 case '/': sym = 3; token[0] = ch; break; //除 case ';': sym = 4; token[0] = ch; break; //语句结束 case '(': sym = 5; token[0] = ch; break;case ')': sym = 6; token[0] = ch; break;case '\'': sym = 7; token[0] = ch; break;case '\"': sym = 8; token[0] = ch; break;case '=': {sym = 9; //等于号 token[0] = ch;ch = prog[p++];if(ch == '=') {sym = 10; //判断是否相等 token[1] = ch;}else {p--;}break;}case '<': {sym = 11; //小于号 token[0] = ch;ch = prog[p++];if(ch == '=') {sym = 12;//小于等于 token[1] = ch;}else {p--;}break;}case '>': { sym = 13; //大于号 token[0] = ch;ch = prog[p++];if(ch == '=') //大于等于 {sym = 14;token[1] = ch;}else {p--;}break;}case '!': {token[0] = ch;ch = prog[p++];if(ch == '=') {sym = 15; //不等于 token[1] = ch;}else {p--;sym = -2;}break;}case '&': {token[0] = ch;ch = prog[p++];if(ch == '&') {sym = 16; //且 token[1] = ch;}else {p--;sym = -2;}break;}case '|': {token[0] = ch;ch = prog[p++];if(ch == '|') {sym = 17; //或 token[1] = ch;}else {p--;sym = -2;}break;}case '#': sym = 18; token[0] = ch; break;case '[': sym = 19; token[0] = ch; break;case ']': sym = 20; token[0] = ch; break;case ',': sym = 21; token[0] = ch; break;case '{': sym = 26; token[0] = ch; break;case '}': sym = 27; token[0] = ch; break;default: {sym = -2;break;}}}}int main(){p = 0;cout<< "read something from :" << endl<<" ";for(;;){cin>>filename;//用 fopen函数打开文件,“r”为只读模式fpincontent = fopen(filename,"r"); if(fpincontent!=NULL)break;elsecout<<"文件路径错误,请输入源文件名:"<<endl<<"";}// 将文件读取到prog数组里cout<<"源程序:"<<endl; do{//fgetc()读取一个字符ch = fgetc(fpincontent); prog[p++] = ch;cout<<ch;}while(ch != EOF);cout<<endl<<endl; p = 0;// 按规则拼单词,并转换成二元式形式do{/*每次调用都对剩余的字符串分析得到一个单词或记号识别其种类,收集该记号的符号串属性,当识别一个单词完毕,采用返回值的形式返回符号的种类,同时采用程序变量的形式提供当前识别出记号的属性值。*/GetToken();switch(sym) {case -1: break;case -2: //返回值为-1、-2时,跳出switch {cout<<"词法分析出错!,错误位于第"<<line<<"行"<<endl;break;}default: cout<<"第"<<line<<"行,<"<<sym<<" , "<<token<<">"<<endl; }}while(prog[p] != EOF);cout<<endl<<endl; p=0;cout<<"修改后:"<<endl;do{ GetToken();cout<<token;} while(prog[p]!=EOF);return 0;}

运行结果:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。