一、实验目的
通过本实验使学生进一步熟悉和掌握程序设计语言的词法分析程序的设计原理及相关的设计技术,如何针对确定的有限状态自动机进行编程序;熟悉和掌握程序设计语言的语法分析程序的设计原理、熟悉和掌握算符优先分析方法。
二、实验要求
本实验要求:①要求能熟练使用C++程序设计语言编程;②在上机之前要有详细的设计报告(预习报告);③要编写出完成相应任务的程序并在计算机上准确地运行;④实验结束后要写出上机实验报告。
三、实验题目
针对下面文法G(S):
S→ v = E
E→E+E│E-E│E*E│E/E│(E)│ v │ i
其中,v为标识符,i为整型或实型数。要求完成
① 使用自动机技术实现一个词法分析程序;
② 使用算符优先分析方法实现其语法分析程序;
③ 在语法分析过程中同时完成常量表达式的计算。
代码一:词法分析
#include
using namespace std;
char opword[]="+-*/";
char eword[]="=";
char lbordword[]="(";
char rbordword[]=")";
FILE *fin,*fout;
int main()
{
queue<int> q;
//新的一行 0 标识符 1 等于号 2 运算符 3 左括号 4 右括号 5 数字 6
char ch,token[40];
int es=0,j,state,brp;
if((fin=fopen("I1.txt","r"))==NULL)
{
printf("\n打开词法分析输入文件出错!\n");
return(1);
}
if((fout=fopen("O1.txt","w"))==NULL)
{
printf("\n创建词法分析输出文件出错!\n");
return(2);
}
ch=getc(fin);
string v;//标识符
string e;//表达式
map<string,string> map1;
while(ch!=EOF)
{
while(ch==' '||ch=='\n'||ch=='\t'){
//fprintf(fout,"\n");
q.push(0);
ch=getc(fin);
v="";
}
if(isalpha(ch)||ch=='_')
{
token[0]=ch;
j=1;
ch=getc(fin);
while(isalnum(ch)||ch=='_')
{
token[j++]=ch;
ch=getc(fin);
}
token[j]='\0';
fprintf(fout,"(%s,%s)\n","标识符",token);
q.push(1);
v = token;
}
else if(isdigit(ch)||ch=='.')
{
j=0;
state=0;
brp=1;
while(brp)
{
switch(state)
{
case 0:
if(ch=='.')
{
token[j++]=ch;
state=1;
}
else if(isdigit(ch))
{
token[j++]=ch;
state=6;
}
ch=getc(fin);
break;
case 1:
if(isdigit(ch))
{
token[j++]=ch;
ch=getc(fin);
state=2;
}
else brp=0;
break;
case 2:
while(isdigit(ch))
{
token[j++]=ch;
ch=getc(fin);
}
if(ch=='E'||ch=='e')
{
token[j++]=ch;
ch=getc(fin);
state=3;
}
else brp=0;
break;
case 3:
if(ch=='+'||ch=='-')
{
token[j++]=ch;
state=4;
ch=getc(fin);
}
else if(isdigit(ch))
{
token[j++]=ch;
state=5;
ch=getc(fin);
}
else brp=0;
break;
case 4:
if(isdigit(ch))
{
token[j++]=ch;
ch=getc(fin);
state=5;
}
else brp=0;
break;
case 5:
brp=0;
break;
case 6:
while(isdigit(ch))
{
token[j++]=ch;
ch=getc(fin);
}
if(ch=='.')
{
token[j++]=ch;
ch=getc(fin);
state=1;
}
else brp=0;
break;
//default:break;
}
}
//printf("%d\n",state);
token[j]='\0';
if(state==6||state==5||state==2)
{
fprintf(fout,"(%s,%s)\n","数字",token);
map1.insert(make_pair(v,token));
q.push(6);
}
}
else if(strchr(lbordword,ch)>0)
{
token[0]=ch;
token[1]='\0';
ch=getc(fin);
fprintf(fout,"(%s,%s)\n","左括号",token);
q.push(4);
}
else if(strchr(rbordword,ch)>0)
{
token[0]=ch;
token[1]='\0';
ch=getc(fin);
fprintf(fout,"(%s,%s)\n","右括号",token);
q.push(5);
}
else if(strchr(opword,ch)>0)
{
token[0]=ch;
token[1]='\0';
ch=getc(fin);
fprintf(fout,"(%s,%s)\n","运算符",token);
q.push(3);
}
else if(strchr(eword,ch)>0)
{
token[0]=ch;
token[1]='\0';
ch=getc(fin);
fprintf(fout,"(%s,%s)\n","等于号",token);
q.push(2);
}
else
{
token[0]=ch;token[1]='\0';
ch=getc(fin);
es=3;
//fprintf(fout,"(%s,%s)\n","ERROR",token);
}
}
// for (map::iterator it = map1.begin(); it != map1.end(); ++it)
// {
// cout <<"first:" <first<<" " <second<
// }
ifstream infile("I1.txt",ios::in);
if(!infile){
// 判断文件是否存在
cerr<<"open error."<<endl;
exit(1); // 退出程序
}
string str; //获取最后一行串
string str1;//获取最后一串表达式
int flag;
while (getline(infile, str)) {
//cout << str << "\n";
}
for(int i=0;i<str.length();i++) {
if(str[i]=='='){
flag = i+1;
}
}
str1 = str.substr(flag,str.length());
//cout<
for (map<string, string>::iterator it = map1.begin(); it != map1.end(); ++it)
{
int f = str1.find(it->first);
//cout<<"f:"<
if(f>=0){
str = str1.substr(0,f) +it->second+ str1.substr(f+it->first.length(),str1.length());
str1 = str;
//cout<
}
}
cout<<str<<endl;
char ss[255];
strcpy(ss,str.c_str());
fprintf(fout,"%s",ss);
fclose(fin);
fclose(fout);
printf("%d\n",es);
return 0;
}
代码二:算符优先分析并输出结果
#include
using namespace std;
struct info{
char left;
vector<string> right;
vector<char> first;
vector<char> last;
};
vector<info> lang;
char mtr[9][9]; //算符优先矩阵
stack<char> sta;
void get(); //获取文法
void print(); //打印文法
void fun(); //求FirstVT 和 LastVT
void matrix(); //求算符优先矩阵
void test(); //测试文法
int cmp(char a,char b); //比较两个运算符的优先级
void out(char now,int avg1,int avg2); //打印三元式
int ope(char op,int a,int b); //定义三元式计算方法
int main(){
int choose;
cout<<"输入1进入程序:"<<endl;
cin>>choose;
switch(choose){
case 1: get(); print(); fun(); matrix(); test();
default:break;
}
return 0;
}
void get(){
info temp,temp1,temp2;
temp.left = 'E';
temp.right.push_back("E+T");
temp.right.push_back("E-T");
temp.right.push_back("T");
temp.right.push_back("i");
temp1.left = 'T';
temp1.right.push_back("T*F");
temp1.right.push_back("T/F");
temp1.right.push_back("F");
temp2.left = 'F';
temp2.right.push_back("(E)");
temp2.right.push_back("i");
lang.push_back(temp);
lang.push_back(temp1);
lang.push_back(temp2);
cout << "————————————————————" << endl;
cout << " 文法获取完成" << endl;
cout << "————————————————————" << endl;
cout << endl;
cout<<"显示文法"<<endl;
}
void print(){
cout << "****************************************" << endl;
for(int i = 0;i < lang.size();i ++){
for(int j = 0;j < lang[i].right.size();j ++){
cout << lang[i].left << " --> ";
cout << lang[i].right[j] << endl;
}
}
cout << "****************************************" << endl;
cout << endl;
cout<<"构造FIRSTVT集和FOLLOWVT集合"<<endl;
}
//FIRSTVT:B=>b......
void fun(){
int i,j,sign = 0,sign1 = 0;
for(i = 0;i < lang.size();i ++){
for(j = 0;j < lang[i].right.size();j ++){
string temp = lang[i].right[j]; //获取右部
if(temp[0] > 'Z' || temp[0] < 'A'){
//终结符
lang[i].first.push_back(temp[0]);
}
else if(temp.length() >= 2){
//终结符
if(temp[1] > 'Z' || temp[1] < 'A'){
lang[i].first.push_back(temp[1]);
}
}
}
}
//LASTVT:B=>.....a
for(i = 0;i < lang.size();i ++){
for(j = 0;j < lang[i].right.size();j ++){
string temp = lang[i].right[j]; //获取右部
if((temp[0] > 'Z' || temp[0] < 'A') && temp.length() == 1){
//终结符
lang[i].last.push_back(temp[0]);
}
else if(temp.length() >= 3){
//终结符
if(temp[1] > 'Z' || temp[1] < 'A')
lang[i].last.push_back(temp[1]);
else if(temp[2] > 'Z' || temp[2] < 'A') //终结符
lang[i].last.push_back(temp[2]);
}
}
}
//FIRSTVT:B=>Cb......
while(sign == 0){
//迭代FirstVT
sign = 1;
for(i = 0;i < lang.size();i ++){
for(j = 0;j < lang[i].right.size();j ++){
string temp = lang[i].right[j]; //获取右部
if(temp.length() == 1 && (temp[0] <= 'Z' && temp[0] >= 'A')){
//可以迭代
for(int k = 0;k < lang.size();k ++){
if(lang[k].left == temp[0]){
//找到了,添加元素
for(int p = 0;p < lang[k].first.size();p ++){
sign1 = 0;
char ch = lang[k].first[p];
for(int q = 0;q < lang[i].first.size();q ++){
if(lang[i].first[q] == ch){
//包含了
sign1 = 1;
}
}
if(sign1 == 0){
lang[i].first.push_back(ch);
sign = 0;
}
}
}
}
}
}
}
}
//LASTVT:B=>......aC
sign = 0;
while(sign == 0){
//迭代LastVT
sign = 1;
for(i = 0;i < lang.size();i ++){
for(j = 0;j < lang[i].right.size();j ++){
string temp = lang[i].right[j]; //获取右部
if(temp.length() == 1 && (temp[0] <= 'Z' && temp[0] >= 'A')){
//可以迭代
for(int k = 0;k < lang.size();k ++){
if(lang[k].left == temp[0]){
//找到了,添加元素
for(int p = 0;p < lang[k].last.size();p ++){
sign1 = 0;
char ch = lang[k].last[p];
for(int q = 0;q < lang[i].last.size();q ++){
if(lang[i].last[q] == ch){
//包含了
sign1 = 1;
}
}
if(sign1 == 0){
lang[i].last.push_back(ch);
sign = 0;
}
}
}
}
}
}
}
}
cout << "……………………………………………………" << endl;
cout << "FirstVT:" << endl;
for(i = 0;i < lang.size();i ++){
cout << lang[i].left << " : ";
for(j = 0;j < lang[i].first.size();j ++){
cout << lang[i].first[j] << " ";
}
cout << endl;
}
cout << endl;
cout << "LasttVT:" << endl;
for(i = 0;i < lang.size();i ++){
cout << lang[i].left << " : ";
for(j = 0;j < lang[i].last.size();j ++){
cout << lang[i].last[j] << " ";
}
cout << endl;
}
cout << "……………………………………………………" << endl;
cout << endl;
cout<<"构造优先关系矩阵请"<<endl;
}
void matrix(){
int i,j;
for(i = 0;i < 9;i ++){
//初始化
for(j = 0;j < 9;j ++){
mtr[i][j] = 'n';
}
}
string temp = "+-*/()i#";
for(i = 1;i < 9;i ++){
mtr[i][0] = temp[i - 1];
mtr[0][i] = temp[i - 1];
}
vector<string> str;
//aU==>a < FirstVT(U)
for(i = 0;i < lang.size();i ++){
//aU a < FirstVT(U)
for(j = 0;j < lang[i].right.size();j ++){
string ss = lang[i].right[j];
string ok = "";
if(ss.length() > 2){
if((ss[0] > 'Z' || ss[0] < 'A') && (ss[1] <= 'Z' && ss[1] >= 'A')){
//aU
ok = "";
ok += ss[0];
ok += ss[1];
str.push_back(ok);
}
if((ss[1] > 'Z' || ss[1] < 'A') && (ss[2] <= 'Z' && ss[2] >= 'A')){
//aU
ok = "";
ok += ss[1];
ok += ss[2];
str.push_back(ok);
}
}
}
}
//找到a和FIRSTVT(U)
for(i = 0;i < str.size();i ++){
for(j = 1;j < 9;j ++){
if(mtr[j][0] == str[i][0]){
for(int k = 0;k < lang.size();k ++){
if(lang[k].left == str[i][1]){
for(int p = 0;p < lang[k].first.size();p ++){
for(int q = 1;q < 9;q ++){
if(mtr[q][0] == lang[k].first[p]){
mtr[j][q] = '<';
}
}
}
}
}
}
}
}
//Ua==>LastVT(U) > a
str.clear();
for(i = 0;i < lang.size();i ++){
for(j = 0;j < lang[i].right.size();j ++){
string ss = lang[i].right[j];
string ok = "";
if(ss.length() > 2){
if((ss[1] > 'Z' || ss[1] < 'A') && (ss[0] <= 'Z' && ss[0] >= 'A')){
//Ua
ok = "";
ok += ss[0];
ok += ss[1];
str.push_back(ok);
}
if((ss[2] > 'Z' || ss[2] < 'A') && (ss[1] <= 'Z' && ss[1] >= 'A')){
//Ua
ok = "";
ok += ss[1];
ok += ss[2];
str.push_back(ok);
}
}
}
}
//找到a和LASTVT(U)
for(i = 0;i < str.size();i ++){
for(j = 1;j < 9;j ++){
if(mtr[0][j] == str[i][1]){
//Find a Then Find LastVt(U)
for(int k = 0;k < lang.size();k ++){
if(lang[k].left == str[i][0]){
//Find U
for(int p = 0;p < lang[k].last.size();p ++){
for(int q = 1;q < 9;q ++){
if(mtr[0][q] == lang[k].last[p]){
mtr[q][j] = '>';
}
}
}
}
}
}
}
}
//aUb || ...ab... ==> a = b
str.clear();
for(i = 0;i < lang.size();i ++){
//ab aUb a = b
for(j = 0;j < lang[i].right.size();j ++){
string ss = lang[i].right[j];
string ok = "";
if(ss.length() > 2){
if((ss[1] > 'Z' || ss[1] < 'A') && (ss[0] > 'Z' || ss[0] < 'A')){
//aa
ok = "";
ok += ss[0];
ok += ss[1];
str.push_back(ok);
}
if((ss[2] > 'Z' || ss[2] < 'A') && (ss[1] > 'Z' || ss[1] < 'A')){
//aa
ok = "";
ok += ss[1];
ok += ss[2];
str.push_back(ok);
}
if((ss[2] > 'Z' || ss[2] < 'A') && (ss[0] > 'Z' || ss[0] < 'A')){
//aUa
ok = "";
ok += ss[0];
ok += ss[2];
str.push_back(ok);
}
}
}
}
for(i = 0;i < str.size();i ++){
for(j = 1;j < 9;j ++){
if(str[i][0] == mtr[j][0]){
for(int k = 1;k < 9;k ++){
if(mtr[0][k] == str[i][1]){
mtr[j][k] = '=';
}
}
}
}
}
for(i = 0;i < lang[0].first.size();i ++){
//#
for(j = 1;j < 9;j ++){
if(lang[0].first[i] == mtr[0][j]){
mtr[8][j] = '<';
}
}
}
for(i = 0;i < lang[0].first.size();i ++){
//#
for(j = 1;j < 9;j ++){
if(lang[0].first[i] == mtr[j][0]){
mtr[j][8] = '>';
}
}
}
mtr[8][8] = '=';
cout << "========================================" << endl;
for(i = 0;i < 9;i ++){
for(j = 0;j < 9;j ++){
if(mtr[i][j] != 'n')
cout << mtr[i][j] << " ";
else
cout << " ";
}
cout << endl;
}
cout << "========================================" << endl;
cout << endl;
cout<<"文法测试"<<endl;
}
void test(){
cout << "----------------------------------------" << endl;
string str;
ifstream infile("O1.txt",ios::in);
if(!infile){
// 判断文件是否存在
cerr<<"open error."<<endl;
exit(1); // 退出程序
}
while(getline(infile, str)) {
}
cout<<"测试文法为"<<str<<endl;
str += '#';
int i,j,k;
stack<int> data;
stack<char> op;
op.push('#');
char now = 'n'; //记录当前栈顶操作符
int sign = 0;
for(i = 0;i < str.length();i ++){
sign = 0;
if(str[i] >= '0' && str[i] <= '9'){
//操作数
int temp = str[i] - '0';
data.push(temp);
}
else{
//运算符
op.push(str[i]);
sign = 1;
}
if(now != 'n' && sign == 1){
//有可比性,并且操作符栈有更新
if(!op.empty()){
char top = op.top(); //栈顶元素
while(cmp(now,top) == 1){
//需要规约
int avg1 = data.top();
data.pop();
int avg2 = data.top();
data.pop();
out(now,avg2,avg1); //打印三元式
data.push(ope(now,avg2,avg1));
op.pop();
op.pop();
if(!op.empty()){
now = op.top();
}
else{
now = 'n';
}
op.push(top);
}
if(cmp(now,top) == 0){
op.pop();
op.pop();
if(!op.empty()){
now = op.top();
}
else{
char temp = '=';
if(!data.empty()){
int da = data.top();
out(temp,da,0);
}
}
}
}
}
else{
//不需要比较
if(!op.empty()){
now = op.top();
}
}
}
}
int cmp(char a,char b){
int i,j;
for(i = 1;i < 9;i ++){
if(mtr[i][0] == a){
for(j = 1;j < 9;j ++){
if(mtr[0][j] == b){
if(mtr[i][j] == '>'){
return 1;
}
else if(mtr[i][j] == '='){
return 0;
}
else if(mtr[i][j] == '<'){
return -1;
}
}
}
}
}
return 2;
}
void out(char now,int avg1,int avg2){
cout << "----------------------------------------" << endl;
cout << now << " ," << avg1 << " ," << avg2 << endl;
cout << endl;
}
int ope(char op,int a,int b){
if(op == '+'){
return a + b;
}
if(op == '-'){
return a - b;
}
if(op == '*'){
return a * b;
}
if(op == '/'){
return a / b;
}
if(op == '='){
return a;
}
return 0;
}
TXT文件放在与CPP文件同一目录下:
I1.txt
x=1
y=4
a=2
b=5
c=6
d=3
z=x+(y-a)*b+c/d
运行方式:
1.可以自己在I1.txt文件中输入标识符=数字/表达式的格式,表达式放在最后一行。
2.运行DFA代码可以得到O1.txt输出文件,文件包含词法分析过程和最后得到的表达式。
3.运行算符优先分析,按照提示输入,可以得到最后运算的结果。
来自ecjtu18老学长