【编译原理】实验:词法分析器的实现与分析(本校实验平台的题)

2023-11-24 11:30

本文主要是介绍【编译原理】实验:词法分析器的实现与分析(本校实验平台的题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

实验题目:实现词法分析器

注:本题解参考文章在最后列出(部分代码引用的是那里面的);实现语言为:C++

注:本文只提供一个思路,作为学习过程中的一个参考,实现词法分析器有很多方法,本文只是其中一种,若想用本文代码提交作业请多改,不然查重率过不了。
【问题描述】

【文法定义】:

<标识符>::=<字母>{<字母>|<数字>} //标识符和关键字都不区分大小写,比如if和IF均为关键字,不允许出现与关键字相同的标识符
<字母>::=_|a|...|z|A|...|Z
<数字>::=0|1|...|9
<整数>::=[+|-]<无符号整数>
<无符号整数>::=<数字>{<数字>}
<字符>::=‘<加法运算符>’|’<乘法运算符>’|’<字母>’|’<数字>’
<加法运算符>::=+|-
<乘法运算符>::=*|/
<字符串>::="{十进制编码为32,33,35-126的ASCII字符}" //字符串中要求至少有一个字符

ASCII码

【问题描述】
请根据给定的文法设计并实现词法分析程序,从源程序中识别出单词,记录其单词类别和单词值,输入输出及处理要求如下:
(1)数据结构和与语法分析程序的接口请自行定义;类别码需按下表格式统一定义;
(2)为了方便进行自动评测,输入的被编译源文件统一命名为testfile.txt(注意不要写错文件名);输出的结果文件统一命名为output.txt(注意不要写错文件名),结果文件中每行按如下方式组织:
单词类别码 单词的字符/字符串形式(中间仅用一个空格间隔)

单词的类别码请统一按如下形式定义:
类别码

【输入形式】testfile.txt中的符合文法要求的测试程序。
【输出形式】要求将词法分析结果输出至output.txt中。

【样例输入】

const int const1 = 1, const2 = -100;
const char const3 = ‘_’;
int change1;
char change3;
int gets1(int var1,int var2){
change1 = var1 + var2;
return (change1);
}
void main(){
printf(“Hello World”);
printf(gets1(10, 20));
}

【样例输出】

CONSTTK const
INTTK int
IDENFR const1
ASSIGN =
INTCON 1
COMMA ,
IDENFR const2
ASSIGN =
MINU -
INTCON 100
SEMICN ;
CONSTTK const
CHARTK char
IDENFR const3
ASSIGN =
CHARCON _
SEMICN ;
INTTK int
IDENFR change1
SEMICN ;
CHARTK char
IDENFR change3
SEMICN ;
INTTK int
IDENFR gets1
LPARENT (
INTTK int
IDENFR var1
COMMA ,
INTTK int
IDENFR var2
RPARENT )
LBRACE {
IDENFR change1
ASSIGN =
IDENFR var1
PLUS +
IDENFR var2
SEMICN ;
RETURNTK return
LPARENT (
IDENFR change1
RPARENT )
SEMICN ;
RBRACE }
VOIDTK void
MAINTK main
LPARENT (
RPARENT )
LBRACE {
PRINTFTK printf
LPARENT (
STRCON Hello World
RPARENT )
SEMICN ;
PRINTFTK printf
LPARENT (
IDENFR gets1
LPARENT (
INTCON 10
COMMA ,
INTCON 20
RPARENT )
RPARENT )
SEMICN ;
RBRACE }

以下是代码思路:
把读入的文件内容全存在ScanBuffer[1000]这个字符串数组里面,里面完整存,空格回车这些都存了。然后用char变量 ch 一个个的读出来,随后判断读出来的是什么类型,再进行分析归类,然后输出到文件里面。

1.代码部分注释很多,不清楚的地方可以仔细看一下注释;
2.有不懂的地方建议自行搜索相关知识点;
3.代码里有些地方是为了测试输出写的,都已经注释掉了;
4.代码里有没用到的变量比如show_strToken变量,是为了debug时候查看全局变量strToken而设置的(全局变量string类型在debug时候没法看到里面的值);
5.代码能够直接在实验平台上运行通过。

#include <iostream>
#include <fstream>
#include<string>
using namespace std;
#define NOT_Found 404 //自己定义的数字404,因为用到它的地方那个数字不可能是404//全局变量
char ch;//用来存字符
string strToken = "";//当前字符串
string ScanBuffer[1000];//我开了1000来存,里面存放文件里面所有内容,文件以EOF结尾,叫缓存区
int row = 0;
int col = 0; //缓存区的行与列
int endrow;string Reserved_words[]={"const","int","char","void","main","if","else","do","while","for","scanf","printf","return"};//保留字,进来字符串的时候验证一下
string Category_code[] ={"CONSTTK","INTTK","CHARTK","VOIDTK","MAINTK","IFTK","ELSETK","DOTK","WHILETK","FORTK","SCANFTK","PRINTFTK","RETURNTK"};//保留字对应的类别码,要与上面一一对应,这样可以对应下标//声明全局函数
void Input();//子程序过程,将源代码输入进扫描缓冲区
void GetChar();//子过程程序,将下一输入字符读到ch中,搜索指示器前移一字符位置
void GetDel();//子程序过程,检查ch中的字符是否为分隔符(空格、回车之类的)。若是,则调用GetChar直至ch中进入一个非分隔符(delimiters->分隔符)
void Concat();//子程序过程,,将ch中的字符连接到strToken之后
bool IsLetter();//布尔函数过程,判断ch中的字符是否为字母
bool IsDigit();//布尔函数构成,判断ch中的字符是否为数字
int Reserve();//整型函数过程,对strToken中的字符串查找保留字表,若它是一个保留字则返回它的index下标,否则返回NOT_Found(404不是保留字的编码)
void Retract();//子程序过程,将搜索指示器回调一个字符位置,将ch置为空白字符
int GetNumFromStr(string s);//将数字字符串返回原来int型数字,存起来输出用(本文法中的数字只有int型的呢)
int Str_Length(string str);//返回字符串长度,用来判断在字符串内的‘a’、‘2’为char类型
void Lexical_analysis();//词法分析函数实现//函数实现
void Input(){  //空格回车都在里面了int i=0;char c;//输入流中的当前字符fstream in;in.open("testfile5.txt",ios::in);while(in.peek()!=EOF){c=in.get();ScanBuffer[i].push_back(c);if(c=='\n') i++;}endrow=--i;//测试,看能不能完整输入:
/*		cout <<"endrow =="<<endrow<<endl; //7行代码,endrow=7;int l = 100;for(int k=0;k<l;k++){cout<<ScanBuffer[k]<<endl;}
*/
}
void GetChar(){ch=ScanBuffer[row][col];col++;
}
void GetDel(){while(ch=='\n'){row++;col=0;GetChar();}while(ch==' '||ch=='\t')GetChar();
}
void Concat(){strToken.push_back(ch);
}
bool IsLetter(){ //注意本文法中的字母,还包括了下划线if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch=='_'))return true;return false;
}
bool IsDigit(){if(ch >='0'&&ch<='9')return true;return false;
}int Reserve(){ //找保留字表,int i;for(i=0;i<13;i++)if(Reserved_words[i]==strToken)return i;return NOT_Found; //循环之后发现不是保留字
}void Retract(){//回退一个col--;ch='\0';
}
int GetNumFromStr(string s){int ans = 0;for(int i=0;i<s.size();i++) ans = ans * 10+ s[i]-'0';return ans;
}
/*
bool IsAllDigit(){int l = strToken.length();bool flag=true;for(int k =0;k<l;k++){if(strToken[k]>='0'&&strToken[k]<='9'){}//flag 保持trueelse{flag = false;break;}}return flag;
}
*/
int Str_Length(string str){return str.length();
}void Lexical_analysis()
{ofstream out("output.txt");//输出到文件,之后把cout全变成out就行了。while(row!=endrow+1){ //别超行读ScanBufferstring Category_code_num;//要输出的类别码int store_number;//用IsAllDigit()看一下,纯数字输入的话把用数字存在这里面然后输出。//	strToken="";
//因为debug不能查看string全局变量,所以需要一个局部变量show_strToken转接一下string show_strToken=strToken;GetChar();GetDel();//得到一个ch合法输入(没有空格、回车的ch)if(IsLetter()){  //字母或下划线开头的进这里while(IsLetter()||IsDigit()){Concat();GetChar();}
//此处show_strToken=strToken;Retract();//上面循环里取多了还回去int isfind; //接收保留字表的下标isfind=Reserve();if(isfind != NOT_Found){ //在表里面找到保留字啦!Category_code_num = Category_code[isfind];out<<Category_code_num<<" "<<strToken<<endl;strToken="";//输出之后就清零!!}else{ //不是保留字,那就是标识符咯(字符串有自己的判定语句,在下面)out<<"IDENFR "<<strToken<<endl;strToken="";//用完之后就清零!!}}else if(IsDigit()){ //数字开头的进这里while(IsDigit()){Concat();GetChar();}
//此处show_strToken=strToken;Retract();//上面循环里取多了还回去//把数字存起来,存进变量:store_numberstore_number = GetNumFromStr(strToken);strToken="";//用完之后就清零!!out<<"INTCON "<<store_number<<endl;}//其他符号的进下面else if(ch=='+')out<<"PLUS "<<ch<<endl;else if(ch=='-')out<<"MINU "<<ch<<endl;else if(ch=='*')out<<"MULT "<<ch<<endl;else if(ch=='/')out<<"DIV "<<ch<<endl;else if(ch=='<'){ //判断一下是<还是<=,要是下一个字符不是=,拿了的给人还回去,用Retract()函数GetChar();if(ch=='=')out<<"LEQ "<<"<="<<endl;else{Retract();//把人家还回去out<<"LSS "<<"<"<<endl;}}else if(ch=='>'){GetChar();if(ch=='=')out<<"GEQ >="<<endl;else{Retract();out<<"GRE >"<<endl;}}else if(ch=='='){//同上,看一下是不是俩等号‘==’GetChar();if(ch=='='){out<<"EQL =="<<endl;}else{Retract();//还回去out<<"ASSIGN ="<<endl;}}else if(ch=='!'){//由于都是合法输入(测试样例里面),!只在字符串里面出现,所以此处出现的得是!=GetChar();if(ch == '='){out<<"NEQ !="<<endl;}else{Retract();//还回去并且无操作}}else if(ch==';')out<<"SEMICN ;"<<endl;else if(ch==',')out<<"COMMA ,"<<endl;else if(ch=='(')out<<"LPARENT ("<<endl;else if(ch==')')out<<"RPARENT )"<<endl;else if(ch=='[')out<<"LBRACK ["<<endl;else if(ch==']')out<<"RBRACK ]"<<endl;else if(ch=='{')out<<"LBRACE {"<<endl;else if(ch=='}')out<<"RBRACE }"<<endl;else if(int(ch)==34||int(ch)==39){//判断字符串 ps:根据对本题的输入输出案例分析,双引号单引号只用来识别字符串用,不输出,不属于字符类别也不属于字符串类别//用ASCII码来比较,中文的双引号是-95,英文的双引号是34,单引号是39,已测试过,可行。GetChar();while(int(ch)!=34&&int(ch)!=39){Concat();GetChar();
//此处show_strToken=strToken;}//出循环的时候,ch等于回引号,不需要还回去;字符串收集结束。int length = Str_Length(strToken);if(length ==1){ //说明是单引号里面的字符型out<<"CHARCON "<<strToken<<endl;}else{out<<"STRCON "<<strToken<<endl;}strToken="";//输出之后就清零!!}}//while end}//function endint main()
{Input();Lexical_analysis();return 0;
}

测试样例输出与标准答案比对:
用word2010的审阅–比较功能:
word比对
结果:
成功

主要的参考文档:【编译原理】实验一 词法分析器设计与实现

由以上文法定义可以看出,比实际文法要简单,只有整数型变量,且-100分开判定,并不是整数-100而是负号和整数100,所以此词法分析器只做学习使用。

在实验平台上运行时选择正确的编译器很重要,本人因为选了C编译器编译不过一度自闭,直到求助的某位美女告诉我可能是我选错编译器了,才破了案。

over。

这篇关于【编译原理】实验:词法分析器的实现与分析(本校实验平台的题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/421857

相关文章

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time