Skip to main content
  1. 归档/

OO Unit1 总结

·122 words·1 min·
心得 学习 BUAA 面向对象
此文章正在更新中……
Table of Contents

你在强测中获得了 59.9668 分的好成绩...


前言
#

第一单元的作业围绕表达式解析与括号展开这一主题,让我们体会了面向对象程序设计的思想与实现。

处理这一个问题的基本流程为:

flowchart LR 输入 --表达式--> 预处理 预处理 --表达式--> 词法分析 词法分析 --Token 流--> 语法分析 语法分析 --AST--> 语义分析 语义分析 --表达式--> 输出

先来讲讲中间四个步骤用来做什么。

预处理
#

按照形式化表述,输入的表达式也许会非常的烦人。它可能会在中间夹着许多的空格、连续的符号和前导零等等,而这些冗余部分我们将在预处理阶段进行处理。

其实,如果后面的词法分析和语法分析阶段完全是严格按照形式化表述搭建的,那么预处理只是一个可有可无的阶段。但我认为这一阶段的优势主要在于降低调试的复杂度

  1. 在进入分析阶段之前就对表达式进行预处理,这样单步调试的时候可以少摁几次键盘/鼠标。
  2. 如果在后面阶段进行处理但是出锅了,就需要逐层去确定问题的位置,增加了调试的困难程度。

预处理阶段算是对词法分析阶段的一个小小的提炼,降低了后面阶段的复杂度

词法分析
#

词法分析 (Lexical Analysis) 是将输入的字符串转换为 Token 序列的过程。

类似汉语、英语这些语言存在的字词句段篇的概念,我们也可以对数学表达式进行类似的划分,便于计算机去理解这一长串的表达式。试想我们一开始学习加减乘除的时候,也是需要先建立对各种数学符号的认知:这是数字、这是计算符号……计算机也不例外。按照词法规则对输入的表达式字符串进行处理,是一次化整为零的过程,同时这个“零”也不是简单的单个字符,而是一个有意义的 Token。

语法分析
#

语法分析 (Syntax Analysis) 基于词法分析的结果,构建表示表达式结构的语法树

无论是最开始的字符串表达式,还是经过词法分析处理得到的 Token 序列型表达式,都是符合阅读顺序的形式。事实上我们在计算表达式的过程中按照的是表达式的计算顺序:比如乘除的优先级高于加减、括号内的部分先进行计算,等等。构建表达式树,便是将阅读顺序的表达式结构,转为符合计算顺序的表达式结构,方便我们进一步进行计算处理。同时,树这一数据结构具有天然的递归性质,方便我们以递归下降法对表达式进行解析、计算和处理。

语义分析
#

语义分析 (Semantic Analysis) 确定表达式的实际含义并执行计算

这三个分析阶段其实是一个理解的重点。究竟什么是词法分析,什么是语法分析,什么是语义分析,如果没有学过编译原理,一开始上来肯定是晕头转向。我觉得还是首先要理清楚整个程序的执行流程以及每个流程阶段该做什么事情,才能依次去完成代码的编写。

有了基本的流程设计,接下来就是根据各次作业的迭代要求,逐渐去丰满流程的细节。第一次作业的架构是较为清晰、易于理解的;等到了之后的作业,出于时间和能力的有限,架构难免变得臃肿,也就无可奈何了。

hw_1 亮剑
#

架构设计
#

参考诸多往届学长的设计,特别是 zyt 学长的笔记,我最终版本实现的架构设计如下:

hw_1

整体设计分为前端和后端两个部分(这两个部分是我画图的时候突然想到的点子,写代码前没有想这么多 hhh)。前端负责输入语法分析部分的流程,后端负责语法分析语义分析部分的流程,最后再将结果交由前端输出

前后端的思想,我原本以为只是存在于 Web 开发之中的。然而寒假学习龙芯杯相关知识,阅读往届优秀代码,才发现所谓处理器也有前后端结构。我觉得简单来说,前端就是输入输出,后端就是处理。有时候为了控制后端的复杂度,会将一部分简单的处理提到前端,某种意义上可以称作“预处理”。从这个意义上来说,流程中的“预处理”、“词法分析”、“语法分析”都属于前端部分的预处理了——占据代码编写复杂度和运行时时空复杂度大头语义处理

为了维护 MainClass 类的简洁程度,整个 MainClass 类只负责输入和输出,中间的处理的详细过程通过 processInput() 调用 parse.Converter 类进行处理。(其实真正意义上的前端只有 MainClass 类吧)

早在高一之前,学校有意培养我们班的信息学竞赛,请了几个老师给我们上网课。当时老师教的 parseIn()core()writeOut() 三件套被我们一顿嘲讽,现在回旋镖打到了我自己身上……不过总的来说,竞赛追求的是快速编码解决问题,强调的是数据结构与算法;现在学习面向对象程序设计,我们更应该注重体会当中的架构设计,这时候“三件套”反倒成为某种“精髓”了。

两种体系
#

起初,我是想着将表达式解析为树的结构之后,直接调用解析好的 Expr 对象的 toString() 方法,递归调用其子节点的 toString() 方法进行输出。然而这一架构不能很好地处理化简的要求,基本上是要大大增加 ast 中各个类的设计复杂度。参考学长的设计之后,我认为将 AST 转换为 Poly-Mono 体系再进行处理、输出,这一架构具有良好的可扩展性和可维护性,理解和实现也都非常方便,所以采取了这一设计。

这种转换有很大的优势:

  1. 实现了模块化与关注点分离。AST 树负责表达式的语法表示,Poly-Mono 体系负责化简与代数计算。
  2. 思维复杂度低。换句话说就是设计简洁。在第一次作业中,所有的表达式都可以表示为 $\sum{term}$,所有的项都可以表示为 $a*x^b$。将原有的 AST 树结构化为“标准项”和“标准项集合”的结构,降低了化简和计算的复杂度。同时,将 AST 转化为 Poly-Mono 体系也极为简单,一看代码便知。

标准项
#

总结出这种设计的人们真是天才!

这是一种化零为整的思想,把 AST 中“表达式-项-因子”这样的解析结构转换为“多项式-项”这样的计算结构,便于化简和计算。

此处待完善……
tsxb
Author
tsxb
Evaluate. Focus. Moderate.