实验三 自下而上语法分析及语义分析

合集下载

编译原理语法分析——自下而上分析

编译原理语法分析——自下而上分析
基本思想:从输入串开始,逐步进行“归约”,直到文法的 开始符号。即从树末端开始,构造语法树。所谓归约,是指 根据文法的产生式规则,把产生式的右部替换成左部符号。
E
1)LR分析法 2)算符优先分析法
E+ T
T
F
T * F i3
F
i2
i1
归约的含义: G(E): E i| E+E | E-E | E*E |
例:设文法G(S): (1) S aAcBe (2) A b (3) A Ab (4) B d
试对abbcde进行“移进-归约”分析。
e
BBd
abbbbcccdddeee
bcc
Ab
Saa
步骤: 1 2 3 4 5 6 7 8 9 10 动作: 进a 进b 归(2) 进b 归(3) 进c 进d 归(4) 进e 归(1)
规范归约是关于是一个最右推导的逆过程
最左归约
规范推导
由规范推导推出的句型称为规范句型。
把上例倒过来写,则得到:
S aAcBe aAcde aAbcde
abbcde
显然这是一个最右推导。
规范归约是关于是一个最右推导的逆过程
最左归约
规范推导
由规范推导推出的句型称为规范句型。
S
句柄“最左”特征的含 义
aAcde (4) B d
aAcBe (1) S aAcBe
S
S
a A c Be
A
bd
b S
S
a A c Be
Ab
d
S
a A c Bea A c Be d
定义:假定是文法G的一个句子,我们称序列 n, n-1, ,0
是的一个规范归约,如果此序列满足:

自下而上语法分析

自下而上语法分析

自下而上语法分析对于产生语言来讲,自上而下分析的方法是自然的。

对于分析语言来讲,自下而上分析的方法更自然,因为语法分析处理的对象一开始都是终结符组成的输入序列,而不是文法的开始符号。

同时,自下而上分析中最一般的方法,LR方法的能力比自上而下分析的LL方法要强,从而使得LR分析成为最为实用的语法分析方法。

3.5.1 自下而上分析的基本方法思路:从句子ω开始,从左到右扫描ω,反复用产生式的左部替换产生式的右部、谋求对ω的匹配,最终得到文法的开始符号,或者发现一个错误。

3.5.1.1 规范归约与“剪句柄”定义3.13设αβδ是文法G的一个句型,若存在S =*>αAδ,A =+>β,则称β是句型αβδ相对于A的短语,特别的,若有A→β,则称β是句型αβδ相对于产生式A→β的直接短语。

一个句型的最左直接短语被称为句柄。

##①直观上,句型是一个完整结构,短语是句型中的某部分。

S是一个句型,而不是一个短语。

②短语形成的两个要素:1.从S可以推导出A,即S=*>αAδ;2.从A至少一次推导出β,即A=+>β。

特征:①短语:以非终结符为根的子树中所有从左到右排列的叶子;②直接短语:只有父子关系的树中所有从左到右排列的叶子(树高为2);③句柄:最左边父子关系树中所有从左到右排列的叶子(句柄是唯一的)。

问题:id1+id2是句型id1+id2*id3的一个短语吗?答案:不是。

因为:①没有一个E的子树,它的全部叶子是id1+id2;或者②找不到某个E,使得E=>* E*id3,E=>+ id1+id2定义3.14 若α是文法G的句子且满足下述条件,则称序列αn,αn-1,...,α0是α的一个最左归约。

1. αn=α2. α0=S(S是G 的开始符号)3. 对任何i(0<i<=n),αi-1是从αi把句柄替换为相应产生式左部非终结符得到的。

##注意:最左归约的逆过程是一个最右推导,分别称最右推导和最左归约为规范推导和规范归约。

语法分析实验报告

语法分析实验报告

语法分析实验报告语法分析实验报告引言语法分析是自然语言处理中的一项重要任务,它旨在根据给定的语法规则和输入句子,确定句子的结构和语法成分,并进行语义解析。

本实验旨在探索语法分析的基本原理和方法,并通过实际操作来加深对其理解。

实验目标本实验的主要目标是实现一个简单的自底向上的语法分析器,即基于短语结构文法的分析器。

具体而言,我们将使用Python编程语言来实现一个基于CYK 算法的语法分析器,并对其进行评估和分析。

