目录
《编译技术》课程实践报告 1
1. 系统描述 2
1.1 系统功能 2
1.2 实现语言和平台 2
1.2.1 开发软件平台 2
1.2.2 开发机硬件环境 2
2. 系统分析与设计 3
2.1 需求简要分析 3
2.2 用例图 4
2.3 流程示意 4
2.2 总体实现设计 4
2.3语法制导定义(SDD) 5
2.3类图 9
3. 系统实现 10
3.2 概括性的程序说明 10
3.3 词法分析器 10
3.3 错误处理 11
3.4源代码清单(源代码以附件提交) 11
3.5 可执行的系统程序 11
4. 系统测试和评估报告 12
4.1 系统测试记录和分析报告 12
4.2 系统的评估和评价 17
设计并实现一个桌面计算器,……这个计算器它接受四则运算表达式、关系运算表达式、逻辑运算表达式为输入,操作数为整数、浮点数或布尔数,且支持变量存储,输出时会输出值的类型,带异常处理。采用带预测的递归下降分析法构建。
基本功能必须完成,可以在此基础上增加更多功能
- 以命令行方式解析用户输入的表达式,计算并显示结果;
(2)支持基本的整型和浮点类型数值计算,还支持布尔运算;
(3)支持用变量和存储计算结果、变量引用,变量类型无需声明,可根据保存的数据变化;
(4)其他扩展功能
说明开发系统所用的语言和开发平台
这个计算器是在Ubuntu平台下用C/C++编程环境,即vscode+gcc+gdb完成开发的。
- 操作系统:Ubuntu 18.4
- 编辑器:Visual Studio Code 1.5.2
- 编译套件:GCC(GNU compiler collection)
- 调试工具:GDB(GNU symbolic debugger)
(5)建模语言:UML(Unified Modeling Language)
(6)程序设计语言:C++
(7)代码编程模型:Microsoft .NET Framework 4.7.2
-- 如果您使用的是Windows系统,建议在Visual Studio中转到“文件”>“打开”>“项目”并选择 .sln 文件同样地可以导入该项目,或者使用其他编辑器查看源码。
(1)处理器: AMD Ryzen 7 3550H with Radeon Vega Mobile Gfx (8 CPUs),~2.1GHz
(2)内存:32768MB RAM
·本计算器要求支持的运算符和优先级(由高到低)
1运算符和常量
id,true,false,number,decimal
2括号
()
3一元运算
+, - !
4算术运算
*,/,%
5算术运算
+,-
6关系运算
<, <=, >, >=
7关系运算
==, !=
8逻辑与
&&
9逻辑或
||
10赋值/存储
=
·数据类型
bool:true和false
integer:整数值
decimal:浮点数值
类型转换规则: (1)整数和浮点数,可以相互转换,但会损失精度;
(2)布尔和其他类型转换0或非0
由于程序不包含编译器后端,所以这里不能叫它编译器,只能叫做解释器或者说计算器。和大部分的编译程序不同,这里会先写出来可以运行的最小单元,然后一边展开范围一边迭代,让解释器可以支持更多的功能。大概的流程会是这样:
具体到某个分析器的参见代码和第3部分的实现。
词法分析程序→语法分析程序→语义分析程序→计算器
产生式 and语义规则
S → Expr
print\(Expr\.type, Expr\.value\)
Expr → id = Expr
ExprL\.value = ExprR\.value
ExprL\.type = ExprR\.value
SymbolTable\.add\(id\.name, Expr\.type, Expr\.value\)
Expr → OrExpr
Expr\.value = OrExpr\.value
Expr\.type = OrExpr\.value
OrExpr → AndExpr OER
OER\.iv = AndExpr\.value
OER\.it = AndExpr\.type
OrExpr\.value = OER\.value
OrExprL\.type = OER\.type
OER → && AndExpr OER
CheckType\(OERL\.itype\) is Bool
CheckType\(AndExpr\.type\) is Bool
if\(OERL\.iv\) OERR\.iv =true;
else OERR\.iv = AndExpr\.value
OERR\.it = Bool
OERL\.value = OERR\.value
OERL\.type = OERR\.type
OER → ε
OER\.value = OER\.iv
OER\.type = OER\.it
AndExpr → CmpExpr NER
NER\.iv = CmpExpr\.value
NER\.it = CmpExpr\.type
AndExpr\.value = NER\.value
AndExprL\.type = NER\.type
NER → && CmpExpr NER
CheckType\(NERL\.itype\) is Bool
CheckType\(CmpExpr\.type\) is Bool
if\(NERL\.iv\) NERR\.iv = CmpExpr\.value;
else NERR\.iv = false
NERR\.it = Bool
NERL\.value = NERR\.value
NERL\.type = NERR\.type
NER → ε
NER\.value = NER\.iv
NER\.type = NER\.it
CmpExpr → RelExpr CER
CER\.iv = RelExpr\.value
CER\.it = RelExpr\.type
CmpExpr\.value = CER\.value
CmpExprL\.type = CER\.type
CER → == RelExpr CER
CheckType\(CERL\.it, RelExpr\.type\) is comparable
CERR\.iv = CERL\.iv == RelExpr\.value
CERR\.it = Bool
CERL\.value = CERR\.value
CERL\.type = CERR\.type
CER → != RelExpr CER
CheckType\(CERL\.it, RelExpr\.type\) is comparable
CERR\.iv = CERL\.iv \!= RelExpr\.value
CERR\.it = Bool
CERL\.value = CERR\.value
CERL\.type = CERR\.type
CER → ε
CER\.value = CER\.iv
CER\.type = CER\.it
RelExpr → AddExpr RER
RER\.iv = AddExpr\.value
RER\.it = AddExpr\.type
RelExpr\.value = RER\.value
RelExprL\.type = RER\.type
RER → relop AddExpr RER
CheckType\(RERL\.it, AddExpr\.type\) is comparable
RERR\.iv = RERL\.iv relop\.lex AddExpr\.value
RERR\.it = Bool
RERL\.value = RERR\.value
RERL\.type = RERR\.type
RER → ε
RER\.value = RER\.iv
RER\.type = RER\.it
AddExpr → MulExpr AER
AER\.iv = MulExpr\.value
AER\.it = MulExpr\.type
AddExpr\.value = AER\.value
AddExprL\.type = AER\.type
AER → + MULExpr AER
CheckType\(AERL\.it, MulExpr\.type\) is convertable
AERR\.iv = AERL\.iv \+ MulExpr\.value
AERR\.it = wider\(aERL\.it, MulExpr\.type\)
AERL\.value = AERR\.value
AERL\.type = AERR\.type
AER → - MULExpr AER
CheckType\(AERL\.it, MulExpr\.type\) is convertable
AERR\.iv = AERL\.iv \- MulExpr\.value
AERR\.it = wider\(AERL\.it, MulExpr\.type\)
AERL\.value = AERR\.value
AERL\.type = AERR\.type
AER → ε
AER\.value = AER\.iv
AER\.type = AER\.it
MulExpr → UniExpr MER
MER\.iv = UniExpr\.value
MER\.it = UniExpr\.type
MulExpr\.value = MER\.value
MulExprL\.type = MER\.type
MER → * UniExpr MER
CheckType\(MERL\.it, UniExpr\.type\) is convertable
MERR\.iv = MER\.iv \* UniExpr\.value
MERR\.it = wider\(MERL\.it, UniExpr\.type\)
MERL\.value = MERR\.value
MERL\.type = MERR\.type
MER → / UniExpr MER
CheckType\(MERL\.it, UniExpr\.type\) is convertable
CheckZero\(UniExpr\.value\) is not 0
MERR\.iv = MER\.iv / UniExpr\.value
MERR\.it = wider\(MERL\.it, UniExpr\.type\)
MERL\.value = MERR\.value
MERL\.type = MERR\.type
MER → % UniExpr MER
CheckType\(MERL\.it, UniExpr\.type\) is convertable
CheckZero\(UniExpr\.value\) is not 0
MERR\.iv = MER\.iv / UniExpr\.value
MERR\.it = wider\(MERL\.it, UniExpr\.type\)
MERL\.value = MERR\.value
MERL\.type = MERR\.type
MER → ε
MER\.value = MER\.iv
MER\.type = MER\.it
UniExpr → !UniExpr
if\(UniExpr\.value==0\) UniExpr\.value = true
else UniExpr\.value = false
UniExpr\.type = Bool
UniExpr → +UniExpr
CheckType\(UniExprR\.type\) is Integer or Decimal;
UniExprL\.value = UniExprR\.value
UniExprL\.type = UniExprR\.type
UniExpr → -UniExpr
CheckType\(UniExprR\.type\) is Integer or Decimal;
UniExprL\.value = \-UniExprR\.value
UniExpr:\.type = UniExpr\.Rtype
UniExpr → ElemExpr
UniExpr\.value = ElemExpr\.value
UniExpr\.type = ElemExpr\.type
ElemExpr → (Expr)
ElemExpr\.value = Expr\.value
ElemExpr\.type = Expr\.type
ElemExpr → id
ElemExpr\.value = id\.value
ElemExpr\.type = id\.type
ElemExpr → number
ElemExpr\.value = number\.value
ElemExpr\.type = number\.type
ElemExpr → decimal
ElemExpr\.value =decimal\.value
ElemExpr\.type = decimal\.type
ElemExpr → true
ElemExpr\.value = true
ElemExpr\.type = Bool
ElemExpr → false
ElemExpr\.value = false
ElemExpr\.type = Bool
Token.h存放基本的声明,如+,-,*,/,(,)等的标记
Lexer.cpp存放词法解析程序,起中包含的一个主要函数get_token()用于返回token
Parser.cpp存放语法分析程序,包含主函数,以及每个非终结符对应的函数.
语法分析程序对于超前读取的字符,如果不需要则退回,也可以保持始终预读一个字符.本代码采用前一种.
词法分析器的主要工作范围:
拆分token。
过滤掉多余的空白符,发现无法识别的无效字符并报错。
记录代码中每个token的位置信息,方便在编译出错时可以定位到具体的位置。
宏定义处理。
和符号表进行交互。例如定义函数时把函数名加入函数表,方便重复定义同名函数时进行报错。
词法分析器的状态机简述:
有一句名言这样说, 永远不要相信用户的输入. 对于一个表达式计算器, 我们可以限定用户只能输入数字和运算符, 但却不能阻止用户输入错误的表达式, 比如 12 + - 34 , 所以对于用户输入的表达式还要有一个语法处理的过程.
语法规定了token的排列规则, 对于表达式计算器, 像 12+-34 这样的表达式是不合法的, 那要怎么样去检测一个表达式是否合法呢?
假设此表达式计算器支持四则运算和括号, 那么它合法表达式的第一个token一定是一个数字或者左括号, 如果第一个token是数字的话, 那么第二个token一定是运算符; 而如果第一个token是左括号的话, 那么第二个token一定是数字.
所以, 当读到一个token的时候, 下一个token的类型是可以预测的. 表达式的语法并不复杂, 因此预测分支并不会太多. 当读入的下一个token与所有的预测分支都不相符时, 证明输入出现了语法错误.
- zmjsq.exe (桌面计算器)
本报告遵循GB8567——88规范。
本测试分析报告与分析报告搭配使用,本测试报告与分析报告记录了测试过程及结果,以及对系统各个功能及整体的分析,供测试人员、开发人员和项目经理审阅。
(1)被测试系统:桌面计算器
(2)测试时使用环境:
0.操作系统: Ubuntu 18.4
1. 处理器: AMD Ryzen 7 3550H with Radeon Vega Mobile Gfx (8 CPUs),~2.1GHz
2. 内存:32768MB RAM
(3)此时软件的需求分析,设计已经完成,测试可以进行了。
(1)系统:若非特别指出,系统指桌面计算机系统程序zmjsq.exe。
(2)词法分析:读入组成源程序的字符流,将它们组织成为有意义的词素(lexeme)序列,输出:对每个词素,词法分析器输出一个词法单元(token),形式如下(token-name, attribute-value).
(3)语法分析:使用词法分析生成的词法单元的第一个分量来创建树形的中间表示
该中间表示给出了词法分析产生的词法单元流的语法结构,使用的表示法是语法树(syntax tree):内部结点表示运算,相应的子结点表示运算的分量.后续步骤使用这个语法结构来分析源程序,并生成运算结果.
(4)语义分析:使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致.收集类型信息,把这些信息存放在语法树或符号表中,以便在随后的中间代码生成过程(即计算表达式的过程)中使用.
测试目的
测试用例设计
预期测试结果
正确的表达式
1算术表达式
正确的结果和类型
2布尔表达式
正确的结果和类型
3数值计算
正确的结果和类型
4使用变量
正确的值和类型
类型兼容和转换
5数值类型的计算
正确结果和类型
6布尔类型的逻辑运算
正确结果和类型
7同类型的比较运算
正确结果和类型
8混合类型的数值计算
正确结果和类型转换
9布尔类型参与的算术运算
类型错误
10不同数值类型比较运算
数值型转换比较
11有布尔类型参与的混合比较运算
类型错误
其他命令
12 help
命令帮助
13 @
退出
14 cls
清屏
存在错误的表达式
15不符合书写规则的运算符和数据
报告错误原因
16不符合语法规则的表达式
报告错误原因
17未定义的变量
报告错误原因
18不匹配的括号
报告错误原因
1算术表达式
2布尔表达式
3数值计算
4使用变量
5数值类型的计算
6布尔类型的逻辑运算
7同类型的比较运算
8混合类型的数值计算
9布尔类型参与的算术运算(应不被允许)
10不同数值类型比较运算
11有布尔类型参与的混合比较运算(应不被允许)
12 help
13@
14cls
15不符合书写规则的运算符和数据
![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAhQAAABvCAIAAAA7Ys6ZAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAABJ0AAASdAHeZh94AAAMLUlEQVR4nO3dz2ta6RrA8afDhfsvaLCOtFK69HZcGAgUxFxOSjMLIRBIVqZx4WR2hjuLICIuLijMYnKzMImrBAJCF02ZOUyCUCjoQorLYbDBsZLjP9HOXfg7Ho3nRE9M+v2sEh/POa9n4eP747zPg3/+a0G+Hu5gYVe5SIfXzm+7JZiaL18+f/ny97Dog7FeAnCNf9x2Ayzi3UicrthEJE/mAIAbe/B19TzwFaDnAVjgm9tuAADg7iF5AAAMI3kAAAwjeQAADLM8ebiDBTWRcBsMAQBmicXJw3e8q0juIFYZOxSIaGpGOwh6DV3H3FEAgPFYmTyciYOQv5idP6yNF/IdqxltobFfN3QVc0cBAAzQSx7uYEHNHAf03m4uJCIi3o1Xm47ydrw4XsiZOAhJOmyPl0a2/wpzRwEAjNFLHpXXP+Ya/mimsOGcTEhExPn9vK2ae3s0bqgWe3Xto+C+Y/XK5cY5CgBwU/rDVqXDmD1ddq3sDE4bmAuJ27vokIu/BgesRoYAADNp+JzH+Z5dyeYdyqkaWb95yGVzSfk33T7BiBAAYCaNnjAvrinJ/bonpTOZYSzk/dY27BojQvqaK6nUjKaG/CKulZ3Wv3GfsfMAAMwavauu71gN+aW8rewNzFUYC5X+agy7xoiQvvM9+3n3Qo9ySb3lWwCAKRre83AHC2rIX1eXB9ODiVC1URXPku5arBEhAMBM0k8e3o2EtqtILml/9bo0iZBUSmd18S/ojSyNCAEAZpJePY8R5fbMhUSkVY5J9rdig4+X64Y65Zt6XVvKydxRuE+o5wFYwMpiUM7Ewc5mPWvXeU5wRAgwhuQBWMDK7Ulqsf+qVV9Ib1nUiBAAYOZ