自底向上分析语法分析程序设计与实现

自底向上分析语法分析程序设计与实现

一、实验任务及内容

  1. 编制一个文法的输入,从键盘、文件或文本框输入给定文法,依次存入输入缓冲区(字符型数据)。
  2. 编制一个算法,模拟LR(0)分析器的主控流程,实现对给定文法的LR分析。最终生成LR(0)分析表。
  3. 编制程序运行时间控制程序,并作为函数在主控程序调用。

二、实验环境

Windows系统、C++

三、实验的整个实现过程

(1) 本实验使用的数据结构主要有map、set、数组。
(2) 读入文件
首先读入文法文件,将其中的文法存放在productions中,并加入“S’->S”。接着利用productions构造圆点只放置于产生式右部开头的位置的拓广文法,之后构造新状态时会用到该拓广文法中的产生式。
(3) 构造项目集

  • 构造I_0状态
    使用产生式“S’->S”开始(本实验使用星号替代课本中的圆点),扫视能由*后的S能推出的产生式对应的项目,例如S->*A、S->*B。接下来分别以A、B等非终结符扫视,依次类推,直到I_0状态不再增加为止。
  • 构造所有的项目集
    以I_0为基本状态集,对于其中的每一个项目,如果圆点不是项目字符串最后的位置,则以圆点后面的字母作为输入符号,将其加入到新状态中,并将圆点向后移动。如果原点后是非终结符,则将该非终结符能推出的串加入到该新状态中。
    如果此新状态与状态集中的某个状态相同,则删除记录。
    在构造新状态时,记录各个状态之间的转换关系,存放到二维数组中,代表DFA图中的连线。
    (4) 构造Action表与GoTo表
    在这里插入图片描述

根据DFA中记录的状态转换关系,可以很轻松的构造出Action表与GoTo表,使用二维数组存储。

四、完整代码

//!!!!!! 2020.11.26 QLU实验报告,QLUer勿抄袭!!!!!! 
#include <iostream>
#include <time.h>
#include <fstream>
#include <set>
#include <map>
using namespace std;
ifstream input("wenfa.txt");
map<string, set<string> > productions;//读入文件后,存放产生式
map<string, set<string> > project;//在每个产生式右部前面加上点,得到初始项目集
map<int, set<string> > StateSet;//状态
map<int, set<string> > StateSetTemp;
string css_by_order[20];
string link[12][12];//存放各个状态之间的关系
string ActionTable[20][20];
int GoToTable[20][20];
set<string> Vn;
set<string> Vt;
string vn_index[10];
string vt_index[10];

bool isVn(char ch) {
    if (ch >= 'A' && ch <= 'Z') {
        return true;
    } else{
        return false;
    }
}

//得到最初项目集
void getProject() {
    productions["S\'"].insert("S");
    //读入文法文件
    int k = 1;
    string temp;
    while (getline(input, temp)) {
        productions[temp.substr(0,1)].insert(temp.substr(3, temp.length() - 3 +1));
        css_by_order[k++] = temp;
    }
    //构造基本项目集,即圆点位于右部开头的位置
    string dot = "*";
    for(map<string, set<string>>::iterator it = productions.begin(); it != productions.end(); it++) {
        for(set<string>::iterator ij =it->second.begin(); ij != it->second.end(); ij++) {
            string startStr = *ij;
            startStr.insert(0, dot, 0, 1);
            project[it->first].insert(startStr);
        }
    }
}

void Init_I0() {
    StateSet[0].insert("S'->*S");
    //先将所有的左部为S的产生式加入0号状态中
    for(map<string, set<string> >::iterator it = project.begin(); it != project.end(); it++) {
        if ((it->first) == "S") {
            for(set<string>::iterator ij = it->second.begin(); ij != it->second.end(); ij++) {
                StateSetTemp[0].insert(it->first + "->" + *ij);
            }
        }
    }
    //根据I0状态中已知内容,添加后续
    while (! StateSetTemp[0].empty()){
        set<string>::iterator it = StateSetTemp[0].begin();
        string it_str = *it;//暂时集合中的每一条产生式
        //如果点后面是非终结符,在project例找到它能推出来的产生式,加入temp,
        if (isVn(it_str[4])) {
            string after_dot_ch = it_str.substr(4,1);
            for(set<string>::iterator css = project[after_dot_ch].begin(); css != project[after_dot_ch].end(); css++) {
                StateSetTemp[0].insert(after_dot_ch + "->" + *css);
            }
            StateSetTemp[0].erase(it_str);
            StateSet[0].insert(it_str);
        }else if(! isVn(it_str[4])) {
            StateSetTemp[0].erase(it_str);
            StateSet[0].insert(it_str);
        }
    }
}

