递归下降分析算术表达式

合集下载

实验3 算术表达式递归下降法

实验3 算术表达式递归下降法

简单算术表达式的递归下降语法分析法一、实验任务完成以下描述算术表达式的递归下降分析程序构造。

G[E]:E→TE1E1→+TE1|εT→FT1T1→*FT1|εF→(E)|i说明:终结符号i为用户定义的简单变量,即标识符的定义。

要求具有如下功能:(1) 从文件读入算术表达式/或者从终端输入。

(2) 总控函数分析算术表达式。

(3) 根据分析结果正误,分别给出不同信息。

二、实验目的和要求通过设计、编制、调试一个递归下降语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,掌握常用的语法分析方法。

通过本实验,应达到以下目标:(1)掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。

(2)掌握语法分析的实现方法。

(3)上机调试编出的语法分析程序。

三、实验背景知识递归下降法是语法分析中最易懂的一种方法。

它的主要原理是,对每个非终结符按其产生式结构构造相应语法分析子程序,其中终结符产生匹配命令,而非终结符则产生过程调用命令。

因为文法递归,相应子程序也递归,所以称这种方法为递归下降法。

其中子程序的结构与产生式结构几乎是一致的。

递归下降分析程序的实现思想是:识别程序由一组子程序组成。

每个子程序对应于一个非终结符号。

每一个子程序的功能是:选择正确的右部,扫描完相应的字。

在右部中有非终结符号时,调用该非终结符号对应的子程序来完成。

自上向下分析过程中,如果带回溯,则分析过程是穷举所有可能的推导,看是否能推导出待检查的符号串,分析速度慢;而无回溯的自上向下分析技术,可根据输入串的当前符号以及各产生式右部首符,选择某非终结符的产生式,效率高,且不易出错。

无回溯的自上向下分析技术可用的先决条件是:无左递归和无回溯。

即:假设A的全部产生式为A->α1|α2|……|αn ,则必须满足如下条件才能保证可以唯一的选择合适的产生式First(αi )∩First(αj)=Φ,当i≠j.无左递归:既没有直接左递归,也没有间接左递归。

四则运算递归下降法

四则运算递归下降法

四则运算递归下降法递归下降法是一种常用于编写表达式解析器的技术,它将一个复杂的问题分解为一系列简单的子问题。

对于四则运算,可以通过递归下降法来解析表达式,例如,一个简单的表达式可以包含加法、减法、乘法和除法。

下面是一个简单的 Python 代码示例,演示了如何使用递归下降法来解析四则运算表达式:class Parser:def __init__(self, expression):self.tokens = self.tokenize(expression)self.current_token = 0def tokenize(self, expression):# 将表达式分解为标记(tokens)# 这里简单地将操作符和数字作为标记,实际的解析可能更复杂return expression.replace(' ', '').replace('+', ' + ').replace('-', ' - ').replace('*', ' * ').replace('/', ' / ').split()def parse_expression(self):return self.parse_addition_subtraction()def parse_addition_subtraction(self):left_expr = self.parse_multiplication_division()while self.current_token < len(self.tokens):operator = self.tokens[self.current_token]if operator in ('+', '-'):self.current_token += 1right_expr = self.parse_multiplication_division()if operator == '+':left_expr += right_exprelse:left_expr -= right_exprelse:breakreturn left_exprdef parse_multiplication_division(self):left_expr = self.parse_number()while self.current_token < len(self.tokens):operator = self.tokens[self.current_token] if operator in ('*', '/'):self.current_token += 1right_expr = self.parse_number()if operator == '*':left_expr *= right_exprelse:if right_expr != 0:left_expr /= right_exprelse:raise ValueError("Division by zero")else:breakreturn left_exprdef parse_number(self):if self.current_token < len(self.tokens):token = self.tokens[self.current_token]self.current_token += 1if token.isdigit() or (token[0] == '-' and token[1:].isdigit()):return int(token)else:raise ValueError(f"Invalid token: {token}")else:raise ValueError("Unexpected end of expression")# 示例用法expression = "3 + 5 * ( 2 - 8 ) / 4"parser = Parser(expression)result = parser.parse_expression()print(f"Result: {result}")在这个示例中,parse_expression是最顶层的解析函数,它调用parse_addition_subtraction来解析加法和减法,而后者又调用parse_multiplication_division来解析乘法和除法,依此类推。

