编译原理实验三 语义分析程序设计与实现

一、实验目的

在实现词法、语法分析程序的基础上,编写相应的语义子程序,进行语义处理,加深对语法制导翻译原理的理解,进一步掌握将语法分析所识别的语法范畴变换为某种中间代码(四元式)的语义分析方法,并完成相关语义分析器的代码开发。

二、基本实验内容及要求

对文法 G2[<算术表达式>]中的产生式添加语义处理子程序,完成运算对象是简单变量(标识符)和无符号数的四则运算的计值处理,将输入的四则运算转换为四元式形式的中间代码。
输入:包含测试用例(由标识符、无符号数和+、−、*、/、(、)构成的算术表达式)的源程序文件。
输出:将源程序转换为中间代码形式表示,并将中间代码序列输出到文件中。若源程序中有错误,应指出错误信息。
要求:
1、结合实验一和实验二中的相关内容,完成语法制导翻译的程序设计。
2、对完成的编译系统进行全面测试,供测试的例子应包括符合语义规则的语句,以及分析程序能够判别的若干错例,并给出执行结果。

四、源程序

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#define _CRT_SECURE_NO_DEPRECATE
//#define _CRT_SECURE_NO_WARNINGS
using namespace std;
/*
begin	BEGIN	1
end		END		2
if		IF		3
then	THEN	4
else	ELSE	5
while	WHILE	6
do		DO		7
标识符	ID		8
浮点常数UCON	9
<		LT		10
<=		LE		11
==		EQ		12
<>		NE		13
>		GT		14
>=		GE		15
=		IS		16
+		PL		17
-		MI		18
*		MU		19
/		DI		20
(		LP		21
)		RP		22
*/

//词法分析部分
const char* table1[] = { " ","begin","end","if","then","else","while","do" };
const char* table2[] = { " ","BEGIN","END","IF","THEN","ELSE","WHILE","DO","ID","UCON","LT","LE","EQ","NE","GT","GE","IS","PL","MI","MU","DI","LP","RP" };
char TOKEN[20];//用来依次存放一个单词词文中的各个字符。
char str[50];//词法分析后的带有i的表达式
int len = 0;
//语法分析部分
string action[16][8] = { {"s4","null","null" ,"null" ,"null","null","s5" , "null" },
					{"null","null","s6","s7","null","null","null","acc"},
					{"null","r3","r3","r3","s8","s9","null","r3"} ,
					{"null","r6","r6","r6","r6","r6","null","r6"},
					{"s4","null","null","null","null","null","s5","null"},
					{"null","r8","r8","r8","r8","r8","null","r8"},
					{"s4","null","null","null","null","null","s5","null"},
					{"s4","null","null","null","null","null","s5","null"},
					{"s4","null","null","null","null","null","s5","null"},
					{"s4","null","null","null","null","null","s5","null"},
					{"null","s15","s6","s7","null","null","null","null"} ,
					{"null","r1","r1","r1","s8","s9","null","r1"},
					{"null","r2","r2","r2","s8","s9","null","r2"} ,
					{"null","r4","r4","r4","r4","r4","null","r4"} ,
					{"null","r5","r5","r5","r5","r5","null","r5"} ,
					{"null","r7","r7","r7","r7","r7","null","r7"} };
int go[16][3] = { {1 , 2 , 3 },
				{ -1 , -1 , -1 },
				{ -1 , -1 , -1 } ,
				{ -1 , -1 , -1 },
				{ 10 , 2 , 3 },
				{ -1 , -1 , -1 },
				{ -1 , 11 , 3 },
				{ -1 , 12 , 3 },
				{ -1 , -1 , 13 },
				{ -1 , -1 , 14 },
				{ -1 , -1 , -1 } ,
				{ -1 , -1 , -1 },
				{ -1 , -1 , -1 } ,
				{ -1 , -1 , -1 } ,
				{ -1 , -1 , -1 } ,
				{ -1 , -1 , -1 } };
//char vt[8] = { '(',')','+','-','*','/','i','#' };
//char vn[3] = { 'E','T','F' };
string grammar[9] = { "S->E","E->E+T","E->E-T","E->T","T->T*F","T->T/F","T->F","F->(E)","F->i" };
string gg[9] = { "S.PLACE=","生成四元式 ","生成四元式","E.PLACE=","生成四元式","生成四元式","T.PLACE=","F.PLACE= ","F.PLACE=" };
int grammarlength[9] = { 4,6,6,4,6,6,4,6,4 };
char grammarleft[9] = { 'S','E','E','E','T','T','T','F','F' };
string grammarright[9] = { "E","E+T","E-T","T","T*F","T/F","F","(E)","i" };
int grammarrightlength[9] = { 1,3,3,1,3,3,1,3,1 };