string MoveDot(string s, int pos) {
    s.erase(pos,1);
    s = s.substr(0, pos+1) + "*" + s.substr(pos+1, s.length()-pos);
    return s;
}

void GenerateState() {
    Init_I0();
    int i = 0;
    int state_num = 0;
    string enter;
    //对于每一个状态
    while (i < StateSet.size()) {
        map<string, set<string>> after_dot_ch;
        //构造该状态中的after_dot_ch的map,first为点后面的字母,即输入字母,second为输入字母为first时的项目
        for (set<string>::iterator it = StateSet[i].begin(); it != StateSet[i].end(); it++) {//对于此状态的每一个项目
            int dot_pos = (*it).find("*");
            if (dot_pos + 1 != (*it).length()) {
                string s = (*it).substr(dot_pos + 1, 1);//点后面的字母
                after_dot_ch[s].insert(*it);
            }
        }
        if (after_dot_ch.size() == 0) {
            i++;
            continue;
        }
        for (map<string, set<string>>::iterator adc = after_dot_ch.begin(); adc != after_dot_ch.end(); adc++) {
            enter = adc->first;
            state_num++;
            for (set<string>::iterator p = adc->second.begin(); p != adc->second.end(); p++) {
                int dot_pos = (*p).find("*");
                string moved_proj = MoveDot(*p, dot_pos);
                int moved_dot_pos = (moved_proj).find("*");
                StateSet[state_num].insert(moved_proj);

                string moved_adc = moved_proj.substr(moved_dot_pos + 1, 1);
                if (isVn(moved_adc[0])) {
                    //如果点移动后的字符串中,点后字母是非终结符,则将以该非终结符开头的project加入该状态
                    for (set<string>::iterator proj_css = project[moved_adc].begin();
                         proj_css != project[moved_adc].end(); proj_css++) {
                        StateSet[state_num].insert(moved_adc + "->" + (*proj_css));
                    }
                }
            }
                //--------判断之前是否有与新产生的状态相等的--------
                bool is_equal = false;
                for (int j = 0; j < state_num; ++j) {
                    if (StateSet[state_num].size() == StateSet[j].size()) {
                        for (set<string>::iterator str = StateSet[j].begin(); str != StateSet[j].end(); str++) {
                            if (StateSet[state_num].count(*str) == 0){
                                break;
                            } else{
                                link[i][j] = enter;
                                is_equal = true;
                            }
                        }
                    }
                }
                if (is_equal == true) {//两个状态全部项目都相等
                    StateSet.erase(state_num);
                    state_num--;
                } else{
                    link[i][state_num] = enter;
                }
                //--------------------------------------------
        }
        i++;
    }
}

void printState() {
    cout << "-------------------------Status--------------------------"<<endl;
    for(map<int, set<string>>::iterator it = StateSet.begin(); it != StateSet.end(); it++) {
        cout << "I_" << it->first << ": ";
        for(set<string>::iterator ij = it->second.begin(); ij != it->second.end(); ij++) {
            cout << *ij << ", ";
        }
        cout << endl;
    }
    cout << "---------------------------------------------------------"<<endl;
}

void printLinkedTable() {
    cout << "============================================DFA================================================"<<endl;
    cout <<  '\t';
    for (int i = 0; i < 11; ++i) {
        cout << i << '\t';
    }
    cout << endl;
    for (int i = 0; i < 11; ++i) {
        cout << i << '\t';
        for (int j = 0; j < 11; ++j) {
                cout << link[i][j] << '\t';
        }
        cout << endl;
    }
}

void getVnandVt() {
    for(map<string, set<string>>::iterator it = productions.begin(); it != productions.end(); it++) {
        string c = it->first;
        if (c != "S'")
            Vn.insert(c);
        for(set<string>::iterator ij = it->second.begin(); ij != it->second.end(); ij++) {
            for (int i = 0; i < (*ij).length(); ++i) {
                if (!isVn((*ij)[i])) {
                    Vt.insert((*ij).substr(i, 1));
                }
            }
        }
    }
    Vt.insert("#");
}