实验过程1. 语法规则的定义在开始实验之前,我们首先需要定义一个适当的语法规则集。

为了简化实验过程,我们选择了一个简单的文法,用于分析包含名词短语和动词短语的句子。

例如,我们定义了以下语法规则:S -> NP VPNP -> Det NVP -> V NP2. 实现CYK算法CYK算法是一种自底向上的语法分析算法,它基于动态规划的思想。

我们将使用Python编程语言来实现CYK算法,并根据定义的语法规则进行分析。

具体而言,我们将根据输入的句子和语法规则,构建一个二维的表格,用于存储句子中各个子串的语法成分。

通过填充表格并进行推导,我们可以确定句子的结构和语法成分。

3. 实验结果与分析我们使用几个示例句子来测试我们实现的语法分析器,并对其结果进行分析。

例如,对于句子"the cat eats fish",我们的语法分析器可以正确地识别出该句子的结构,并给出相应的语法成分。

具体而言,我们的分析器可以识别出句子的主语是"the cat",谓语是"eats",宾语是"fish"。

通过对多个句子的测试,我们可以发现我们实现的语法分析器在大多数情况下都能正确地分析句子的结构和语法成分。

然而,在一些复杂的句子中,我们的分析器可能会出现一些错误。

这可能是由于语法规则的不完备性或者算法的限制所致。

结论与展望通过本实验,我们深入了解了语法分析的基本原理和方法,并实现了一个简单的自底向上的语法分析器。

实验三 自下而上语法分析及语义分析

实验三 自下而上语法分析及语义分析

实验三自下而上语法分析及语义分析一、实验目的:通过本实验掌握LR分析器的构造过程,并根据语法制导翻译,掌握属性文法的自下而上计算的过程。

二、实验学时:4学时。

三、实验内容根据给出的简单表达式的语法构成规则(见五),编制LR分析程序,要求能对用给定的语法规则书写的源程序进行语法分析和语义分析。

对于正确的表达式,给出表达式的值。

对于错误的表达式,给出出错位置。

四、实验方法采用LR分析法。

首先给出S-属性文法的定义(为简便起见,每个文法符号只设置一个综合属性,即该文法符号所代表的表达式的值。

属性文法的定义可参照书137页表6.1),并将其改造成用LR分析实现时的语义分析动作(可参照书145页表6.5)。

接下来给出LR分析表。

然后程序的具体实现:●LR分析表可用二维数组(或其他)实现。

●添加一个val栈作为语义分析实现的工具。

●编写总控程序,实现语法分析和语义分析的过程。

注:对于整数的识别可以借助实验1。

五、文法定义简单的表达式文法如下:E->E+T|E-T|TT->T*F|T/F|FF->(E)|i上式中,i 为整数。

六、处理程序例例1: 正确源程序例:23+(45+4)* 40分析结果应为:正确的表达式。

