**
算符優先分析程序(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;
附件:
文件中的產生式: