日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

大连理工大学软件学院编译原理第四次上机-----非递归语法分析

發布時間:2024/1/1 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大连理工大学软件学院编译原理第四次上机-----非递归语法分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

要求:

  • 使用的文法如下:
    E->TE’
    E’->+TE’|ε
    T->FT’
    T’->*FT’|ε
    F->(E)|id
  • 對于任意給定的輸入串(詞法記號流)進行語法分析,非遞歸預測分析方法可以任選其一來實現。
  • 要有一定的錯誤處理功能。即對錯誤能提示,并且能在一定程度上忽略盡量少的記號來進行接下來的分析。可以參考書上介紹的同步記號集合來處理。
    可能的出錯情況:ididid, id**id, (id+id, +id+id ……
  • 輸入串以#結尾,輸出推導過程中使用到的產生式。例如:
    輸入:id+idid#
    輸出:
    E ->TE ’
    T ->FT’
    F ->id
    E’->+ TE ’
    T -> FT ’
    ……
    如果輸入串有錯誤,則在輸出中要體現是跳過輸入串的某些記號了,還是彈棧,彈出某個非終結符或者是終結符了,同時給出相應的出錯提示信息。比如:
    ididid對應的出錯信息是:“輸入串跳過記號id,用戶多輸入了一個id”;
    id**id對應的出錯信息是:“彈棧,彈出非終結符F,用戶少輸入了一個id”
    (id+id對應的出錯信息是:“彈棧,彈出終結符 ) ,用戶少輸入了一個右括號(或者說,括號不匹配)”
  • 有余力的同學可進一步考慮如下擴展:
    1.在語法分析的過程中調用詞法分析的上機結果,即利用詞法分析器來返回一個記號給語法分析器。
    2.調用求first集合函數。
    編寫Follow函數,實現其求解過程。

    程序說明

    1.本程序采用非遞歸構造預測分析表的方法實現
    2.終結符均采用單個字符(為了尋找終結符和非終結符方便)。處理后的文法如下,其中#代表空串:
    E->TE’
    E’->+TE’|#
    T->FT’
    T’->*FT’|#
    F->(E)|i
    3.程序中并沒有給出FIRST集和FOLLOW集的構造方法,均為提前定義好的集合
    想要用代碼求出FIRST集和FOLLOW集,可以看我的另外一篇文章
    編譯原理------C++實現求First集和Follow集
    4.同步符號(synch)處理存在問題,即第二個測試用例結果不對

    代碼實例及程序解釋

    類定義

    class pre_analysis { public:set<string> productions;//產生式集合map<string,string> split_productions;//分解后的產生式集合set<string>nonfish;//非終結符set<string>finish;//終結符map<string, set<string>> mfirst;//first集map<string, set<string>>mfollow;//follow集map<map<string, string>, string>pretable;//預測分析表:<<非終結符,輸入符號> 值 >void SSS();//將生成式分解成左右兩部分void init();//讀取文件,初始化生成式集合void getpretable();//構造預測分析表void printpretable();//打印預測分析表bool isInFollow(string nonFinish, string a);//判斷一個輸入字符是否在一個非終結符的FOLLOW集合中string matchpretable(string s1, string s2);//查找分析表void analysis(string s);//對輸入串進行分析 };

    初始化內容

    1.讀取存在文件中的產生式,并放入productions中
    2.從產生式中拆分出終結符和非終結符,分別存于finish和nonfish中
    3.構造出產生式的FITSR集和FOLLOW集,分別存于mfirst和mfollow中,本程序采用了直接定義的方式
    找出終結符和非終結符的代碼如下:

    //獲得終結符和非終結符for (set<string>::iterator it = productions.begin(); it != productions.end(); it++) {string temp = *it;for (int i = 0; i < temp.length(); i++) {if (temp[i] == '-' || temp[i] == '>' || temp[i] == '|')continue;//是大寫字母if (temp[i] >= 'A' && temp[i] <= 'Z') {//后面帶'if (temp[i + 1] == '\'') {nonfish.insert(temp.substr(i, 2));i++;}else {nonfish.insert(temp.substr(i, 1));}}//是終結符else{finish.insert(temp.substr(i, 1));}}}

    構造預測分析表

    算法說明:
    如果一個產生式中含有“|”,最好對其進行拆分,然后再進行分析
    (1)對文法的每個產生式A->@ ,執行(2)和(3)。
    (2)對FIRST(@)的每個終結符a,把A ->@ 加入 M[A, a](即加入表中A行a列)。
    (3)如果ε在FIRST(@)中,對FOLLOW(A)的每個終結符b(包括),把A?>@加入M[A,b]。(4)如果FOLLOW(A)的非終結符b(包括), 把A ->@ 加入M[A, b]。 (4)如果FOLLOW(A)的非終結符b(包括,A?>@M[A,b]4FOLLOW(A)b)的表項M[A, b]為空的話,把同步符號sync加入到表項中。
    (4)M的其它沒有定義的條目都是error。
    代碼:

    //構造預測分析表 void pre_analysis::getpretable() {for (map<string,string>::iterator it = split_productions.begin(); it != split_productions.end(); it++) {bool flag = false;if (it->second.find("|") == it->second.npos) {//產生式不含有 |if (mfirst.count(it->first) > 0) {set<string> temp = mfirst[it->first];//找到first集for (set<string>::iterator i = temp.begin(); i != temp.end(); i++) {if (*i == "#") {//如果 # 在first集中flag = true;//把該產生式follow集中的元素加入到分析表set<string> temp_follow = mfollow[it->first];for (set<string>::iterator it_follow = temp_follow.begin(); it_follow != temp_follow.end(); it_follow++) {map<string, string> temppp;temppp[it->first] = *it_follow;pretable[temppp] = it->second;}}else {//如果 # 不在first集中map<string, string>tempp;tempp[it->first] = *i;pretable[tempp] = it->second;}}}}else//產生式含有 |{//處理 |string body = it->second;vector<string> v;istringstream iss(body);string token;while (getline(iss, token, '|')) {v.push_back(token);}for (string s : v) {if (mfirst.count(s) > 0) {set<string> have_temp = mfirst[s];//找到first集for (set<string>::iterator i = have_temp.begin(); i != have_temp.end(); i++) {if (*i == "#") {//如果 # 在first集中flag = true;//把該產生式follow集中的元素加入到分析表set<string> have_temp_follow = mfollow[it->first];for (set<string>::iterator it_follow = have_temp_follow.begin(); it_follow != have_temp_follow.end(); it_follow++) {map<string, string> have_temppp;have_temppp[it->first] = *it_follow;pretable[have_temppp] = "#";}}else {//如果 # 不在first集中map<string, string>have_tempp;have_tempp[it->first] = *i;pretable[have_tempp] = s;}}}}}//如果沒有產生式可以推出空串,將其FOLLOW集添加同步集合if (flag == false) {set<string>no_follow = mfollow[it->first];for (set<string>::iterator i = no_follow.begin(); i != no_follow.end(); i++) {map<string, string>no_follow_tempp;no_follow_tempp[it->first] = *i;pretable[no_follow_tempp] = "synch";}}} }

    寫的很繁瑣,可以對其進行簡化。。。。。。

    根據預測分析表對輸入串進行分析

    算法在代碼中有注釋,就不介紹了,直接上代碼(目前算法是有問題的,希望有大佬可以指正)

    //輸入式子,進行分析 式子以$結尾 void pre_analysis::analysis(string s) {stack<string> S;string content = "nothing";//content內存儲查找預測分析表返回的內容,若分析表為空,content="nothing"S.push("$");S.push("E");//結束符和開始符號入棧cout << "輸入" << s;cout << "分析結果:" << endl;/*1 查表,當前表項空白nothing,指向記號流的指針后移;2 查表,當前表項中含有同步記號synch,輸入串指針后移,知道看到當前非終結符A的FOLLOW(A)中的元素,將當前棧中的非終結符A彈出棧;3 查表,當前表項中含有空串#,將當前棧中非終結符彈出;3 棧頂終結符和當前指針指向的終結符不匹配,將棧頂終結符彈出棧。4 其他,將當前表項反向壓棧;*/for (int i = 0; i < s.length() && !S.empty() ; i++) {content = matchpretable(S.top(), s.substr(i,1));cout << "當前輸入符號為" << s.substr(i, 1) <<" 當前棧頂符號為"<<S.top()<< endl;if (s.substr(i, 1) == "$" && S.top() == "$") {cout << "整個串匹配成功!!!!" << endl;}/*else if (s.substr(i, 1) == "$" && S.top() != "$"){i--;cout << "彈棧,彈出終結符" << endl;while (S.top() != "$") {cout << S.top();S.pop();}cout << ",用戶少輸入這些終結符" << endl;}*/else{if (content == "nothing") {cout << "輸入串跳過記號" << s.substr(i, 1) << "用戶多輸入了一個" << s.substr(i, 1) << endl;}else if (content == "synch") {while (!isInFollow(S.top(),s.substr(i,1))&& i<s.length()){cout << "用戶多輸入" << s.substr(i,1) << endl;i++;}cout << "遇到synch,彈出棧頂非終結符" + S.top() << endl;i--;S.pop();}else {cout << S.top() << "->" << content << endl;//壓棧-彈棧-壓棧,相當于逆序壓棧stack <string>ss;for (int j = 0; j < content.length(); j++) {if (content[j + 1] == '\'') {ss.push(content.substr(j, 2));j++;}else{ss.push(content.substr(j, 1));}}S.pop();while (!ss.empty()){S.push(ss.top());ss.pop();}if (finish.find(S.top()) != finish.end())//當前棧頂為終結符{if (S.top() == "#") {cout << "彈棧,因為棧頂為#" << endl;S.pop();i--;}else if (s.substr(i, 1) == "$") {//棧頂不是 $,但是當前字符是$cout << "彈棧,彈出" << S.top() << "用戶少輸了一個" << S.top() << endl;S.top();i--;}else if (S.top() != s.substr(i, 1))//棧頂終結符不匹配{cout << "彈棧,彈出終結符" << S.top() << "用戶少輸入了" << endl;S.pop();i--;}else if (S.top() == s.substr(i, 1)) //棧頂終結符匹配{cout << "終結符" << S.top() << "匹配成功" << endl;S.pop();}}else{i--;}}}} }

    源程序可以在此進行載//download.csdn.net/download/weixin_41920883/11988047

    總結

    以上是生活随笔為你收集整理的大连理工大学软件学院编译原理第四次上机-----非递归语法分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。