基於算符優先分析算法的語法制導翻譯——程序設計與編譯原理

一、在算符優先語法分析的基礎上進行翻譯工作(即語義分析),每當將一個最左素短語歸約爲一個非終結符號時,就調用對應產生式的語義子程序,去完成相應的語義翻譯工作,這步歸約使用的產生式對非終結符號不加區分(即將所有的非終結符號用一個通用的非終結符號表示)。

判斷是句子的情況下,輸出:四元式序列(*,val,count,T1)

算符優先分析前期準備:https://blog.csdn.net/lfy905805357/article/details/89333111

二、code

#include <iostream>
#include "stdio.h"
#include "stdlib.h"
#include <string>
#include <map>
#include <sstream>
using namespace std;
char Data[20][20];                    //算符優先關係
char s[100];                          //模擬符號棧s
string str[100];                      //用來類似模擬符號棧s,不過該棧爲字符串(用於同時給非終結符加上下標,例如P1)
char lable[20];                       //文法終極符集
char input[100];                      //文法輸入符號串
char In_str[20][10];                  //用於輸入串的分析
char text[20][10];
int k;
char a;
int j;
char q;
int r;                                //文法規則個數
int r1;                               //轉化後文法規則個數
char st[10][30];                      //用來存儲文法規則
char first[10][10];                   //文法非終結符FIRSTVT集
char last[10][10];                    //文法非終結符LASTVT集
int fflag[10] = { 0 };                //標誌第i個非終結符的FIRSTVT集是否已求出
int lflag[10] = { 0 };                //標誌第i個非終結符的LASTVT集是否已求出
map<char,int> charmap;                //用來判斷該字符的下標是幾
map<string,string> stringmap;         //用來下標,值健對查找
stringstream ss;                      //利用該stringstream來進行其他類型轉換爲字符串
string qua[100][4];                   //存儲四元組
int quaCounts=0;                      //四元組個數
int deal();                           //對輸入串的分析
int deal1();                          //對輸入串的分析(包括求四元組)
int Terminator(char c);               //判斷字符c是否是終極符
int getIndex(char c);                 //求字符c在算符優先關係表中的下標
void out(int j, int k, char *s);      //打印s棧
void out1(int j, int k, string *str); //打印str棧
void firstvt(char c);                 //求非終結符c的FIRSTVT集
void lastvt(char c);                  //求非終結符c的LASTVT集
void table();                         //創建文法優先關係表
bool check(char *in);                 //判斷輸入是不是都是終結符構成的句子
int main()
{
	int i, j, k = 0;
	printf("請輸入文法規則數:");
	cin >> r;
	printf("請輸入文法規則:\n");
	for (i = 0; i<r; i++)
	{
		cin >> st[i];		        //存儲文法規則,初始化FIRSTVT集和LASTVT集*/
		first[i][0] = 0;            /*first[i][0]和last[i][0]分別表示st[i][0]非終極
									符的FIRSTVT集和LASTVT集中元素的個數*/
		last[i][0] = 0;
	}
	for (i = 0; i<r; i++)          //判斷文法是否合法
	{
		for (j = 0; st[i][j] != '\0'; j++)
		{
			if (st[i][0]<'A' || st[i][0]>'Z')
			{
				printf("不是算符文法!\n");
				exit(-1);
			}
			if (st[i][j] >= 'A'&&st[i][j] <= 'Z')
			{
				if (st[i][j + 1] >= 'A'&&st[i][j + 1] <= 'Z')//兩非終結符不能相鄰
				{
					printf("不是算符文法!\n");
					exit(-1);
				}
			}
		}
	}
	for (i = 0; i<r; i++)
	{
		for (j = 0; st[i][j] != '\0'; j++)
		{
			if ((st[i][j]<'A' || st[i][j]>'Z') && st[i][j] != '-'&&st[i][j] != '>'&&st[i][j] != '|')
				lable[k++] = st[i][j];
		}
	}
	lable[k] = '#';//把井號終結符加入到終結符集合裏面
	lable[k + 1] = '\0';
	table();

	printf("每個非終結符的FIRSTVT集爲:\n");    //輸出每個非終結符的FIRSTVT集
	for (i = 0; i<r; i++)
	{
		printf("%c: ", st[i][0]);
		for (j = 0; j<first[i][0]; j++)
		{
			printf("%c ", first[i][j + 1]);
		}
		printf("\n");
	}
	printf("每個非終結符的LASTVT集爲:\n");    //輸出每個非終結符的LASTVT集
	for (i = 0; i<r; i++)
	{
		printf("%c: ", st[i][0]);
		for (j = 0; j<last[i][0]; j++)
		{
			printf("%c ", last[i][j + 1]);
		}
		printf("\n");
	}
	printf("算符優先分析表如下:\n");
	for (i = 0; lable[i] != '\0'; i++)
		printf("\t%c", lable[i]);
	printf("\n");
	for (i = 0; i<k + 1; i++)
	{
		printf("%c\t", lable[i]);
		for (j = 0; j<k + 1; j++)
		{
			printf("%c\t", Data[i][j]);
		}
		printf("\n");
	}
	printf("請輸入文法輸入符號串以#結束:");
	while (cin >> input && input != "exit") {
		int flag=deal1();//標記是否符合文法定義
		if(flag==1&&check(input)){//檢測輸入串是否是終結符組成的句子
            cout<<"該符號串是句子!"<<endl;
            cout<<"\n四元式如下:"<<endl;
            for(int i=0;i<quaCounts;i++){
                cout<<"產生【"<<(i+1)<<"】:";
                cout<<"("+qua[i][0]+","+qua[i][1]+","+qua[i][2]+","+qua[i][3]+")"<<endl;
            }
		}
		quaCounts=0;//重新歸零
		printf("請輸入文法輸入符號串以#結束:");
	}

	system("pause");
}
//判斷輸入是不是都是終結符,判斷是不是句子
bool check(char *in){
    for(int i=0;in[i]!='\0';i++){
        if(!Terminator(in[i]))//逐個判斷是不是終結符
            return false;
    }
    return true;
}
void table()
{
	//char text[20][10];
	int i, j, k, t, l, x = 0, y = 0;
	int m, n;
	x = 0;
	//求firstvt集和lastvt集
	for (i = 0; i<r; i++)
	{
		firstvt(st[i][0]);
		lastvt(st[i][0]);
	}
	//轉化文法,化爲單候選式文法
	for (i = 0; i<r; i++)
	{
		text[x][y] = st[i][0];
		y++;
		for (j = 1; st[i][j] != '\0'; j++)
		{
			if (st[i][j] == '|')
			{
				text[x][y] = '\0';
				x++;
				y = 0;
				text[x][y] = st[i][0];
				y++;
				text[x][y++] = '-';
				text[x][y++] = '>';
			}
			else
			{
				text[x][y] = st[i][j];
				y++;
			}
		}
		text[x][y] = '\0';
		x++;
		y = 0;
	}
	r1 = x;//更改轉換後文法的數目
	printf("轉化後的文法爲:\n");
	for (i = 0; i<x; i++)                                  //輸出轉化後的文法規則串
	{
		printf("%s\n", text[i]);
	}
	/*求每個終結符的推導結果(去掉"->"
	後的轉化文法,用於最後的規約)*/
	for (i = 0; i<x; i++)
	{
		In_str[i][0] = text[i][0];
		for (j = 3, l = 1; text[i][j] != '\0'; j++, l++)
			In_str[i][l] = text[i][j];
		In_str[i][l] = '\0';
	}

	//利用書上算法構造算符優先分析表
	//firstvt[0][0]第一位爲firstvt集元素數目
	//lastvt集也一樣
	for (i = 0; i<x; i++)
	{
		for (j = 1; text[i][j + 1] != '\0'; j++)
		{
			if (Terminator(text[i][j]) && Terminator(text[i][j + 1]))
			{
				m = getIndex(text[i][j]);
				n = getIndex(text[i][j + 1]);
				Data[m][n] = '=';
			}
			if (text[i][j + 2] != '\0'&&Terminator(text[i][j]) && Terminator(text[i][j + 2]) && !Terminator(text[i][j + 1]))
			{
				m = getIndex(text[i][j]);
				n = getIndex(text[i][j + 2]);
				Data[m][n] = '=';
			}
			if (Terminator(text[i][j]) && !Terminator(text[i][j + 1]))
			{
				for (k = 0; k<r; k++)
				{
					if (st[k][0] == text[i][j + 1])
						break;
				}
				m = getIndex(text[i][j]);
				for (t = 0; t<first[k][0]; t++)
				{
					n = getIndex(first[k][t + 1]);
					Data[m][n] = '<';
				}
			}
			if (!Terminator(text[i][j]) && Terminator(text[i][j + 1]))
			{
				for (k = 0; k<r; k++)
				{
					if (st[k][0] == text[i][j])
						break;
				}
				n = getIndex(text[i][j + 1]);
				for (t = 0; t<last[k][0]; t++)
				{
					m = getIndex(last[k][t + 1]);
					Data[m][n] = '>';
				}
			}
		}
	}
	//將#E#開始文法也加上去求出其對應的firstvt和lastvt集。
	m = getIndex('#');
	for (t = 0; t<first[0][0]; t++)
	{
		n = getIndex(first[0][t + 1]);
		Data[m][n] = '<';
	}
	n = getIndex('#');
	for (t = 0; t<last[0][0]; t++)
	{
		m = getIndex(last[0][t + 1]);
		Data[m][n] = '>';
	}
	Data[n][n] = '=';
}