int findIndex(string enter) {
    int pos;
    if (!isVn(enter[0])) {
        for (int k = 0; k < 10; ++k) {
            if (vt_index[k] == enter) {
                pos = k;
                break;
            }
        }
    } else{
        for (int k = 0; k < 10; ++k) {
            if (vn_index[k] == enter) {
                pos = k;
                break;
            }
        }
    }
    return pos;
}

void GenerateAction_Table() {
    //构造Action分析表的行名与列名
    ActionTable[0][0] = "";
    int j = 0;
    set<string>::iterator ij = Vt.begin();
    while (j < Vt.size()) {
        vt_index[j] = *ij;
        ij++; j++;
    }

    //构造Action表
    // ---------移入
    for (int i = 0; i < StateSet.size(); ++i) {
        for (int j = 0; j < StateSet.size(); ++j) {
            if (link[i][j].length() != 0 && (!isVn(link[i][j][0]))) {
                string enter = link[i][j];
                int pos = findIndex(enter);
                ActionTable[i][pos] = "s" + to_string(j);
            }
        }
    }
    // ---------规约
    for (int l = 0; l < StateSet.size(); ++l) {
        if (StateSet[l].size() == 1) {
            set<string>::iterator it = StateSet[l].begin();
            string proj = *it;
            if (proj == "S'->S*") {
                ActionTable[l][findIndex("#")] = "acc";
                continue;
            }
            int dot_pos = proj.find("*");
            if (dot_pos+1 == proj.length()) {
                string no_dot_proj = proj.erase(dot_pos,1);
                //先找到这个项目对应的无点产生式index
                int index = 0;//无点产生式的编号index。第几条产生式
                for (index = 0; index < 20; ++index) {
                    if (css_by_order[index] == no_dot_proj) {
                        break;
                    }
                }
                for (int m = 0; m < Vt.size(); ++m) {
                    ActionTable[l][m] = "r" + to_string(index);
                }
            }
        }
    }
    cout << endl;
    cout << endl;
    cout << "----------------------[Action]---------------------" << endl;
    int m = 0;
    cout << '\t';
    while (vt_index[m].length() != 0) {
        cout << vt_index[m] << '\t';
        m++;
    }
    cout << endl;
    for (int k = 0; k < StateSet.size(); ++k) {
        cout << k << '\t';
        for (int l = 0; l < Vt.size(); ++l) {
            cout << ActionTable[k][l] << '\t';
        }
        cout <<endl;
    }
}

void GenerateGoTo_Table() {
    int i = 0;
    set<string>::iterator it = Vn.begin();
    while (i < Vn.size()) {
        vn_index[i] = *it;
        it++; i++;
    }

    //构造GoTo表
    //在link表中遍历
    for (int i = 0; i < StateSet.size(); ++i) {
        for (int j = 0; j < StateSet.size(); ++j) {
            if ( link[i][j].length() != 0 && isVn(link[i][j][0]) ) {
                string enter = link[i][j];
                int pos = findIndex(enter);
                GoToTable[i][pos] = j;
            }
        }
    }
    cout << endl;
    cout << endl;
    cout << "----------------------[GoTo]---------------------" << endl;
    int m = 0;
    cout << '\t';
    while (vn_index[m].length() != 0) {
        cout << vn_index[m] << '\t';
        m++;
    }
    cout << endl;
    for (int k = 0; k < StateSet.size(); ++k) {
        cout << k << '\t';
        for (int l = 0; l < Vn.size(); ++l) {
            if (GoToTable[k][l] != 0)
                cout << GoToTable[k][l] << '\t';
            else
                cout << '\t';
        }
        cout << endl;
    }
}

int main() {
    clock_t start,end;//定义clock_t变量
    start = clock(); //开始时间

    getProject();
    GenerateState();
    printState();
    printLinkedTable();
    getVnandVt();
    GenerateAction_Table();
    GenerateGoTo_Table();

    //输出时间
    end = clock();   //结束时间
    cout << endl;
    double times = double(end-start)/CLOCKS_PER_SEC;
    cout<<"The Run time = "<<times<<"s" << " = " <<times * 1000 <<"ms" << endl;
    return 0;
}

四、实验结果

实验用例:以文本文件与C++程序放在同一目录下

S->A
S->B
A->aAb
A->c
B->aBb
B->d

实验结果图

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值