递归下降分析法实现强化计算器

一. 实验概述

1.使用bison 和 flex 实现扩展版计算器

       该计算器支持实型的两种表达,分别是小数和科学计数法.

       该计算器支持 加, 减, 乘 除 四种运算 和括号()运算符.

       该计算器支持整形,实型混合运算

2.通过递归下降分析法自行编写的语法分析和使用flex进行的词法分析的计算器.

       支持整数,实数

       支持加减乘除和括号

       支持混合运算.

二. 测试和结果

如图所示,编写test.txt测试内容,其中有加减乘除混合运算,连除,指数e表达式等

调用calculator_self 分析执行,与手算结果均一致,且没有bug.

三. 总体架构

1.flex+bison的软件总体架构:

2.flex+手动语法分析的架构:

四. 详细设计

1.在calculator.l 文件中实现对实数和减,除的词法支持:

       eee可识别科学计数法的e或E符号;

       point 用于识别 点 .

       plus_minu 用于识别 科学计数法中的正负号

       reald 用于识别 实性数字,设计思想为:先识别一个数字,再接一个点,再接一堆数字,再接一个e或E的克林闭包,

增加对reald的操作:

调用库函数识别realnumber, 并返回REALDIGIT;

white_line返回’\n’便于我们后续分析.

2.在calculator.y中增加强化计算器的语法支持.

在union中添加对double类型的支持.

修改Factor,增加一项对REALDIGIT的支持.

修改Line 文法使之支持对换行符的识别.

3.在expr.c中增加对两种类型的加减乘除的支持.

例如:

在加法中,先判断是否又实数,如果是在判断哪个是实数,然后加减乘除,如果不是就直接加两个src.val.

减乘除的方法类似,就是把运算法号一改变就可.详情见源码expr.c .

4. 在main.c中调用设计的内容.

在main.c中引用lex和yacc的头文件,然后判断文件是否为空,不是就调用yyparse();

二. 自己设计的语法分析部分:

1.自己设计的calculator_myyacc.c

总体设计如图所示,根据文法使用递归下降分析法逐级分析.

myprint()的功能是打印结构体中的值.

yyparse() 是主函数,文法开始调用Input();

Input()是输入函数, 先判断下一个token是否在input的First集里面,不是就直接报错,如果是,则根据情况调用line();如果是文件末尾就返回.

line()是line文法分析函数.同理也是先判断是否正在First集合里,然后调用expr()分析,如果遇到\n 则tonken取下一个,继续调用line(),直到最后到EOF.

expr()函数支持对expr文法的支持.这里要返回具体的运算结果了,因此先malloc所需结构体的内存.

然后判断token是否在First集里面,如果是则调用term()分析,将结果赋给src1,然后term()中最终会交还数据并且token会指向没有识别的下一个token,这里不需要再next_token(),直接判断token是否是’+’, 或 ‘-‘, 如果是则继续调用term,并把结果赋给src2,然后调用expr中的加减算法,最后使用完了free掉src2.以此类推,直到expr中遇到该文法无法处理的符号则返回,交给上级处理.

 term()与expr文法类似,函数结构也类似,在这里不再赘述,详情见calculator_myyacc.c

factor()用于判断realdigit和digit和( .如果是’(‘,则读取下一个token ,调用expr()分析,然后看下一个token是否是 ‘)’ 或’\n’不是就报错,是就返回,交给上级处理.

如果是digit 或 realdigit 则直接到yylval中读取数字,把数字内容返回.

 next_token()就是读取下一个token.

2.calculator_myyacc.h

在这里设计了myyacc.c中需要的联合体和头文件,和函数声明.详情见calculator_myyacc.h,在此不再赘述.

3. 对Makefile的修改:

修改makefile使之支持calculator 和 calculator_self的同时编译,并且调用不同的设计文件.

 五. 实验总结

5.1 调试和bug修改总结

1.一开始编写.l文件时不知道lex的语法,写完后总是报错,后来去ppt里学习了相关语法,完成实验. 一开始不知道c语言怎么将实型数字字符串识别为double ,最后上网查询调用strtod函数可以直接转换,并且 科学计数法也可以直接识别,这样省去了很多麻烦.

2.在编写calculator.y时,模仿老师的代码,在Factor中增加realdigit的支持,发现expr中没有double类型参数的调用,遂在expr.c中增加一项double realdigit,并且作为参数传入,完成实验.

3.一开始编写expr.c时,本来想如果有real类型的src,就直接把所有的val 全部赋给ralval,然后全部使用realval来计算.后来调试时发现编译器的优化会使result和src1是一个相同的的地址,最后返回的是src1,这样的话参数会总是有问题.

(个人觉得这样的优化是不合理的,目前还不知道为什么.)

4.自己根据文法写calculator_myyacc.c时,一开始根据文法规则总是递归的调用下一级分析器,发现当出现 连除 的时候,总是最后两个数先算,然后逐级向上回溯,这样和我们一般理解的从左往右计算是截然相反的,就比如4/2/2这个表达式,上述计算方法结果是4,而我们一般认为应该是1,因此后来更改为使用循环,当遇到一个term就继续判断然后计算,将结果存入src1,再继续读取下一个token直到遇到无法处理的运算符返回交给上级.

六.程序源码

TODO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值