其值为:1983例2: 错误源程序例:5+(56+)-24分析结果应为:错误的表达式:出错位置为)附录:源程序#include <stdio.h>#include"string.h"#include <iostream>using namespace std;#define R 30#define C 20typedef struct elem{char e[4];}Elem; //ACTION表与GoTo表中的元素类型Elem LR[R][C]; //存放ACTION表与GoTo表中的内容typedef struct out{int order; //序号int state[10]; //状态栈char sign[30]; //符号栈char grasen[20]; //产生式char input[30]; //输入串char explen[50]; //解释说明}OutNode; //输出结果中每一行的类型OutNode out[20]; //存放输出结果char Sentence[20]; //存放文法的一个句子char GramSent[10][20]; //存放文法的一组产生式int row,colno; //row为状态个数数,colno为ACTION表与GoTo表列总数int stateTop=0,signTop=0; //状态栈与符号栈的栈顶位置(值与栈中元素的个数相等)void input_GramSent(){int i,num;printf("请输入文法中产生式的个数\n");scanf("%d",&num);for(i=0;i<num;i++){printf("请输入文法的第%d个产生式\n",i);scanf("%s",GramSent+i-1);}printf("请输入文法的一个句子\n");scanf("%s",Sentence);printf("**********************************************************\n");printf("* 文法的产生式如下: *\n");printf("**********************************************************\n");for(i=0;i<num;i++)printf("%s\n",GramSent+i);printf("**********************************************************\n");printf("* 文法的句子如下: *\n");printf("**********************************************************\n");printf("%s\n",Sentence);}void input_LR(int row,int colno) //row为行总数,colno为列总数{int i,j;char mid[4];printf("**********************************************************\n");printf("* 提示:每输入一个元素后就回车 *\n");printf("**********************************************************\n");printf("请输入LR分析表的终结符(包括#)与非终结符\n");for(j=0;j<colno;j++)scanf("%s",LR[0][j].e);for(i=0;i<row;i++){printf("请输入%d号状态所对应的各列的元素,空白的地方用s代替\n",i);for(j=0;j<colno;j++){scanf("%s",mid);if(strcmp(mid,"s")==0||strcmp(mid,"S")==0)strcpy(LR[i+1][j].e," ");elsestrcpy(LR[i+1][j].e,mid);}}}void output_LR(int row,int colno){int i,j;printf("**********************************************************\n"); printf("* LR分析表如下: *\n");printf("**********************************************************\n"); printf("\n");printf(" ");for(j=0;j<colno;j++)printf("%s ",LR[0][j].e);printf("\n");for(i=1;i<=row;i++){printf("%d ",i-1);for(j=0;j<colno;j++)printf("%s ",LR[i][j].e);printf("\n");}printf("\n");}int SignNum(char ch)//给定一个终结符或非终结符,返回其在ACTION表与GoTo表中的列位置int i;char c[2]="0";c[0]=ch;for(i=0;i<colno;i++)if(strcmp(c,LR[0][i].e)==0)return i;return -1;}int CharChangeNum(char* ch)//给定一数字字符串,返回其所对应的数字{int result=0;while(*ch!='\0'){result=result*10+(*ch-'0');ch++;}return result;}int OutResult(int s,int c,int i)//输出结果的第i+1行处理函数,(s 为状态,c为列){char mid[4],gra[20];int s_num,r_num;int n,len,j;strcpy(mid,LR[s+1][c].e);if(strcmp(mid," ")==0){ printf("不能规约\n"); return -2; }if(strcmp(mid,"acc")==0||strcmp(mid,"ACC")==0){ printf("规约成功\n"); return -1; }out[i+1].order=i+2;if(mid[0]=='s'||mid[0]=='S'){s_num=CharChangeNum(mid+1);//s_num为S后的数字for(j=0;j<stateTop;j++)out[i+1].state[j]=out[i].state[j];out[i+1].state[stateTop]=s_num;out[i+1].state[++stateTop]=-1; //完成第i+1行的状态栈赋值strcpy(out[i+1].sign,out[i].sign);out[i+1].sign[signTop]=out[i].input[0];out[i+1].sign[++signTop]='\0'; //完成第i+1行的符号栈的赋值strcpy(out[i+1].grasen," "); //完成第i+1行的产生式的赋值strcpy(out[i+1].input,out[i].input+1); //完成第i+1行的输入符号串的赋值}else if(mid[0]=='r'||mid[0]=='R'){r_num=CharChangeNum(mid+1);//r_num为r后的数字strcpy(gra,*(GramSent+r_num-1));len=strlen(gra);for(j=0;j<len;j++)if(gra[j]=='-' && gra[j+1]=='>')break;n=strlen(gra+j+2);stateTop-=n; signTop-=n;for(j=0;j<stateTop;j++)out[i+1].state[j]=out[i].state[j];j=SignNum(gra[0]);out[i+1].state[stateTop]=CharChangeNum(LR[out[i+1].state[stateTop-1]+1][ j].e);out[i+1].state[++stateTop]=-1; //完成第i+1行的状态栈赋值strcpy(out[i+1].sign,out[i].sign);out[i+1].sign[signTop]=gra[0];out[i+1].sign[++signTop]='\0'; //完成第i+1行的符号栈的赋值strcpy(out[i+1].grasen,gra); //完成第i+1行的产生式的赋值strcpy(out[i+1].input,out[i].input); //完成第i+1行的输入符号串的赋值}return 1;}void OutputResult(int r){int i,j;printf("**********************************************************\n"); printf("* 句子:%s 用LR分析表规约过程如下:*\n",Sentence);printf("**********************************************************\n"); for(i=0;i<=r;i++){j=0;printf("%2d ",out[i].order);while(out[i].state[j]!=-1)printf("%d",out[i].state[j++]);printf(" %s %s %s\n",out[i].sign,out[i].grasen,out[i].input);}}int OutControl()//输出结果的总控函数{int s_num,i=0;out[0].order=1; //序号赋值out[0].state[0]=0; stateTop=1; out[0].state[stateTop]=-1; //状态栈赋值,置栈顶位strcpy(out[0].sign,"#"); signTop=1; //符号栈赋值,置栈顶位strcpy(out[0].grasen," "); //产生式为空strcpy(out[0].input,Sentence); //以下两行为输入串赋值strcat(out[0].input,"#");strcpy(out[0].explen,"0和#进栈"); //解释说明//初使化输出结果的第一行while(1){s_num=SignNum(out[i].input[0]);//if(s_num!=-1)if(OutResult(out[i].state[stateTop-1],s_num,i)!=1)break;i++;}return i;}main(){int r;printf("**********************************************************\n"); printf("* 函数的输入: 文法的产生式,文法句型的一个句子,LR分析表 *\n");printf("* 函数的输出: LR分析器的工作过程与说明 *\n");printf("**********************************************************\n"); printf("请输入LR分析表中终结符与非终结符的总个数\n");scanf("%d",&colno);printf("请输入LR分析表中状态的总个数\n");scanf("%d",&row);input_LR(row,colno);output_LR(row,colno);input_GramSent();r=OutControl(); //r为输出结果的行数OutputResult(r);}七、实验小结这个程序是从网上下载下来的,根据这个实验要求做了些更改,但是总是出现溢出错误,只能运行到LR分析表的部分(如截图),没有找到解决问题的办法。

