编译原理实验:自下而上的语法分析---(算符优先分析)

**

算符优先分析程序(NCWU慎用)

**
1.实验要求
⑴ 选择算符优先分析方法;
⑵ 选择对各种常见程序语言都用的语法结构,如赋值语句或表达式或控制流语句等作为分析对象,并且与所选语法分析方法要比较贴切。
⑶ 实验时间为6学时。

2.实验内容及要求
(1)根据给定文法,先求出FirstVt和LastVt集合,构造算符优先关系表(要求算符优先关系表 输出到显示器或者输出到文件);
(2)根据算法和优先关系表分析给定表达式是否是该文法识别的正确的算术表达式(要求输出归约过程)
(3)假如给定表达式文法为:
G(E’): E’→#E#
E→E+T | T
T→T*F |F
F→(E)|i
(4) 分析的句子可为:
(i+i)*i和i+i)*i
3.运行结果:
在这里插入图片描述
在这里插入图片描述
4.源代码:

// Exper2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

static char Vn[50];//记录非终结符
static int len_vn;
static char Vt[50];//记录终结符
static int len_vt;
static string AftSource[50][50];//处理后的产生式,一行一个产生式
static int num[50];//每个产生式有用部分的个数
static int Len_Source;//产生式的个数
static char firstvt[50][50];//记录firstvt集 
static int len_first[50];
static char lastvt[50][50];//记录lastvt集
static int len_last[50];
static char Vt_[50];//加入#号的
static char table[50][50];//记录生成的算符优先关系表



bool IsVn(char c) {//判断该字符为非终结符
	for (int i = 0; i < len_vn; i++) {
		if (c == Vn[i]) {
			return true;
		}
	}
	return false;
}
bool IsVt(char c) {//判断该字符是否为终结符
	if (c == '#') {
		return true;
	}
	for (int i = 0; i < len_vt; i++) {
		if (c == Vt[i]) {
			return true;
		}
	}
	return false;
}

void Pretreatment(string arr[], int n) {//预处理,将产生重新存储,并且将终结符和非终结符分开存放
	for (int i = 0; i < n; i++) {
		Vn[len_vn++] = arr[i][0];
		AftSource[i][num[i]++] = arr[i].substr(0, 1);//将第一个字符存入处理后的数组
		int npc = 3;
		for (int j = 3; j < arr[0].length(); j++) {
			if (arr[i][j] == '|' || arr[i][j] == ';') {
				AftSource[i][num[i]++] = arr[i].substr(npc, j - npc);
				npc = j + 1;
			}
		}
	}
	for (int i = 0; i < Len_Source; i++) {
		for (int j = 1; j < num[i]; j++) {
			for (int k = 0; k < AftSource[i][j].length(); k++) {
				if (!IsVn(AftSource[i][j][k])) {
					Vt[len_vt++] = AftSource[i][j][k];
				}
			}
		}
	}
}

int RepeatFirst(int n, char c) {//判断即将加入的终结符是否已经在firstvt集中了
	for (int i = 0; i < len_first[n]; i++) {
		if (firstvt[n][i] == c) {
			return 0;
		}
	}
	return 1;
}
int RepeatLast(int n, char c) {//判断即将加入的终结符是否已经在lastvt集中了
	for (int i = 0; i < len_last[n]; i++) {
		if (lastvt[n][i] == c) {
			return 0;
		}
	}
	return 1;
}