//语义分析部分
#define PMAX 5 //定义产生式符号属性字符串的长度
int NXQ = 0;//指示下一个四元式编号
int NXTemp = 1;//指示临时变量的编号

string eplace[10];//E的语义属性
string tplace[10];//T的语义属性
string fplace[10];//F的语义属性
int eindex = -1,tindex =-1,findex = -1;
char* NewTemp(void) /*产生一个临时变量*/
{
	char* TempID = (char*)malloc(PMAX);
	sprintf(TempID, "T%d", NXTemp++); /*整型变量 NXTemp 指示临时变量的编号*/
	return TempID;
}


int lookup(char a[])/*每调用一次,就以 TOKEN 中的字符串查保留字表,若查到,就将相应关键字的类别码赋给整型变量 c;否则将 c 置为零。*/
{
	int i;
	for (i = 1; i <= 7; i++)
	{
		if (strcmp(a, table1[i]) == 0)return i;
	}
	if (i == 8)
	{
		return 0;
	}

}
void out(int a, const char b[])
/*一般仅在进入终态时调用此函数,调用的形式为 OUT(c,VAL)。
其中,实参 c 为相应单词的类别码助记符;实参 VAL 为 TOKEN(即词文)或为空串。
函数 OUT 的功能是,在送出一个单词的内部表示之后,返回到调用该词法分析程序的那个程序。*/
{
	ofstream fout("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\result.txt", fstream::app);
	char temp = ' ';
	if (a == 8 || a == 9)
	{
		fout << "(" << table2[a] << " ," << b << ")" << endl;
	}
	else
	{
		fout << "(" << table2[a] << " ," << temp << ")" << endl;
	}

	fout.close();
}

void report_error(void)//返回错误
{
	ofstream fout("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\result.txt", fstream::app);
	fout << "输入不合规范!";
	fout.close();
	exit(0);
}
void scanner_example(FILE* fp)
{
	char ch;
	int i, c, flag = 0;;
	//ch = fgetc(fp);
	while ((ch = fgetc(fp)) != EOF)
	{
		if (ch == ' ')ch = fgetc(fp);
		if (ch == '\n')ch = fgetc(fp);
		if (ch == '#')break;
		if (isalpha(ch)) //判断字符是否为字母,识别标识符和关键字
		{
			TOKEN[0] = ch; ch = fgetc(fp); i = 1;
			while (isalnum(ch))//检查所传的字符是否是字母和数字
			{
				TOKEN[i] = ch; i++;
				ch = fgetc(fp);
			}
			TOKEN[i] = '\0';//结束符
			fseek(fp, -1, 1); //从文件当前位置后退一个字符
			c = lookup(TOKEN);//查找在第二个表中的位置,如果是关键字返回下标,标识符返回0
			if (c == 0)
			{
				out(8, TOKEN);//识别标识符
				str[len] = 'i';
				len++;
			}
			else out(c, TOKEN);//识别关键字
		}
		else if (isdigit(ch))//判断字符是否为数字字符
		{
			TOKEN[0] = ch; ch = fgetc(fp); i = 1;
			while (isdigit(ch) || ch == '.')
			{
				if (ch == '.')
				{
					if (flag == 0)
					{
						flag = 1;
						TOKEN[i] = ch; i++;
					}
					else report_error();
				}
				else
				{
					TOKEN[i] = ch; i++;

				}
				ch = fgetc(fp);
			}
			TOKEN[i] = '\0';
			fseek(fp, -1, 1);
			out(9, TOKEN);//识别数字
			str[len] = 'i';
			len++;
		}
		else
			switch (ch)
			{
			case '<': ch = fgetc(fp);
				if (ch == '=')out(11, TOKEN);//<=
				else if (ch == '>') out(13, TOKEN);//<>
				else
				{
					fseek(fp, -1, 1);
					out(10, TOKEN);//<
				}
				break;
			case '=': ch = fgetc(fp);
				if (ch == '=')out(12, TOKEN);//==
				else
				{
					fseek(fp, -1, 1);
					out(16, TOKEN);//=
				}
				break;
			case '>': ch = fgetc(fp);
				if (ch == '=')out(15, TOKEN);//>=
				else
				{
					fseek(fp, -1, 1);
					out(14, TOKEN);//>
				}
				break;
			case '+':
			{
				out(17, TOKEN);
				str[len] = '+';
				len++;
				break;
			}
			case '-':
			{
				out(18, TOKEN);
				str[len] = '-';
				len++;
				break;
			}

			case '*':
			{
				out(19, TOKEN);
				str[len] = '*';
				len++;
				break;
			}
			case '/':
			{
				out(20, TOKEN);
				str[len] = '/';
				len++;
				break;
			}
			case '(':
			{
				out(21, TOKEN);
				str[len] = '(';
				len++;
				break;
			}
			case ')':
			{
				out(22, TOKEN);
				str[len] = ')';
				len++;
				break;
			}
			default: report_error(); break;
			}

	}
	return;
}