语法分析(自上而下分析)实验报告

语法分析(自上而下分析)实验报告

实习二语法分析-自上而下分析一、实验目的使用预测分析方法对输入的表达式进行分析,掌握其具体的使用并且学会去分析一个文法。

二、实验内容1.设计表达式的语法分析器算法(使用预测分析)2.编写一段代码并上机调试查看其运行结果三、实验要求使用LL(1)分析算法设计表达式的语法分析器LL(1)文法是一个自上而下的语法分析方法,它是从文法的开始符号出发,生成句子的最左推导,从左到右扫描源程序,每次向前查看一个字符,确定当前应该选择的产生式。

实现LL(1)分析的另一种有效方法是使用一张分析表和一个栈进行联合控制。

预测分析程序的总控程序在任何时候都是按STACK栈顶符号X和当前a的输入符号行事的。

对于任何(X,a),总控程序每次都执行三种可能的动作之一。

1.若X=a=“#”,则宣布分析成功,停止分析过程2.若X=a≠“#”,则把X从STACK栈顶逐出,让a指向下一个输入符号。

3.若X是一个非终结符,则查看分析表。

四、运行结果(本程序只能对由'i','+','*','(',')'构成的以'#'结束的字符串进行分析)五、源程序实现/*LL(1)分析法源程序,只能在VC++中运行*/#include<stdio.h>#include<stdlib.h>#include<string.h>#include<dos.h>char A[20];char B[20];char v1[20]={'i','+','*','(',')','#'};/*终结符*/char v2[20]={'E','G','T','S','F'};/*非终结符*/int j=0,b=0,top=0,l;/*L为输入串长度*/typedef struct type{char origin;/*大写字符*/char array[5];/*产生式右边字符*/int length;/*字符个数*/}type;type e,t,g,g1,s,s1,f,f1;/*结构体变量*/ type C[10][10];/*预测分析表*/void print()/*输出分析栈*/{int a;/*指针*/for(a=0;a<=top+1;a++)printf("%c",A[a]);printf("\t\t");}/*print*/void print1()/*输出剩余串*/{int j;for(j=0;j<b;j++)/*输出对齐符*/printf(" ");for(j=b;j<=l;j++)printf("%c",B[j]);printf("\t\t\t");}/*print1*/void main(){int m,n,k=0,flag=0,finish=0;char ch,x;type cha;/*用来接受C[m][n]*//*把文法产生式赋值结构体*/e.origin='E';strcpy(e.array,"TG");e.length=2;t.origin='T';strcpy(t.array,"FS");t.length=2;g.origin='G';strcpy(g.array,"+TG");g.length=3;g1.origin='G';g1.array[0]='^';g1.length=1;s.origin='S';strcpy(s.array,"*FS");s.length=3;s1.origin='S';s1.array[0]='^';s1.length=1;f.origin='F';strcpy(f.array,"(E)");f.length=3;f1.origin='F';f1.array[0]='i';f1.length=1;for(m=0;m<=4;m++)/*初始化分析表*/for(n=0;n<=5;n++)C[m][n].origin='N';/*全部赋为空*/ /*填充分析表*/C[0][0]=e;C[0][3]=e;C[1][1]=g;C[1][4]=g1;C[1][5]=g1;C[2][0]=t;C[2][3]=t;C[3][1]=s1;C[3][2]=s;C[3][4]=C[3][5]=s1;C[4][0]=f1;C[4][3]=f;printf("请输入要分析的字符串:");do/*读入分析串*/{scanf("%c",&ch);if ((ch!='i') &&(ch!='+') &&(ch!='*')&&(ch!='(')&&(ch!=')')&&(ch!='#')){printf("输入串中有非法字符\n");exit(1);}B[j]=ch;j++;}while(ch!='#');l=j;/*分析串长度*/ch=B[0];/*当前分析字符*/A[top]='#'; A[++top]='E';/*'#','E'进栈*/printf("步骤\t\t分析栈\t\t剩余字符\t\t所用产生式\n");do{x=A[top--];/*x为当前栈顶字符*/ printf("%d",k++);printf("\t\t");for(j=0;j<=5;j++)/*判断是否为终结符*/ if(x==v1[j]){flag=1;break;}if(flag==1)/*如果是终结符*/{if(x=='#'){finish=1;/*结束标记*/printf("acc!\n");/*接受*/getchar();getchar();exit(1);}/*if*/if(x==ch){print();print1();printf("%c匹配\n",ch);ch=B[++b];/*下一个输入字符*/flag=0;/*恢复标记*/}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",ch);/*输出出错终结符*/exit(1);}/*else*/}/*if*/else/*非终结符处理*/{for(j=0;j<=4;j++)if(x==v2[j]){m=j;/*行号*/break;}for(j=0;j<=5;j++)if(ch==v1[j]){n=j;/*列号*/break;}cha=C[m][n];if(cha.origin!='N')/*判断是否为空*/{print();print1();printf("%c->",cha.origin);/*输出产生式*/for(j=0;j<cha.length;j++)printf("%c",cha.array[j]);printf("\n");for(j=(cha.length-1);j>=0;j--)/*产生式逆序入栈*/ A[++top]=cha.array[j];if(A[top]=='^')/*为空则不进栈*/top--;}/*if*/else/*出错处理*/{print();print1();printf("%c出错\n",x);/*输出出错非终结符*/exit(1);}/*else*/}/*else*/}while(finish==0);}/*main*/。