void FirstVT() {//构造firstvt集
	for (int i = 0; i < len_vn; i++) {//对非终结符进行逐个判断
		string temp = "";
		temp += Vn[i];
		firstvt[i][len_first[i]++] = Vn[i];
		for (int j = 0; j < Len_Source; j++) {
			if (temp._Equal(AftSource[j][0])) {//找出当前非终结符对应的产生式所对应的行
				for (int k = 1; k < num[j]; k++) {
					int len = AftSource[j][k].length();
					if (IsVt(AftSource[j][k][0]) || (IsVn(AftSource[j][k][0]) && AftSource[j][k][0] != Vn[i])) {//开头是终结符   p->a....||  p->Q....则a,Q加入这里Q不是当前非终结符
						if (RepeatFirst(i, AftSource[j][k][0])) {
							firstvt[i][len_first[i]++] = AftSource[j][k][0];
						}
					}
					if (len >= 2 && IsVn(AftSource[j][k][0]) && IsVt(AftSource[j][k][1])) {//p->Qa...   a加入
						if (RepeatFirst(i, AftSource[j][k][1])) {
							firstvt[i][len_first[i]++] = AftSource[j][k][1];
						}
					}
				}
			}
		}
	}
	int flag = 1;
	while (flag) {
		flag = 0;
		for (int i = 0; i < len_vn; i++) {
			char str[50];
			int p = 0;
			for (int j = 1; j < len_first[i]; j++) {
				if (IsVt(firstvt[i][j])) {//当前符号是终结符
					str[p++] = firstvt[i][j];
				}
				else {         //当前符号是非终结符
					for (int k = 0; k < len_vn; k++) {//找出该非终结符的位置
						if (Vn[k] == firstvt[i][j]) {   //k为当前非终结符在表中的行下标
							for (int q = 1; q < len_first[k]; q++) {//将k行中的firstvt集中的元素全部加入i中
								char ch = firstvt[k][q];
								int npc = 1;
								for (int m = 1; m < len_first[i]; m++) {//遍历第i行,去除重复的。
									if (ch == firstvt[i][m]) {
										npc = 0;
										break;
									}
								}
								if (npc == 1) {
									str[p++] = ch;
								}
							}
						}
					}
				}
			}
			for (int j = 0; j < p; j++) {//重新写入i行的first
				firstvt[i][j + 1] = str[j];
			}
			len_first[i] = p + 1;
			if (flag == 0) {
				for (int j = 1; j < len_first[i]; j++) {
					if (IsVn(firstvt[i][j])) {
						flag = 1;
						break;
					}
				}
			}
		}
	}

}
void LastVT() {
	for (int i = 0; i < len_vn; i++) {//对非终结符进行逐个判断
		string temp = "";
		temp += Vn[i];
		lastvt[i][len_last[i]++] = Vn[i];
		for (int j = 0; j < Len_Source; j++) {
			if (temp._Equal(AftSource[j][0])) {
				for (int k = 1; k < num[j]; k++) {
					int len = AftSource[j][k].length();
					if (len >= 2 && IsVn(AftSource[j][k][len - 1]) && IsVt(AftSource[j][k][len - 2])) {//开头是终结符   p->....a||  p->....Q 则a,Q加入这里Q不是当前非终结符
						if (RepeatLast(i, AftSource[j][k][len - 2])) {
							lastvt[i][len_last[i]++] = AftSource[j][k][len - 2];
						}
					}
					else if (IsVt(AftSource[j][k][len - 1]) || (IsVn(AftSource[j][k][len - 1]) && AftSource[j][k][len - 1] != Vn[i])) {//p->...aQ   a加入
						if (RepeatLast(i, AftSource[j][k][len - 1])) {
							lastvt[i][len_last[i]++] = AftSource[j][k][len - 1];
						}
					}
				}
			}
		}
	}
	int flag = 1;
	while (flag) {
		flag = 0;
		for (int i = 0; i < len_vn; i++) {
			char str[50];
			int p = 0;
			for (int j = 1; j < len_last[i]; j++) {
				if (IsVt(lastvt[i][j])) {//当前符号是终结符
					str[p++] = lastvt[i][j];
				}
				else {         //当前符号是非终结符
					for (int k = 0; k < len_vn; k++) {//找出该非终结符的位置
						if (Vn[k] == lastvt[i][j]) {   //k为当前非终结符在表中的行下标
							for (int q = 1; q < len_last[k]; q++) {//将k行中的firstvt集中的元素全部加入i中
								char ch = lastvt[k][q];
								int npc = 1;
								for (int m = 1; m < len_last[i]; m++) {//遍历第i行,去除重复的。
									if (ch == lastvt[i][m]) {
										npc = 0;
										break;
									}
								}
								if (npc == 1) {
									str[p++] = ch;
								}
							}
						}
					}
				}
			}
			for (int j = 0; j < p; j++) {//重新写入i行的first
				lastvt[i][j + 1] = str[j];
			}
			len_last[i] = p + 1;
			if (flag == 0) {
				for (int j = 1; j < len_last[i]; j++) {
					if (IsVn(lastvt[i][j])) {
						flag = 1;
						break;
					}
				}
			}
		}
	}
}

