编译原理词法分析程序设计
实验内容
1.对源程序进行理解,从PL0文档中抽取出词法部分的代码,单独作为一个程序,变成一个词法程序,用visual6.0或者Dev c++进行编译,编译成为可执行文件;
词法分析部分的代码如下:
#include<fstream>
#include<cstring>
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<map>
#include<bits/stdc++.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
using namespace std;
map<string,string> word;//应用map数据结构形成一个string->string的对应
std::map<string,string>::iterator it;//用来遍历整个对应关系的迭代器
void map_init(){//对应关系进行初始化
word["begin"]="beginsym";
word["call"]="callsym";
word["const"]="constsym";
word["do"]="dosym";
word["end"]="endsym";
word["if"]="ifsym";
word["odd"]="oddsym";
word["procedure"]="proceduresym";
word["read"]="readsym";
word["then"]="thensym";
word["var"]="varsym";
word["while"]="whilesym";
word["write"]="writesym";
word["+"]="plus";
word["-"]="minus";
word["*"]="times";
word["/"]="slash";
word["="]="eql";
word["<>"]="neq";
word["<"]="lss";
word["<="]="leq";
word[">"]="gtr";
word[">="]="geq";
word[":="]="becomes";
word[":"]="colon";
word["("]="lparen";
word[")"]="rparen";
word["["]="lmiddlebracket";
word["]"]="rmiddlebracket";
word[","]="comma";
word[";"]="semicolon";
word["."]="period";
word["!"]="exclamationmark";
word["\""]="doublequotation";
word["\'"]="singlequotes";
word["?"]="questionmark";
word["^"]="power";
word["#"]="poundsign";
}
struct node{
string id;
string s;
}aa[10000];
int main(){
map_init();//初始化
char ch;
char a;
int len = 0;
string word1;//string变量识别单词
string str;//string变量进行字符识别
ifstream infile("D:\\源文件.txt");//文件输入流,文件路径
ofstream outfile("D:\\二元组结果.txt");//文件输出流
ostringstream buf;
while(buf&&infile.get(ch)) buf.put(ch);//将文件中的字符读出来
str= buf.str();//将得到的字符储存到string类型变量中
int csize=str.length();
for(int i=0;i<csize;i++){//对整个字符串进行遍历
while(str[i]==' '||str[i]=='\n') i++;//若最开始为空格或换行符,则将指针的位置往后移
if(isalpha(str[i])){//对标识符和基本字进行识别,调用库函数isalpha()
word1=str[i++];
while(isalpha(str[i])||isdigit(str[i])){
word1+=str[i++];
}
it=word.find(word1);
if(it!=word.end()){//判断是不是基本字,若为基本字则进行输出
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
aa[len].id =word[word1];
aa[len++ ].s = word1;
}
else{//否则直接输出
cout<<"(ident"<<","<<word1<<")"<<endl;
aa[len].id = "ident";
aa[len++].s = word1;
}
i--;
}
else if(isdigit(str[i])){//判断是不是常数,调用库函数isdigit()
word1=str[i++];
while(isdigit(str[i])){
word1+=str[i++];
}
if(isalpha(str[i])){
cout<<"error!"<<endl;
break;
}
else{
cout<<"(number"<<","<<word1<<")"<<endl;
aa[len].id = "number";
aa[len++].s = word1;
}
i--;
}else if(str[i]=='<'){//对<,<=分别进行判断
word1=str[i++];
if(str[i]=='>'){
word1+=str[i];
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
aa[len].id = word[word1];
aa[len++].s = word1;
}else if(str[i]=='='){
word1+=str[i];
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
aa[len].id = word[word1];
aa[len++].s = word1;
}else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
aa[len].id = word[word1];
aa[len++].s = word1;
}else{
cout<<"error!"<<endl;
break;
}
i--;
}else if(str[i]=='>'){//对>,>=分别进行判断
word1=str[i++];
if(str[i]=='='){
word1+=str[i];
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
aa[len].id = word[word1];
aa[len++].s = word1;
}else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
aa[len].id = word[word1];
aa[len++].s = word1;
}else{
cout<<"error!"<<endl;
break;
}
i--;
}else if(str[i]==':'){//对:=进行判断
word1=str[i++];
if(str[i]=='='){
word1+=str[i];
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
aa[len].id = word[word1];
aa[len++].s = word1;
}else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
aa[len].id = word[word1];
aa[len++].s = word1;
}else{
cout<<"error!"<<endl;
break;
}
i--;
}else{//对其他的基本字依次进行判断
word1=str[i];
it=word.find(word1);
if(it!=word.end()){
cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
aa[len].id = word[word1];
aa[len++].s = word1;
}else{
cout<<"error!"<<endl;
break;
}
}
}
//输出流,输出到对应的结果文件中
if (outfile.is_open())
{
for(int i = 0 ;i < len ;i ++){
outfile <<"("<<aa[i].id<<","<<aa[i].s<<")"<<'\n';
}
outfile.close();
}
infile.close();
return 0;
}
2.对输出的文件进行检验,用PL0验证源程序作为词法验证输入源程序,对其进行读入;
我这里读取的是一个很长的pl0的程序代码,里面包含各种标识符、关键字、界符、运算符,常数等,比较有验证性。
3.单词序列二元组结果的显示并保存成结构文件;
以二元组的格式保存在结果文件中。
我最开始做这个实验的时候一头雾水,这是给我指路的文章,非常感谢,里面对词法分析的设计思想、算法流程等都有详细的说明。https://blog.csdn.net/Flamewaker/article/details/82902906?utm_source=app
但是经过实践发现了两个小问题:
1.我的被识别文件里面的字符种类太多,所以在链接中这篇文章里的代码基础上添加了一些自负的对应关系;
2.链接中这篇文章里的代码中只有输入流操作代码,缺少输出流的操作代码,导致程序可以运行,但结果文件中没有输出内容。添加对输出流的操作后,运行结果和结果文件中都有了正确的输出内容。