语法分析实验报告

语法分析实验报告

语法分析实验报告一: 实验内容:编写语法分析程序, 实现对算术表达式的语法分析, 要求所分析的算术表达式由如下的文法产生。

E->E+T|E-T|TT->T*F|T/F|FF->id|(E)|num二: 实验要求:在对表达式进行分析的同时, 输出所采用的产生式。

1.编写LL(1)语法分析程序, 要求:编程实现算法4.2, 为给定的文法自动构造预测分析表编程实现算法4.1, 构造LL(1)预测分析程序,2.编写语法分析程序, 实现自底向上的分析, 要求:构造识别所有活前缀的DFA构造LR分析表编程实现算法4.3, 构造LR分析程序1.三: 实验分析:2.方法二(编写LL(1)语法分析程序)1.步骤:(1)根据题目所给出的文法构造相应的无左递归文法, 并求出该文法各非终结符的FIRST、FOLLOW集合;(2)构造文法的LL(1)分析表;(3)由此构造LL分析程序。

2.实现方法:1.输入缓冲区为一个字符型数组, 读入输入的算术表达式并保存在此, 以’$’结束;2.为构造文法的LL(1)分析表, 构建一个相对应的字符串数组;3.在实际程序中P代表E', Q代表T', e代表ε,i代表id, n代表num;4.处理输入表达式中代表id和num的子串, 分别将它们转化为'i'和'n'进行分析;5.LL(1)预测分析程序的总控程序在任何时候都是按STACK栈顶符号X和当前的输入符号a做哪种过程的。

对于任何(X,a),总控程序每次都执行下述三种可能的动作之一:(1)若X = a =‘$’, 则宣布分析成功, 停止分析过程。