实验二 递归下降分析法的实现

实验二  递归下降分析法的实现

实验二递归下降分析法的实现一、实验目的实现一个递归下降语法分析程序,识别用户输入的算术表达式。

二、实验主要内容1、文法如下:E→TE`E’→+TE’|-TE’|εT→FT`T’→*FT’|/FT’|εF→(E)|i2、求取各非终结符的First及Follow集合3、编程实现下降递归分析法,识别从键盘输入的关于整数或浮点数的算术表达式(在此,上述文法中的i代表整数或浮点数)4、对于语法错误,要指出错误具体信息。

5、运行实例如下:三、提示1、纸质实验报告内容:实验内容、非终结符的First及Follow集合、正确表达式与错误表达式各举一例进行测试并给出结果、核心源代码。

2、将本次实验代码(.c、.cpp、.java等代码文件,删除编译产生的所有其他文件,不要打包)在规定时间内以作业附件(不可在线编辑、粘贴代码)的形式提交至网站,自己保存以备课程设计(本部有毕业设计要求的学生)参考。

3、纸质实验报告提交时间:临时要求。

实验指导(参考)一、实验步骤1、求取各非终结符的First及Follow集合;2、设计几个函数E(); Ep(); T(); Tp(); F();运用First集合进行递归函数选择,运用Follow集合进行出错情况判断;3、设计主函数:从键盘接受一个算术表达式串;在串尾添加尾部标志’#’;调用函数E()进行递归下降分析。

二、如何识别整数与浮点数在函数F()中要涉及到如何识别整数与浮点数。

识别的方法是:只要碰到‘0’~‘9’之间的字符就一直循环,循环到不是数字字符与小数点字符’.’为止,其间要运用一个标志变量来保证最多只能出现一个小数点,否则应该报错。

上述循环结束即表示识别了一个数,也即表达式文法中的i。

用递归下降方法实现算术表达式解析器

用递归下降方法实现算术表达式解析器