int main()
{
	cout << "请输入要分析的表达式(以#结束):" << endl;
	char strr[50];//输入的表达式
	int i = 0;
	ofstream out1("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\test.txt");
	out1.close();
	ofstream out("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\test.txt", ios::out);
	while (true)
	{
		cin >> strr[i];
		out << strr[i];
		if (strr[i] == '#')break;
		i++;
	}
	out.close();
	FILE* fp1;
	FILE* fp2;
	fp2 = fopen("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\result.txt", "w");
	fclose(fp2);
	fp1 = fopen("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\test.txt", "r");
	if (!fp1)
	{
		printf("打开文件失败!");
	}
	scanner_example(fp1);

	string temp;
	cout << endl;
	cout << "词法分析结果为:" << endl;
	ifstream myfile2("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\result.txt", ios::in);
	if (!myfile2.is_open())
	{
		cout << "未成功打开文件" << endl;
	}
	while (getline(myfile2, temp))
	{
		cout << temp << endl;
	}
	myfile2.close();

	str[len] = '#';
	cout << endl;
	cout << "词法分析后表达式为:" << endl;
	for (int i = 0; i <= len; i++)
	{
		cout << str[i];
	}
	cout << endl;
	cout << endl;
	cout << "语法分析结果为:" << endl;

	int count;//步骤
	int state[100], stateIndex;//状态串及下标
	state[0] = 0; stateIndex = 0;//初始化状态串
	char inSymbol[100], outSymbol[100];//栈中符号串  余留符号串
	inSymbol[0] = '#';//初始化
	int inSymbolIndex = 0, outSymbolIndex = 0;
	string analysis;//分析动作
	//string nextState;//下一状态
	for (int i = 0; i <= len; i++)
	{
		outSymbol[i] = str[i];
	}
	cout << "字符串长度为:" << len << endl;
	cout << "步骤" << "\t" << "状态" << "\t\t";
	cout << "栈中符号" << "\t\t" << "余留符号串" << "\t\t";
	cout << "分析动作" << "\t\t" << "语义处理" << "\t\t" << "生成中间代码" << "\t\n";
	for (count = 1;;)
	{
		cout << count << fixed << setprecision(3) << "\t";
		for (int i = 0; i <= stateIndex; i++)
		{
			cout << state[i] << " " << fixed << setprecision(4);
		}
		cout << "\t\t";
		for (int i = 0; i <= inSymbolIndex; i++)
		{
			cout << inSymbol[i] << " " << fixed << setprecision(4);
		}
		cout << "\t\t";
		for (int i = outSymbolIndex; i <= len; i++)
		{
			cout << outSymbol[i] << " " << fixed << setprecision(4);
		}
		cout << "\t\t";


		int row = state[stateIndex], column;
		if (outSymbol[outSymbolIndex] == '(')column = 0;
		else if (outSymbol[outSymbolIndex] == ')')column = 1;
		else if (outSymbol[outSymbolIndex] == '+')column = 2;
		else if (outSymbol[outSymbolIndex] == '-')column = 3;
		else if (outSymbol[outSymbolIndex] == '*')column = 4;
		else if (outSymbol[outSymbolIndex] == '/')column = 5;
		else if (outSymbol[outSymbolIndex] == 'i')column = 6;
		else if (outSymbol[outSymbolIndex] == '#')column = 7;


		if (action[row][column] == "null")
		{
			cout << "error!" << endl;
			break;
		}
		else
		{
			analysis = action[row][column];
			cout << analysis << "\t";
			if (analysis[0] == 's')
			{
				cout << endl;
				stateIndex++;
				if (analysis.length() == 3)
				{
					state[stateIndex] = ((int)(analysis[1]) - 48) * 10 + ((int)(analysis[2]) - 48);
				}
				else state[stateIndex] = (int)analysis[1] - 48;
				inSymbolIndex++;
				inSymbol[inSymbolIndex] = outSymbol[outSymbolIndex];
				outSymbolIndex++;
				count++;
			}
			else if (analysis[0] == 'r')
			{
				int temp = (int)analysis[1] - 48;
				cout << grammar[temp] << endl;
				stateIndex = stateIndex - grammarrightlength[temp];
				inSymbolIndex = inSymbolIndex + 1 - grammarrightlength[temp];
				inSymbol[inSymbolIndex] = grammarleft[temp];
				cout << " " << fixed << setprecision(3) << "\t";
				for (int i = 0; i <= stateIndex; i++)
				{
					cout << state[i] << " " << fixed << setprecision(4);
				}
				cout << "\t\t";
				for (int i = 0; i <= inSymbolIndex; i++)
				{
					cout << inSymbol[i] << " " << fixed << setprecision(4);
				}
				cout << "\t\t";
				for (int i = outSymbolIndex; i <= len; i++)
				{
					cout << outSymbol[i] << " " << fixed << setprecision(4);
				}
				cout << "\t\t";


				int row2 = state[stateIndex], column2;
				if (inSymbol[inSymbolIndex] == 'E')column2 = 0;
				else if (inSymbol[inSymbolIndex] == 'T')column2 = 1;
				else if (inSymbol[inSymbolIndex] == 'F')column2 = 2;

				if (go[row2][column2] == -1)
				{
					cout << "error!" << endl;
					break;
				}
				else
				{
					cout << "go[" << row2 << "," << column2 << "]=" << go[row2][column2] << "\t";
					stateIndex++;
					state[stateIndex] = go[row2][column2];
					count++;
					if (temp == 8)
					{
						findex++;
						cout << gg[temp] << strr[outSymbolIndex - 1];
						fplace[findex] = strr[outSymbolIndex - 1];
						
					}
					else if(temp==6)
					{
						tindex++;
						cout << gg[temp] << strr[outSymbolIndex - 1];
						tplace[tindex] = strr[outSymbolIndex - 1];
						
						findex--;
					}
					else if (temp == 3)
					{
						eindex++;
						cout << gg[temp] << strr[outSymbolIndex - 1];
						eplace[eindex] = strr[outSymbolIndex - 1];
						
						tindex--;
					}
					else if (temp == 1)
					{
						cout << gg[temp] ;
						
						const char* temp1 = eplace[eindex].c_str();
						const char* temp2 = tplace[tindex].c_str();					
						tindex--;
						char* temp=NewTemp();
						//GEN("+", temp1, temp2, temp);
						cout << "( + , " << temp1 << " , " << temp2 << " , " << temp << " ) ";
						eplace[eindex] = NXTemp;

					}
					else if (temp == 2)
					{
						cout << gg[temp] ;
						
						const char* temp1 = eplace[eindex].c_str();
						const char* temp2 = tplace[tindex].c_str();
						tindex--;
						char* temp = NewTemp();
						//GEN("-", temp1, temp2, temp);
						cout << "( - , " << temp1 << " , " << temp2 << " , " << temp << " ) ";
						eplace[eindex] = temp;
					}
					else if (temp == 4)
					{
						cout << gg[temp] ;
						const char* temp1 = tplace[tindex].c_str();
						const char* temp2 = fplace[findex].c_str();
						findex--;
						char* temp = NewTemp();
						//GEN("*", temp1, temp2, temp);
						cout << "( * , " << temp1 << " , " << temp2 << " , " << temp << " ) ";
						tplace[tindex] = temp;
					}
					else if (temp == 5)
					{
						cout << gg[temp] ;
						const char* temp1 = tplace[tindex].c_str();
						const char* temp2 = fplace[findex].c_str();
						findex--;
						char* temp = NewTemp();
						//GEN("/", temp1, temp2, temp);
						cout << "( / , " << temp1 << " , " << temp2 << " , " << temp << " ) ";
						tplace[tindex] = temp;
					}
					else if (temp == 7)
					{
						findex++;
						fplace[findex] = eplace[eindex];
						eindex--;
					}
					cout << endl;
				}
			}
			else if (analysis == "acc")
			{
				cout << endl << "分析成功!";
				break;
			}

		}
	}
	
	fclose(fp1);
	fclose(fp2);
	return 0;
}

五、实验结果及分析
1、正确表达式
编译原理实验三 语义分析程序设计与实现_第1张图片
编译原理实验三 语义分析程序设计与实现_第2张图片
2、错误表达式
编译原理实验三 语义分析程序设计与实现_第3张图片

你可能感兴趣的:(编译原理)