什么是词法分析器
简单来说,词法分析器,就是将用户输入的代码(一个个字符)通过某种方式拼接成有意义的一个个字符片段,什么是有意义呢?不同语言的定义不太相同,但大体来说,有意义表示这五类:关键字、标识符、数字串、运算符和分隔符、空白字符。拼接的方式多种多样,可以使用DFA也可以单纯的进行字符的拼接。
大致思路
这里就使用字符的拼接,由于这个程序比较简单,就每次判断下一个字符是字母、数字或者下划线或者是其他字符,比如第一个字符是字母数字或下划线,那就一直向下加,直至加到不是字母数字或下划线,然后一直加不是字母数字或下划线。虽然这种思路有一点点小的bug,但对付大部分数据还是可以的。
实验具体内容及要求
实验目的
设计、编制并调试一个简单语言CP(Compiler Principle)的词法分析程序,加深对词法分析原理的理解。
实验内容
1. CP语言的词法
(1) 关键词: begin end if then else for while do and or not
注意:所有关键词都是小写的。
(2) 标识符ID,与标准C语言一致,即:以下划线或字母开头的字母数字下划线组成的符号串。
(3)无符号整数NUM:数字串
(4)运算符和分界符: +、-、*、/、>、<、=、:=、>=、<=、<>、++、--、(、)、; 、 #
注意::=表示赋值运算符、#表示注释开始的部分,;表示语句结束,<>表示不等关系
(5) 空白符包括空格、制表符和换行符,用于分割ID、NUM、运算符、分界符和关键词,词法分析阶段要忽略空白符。
2. 说明
(1)CP语言是大小写敏感语言;
(2)字母为a-zA-Z,数字为0-9;
(3)学有余力同学可以在上述词法要求基础上进行扩充和改造;
(4)每行代码中从#开始的部分为注释部分(参考python语法)
3. 设计要求
(1) 给出各类单词符号的分类编码(可以根据自己程序的需要来给各种类别单词编码,给每个词法单位一个编码,也可以给一个类别里所有符号都编同一个编码)。
(2) 词法分析程序应该能发现输入串中的错误
(3) 词法分析作为单独一遍,将词法分析程序输出的二元式序列保存为中间文件形式【也可以在屏幕窗口直接输出】
实验要求
1. 写出程序框图、设计过程、主要数据结构等。
2.写出程序源代码,并调试通过,输出实验结果。
3.完成实验报告及总结【按实验教学的PDF文件要求撰写和提交】。
注意:实现语言不限,用你最熟悉或最感兴趣的语言来实现即可。
源代码
首先给关键字进行以下标号
其中1.cpp为词法分析器实现代码,yuan.txt为需要处理的源代码,out.txt为处理输出结果
#include<bits/stdc++.h>
using namespace std;
string str; //源程序
int flag=0; //注释
map<string,int> mmap,guan; //存放所有关键字和出现的关键字
set<string> vec; //错误字符
set<string> v; //无符号整数
set<string> biao_zhi; //标识符
string word[]={
"",
"#",
"begin",
"end",
"if",
"then",
"else",
"for",
"while",
"do",
"and",
"or",
"not",
"+",
"-",
"*",
"/",
">",
"<",
"=",
":=",
">=",
"<=",
"<>",
"++",
"--",
"(",
")",
";" };
int check(char c){ //检查是否为数字 字母 下划线
if(c=='_'||(c>='0'&&c<='9')||((c>='a'&&c<='z')||(c>='A'&&c<='Z')))
return 1;
return -1;
}
void init(){ //初始化map(单词符号和种别码一一对应关系)
for(int q=1;q<=28;q++){
mmap.insert(map<string,int>::value_type(word[q],q));
}
}
void yu_chu_li(){ //预处理,去掉空白符
string s="";
for(int q=0;q<str.length();q++){
if(str[q]=='\n'||str[q]=='\t')
s+=" ";
else
s+=str[q];
}
str.assign(s);
}
bool biao(string s){ //标识符匹配
bool flag=true;
if(s[0]=='-'||((s[0]>='a'&&s[0]<='z')||(s[0]>='A'&&s[0]<='Z'))){
for(int q=1;q<s.length();q++){
if(s[q]=='-'||((s[q]>='a'&&s[q]<='z')||(s[q]>='A'&&s[q]<='Z'))){}
else{
flag=false;
break;
}
}
}
else flag=false;
return flag;
}
bool dfa(string s){ //无符号整数匹配
bool flag=true;
for(int q=0;q<s.length();q++){
if(s[q]>='0'&&s[q]<='9') {}
else{
flag=false;
break;
}
}
return flag;
}
int main(){
guan.clear();
vec.clear();
str="";
ofstream out("out.txt");
ifstream data("yuan.txt");
string line;
while(!data.eof()){
getline(data,line);
for(int q=0;q<line.length();q++){
if(line[q]=='#') { guan.insert(map<string,int>::value_type("#",mmap["#"])); break; } //去掉注释并添加#关键字
str+=line[q];
}
}
yu_chu_li();
init();
string s1="",s2="";
int in=1; //为1识别关键字 -1其他
str+=" ";
for(int q=0;q<str.length();q++){
if(str[q]==' '){
goto part;
}
if(s1.length()==0){
if(s2.length()!=0){
in=check(s2[0]);
s1+=s2[0];
s2="";
}
else
in=check(str[q]);
}
if(check(str[q])==in){
s1+=str[q];
}
else{
s2+=str[q];
}
part:
if(in!=check(str[q])){
if(s1.length()>0){
if(mmap[s1]!=0){ //是否为关键字
guan.insert(map<string,int>::value_type(s1,mmap[s1]));
}
else if(biao(s1)){ //是否为标识符
biao_zhi.insert(s1);
}
else if(dfa(s1)){ //是否为无符号整型常量
v.insert(s1);
}
else{ //错误字符
vec.insert(s1);
}
}
s1="";
}
}
cout<<"success"<<endl;
if(vec.size()!=0) out<<vec.size()<<" errors"<<endl;
out<<"------关键字------"<<endl;
for(map<string,int>::iterator it=guan.begin();it!=guan.end();it++){ //关键字输出
out<<"<"<<it->first<<","<<it->second<<">"<<endl;
}
out<<"------标识符------"<<endl;
for(set<string>::iterator it=biao_zhi.begin();it!=biao_zhi.end();it++){ //标识符输出
out<<"<标识符,"<<*it<<">"<<endl;
}
out<<"------无符号整型常量------"<<endl;
for(set<string>::iterator it=v.begin();it!=v.end();it++){ //无符号整数输出
out<<"<无符号整型常量,"<<*it<<">"<<endl;
}
out<<"------错误------"<<endl;
for(set<string>::iterator it=vec.begin();it!=vec.end();it++){ //错误输出
out<<"<错误,"<<*it<<">"<<endl;
}
out.close();
data.close();
return 0;
}