void firstvt(char c)                                       //求FIRSTVT集
{
	int i, j, k, m, n;
	for (i = 0; i<r; i++)
	{
		if (st[i][0] == c)
			break;
	}
	if (fflag[i] == 0)
	{
		n = first[i][0] + 1;
		m = 0;
		do
		{
			if (m == 2 || st[i][m] == '|')
			{
				if (Terminator(st[i][m + 1]))
				{
					first[i][n] = st[i][m + 1];
					n++;
				}
				else
				{
					if (Terminator(st[i][m + 2]))
					{
						first[i][n] = st[i][m + 2];
						n++;
					}
					if (st[i][m + 1] != c)
					{
						firstvt(st[i][m + 1]);
						for (j = 0; j<r; j++)
						{
							if (st[j][0] == st[i][m + 1])
								break;
						}
						for (k = 0; k<first[j][0]; k++)
						{
							int t;
							for (t = 0; t<n; t++)
							{
								if (first[i][t] == first[j][k + 1])
									break;
							}
							if (t == n)
							{
								first[i][n] = first[j][k + 1];
								n++;
							}
						}
					}
				}
			}
			m++;
		} while (st[i][m] != '\0');
		first[i][n] = '\0';
		first[i][0] = --n;//第一位值存firstvt集中元素的個數(字符形式)
		fflag[i] = 1;//表明該非終極符的firstvt集求出來了
	}
}

