LR 分析方法程序设计原理与实现技术
LR分析及分析程序自动构造-编译原理

1、LR文法(上下文无关):自左向右扫描,最右推导的逆过程2、LR方法1)思想:在规范规约过程中,一方面记住已移近和规约出的整个符号串,另一方面根据所用的产生式推测出未来可能碰到的输入符号。
2)优点:不其他技术相比,适应范围更广,能力更强,识别效率相当,尤其在自左向右扫描输入串时就能发现其中错误,并能准确指出出错位置。
缺点:若用手工构造分析程序,工作量太大,且容易出错,所以必须使用自劢产生这种分析程序的产生器。
3、产生器作用:⏹应用产生器产生一大类上下文无关文法的LR分析程序⏹对二义性文法或难分析的特殊文法,施加一些限制,使乊能用LR分析。
4、LR分析器:从逻辑上说,LR分析器包括两部分:●总控程序:或称为语法分析程序●分析表●注:后面学习的所有LR分析器的总控制程序都相同,仅仅是他们的分析表丌同。
5、总控制程序的作用:●查分析表:根据分析表的内容做出若干简单劢作,如读头后移,入栈,出栈等。
●注:由于总控制程序很简单,所以产生器的任务就是产生分析表。
6、分析表:一个文法的LR分析器常常对应着若干丌同的分析表,所有分析表都恰好识别文法所差生的所有语句。
LR(0)分析表:分析能力有限,但这是建立其他LR分析法的基础。
LR(1)(规范LR分析表)需要看读头下一个符号,它能力最强,但实现代价过高,分析表尺寸太大。
SLR分析表:简单LR分析表构造法,是一种容易实现又有实用价值的方法,但存在一些文法构造丌出SLR分析表。
LALR分析表向前看LR分析表构造法,也是一种常用方法。
注:实际上,SLR和LALR分别是对LR(0)和规范LR的改进。
7、LR分析法的基本思想在规范规约时,当一串貌似句柄的符号串呈现于栈顶时,LR分析法根据三方面的信息找句柄。
●历史:记录在栈内的符号串移进、规约的历史情况。
●展望:预测句柄乊后可能出现的信息●现实:读头下的符号8、LR分析器一个LR分析器实际上是带有下推栈的确定有限状态的自劢机。
第六章 LR分析法

3
6.1 LR分析概述
一个分析栈、一个驱动程序和一张分析表; 一个输入、一个输出。
输入
id+id*id#
状态栈 符号栈
im
Ym
im-1 Ym-1
…… i0 # 分析栈
LR驱动程序
输出
分
动作
转移 析
action goto
表
4
特殊性
#aAcd
e#
#aAcB
e#
#aAcBe
#
#S
#
动作 移进
移进 归约(A→b) 移进 归约(A→Ab) 移进 移进 归约(B→d) 移进
归约(S→aAcBe) 接受
注意:在分析 过程中,符号
S
栈内容连接剩
余输入串恰为
句型。
A
A
B
a b b c de
输出结果
文法G[S]: (1)S→aAcBe (2)A→b (3)A→Ab (4)B→d
ACTION[i,a]= 归约
接受
出错
7
-移进Shift:
表示:ACTION[i,a]=Sj 动作:状态j和输入符号a分别入符号
栈和状态栈,输入串向前进一字符。
-归约reduce:
表示:ACTION[i,a]=rk 其中: k表示第k个产生式。
动作:设第k个产生式右部长度为m, 左边非终结符为A,距状态栈栈顶m个 位置的状态为p。
造LR分析表。
17
拓广文法:
• 引入一新非终结符作为文法的新开始符,
添加一新产生式: S’→S :S’为新开始符,S为原来的开始符号。
• 拓展文法的目的: • 使文法只有一个以识别符号作为左部的产生
第4章LR分析法

ACTION 表
a1 S1 S2 … Sn ACTION(S1 ,a1] ACTION(S2 ,a1] … ACTION(Sn ,a1] a2 ACTION(S1 ,a2] ACTION(S2 ,a2] … ACTION(Sn ,a2] … … … … … al ACTION(S1 ,al] ACTION(S2 ,al] … ACTION(Sn ,al]
3 3
7 1
4.5.2 LR(0) 分析法
称为LR(0)分析器。 LR(0)分析法在分析每一步,只需根据当前栈顶状 态而不必向前查看输入符号就能确定采取的动作。 LR(0)分析法对文法的限制较大,对绝大多数高级 语言的语法分析器不适用。 构造LR(0)分析表的思想和方法是构造其他LR分析 表的基础。
1. 4. 7. 10. 13. 16.
(4)LR(0)项目分类 根据圆点所在的位置和圆点后是终结符还是非终结符 把LR(0)项目分为以下几种: 移进项目:
形如A→α•аβ的项目,其中а∈VT, α,β ∈V*。
则有待于移进一个VT符号a到栈中,因此称为移进项目。
待约项目:
形如A→α•Bβ的项目,其中B∈VN, α,β ∈V* 。 即圆点后面为非终结符的项目。 表明用产生式A的右部归约时,首先要将B的产生式右部
4.5 LR分析法
迄今为止我们所学的分析方法对文法都有一定的要 求,即有局限性; 1965年D.Knuth提出了分析效率极高的LR(k)分析 技术;
L: 表示从左至右扫描输入符号串;
R:表示为输入串构造一个最右推导的逆过程。 K:表示为了确定分析动作(移进、归约、接受、报错)而
需要向前看的输入符号的个数。 LR分析对文法要求很少,效率极高,且能及时发现错误,是 目前最广泛使用的方法;一般用上下文无关文法描述的语 言均可用LR分析法 缺点:构造LR分析程序工作量很大。
实验四 LR分析方法的设计与实现

