編譯原理簡單的LALR(1)分析表的構造
閒著無聊,,,,寫了一個簡單的LALR(1)分析表的構造,就當是複習了
#include <cstdio> #include <cstring> #include <map> #include <vector> #include <queue> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f /* 1、輸入文法,對非終結符和終結符進行對映 2、求出非終結符的FIRST集 3、求專案集的閉包函式(向前搜尋符) 4、求GO函式 5、LR(1)分析表 6、合併LR(1)分析表內的同心專案集 7、LALR(1)分析表 8、輸入串分析 注意: 1、輸入產生式不超過100條 2、'@'代表空 3、'$'代表增加產生式$->S,拓廣文法 4、終結符和非終結符的個數都不超過20 5、專案集不超過100 */ struct grammar{ char vn, s[10];//產生式vn->s[10] }g[100]; int g_num;//記錄產生式的個數 map<char, int> vn_map;//對非終結符進行對映 map<char, int> vt_map;//對終結符進行對映 int vn_num, vt_num;//記錄非終結符和終結符的個數 char vn[20], vt[20];//儲存非終結符和終結符的值 int first[20][20];//fisrt[i][j]代表非終結符vn[i]的first集包含終結符vt[j] struct project{ grammar g;//產生式 int k, pre[20];//空格點位置k,向前搜尋符pre }; vector<project> closure[100];//專案集 int closure_num;//專案集的個數 struct Edge{ int u, v; int next; char ch; }edge[1000];//專案集closure[u]由條件ch轉換為專案集closure[v] int go[100];//GO函式頭指標 int edge_num;//轉換條件數目 int belong[100];//合併專案集後的歸屬 int merge_num;//合併後項目集的個數 int lalr1_action[100][20], lalr1_goto[100][20];//LALR(1)分析表的action和goto表 /* 讀入文法G 控制輸入格式 擴廣文法 對非終結符和終結符進行對映 */ void read() { printf("請輸入文法G,'@'代表空\n"); printf("直接輸入'@'輸入結束\n"); g_num = 0; int i, j, len, flag; char ch, str[20]; grammar temp; while( gets(str) ) { if( str[0] == '@' ) break; len = strlen(str); flag = 0; if( len < 4 ) flag = 1; else if( str[0] < 'A' || str[0] > 'Z' || str[1] != '-' || str[2] != '>' ) flag = 1; else { temp.vn = str[0]; for(i = 3; i < len; i++) { if( str[i] == ' ' ) break; temp.s[i-3] = str[i]; } temp.s[i-3] = '\0'; if( i < len ) flag = 1; } if( flag ) { printf("產生式%s不符合文法規則,已忽略。\n", str); continue ; } else { g[ ++g_num ] = temp; } } if( g_num == 0 ) { printf("未成功輸入產生式\n"); return; } printf("輸入完成,共輸入%d條產生式\n", g_num); g[0].vn = '$'; g[0].s[0] = g[1].vn; g[0].s[1] = '\0'; printf("拓廣文法:%c->%s\n", g[0].vn, g[0].s); for(i = 1; i <= g_num; i++) { printf("\t %c->%s\n", g[i].vn, g[i].s); } vn_num = vt_num = 0; if( vt_map['@'] == 0 ) { vt_map['@'] = ++vt_num; vt[vt_num] = '@'; } for(i = 0; i <= g_num; i++) { ch = g[i].vn; if( vn_map[ch] == 0 ) { vn_map[ch] = ++vn_num; vn[vn_num] = ch; } len = strlen( g[i].s ); for(j = 0; j < len; j++) { ch = g[i].s[j]; if( ch >= 'A' && ch <= 'Z' ) continue; if( vt_map[ch] == 0 ) { vt_map[ch] = ++vt_num; vt[vt_num] = ch; } } } if( vt_map['#'] == 0 ) { vt_map['#'] = ++vt_num; vt[vt_num] = '#'; } for(i = 1, printf("非終結符:\n"); i <= vn_num; i++) { printf("%c -> %d\n", vn[i], vn_map[ vn[i] ]); } for(i = 1, printf("終結符:\n"); i <= vt_num; i++) { printf("%c -> %d\n", vt[i], vt_map[ vt[i] ]); } return; } /* 求first集 solve_fisrt()求出所有的非終結符的first集 dfs(char ch)求非終結符ch的first集 */ void dfs(char ch,int acc[],int vis[],int val[]) { int i, j, k, c = vn_map[ch]; if( acc[c] ) { for(i = 1; i <= vt_num; i++) val[i] = first[c][i]; return; } int value[20]; memset(value,0,sizeof(value)); for(i = 0; i <= g_num; i++) { if( vis[i] ) continue; vis[i] = 1; if( g[i].vn != ch ) continue; int len = strlen( g[i].s ); for(j = 0; j < len; j++) { char sh = g[i].s[j]; if( vn_map[sh] ) { dfs(sh,acc,vis,value); for(k = 2; k <= vt_num; k++) { if( value[k] ) val[k] = 1; } if( value[1] == 0 ) break; } else { c = vt_map[sh]; val[c] = 1; break; } } if( j == len ) val[1] = 1; } return; } void solve_first() { int acc[20], vis[20], value[20]; int i, j, k; memset(first,0,sizeof(first)); memset(acc,0,sizeof(acc)); for(i = 1; i <= vn_num; i++) { if( acc[i] ) continue; memset(vis,0,sizeof(vis)); memset(value,0,sizeof(value)); dfs(vn[i],acc,vis,value); for(j = 1; j <= vt_num; j++) first[i][j] = value[j]; acc[i] = 1; } printf("輸出first集\n"); printf("\t"); for(i = 1; i <= vt_num; i++) printf("%c\t", vt[i]); printf("\n"); for(i = 1; i <= vn_num; i++) { printf("%c\t", vn[i]); for(j = 1; j <= vt_num; j++) printf("%d\t", first[i][j]); printf("\n"); } return; } /* 求解閉包函式/go函式 newproject()獲得一個新的專案 solve_closure()求專案集的閉包 solve_projects()求所有的專案集 */ int Equal(grammar u,grammar v) { if( u.vn != v.vn ) return 0; if( !strcmp(u.s,v.s) ) return 1; return 0; } int Equal(project u,project v) { if( !Equal(u.g,v.g) ) return 0; if( u.k != v.k ) return 0; for(int i = 1; i <= vt_num; i++) if( u.pre[i] != v.pre[i] ) return 0; return 1; } int Equal(int x,int y) { int i, j; if( closure[x].size() != closure[y].size() ) return 0; for(i = 0; i < closure[x].size(); i++) { project u = closure[x][i]; for(j = 0; j < closure[y].size(); j++) { project v = closure[y][j]; if( Equal(u,v) ) break; } if( j == closure[y].size() ) break; } if( i == closure[x].size() ) return 1; return 0; } project newproject() { project temp; memset(temp.pre,0,sizeof(temp.pre)); return temp; } int addproject(project temp,int c) { for(int i = 0; i < closure[c].size(); i++) { project old = closure[c][i]; if( Equal(old.g,temp.g) && old.k == temp.k ) return i; } return -1; } int solve_closure(int c){ int i, j, k, l; for(i = 0; i < closure[c].size(); i++) { project old = closure[c][i]; int len = strlen( old.g.s ); if( old.k == len ) continue; char vn = old.g.s[ old.k ]; if( vt_map[vn] ) break; for(j = 0; j <= g_num; j++) { if( g[j].vn != vn ) continue; //得到新新增專案temp project temp = newproject(); temp.g = g[j]; temp.k = 0; //排除S->
[email protected]的情況 for(k = 0; k < strlen( g[j].s ); k++) { if( g[j].s[k] == '@' ) temp.k++; else break; } char ch = old.g.s[old.k+1]; if( ch == '\0' ) { for(k = 1; k <= vt_num; k++) temp.pre[k] = old.pre[k]; } else if( vn_map[ch] ) { for(k = 1; k <= vt_num; k++) temp.pre[k] = first[ vn_map[ch] ][k]; } else temp.pre[ vt_map[ch] ] = 1; //判斷temp是否已經存在在專案集中 int flag = addproject(temp,c); if( flag == -1 ) closure[c].push_back(temp); else { for(k = 1; k <= vt_num; k++) if( temp.pre[k] ) closure[c][flag].pre[k] = 1; } } } //完成新的專案集closure[c],判斷是否出現過 for(i = 1; i < c; i++) { if( Equal(i,c) ) return i; } return c; } void addedge(int u,int v,char ch) {//設定GO函式的邊 edge[edge_num].u = u; edge[edge_num].v = v; edge[edge_num].ch = ch; edge[edge_num].next = go[u]; go[u] = edge_num++; } void solve_projects() { project temp = newproject(); //初始化專案集,僅包含g[0],向前搜尋符包含'#' closure_num = 0; temp.g = g[0]; temp.k = 0; temp.pre[ vt_map['#'] ] = 1; closure[closure_num+1].clear(); closure[closure_num+1].push_back(temp); int c = solve_closure(closure_num+1); if( c == closure_num+1 ) { closure_num++; } int i, j, k; //求GO函式 memset(go,-1,sizeof(go)); edge_num = 0; for(i = 1; i <= closure_num; i++) { //測試專案集輸出 printf("專案集%d包含:\n", i); for(j = 0; j < closure[i].size(); j++) { project old = closure[i][j]; printf("\t%c->", old.g.vn); for(k = 0; k <= strlen( old.g.s ); k++) { if( k == old.k ) printf("."); printf("%c", old.g.s[k]); } printf("\t"); for(k = 1; k <= vt_num; k++) if( old.pre[k] ) printf("%c ", vt[k]); printf("\n"); } //求GO函式 int vis[100]; memset(vis,0,sizeof(vis)); for(j = 0; j < closure[i].size(); j++) { if( vis[j] ) continue; project old = closure[i][j]; int len = strlen(old.g.s); if( old.k == len ) continue; closure[ closure_num+1 ].clear(); for(k = j; k < closure[i].size(); k++) { project oldd = closure[i][k]; if( oldd.g.s[ oldd.k ] == old.g.s[ old.k ] ) { vis[k] = 1; project temp = oldd; temp.k++; closure[ closure_num+1 ].push_back(temp); } } if( closure[ closure_num+1 ].size() == 0 ) continue; c = solve_closure(closure_num+1); if( c == closure_num+1 ) { closure_num++; } addedge(i,c,old.g.s[ old.k ]); } } return; } /* 輸出LR(1)分析表 所有狀態從1到closure_num lr1_action中非負數i代表第i個產生式,負數-i代表狀態i lr1_goto中負數-i代表狀態i */ int findgrammar(grammar temp) { for(int i = 0; i <= g_num; i++) { if( Equal(temp,g[i]) ) return i; } } void printLR1() { int flag = 0; int lr1_action[100][20], lr1_goto[100][20]; memset(lr1_action,INF,sizeof(lr1_action)); memset(lr1_goto,INF,sizeof(lr1_goto)); int i, j, k; for(i = 1; i <= closure_num; i++) { for(j = 0; j < closure[i].size(); j++) { project old = closure[i][j]; char ch = old.g.s[ old.k ]; int c = findgrammar(old.g); if( ch == '\0' ) { for(k = 1; k <= vt_num; k++) { if( old.pre[k] ) { if( lr1_action[i][k] == INF || lr1_action[i][k] == c ) lr1_action[i][k] = c; else flag = 1; } } } } for(j = go[i]; j != -1; j = edge[j].next) { int u = edge[j].u, v = edge[j].v; char ch = edge[j].ch; if( vn_map[ch] ) { if( lr1_goto[u][ vn_map[ch] ] == INF || lr1_goto[u][ vn_map[ch] ] == -v ) lr1_goto[u][ vn_map[ch] ] = -v; else flag = 1; } else { if( lr1_action[u][ vt_map[ch] ] == INF || lr1_action[u][ vt_map[ch] ] == -v ) lr1_action[u][ vt_map[ch] ] = -v; else flag = 1; } } } if( flag ) { printf("出現衝突,該文法不是LR(1)文法\n"); return; } printf("LR(1)分析表:\n"); printf("狀態\t"); for(i = 1; i <= vt_num; i++) printf("%c\t", vt[i]); for(i = 1; i <= vn_num; i++) printf("%c\t", vn[i]); printf("\n"); for(i = 1; i <= closure_num; i++) { printf("%d\t", i); for(j = 1; j <= vt_num; j++) { k = lr1_action[i][j]; if( k == INF ) printf("\t"); else if( k < 0 ) printf("S%d\t", -k); else printf("r%d\t", k); } for(j = 1; j <= vn_num; j++) { k = lr1_goto[i][j]; if( k == INF ) printf("\t"); else if( k < 0 ) printf("%d\t", -k); else printf("r%d\t", k); } printf("\n"); } return ; } /* 合併同心專案集 */ int Equalproject(int x,int y) { if( closure[x].size() != closure[y].size() ) return 0; int i, j, k; for(i = 0; i < closure[x].size(); i++) { project u = closure[x][i]; for(j = 0; j < closure[y].size(); j++) { project v = closure[y][j]; if( u.k == v.k && Equal(u.g,v.g) ) break; } if( j == closure[y].size() ) return 0; } return 1; } void project_merge() { int i, j, k; merge_num = 0;//num表示合併後的狀態編號索引 int vis[100]; memset(vis,0,sizeof(vis)); for(i = 1; i <= closure_num; i++) { if( vis[i] ) continue; belong[i] = ++merge_num; vis[i] = 1; for(j = i+1; j <= closure_num; j++) { if( Equalproject(i,j) ) { belong[j] = merge_num; vis[j] = 1; } } } printf("專案集合並:\n"); for(i = 1; i <= merge_num; i++) { printf("新專案集%d包含專案集:", i); for(j = 1; j <= closure_num; j++) if( belong[j] == i ) printf("%d ", j); printf("\n"); } } /* 構造LALR(1)分析表 */ void solve_lalr1() { int flag = 0; memset(lalr1_action,INF,sizeof(lalr1_action)); memset(lalr1_goto,INF,sizeof(lalr1_goto)); int i, j, k; for(i = 1; i <= closure_num; i++) { for(j = 0; j < closure[i].size(); j++) { project old = closure[i][j]; char ch = old.g.s[ old.k ]; int c = findgrammar(old.g); if( ch == '\0' ) { for(k = 1; k <= vt_num; k++) { if( old.pre[k] ) { if( lalr1_action[ belong[i] ][k] == INF || lalr1_action[ belong[i] ][k] == c ) lalr1_action[ belong[i] ][k] = c; else flag = 1; } } } } for(j = go[i]; j != -1; j = edge[j].next) { int u = belong[edge[j].u], v = belong[edge[j].v]; char ch = edge[j].ch; if( vn_map[ch] ) { if( lalr1_goto[u][ vn_map[ch] ] == INF || lalr1_goto[u][ vn_map[ch] ] == -v ) lalr1_goto[u][ vn_map[ch] ] = -v; else flag = 1; } else { if( lalr1_action[u][ vt_map[ch] ] == INF || lalr1_action[u][ vt_map[ch] ] == -v ) lalr1_action[u][ vt_map[ch] ] = -v; else flag = 1; } } } if( flag ) { printf("出現衝突,該文法不是LALR(1)文法\n"); return; } printf("LALR(1)分析表:\n"); printf("狀態\t"); for(i = 1; i <= vt_num; i++) printf("%c\t", vt[i]); for(i = 1; i <= vn_num; i++) printf("%c\t", vn[i]); printf("\n"); for(i = 1; i <= merge_num; i++) { printf("%d\t", i); for(j = 1; j <= vt_num; j++) { k = lalr1_action[i][j]; if( k == INF ) printf("\t"); else if( k < 0 ) printf("S%d\t", -k); else printf("r%d\t", k); } for(j = 1; j <= vn_num; j++) { k = lalr1_goto[i][j]; if( k == INF ) printf("\t"); else if( k < 0 ) printf("%d\t", -k); else printf("r%d\t", k); } printf("\n"); } return ; } /* 對輸入串進行匹配 當產生式S->@,不需要符號棧退出字元 */ void solve_str() { printf("請輸入輸入串:\n"); char str[100]; int step = 0, sta[100]; char sym[100]; int sta_num = 0, sym_num = 0; sta[sta_num++] = 1; sym[sym_num++] = '#'; int i, j, k, len; scanf("%s", str); len = strlen(str); printf("步驟\t狀態棧\t符號棧\t輸入串\tACTION\tGOTO\t\n"); k = 0; while(k < len) { printf("%d\t", ++step); for(i = 0; i < sta_num; i++) printf("%d", sta[i]); printf("\t"); for(i = 0; i < sym_num; i++) printf("%c", sym[i]); printf("\t"); for(i = k; i < len; i++) printf("%c", str[i]); printf("\t"); if( sta_num == 0 ) { printf("狀態棧為空,錯誤\n"); break; } int x = sta[ sta_num-1 ]; int y = vt_map[ str[k] ]; int c = lalr1_action[x][y]; if( c == INF ) { printf("ACTION函式為空,錯誤\n"); break; } if( c < 0 ) { sta[ sta_num++ ] = -c; sym[ sym_num++ ] = str[k++]; printf("S%d\t\t", -c); } else { if( c == 0 ) { printf("acc\n"); break; } for(i = 0; i < strlen(g[c].s); i++) { if( g[c].s[i] != '@' ) { sym_num--; sta_num--; } } if( sym_num < 0 || sta_num < 0 ) { printf("歸約失敗\n"); break; } sym[ sym_num++ ] = g[c].vn; x = sta[ sta_num-1 ]; y = vn_map[ g[c].vn ]; if( lalr1_goto[x][y] == INF ) { printf("GO函式為空,錯誤\n"); } sta[ sta_num++ ] = -lalr1_goto[x][y]; printf("r%d\t%d\t", c, -lalr1_goto[x][y]); } printf("\n"); } return; } int main() { freopen("in2.txt","r",stdin); read();//讀入文法G(S) solve_first();//求非終結符的first集 solve_projects();//求閉包函式,go函式 printLR1();//輸出LR(1)分析表 project_merge();//合併同心專案集 solve_lalr1();//計算LALR(1)分析表 solve_str();//輸入串處理 return 0; }
相關推薦
編譯原理簡單的LALR(1)分析表的構造
閒著無聊,,,,寫了一個簡單的LALR(1)分析表的構造,就當是複習了 #include <cstdio> #include <cstring> #include <map> #include <vector> #includ
《編譯原理》LR 分析法與構造 LR(1) 分析表的步驟 - 例題解析
《編譯原理》LR 分析法與構造 LR(1) 分析表的步驟 - 例題解析 筆記 直接做題是有一些特定步驟,有技巧。但也必須先了解一些基本概念,本篇會通過例題形式解釋概念,會容易理解和記憶,以及解決類似問題。 如果只想做題可以直接下拉至習題部分。 (一)關於狀態 對於產生式 A→aBcD,就可以分解為下面幾個不同
編譯原理根據專案集規範族構造LR(0)分析表
上回把文法的LR(0)專案集規範族搞了半天,革命進行了一半。 鼓搗了半天整了一堆專案集規範族出來,總是有用的呀,接下來就是在那堆的基礎上構造分析表了,構造好分析表就能分析輸入串了。本文主要講LR(0)分析表的構造和輸入串分析過程。 我這個菜雞都覺得是通!俗!易!懂!的!! 憋說話往下
編譯原理:LL(1)文法 語法分析器(預測分析表法)
設計要求:對於任意輸入的一個LL(1)文法,構造其預測分析表,並對指定輸入串分析其是否為該文法的句子。思路:首先實現集合FIRST(X)構造演算法和集合FOLLOW(A)構造演算法,再根據FIRST和F
編譯原理之LL(1) 、LR(0)、SLR、LR(1)、LALR文法的對比
考完編譯原理有一段時間了,記得當時都被以上這五種文法搞懵了,所以希望寫篇文章幫助那些正在學習的人。以下內容是依據龍書中文版講解的,由於老師不同可能某些地方大同小異,如有什麼紕漏之處還請指出,多謝~ 以下文章參考了:LL LR SLR LALR 傻傻分不清。 首先來看張圖,上圖是四種文法的包含
一個簡單的編譯原理詞法語法語義分析程式
這是我們學校的課程實驗,想做個學習記錄,所以發表了這篇部落格,有不足的地方,歡迎大家共同探討,也歡迎大家轉載,轉載時請務必註明作者,希望對想學習編譯原理的同學有一定的幫助。 一 語法結構的詞法說明 關鍵字:begin if while 和檔案結束符E
構造 LL(1) 分析表的步驟與例題解析
構造 LL(1) 分析表的步驟與例題解析 易錯點及擴充套件: 1、求每個產生式的 SELECT 集 2、注意區分是對誰 FIRST 集 FOLLOW 集 3、開始符號的 FOLLOW 集包含 # 4、各集合對對應的物件以及含義 集 物件 含義 FIRST 集 是對產生式右部 右部內部的所有終結符
編譯原理-遞歸下降分析法
int urn sta ret pan package 編譯 string 遞歸 題:對下列文法,用遞歸下降分析法對任意輸入的符號串進行分析: (1)E->TG (2)G->+TG|—TG (3)G->ε, (4)T-
LR(1)分析表
ase ace using += man CI ont div cin input.in: S -> A A -> BB B -> aB B -> b output.out: CLOSURE ----------
編譯原理——算符優先分析法詳解
轉載地址 https://blog.csdn.net/qq_37977106/article/details/80301761 概述 算符優先分析法(Operator Prece
編譯原理實驗四 語法分析程式
實驗四 語法分析程式 (一)學習經典的語法分析器(1學時) 一、實驗目的 學習已有編譯器的經典語法分析源程式。 二、實驗任務 閱讀已有編譯器的經典語法分析源程式,並測試語法分析器的輸出。 三、實驗內容 (1)選擇一個編譯器,如:TINY,其它編譯器也可(需自備原始碼)。 (2)閱讀語法分
編譯原理及實踐-----詞法分析
詞法分析 【實驗目的】 通過設計編制除錯一個具體的詞法分析程式,加深對詞法分析原理的理解。並掌握在對程式設計語言源程式進行掃描過程中將其分解為各類單詞的詞法分析方法。掌握對字元進行靈活處理的方法。 程式開始變得複雜起來,可能是大家目前編過的程式中最複雜
編譯原理-詞法分析器1(lex實現)
編譯原理課實驗一是詞法分析器,但是在網上查了很多資料,發現用lex實現還要用Linux,Windows可以用對應的flex實現,但是網上的資料很零散,所以整理了一下從安裝到配置,到實現一個詞法分析器的過程 一、 安裝 開啟安裝好的軟體,選Basic
編譯原理-TEST語言詞法分析
原始碼 分析程式碼: { /*This a test program.*/ int abc; int 1203; int [email protecte
編譯原理 實驗3 語法分析
語法分析 一、 實驗目的 算術表示式的文法可以是(你可以根據需要適當改變): E→E+E|E-E|E*E|E/E|(E)|i 根據算符優先分析法,將表示式進行語法分析,判斷一個表示式是否正確。 二、 實驗環境 作業系統:window xp 編寫環境
編譯原理 實驗一 詞法分析之預處理
import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public cl
哈工大編譯原理實驗2——語法分析
此次試驗由於指導書的文法比較簡單,且沒有消除左遞迴(我懶),因此使用學長的文法,並加上了陣列判斷。 S -> func funcs funcs -> func funcs funcs -> $ func -> type IDN ( args ) f
編譯原理中的語法分析——自頂向下
語法分析——自頂向下 語法分析在編譯原理的: 語法分析分為自頂向下和自下而上 自頂向下:(就是從文法的句子可以歸約出開始符,簡單的說就是從一個語法樹的底部推出語法樹的根) 自下而上:(就是從文法的開始符推出文法的句子,簡單的說就是從一棵語法樹的根推出
編譯原理實驗一:詞法分析
實驗一:詞法分析程式 一、實驗目的 通過設計編制除錯一個具體的詞法分析程式,加深對詞法分析原理的理解。並掌握在對程式設計語言源程式進行掃描過程中將其分解為各類單詞的詞法分析方法。 編制一個讀單詞過程,從輸入的源程式中,識別出各個具有獨立意義的單詞,即基
哈工大編譯原理實驗一詞法分析
這是我自己寫的一個比較簡陋的詞法分析吧 但也是耗費了心血的 還是放在這裡希望對你們有用~~ 實驗指導書裡面的圖都是我用心畫的哈哈哈 實驗報告:http://download.csdn.net/download/qq_32285991/10125099 實驗要求: 實驗