(2)若X = a!=‘$’, 则把X从STACK栈顶弹出, 让a指向下一个输入符号。

①如果是终结符合, 则栈不加入新符号②如果是非终结符合, 则把表达式右边入栈(3)若M[A, a]中存放着“出错标志”, 则调用出错诊断程序ERROR。

自下而上语法分析

自下而上语法分析

自下而上语法分析1、规约:自下而上的语法分析过程:分为简单优先分析法,算符优先分析法,LR分析法。

2、自下而上的语法分析过程思想:自下而上的语法分析过程是一个最左规约的过程,从输入串开始,朝着文法的开始符号进行规约,直到文法的开始符号为止的过程。

输入串在这里是指词法分析器送来的单词符号组成的二元式的有限序列。

3、自下而上的PDA(下推自动机)工作方式:“移近-规约”方式注:初态时栈内仅有栈顶符“#”,读头指在最左边的单词符号上。

语法分析程序执行的动作:◆移进:读入一个单词并压入栈内,读头后移◆规约:检查栈顶若干符号能否进行规约,若能,就以产生式左部代替该符号串,同时输出产生式编号。

◆识别成功:移近-规约的结局是栈内只剩下栈底符号和文法的开始符号,读头也指向语句的结束符。

◆识别失败。

4、判读一语句是否是该文法的合法语句(可以用语法树)5、优先分析器:简单优先分析法(理论简单,实际比较麻烦)算符优先分析法6、LR分析器7、相邻文法符号之间的优先关系◆在句型中,句柄内各相邻符号之间具有相同的优先级。

◆由于句柄要先规约,所以规定句柄两端符号的优先级要比位于句柄之外的相邻符号的优先级高。

(#的优先级是最低的。

)9、简单优先文法:定义:一个文法G,如果它不含ε的产生式,也不含任何右部相同的不同产生式,并且它的任何符号(X,Y)-X,Y是非终结符或终结符—或者没有关系,或者存在优先级相同或低于、高于等关系之一,则这是一个简单优先文法。

10、简短优先分析的思想1)简单优先矩阵:根据优先关系的定义:将简单优先文法中各文法符号之间的这种关系用一个矩阵表示,称作简单优先矩阵。

2)PDA读入一个单词后,比较栈顶符号和该单词的优先级,若栈顶符号优先级低于该单词,继续读入;若栈顶符号优先级高于或者等于读入符号,则找句柄进行规约,找不到句柄继续读入11、简单优先法的优缺点:1、优点:算法比较好理解。

2、缺点:适用范围小,分析表尺寸太大。

语法之自下而上分析