实验四 LR分析方法的设计与实现(8学时)一、实验目的通过LR分析方法的实现,加深对自下而上语法分析方法及语法分析程序自动生成过程的理解。
二、实验要求输入上下文无关文法,对给定的输入串,给出其LR分析过程及正确与否的判断。
三、实验步骤1.参考数据结构typedef struct{/*文法*/char head;//产生式左部符号char b[20];//用于存放产生式int point;int lg;//产生式的长度}regular;typedef struct{int l; //文法数量int m; //vn 数量int n; //vt 数量regular re[20];nfinal vn[20];//非终结符final vt[20];//终结符}condition;condition cd[20];//项目regular first[20];//产生式2. 使用闭包函数(CLOSURE)和转换函数(GO(I,X))构造文法G’的LR(0)的项目集规范族。
计算LR(0)项目集规范族C={I0,I1,...,I n}算法描述如下:Procedure itemsets(G’);Begin C = { CLOSURE ({S’→.S})}RepeatFor C 中每一项目集I和每一文法符号XDo if GO(I,X) 非空且不属于CThen 把 GO(I,X) 放入C中Until C 不再增大End;定义转换函数如下:GO(I,X)= CLOSURE(J)其中:I为包含某一项目集的状态,X为一文法符号,J={A→aX.b|A→a.X b∈I}。
3. 构造LR(0)分析表对于LR(0)文法,我们可以直接从它的项目集规范族C和活前缀识别自动机的状态转换函数GO构造出LR分析表。
算法描述如下:beginif A→α•aβ∈ I k and GO(I k,a) = I j (a∈V T) then置ACTION[k,a] = sj;If A→α•∈ I k then对任意终结符a(包括#)置ACTION[k,a] = rj;If S’→S•∈ I k then置ACTION[k,#] = acc;If GO(I k,A) = I j (A∈V N) then置 GOTO(k,A) = j;else ERROR //出错4. LR分析算法描述对给定的输入串,给出其分析过程及正确与否的判断将S0移进状态栈,#移进符号栈,S为状态栈栈顶状态begina=getsym() //读入第一个符号给awhile(ACTION[S,a]!=acc)If ACTION[S,a]=si thenPUSH i,a(分别进栈);输出进栈信息a=getsym();//读入下一个符号给aelse if ACTION[S,a] = rj (第j条产生式为A→β) then输出归约信息将状态栈和符号栈分别弹出|β|项; push(A);将GOTO[S’,A]移进状态栈(S’为当前栈顶状态);else error;输出分析结果,接受或出错End5、对给定输入串输出其准确与否的分析过程。
第11讲 LR分析法

文法G(E): (1) E→E+T (2) E→T (3) T→T*F (4) T→F (5) F→(E) (6) F→i
视频区域
T* F
步骤 状态 (5) 027 (6) 0275 (7) 02710 (8) 02 (9) 01 (10) 016
符号 #T* #T*i #T*F #T #E #E+
r4 r4
s4
r6 r6
r6 r6
s4
s4
s6
s11
r1 s7
r1 r1
r3 r3
r3 r3
r5 r5
r5 r5
GOTO ETF 123
视频区域
823
93 10
LR分析表
报错
状态 i 0 s5 1 2 3 4 s5 5 6 s5 7 s5 8 9 10 11
ACTION
+* ( )#
s4
s6
acc
r2 s7
r2 r2
r4 r4
r4 r4
s4
r6 r6
r6 r6
s4
s4
s6
s11
r1 s7
r1 r1
r3 r3
r3 r3
r5 r5
r5 r5
GOTO ETF 123
视频区域
823
93 10
LR分析过程
分析开始时:
状态栈 符号栈
输入串
(s0,
#,
a1a2 … an #) 视频区域
以后每步的结果可以表示为:
ACTION
+* ( )#
s4
s6
acc
r2 s7
r2 r2
r4 r4
r4 r4
编译原理报告二 LR分析器

LR分析器一、目的和要求通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。
1、选择最有代表性的语法分析方法,如LL(1) 语法分析程序、算符优先分析程序和LR 分析分析程序,并至少完成两个题目。
2、选择对各种常见程序语言都用的语法结构,如赋值语句(尤指表达式)作为分析对象,并且与所选语法分析方法要比较贴切。
⑴实验前的准备按实验的目的和要求,编写语法分析程序,同时考虑相应的数据结构。
⑵调试调试例子应包括符合语法规则的算术表达式,以及分析程序能够判别的若干错例。
⑶输出对于所输入的算术表达式,不论对错,都应有明确的信息告诉外界。
⑷扩充有余力的同学,可适当扩大分析对象。
譬如:①算术表达式中变量名可以是一般标识符,还可含一般常数、数组元素、函数调用等等。
②除算术表达式外,还可扩充分析布尔、字符、位等不同类型的各种表达式。
③加强语法检查,尽量多和确切地指出各种错误。
⑸编写上机实习报告。
二、背景知识※自下而上分析技术-LR(K)方法LR(K)方法是一种自下而上的语法分析方法,是当前最广义的无回溯的“移进- 归约”方法。
它根据栈中的符号串和向前查看的k(k 0)个输入符号,就能唯一确定分析器的动作是移进还是归约,以及用哪个产生式进行归约。
优点:文法适用范围广;识别效率高;查错能力强;可自动构造。
逻辑组成:总控程序+LR分析表LR分析器的结构:一个LR分析器实际是一个带先进后出存储器(栈)的确定下推自动机,它由一个输入串、一个下推栈和一个带有分析表的总控程序组成。
栈中存放着由“历史”和“展望”材料抽象而来的各种“状态”。
任何时候,栈顶的状态都代表了整个的历史和已推测出的展望。
为了有助于明确归约手续,我们把已归约出的文法符号串也同时放进栈里。
LR分析器的每一动作都由栈顶状态和当前输入符号所唯一确定。
LR分析器模型图分析器的任何一次移动都是根据栈顶状态S m和当前输入符号a i,去查看ACTION表并执行ACTION(S m,a i)规定的动作,直至分析成功或失败。
编译原理课程设计-LR分析器总控程序的实现

合肥工业大学计算机与信息学院课程设计课程:编译原理专业班级:计算机科学与技术09-2班学号:姓名:一:设计题目题目: LR分析器总控程序的实现设计内容及要求:对P.101中的文法,按图5.5LR分析表构造LR分析器。
要求程序按P.102例5.7那样,对于输入串i*i+i,输出LR分析器的工作过程。
改进:可以自行输入输入串,能按重新按钮重新开始,外加了一个计时器。
二:设计目的进一步了解了LR分析器的整个工作过程,将LR分析器以图形界面的形式展现了出来,有利加深了对LR分析过程的掌握。
三:实验原理本程序是用windows编的,大体的思想是这样的:通过建立一个符号栈,状态栈,输入栈(结构体类型定义的)分别用来存放符号,状态,输入串,将LR 分析表构造成为一个二维数组table[13][9],其中0--11表示状态结点,21--26表示规约标号,-1表示error(出错),12表示acc(接受),在acation函数里面通过i等于多少来判断到底是规约还是移进。
在Main_OnCommand()函数中通过switch....case..来判断每次及下一步所要执行的操作。
运行的时候,首先要输入一个以#结尾的输入串,然后单击开始——>下一步.....,如果规约成功,则弹出一个规约成功的对话框,否则弹出一个规约失败的对话框。
当然在运行的过程中如果出现什么差错,都可以单击重新开始按钮重新输入输入串重新开始。
四:实验代码#include "stdAfx.h"#include <windows.h>#include <windowsx.h>#include "resource.h"#include "MainDlg.h"char *str2[6]={"E->E+T","E->T","T->T*F","T->F","F->(E)","F->i"};int flag=0;#define MAX 20typedef struct{int stack1[MAX];int top1;}status;typedef struct{char stack2[MAX];int top2;}symbol_instr;char index_char[9]={'i','+','*','(',')','#','E','T','F'};//为二维数数组的纵坐标//LR分析表//0--11表示状态结点,21--26表示规约标号,//-1表示error(出错),12表示acc(接受)int table[13][9] = {{ 5,-1,-1, 4,-1,-1, 1, 2, 3},\{-1, 6,-1,-1,-1,12,-1,-1,-1},\{-1,22, 7,-1,22,22,-1,-1,-1},\{-1,24,24,-1,24,24,-1,-1,-1},\{ 5,-1,-1, 4,-1,-1, 8, 2, 3},\{-1,26,26,-1,26,26,-1,-1,-1},\{ 5,-1,-1, 4,-1,-1,-1, 9, 3},\{ 5,-1,-1, 4,-1,-1,-1,-1,10},\{-1, 6,-1,-1,11,-1,-1,-1,-1},\{-1,21, 7,-1,21,21,-1,-1,-1},\{-1,23,23,-1,23,23,-1,-1,-1},\{-1,25,25,-1,25,25,-1,-1,-1}};//规约规则struct rule{char x;int y;}r[6]={{'E',3},{'E',1},{'T',3},{'T',1},{'F',3},{'F',1}}; //后面的代表A—>@中@的长度BOOL WINAPI Main_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {switch(uMsg){HANDLE_MSG(hWnd, WM_INITDIALOG, Main_OnInitDialog);HANDLE_MSG(hWnd, WM_COMMAND, Main_OnCommand);HANDLE_MSG(hWnd,WM_CLOSE, Main_OnClose);}return FALSE;}void init_stack1(HWND hwnd,status *p){if( !p)MessageBox(hwnd,TEXT("出错"),TEXT("警告"),MB_OK|MB_ICONHAND);p->top1 = -1;}void push1(HWND hwnd,status *&p,int x){if(p->top1 < MAX-1){p->top1++;p->stack1[p->top1] = x;}else MessageBox(hwnd,TEXT("出错"),TEXT("警告"),MB_OK|MB_ICONHAND);}int pop1(HWND hwnd,status *p){int x;if(p->top1 != 0){x = p->stack1[p->top1];p->top1--;return x;}else{MessageBox(hwnd,TEXT("状态栈为空"),TEXT("警告"),MB_OK|MB_ICONHAND);//printf("\n状态栈1空!\n");return 0;}}void out_stack(HWND hwnd,status *p){if(p->top1 <0)MessageBox(NULL,TEXT("状态栈为空"),TEXT("警告"),MB_OK|MB_ICONHAND);//printf("\n状态栈3空!\n");int i;TCHAR str[256];for(i=0;i<=p->top1;i++)wsprintf(&str[i],"%d",p->stack1[i]);SetDlgItemText(hwnd,IDC_EDIT1,str);}int get_top1(HWND hwnd,status *p){int x;if(p->top1 != -1){x = p->stack1[p->top1];return x;}else{MessageBox(hwnd,TEXT("状态栈为空"),TEXT("警告"),MB_OK|MB_ICONHAND);//printf("\n状态栈2空!\n");return 0;}}void init_stack2(HWND hwnd,symbol_instr *p){if( !p)MessageBox(hwnd,TEXT("出错"),TEXT("警告"),MB_OK|MB_ICONHAND);p->top2= -1;}void push2(HWND hwnd,symbol_instr *p,char x){if(p->top2 < MAX-1){p->top2++;p->stack2[p->top2] = x;p->stack2[p->top2+1]='\0';}else MessageBox(hwnd,TEXT("出错"),TEXT("警告"),MB_OK|MB_ICONHAND);}char pop2(HWND hwnd,symbol_instr *p){char x;if(p->top2 != -1){x = p->stack2[p->top2];p->top2--;p->stack2[p->top2+1]='\0';return x;}else{MessageBox(hwnd,TEXT("符号栈为空"),TEXT("警告"),MB_OK|MB_ICONHAND);//printf("\n符号栈1空!\n");return 0;}}void out_stack1(HWND hwnd,symbol_instr *p){if(p->top2 <0)MessageBox(hwnd,TEXT("符号栈为空"),TEXT("警告"),MB_OK|MB_ICONHAND);//printf("\n状态栈3空!\n");SetDlgItemText(hwnd,IDC_EDIT2,p->stack2);}void out_stack2(HWND hwnd,symbol_instr *p){if(p->top2 <0)MessageBox(hwnd,TEXT("符号栈为空"),TEXT("警告"),MB_OK|MB_ICONHAND);//printf("\n状态栈3空!\n");SetDlgItemText(hwnd,IDC_EDIT3,p->stack2);}char get_top2(HWND hwnd,symbol_instr *p){char x;if(p->top2 != -1){x = p->stack2[p->top2];return x;}else{MessageBox(hwnd,TEXT("符号栈为空"),TEXT("警告"),MB_OK|MB_ICONHAND);//printf("\n符号栈2空!\n");return 0;}}void print(HWND hwnd,status *status_p,symbol_instr *symbol_p,symbol_instr *instr_p){out_stack(hwnd,status_p); //输出状态栈的内容out_stack1(hwnd,symbol_p); //输出符号栈的内容out_stack2(hwnd,instr_p); //输出输入串}int get_index_char(char i){for(int j=0;j<9;j++){if(index_char[j] == i)return j;}return -1;}int goto_char(HWND hwnd,status *status_p,symbol_instr *instr_p){char x;int y,z;x = get_top2(hwnd,instr_p); //输入栈的内容y = get_top1(hwnd,status_p); //状态栈栈顶内容z = get_index_char(x); //得到i,*等相当于二维数组return table[y][z];}void action(HWND hwnd,status *status_p,symbol_instr *symbol_p,symbol_instr *instr_p){int i,j,x;char a;i = goto_char(hwnd,status_p,instr_p);//规约出错if(i == -1)MessageBox(hwnd,TEXT("规约出错!"),TEXT("结束"),MB_OK|MB_ICONEXCLAMATION);//规约成功if(i == 12){MessageBox(hwnd,TEXT("规约成功!"),TEXT("结束"),MB_OK|MB_ICONEXCLAMATION);flag=1;}//移进动作if(i>=0 && i<=11){push1(hwnd,status_p,i);a = pop2(hwnd,instr_p);push2(hwnd,symbol_p,a);print(hwnd,status_p,symbol_p,instr_p);}//规约动作if(i>=21 && i<=26){x = r[i-21].y;for(j=0;j<x;j++){pop1(hwnd,status_p);pop2(hwnd,symbol_p);}push2(hwnd,instr_p,r[i-21].x);SetDlgItemText(hwnd,IDC_EDIT4,str2[i-21]);}}void CALLBACK TimerProc(HWND hwnd,UINT message,UINT iTimerID,DWORD dwTime) {SYSTEMTIME stLocal;TCHAR buf[256];GetLocalTime(&stLocal);wsprintf(buf,"%d年%d月%d 日%d:%d:%d",stLocal.wYear,stLocal.wMonth,stLocal.wDay,stLocal.wHour,stLocal.wM inute,stLocal.wSecond);SetDlgItemText(hwnd,IDC_EDIT5,buf);}BOOL Main_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){SetTimer(hwnd,0,1000,TimerProc);return TRUE;}status *status_p=new status;symbol_instr *symbol_p=new symbol_instr;symbol_instr *instr_p=new symbol_instr ;void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify){switch(id){case IDC_BUTTON1:{init_stack1(hwnd,status_p); //初始化各栈init_stack2(hwnd,symbol_p);init_stack2(hwnd,instr_p);//压进栈初始元素push1(hwnd,status_p,0);push2(hwnd,symbol_p,'#');char x;TCHAR msg[256];GetDlgItemText(hwnd,IDC_EDIT3,msg,sizeof(msg));unsigned int i;for(i=0;i < strlen(msg);i++)push2(hwnd,symbol_p,msg[i]);//然后由符号栈弹出,压进输入栈while( symbol_p->top2 != 0){x = pop2(hwnd,symbol_p);push2(hwnd,instr_p,x);}print(hwnd,status_p,symbol_p,instr_p);//打印初始分析表*/ }break;case IDC_BUTTON2:{action(hwnd,status_p,symbol_p,instr_p);}break;case IDC_BUTTON3:{SetDlgItemText(hwnd,IDC_EDIT1,TEXT(""));SetDlgItemText(hwnd,IDC_EDIT2,TEXT(""));SetDlgItemText(hwnd,IDC_EDIT3,TEXT(""));SetDlgItemText(hwnd,IDC_EDIT4,TEXT(""));}break;default:break;}}void Main_OnClose(HWND hwnd){EndDialog(hwnd, 0);}四:实验结果(1)当输入i*i+i#时最终弹出规约成功的对话框:(2)当输入ii*i#时,最终会弹出规约出错的对话框如下:。
第四章_3 LR分析法

4.5.1 LR分析器的工作原理和过程
• 3 LR分析器的工作过程 例 4.14 文法G’为: 0. S’ → S 1. S → A 该文法的LR分析表 2. S → B 3. A → aAb 4. A → c 5. B → aBb 6. B → d
根据文法G[S]的LR(0)分析表,对输入串aacbb$进行语法分析。
• 4 SLR(1)分析表 与LR(0)分析表构造基本相同,仅对归约项目修 改: 若I中有归约项目A → α •,对a ∈FOLLOW(A), 置ACTION(I,a)=rj。
构造例 4.15 的SLR(1)分析表。
结论: 若文法的SLR(1)分析表不含多重定义元素,则 称该文法为SLR(1)文法。
7
9
4.5.2 LR(0)分析法
• 0 LR分析表的构造步骤 (1)根据文法构造识别文法所有规范句型活前缀 的DFA (2)将DFA转换成一张LR分析表
4.5.2 LR(0)分析法
• 1 文法规范句型的活前缀 ◆字符串的前缀 指字符串的任意首部。 例:字符串abc的前缀有: ε , a, ab, abc ◆规范句型的活前缀 不包含句柄右边的符号。 例:某文法规范句型aaAbb$,它的句柄是aAb, ε 则 前缀: , a, aa, aaA, aaAb, aaAbb, aaAbb$. 活前缀: , a, aa, aaA, aaAb. ε
分析例4.16中的冲突项目集I1,I2,I9 。
I1:{ E’ → E • E → E • +T} I2:{E → T • T → T • *F} I9:{E → E+T • T → T • *F} FOLLOW(E’)={$}
FOLLOW(E)={+,),$}
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
LR 分析方法程序设计原理与实现技术1郑杰09274053本实验程序中的一些约定:在工程文件main.h中定义所有函数,和数据结构。
在符号方面,$S定义为拓广文法的新引入的起始符号,$START不能和$S一样,并且,为了方便,在原来的产生式上强行加上这么一条产生式$S $START,这一点在main.c中定义文法可以看出来,并且该产生式加在产生式集的首要位置。
状态栈的设计引用以前程序中的数据结构,但是栈操作在本程序中有所扩展。
下面按照程序编写过程顺序介绍各个模块:一.文法产生式扩展由原来的产生式拓展成为加’.’的文法,并且在这个过程中要引入新的起始符号,但是在程序中并没有在这个过程中这么做,原因是因为在原来的产生式集中已经引入新的符号以及产生式,根据原始产生式集计算所需要存储新的拓展产生式集的所需要的产生式个数,然后动态开辟内存空间,再对每个原始产生式的各个位置加'.'。
在本次程序中用来产生拓展文法产生式集的函数定义如下:PPRO ParseProArray(PPRO lpPriProArr,int iProLen,int *iParsedLen)//参数说明:lpPriProArr:PPRO原始产生式集iProLen:int原始产生式个数iParsedLen:int*;拓展产生式集的个数返回值//返回值:拓展产生式集的首地址二.CLOSURE闭包求取在介绍求一个项目集的闭包前,先介绍程序中存储项目集(状态)的数据结构:typedef struct _ITEM_COLLOECTION{int iCount;//项目集合中的产生式个数int iSeqNumber;//项目集合(状态)的状态号PPRO ProCollection[MAX_ITEM_COUNT];//产生式集合的引用数组struct _ITEM_COLLOECTION * nextCollection;//由于程序中项目集合之间存储组织是单向链表,因此有这个域struct _GO{//GOTO映射数组,byte Symbol;//经历当前符号struct _ITEM_COLLOECTION * DestStatus;//跳转的下一个状态(项目集合)的引用}GO_MAP[SYMBOL_COUNT];//由符号个数来定义这个数组的长度}ITEM_COLL,*PITEM_COLL;1编译原理第五次实验报告.求解一个项目集合的CLOSURE闭包的具体方法是1.对于给定的项目集I,对于I中的的每一个产生式属于2.对于现有的闭包集合中的产生式A-->a.Xb,其中X是非终结符,那么对于文法拓展的产生式X-->.Y均属于CLOSURE(I)。
迭代这个过程直到收敛为止。
程序中沿用之前程序中收敛方式,引入一下函数:int AddPro(PITEM_COLL pColl,PPRO ppro,int *iVar)//这个函数往项目集中加入产生式//iVar的值为在函数成功调用的时候返回加入产生式前后的变化//iVar==0说明这个函数在此次调用中并没有加入新的产生式,即该产生式重复//iVar==1说明加入的产生式为之前不存在的在上述求闭包的过程中进行一次完整的查找遍历时候,每次调用AddPro的时候,若都iVar==0,则说明可以收敛了。
产生CLOSURE闭包的函数定义如下:PITEM_COLL GetClosure(PPRO lpProArray,PITEM_COLL lpSrcColl,int iProLen)//参数说明:lpSrcColl:PPRO ,拓展文法产生式数组//lpSrcColl:PITEM_COLL源状态//iProLen:int//返回值:闭包集三.创建项目集规范族创建项目集规范族的过程也是一个收敛迭代过程,以状态(项目集)为单位,对于每一个符号S,在这个项目集中查找右部形如-->.Sb的产生式,获取其后继项目2,,对于所有满足条件的后继项目所组成的集合,当这个项目集不为空时,再获取其闭包,这个闭包就是项目集合,但是这个项目集合有可能与之前的项目集合重复3,因此不能在没有判断是否重复的情况下加入的项目集规范族。
程序中构建项目集规范族的函数在程序中如下定义:void ConstructItemCollFamily(PITEM_COLL lpCollHeader,PPRO lpProArray,int iProLen,PITEM_COLL lpInitStatus)//lpCollHeader:PITEM_COLL:项目族的链表头//lpProArray:PPRO原始产生式数组//iProLen:int 原始产生式数组长度//lpInitStatus:PITEM_COLL:初始状态函数返回后,以lpCollHeader为首的状态链表中蕴含了能够识别所有活前缀的有穷自动机。
状态变迁隐含在项目集族的每一个项目集中GO_MAP:struct _GO数组域中,数组的长度为2程序中获取后继项目的函数在程序中定义为:PPRO GetSubSeqItem(PPRO lpProArray,int iProLen,PPRO lpCurPro)3程序中判断项目集合产生式相等的函数定义:int BeEqualColl(PITEM_COLL Coll1,PITEM_COLL Coll2);int beEqualPro(PPRO lpPro1,PPRO lpPro2);文法中所有的除了拓广文法起始符号的所有符号。
四.构建LR(0)分析表(状态迁移函数)在程序中,建表的目的是为了提高程序处理速度,但是在本程序中为了处理方便和表中元素统一格式存储,并没有构造一张内存中真实的查找表,取而代之的是一个状态字获取函数,函数返回一个状态字4这个状态字有两个字节构成:状态字节和内容字节,下面是图示:状态字图示:程序中定义如下函数获取状态字:word GetStatusWord(PITEM_COLL lpCollHeader,PPRO lpProArray,int iProLen,byte bCurStatus,byte bSymbol)//参数描述4借鉴Window消息参数构造方式typedef unsigned char byte;typedef unsigned short word;并且定义三个字节重组字的宏和字拆分为字节的宏#define MAKEWORD(highbyte,lowbyte) ((word)((0xff&(highbyte))<<8|(0xff&(lowbyte))))#define HIBYTE(data) ((byte)((data)>>8))#define LOWBYTE(data) ((byte)data)例如:word wd=MAKEWORD(0xff,0x12)那么HIBYTE(wd)==0xff,LOWBYTE(wd)==0x12lpCollHeader:项目集规范族的链表首,DFA的表示lpProArray:原始产生式数组iProLen:产生式数组长度bCurStatus:当前状态bSymbol:遇到的符号**当前状态和符号用来在LR(0)分析表中作为索引查找ACTION或者GOTO元素**但是在程序中没有构造这张表,而是从DFA(项目集族中的)实时查找//返回值说明:由图示中可以看出,返回的状态字类型有五种1.遇到终结符号移进:return MAKEWORD(VS_FLAG,迁移的状态序号);2.遇到非终结符号移进return MAKEWORD(NS_FLAG,迁移的状态序号);3.遇到非终结符规约(规约产生式左部不是拓广文法起始符号遇到'#'):return MAKEWORD(R_FLAG,规约产生式序号);4.当遇到"#"符号,并且规约产生式左部是拓广文法起始符号:return MAKEWORD(ACC_FLAG,0);5.其余情况:return MAKEWORD(ERR_FLAG,0);五.分析总控程序状态栈:状态栈的数据结构沿用之前程序中的定义,但是在每次试验中添加了新操作: byte Peek(LPSTACK lpStack);这个函数的作用是返回栈顶元素的内容,但是实际上并不做退栈工作。
在程序中只设置一个状态栈,没有设置符号栈下面是驱动程序的伪代码:Push(0);//入展初始状态//inPtr是输入符号指针while(1){StatusWord=GetStatusWord(CurStatus,szInput[inPtr]);switch(HIBYTE(StatusWord)){case VS_FLAG:Push(CurStatus=LOWBYTE(StatusWord));inPtr++;break;case ACC_FLAG:puts("Accept Successfully");return 1;break;case R_FLAG:lpProBuff=lpProArray+LOWBYTE(StatusWord);for(idx_buff=0;lpProBuff->rightTerArr[idx_buff];idx_buff++)Pop ();//以当前规约产生式的右部符号个数做POP操作StatusWord=GetStatusWord(Peek(&StatusStack),lpProBuff->leftNon Ter);//以当前栈顶的状态和规约产生式左部符号if(HIBYTE(StatusWord)!=NS_FLAG){ReportError();;return 0;}//在这种情况下应该标志NS_FLAGPush(CurStatus=LOWBYTE(StatusWord));break;case NS_FLAG:default:ReportError();return 0;}}分析函数的定义如下:int AnalyzeInput(PITEM_COLL lpCollHeader,PPRO lpProArray,int iProLen,byte bInputStr[]);//说明:1.bInputStr是待分析的符号数组,必须以$SHARP结尾2.分析成功返回1,错误返回0示例演示分析:1.项目集规范族和DFA的演示:在main.c中定义文法:定义如下产生式:PRO PrimitiveProArray[]={{$S,$START,0},//Should Exists In Every Grammer,in terms of Extending This Grammer{$E,$a,$A,0},{$E,$b,$B,0},// {$E,$B,0},//Used For Test Production{$A,$c,$A,0},{$A,$d,0},{$B,$c,$B,0},{$B,$d,0}};下面分别对两种情况中间结果进行罗列:不存在红色注释的产生式存在上述上产生拓广文法:(说明:图中的产生式均为main.h中宏定义码,其中$DOT==5,S'==81)0 .81-->5 821 .81-->82 52 .82-->5 1 833 .82-->1 5 834 .82-->1 83 55 .82-->5 2 846 .82-->2 5 847 .82-->2 84 58 .83-->5 3 839 .83-->3 5 8310.83-->3 83 511.83-->5 412.83-->4 513.84-->5 3 8414.84-->3 5 8415.84-->3 84 516.84-->5 417.84-->4 5 拓广文法:0 .81-->5 821 .81-->82 52 .82-->5 1 833 .82-->1 5 834 .82-->1 83 55 .82-->5 2 846 .82-->2 5 847 .82-->2 84 58 .82-->5 849 .82-->84 510.83-->5 3 8311.83-->3 5 8312.83-->3 83 513.83-->5 414.83-->4 515.84-->5 3 8416.84-->3 5 8417.84-->3 84 518.84-->5 419.84-->4 5项目集族和DFA0 .Collection Total Item:3(0)Item Pro:81--> 5 82(1)Item Pro:82--> 5 1 83(2)Item Pro:82--> 5 2 84 [0]Status Transit:--82-->1 0 .Collection Total Item:6(0)Item Pro:81--> 5 82(1)Item Pro:82--> 5 1 83(2)Item Pro:82--> 5 2 84(3)Item Pro:82--> 5 84(4)Item Pro:84--> 5 3 84[3]Status Transit:--1 -->2[4]Status Transit:--2 -->3 1 .Collection Total Item:1(0)Item Pro:81-->82 52 .Collection Total Item:3(0)Item Pro:82--> 1 5 83(1)Item Pro:83--> 5 3 83(2)Item Pro:83--> 5 4[1]Status Transit:--83-->4[5]Status Transit:--3 -->5[6]Status Transit:--4 -->6 3 .Collection Total Item:3(0)Item Pro:82--> 2 5 84(1)Item Pro:84--> 5 3 84(2)Item Pro:84--> 5 4[2]Status Transit:--84-->7[5]Status Transit:--3 -->8[6]Status Transit:--4 -->9 4 .Collection Total Item:1(0)Item Pro:82--> 1 83 5 5 .Collection Total Item:3(0)Item Pro:83--> 3 5 83(1)Item Pro:83--> 5 3 83(2)Item Pro:83--> 5 4[1]Status Transit:--83-->10[5]Status Transit:--3 -->5[6]Status Transit:--4 -->6 6 .Collection Total Item:1(0)Item Pro:83--> 4 57 .Collection Total Item:1(0)Item Pro:82--> 2 84 5 8 .Collection Total Item:3(0)Item Pro:84--> 3 5 84(1)Item Pro:84--> 5 3 84(2)Item Pro:84--> 5 4[2]Status Transit:--84-->11[5]Status Transit:--3 -->8[6]Status Transit:--4 -->9 9 .Collection Total Item:1(0)Item Pro:84--> 4 510 .Collection Total Item:1(0)Item Pro:83--> 3 83 5 11 .Collection Total Item:1(0)Item Pro:84--> 3 84 5 (5)Item Pro:84--> 5 4[0]Status Transit:--82-->1[2]Status Transit:--84-->2[3]Status Transit:--1 -->3[4]Status Transit:--2 -->4[5]Status Transit:--3 -->5[6]Status Transit:--4 -->6 1 .Collection Total Item:1(0)Item Pro:81-->82 52 .Collection Total Item:1(0)Item Pro:82-->84 53 .Collection Total Item:3(0)Item Pro:82--> 1 5 83(1)Item Pro:83--> 5 3 83(2)Item Pro:83--> 5 4[1]Status Transit:--83-->7[5]Status Transit:--3 -->8[6]Status Transit:--4 -->9 4 .Collection Total Item:3(0)Item Pro:82--> 2 5 84(1)Item Pro:84--> 5 3 84(2)Item Pro:84--> 5 4[2]Status Transit:--84-->10[5]Status Transit:--3 -->5[6]Status Transit:--4 -->6 5 .Collection Total Item:3(0)Item Pro:84--> 3 5 84(1)Item Pro:84--> 5 3 84(2)Item Pro:84--> 5 4[2]Status Transit:--84-->11[5]Status Transit:--3 -->5[6]Status Transit:--4 -->6 6 .Collection Total Item:1(0)Item Pro:84--> 4 57 .Collection Total Item:1(0)Item Pro:82--> 1 83 5 8 .Collection Total Item:3(0)Item Pro:83--> 3 5 83(1)Item Pro:83--> 5 3 83(2)Item Pro:83--> 5 4[1]Status Transit:--83-->12[5]Status Transit:--3 -->8[6]Status Transit:--4 -->9 9 .Collection Total Item:1(0)Item Pro:83--> 4 510 .Collection Total Item:1(0)Item Pro:82--> 2 84 5 11 .Collection Total Item:1(0)Item Pro:84--> 3 84 5 12 .Collection Total Item:1(0)Item Pro:83--> 3 83 5说明:1.上述每个单元分别代表一个状态(项目集)2.红色标注的是接收状态3.蓝色标记的是规约状态,可以看出其中项目产生式均是以"."结尾4.其余均为移进项目,状态迁移为:迁移说明:Status Transit:--4 -->9当前状态在遇到符号4(宏定义码)的时候移进并状态迁移到9,由前述可知当前情况下查表返回VS_FLAG标志的状态字。