⽤递归下降⽅法实现算术表达式解析器对于形如2*2+2/1+3的算术表达式,如果不将优先级顺序考虑进去的话,那么解析如上的表达式⼗分容易,1 2 3 4 5 6a = get first operand while(operand present){ op = get operatorb = get second operand a = a op b} 如果将优先级考虑进去的话,⽽且还使⽤上述算法,那么复杂度可想⽽知.在此,我⽤递归下降的⽅式实现解析有优先级的算术表达式. 在此解析的算术表达式,由如下元素组成: 数字运算符+ - * / % 运算符的优先级如下 % / * > + - 优先级相等的运算符从左向右顺序计算 在使⽤递归向下解析器时,表达式被视为递归的数据结构,那么所有的表达式可以由如下的规则⽣成 表达式 ->项 [+项][-项] 项 -> 因数 [*因数][/因数][%因数] 因数 -> 数字或表达式 注意,上⾯的⽣成规则是以表达式中只包含+-*/%运算符且⽆变量为前提的,⽽且⽣成规则也包含了运算优先级,下⾯举例说明表达式的解析过程 2*3+2 有两个项,分别为2*3和2,前者包含两个因素2,3 下⾯以⼀个例⼦跟踪递归向下解析过程 2*3+3*41. 获得第⼀项2*32. 计算得到63. 获得第⼆项3*44. 计算得到125. 从第⼆项递归计算过程返回6. 6+12计算得到18 为计算表达式的值,需要对表达式进⾏分解,例如2*3-4可以分解成2,*,3,-,4四个元素,这些元素在解析器术语中称为标识符,是⼀个不能再分的独⽴单元.为了将表达式分解⼀独⽴的元素单元,需要设计⼀个过程,该过程能从头⾄尾扫描整个表达式,顺序地返回每个元素,并且能够识别每个元素的,在本解析器,实现该功能的函数称为getToken. 本⽂的解析器封装在⼀个Parser的类中,为对getToken功能有个更好的理解,现说明它的第⼀部分1 //解析器2 class Parser{3 //标识符的类型种类4 final int NONE = 0;5 final int NUMBER= 1;6 final int DELIMITER = 2;78 //异常的类型9 final int NOEXP = 0;10 final int SYNTAX = 1;11 final int DIVBYZERO = 2;1213 final String EOE = "\0";//标明表达式结尾14 private int tokType;//⽤于存放标识符类型15 private String token;//⽤于存放标识符16 private String exp;//⽤于存放表达式17 private int expIdx;//在表达式中的当前位置 解析器解析表达式时,每个标识符必须有与之关联的标识符,本解析器只⽤到2种类型,分别为NUMBER,DELIMITER.此外NONE类型只是当标识符未定义时的⼀个占位符. 此外,Parser类还定义⼏个异常,其中NOEXP是当解析器解析时没有表达式,SYNTAX代表表达式不符合规则的错误,DIVBYZERO代表除数为0时的错误. final变量EOE表⽰解析器⼰达到表达式的结尾. 被解析的表达式⼰字符串形式保存,exp保存该字符串的⼀个引⽤,exIdx保存下⼀个标识符在exp中的索引,初始值为0.当前标识符保存在token中,其类型则保存在tokType.这些变量都是private型,只允许解析器⾃⼰访问⽽不能被外部代码修改. 下⾯列出getToken函数的完整代码,每调⽤⼀次getToken(),将得到表达式的下⼀个标识,也就是exp[expIdx]后的⼀个标识.getToken()将标识符保存在token中,标识符类型则保存在tokType之中.//获得下⼀个标识符private void getToken(){token = "";tokType = NONE;//检查表达式是否到达末尾if(expIdx == exp.length()){token = EOE;return;}//去掉空格while(expIdx < exp.length() && Character.isWhitespace(exp.charAt(expIdx))) expIdx++;//当表达式以空格结束if(expIdx >= exp.length()){token = EOE;return;}if(isDelim(exp.charAt(expIdx))){//是运算符token += exp.charAt(expIdx));tokType = DELIMITER;expIdx ++;} else if(Character.isDigit(exp.charAt(expIdx))){//是数字while(!isDelim(exp.charAt(expIdx))){token += exp.charAt(expIdx);expIdx ++;if(expIdx >= exp.length())break;}tokType = NUMBER;} else {//不知名的字符结束字符串token = EOE;return;}}private boolean isDelim(char c){//判断字符是否是运算符if((" +-*/%").indexOf(c) != -1)return true;return false;}} 下⾯简单分析下getToken().getToken()⾸先做初始化⼯作,然后查看expIdx是否等于表达式的.由于expIdx保存的是解析器解析表达当前的进度,如果expIdx和exp.length(),那么表明解析器完成了表达式的解析. 如果解析器还能找到未处理的标识符,则解析过程继续进⾏.⾸先跳过下⼀个标识符之前所有的空格,如果表达式以空格结尾,则返回EOE结尾.根据exp[expIdx]后的⼀个字符的类型不同,getToken()对当前标识符的处理过程不同.如果⼀个字符为运算符,那么getToken()将当前标识符保存在token中,并将tokType设置为DELIMITER.若下⼀个字符为数字,token保存当前标识符,并将tokType设为NUMBER.如果下⼀个字符不为以上两种之⼀,则token保存EOE返回. 下⾯为解析器的代码,这个解析器只能解析由数字和运算符组成的表达式,其中运⾏符只包含+-*/%.class ParserException extends Exception{private String error;public ParserException(String error){this.error = error;}public String toString(){return error;}}class Parser {final int NONE = 0;final int NUMBER = 1;final int DELIMITER = 2;final int NOEXP = 0;final int SYNTAX = 1;final int DIVBYZERO = 2;final String EOE = "\0";private String exp;private String token;private int expIdx;private int tokType;//解析⼊⼝public double evaluate(String expStr) throws ParserException{this.exp = expStr;this.expIdx = 0;double result;getToken();if(token.equals(EOE)){handleErr(NOEXP);}result = evalExp1();if(!token.equals(EOE)){handleErr(SYNTAX);}return result;}//加或减private double evalExp1() throws ParserException{double result;double partialResult;char op;result = evalExp2();while((op = token.charAt(0)) == '+'|| op == '-'){getToken();partialResult = evalExp2();switch(op){case'+':result += partialResult;break;case'-':result -=partialResult;break;}}return result;}//乘或除或取余private double evalExp2() throws ParserException{double result;double partialResult;char op;result = atom();while((op = token.charAt(0)) == '*'|| op == '/'|| op == '%'){getToken();partialResult = atom();switch(op){case'*':result *= partialResult;break;case'/':if(partialResult == 0.0) handleErr(DIVBYZERO);result /=partialResult;break; case'%':result %= partialResult;break;}}return result;}//获得数的值private double atom() throws ParserException{double result = 0.0;switch(tokType){case NUMBER:try{result = Double.parseDouble(token);getToken();}catch(NumberFormatException exc){handleErr(SYNTAX);}break;default:handleErr(SYNTAX);}return result;}//错误处理private void handleErr(int error) throws ParserException{String[] errs = {"表达式不存在","表达式不符合规则","除数为0"};throw new ParserException(errs[error]);}//获得下⼀个标识符private void getToken(){token = "";tokType = NONE;//检查表达式是否到达末尾if(expIdx == exp.length()){token = EOE;return;}//去掉空格while(expIdx < exp.length() && Character.isWhitespace(exp.charAt(expIdx))) expIdx++; //当表达式以空格结束if(expIdx >= exp.length()){token = EOE;return;}if(isDelim(exp.charAt(expIdx))){//是运算符token += exp.charAt(expIdx);tokType = DELIMITER;expIdx ++;} else if(Character.isDigit(exp.charAt(expIdx))){//是数字while(!isDelim(exp.charAt(expIdx))){token += exp.charAt(expIdx);expIdx ++;if(expIdx >= exp.length())break;}tokType = NUMBER;} else{//不知名的字符结束字符串token = EOE;return;}}private boolean isDelim(char c){//判断字符是否是运算符if((" +-*/%").indexOf(c) != -1)return true;return false;}} 在代码最开始部分声明了⼀个ParserException类,这是⼀个异常类,当解析器解析表达式时就会根据异常类抛出特定的,该异常的处理需要使⽤该解析器的主程序处理.使⽤该解析器的⽅法是先实例化⼀个Parser,然后将⼀个表达式字符串传⼊该实例的evaluate⽅法,该⽅法返回最终的结果.下⾯的代码说明解析器的使⽤⽅法.import java.io.*;public class PDemo{public static void main(String[] args){String expr;BufferedReader br = newBufferedReader(new InputStreamReader(System.in));Parser p = new Parser();System.out.println("Enter an empty expression to stop");for(;;){System.out.print("Enter expression:");expr = br.readLine();if(expr.equals("")) break;try{System.out.println("Result :"+p.evaluate(expr));System.out.println();}catch(ParserException exc){System.out.println(exc);}}}}。

