|
吾爱游客
发表于 2018-5-15 11:01
1. 申请ID:钟离绝霞
2. 个人邮箱:1004789224@qq.com
3. 原创技术文章:
LR(1)分析法实验
一个编译原理实验...LR(1)分析法实验,大家如果学过编译原理肯定对LR 分析法印象很深,它很麻烦不是我说直到我写完这个程序才真正理解了LR分析法 .下面分析以下LR分析法
vs2017编译通过
分析表是那个压缩包解压后的.csv文件
// LR分析程序.cpp: 定义控制台应用程序的入口点。
//
#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<fstream>
using namespace std;
struct StackContent {
int state; //状态栏
string sign; //符号栏
};
struct tableContent {
char action; //动作:A 接受, S 移进,R 归约,G 转向
int num; //动作后附加的字数
};
class Production
{
public:
int id; //产生式的编号
string left; //左侧非终结符,为直观起见考虑到有些非终结符是两个字符构成,如 E',以字符串为单位
vector<string> right; //右侧符号串
Production(const string &s) :producerString(s) { //产生式的构造函数
if (s == "")
return;
int i = 1;
if (s[1] == '\'') i++; //以撇号结尾的非终结符
left = s.substr(0, i);
i += 2; //跳过箭头
while (i < s.length())
{
//查双字符(汉字和希腊字母均为双字)
if (i < s.length() - 1) {
string next = s.substr(i, 2);
if (next == "ε") //右侧为空串
{
right.clear();
break;
}
else if (next[1] == '\'') //以撇号结尾的非终结符
{
right.push_back(next);
i += 2;
continue;
}
}
//单个符号
right.push_back(s.substr(i, 1));
i++;
}
}//构造函数
bool operator==(const string &s) {
return producerString == s;
} //比较是否是指定产生式
bool operator!=(const string &s) {
return producerString != s;
} //比较是否是指定产生式
private:
string producerString; //产生式原始字符串
};
class AnalysisTable
{
public:
// 由文本文件创建分析表,文件格式将分析表做成 Excel 文件,然后另存为 CSV 格式文件,箭头使用中文箭头→
bool CreateTable(string filename) {
ifstream fin(filename.c_str());
if (!fin)return false;
table.clear();
const int LINE_LENGTH = 0xff;
char buf[LINE_LENGTH + 1];
vector<string> signs;
vector<string>::size_type i;
while (fin.getline(buf, LINE_LENGTH))
{
vector<string>words = SplitLineOfCVS(buf);
if (!producers.size()) {
for (i = 0; i<words.size(); i++) {
producers.push_back(Production(words));
producers.id = i + 1;
}
continue;
}
if (!signs.size()) {
for (i = 1; i<words.size() && words.length(); i++) {
signs.push_back(words);
}
continue;
}
int state;//当前状态编号
for (i = 0; i<words.size(); i++) {
string word = words;
if (i == 0) {
state = atoi(word.c_str());
continue;
}
string sign = signs[i - 1];
SettableContent(state, sign, word);
}
}
fin.close();
return true;
}
// 根据状态和符号查 LR 分析表,如果是空白(ERROR)的,返回 flase,否则返回 true,并将查到的结果填充到 result 中
bool Lookup(int state, string sign, tableContent &result) {
string key = CreateKey(state, sign.c_str());
map<string, tableContent>::iterator it;
it = table.find(key);
if (it == table.end())return false;
result = it->second;
return true;
}
// 获取指定编号的生成式
const Production &GetProducer(int id) {
return producers[id - 1];
}
private:
vector<string> SplitLineOfCVS(char *s) {
vector<string> result;
char *p = s;
while (*s) {
if (*s == ',') {
*s = '\0';
result.push_back(string(p));
p = s + 1;
}
s++;
}
result.push_back(string(p));
return result;
} //分割 CVS 行
string CreateKey(int state, string sign) {
char buf[50];
sprintf_s(buf, "%04d\%s", state, sign.c_str());//转换为四位整数|符号
return buf;
} //创建表的关键字
void SettableContent(int state, string sign, string content) {
if (content.length() == 0)return;
string key = CreateKey(state, sign);
tableContent tableContent;
if (isdigit(content[0])) {
tableContent.action = 'G';
tableContent.num = atoi(content.c_str());
}
else if (toupper(content[0] == 'A')) {
tableContent.action = 'A';
tableContent.num = 0;
}
else {
tableContent.action = toupper(content[0]);
tableContent.num = atoi(content.c_str() + 1);
}
table[key] = tableContent;
} //设置表的内容
private:
vector<Production> producers; //产生式表
map<string, tableContent> table; //LR 分析表
};
class PushDownStack : public vector<StackContent>
{
public:
void push(int state, string sign) {
StackContent sc; sc.state = state; sc.sign = sign;
vector<StackContent>::push_back(sc);
}
void pop() { vector<StackContent>::pop_back(); }
StackContent top() { return vector<StackContent>::back(); }
};
//下推自动机
class PushDownAutomachine
{
public:
PushDownAutomachine(AnalysisTable &at) : at(at) {}
void AnalyzeSetence(const string &setence) {
stepNum = 0;
readPos = 0;
pds.clear();
outline.clear();
pds.push(0, "#");
instring = setence;
int &i = readPos;
cout << "步骤\t状态栏\t符号栏\t输入串\t输出带\t下步动作\n";
while (i<setence.length()) {
if (pds.empty())return;
int state = pds.top().state;
string a(1, setence);
tableContent result;
if (!at.Lookup(state, a, result)) {
Output("出错");
break;
}
else if (result.action == 'A') {
Output("成功");
break;
}
else if (result.action == 'S') {
Output("移进");
pds.push(result.num, a);
i++;
}
else {
Output("归约");
Production p = at.GetProducer(result.num);
outline.push_back(p.id);
int count = p.right.size();
if (count>pds.size()) {
cout << "分析表错误\n";
break;
}
while (count--)pds.pop();
if (!at.Lookup(pds.top().state, p.left, result)) {
Output("出错");
break;
}
else {
pds.push(result.num, p.left);
}
}
}
} //语法分析
private:
void Output(string nextAction) {
int i;
//输出当前步骤
cout << stepNum++ << "\t";
//输出栈内状态栏的情况
for (i = 0; i < pds.size(); i++) {
if (i > 0) cout << ",";
cout << pds.state;
}
cout << "\t";
//输出栈内符号栏的情况
for (i = 0; i < pds.size(); i++) {
cout << pds.sign;
}
cout << "\t";
//输出输入串情况
for (i = 0; i < instring.length(); i++)
{
if (i < readPos)
cout << " "; //已读过的输出空格
else
cout << instring;
}
cout << "\t";
//输出输出带的情况
for (i = 0; i < outline.size(); i++)
{
if (i > 0) cout << ",";
cout << outline;
}
//输出下一步的动作
cout << "\t" << nextAction << endl;
} //输出分析过程,nextAction 下一步的动作
private:
AnalysisTable & at; //分析表
int stepNum; //步骤数
int readPos; //读头位置
string instring; //输入带
vector<int> outline; //输出带
PushDownStack pds; //下推栈
};
void main()
{
string filename; //文件名
AnalysisTable at; //分析表
PushDownAutomachine pda(at); //下推自动机
cout << "===================================\n";
cout << "| LR 语法分析程序 |\n";
cout << "===================================\n";
while (1)
{
cout << "请输入分析表路径:";
cin >> filename;
if (at.CreateTable(filename))
break; //创建分析表成功
cout << "创建分析表失败,请确认文件格式是符合要求的,路径是正确的。" << endl;
}
string setence; //待分析的句子
while ((cout << "请输入语句(单个\"#\"退出程序):"),
(cin >> setence),
setence != "#")
{
if (setence[setence.length() - 1] != '#')
setence.append("#"); //添加上结束符
pda.AnalyzeSetence(setence);
}
}
|
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|