void lastvt(char c)                                        //求LASTVT集
{
	int i, j, k, m, n;
	for (i = 0; i<r; i++)
	{
		if (st[i][0] == c)
			break;
	}
	if (lflag[i] == 0)
	{
		n = last[i][0] + 1;
		m = 0;
		do
		{
			if (st[i][m + 1] == '\0' || st[i][m + 1] == '|')
			{
				if (Terminator(st[i][m]))
				{
					last[i][n] = st[i][m];
					n++;
				}
				else
				{
					if (Terminator(st[i][m - 1]))
					{
						last[i][n] = st[i][m - 1];
						n++;
					}
					if (st[i][m] != c)
					{
						lastvt(st[i][m]);
						for (j = 0; j<r; j++)
						{
							if (st[j][0] == st[i][m])
								break;
						}
						for (k = 0; k<last[j][0]; k++)
						{
							int t;
							for (t = 0; t<n; t++)
							{
								if (last[i][t] == last[j][k + 1])
									break;
							}
							if (t == n)
							{
								last[i][n] = last[j][k + 1];
								n++;
							}
						}
					}
				}
			}
			m++;
		} while (st[i][m] != '\0');
		last[i][n] = '\0';
		last[i][0] = --n;
		lflag[i] = 1;
	}
}

int deal()
{
	int i, j;
	int x, y;
	int z;                                 //輸入串的長度
	k = 1;
	s[k] = '#';                            //棧置初值
	for (i = 0; input[i] != '\0'; i++);    //計算輸入串的長度
	z = i--;
	i = 0;
	while ((a = input[i]) != '\0')
	{
		//j指向最接近棧頂的終極符
		if (Terminator(s[k]))
			j = k;
		else
			j = k - 1;
		x = getIndex(s[j]);//獲取最接近棧頂的終極符在終極符表中位置
		y = getIndex(a);//獲取第一個輸入符號在終極符表中位置
		if (Data[x][y] == '>')//歸約
		{
			out(1, k, s);
			printf("%c", a);
			out(i + 1, z, input);
			printf("規約\n");
			do
			{
				q = s[j];
				if (Terminator(s[j - 1]))
					j = j - 1;
				else j = j - 2;
				x = getIndex(s[j]);
				y = getIndex(q);
			} while (Data[x][y] != '<');
			int m, n, N;
			for (m = j + 1; m <= k; m++)
			{
				for (N = 0; N<r1; N++)
					for (n = 1; In_str[N][n] != '\0'; n++)
					{
						if (!Terminator(s[m]) && !Terminator(In_str[N][n]))
						{
							if (Terminator(s[m + 1]) && Terminator(In_str[N][n + 1])
								&& s[m + 1] == In_str[N][n + 1])
							{
								s[j + 1] = In_str[N][0];
								break;
							}
						}
						else
							if (Terminator(s[m]))
								if (s[m] == In_str[N][n])
								{
									s[j + 1] = In_str[N][0];
									break;
								}
					}
			}
			k = j + 1;
			if (k == 2 && a == '#')
			{
				out(1, k, s);
				printf("%c", a);
				out(i + 1, z, input);
				printf("結束\n");
				printf("\n輸入串符合文法的定義!\n");
				return 1;                               //輸入串符合文法的定義
			}
		}
		else
			if (Data[x][y] == '<' || Data[x][y] == '=')
			{                                                //移進
				out(1, k, s);
				printf("%c", a);
				out(i + 1, z, input);
				printf("移進\n");
				k++;
				s[k] = a;
				i++;
			}
			else
			{
				printf("\n輸入串不符合文法的定義!\n");
				return 0;
			}
	}
	printf("\n輸入串不符合文法的定義!\n");
	return 0;
}