递归下递语法分析

递归下递语法分析

递归下递语法分析递归下降语法分析是一种自上而下的分析方法,基于产生式规则和递归函数的方式来进行语法分析。

在递归下降语法分析中,每个非终结符对应一个递归函数,该函数负责对该非终结符所对应的产生式进行分析。

这种分析方法的优点是简单易懂,容易实现,但是对于左递归、回溯以及二义性文法的处理较为困难。

递归下降语法分析的核心思想是根据当前输入符号和预测分析表,选择适当的递归函数进行调用,直到遇到终结符或无法继续推导为止。

下面我们将详细介绍递归下降语法分析的步骤。

1.定义语法产生式规则:首先需要定义待分析的文法的产生式规则。

产生式规则由左部和右部组成,左部表示非终结符,右部表示由终结符和非终结符组成的字符串。

例如,对于表达式文法E->E+T,T,E为非终结符,+为终结符,T为非终结符,表示一个表达式可以是一个表达式加一个项,或者仅仅是一个项。

2.构建预测分析表:根据产生式规则,构建一个预测分析表。

预测分析表是一个二维表,由非终结符和终结符构成,表中的每个元素表示哪个产生式规则应该被应用。

例如,对于表达式文法,预测分析表可能如下所示:, + , * , id , ( , ) ,---,---,---,---,---,---,--E,-,-,T,T,-,T,F,-,F,F,-,F , - , - , id , (E), - ,表中的'-'代表无动作。

