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)={+,),$}
编译原理LR分析法
编译原理是研究如何将高级语言程序转换成等价的低级机器语言程序的学科, LR分析法是其中一种重要的语法分析方法。
何为编译原理
编译原理是计算机科学的一个分支,研究将高级语言程序转换为等价的底层机器代码的过程。它涉及词法分析、 语法分析、语义分析、优化和代码生成等多个阶段。
LR分析法的概述
LR分析法的步骤
1
1. 构建LR项集族
基于文法的产生式,生成LR(0)项集族,
2. 构建LR分析表
2
包括起始项集和其它项集。
根据LR项集族和文法的终结符和非终结
符,构建LR分析表,包括移进、规约和
接受操作。Leabharlann 33. 进行语法分析
使用构建的LR分析表,对输入的符号串 进行逐步解析,直到接受或出错。
构建LR分析表
项集的闭包
通过对项集进行闭包运算,计算 出项集中的所有项。
项集的转移
根据项目集的状态和接收符号, 进行项集的状态转移。
规约项的处理
确定规约的产生式和规约动作, 构建规约表。
LR分析表的使用
使用构建的LR分析表,可进行能够解析输入符号串的自底向上语法分析。它 根据输入符号和栈顶符号,执行移进、规约或接受操作来推导和验证语法结 构。
优缺点和应用
优点
具有广泛适用性,支持大多 数上下文无关文法。解析效 率高,能够快速生成语法树。
缺点
对于某些复杂的语法,可能 需要构建大型的分析表。编 写LR分析器的难度较高。
应用
LR分析法被广泛用于编译器 设计、解析器生成器和语法 分析工具的开发中。
LR分析法是一种自底向上的语法分析方法,用于构建一个确定性的有限状态 自动机(LR自动机)以解析各种语法结构。它具有广泛的应用,包括编译器 设计和语法分析工具的开发。
编译原理 LR分析法实验报告
实验五、LR分析法实验报告计算机与信息技术学院程序功能描述通过设计、编写和构造LR(0)项目集规范簇和LR 分析表、对给定的符号串进行LR 分析的程序,了解构造LR(0)分析表的步骤,对文法的要求,能够从文法G 出发生成LR(0)分析表,并对给定的符号串进行分析。
要求以表格或图形的方式实现。
G[E]:E→aA∣bBA→cA∣dB→cB∣d设计要求:(1)构造LR(0)项目集规范簇;要求输入LR(0)文法时,可以直接输入,也可以读取文件,并能够以表格的形式输出项目集规范簇集识别活前缀的有穷自动机(2)构造LR(0)分析表。
要求要求输入LR(0)文法时,可以直接输入,也可以读取文件;输出项目集规范簇,可以调用前一处理部分的结果,输出为LR(0)分析表(3)LR(0)分析过程【移进、归约、接受、报错】的实现。
要求调用前一部分处理结果的分析表,输入一个符号串,依据LR(0)分析表输出与句子对应的语法树,或直接以表格形式输出分析过程。
主要数据结构描述程序结构描述1.首先要求用户输入规则,并保存,分析出规则的数目,规则里的非终结符号和终结符号等信息,为下一步分析备用。
2.根据产生式构造分析表,首先分析每个状态里有哪些产生式,逐步将状态构造完整,最后的规约状态数应该等于产生式的个数。
3.在构造状态的时候,首先将所有的内容均填为出错情况,在每一步状态转换时可以将移进项目填进action表中,对于最后的规约项目,则再用规约覆盖掉之前填的移进。
4.要求用户输入分析串,并保存在输入序列数组中。
5.每一步根据当前的状态栈栈顶状态和输入符号查分析表,若是移进,则直接将符号和相应的状态添进栈中,否则弹出与产生式右部相同个数的字符和状态,并用剩下的状态和产生式的左部在goto表中进行查找,将非终结符和得到的状态压入两个栈内。
6.无论是规约还是移进都要输出当前三个栈内保存内容的情况。
7.如果碰到acc则输出accept,若碰到error则输出error,否则则继续进行规约和移进,不进行结果输出,直至输出接受或出错。
编译原理_第4章_第3节_LR分析法63页PPT文档
❖ 采用自底向下语法分析方法,在分析过程中的每一步,都会面 对两个关键问题:
(1)如何确定句柄 (2)找出的句柄应规约到哪一个非终结符
解决方法:(移进-规约法) (1)引入一个先进后出的符号栈来存放符号,按照顺序把当前
输入符号入栈(移进),然后查看栈顶符号串是否形成一个句柄。 (2)形成一个句柄时,便对此句柄直接规约,把它代替为相
(s0 s1…sms, #X1X2…Xmai, ai+1…an#)
(2) Action[sm, ai]=rn: {Aβ},且s=Goto[sm-|β|, A],则三元式变为:
(s0 s1…sm-|β|s, #X1X2…Xm-|β|A, aiai+1…an#) (3) Action[sm, ai]=acc,宣布接受,三元式不再变化。 (4) Action[sm, ai]=err,报错,三元式不再变化。
A c
d
3
EaA•
Ac•A A•d A•cA
d Ad•
4A c
5
6 AcA•
例:识别acd
状态栈 0 02
024 0245 0246 023
01 0
活前缀栈 当前符号
#
a
#a
c
#ac
d
#acd
#
#acA
#
#aA
#
#E
#
#S
#
输入串 cd# d# #
0
E
S•E E•aA
a
1
SE•
2 Ea•A A•d A•cA
A c
d
3
EaA•
Ac•A A•d A•cA
d Ad•
4A c
5
6 AcA•
LR分析程序
LR分析程序构造LR分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
1)实验原理LR分析器由三个部分组成:(1)总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
(2)分析表:分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
LR分析器结构:其中:SP为栈指针,S[i]为状态栈,X[i]为文法符号栈。
状态转换表用GOTO[i,X]=j表示,规定当栈顶状态为i,遇到当前文法符号为X时应转向状态j,X为终结符或非终结符。
ACTION[i,a]规定了栈顶状态为i时遇到输入符号a应执行。
动作有四种可能:(1)移进:action[i,a]= Sj:状态j移入到状态栈,把a移入到文法符号栈,其中i,j表示状态号。
(2)归约:action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A-B 的产生式,若B的长度为R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉R个符号,即栈指针SP减去R,并把A移入文法符号栈内,j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。
(3)接受acc:当归约到文法符号栈中只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。
(4)报错:当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入端不是该文法能接受的符号串。
2)、实验过程(1):数据结构:动作表(ACTION)和状态转换(GOTO)表用二维数组表示.(2)).使用文法E->E+TE->TT->T*FT->FF->(E)F->i3)程序思路(1)建立LR分析表(2)控制部分:从键盘输入一个表达式符号串;利用LR分析算法进行表达式处理:根据LR分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示错误信息。
编译原理LR分析法
编译原理LR分析法编译原理中的LR分析法是一种自底向上的语法分析方法,用于构建LR语法分析器。
LR分析法将构建一个识别句子的分析树,并且在分析过程中动态构建并操作一种非常重要的数据结构,称为句柄(stack)。
本文将详细介绍LR分析法的原理、算法以及在实际应用中的一些技巧。
1.LR分析法的原理LR分析法是从右向左(Right to Left)扫描输入串,同时把已处理的输入串的右侧部分作为输入串的前缀进行分析的。
它的核心思想是利用句柄来识别输入串中的语法结构,从而构建分析树。
为了实现LR分析法,需要识别和操作两种基本的语法结构:可规约项和可移近项。
可规约项指的是已经识别出的产生式右部,可以用产生式左部进行规约。
可移近项指的是当前正在处理的输入符号以及已处理的输入串的右侧部分。
2.LR分析法的算法LR分析法的算法包括以下几个步骤:步骤1: 构建LR分析表,LR分析表用于指导分析器在每个步骤中的动作。
LR分析表包括两个部分:动作(Action)表和状态(Goto)表。
步骤2: 初始化分析栈(stack),将初始状态压入栈中。
步骤3:从输入串中读取一个输入符号,并根据该符号和当前状态查找LR分析表中的对应条目。
步骤4:分析表中的条目可能有以下几种情况:- 移进(shift):将输入符号移入栈中,并将新的状态压入栈中。
- 规约(reduce):将栈中符合产生式右部的项规约为产生式左部,并将新的状态压入栈中。
- 接受(accept):分析成功,结束分析过程。
- 错误(error):分析失败,报告错误。
步骤5:重复步骤3和步骤4,直到接受或报错。
3.LR分析法的应用技巧在实际应用中,为了提高LR分析法的效率和准确性,一般会采用以下几种技巧:-使用LR分析表的压缩表示:分析表中的大部分条目具有相同的默认动作(通常是移进操作),因此可以通过压缩表示来减小分析表的大小。
-使用语法冲突消解策略:当分析表中存在冲突时,可以使用优先级和结合性规则来消解冲突,以确定应该选择的操作。
LR 分析方法程序设计原理与实现技术
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)。
最新实验题目:语法分析程序设计与实现(LR)
实验题目:语法分析程序设计与实现(LR)一.实验内容:编写语法分析程序,实现对算数表达式的语法分析。
要求所分析算数表达式由如下的文法产生。
E->E+T|E-T|TT->T*F|T/F|FF->id|(E)|num二.实现要求:在对输入表达式进行分析的过程中,输出所采用的产生式。
方法3:编写语法分析程序实现自底向上的分析,要求如下:1)构造识别所有或前缀的DFA2)构造LR分析表3)编程实现算法4.3,构造LR分析程序三.程序设计说明1.拓广文法。
加入产生式 S->·E。
2.构造项目集规范族(由于作图能力有限,DFA不在此进行显示)。
该过程中考虑到文法是通过字符串数组存储的,故分析过程是一个字符一个字符进行的,所以如果出现类似num,id多个字符构成一个整体的形式,难以处理,程序中对于这种情况采取只取第一个字符的方式处理,也就是用n代替num,i代替id。
对生成式进行编号后:0. S->E1.E->E+T 4.T->T*F 7.F->i2.E->E-T 5.T->T/F 8.F->(E)3.E->T 6.T->F 9.F->nI0 =closure({S′→·E})={ S′→·E,E→·E+T,E→·E-T,E→·T,T→·T*F,T→·T/F,T→·F,F→·i,F→·(E),F→·n}从I0出发的转移有I1=go(I0 ,E)=closure({S→E·}, {E→E·+T},{E→E·-T})={S→E·,E→E·+T,E→E·-T}I2=go(I0 ,T)=closure({E→T·}, { T→T·*F}, {T→T·/F})={ E→T·,T→T·*F,T→T·/F }I3=go(I0 ,F)=closure({T→F ·})={ T→F ·}I5=go( I0,( )= closure({F→(·E)})={ F→(·E), E→·E+T,E→·E-T,E→·T,T→·T*F,T→·T/F,T→·F,F→·i,F→·(E),F→·n }I6=go(I0,n)= closure({F→n· })={ F→n· }从I1出发的转移有I7=go(I1,+)= closure({E→E+·T })={E→E+·T,T→·T*F,T→·T/F,T→·F,F→·i,F→·(E),F→·n }I8=go(I1, -)= closure({E→E-·T })={ E→E-·T ,T→·T*F,T→·T/F,T→·F,F→·i,F→·(E),F→·n }从I2出发的转移有I9=go(I2, *)= closure({T→T*·F })={ T→T*·F,F→·i,F→·(E),F→·n } I10=go(I2, /)= closure({T→T/·F })={ T→T/·F,F→·i,F→·(E),F→·n }从I5出发的转移有I11=go(I5, E)= closure({F→(E·)}, { E→E·+T}, {E→E·-T })={F→(E·), E→E·+T, E→E·-T }go(I5, T)=I2 go(I5, i)=I4 go(I5, ( )=I5 go(I5, n)=I6从I7出发的转移有I12=go(I7, T)= closure({E→E+T·},{T→T·*F},{T→T·/F })={ E→E+T·,T→T·*F, T→T·/F }go(I7, F)=I3 go(I7, i)=I4 go(I7, ( )=I5 go(I7, n)=I6从I8出发的转移有I13=go(I7, T)= closure({E→E-T·},{T→T·*F},{T→T·/F })={ E→E-T·,T→T·*F, T→T·/F }go(I8, F)=I3 go(I8, i)=I4 go(I8, ( )=I5 go(I8, n)=I6从I9出发的转移有I14=go(I9,F)= closure({T→T*F· })={ T→T*F· }go(I9, i)=I4 go(I9, ( )=I5 go(I9, n)=I6从I10出发的转移有I15= go(I10,F)= closure({T→T/F· })go(I10, i)=I4 go(I10, ( )=I5 go(I10, n)=I6 从I11出发的转移有I16= go(I11, ))= closure({F→(E) ·})={F→(E) ·} go(I11, +)=I7 go(I11, - )=I8从I12出发的转移有go(I12, *)=I9 go(I12, / )=I10从I13出发的转移有go(I13, *)=I9 go(I13, / )=I103.构造分析表4. 根据算法4.3,构造LR预测分析程序。
编译原理及实现技术:15.语法分析_LR(1)方法
可归前缀图的构造
1.产生初始项目集IS0,且IS0∈ISS IS0=CLOSURE(Z•,#),其中Z为开始符 。
2.若ISi∈ISS,XVT∪VN,则定义 ISj=GO(ISi,X),若ISj不空且不属于ISS则 将ISj加入ISS,建立ISi到ISj的X映射,重复 该过程,直到ISS不产生新状态。
4
LR(1)基本思想
构造各种LR分析器的任务就是构造其 action表和goto表,其他部分基本相同。 LR(1)的基本思想是对非终极符的每个不 同出现求其后继符,而不是给每个非终极 符求其统一的后继符,我们称其为展望符 集。
5
LR(1)项目、投影
LR(1)项目:[A•, a],即LR(0)项目及 一个VT{#}的展望符组成的二元组。 用IS表示LR(1)项目的集合,简称LR(1)项 目集。其中,项Z•的展望符为#
B•b a/b
BaB• a/b
LR分析表
有文法: [1]ZBB [2]BaB [3]Bb
action表
goto表
a
b
#
B
0
S6
S4
1
1
S5
S3
2
2
AC
3
R3
4
R3
R3
5
S5
S3
8
6
S6
S4
7
7
R2
R2
8
R2
11
状态栈
0 0,6 0,6,4 0,6,7 0,1 0,1,5 0,1,5,5 0,1,5,5,3 0,1,5,5,8 0,1,5,8 0,1,2
5
R1
6 R3 R3 R3
G[Z]: ZS[0] SAS[1] S[2] AaA[3] Ab[4]
LR 分析方法程序设计原理与实现技术实验报告及源代码 北京交通大学
LR 分析方法程序设计原理与实现技术
分析失败:aAcAd
分析成功:acd
7. 实验总结:
本次实验按照书上的相应步骤,一步一步按照要求来完成实现,最终文成了给定文 法的分析程序。首先是获取文法,文法的获取是采用直接输入的方法,保存成预先设定 的结构体,然后根据文法,对文法编号,求出项目集规范族,然后再构造 LR(0)分析 表,最后根据分析表来判断输入符号串是否为此文法产生的语言。
sign = 0;
for(int i = 0;i < pro[0].data.size();i ++){
for(int j = 0;j < pro[0].data[i].right.size();j ++){
char ch = pro[0].data[i].right[j][1];
if(ch <= 'Z' && ch >= 'A' && pro[0].data[i].sign == 0){ //
cout << " 文法获取完成"
<< endl;
cout << "****************************************" << endl;
cout << endl;
编译原理LR(1)分析技术
西北师范大学计算机科学与工程学院学生实验报告学号201271030103 专业计算机科学与技术班级计师(1)班姓名实验课课程名称编译原理课程类型实验名称LR(1)分析技术实验目的:构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
实验内容:对下列文法,用LR(1)分析法对任意输入的符号串进行分析:(产生式有误,进行修改) (1)E- E+T (2)E- E—T(E->T)(3)T- T*F(4)T- T/F(T->F) (5)F- (E) (6)F- i实验代码如下:#include<iostream>using namespace std;const int MaxStateNum=12;const int MaxVtNum=6;const int MaxVnNum=4;const int MaxNodeNum=50;const int MaxStackDepth=50;const int MaxRuleNum=7;enum isAccept{YES,NO,ERROR};struct Grammar{int node;int RightLength;};struct StackNode{int state;int node;};class Lasa{private:char Vn[MaxVnNum];char Vt[MaxVtNum];int Action[MaxStateNum][MaxVtNum];int Goto[MaxStateNum][MaxVnNum];Grammar grammar[MaxRuleNum];StackNode Stack[MaxStackDepth];int tops;public:Lasa();~Lasa(){}isAccept accept(char str[]);};Lasa::Lasa(){char vn[MaxVnNum]={'Z','E','T','F'};char vt[MaxVtNum]={'#','+','*','(',')','i'};intac[MaxStateNum][MaxVtNum]={{0,0,0,4,0,5},{999,6,0,0,0,0},{-2,-2,7,0,-2,0},{-4,-4,-4,0,-4,0},{0,0,0,4,0,5},{-6,-6,-6,0,-6,0},{0,0,0,4,0,5},{0,0,0,4,0,5},{0,6,0,0,11,0},{-1,-1,7,0,-1,0},{-3,-3,-3,0,-3,0},{-5,-5,-5,0, -5,0}};int go[MaxStateNum][MaxVnNum]={{0,1,2,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,8,2,3},{0,0,0,0},{0,0,9,3},{0,0,0,10},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};Grammar gra[MaxRuleNum]={{100,2},{101,3},{101,1},{102,3},{102,1},{103,3},{103,1}}; int i=0,j=0;tops=0;Stack[tops].state=0;while(i<MaxVnNum){Vn[i]=vn[i++];}i=0;while(i<MaxVtNum){Vt[i]=vt[i++];}for(i=0;i<MaxStateNum;i++)for(j=0;j<MaxVtNum;j++){ Action[i][j]=ac[i][j];}for(i=0;i<MaxStateNum;i++)for(j=0;j<MaxVnNum;j++){Goto[i][j]=go[i][j];}i=0;while(i<MaxRuleNum){grammar[i].node=gra[i].node;grammar[i].RightLength=gra[i++].RightLength;}};isAccept Lasa::accept(char str[]){int tag=0;int S,R,act,m,N=0,U,News;int i=0,j=0,k=0;cout<<"\t编号\tStack "<<"\t\t字符串\n";act=0;while(str[i]!='\0'||act<999){if(str[i]=='\0')tag=1;j=0;cout<<"\t"<<k++<<"\t";while(j<=tops){if(j!=0){if(Stack[j].node>99&&Stack[j].node<110)cout<<Vn[Stack[j].node-100];else cout<<Vt[Stack[j].node];}cout<<Stack[j++].state;}cout<<"\t\t\t";j=i;while(str[j]!='\0')cout<<str[j++];cout<<endl;j=0;S=Stack[tops].state;while(j!=MaxVtNum){if(Vt[j]==str[i])break;j++;}if(j==MaxVtNum&&tag==0){return ERROR;}if(tag==0)R=j;else R=0;act=Action[S][R];if(act>0){tops++;Stack[tops].node=R;Stack[tops].state=act;if(tag==0)i++;}else if(act<0){act=-act;m=grammar[act].RightLength;U=grammar[act].node;tops=tops-m;News=Goto[Stack[tops].state][U-100];tops=tops+1;Stack[tops].node=U;Stack[tops].state=News;}else if(act==0){return ERROR;}j=0;}if(act==999)return YES;else return ERROR;}void main(){Lasa s,t;char pp[100];isAccept a;cout<<"LR分析技术"<<endl;cout<<"输入字符串:";cin>>pp;a=t.accept(pp);if(a==YES)cout<<"该字符串是文法的句子"<<endl;else if(a==ERROR) cout<<"error"<<"输入错误"<<endl; else cout<<"no"<<"该字符串不是文法的句子"<<endl; system("pause");}实验结果如下所示:实验总结:通过本次实验,初步掌握了语法分析的基本方法。
编译原理lr分析
编译原理lr分析编译原理是计算机科学中的一个重要领域,涉及到将源代码转化为可执行代码的过程。
LR分析是编译原理中一种常用且有效的语法分析方法,它通过构建自底向上的语法分析表格,可以对大部分上下文无关文法进行分析。
1. 简介LR分析是一种基于有穷状态自动机模型的语法分析方法,它基于Look-Ahead操作来向前预测分析所需的动作。
LR分析是一种自底向上的语法分析方法,从输入串右侧开始构建句子,直到最后归约为文法的起始符号。
2. LR分析表格LR分析表格是LR分析算法的核心,它将输入符号和状态作为表格的行和列,并填充相应的动作和转移信息。
LR分析表格一般分为动作表和转移表两部分。
在动作表中,我们记录了各个状态下的移进(shift)、归约(reduce)和接受(accept)等动作。
在转移表中,记录了各个状态下的状态转移信息。
3. LR分析算法步骤LR分析算法的主要步骤如下:步骤1: 构建文法的项集族根据给定的上下文无关文法,利用闭包和转移规则构建项集族,形成项目集的有限状态机。
步骤2: 构建LR(0)自动机在项集族的基础上,通过状态间的转移关系构建LR(0)自动机,确定自动机的开始状态和结束状态。
步骤3: 构建LR(0)分析表根据LR(0)自动机,填充LR(0)分析表的动作和转移信息,用于后续的分析过程。
步骤4: 使用LR(0)分析表进行分析利用构建好的LR(0)分析表格,根据输入符号和当前状态,执行相应的移进、归约和接受动作,直到完成分析或出现错误。
4. LR分析的优势和应用相比其他的语法分析方法,LR分析具有以下优势:- 适用性广泛:LR分析适用于大部分上下文无关文法的分析,能够应对复杂的语法结构。
- 自底向上:LR分析从输入串的右侧开始构建句子,逐步归约为文法的起始符号,更为高效。
- 错误检测:LR分析能够及时发现语法错误,并给出相应的错误提示,提高了代码的可靠性和稳定性。
LR分析在实际编译器的设计和实现中得到了广泛的应用。
北邮编译原理实验 LR语法分析 实验报告
LR语法分析实验报告班级:2010211308 姓名:杨娜学号:10211369一.题目:LR语法分析程序的设计与实现二.设计目的:(1)了解语法分析器的生成工具和编译器的设计。
(2)了解自上而下语法分析器的构造过程。
(3). 理解和掌握LR语法分析方法的基本原理;根据给出的LR)文法,掌握LR分析表的构造及分析过程的实现。
(4)掌握预测分析程序如何使用分析表和栈联合控制实现LR分析。
三.实验内容:编写语法分析程序,实现对算术表达式的语法分析,要求所分析算数表达式由如下的文法产生:E->E+T|E-T|TT->T/F|T*F|FF->i|n|(E)四.实验要求:编写LR语法分析程序,要求如下:(1)构造识别所有活动的DFA(2)构造LR分析表(3)编程实现算法4.3,构造LR分析程序五.算法流程分析程序可分为如下几步:六.算法设计1.数据结构s :文法开始符号line :产生式的个数G[i][0] :产生式的标号Vt[] :终结符Vn[] :非终结符id :项目集编号Prjt *next :指示下一个项目集Prjt[]:存储项目的编号,prjt[0]项目编号的个数Pointafter[] :圆点后的字符,pointafter[0]为字符个数Prjset*actorgo[]:存储出度Pointbefore:圆点前面的字符Form:动态数组下标,同时作为符号的编号Vn[] :非终结符序列Vt[]:终结符序列2.LR分析器由三个部分组成(1)总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
(2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
- 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标志的状态字。