void PrinFirst() {
	for (int i = 0; i < len_vn; i++) {
		cout << "Firstvt(" << firstvt[i][0] << "):";
		for (int j = 1; j < len_first[i]; j++) {
			cout << firstvt[i][j] << " ";
		}
		cout << endl;
	}
}
void PrinLast() {
	for (int i = 0; i < len_vn; i++) {
		cout << "Lastvt(" << lastvt[i][0] << "):";
		for (int j = 1; j < len_last[i]; j++) {
			cout << lastvt[i][j] << " ";
		}
		cout << endl;
	}
}
void PrintTable() {//输出算符优先关系表
	for (int i = 0; i < len_vt + 1; i++) {
		cout << "\t" << Vt_[i];
	}
	cout << endl;
	for (int i = 0; i < len_vt + 1; i++) {
		cout << Vt_[i];
		for (int j = 0; j < len_vt + 1; j++) {
			cout << "\t" << table[i][j];
		}
		cout << endl;
	}
}

void Init() {//对Vt数组增加# 生成Vt_数组  在构建算符优先分析表中用到
	int i;
	for (i = 0; i < len_vt; i++) {
		Vt_[i] = Vt[i];
	}
	Vt_[i] = '#';
}
int FindSub(char c) {//寻找某个终结符在数组里面对应的下标
	for (int i = 0; i < len_vt + 1; i++) {
		if (Vt_[i] == c) {
			return i;
		}
	}
	return -1;//#的下标
}
void CreateTable() {//构建算符优先分析表
	Init();
	AftSource[Len_Source][num[Len_Source]++] = "E'";
	AftSource[Len_Source][num[Len_Source]++] = "#";
	AftSource[Len_Source][num[Len_Source] - 1] += AftSource[0][0];
	AftSource[Len_Source][num[Len_Source] - 1] += '#';
	Len_Source++;
	for (int i = 0; i < Len_Source; i++) {//遍历每条产生式
		for (int j = 1; j < num[i]; j++) {//遍历每条产生式中的每个生成式
			int len = AftSource[i][j].length();
			for (int k = 0; k < len - 1; k++) {//遍历每个生成式中的每个元素
				if (IsVt(AftSource[i][j][k]) && IsVt(AftSource[i][j][k + 1])) {//Xi和Xi+1都是终结符P->...ab...
					int x = FindSub(AftSource[i][j][k]);
					int y = FindSub(AftSource[i][j][k + 1]);
					table[x][y] = '=';
				}
				if (k <= len - 3 && IsVt(AftSource[i][j][k]) && IsVt(AftSource[i][j][k + 2]) && IsVn(AftSource[i][j][k + 1])) { //P->..aQb..
					int x = FindSub(AftSource[i][j][k]);
					int y = FindSub(AftSource[i][j][k + 2]);
					table[x][y] = '=';
				}
				if (IsVt(AftSource[i][j][k]) && IsVn(AftSource[i][j][k + 1])) {//p->..aQ.. 则 a < firstvt(Q)
					int x = FindSub(AftSource[i][j][k]);
					for (int m = 0; m < len_vn; m++) {
						if (firstvt[m][0] == AftSource[i][j][k + 1]) {//找到非终结符Xi+1对应的位置
							for (int n = 1; n < len_first[m]; n++) {//遍历该firstvt集中的每个元素
								int y = FindSub(firstvt[m][n]);
								table[x][y] = '<';
							}
							break;
						}
					}
				}
				if (IsVn(AftSource[i][j][k]) && IsVt(AftSource[i][j][k + 1])) {//p->..Qa..  则lastvt(Q) > a
					int x = FindSub(AftSource[i][j][k + 1]);
					for (int m = 0; m < len_vn; m++) {
						if (lastvt[m][0] == AftSource[i][j][k]) {
							for (int n = 1; n < len_last[m]; n++) {
								int y = FindSub(lastvt[m][n]);
								table[y][x] = '>';
							}
							break;
						}
					}
				}
			}
		}
	}
}