3.实现递归函数:根据预测分析表中的产生式规则,实现对应的递归函数。

每个非终结符对应一个递归函数,函数的实现根据当前输入符号和预测分析表中选择对应的产生式规则进行推导。

例如,对于表达式文法,可以定义如下的递归函数:```pythondef E(:if symbol == '+':match('+')TEelif symbol == 'id' or symbol == '(':TEelse:# Errordef T(:if symbol == '+':FTelif symbol == 'id' or symbol == '(':FTelse:# Errordef F(:if symbol == 'id':match('id')elif symbol == '(':match('(')Ematch(')')else:# Error```在每个递归函数中,首先需要判断当前输入符号与预测分析表的元素是否匹配,如果匹配则进行相应的操作(例如推导产生式、移动指针等),如果不匹配则报错。

自顶向下分析——递归下降法

自顶向下分析——递归下降法

假设有文法
Z→aBa
B→bB |c
则相应的递归子程序可如下:
ReadToken
procedure Z( )
procedure B ( )
begin
begin
if token=a then Match(a);
B;
ReadToken
Match(a)
else err( )
end;
if token = b then Match(b); B;
else if token = c then Match(c); else err( )
end;
主程序:Begin ReadToken; Z end
产生式A→被选择的条件是: 当前的输入符属于predict(A→)。
至多一个产生式被选择的条件是: predict(A→k) predict(A→j )=,当k j
if tokenPredict(A2) then (2) else …… if tokenPredict(An) then (n) else err( )
end 其中对i=X1X2…Xn,(i) = ’(X1);’(X2);…;’(Xn); 如果XVN,’(X)= X 如果XVT,’(X)= Match(X) 如果X= , () = skip(空语句)
自顶向下分析——递归下降法
递归下降法(Recursive-Descent Parsing) 对每个非终极符按其产生式结构产生相应 语法分析子程序. 终极符产生匹配命令 非终极符则产生调用命令 文法递归相应子程序也递归,所以称这种 方法为递归子程序方法或递归下降法。
例:Stm→ while Exp do Stm 则对应产生式右部的语法分析程序部 分如下: begin Match($while); Exp; Match($do); Stm end

编译原理---递归下降分析法

编译原理---递归下降分析法

编译原理---递归下降分析法所谓递归下降法 (recursive descent method),是指对⽂法的每⼀⾮终结符号,都根据相应产⽣式各候选式的结构,为其编写⼀个⼦程序 (或函数),⽤来识别该⾮终结符号所表⽰的语法范畴。

