编译原理 词法分析 算符优先分析法
实验目的
加深对语法分析器工作工程的理解,加强对算符优先分析法实现语法分析程序的掌握;能够采用一种编程语言实现简单的语法分析程序;能够使用自己辨析的分析程序对简单的程序段进行语法翻译。
实验环境
Microsoft Visual Studio 2019 Community
思路
首先从文件中读取产生式,并进行分割,将包含“|”的产生式分割成单独的一条产生式。
然后根据产生式求Vt和Vn。先获取每条产生式左侧的字符,这些就是所有的Vn,然后在每条产生式右侧中寻找非Vn的字符,就是Vt。
之后根据求到的Vt和Vn求每个Vn的FIRSTVT集和LASTVT集。每个非终结符在Vn中的下标就是在FIRSTVT集和LASTVT集的横坐标。求FIRSTVT集和LASTVT集需要递归求解。要求FIRSTVT集首先求第一个非终结符,若左侧是该非终结符的产生式的右侧第一个字符是终结符,那么该非终结符的FIRSTVT集就是该终结符;如果右侧第一个字符是非终结符,那么第二个字符一定是终结符,该终结符就属于该非终结符的FIRSTVT集,然后右侧第一个非终结符的FIRSTVT集的元素也属于该非终结符,所以递归求右侧第一个非终结符的FIRSTVT集。LASTVT集也是类似的递归求法。
之后求算符优先关系表,对每条产生式,相邻的终结符之间优先级相同;然后寻找每一个终结符的前面的非终结符,这些非终结符的LASTVT集中的终结符的优先级都大于当前终结符;寻找每一个终结符的后面的非终结符,这些非终结符的FIRSTVT集中的终结符的优先级都大于该终结符。
最后开始分析,若字符串第一个字符为非终结符则直接进栈;否则判断栈内第一个终结符与字符串第一个终结符的优先级,若站内的小于等于字符串的,则直接将字符串第一个终结符压入栈,并将其优先关系压入优先关系栈中;否则开始出栈,若出栈的元素是终结符,则优先关系栈也出栈;直到优先关系栈弹出一个‘<’,然后如果栈顶元素是非终结符还需将栈顶的非终结符出栈。此时出栈结束,压入一个非终结符,并且此次操作没有将字符串字符压入栈,所以不能继续读取下一个字符。当字符串所有元素都读取完毕则完成匹配。
产生式
E→E+T|T
T→T*F|F
F→(E)|i
#pragma once
#include <iostream>
#include <ostream>
#include <stack>
#include <fstream>
#include <vector>
#include <set>
#include <sstream>
using namespace std;
/// <summary>
/// 算符优先分析法词法分析
/// </summary>
class SyntexAnalysis_OperatorPrecedenceParsing
{
static vector<string> productions;//产生式集合
static vector<char> Vn;//非终结符集
static vector<char> Vt;//终结符集
static vector<vector<char>> firstVt;//FIRSTVT集
static vector<vector<char>> lastVt;//LASTVT集
static vector<bool> fished;//标志一个非终结符的FIRSTVT集或LASTVT集是否已经求过,下标与Vn中的下标一一对应
static vector<vector<char>> operatorPrecedenceRelationTable;//算符优先关系表,下标与Vt中的下标一一对应
static void getVtAndVn();
static void readProduction(string fileName);
static int findChar(char ch, vector<char>& v);
static void divideProduction();
static void getFirstVt(char vn);
static void getLastVt(char vn);
static void removeSame(vector<char>& v);
static void initFished();
static void getOperatorPrecedenceRelationTable();
static void resizeVector2(vector<vector<char>>& v, int size);
static void printOperatorPrecedenceRelationTable();
static void printVtSet(vector<vector<char>>& v);
static void printProductions();
static void printV(vector<char>& v);
static void printAll();
static void printStack(stack<char> S);
static void analyse(string str);
public:
static void SyntexAnalyse_OperatorPrecedenceParsing(string str, string fileName);
};
#include "SyntaxAnalysis.h"
using namespace std;
vector<char> SyntexAnalysis_OperatorPrecedenceParsing::Vn;
vector<char> SyntexAnalysis_OperatorPrecedenceParsing::Vt;
vector<string> SyntexAnalysis_OperatorPrecedenceParsing::productions;
vector<vector<char>> SyntexAnalysis_OperatorPrecedenceParsing::firstVt;
vector<vector<char>> SyntexAnalysis_OperatorPrecedenceParsing::lastVt;
vector<bool> SyntexAnalysis_OperatorPrecedenceParsing::fished;
vector<vector<char>> SyntexAnalysis_OperatorPrecedenceParsing::operatorPrecedenceRelationTable;
/// <summary>
/// 从文件读取产生式
/// </summary>
/// <param name="fileName">文件名</param>
void SyntexAnalysis_OperatorPrecedenceParsing::readProduction(string fileName)
{
fstream file(fileName);
while (!file.eof())
{
string s;
file >> s;
productions.push_back(s);
}
file.close();
}
/// <summary>
/// 划分产生式,将包含“|”的产生式划分成单独的一条产生式
/// </summary>
void SyntexAnalysis_OperatorPrecedenceParsing::divideProduction()
{
for (int i = 0; i < productions.size(); i++)
{
for (int j = 0; j < productions[i].length(); j++)
{
if (productions[i][j] == '|')
{
productions.push_back(productions[i].substr(0, 3) + productions[i].substr(j + 1));
productions[i] = productions[i].substr(0, j);
}
}
}
}
/// <summary>
/// 寻找ch在v中的下标,未找到则返回-1
/// </summary>
/// <param name="ch">要查找的字符</param>
/// <param name="v">要查找的向量</param>
/// <returns>ch在v中的下标,未找到返回-1</returns>
int SyntexAnalysis_OperatorPrecedenceParsing::findChar(char ch, vector<char>& v)
{
for (int i = 0; i < v.size(); i++)
{
if (v[i] == ch)
{
return i;
}
}
return -1;
}
/// <summary>
/// 去掉v中重复的元素
/// </summary>
/// <param name="v">要去重的向量</param>
void SyntexAnalysis_OperatorP