语法分析之递归子程序
子程序的嵌套与递归
![子程序的嵌套与递归](https://img.taocdn.com/s3/m/277ba71d6294dd88d1d26b9b.png)
子程序的嵌套与递归
1.1 子程序的嵌套
主程序调用子程序,若子程序又调用另一个子程序,则称 之为嵌套,可见主程序与子程序都是相对的概念,主程序也可 能是另一个程序的子程序。子程序嵌套的结构如下图:
┇
CALL SUB1 ┇
SUB1 PROC ┇
CALL SUB2 ┇
RET
SUB2 PROC
ENDS
MY_CODE SEGMENT
ASSUME
CS:MY_CODE,DS:MY_DATA
START:MOV AX,MY_DATA
MOV DS,AX
MOV AX,N CALL FACT
;求N!
MOV ANS,AX
MOV AH,4CH
INT 21H
;功能:求X!,入口参数:AX,出口参数:结
果在AX中
RET
BTOBCD ENDP
DISP
PROC
MOV AX,BCD
ADD AH,0D0H
MOV BCD,AX
;最高位无用,显示'='
MOV BX,4
MOV CL,4
LP2: MOV AX,BCD
ROL AX,CL
;循环4次移位取出最高4位
MOV BCD,AX
MOV DX,AX
AND DX,000FH
ADD DL,30H;转换为ASCII码
DAA
ADC AH,DH;十进制加法
MOV BCD,AX;存储部分和
NEXT: MOV AL,DL
ADD AL,DL;权*2转为十进制数
DAA
MOV DL,AL
ADC DH,0 ; 权 的 十 进 制 数 依 次
是01H/02H/04H┅/0128H
pl0语法分析词法分析语义分析
![pl0语法分析词法分析语义分析](https://img.taocdn.com/s3/m/451964ae3b3567ec112d8a43.png)
作者:love冥天出处:PL/O语言是Pascal语言的一个子集,我们这里分析的PL/O的编译程序包括了对PL/O语言源程序进行分析处理、编译生成类PCODE代码,并在虚拟机上解释运行生成的类PCODE代码的功能。
PL/O语言编译程序釆用以语法分析为核心、一遍扫描的编译方法。
词法分析和代码生成作为独立的子程序供语法分析程序调用。
语法分析的同时,提供了出错报告和出错恢复的功能。
在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。
词法分析子程序分析:词法分析子程序名为getsym,功能是从源程序中读出一个单词符号(token), 把它的信息放入全局变量sym. id和num中,语法分析器需要单词时,直接从这三个变量中获得。
(注意!语法分析器每次用完这三个变量的值就立即调用getsym子程序获取新的单词供下一次使用。
而不是在需要新单词时才调用getsym iS 程。
)getsym过程通过反复调用getch子过程从源程序过获取字符,并把它们拼成单词。
getch过程中使用了行缓冲区技术以提高程序运行效率。
词法分析器的分析过程:调用getsym时,它通过getch过程从源程序中获得一个字符。
如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把sym变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把sym置为ident,把这个单词存入id变量。
查保留字表时使用了二分法查找以提高效率。
如果getch获得的字符是数字,则继续用getch获取数字,并把它们拼成一个整数,然后把sym置为number,并把拼成的数值放入num变量。
如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把sym则成相应的类型。
如果遇到不合法的字符,把sym置成nul。
语法分析子程序分析:语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语意生成相应的代码,并提供了出错处理的机制。
编译原理-递归下降子程序-课程设计报告
![编译原理-递归下降子程序-课程设计报告](https://img.taocdn.com/s3/m/08576d28c8d376eeafaa3132.png)
编译原理课程设计报告2011 年 12 月 2 日设计题目 递归下降分析程序的实现 学号专业班级 计算机科学与技术学生姓名指导教师一、实验目的:(1)掌握自上而下语法分析的要求与特点。
(2)掌握递归下降语法分析的基本原理和方法。
(3)掌握相应数据结构的设计方法。
二、实验内容:递归下降分析程序的实现设计内容及要求:对文法 G: E→E+T|T构造出G的递归下降分析程序。
程序显示输出T→T*F|F匹配过程(即自上而下生成语法分析树的步骤,F→(E)|i 输出各匹配产生式序号即可)。
三、设计思路:(1)语法分析:语法分析是编译程序的核心部分,任务是分析一个文法的句子结构。
递归下降分析程序的实现的功能:按照文法的产生式(语言的语法规则),识别输入符号串是否为一个句子(合式程序)。
(2)自上而下分析:从文法的开始符号出发,向下推导,推出句子。
可分为带“回溯”的和不带回溯的递归子程序(递归下降)分析方法。
它的主旨是对任何输入串,试图用一切可能的办法,从文法开始符号(根结点)出发,自上而下地为输入串建立一棵语法树。
或者说,为输入串寻找一个最左推导。
也即从文法的开始符号出发,反复使用各种产生式,寻找"匹配"的推导。
(3)递归下降分析法:对每一语法变量(非终结符)构造一个相应的子程序,每个子程序识别一定的语法单位,通过子程序间的信息反馈和联合作用实现对输入串的识别。
(4)分析过程中遇到的问题:a. 分析过程中,当一个非终结符用某一个候选匹配成功时,这种匹配可能是暂时的。
出错时,不得不“回溯”。
b.文法左递归问题。
含有左递归的文法将使自上而下的分析陷入无限循环。
(5)构造不带回溯的自上而下分析算法:a.要消除文法的左递归性:一个文法可以消除左递归的条件是①不含以 为右部的产生式②不含回路。
b.克服回溯,构造不带回溯的自上而下分析的文法条件(6)满足LL(1)文法的三个条件:①. 文法不含左递归,②. 对于文法中每一个非终结符A的各个产生式的候选首符集两两不相交。
子程序调用自己称为递归调用
![子程序调用自己称为递归调用](https://img.taocdn.com/s3/m/ee736c14854769eae009581b6bd97f192279bfe8.png)
递归子程序调用自己称为递归调用,用自身的简单情况来定义自己。
如⑴求n!⎪⎩⎪⎨⎧⨯-=n n )!1(1n!⑵斐波纳契数列⎪⎪⎩⎪⎪⎨⎧-+-=)2()1(10fib(n)n fib n fib⑶给定n (n>=1),求1+2+3+…+n 的值。
设s(n)=1+2+3+…+(n-1)+n则 ⎪⎩⎪⎨⎧+-=nn s n s )1(1)(能用递归算法求解的的问题一般应该满足如下要求:⑴符合递归的描述:需要解决的问题可以化为子问题求解,而子问题求解的方法与原问题相同,只是数量增大与减少;⑵递归调用的次数是有限的;⑶必须有递归的结束条件。
归纳起来递归的两个条件:⑴递归有边界条件。
⑵递归形式。
当n=0时 当n>0时当n=1时 当n=2时 当n>2时当n=1时当n>1时例 1、求n!分析:根椐数学知识,0!=1,正整数N的阶乘为:N*(N-1)*(N-2)*…*2*1,该阶乘序列可转换为求N*(N-1)!,而(N-1)!以可转换为(N-1)*(N-2)!,……,直至转换为1*0!,而0!=1。
源程序如下:program ex;function f(n:integer):longint;beginif n=0 then f:=1 {递归边界}else f:=f(n-1)*n {递归形式}end;begin {main}writeln(f(3))end.在过程f中,当n>1时,又调用过程f,参数为n-1,…,这种操作一直持续到n=0为止。
例如当n=5时,f (5)的值变为5*f (4),求 f ( 4)又变为4*f (3),…,当n= 0时递归停止,逐步返回到第一次调用的初始处,返回结果5*4*3*2*1,即5!。
例2、斐波纳契数列0、1、1、2、3、5、8、13、21、34、……从第三项开始,每一项都是紧挨着的前两项之和。
编程求该数列第n项。
分析:我们已经知道菲波纳葜数列的各数列的产生可用下列公式表示:f(1)=0f(2)=1 f(n)=f(n-1)+f(n-2) (当n>2时)因此当n大于2时,求第n项值可转化为求第n-1项值与第n-2项值的和;而求第n-1项又可转化为求n-2项值与n-3项的和,相应地,求n-2项值可转化为求n-3项值和n-4项值的和;……;如此反复,直至转化为求第1项或第2项值,而第 1项与第2项为已知值0和1。
汇编语言——子程序的递归
![汇编语言——子程序的递归](https://img.taocdn.com/s3/m/861f17878762caaedd33d49c.png)
递归子程序的基本模式是: 若参数满足问题的最简条件,则 直接求解答案,作为本次子程序调用的结果 否则 求解分解出的小问题中可直接求解者; 对小问题中的同型者,以较简单的参数调用自身; 把各个小问题的答案拼装,作为本次调用结果。 下面是Pascal语言的一个递归子程序,用于求n!。 FUNCTION fact(n:INTEGER):INTEGER; BEGIN IF n<=1 THEN fact:=1 ELSE fact:=n*fact(n-1); END;
0001 0002 03F0 001A 0001 0002 0003 03FA 001A 0002 003D 0003 0000 0040 0003 (g)
处理完最简情况后,已在AX中准备好最深层调用的结 果,即出口参数值,再由第13行转到第20行,连续三条出栈 指令,从图6.7(g)所示的栈中依次取出三个字0001、0002和 03F0H,分别给DX、BX及BP,此时栈的情况又回到图6.7(f)。 现在,递归调用开始从最深一层逐步返回,并在每一层返回 过程中要完成本层答案的组装。在求阶乘问题中组装就是做 本层参数与深一层调用结果的乘法操作。
code SEGMENT CS:CODE,SS:s fact PROC NEAR PUSH BP MOV BP,SP PUSH BX PUSH DX
MOV BX,[BP+4] CMP BX,1 JG f1
; (9)0005 ;(10)0008 ;(11)000B ;(12)000D ;(13)0010 ;(14)0013 ;(15)0015 ;(16)0016 ;(17)0017 ;(18)001A ;(19)001B
模块化程序设计是编写大型软件时的常用方法。汇编 语言的一个模块由若干个段和一个结束伪指令END构成, 并且只有主模块的END伪指令后面需要入口地址。各模块 可以各自用汇编程序进行翻译,得到各自的目标文件,再 用LINK软件连接成一个完整的程序。各个模块间相互通讯 时,要用PUBLIC和EXTRN伪指令说明标识符是公共的或 外部的。除了建立子程序库文件(.LIB)之外,还有其它方法 可以实现多个程序段间的拼接。 汇编语言的子程序可以进行递归调用,递归子程序在 编写上有其特殊性,需要把问题进行分解,找出最简情况, 对最简情况下的问题直接求解,非最简情况则递归调用进 一步分解。分解后的各个子问题最终还要拼装在一起,构 成原问题的解。
实验12 递归与外部子程序
![实验12 递归与外部子程序](https://img.taocdn.com/s3/m/d672383eeefdc8d376ee3267.png)
实验十二 递归与外部子程序递归子程序是FORTRAN90新增的功能之一,递归子程序适用于对递归问题的求解。
对于递归问题,使用递归子程序求解,将大大降低程序设计的难度。
一般情况下,应尽可能将求解问题描述成递推或递归问题,以便使用递归子程序求解。
递归子程序分递归函数子程序和递归子例行程序,递归子程序定义类似于普通子程序,不同之处是在FUNCTION 或SUBROUTINE 语句之前增加一个RECURSIVE 属性关键字前缀。
外部子程序是出现在主调程序单元之外的子程序,外部子程序和主程序可单独保存在不同的源程序文件中,可分别独立编译。
外部子程序可用于大型复杂的程序设计,可实现多人并行(同时)、协调、合作开发大型复杂程序。
使用外部子程序,有时需要在主调程序单元中通过EXTERNAL 语句声明。
外部子程序分外部函数子程序和外部子例行程序,外部子程序类似于普通子程序,不同之处是出现在主调程序单元之外。
本次实验是学习和掌握递归和外部子程序的一次系统实验活动。
通过本次实验,能够熟练使用递归和外部子程序设计和编写程序,求解比较复杂的实际问题。
一.实验目的1. 了解递归概念,掌握递归问题的求解方法。
2. 掌握递归子程序定义、调用、参数传递关系的基本内容和使用规则。
3. 了解外部子程序概念,掌握并行、协调、合作编写大型复杂程序的方法。
4. 掌握外部子程序定义、调用、参数传递关系的基本内容和使用规则。
5. 掌握使用递归和外部子程序设计和编写程序的方法。
二.实验内容11.问题描述已知:计算当x=2.85,n=15时的函数值。
使用递归函数求解该问题。
编写程序实现之。
x 和n 的值从键盘输入。
-------+-+-+=)2n (x )1n (x n x )n ,x (f x1x ++函数f 可用以下递推公式描述。
根据递推公式,学生自行设计递归函数求解算法。
3.程序编写根据递推公式和递推求解算法,学生自行编写程序,要求使用递归函数子程序实现。
编译原理语法分析递归下降子程序实验报告
![编译原理语法分析递归下降子程序实验报告](https://img.taocdn.com/s3/m/bf1050ceac51f01dc281e53a580216fc700a53dc.png)
编译原理语法分析递归下降子程序实验报告编译课程设计-递归下降语法分析课程名称编译原理设计题目递归下降语法分析一、设计目的通过设计、编制、调试一个具体的语法分析程序,加深对语法分析原理的理解,加深对语法及语义分析原理的理解,并实现对文法的判断,是算符优先文法的对其进行FirstVT集及LastVT集的分析,并对输入的字符串进行规约输出规约结果成功或失败。
二、设计内容及步骤内容:在C++ 6.0中编写程序代码实现语法分析功能,调试得到相应文法的判断结果:是算符优先或不是。
若是,则输出各非终结符的FirstVT与LastVT集的结果,还可进行字符串的规约,输出详细的规约步骤,程序自动判别规约成功与失败。
步骤:1.看书,找资料,了解语法分析器的工作过程与原理2.分析题目,列出基本的设计思路1定义栈,进栈,出栈函数○2栈为空时的处理○3构造函数判断文法是否是算符文法,算符优先文法○4构造FirstVT和LastVT函数对文法的非终结符进行分析○5是算符优先文法时,构造函数对其可以进行输入待规约○串,输出规约结果○6构造主函数,对过程进行分析3.上机实践编码,将设计的思路转换成C++语言编码,编译运行4.测试,输入不同的文法,观察运行结果详细的算法描述详细设计伪代码如下:首先要声明变量,然后定义各个函数1.void Initstack(charstack &s){//定义栈s.base=new charLode[20];s.top=-1; }2. void push(charstack&s,charLode w){//字符进栈s.top++;s.base[s.top].E=w.E;s.base[s.top].e=w.e;}3. void pop(charstack&s,charLode &w){//字符出栈w.E=s.base[s.top].E; 三、w.e=s.base[s.top].e;s.top--;}4. int IsEmpty(charstack s){//判断栈是否为空if(s.top==-1)return 1;else return 0;}5.int IsLetter(char ch){//判断是否为非终结符if(ch='A'&&ch= 'Z')return 1;else return 0;}6.int judge1(int n){ //judge1是判断是否是算符文法:若产生式中含有两个相继的非终结符则不是算符文法}7. void judge2(int n){//judge2是判断文法G是否为算符优先文法:若不是算符文法或若文法中含空字或终结符的优先级不唯一则不是算符优先文法8.int search1(char r[],int kk,char a){ //search1是查看存放终结符的数组r中是否含有重复的终结符}9.void createF(int n){ //createF函数是用F数组存放每个终结符与非终结符和组合,并且值每队的标志位为0;F数组是一个结构体}10.void search(charLode w){ //search函数是将在F数组中寻找到的终结符与非终结符对的标志位值为1 }分情况讨论://产生式的后选式的第一个字符就是终结符的情况//产生式的后选式的第一个字符是非终结符的情况11.void LastVT(int n){//求LastVT}12.void FirstVT(int n){//求FirstVT}13.void createYXB(int n){//构造优先表分情况讨论://优先级等于的情况,用1值表示等于}//优先级小于的情况,用2值表示小于//优先级大于的情况,用3值表示大于}14.int judge3(char s,char a){//judge3是用来返回在归约过程中两个非终结符相比较的值}15.void print(char s[],charSTR[][20],int q,int u,int ii,int k){//打印归约的过程}16. void process(char STR[][20],int ii){//对输入的字符串进行归约的过程}四、设计结果分两大类,四种不同的情况第一类情况:产生式的候选式以终结符开始候选式以终结符开始经过存在递归式的非终结符后再以终结符结束篇二:编译原理递归下降子程序北华航天工业学院《编译原理》课程实验报告课程实验题目:递归下降子程序实验作者所在系部:计算机科学与工程系作者所在专业:计算机科学与技术作者所在班级:xxxx作者学号:xxxxx_作者姓名:xxxx指导教师姓名:xxxxx完成时间:2011年3月28日一、实验目的通过本实验,了解递归下降预测分析的原理和过程以及可能存在的回溯问题,探讨解决方法,为预测分析表方法的学习奠定基础。
编译原理递归子程序
![编译原理递归子程序](https://img.taocdn.com/s3/m/6c7d073da32d7375a417806d.png)
#include<stdio.h>#include<conio.h>char str[50]; //保存输入的字符串char ch;int strLength=0; //字符串的长度int point=1; //标记当前判断的是第几个字符int T();int G();int F();int S();int wrong1(){ int i,j=1;for(i=1;i<strLength;i++){if(str[i]=='('){j=j+1;}if(str[i]==')'){j=j-1;}}if(j!=1){ printf("()需成对出现!\n");return 1;}}int wrong() //判断某些输入非法的情况{int i;for(i=1;i<strLength;i++) //不能两个i一起{if(str[i]==str[i+1]){printf("不能连续输入两个相同字符!\n");return 1;}}if(str[1]!='(' && str[1]!='i') //必须是以(或i开头{printf("首字符错误!\n");return 1;}if(str[strLength]!='i' && str[strLength]!=')') //必须是以)或i结尾{printf("最后一个字符错误!\n");return 1;}else return 0;}void nextchar() //前进一个字符函数{point++;ch=str[point];}int E() //E->TG{if(T()==1){if(G()==1) return 1;else return 0;}else return 0;}int G() //G->+TG|-TG G->ε{ch=str[point];if(ch=='+' || ch=='-'){nextchar();if(T()==1){if(G()==1) return 1;else return 0;}else return 0;}else return 1; //有ε的时候当ch无法配对也不能返回错误}int T() //T->FS{if(F()==1){if(S()==1) return 1;else return 0;}else return 0;}int S() //S->*FS|/FS S->ε{ch=str[point];if(ch=='*' || ch=='/'){nextchar();if(F()==1){if(S()==1) return 1;else return 0;}else return 0;}else return 1;//有ε的时候当ch无法配对也不能返回错误}int F() //F->(E) F->i{ch=str[point];if(ch=='('){nextchar();if(E()==1){if(ch==')'){nextchar();return 1;}else return 0;}else return 0;}else if(ch=='i'){nextchar();return 1;}else return 0;}void main(){int i;printf("\t递归下降分析程序\n");printf("*************************************************\n");printf("\t张英1104011024 11计本(1)班\n\n");printf("请输入待分析字符串(以#结束):");//输入提示scanf("%c",&ch);while(ch!='#'){strLength++;str[strLength]=ch;scanf("%c",&ch);}str[strLength+1]='#';printf("\n");if(wrong1()==1) //检查输入是否有误{printf("错误输入!\n");}else{if(wrong()==1) //初步检查输入是否合法{printf("输入错误!\n");}else{for(i=1;i<=strLength;i++)printf("%c",str[i]);ch=str[1];if(E()==1) printf(" 是合法符号串!\n");else printf(" 是非法符号串!\n");}}getch();}。
编译原理之递归下降语法分析程序(实验)
![编译原理之递归下降语法分析程序(实验)](https://img.taocdn.com/s3/m/aed6ff1b78563c1ec5da50e2524de518964bd32f.png)
编译原理之递归下降语法分析程序(实验)⼀、实验⽬的利⽤C语⾔编制递归下降分析程序,并对简单语⾔进⾏语法分析。
编制⼀个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。
⼆、实验原理每个⾮终结符都对应⼀个⼦程序。
该⼦程序根据下⼀个输⼊符号(SELECT集)来确定按照哪⼀个产⽣式进⾏处理,再根据该产⽣式的右端:每遇到⼀个终结符,则判断当前读⼊的单词是否与该终结符相匹配,若匹配,再读取下⼀个单词继续分析;不匹配,则进⾏出错处理每遇到⼀个⾮终结符,则调⽤相应的⼦程序三、实验要求说明输⼊单词串,以“#”结束,如果是⽂法正确的句⼦,则输出成功信息,打印“success”,否则输出“error”,并指出语法错误的类型及位置。
例如:输⼊begin a:=9;b:=2;c:=a+b;b:=a+c end #输出success输⼊a:=9;b:=2;c:=a+b;b:=a+c end #输出‘end' error四、实验步骤1.待分析的语⾔的语法(参考P90)2.将其改为⽂法表⽰,⾄少包含–语句–条件–表达式E -> E+T | TT -> T*F | FF -> (E) | i3. 消除其左递归E -> TE'E' -> +TE' | εT -> FT'T' -> *FT' | εF -> (E) | i4. 提取公共左因⼦5. SELECT集计算SELECT(E->TE) =FIRST(TE')=FIRSI(T)-FIRST(F)U{*}={(, i, *}SELECT(E'->+TE')=FIRST(+TE')={+}SELECT(E'->ε)=follow(E')=follow(E)={#, )}SELECT(T -> FT')=FRIST(FT')=FIRST(F)={(, i}SELECT(T'->*FT')=FRIST(*FT')={*}SELECT(T'->ε)=follow(T')=follow(T)={#, ), +}SELECT(F->(E))=FRIST((E)) ={(}SELECT(F->i)=FRIST(i) ={i}6. LL(1)⽂法判断 其中SELECT(E'->+TE')与SELECT(E'->ε)互不相交,SELECT(T'->*FT')与SELECT(T'->ε)互不相交,SELECT(F->(E))与SELECT(F->i)互不相交,故原⽂法为LL(1)⽂法。
递归子程序实验报告(3篇)
![递归子程序实验报告(3篇)](https://img.taocdn.com/s3/m/7679d9031fd9ad51f01dc281e53a580216fc50e5.png)
第1篇一、实验目的1. 理解递归的概念和原理;2. 掌握递归子程序的设计方法;3. 学会递归子程序在实际问题中的应用;4. 提高编程能力和算法设计能力。
二、实验原理递归是一种编程技巧,它允许函数调用自身。
递归子程序通常具有以下特点:1. 递归基准:确定递归结束的条件;2. 递归步骤:确定递归调用时的参数变化;3. 递归终止:当递归基准条件满足时,递归调用停止。
递归子程序在解决一些具有“分治”特点的问题时非常有效,如阶乘计算、斐波那契数列、汉诺塔等。
三、实验内容本次实验主要设计以下递归子程序:1. 计算阶乘;2. 计算斐波那契数列;3. 求汉诺塔问题的解。
1. 计算阶乘阶乘是指一个正整数n的阶乘,记作n!,表示为n×(n-1)×(n-2)×...×1。
计算阶乘的递归子程序如下:```cint factorial(int n) {if (n == 0) {return 1;} else {return n factorial(n - 1);}}```2. 计算斐波那契数列斐波那契数列是指这样一个数列:0, 1, 1, 2, 3, 5, 8, 13, ...,其中第n项是前两项的和。
计算斐波那契数列的递归子程序如下:```cint fibonacci(int n) {if (n == 0 || n == 1) {return n;} else {return fibonacci(n - 1) + fibonacci(n - 2);}}```3. 求汉诺塔问题的解汉诺塔问题是一个经典的递归问题,其目的是将n个盘子从一个柱子移动到另一个柱子,每次只能移动一个盘子,且在移动过程中大盘子不能放在小盘子上面。
求汉诺塔问题的解的递归子程序如下:```cvoid hanoi(int n, char from_rod, char to_rod, char aux_rod) {if (n == 1) {printf("Move disk 1 from rod %c to rod %c\n", from_rod, to_rod); return;}hanoi(n - 1, from_rod, aux_rod, to_rod);printf("Move disk %d from rod %c to rod %c\n", n, from_rod, to_rod); hanoi(n - 1, aux_rod, to_rod, from_rod);}```四、实验步骤1. 编写计算阶乘的递归子程序;2. 编写计算斐波那契数列的递归子程序;3. 编写求汉诺塔问题的解的递归子程序;4. 测试递归子程序的正确性;5. 分析递归子程序的性能。
4 语法分析(1)_ 递归下降分析法
![4 语法分析(1)_ 递归下降分析法](https://img.taocdn.com/s3/m/2f51b23e376baf1ffc4fada1.png)
• 扩展的巴科斯范式(EBNF) 扩展的巴科斯范式(EBNF) • 用EBNF描述语言,直观易懂,便于表示左递归的 EBNF描述语言 直观易懂, 描述语言, 消除和因子的提取,构造递归下降器时可采用这种 消除和因子的提取, 定义描述系统语言。 定义描述系统语言。 EBNF是在 EBNF是在BNF基础上扩展如下三组符号: 是在BNF基础上扩展如下三组符号 基础上扩展如下三组符号: • — 用花括号{α}表示闭包运算α*。 用花括号{α}表示闭包运算α*。 表示闭包运算 • — 用{α} n 0表示 可任意重复 到n次, 表示α可任意重复 可任意重复0到 次 • 特别地, 特别地,{α}n0=α0= ε。 。 • — 用方括号 表示{α}10, 用方括号[α]表示 表示 • 即表示α可以出现也可以不出现,等价于α 。 即表示 可以出现也可以不出现,等价于 | ε。 可以出现也可以不出现
例1
为下列表达式文法G[E]编写递归下降识别程序 为下列表达式文法G[E]编写递归下降识别程序。 编写递归下降识别程序。 E→ E+T | T T→ T*F | F F→ (E) | i 【解】 步骤1 消除左递归: 步骤1:消除左递归: E→ TE' E'→ +TE' | ε T→ FT' T'→ *FT' | ε F→ (E) | i 步骤2 编写递归下降识别子程序, 步骤2:编写递归下降识别子程序,这 里使用C/C++语言形式 语言形式。 里使用C/C++语言形式。
• 递归下降分析器的设计
设文法G=(V 设文法G=(VN,VT,P,S), VN={X1,X2,…,Xn}。 S), 对 G 的每个非终结符号 Xi , 可以按照下面方法设计子 的每个非终结符号X 程序P 程序Pi( ):
语法分析递归下降分析法
![语法分析递归下降分析法](https://img.taocdn.com/s3/m/0467d55da66e58fafab069dc5022aaea998f41b3.png)
语法分析递归下降分析法递归下降分析法是一种常用的语法分析方法,它通过构建递归子程序来解析输入的语法串。
该方法可以分为两个步骤:构建语法树和构建语法分析器。
首先,我们需要构建语法树。
语法树是一个表示语言结构的树形结构,它由各类语法片段(非终结符)和终结符组成。
构建语法树的过程就是根据文法规则从根节点开始递归地扩展子节点,直到达到文法推导出的终结符。
具体来说,我们可以通过以下步骤来构建语法树:1.设计满足语言结构的文法规则。
文法规则定义了语法片段之间的关系和转换规则。
2.将文法规则转换为程序中的递归子程序。
每个递归子程序对应一个语法片段,并按照文法规则递归地扩展子节点。
3.设计词法分析器将输入的语法串分词为单个有效的词法单元。
4.从语法树的根节点开始,根据递归子程序逐步扩展子节点,直到达到终结符。
同时,将每一步的扩展结果记录在语法树中。
接下来,我们需要构建语法分析器。
语法分析器是一个根据语法规则判断输入语法串是否符合语法规则的程序。
它可以通过递归下降分析法来实现。
具体来说,我们可以通过以下步骤来构建语法分析器:1.定义一个语法分析器的函数,作为程序的入口。
2.在语法分析器函数中,根据文法规则调用递归子程序,分析输入的语法串。
3.每个递归子程序对应一个语法片段,它会对输入的语法串进行识别和匹配,并根据文法规则进行扩展。
4.如果递归子程序无法匹配当前的输入,那么意味着输入的语法串不符合文法规则。
5.如果递归子程序成功扩展,并继续匹配下一个输入,则语法分析器会一直进行下去,直到分析完整个语法串。
总结起来,递归下降分析法是一种简单而有效的语法分析方法。
它通过构建递归子程序来解析输入的语法串,并构造出对应的语法树。
虽然递归下降分析法在处理左递归和回溯等问题上存在一定的困难,但它仍然是一种重要的语法分析方法,被广泛应用于编译器和自然语言处理等领域。
递归子程序递归
![递归子程序递归](https://img.taocdn.com/s3/m/3faebc0f2379168884868762caaedd3383c4b5df.png)
递归子程序一个过程或函数,如果在说明中出现对这个函数或过程本身的调用时,称这个函数或过程是递归函数或递归过程。
注意:(1) 递归就是在过程或函数里调用自身;(2) 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。
1、直接递归Procedure a(x:integer);┇┇begin┇a(30);┇end;直接递归是在过程或函数中直接调用自己。
上面说明过程a中又出现了过程调用a(30)。
2、间接递归procedure a(x:integer);┇begin┇b(y);┇end;procedure b(x:char);┇begin┇a(m);┇end;间接递归是通过调用其他过程或函数来调用自己。
上面说明过程a中出现了过程调用b(y),而过程b 中又出现了调用过程a(m)。
从简单起见,本课只介绍直接递归。
例1:求n!的递归子程序。
因为N!=1*2*3*4*……*n=[1*2*3*...*(N-1)]*N而(N-1)!=1*2*3*...*(N-1)所以N!=N*(N-1)!,则要求n!,只要先求(n-1)!,而(n-1)!与n!的计算方法是一样的,只不过缩小了计算范围。
由此可知(N-1)!=(N-1)*(N-2)!(N-2)!=(N-2)*(N-3)!…………3!=3*2!2!=2*1!1!=1*0!而数学中定义0!=1。
设 f(N)=N!那么 f(N-1)=(N-1)!则 f(N)=f(N-1)*N 这就是递归式子概括得到1N=0F(N)=N*f(N-1) N>0于是我们定义一个递归函数求N !。
function f(n:integer):real;beginif n>0 then f:= n*f(n-1) {递归}else f:=1; {递归终止}end;完整程序如下:program example;varnum:integer;jc:real;function f(n:integer):real;beginif n>0 then f:= n*f(n-1)else f:=1;end;beginreadln(num);jc:=f(num); writeln(num,’!=’,jc:10:0);end.若输入4,则要求f(4),函数递归执行过程如下:第一次第二次第三次第四次 第五次N=4n=3 n=2n=1 n=0 F:= n*f(n-1) f:= n*f(n-1) f:= n*f(n-1) f:= n*f(n-1) f:=1;=4*f(3) =3*f(2)=2*f(1) =1*f(0)=4*6=24 =3*2=6 =2*1=2 =1*1=1即f(4)=4*f(3)=4*(3*f(2))=4*(3*(2*f(1)))= 4*(3*(2*(1*f(0))))= 4*(3*(2*(1*1)))=4*(3*(2*1))= 4*(3*2))=4*6=24再看一个递归过程的执行过程例2:Program ex; Procedure p;① ②③ ④ ⑤⑥ ⑦ ⑧VarCh:char;BeginRead(ch);If ch<>’.’ Then p; {递归,当ch=’.’是递归终止条件}Write(ch); End; BeginP;Readln;End.输入abc. 执行过程如图所示:第一次 第二次 第三次第四次Read(ch); read(ch);read(ch);read(ch);Ch (p1)=’a ’ ch(p2)=’b’ ch(p3)=’c ’ ch(p4)=’.’P;p;p;条件不满足执行write(ch)Write(ch);Write(ch);Write(ch);输出ch(p4)为’.’输出ch(p1)为’a ’ 输出ch(p2)为’b ’ 输出ch(p3)为’c ’因为ch 是局部变量,每调用一次过程,ch 的值都会保留,也就是不同递归层次上取值是不同的。
编译原理实验二:LL(1)语法分析器
![编译原理实验二:LL(1)语法分析器](https://img.taocdn.com/s3/m/c625d5e6b9f67c1cfad6195f312b3169a451ea8c.png)
编译原理实验⼆:LL(1)语法分析器⼀、实验要求 1. 提取左公因⼦或消除左递归(实现了消除左递归) 2. 递归求First集和Follow集 其它的只要按照课本上的步骤顺序写下来就好(但是代码量超多...),下⾯我贴出实验的⼀些关键代码和算法思想。
⼆、基于预测分析表法的语法分析 2.1 代码结构 2.1.1 Grammar类 功能:主要⽤来处理输⼊的⽂法,包括将⽂法中的终结符和⾮终结符分别存储,检测直接左递归和左公因⼦,消除直接左递归,获得所有⾮终结符的First集,Follow集以及产⽣式的Select集。
#ifndef GRAMMAR_H#define GRAMMAR_H#include <string>#include <cstring>#include <iostream>#include <vector>#include <set>#include <iomanip>#include <algorithm>using namespace std;const int maxn = 110;//产⽣式结构体struct EXP{char left; //左部string right; //右部};class Grammar{public:Grammar(); //构造函数bool isNotTer(char x); //判断是否是终结符int getTer(char x); //获取终结符下标int getNonTer(char x); //获取⾮终结符下标void getFirst(char x); //获取某个⾮终结符的First集void getFollow(char x); //获取某个⾮终结符的Follow集void getSelect(char x); //获取产⽣式的Select集void input(); //输⼊⽂法void scanExp(); //扫描输⼊的产⽣式,检测是否有左递归和左公因⼦void remove(); //消除左递归void solve(); //处理⽂法,获得所有First集,Follow集以及Select集void display(); //打印First集,Follow集,Select集void debug(); //⽤于debug的函数~Grammar(); //析构函数protected:int cnt; //产⽣式数⽬EXP exp[maxn]; //产⽣式集合set<char> First[maxn]; //First集set<char> Follow[maxn]; //Follow集set<char> Select[maxn]; //select集vector<char> ter_copy; //去掉$的终结符vector<char> ter; //终结符vector<char> not_ter; //⾮终结符};#endif 2.1.2 AnalyzTable类 功能:得到预测分析表,判断输⼊的⽂法是否是LL(1)⽂法,⽤预测分析表法判断输⼊的符号串是否符合刚才输⼊的⽂法,并打印出分析过程。
编译原理分知识点习题自上而下语法分析 (1)
![编译原理分知识点习题自上而下语法分析 (1)](https://img.taocdn.com/s3/m/bf116d0b58fafab069dc0271.png)
1.设有文法G[S]:S→ABA→bB|AaB→Sb|a试消除该文法的左递归。
解:本题考查消除左递归的方法。
应用消除文法左递归的算法对文法G[S]消除左递归的过程如下:(1)将非终结符排序为:U1=S,U2=A,U3=B(2)进入算法排序:i=1时,对文法无影响i=2,j=1时:A→Aa有直接左递归,消去该直接左递归,得A→bBA’A’→aA’|εi=3,j=1时:改写文法,有B→ABb|aj=2时:改写文法,有B→bBA’Bb|a无左递归。
(3)所以文法G[S]消除左递归后变为:G’[S]:S→ABA→bBA’A’→aA’|εB→bBA’Bb|a2.设有文法G[E]:E→Aa|BbA→cA|eBB→bd试按照递归子程序法为该文法构造语法分析程序。
解:本题考查递归子程序的构造方法。
首先判断文法是否满足递归子程序法对文法的要求,然后再构造递归子程序。
因为:(1)该文法无左递归。
(2)文法的产生式E→Aa|Bb和A→cA|eB的右部有若干选项,判断这两条产生式右部各候选式的终结首符号集合是否两两互不相交。
对产生式E→Aa|Bb,有FIRST(Aa)∩FIRST(Bb)={c,e}∩{b}=ø对产生式A→cA|eB,有FIRST(cA)∩FIRST(eB)={c}∩{e}=ø文法中其他产生式都只有一个非空ε的右部。
综合(1)、(2),该文法可以采用自上而下分析方法进行语法分析而不会出现回朔和无限循环。
下面为该文法的每一个非终结符号构造递归子程序。
假设用READAWORD代表读下一个单词。
用P(E)、P(A)、P(B)分别表示非终结符号E、A、B对应的子程序名。
约定输入符号串以“#”作为输入结束符。
P(E)的递归子程序为:PROCEDURE P(E);BEGINIF WORD IN FIRST(Aa)THENBEGINP(A);READAWORD;IF WORD=’a’THEN READAWORDELSE ERRORENDELSE IF WORD IN FIRST(Bb)THENBEGINP(B);READAWORD;IF WORD=’b’THEN READAWORDELSE ERRORENDELSE ERROREND;P(A)的递归子程序为:PROCEDURE P(A);BEGINIF WORDD=’c’THENBEGINREADAWORD;P(A)ENDELSE IF WORD=’e’THENBEGINREADWORD;P(B)ENDELSE ERROREND;P(B)的递归子程序为:PROCEDURE P(B);BEGINIF WORD=’b’THENBEGINREADAWORD;IF WORD=’d’THEN READAWORDELSE ERRORENDELSE ERROREND;主程序中的主要内容为:READAWORD;P(E);IF WORD=”#”THEN WRITE(“RIGHT!”)ELSE WRITE(“ERROR!”)3.已知文法G[E]:G[E]:E→E+T|TT→T*F|FF→i|(E)请按递归子程序法为其构造语法分析程序。
递归子程序
![递归子程序](https://img.taocdn.com/s3/m/02f3c22c4b35eefdc8d3332e.png)
#include <stdio.h>#include<dos.h>#include<stdlib.h>#include<string.h>char a[50] ,b[50],d[200],e[10];char ch;int n1,i1=0,flag=1,n=5;int E();int E1();int T();int G();int S();int F();void input();void input1();void output();void main() /*递归分析*/{ int f,p,j=0;char x;d[0]='E';d[1]='=';d[2]='>';d[3]='T';d[4]='G';d[5]='#';printf("请输入字符串(长度<50,以#号结束)\n");do{scanf("%c",&ch);a[j]=ch;j++;}while(ch!='#');n1=j;ch=b[0]=a[0];printf("文法\t分析串\t\t分析字符\t剩余串\n");f=E1();if (f==0) return;if (ch=='#'){ printf("合法符号串\n");p=0;x=d[p];while(x!='#') {printf("%c",x);p=p+1;x=d[p]; /*输出推导式*/ }}printf("非法的符号串\n");printf("回车返回\n");getchar();getchar();return;}printf("\n");printf("回车返回\n");getchar();getchar();}int E1(){ int f,t;printf("E->TG\t");flag=1;input();input1();f=T();if (f==0) return(0);t=G();if (t==0) return(0);else return(1);}int E(){ int f,t;printf("E->TG\t");e[0]='E';e[1]='=';e[2]='>';e[3]='T';e[4]='G';e[5]='#'; output();flag=1;input();input1();f=T();if (f==0) return(0);t=G();if (t==0) return(0);else return(1);}int T(){ int f,t;printf("T->FS\t");e[0]='T';e[1]='=';e[2]='>';e[3]='F';e[4]='S';e[5]='#';output();flag=1;input();f=F();if (f==0) return(0);t=S();if (t==0) return(0);else return(1);}int G(){ int f;if(ch=='+') {b[i1]=ch;printf("G->+TG\t");e[0]='G';e[1]='=';e[2]='>';e[3]='+';e[4]='T';e[5]='G';e[6]='#'; output();flag=0;input();input1();ch=a[++i1];f=T();if (f==0) return(0);G();return(1);}printf("G->^\t");e[0]='G';e[1]='=';e[2]='>';e[3]='^';e[4]='#';output();flag=1;input();input1();return(1);}int S(){int f,t;if(ch=='*') {b[i1]=ch;printf("S->*FS\t");e[0]='S';e[1]='=';e[2]='>';e[3]='*';e[4]='F';e[5]='S';e[6]='#'; output();flag=0;input();input1();ch=a[++i1];f=F();if (f==0) return(0);t=S();if (t==0) return(0);else return(1);}e[0]='S';e[1]='=';e[2]='>';e[3]='^';e[4]='#';output();flag=1;a[i1]=ch;input();input1();return(1);}int F(){ int f;if(ch=='(') {b[i1]=ch;printf("F->(E)\t");e[0]='F';e[1]='=';e[2]='>';e[3]='(';e[4]='E';e[5]=')';e[6]='#'; output();flag=0;input();input1();ch=a[++i1];f=E();if (f==0) return(0);if(ch==')') {b[i1]=ch;printf("F->(E)\t");flag=0;input();input1();ch=a[++i1];}else {printf("非法的符号串\n");return(0);}}else if(ch=='i') {b[i1]=ch;printf("F->i\t");e[0]='F';e[1]='=';e[2]='>';e[3]='i';e[4]='#';output();flag=0;input();input1();ch=a[++i1];}else {printf("非法的符号串\n");return(0);}return(1);}void input(){int j=0;for (;j<=i1-flag;j++)printf("%c",b[j]); /*输出分析串*/printf("%c\t\t",ch); /*输出分析字符*/}void input1(){int j;for (j=i1+1-flag;j<n1;j++)printf("%c",a[j]); /*输出剩余字符*/ printf("\n");}void output(){ /*推导式计算*/ int m,k,j,q;int i=0;m=0;k=0;q=0;i=n;d[n]='=';d[n+1]='>';d[n+2]='#';n=n+2;i=n;i=i-2;while(d[i]!='>'&&i!=0) i=i-1;i=i+1;while(d[i]!=e[0]) i=i+1;q=i;m=q;k=q;while(d[m]!='>') m=m-1;m=m+1;while(m!=q) {d[n]=d[m];m=m+1;n=n+1;}d[n]='#';for(j=3;e[j]!='#';j++){d[n]=e[j];n=n+1;}k=k+1;while(d[k]!='=') {d[n]=d[k];n=n+1;k=k+1;}d[n]='#';}。
【编译原理实验】递归子程序法
![【编译原理实验】递归子程序法](https://img.taocdn.com/s3/m/e15f8327a22d7375a417866fb84ae45c3b35c2de.png)
【编译原理实验】递归⼦程序法⽂法:E->TGG->+TG|-TG|^T->FSS->*FS|/FS|^F->i|(E)表达式串的每个数符必须以i代替(懒得优化)1 #include<stdio.h>2 #include<iostream>3 #include<string.h>4 #include<stdlib.h>5using namespace std;678int step_Counter=0;//计数第⼏步9char in[82];//存储输⼊串10char analized_str[82];int top=-1;//存储分析过的字符串11char *ch;//指向当前正在分析的字符12char * left_Function(char[]);//计算并返回剩余串的起始地址⽼师请注意:left:剩余,不是左边1314char finished_dri[82];int t_f=-1;//推导式中的已经完成分析的字符串和其栈顶指针15char unfinished_dri[82];int t_uf=-1;//推到是中的未完成分析的字符串和其栈顶指针16char record_div[10000];//记录推导过程的数组17void add(char arr[],char arr1[]);//add⽅法将未完成部分的栈倒序装⼊record_div记录数组1819int E();20int T();21int F();22int S();23int G();2425int main()26 {27 cout<<"请输⼊长度不⼤于81的表达式:";28 cin>>in;29//cout<<strlen(in)<<endl;30char const_str[10]="分析串";31 printf("步骤\t⽂法\t%-40s分析字符\t剩余串\n",const_str);32 ch=in;3334 unfinished_dri[++t_uf]='E';//初始化⾮终结符栈35 strcat(record_div,"E\0");//记录第⼀条推导363738int flag=E();39if(flag==0)40 cout<<endl<<"\t\t\tERROR !"<<endl;41else42 {43 cout<<endl<<"\t\t\tACCEPT !"<<endl;44 cout<<"推导过程:"<<endl;45 cout<<record_div<<endl;46 }47return0;48 }49int E()50 {51 t_uf--;//⾮终结符栈栈顶元素出栈52 unfinished_dri[++t_uf]='G';//⾮终结符倒序⼊⾮终结符栈53 unfinished_dri[++t_uf]='T';5455 unfinished_dri[t_uf+1]='\0';//给栈顶元素增加结束标识,以免出错56 strcat(record_div,"\n=>");//以下三条是记录推导的语句57 strcat(record_div,finished_dri);58 add(record_div,unfinished_dri);//因为⾮终结符栈是倒序的,所以不能直接使⽤strcat函数,要进⾏⼀次颠倒才能进⾏连接 59//以上解释使⽤于下⾯的⼏个函数,故不再解释606162 step_Counter++;//标识第⼏步的变量63 analized_str[top+1]='\0';//为第⼀次调⽤此函数做准备64char * left_str=left_Function(analized_str);//得到剩余串的起始地址65 printf("%d\tE=>TG\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str);//格式打印输出66//cout<<"调⽤了函数E"<<endl;67if(*ch=='#')68return1;69int flag=T();70if(flag==0)71return0;72else73 {74 flag=G();75if(flag==0)76return0;77else78 {79return1;80 }81 }82 }83int T()84 {85 t_uf--;86 unfinished_dri[++t_uf]='S';87 unfinished_dri[++t_uf]='F';8889 unfinished_dri[t_uf+1]='\0';90 finished_dri[t_f+1]='\0';91 strcat(record_div,"\n=>");92 strcat(record_div,finished_dri);93 add(record_div,unfinished_dri);949596 step_Counter++;97 analized_str[top+1]='\0';98char * left_str=left_Function(analized_str);99 printf("%d\tT=>FS\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str); 100//cout<<"调⽤了函数T"<<endl;101if(*ch=='#')102return1;103int flag=F();104if(flag==0)105return0;106else107 {108 flag=S();109if(flag==0)110return0;111else112 {113return1;114 }115 }116 }117int F()118 {119if(*ch=='#')120return1;121//cout<<"调⽤了函数F"<<endl;122if(*ch=='i')123 {124 t_uf--;//未完成的部分栈顶出栈125 finished_dri[++t_f]='i';//完成的部分⼊栈126 unfinished_dri[t_uf+1]='\0';127 finished_dri[t_f+1]='\0';128 strcat(record_div,"\n=>");129 strcat(record_div,finished_dri);130 add(record_div,unfinished_dri);131132133134 top++;135 analized_str[top]='i';136 analized_str[top+1]='\0';137 step_Counter++;138char * left_str=left_Function(analized_str);139 printf("%d\tF=>i\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str);140//cout<<++step_Counter<<"i匹配"<<endl;141 ch++;142return1;143 }144else if(*ch=='(')145 {146147148 t_uf--;//未完成的部分F栈顶出栈149 finished_dri[++t_f]='(';//完成的部分⼊栈150 unfinished_dri[++t_uf]=')';//未完成的部分倒序⼊栈151 unfinished_dri[++t_uf]='E';//未完成的部分倒序⼊栈152 unfinished_dri[t_uf+1]='\0';153 finished_dri[t_f+1]='\0';154 strcat(record_div,"\n=>");155 strcat(record_div,finished_dri);156 add(record_div,unfinished_dri);157158159 top++;160 analized_str[top]='(';161 analized_str[top+1]='\0';162 step_Counter++;163char * left_str=left_Function(analized_str);164 printf("%d\tF=>(E)\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str); 165//cout<<++step_Counter<<"(匹配"<<endl;166 ch++;167int flag=E();168if(flag==0)169return0;170else171 {172if(*ch==')')173 {174 t_uf--;//完成部分出栈175 finished_dri[++t_f]=')';//完成部分⼊栈176177178 unfinished_dri[t_uf+1]='\0';179 finished_dri[t_f+1]='\0';180 strcat(record_div,"\n=>");181 strcat(record_div,finished_dri);182 add(record_div,unfinished_dri);183184 top++;185 analized_str[top]=')';186 analized_str[top+1]='\0';187 step_Counter++;188char * left_str=left_Function(analized_str);189 printf("%d\tF=>(E)\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str); 190// cout<<++step_Counter<<")匹配"<<endl;191 ch++;192return1;193 }194else195return0;196 }197 }198else199 {200return0;201 }202 }203int S()204 {205//cout<<"调⽤了函数S"<<endl;206if(*ch=='*')207 {208 t_uf--;//⾮终结符S出栈209 finished_dri[++t_f]='*';//终结符⼊栈210 unfinished_dri[++t_uf]='S';//⾮终结符倒序⼊栈211 unfinished_dri[++t_uf]='F';212 unfinished_dri[t_uf+1]='\0';213 finished_dri[t_f+1]='\0';214 strcat(record_div,"\n=>");215 strcat(record_div,finished_dri);216 add(record_div,unfinished_dri);217218219220 top++;221 analized_str[top]='*';222 analized_str[top+1]='\0';223 step_Counter++;224char * left_str=left_Function(analized_str);225 printf("%d\tS=>*FS\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str); 226// cout<<++step_Counter<<"*匹配"<<endl;227 ch++;228int flag=F();229if(flag==0)230return0;231else232 {233 flag=S();234if(flag==1)235return1;236else237return0;238 }239 }240else if(*ch=='/')241 {242 t_uf--;//⾮终结符S出栈243 finished_dri[++t_f]='/';//终结符⼊栈244 unfinished_dri[++t_uf]='S';245 unfinished_dri[++t_uf]='F';246 unfinished_dri[t_uf+1]='\0';247 finished_dri[t_f+1]='\0';248 strcat(record_div,"\n=>");249 strcat(record_div,finished_dri);250 add(record_div,unfinished_dri);251252253 top++;254 analized_str[top]='/';255 analized_str[top+1]='\0';256 step_Counter++;257char * left_str=left_Function(analized_str);258 printf("%d\tS=>/FS\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str); 259// cout<<++step_Counter<<"/匹配!"<<endl;260 ch++;261int flag=F();262if(flag==0)263return0;264else265 {266 flag=S();267if(flag==1)268return1;269else270return0;271 }272 }273else274 {275 t_uf--;//⾮终结符S出栈276 finished_dri[++t_f]='^';//终结符⼊栈277 unfinished_dri[t_uf+1]='\0';278 finished_dri[t_f+1]='\0';279 strcat(record_div,"\n=>");280 strcat(record_div,finished_dri);281 add(record_div,unfinished_dri);282283284 step_Counter++;285char * left_str=left_Function(analized_str);286 printf("%d\tS=>^\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str); 287return1;288 }289 }290int G()291 {292//cout<<"调⽤了函数G"<<endl;293if(*ch=='+')294 {295 t_uf--;//⾮终结符S出栈296 finished_dri[++t_f]='+';//终结符⼊栈297 unfinished_dri[++t_uf]='G';298 unfinished_dri[++t_uf]='T';299 unfinished_dri[t_uf+1]='\0';300 finished_dri[t_f+1]='\0';301 strcat(record_div,"\n=>");302 strcat(record_div,finished_dri);303 add(record_div,unfinished_dri);304305306307 top++;308 analized_str[top]='+';309 analized_str[top+1]='\0';310 step_Counter++;311char * left_str=left_Function(analized_str);312 printf("%d\tG=>+TG\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str); 313// cout<<++step_Counter<<"+匹配"<<endl;314 ch++;315int flag=T();316if(flag==0)317return0;318else319 {320 flag=G();321if(flag==1)322return1;323else324return0;325 }326 }327else if(*ch=='-')328 {329330 t_uf--;//⾮终结符S出栈331 finished_dri[++t_f]='-';//终结符⼊栈332 unfinished_dri[++t_uf]='G';333 unfinished_dri[++t_uf]='T';334 unfinished_dri[t_uf+1]='\0';335 finished_dri[t_f+1]='\0';336 strcat(record_div,"\n=>");337 strcat(record_div,finished_dri);338 add(record_div,unfinished_dri);339340341342 top++;343 analized_str[top]='-';344 analized_str[top+1]='\0';345 step_Counter++;346char * left_str=left_Function(analized_str);347 printf("%d\tG=>-TG\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str); 348// cout<<++step_Counter<<"-匹配"<<endl;349 ch++;350int flag=T();351if(flag==0)352return0;353else354 {355 flag=G();356if(flag==1)357return1;358else359return0;360 }361 }362else363 {364365 t_uf--;366 finished_dri[++t_f]='^';367 unfinished_dri[t_uf+1]='\0';368 finished_dri[t_f+1]='\0';369 strcat(record_div,"\n=>");370 strcat(record_div,finished_dri);371 add(record_div,unfinished_dri);372373 step_Counter++;374char * left_str=left_Function(analized_str);375 printf("%d\tG=>^\t%-40s%c\t\t%s\n",step_Counter,analized_str,*ch,left_str); 376return1;377 }378 }379380381char * left_Function(char aim[])//获取剩余的字符串⽼师请注意:left:剩余,不是左边382 {383char * left;384int length=strlen(aim);385 left=&in[length];386return left;387 }388389void add(char aim[],char source[])390 {391char temp[1000];int top=-1;392int len=strlen(source);393for(int i=len-1;i>=0;i--)394 {395 temp[++top]=source[i];396 }397 temp[++top]='\0';398 strcat(aim,temp);399 }400401//测试数据:((i*i+i)*i/i)-(i*i*(i+i)/i-i-i)*i/i+i-i# View Code。
子程序的递归与嵌套
![子程序的递归与嵌套](https://img.taocdn.com/s3/m/a9328c6227d3240c8447ef4a.png)
执行过程分析
K number
8 157 8 19 8 2 0
第1次调用 digit=5 number=19 tentok(19,8)
5 3 2
第2次调用 digit=3 number=2 tentok(2,8)
write(digit) 第3次调用 digit=2 number=0 write(digit)
递归算法表现出处理问题的强大能力。然而,如同循环一样, 递归也会带来无终止调用的可能性,因此,在设计递归过程 (函数)时,必须考虑递归调用的终止问题,就是递归调用要 受限于某一条件,而且要保证这个条件在一定情况下肯定能得 到满足。
如何设计递归算法?
1.确定递归公式 2.确定边界(终了)条件
课堂练习2:
1.求:1+2+3+...+n 的值。n从键盘上输入。
2.有一对雌雄兔,每两个月就繁殖雌雄各一对兔子.问 n个月后共有多少对兔子? 3.用递归的方法求Xn(X和n由键盘输入) 4.已知:数列1,1,2,4,7,13,24,44,...求数列的第 n项.
使用递归求解问题,通常可以将一个比较大的问题层层 转化为一个与原问题相类似的、规模较小的问题进行求解, 最终达到对原问题的求解。
【例3】从M 个学生中选N个学生到 舞台上表演一个游戏, 问有多少种选择方法。 这是数学中的组合运算, 可用下列公式计算:
s:real; function fac(k:integer):longint; var i:integer; t:longint; begin t:=1; for i:=2 to k do t:=t*i; fac:=t; end; function cnm(n,m:integer):real; begin cnm:=fac(n)/(fac(m)*fac(n-m)); end; begin s:=cnm(6,3)+cnm(9,5); writeln(‘s=’,(s/fac(7)):8:2); end.
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/**************************
E->TG
G->+TG|-TG
G->ε
T->FS
S->*FS|/FS
S->ε
F->(E)
F->i
***************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int index;
char word[30];
char *Es[2]={"i(",")#"};//first follow $代表空char *Ss[2]={"$*/","+-)#"};
char *Gs[2]={"$+-",")#"};
char *Ts[2]={"i(","+-)#"};
char *Fs[2]={"i(","+-*/)#"};
void E();
void S();
void G();
void T();
void F();
void error();
bool Find(char *dst,char src)//此处是一个字符{
int j=0;
while(dst[j]!='\0')
{
if(src==dst[j]) return true;
j++;
}
return false;
}
void S()
{
if(word[index]=='*'||word[index]=='/')
{
index++;//接受一个单词
F();
S();
else ;//error();可以推出空就直接接受}
void F()
{
if(word[index]=='(')
{
index++;
E();
if(word[index]==')')
{
/* if(word[index+1]=='\0')
{
printf("right!\n");
exit(0);
}
else*/
index++;//接受
}
else error();
}else if(word[index]=='i')
{
/* if(word[index+1]=='\0')
{
if(number==0)
{
printf("right!\n");
exit(0);
}
else error();
}
else */index++;//接受
}else error();
}
void G()
{
if(word[index]=='+'||word[index]=='-')
{
index++;
T();
G();
else ;//error();可以推出空就直接接受
}
void T()
{
if(Find(Fs[0],word[index]))
{
F();
S();
}else error();
}
void E()
{
if(Find(Ts[0],word[index]))//Ts[0]表示first集,1follow集{
T();
G();
}else error();
}
void error()
{
printf("error!");
exit(0);
}
void main()
{
scanf("%s",word);
index=0;
E();
//判断是否所有的串都识别了
if(word[index]=='#') printf("right!\n");
else error();
}。