例如,对于产⽣式E′→+TE′,可写出相应的⼦程序如下:exprprime( ){if (match (PLUS)){advance( );term( );exprprime( );}}其中:函数match()的功能是,以其实参与当前正扫视的符号 (单词)进⾏匹配,若成功则回送true,否则回送false;函数advance()是⼀个读单词⼦程序,其功能是从输⼊单词串中读取下⼀个单词,并将它赋给变量Lookahead;term则是与⾮终结符号T相对应的⼦程序。

诸如上述这类⼦程序的全体,便组成了所需的⾃顶向下的语法分析程序。

应当指出,由于⼀个语⾔的各个语法范畴 (⾮终结符号)常常是按某种递归⽅式来定义的,此种特点也就决定了这组⼦程序必然以相互递归的⽅式进⾏调⽤,因此,在实现递归下降分析法时,应使⽤⽀持递归调⽤的语⾔来编写程序。

所以,通常也将上述⽅法称为递归⼦程序法。

例4 2对于如下的⽂法G[statements]:statements→expression; statements |εexpression→term expression′expression′→+term expression′ |εterm→factor term′term′→*factor term′ |εfactor→numorid | (expression)通过对其中各⾮终结符号求出相应的FIRST集和FOLLOW集 (计算FIRST集和FOLLOW集的⽅法后⾯再做介绍),可以验证,此⽂法为⼀LL(1)⽂法,故可写出递归下降语法分析程序如程序41所⽰(其中,在⽂件lex.h⾥,将分号、加号、乘号、左括号、右括号、输⼊结束符及运算对象分别命名为SEMI,PLUS,TIMES,LP,RP,EOI及NUMORID,并指定了它们的内部码;此外,还对外部变量yytext,yyleng及yylineno进⾏了说明)。

递归下降程序实验报告

递归下降程序实验报告

一、实验目的1. 理解递归下降分析法的原理和实现方法。

2. 掌握递归下降分析程序的设计和调试。

3. 加深对编译原理中语法分析部分的理解。

二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发环境:Visual Studio 2019三、实验内容1. 递归下降分析法原理介绍2. 递归下降分析程序的设计与实现3. 递归下降分析程序的调试与测试四、实验步骤1. 递归下降分析法原理介绍递归下降分析法是一种自顶向下的语法分析方法,它将文法中的非终结符对应为分析过程中的递归子程序。

当遇到一个非终结符时,程序将调用对应的递归子程序,直到处理完整个输入串。

2. 递归下降分析程序的设计与实现(1)定义文法以一个简单的算术表达式文法为例,文法如下:E -> E + T| TT -> T F| FF -> ( E )| id(2)消除左递归由于文法中存在左递归,我们需要对其进行消除,消除后的文法如下:E -> T + E'E' -> + T E' | εT -> F T'T' -> F T' | εF -> ( E ) | id(3)设计递归下降分析程序根据消除左递归后的文法,设计递归下降分析程序如下:```cpp#include <iostream>#include <string>using namespace std;// 定义终结符const char PLUS = '+';const char MUL = '';const char LPAREN = '(';const char RPAREN = ')';const char ID = 'i'; // 假设id为'i'// 分析器状态int index = 0;string input;// 非终结符E的分析程序void E() {T();while (input[index] == PLUS) {index++;T();}}// 非终结符T的分析程序void T() {F();while (input[index] == MUL) {index++;F();}}// 非终结符F的分析程序void F() {if (input[index] == LPAREN) {index++; // 跳过左括号E();if (input[index] != RPAREN) {cout << "Error: Missing right parenthesis" << endl; return;}index++; // 跳过右括号} else if (input[index] == ID) {index++; // 跳过标识符} else {cout << "Error: Invalid character" << endl;return;}}// 主函数int main() {cout << "Enter an arithmetic expression: ";cin >> input;index = 0; // 初始化分析器状态E();if (index == input.size()) {cout << "The expression is valid." << endl;} else {cout << "The expression is invalid." << endl;}return 0;}```3. 递归下降分析程序的调试与测试将以上代码编译并运行,输入以下表达式进行测试:```2 +3 (4 - 5) / 6```程序输出结果为:```The expression is valid.```五、实验总结通过本次实验,我们了解了递归下降分析法的原理和实现方法,掌握了递归下降分析程序的设计与调试。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