int deal1()
{
	int i, j;
	int x, y;
	int z;                                 //輸入串的長度
	k = 1;
	s[k] = '#';                            //s棧置初值
	str[k]="#";                            //類似str棧置初值
	for (i = 0; input[i] != '\0'; i++);    //計算輸入串的長度
	z = i--;
	i = 0;
	while ((a = input[i]) != '\0')
	{
		//j指向最接近棧頂的終極符
		if (Terminator(s[k]))
			j = k;
		else
			j = k - 1;
		x = getIndex(s[j]);//獲取最接近棧頂的終極符在終極符表中位置
		y = getIndex(a);//獲取第一個輸入符號在終極符表中位置
		if (Data[x][y] == '>')//歸約
		{
			out1(1, k, str);
			printf("%c", a);
			out(i + 1, z, input);
			printf("規約");
			do
			{
				q = s[j];
				if (Terminator(s[j - 1]))
					j = j - 1;
				else j = j - 2;
				x = getIndex(s[j]);
				y = getIndex(q);
			} while (Data[x][y] != '<');
			int m, n, N;
			for (m = j + 1; m <= k; m++)
			{
				for (N = 0; N<r1; N++)
					for (n = 1; In_str[N][n] != '\0'; n++)
					{
						if (!Terminator(s[m]) && !Terminator(In_str[N][n]))
						{
							if (Terminator(s[m + 1]) && Terminator(In_str[N][n + 1])
								&& s[m + 1] == In_str[N][n + 1])
							{
							    //printf("%s",text[N]);
							    //printf("%c%d->%c%d%c%c%d",In_str[N][0],m,s[m],m,s[m+1],s[m+2],m+2);
							    //printf("s[%d]==%c&In_str[%d][%d]==%c&s[%d]==%c&In_str[%d][%d]==%c",m,s[m],N,n,In_str[N][n],m+1,s[m+1],N,n+1,In_str[N][n+1]);
								string avl=str[m];//提前保留還未規約更新的值用於輸出
								s[j + 1] = In_str[N][0];//規約代替例如T->E+P
								charmap[In_str[N][0]]+=1;//利用map存儲記憶該X的下標,例如X1->i
                                ss<<In_str[N][0];//利用ss將char轉換爲string
                                ss<<charmap[In_str[N][0]];//對應數字下標也轉入string方便入棧str
                                str[j+1]=ss.str()+"\0";//str棧內對應s棧一樣壓入對應值,不同點非終結符X加入下標X1
                                ss.str("");//ss清空
								cout<<str[j+1]<<"->"<<avl<<str[m+1]<<str[m+2];//輸出規約對應表達式(推導式)
								stringmap[str[j+1]]=str[j+1];//將轉換對應值用map存儲,例如X1=i或X1=X1那麼stringmap[X1]="i",用於四元組輸出求值
								qua[quaCounts][0]=str[m+1];//存入四元組計算符,例如+
								qua[quaCounts][1]=stringmap[avl];//存入四元組第一個計算數,例如E1
								qua[quaCounts][2]=stringmap[str[m+2]];//存入四元組第二個計算數,例如P1
								qua[quaCounts][3]=stringmap[str[j+1]];//存入四元組計算結果,例如T1
								cout<<"\t\t";
								cout<<"產生【"<<(quaCounts+1)<<"】:";
								cout<<"("+qua[quaCounts][0]+","+qua[quaCounts][1]+","+qua[quaCounts][2]+","+qua[quaCounts][3]+")";//輸出對應直接生成的四元組
								quaCounts++;//四元組數目加一
								goto outer;//直接跳出全部循環
							}
						}
						else{
                            if(Terminator(s[m])&&s[m]=='('&&Terminator(s[m+2])&&s[m+2]==')'){//專門爲T->(E)這種情況而設定
                                if (s[m] == In_str[N][n])
								{
								    //printf("%c%d->%c",In_str[N][0],m,In_str[N][n]);
									string avl=str[m];//提前保留還未規約更新的值用於輸出
									s[j + 1] = In_str[N][0];//規約代替T->(E)
									charmap[s[j + 1]]+=1;//利用map存儲記憶該X的下標,例如X1->i
									ss<<s[j+1];//利用ss將char轉換爲string
									ss<<charmap[s[j + 1]];//對應數字下標也轉入string方便入棧str
									str[j+1]=ss.str()+"\0";//str棧內對應s棧一樣壓入對應值,不同點非終結符X加入下標X1
									ss.str("");//ss清空
									cout<<str[j+1]<<"->"<<avl<<str[m+1]<<str[m+2];//輸出規約對應表達式(推導式)
									stringmap[str[j+1]]=str[j+1];//將轉換對應值用map存儲,例如X1=i或X1=X1那麼stringmap[X1]="i",用於四元組輸出求值
									goto outer;//直接跳出全部循環
								}
                            }
                            else if (Terminator(s[m]))//若爲終結符例如X->i
								if (s[m] == In_str[N][n])
								{
								    //printf("%c%d->%c",In_str[N][0],m,In_str[N][n]);
									s[j + 1] = In_str[N][0];//將終結符i利用X規約代替
									charmap[s[j + 1]]+=1;//利用map存儲記憶該X的下標,例如X1->i
									ss<<s[j+1];//利用ss將char轉換爲string
									ss<<charmap[s[j + 1]];//對應數字下標也轉入string方便入棧str
									str[j+1]=ss.str()+"\0";//str棧內對應s棧一樣壓入對應值,不同點非終結符X加入下標X1
									ss.str("");//ss清空
									cout<<str[j+1]<<"->"<<In_str[N][n];//輸出規約對應表達式(推導式)
									ss<<In_str[N][n];//利用ss將char轉換爲string
									stringmap[str[j+1]]=ss.str();//將轉換對應值用map存儲,例如X1->i那麼stringmap[X1]="i",用於四元組輸出求值
									ss.str("");//ss清空
									goto outer;//直接跳出全部循環
								}
						}
					}
			}
			outer://循環跳出位置
			k = j + 1;//棧頂位置k更新
			printf("\n");//下一行
			if (k == 2 && a == '#')//規約完畢,只剩#X符號
			{
				out1(1, k, str);
				printf("%c", a);
				out(i + 1, z, input);
				printf("結束\n");
				printf("\n輸入串符合文法的定義!\n");
				return 1;                               //輸入串符合文法的定義
			}
		}
		else
			if (Data[x][y] == '<' || Data[x][y] == '=')
			{                                                //移進
				out1(1, k, str);//輸出當前範圍內的棧str
				printf("%c", a);
				out(i + 1, z, input);
				printf("移進\n");
				k++;
				s[k] = a;//移進賦值
				//類似的棧str也對應移進賦值,此處借用ss將char轉換爲string類型
				ss<<a;
				str[k]=ss.str()+"\0";
				ss.str("");//清空ss
				i++;
			}
			else
			{
				printf("\n輸入串不符合文法的定義!\n");
				return 0;
			}
	}
	printf("\n輸入串不符合文法的定義!\n");
	return 0;
}

void out(int j, int k, char *s)
{
	int n = 0;
	int i;
	for (i = j; i <= k; i++)
	{
		printf("%c", s[i]);
		n++;
	}
	for (; n<15; n++)
	{
		printf(" ");
	}
}

void out1(int j, int k, string *str)
{
	int n = 0;
	int i;
	for (i = j; i <= k; i++)//輸出到k位置範圍內的棧str
	{
	    cout<<str[i];
        n=n+str[i].size();
	}
	for (; n<15; n++)//差額空格,水平製表
	{
		cout<<" ";
	}
}

int getIndex(char c)                           //求字符c在文法終極符表中的下標
{
	int i;
	for (i = 0; lable[i] != '\0'; i++)
	{
		if (c == lable[i])
			return i;
	}
	return -1;
}

int Terminator(char c)                            //判斷字符c是否是終極符
{
	int i;
	for (i = 0; lable[i] != '\0'; i++)
	{
		if (c == lable[i])
			return 1;
	}
	return 0;
}

三、結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章