Skip to content

pqdxiao/mySimpleCompilerCalc

Repository files navigation

《编译技术》课程实践报告

目录

《编译技术》课程实践报告 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

1. 系统描述

设计并实现一个桌面计算器,……这个计算器它接受四则运算表达式、关系运算表达式、逻辑运算表达式为输入,操作数为整数、浮点数或布尔数,且支持变量存储,输出时会输出值的类型,带异常处理。采用带预测的递归下降分析法构建。

1.1 系统功能

基本功能必须完成,可以在此基础上增加更多功能

  1. 以命令行方式解析用户输入的表达式,计算并显示结果;

(2)支持基本的整型和浮点类型数值计算,还支持布尔运算;

(3)支持用变量和存储计算结果、变量引用,变量类型无需声明,可根据保存的数据变化;

(4)其他扩展功能

1.2 实现语言和平台

说明开发系统所用的语言和开发平台

这个计算器是在Ubuntu平台下用C/C++编程环境,即vscode+gcc+gdb完成开发的。

1.2.1 开发软件平台

  1. 操作系统:Ubuntu 18.4
  2. 编辑器:Visual Studio Code 1.5.2
  3. 编译套件:GCC(GNU compiler collection)
  4. 调试工具:GDB(GNU symbolic debugger)

(5)建模语言:UML(Unified Modeling Language)

(6)程序设计语言:C++

(7)代码编程模型:Microsoft .NET Framework 4.7.2

-- 如果您使用的是Windows系统,建议在Visual Studio中转到“文件”>“打开”>“项目”并选择 .sln 文件同样地可以导入该项目,或者使用其他编辑器查看源码。

1.2.2 开发机硬件环境

(1)处理器: AMD Ryzen 7 3550H with Radeon Vega Mobile Gfx (8 CPUs),~2.1GHz

(2)内存:32768MB RAM

2. 系统分析与设计

2.1 需求简要分析

·本计算器要求支持的运算符和优先级(由高到低)

1运算符和常量

id,true,false,number,decimal

2括号

()

3一元运算

+, - !

4算术运算

*,/,%

5算术运算

+,-

6关系运算

<, <=, >, >=

7关系运算

==, !=

8逻辑与

&&

9逻辑或

||

10赋值/存储

=

·数据类型

bool:true和false

integer:整数值

decimal:浮点数值

类型转换规则: (1)整数和浮点数,可以相互转换,但会损失精度;

(2)布尔和其他类型转换0或非0

2.2 用例图

2.3 流程示意

由于程序不包含编译器后端,所以这里不能叫它编译器,只能叫做解释器或者说计算器。和大部分的编译程序不同,这里会先写出来可以运行的最小单元,然后一边展开范围一边迭代,让解释器可以支持更多的功能。大概的流程会是这样:

IMG_256

具体到某个分析器的参见代码和第3部分的实现。

2.2 总体实现设计

词法分析程序→语法分析程序→语义分析程序→计算器

  1. 根据文法构造语法分析表。(参见整合的SDD)
  2. 编写总控程序实现语法分析。
  3. 模块图及实现过程如下:

2.3语法制导定义(SDD)

产生式 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

2.3类图

ClassDiagram1

系统实现

3.2 概括性的程序说明

Token.h存放基本的声明,如+,-,*,/,(,)等的标记

Lexer.cpp存放词法解析程序,起中包含的一个主要函数get_token()用于返回token

Parser.cpp存放语法分析程序,包含主函数,以及每个非终结符对应的函数.

语法分析程序对于超前读取的字符,如果不需要则退回,也可以保持始终预读一个字符.本代码采用前一种.

3.3 词法分析器

词法分析器的主要工作范围:

拆分token。

过滤掉多余的空白符,发现无法识别的无效字符并报错。

记录代码中每个token的位置信息,方便在编译出错时可以定位到具体的位置。

宏定义处理。

和符号表进行交互。例如定义函数时把函数名加入函数表,方便重复定义同名函数时进行报错。

词法分析器的状态机简述:

IMG_256

3.3 错误处理

有一句名言这样说, 永远不要相信用户的输入. 对于一个表达式计算器, 我们可以限定用户只能输入数字和运算符, 但却不能阻止用户输入错误的表达式, 比如 12 + - 34 , 所以对于用户输入的表达式还要有一个语法处理的过程.

语法规定了token的排列规则, 对于表达式计算器, 像 12+-34 这样的表达式是不合法的, 那要怎么样去检测一个表达式是否合法呢?

假设此表达式计算器支持四则运算和括号, 那么它合法表达式的第一个token一定是一个数字或者左括号, 如果第一个token是数字的话, 那么第二个token一定是运算符; 而如果第一个token是左括号的话, 那么第二个token一定是数字.

所以, 当读到一个token的时候, 下一个token的类型是可以预测的. 表达式的语法并不复杂, 因此预测分支并不会太多. 当读入的下一个token与所有的预测分支都不相符时, 证明输入出现了语法错误.

3.4源代码清单(源代码以附件提交)

3.5 可执行的系统程序

- zmjsq.exe (桌面计算器)

4. 系统测试和评估报告

4.1 系统测试记录和分析报告

本报告遵循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)此时软件的需求分析,设计已经完成,测试可以进行了。

4.1.1概念定义

(1)系统:若非特别指出,系统指桌面计算机系统程序zmjsq.exe。

(2)词法分析:读入组成源程序的字符流,将它们组织成为有意义的词素(lexeme)序列,输出:对每个词素,词法分析器输出一个词法单元(token),形式如下(token-name, attribute-value).

(3)语法分析:使用词法分析生成的词法单元的第一个分量来创建树形的中间表示

该中间表示给出了词法分析产生的词法单元流的语法结构,使用的表示法是语法树(syntax tree):内部结点表示运算,相应的子结点表示运算的分量.后续步骤使用这个语法结构来分析源程序,并生成运算结果.

(4)语义分析:使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致.收集类型信息,把这些信息存放在语法树或符号表中,以便在随后的中间代码生成过程(即计算表达式的过程)中使用.

4.1.2测试计划

测试目的

测试用例设计

预期测试结果

正确的表达式

1算术表达式

正确的结果和类型

2布尔表达式

正确的结果和类型

3数值计算

正确的结果和类型

4使用变量

正确的值和类型

类型兼容和转换

5数值类型的计算

正确结果和类型

6布尔类型的逻辑运算

正确结果和类型

7同类型的比较运算

正确结果和类型

8混合类型的数值计算

正确结果和类型转换

9布尔类型参与的算术运算

类型错误

10不同数值类型比较运算

数值型转换比较

11有布尔类型参与的混合比较运算

类型错误

其他命令

12 help

命令帮助

13 @

退出

14 cls

清屏

存在错误的表达式

15不符合书写规则的运算符和数据

报告错误原因

16不符合语法规则的表达式

报告错误原因

17未定义的变量

报告错误原因

18不匹配的括号

报告错误原因

4.1.2测试概要

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

About

一个学完编译原理写的小玩意~

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published