递归下降分析算术表达式
计算机092—07 邹芬芬
●实验目的:
(1)掌握自上而下语法分析的要求与特点。

(2)掌握递归下降语法分析的基本原理和方法。

(3)掌握相应数据结构的设计方法。

●实验内容:
编程实现给定算术表达式的递归下降分析器。

算术表达式文法如下:E→E+T | T
T→T*F | F
F→(E) | i
●设计分析
题目所给的文法不为LL(1)文法,应改写成如下文法:
E →TE2
E2→+TE2 |∑
T →FT2
T2→*FT2 | ∑
F →(E) | i
采用递归下降分析法时,需要求出E2和T2 的FOLLOW集:
FOLLOW(E2)={),#}
FOLLOW(T2)={+,),#}
递归下降分析法是确定的自上而下分析法,基本思想是,对文法中的每个非终结符编写一个函数,每个函数的功能是识别由该非终结符所表示的语法成分。

因此需要分别构造E,E2,T,T2,F函数来执行自己的识别功能,根据文法的内容顺序决定函数的识别功能。

advance函数用于字符串的推进,input函数用于字符串的输入。

●程序代码
#include <iostream>
using namespace std;
char a[80]; // 字符串的存入
char sym; // 单个的判断字符
int i=0; // 字符串下标
void E(); // 功能识别函数
void E2(); // 功能识别函数
void T(); // 功能识别函数
void T2(); // 功能识别函数
void F(); // 功能识别函数
void input(); // 输入函数
void advance(); // 字符串小标进一函数
void main()
{
while(1)
{
input();
advance();
E(); // 从首个推导式E开始
if (sym=='#')
cout<<"success"<<endl;
else
cout<<"fail"<<endl;
i=0; // 重新输入时,下标置0 }
}
void E()
{
T();
E2();
}
void E2()
{
if(sym=='+')
{
advance();
T();
E2();
}
else if (sym != ')' && sym != '#')
{
cout<<"error!"<<endl;
exit(0);
}
}
void T()
{
F();
T2();
}
void T2()
{
if(sym=='*')
{
advance();
F();
T2();
}
else if(sym!='+'&&sym!=')'&&sym!='#')
{
cout<<"error!"<<endl;
exit(0);
}
}
void F()
{
if(sym=='(')
{
advance();
E();
if(sym==')')
advance();
else
{
cout<<"error!"<<endl;
exit(0);
}
}
else if(sym=='i')
{
advance();
}
else
{
cout<<"error!"<<endl;
exit(0);
}
}
void input()
{
cout<<"请输入需识别的句子:";
cin>>a;
}
void advance()
{
sym=a[i];
i++;
}
测试用例
(1)只含有一个字符的形式:
i
E
(2) 含有‘+’的形式:
i+i
i+E
(3) 含有‘*’的形式:
i*i
i*
(4) 含有‘(’‘)’的形式:、
(i)
()
(5) 综合形式:
(i+i)*(i+i)
i*(i+i)
i*i+i
实验总结
通过本次试验实践掌握了自上而下语法分析法的特点。

掌握了递归下降语法分析的基本原理和方法。

运用递归下降分析法完成了本试验的语法分析构造,并且成功的分析出每种正确的句子和错误的句子。

函数的构造是根据文法分析的递归过程,所编写每个函数的功能,以文法的右部为函数名,对应的左部为相应分析过程。

此分析法简单,直观,易构造分析程序,但是不适于文法过于复杂的,不易检查出错误。

在试验的过程中,遇到了一些问题,都是粗心大意而造成,并非是对文法分析和编程的熟悉问题,说明了我再以后的试验中应该更细心的编写程序的每一步,对于本次试验所出现的马虎,应该牢记,以后不再犯同样的错误。

相关文档
最新文档