char Judge(string temp) {
	for (int r = 0; r < Len_Source; r++) {
		for (int s = 1; s < num[r]; s++) {
			if (temp.length() == AftSource[r][s].length()) {//保证可规约串与 产生式里的式子长度相等
				for (int h = 0; h < temp.length(); h++) {
					if (temp[h] == AftSource[r][s][h] && IsVt(temp[h])) {
						return AftSource[r][0][0];
					}
				}
			}
		}
	}
}

void Analysis(string str) {//算符优先分析
	int Len = str.length();
	string stack = "#";
	int k = 1;//记录栈顶元素
	char a;//记录输入缓冲区最前面的元素
	int j;
	int i = 0;
	int tap = 0;
	cout << "步骤\t\t" << "符号栈\t\t" << "输入串\t\t" << "动作\n\n";
	cout << tap++ << "\t\t" << stack << "\t\t" << str << "\t" << "预备\n";
	do {
		a = str[i];
		if (IsVt(stack[k - 1])) {
			j = k - 1;
		}
		else {
			j = k - 2;
		}
		int x = FindSub(stack[j]);
		int y = FindSub(a);
		while (table[x][y] == '>') {//归约
			int m, n;
			do {
				char Q = stack[j];
				if (IsVt(stack[j - 1])) {
					j = j - 1;
				}
				else {
					j = j - 2;
				}
				m = FindSub(stack[j]);
				n = FindSub(Q);
			} while (table[m][n] != '<');
			string temp = stack.substr(j + 1, k - j - 1);
			char ch = Judge(temp);//判断归约后的符号
			stack.erase(j + 1, k - 1);
			k = j + 1;
			stack += ch;
			k++;//入栈后栈的长度还得+1,
			x = FindSub(stack[j]);//这里的x更换了
			cout << tap++ << "\t\t" << stack << "\t\t" << str.substr(i, Len - i) << "\t\t" << "归约\n";
			//cout << stack << endl;
		}
		if ((table[x][y] == '<' || table[x][y] == '=') && a != '#') { //移进操作
			stack += a;
			k++;
			i++;
			cout << tap++ << "\t\t" << stack << "\t\t" << str.substr(i, Len - i) << "\t\t" << "移进\n";
		}
		else if (a != '#') {//错误
			cout << "error" << endl;
			return;
		}
	} while (a != '#');
	cout << tap++ << "\t\t" << stack << "\t\t" << str.substr(i, Len - i) << "\t\t" << "接受\n";
}

int main() {
	static string BefSource[100];
	ifstream infile("Source.txt");
	if (!infile)
		cout << "error" << endl;
	int Len = 0;
	while (infile.good()) {
		getline(infile, BefSource[Len++]);
	}
	cout << "==========从文件中读取到的产生式==========\n" << endl;
	for (int i = 0; i < Len; i++) {
		cout << BefSource[i] << endl;
	}
	Len_Source = Len;
	Pretreatment(BefSource, Len);//预处理
	FirstVT();
	LastVT();
	cout << "\n==========firstVt集==========\n" << endl;
	PrinFirst();
	cout << "\n==========LastVt集==========\n" << endl;
	PrinLast();
	CreateTable();
	cout << "\n==========算符优先关系表==========\n" << endl;
	PrintTable();

	string str;
	cout << "\n==========请输入要分析的句子:==========" << endl;
	cin >> str;
	cout << "\n==========分析步骤==========\n" << endl;
	Analysis(str);
	return 0;
}