语法之自下而上分析
在上例中当进行完步骤5后,符号栈和剩余输入符号 串的内容为:
5
#aAb
cde#
即输入符号串已经归约为:#aAbcde#,根据上述算法, 下一步Ab和b都可以归约(它们都在符号栈的栈顶且有 产生式AAb和Ab)。假若判b为句柄,则可把b归约 为A,即符号串归约为:#aAAcde#。那么,后面的工 作无论怎样做,都无法归约成功。
例2,设有文法G[E]:
F
+ * ( ) i STACK EFT , ii
EE+T |T TT*F | F
F(E) | i
E 10 01 10 0 01 T 0 01 10 0 10 F 0 0 10 0 10
TE ,, ** E,+ TFE,,((
①数组元素初始化为FALSE(用0表示FF)II;RRSSTTVVTT((ET))=={{+*,,*(,,(i,} i} ② F[U从,b文]=法T中RU找E出(用形1表如示U);b…E或EU+TVFbI的R产TST生VT式*TF,(F并)=使F{对(,应(iE}的) 数F组元i 素
自下而上分析 采用最左归约即规范归约。
5.1 自底向上分析的一般过程
一、一般过程:
一般的自底向上分析法,也称为“ 移进—归约”法,其一 般过程为: (1)设置一个存放符号的栈称为符号栈,用于记录分析的过程和确 定下一步的动作。
(2)把输入符号按扫描顺序逐个移进栈里(符号栈),当栈顶的符号 组成的符号串形成一个句柄时(正好是某条产生式的右部),就进 行归约。即把该符号串用与它对应的产生式左部的非终结符号代 替,仍然置于栈顶。
a的优先级高于b 记为: a .> b a的优先级等于b 记为: a . b a的优先级低于b 记为: a<. b
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验三自下而上语法分析及语义分析一、实验目的:通过本实验掌握LR分析器的构造过程,并根据语法制导翻译,掌握属性文法的自下而上计算的过程。

二、实验学时:4学时。

三、实验内容根据给出的简单表达式的语法构成规则(见五),编制LR分析程序,要求能对用给定的语法规则书写的源程序进行语法分析和语义分析。

对于正确的表达式,给出表达式的值。

对于错误的表达式,给出出错位置。

四、实验方法采用LR分析法。

首先给出S-属性文法的定义(为简便起见,每个文法符号只设置一个综合属性,即该文法符号所代表的表达式的值。

属性文法的定义可参照书137页表6.1),并将其改造成用LR分析实现时的语义分析动作(可参照书145页表6.5)。

接下来给出LR分析表。

然后程序的具体实现:●LR分析表可用二维数组(或其他)实现。

●添加一个val栈作为语义分析实现的工具。

●编写总控程序,实现语法分析和语义分析的过程。

注:对于整数的识别可以借助实验1。

五、文法定义简单的表达式文法如下:E->E+T|E-T|TT->T*F|T/F|FF->(E)|i上式中,i 为整数。

六、处理程序例例1: 正确源程序例:23+(45+4)* 40分析结果应为:正确的表达式。

其值为:1983例2: 错误源程序例:5+(56+)-24分析结果应为:错误的表达式:出错位置为)附录:源程序#include <stdio.h>#include"string.h"#include <iostream>using namespace std;#define R 30#define C 20typedef struct elem{char e[4];}Elem; //ACTION表与GoTo表中的元素类型Elem LR[R][C]; //存放ACTION表与GoTo表中的内容typedef struct out{int order; //序号int state[10]; //状态栈char sign[30]; //符号栈char grasen[20]; //产生式char input[30]; //输入串char explen[50]; //解释说明}OutNode; //输出结果中每一行的类型OutNode out[20]; //存放输出结果char Sentence[20]; //存放文法的一个句子char GramSent[10][20]; //存放文法的一组产生式int row,colno; //row为状态个数数,colno为ACTION表与GoTo表列总数int stateTop=0,signTop=0; //状态栈与符号栈的栈顶位置(值与栈中元素的个数相等)void input_GramSent(){int i,num;printf("请输入文法中产生式的个数\n");scanf("%d",&num);for(i=0;i<num;i++){printf("请输入文法的第%d个产生式\n",i);scanf("%s",GramSent+i-1);}printf("请输入文法的一个句子\n");scanf("%s",Sentence);printf("**********************************************************\n");printf("* 文法的产生式如下: *\n");printf("**********************************************************\n");for(i=0;i<num;i++)printf("%s\n",GramSent+i);printf("**********************************************************\n");printf("* 文法的句子如下: *\n");printf("**********************************************************\n");printf("%s\n",Sentence);}void input_LR(int row,int colno) //row为行总数,colno为列总数{int i,j;char mid[4];printf("**********************************************************\n");printf("* 提示:每输入一个元素后就回车 *\n");printf("**********************************************************\n");printf("请输入LR分析表的终结符(包括#)与非终结符\n");for(j=0;j<colno;j++)scanf("%s",LR[0][j].e);for(i=0;i<row;i++){printf("请输入%d号状态所对应的各列的元素,空白的地方用s代替\n",i);for(j=0;j<colno;j++){scanf("%s",mid);if(strcmp(mid,"s")==0||strcmp(mid,"S")==0)strcpy(LR[i+1][j].e," ");elsestrcpy(LR[i+1][j].e,mid);}}}void output_LR(int row,int colno){int i,j;printf("**********************************************************\n"); printf("* LR分析表如下: *\n");printf("**********************************************************\n"); printf("\n");printf(" ");for(j=0;j<colno;j++)printf("%s ",LR[0][j].e);printf("\n");for(i=1;i<=row;i++){printf("%d ",i-1);for(j=0;j<colno;j++)printf("%s ",LR[i][j].e);printf("\n");}printf("\n");}int SignNum(char ch)//给定一个终结符或非终结符,返回其在ACTION表与GoTo表中的列位置int i;char c[2]="0";c[0]=ch;for(i=0;i<colno;i++)if(strcmp(c,LR[0][i].e)==0)return i;return -1;}int CharChangeNum(char* ch)//给定一数字字符串,返回其所对应的数字{int result=0;while(*ch!='\0'){result=result*10+(*ch-'0');ch++;}return result;}int OutResult(int s,int c,int i)//输出结果的第i+1行处理函数,(s 为状态,c为列){char mid[4],gra[20];int s_num,r_num;int n,len,j;strcpy(mid,LR[s+1][c].e);if(strcmp(mid," ")==0){ printf("不能规约\n"); return -2; }if(strcmp(mid,"acc")==0||strcmp(mid,"ACC")==0){ printf("规约成功\n"); return -1; }out[i+1].order=i+2;if(mid[0]=='s'||mid[0]=='S'){s_num=CharChangeNum(mid+1);//s_num为S后的数字for(j=0;j<stateTop;j++)out[i+1].state[j]=out[i].state[j];out[i+1].state[stateTop]=s_num;out[i+1].state[++stateTop]=-1; //完成第i+1行的状态栈赋值strcpy(out[i+1].sign,out[i].sign);out[i+1].sign[signTop]=out[i].input[0];out[i+1].sign[++signTop]='\0'; //完成第i+1行的符号栈的赋值strcpy(out[i+1].grasen," "); //完成第i+1行的产生式的赋值strcpy(out[i+1].input,out[i].input+1); //完成第i+1行的输入符号串的赋值}else if(mid[0]=='r'||mid[0]=='R'){r_num=CharChangeNum(mid+1);//r_num为r后的数字strcpy(gra,*(GramSent+r_num-1));len=strlen(gra);for(j=0;j<len;j++)if(gra[j]=='-' && gra[j+1]=='>')break;n=strlen(gra+j+2);stateTop-=n; signTop-=n;for(j=0;j<stateTop;j++)out[i+1].state[j]=out[i].state[j];j=SignNum(gra[0]);out[i+1].state[stateTop]=CharChangeNum(LR[out[i+1].state[stateTop-1]+1][ j].e);out[i+1].state[++stateTop]=-1; //完成第i+1行的状态栈赋值strcpy(out[i+1].sign,out[i].sign);out[i+1].sign[signTop]=gra[0];out[i+1].sign[++signTop]='\0'; //完成第i+1行的符号栈的赋值strcpy(out[i+1].grasen,gra); //完成第i+1行的产生式的赋值strcpy(out[i+1].input,out[i].input); //完成第i+1行的输入符号串的赋值}return 1;}void OutputResult(int r){int i,j;printf("**********************************************************\n"); printf("* 句子:%s 用LR分析表规约过程如下:*\n",Sentence);printf("**********************************************************\n"); for(i=0;i<=r;i++){j=0;printf("%2d ",out[i].order);while(out[i].state[j]!=-1)printf("%d",out[i].state[j++]);printf(" %s %s %s\n",out[i].sign,out[i].grasen,out[i].input);}}int OutControl()//输出结果的总控函数{int s_num,i=0;out[0].order=1; //序号赋值out[0].state[0]=0; stateTop=1; out[0].state[stateTop]=-1; //状态栈赋值,置栈顶位strcpy(out[0].sign,"#"); signTop=1; //符号栈赋值,置栈顶位strcpy(out[0].grasen," "); //产生式为空strcpy(out[0].input,Sentence); //以下两行为输入串赋值strcat(out[0].input,"#");strcpy(out[0].explen,"0和#进栈"); //解释说明//初使化输出结果的第一行while(1){s_num=SignNum(out[i].input[0]);//if(s_num!=-1)if(OutResult(out[i].state[stateTop-1],s_num,i)!=1)break;i++;}return i;}main(){int r;printf("**********************************************************\n"); printf("* 函数的输入: 文法的产生式,文法句型的一个句子,LR分析表 *\n");printf("* 函数的输出: LR分析器的工作过程与说明 *\n");printf("**********************************************************\n"); printf("请输入LR分析表中终结符与非终结符的总个数\n");scanf("%d",&colno);printf("请输入LR分析表中状态的总个数\n");scanf("%d",&row);input_LR(row,colno);output_LR(row,colno);input_GramSent();r=OutControl(); //r为输出结果的行数OutputResult(r);}七、实验小结这个程序是从网上下载下来的,根据这个实验要求做了些更改,但是总是出现溢出错误,只能运行到LR分析表的部分(如截图),没有找到解决问题的办法。

相关文档
最新文档