//E->E+T|T;
//T->T*F|F;
//F->P!F|P;
//P->(E)|i;

附件:
文件中的产生式:
在这里插入图片描述

  • 13
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
算符优先分析法是一种自下而上语法分析方法,它可以用于分析和处理算术达式、布尔达式等。下面是算符优先分析法的实现步骤: 1. 定义终结符和非终结符:终结符是指不能再分解的基本符号,如数字、运算符等;非终结符是指可以分解成其他符号的符号,如达式、语句等。 2. 定义运算符之间的优先关系和结合性质:将运算符按照优先级从高到低排列,相同优先级的运算符再按照结合性质(左结合或右结合)进行排列。 3. 构造算符优先关系:根据定义的运算符优先关系和结合性质,构造算符优先关系中的行和列分别示两个相邻的运算符,中的元素示它们之间的优先关系(“<”示优先级低,“>”示优先级高,“=”示优先级相等)。 4. 进行语法分析:将输入的达式转换成一个个终结符和非终结符的序列,然后根据算符优先关系进行分析。具体地,从左到右扫描输入序列,将扫描到的符号压入栈中,同时比较栈顶符号和下一个输入符号之间的优先关系,如果栈顶符号的优先级低于或等于下一个输入符号的优先级,则将下一个输入符号压入栈中;否则,从栈中弹一个或多个符号进行归约,直到栈顶符号的优先级低于或等于下一个输入符号的优先级。 5. 进行达式求值:在进行归约时,如果遇到两个相邻的终结符之间有一个运算符,则可以对它们进行求值,并将结果压入栈中。最终,栈中只剩下一个值,即为达式的值。 下面是一个简单的算符优先分析法的实现例子,用于分析和处理四则运算达式: ```python # 定义终结符和非终结符 terminals = ['+', '-', '*', '/', '(', ')', 'num'] non_terminals = ['E', 'T', 'F'] # 定义运算符之间的优先关系和结合性质 precedence = { '+': {'+': '>', '-': '>', '*': '<', '/': '<', '(': '<', ')': '>', 'num': '<'}, '-': {'+': '>', '-': '>', '*': '<', '/': '<', '(': '<', ')': '>', 'num': '<'}, '*': {'+': '>', '-': '>', '*': '>', '/': '>', '(': '<', ')': '>', 'num': '<'}, '/': {'+': '>', '-': '>', '*': '>', '/': '>', '(': '<', ')': '>', 'num': '<'}, '(': {'+': '<', '-': '<', '*': '<', '/': '<', '(': '<', ')': '=', 'num': '<'}, ')': {'+': '>', '-': '>', '*': '>', '/': '>', '(': ' ', ')': '>', 'num': ' '}, 'num': {'+': '>', '-': '>', '*': '>', '/': '>', '(': ' ', ')': '>', 'num': ' '} } # 构造算符优先关系 table = {} for i in range(len(terminals)): table[terminals[i]] = {} for j in range(len(terminals)): table[terminals[i]][terminals[j]] = precedence[terminals[i]][terminals[j]] # 进行语法分析 def parse(expr): stack = ['#'] tokens = expr.split() for token in tokens: while table[stack[-1]][token] == '>': op = stack.pop() if op in ['+', '-', '*', '/']: b = stack.pop() a = stack.pop() stack.append(str(eval(a + op + b))) else: stack.pop() if table[stack[-1]][token] == '<' or table[stack[-1]][token] == '=': stack.append(token) else: raise ValueError('Invalid expression') while stack[-1] != '#': op = stack.pop() if op in ['+', '-', '*', '/']: b = stack.pop() a = stack.pop() stack.append(str(eval(a + op + b))) else: raise ValueError('Invalid expression') return stack[0] # 进行达式求值 expr = '3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3' result = parse(expr) print(result) # 输:3.0001220703125 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_码到成功_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值