前言

相较于第一次作业,第二次作业进行迭代开发主要完成的功能有:

  1. 支持三角函数
  2. 支持自定义函数

括号嵌套在第一次作业中就已经实现。


整体架构

hw2 的类图如下所示:

类图

本次迭代中主要涉及到的工作有:

  • 新增了 Function 类,用于存储自定义函数的定义并作为 Parser 的属性参与解析过程。
  • Var 类中新增了属性 exprs,用于存储三角函数的表达式。
  • ExprTermVar 三个类新增了 equals() 方法。
  • Parser 类新增了 parseBracket() 用于专门解析括号,parseFunction() 用于专门解析函数。
  • Lexer 类增加了识别 Function 的方法:getFunction()
  • 对预处理函数进行了若干调整。

迭代思路

处理三角函数

首先,将三角函数作为一项新的属性添加到了原子项当中。

在视图中,三角函数内部包含一个表达式。判断两个三角函数是否相等即等价于判断其内部的表达式是否相等。于是对 ExprTermVar 三个类中添加了 equals() 方法。

解析三角函数等价于解析括号内部表达式。将解析得到的表达式添加至三角函数内即可。

并没有对三角函数作出很强的优化。仅做了类似 sin(0) 等于 0 这样的简单化简。

Function

本类是第二次作业中新增的类,用于处理、解析、调用函数。

本类主要包含构造函数和调用函数。

在构造过程中,将函数表达式进行格式化处理。举例而言:f(x,y)=sin(x**2)+y 经处理后,解析得到 sin(($0)**2)+($1) 存储进 functionexpr 中。

在调用方法,调用流程如下:

  1. 识别实参列表。
  2. $n 替换成对应的实参。
  3. 传回替换实参后的字符串。

自定义函数解析

Parser 类中新增了 parseFunction() 方法用于解析表达式中的函数。

在解析过程中,首先进行函数的调用得到替换实参后的字符串,之后对字符串进行表达式解析,再传回解析得到的表达式。

预处理

对预处理函数的主要处理有:将 cos1*(sin1*(f1*( 等替换成 cos(sin(1*f(

复杂度分析

method CogC ev(G) iv(G) v(G)
Expr.addTerm(Term) 0.0 1.0 1.0 1.0
Expr.addTerms(ArrayList\) 1.0 1.0 2.0 2.0
Expr.equals(Expr) 16.0 5.0 5.0 9.0
Expr.Expr() 0.0 1.0 1.0 1.0
Expr.Expr(ArrayList\) 2.0 2.0 2.0 3.0
Expr.getTerms() 0.0 1.0 1.0 1.0
Expr.toString() 1.0 1.0 2.0 2.0
Function.call(String) 9.0 1.0 6.0 7.0
Function.Function(String) 1.0 1.0 2.0 2.0
Function.getExpr() 0.0 1.0 1.0 1.0
Function.getState() 0.0 1.0 1.0 1.0
Function.toString() 0.0 1.0 1.0 1.0
Lexer.getFunction() 5.0 1.0 2.0 4.0
Lexer.getNumber() 2.0 1.0 3.0 3.0
Lexer.Lexer(String) 0.0 1.0 1.0 1.0
Lexer.next() 8.0 2.0 5.0 7.0
Lexer.peek() 0.0 1.0 1.0 1.0
MainClass.main(String[]) 1.0 1.0 2.0 2.0
Parser.parseBracket(ArrayList\) 4.0 2.0 3.0 3.0
Parser.parseExpr() 2.0 1.0 3.0 3.0
Parser.parseFunction(ArrayList\, String) 7.0 4.0 5.0 5.0
Parser.Parser(Lexer, ArrayList\) 0.0 1.0 1.0 1.0
Parser.parseTerm() 13.0 1.0 10.0 10.0
Parser.parseVar() 23.0 7.0 11.0 15.0
Term.add(Term) 9.0 3.0 5.0 7.0
Term.addVar(Var) 1.0 1.0 2.0 2.0
Term.addVars(ArrayList\) 2.0 2.0 2.0 3.0
Term.addVars(Term) 1.0 1.0 2.0 2.0
Term.copy() 0.0 1.0 1.0 1.0
Term.equals(Term) 17.0 6.0 5.0 10.0
Term.getConstant() 3.0 3.0 3.0 3.0
Term.getSymbol() 0.0 1.0 1.0 1.0
Term.setSymbol() 1.0 1.0 2.0 2.0
Term.setSymbol(int) 0.0 1.0 1.0 1.0
Term.similar(Term) 39.0 13.0 15.0 21.0
Term.simplify() 23.0 5.0 13.0 14.0
Term.Term() 0.0 1.0 1.0 1.0
Term.Term(int) 0.0 1.0 1.0 1.0
Term.Term(Var) 0.0 1.0 1.0 1.0
Term.toString() 6.0 3.0 3.0 6.0
Tool.afterTreat(String) 1.0 1.0 2.0 2.0
Tool.exprSimplify(ArrayList\) 8.0 2.0 5.0 6.0
Tool.mul(ArrayList\, ArrayList\) 3.0 1.0 3.0 3.0
Tool.mul(Term, Term) 0.0 1.0 1.0 1.0
Tool.preTreat(String) 2.0 1.0 5.0 5.0
Tool.removeSpace(String) 0.0 1.0 1.0 1.0
Var.addAbs(Var) 2.0 2.0 1.0 3.0
Var.copy() 0.0 1.0 1.0 1.0
Var.equals(Var) 5.0 4.0 3.0 6.0
Var.getCharacter() 0.0 1.0 1.0 1.0
Var.getExpr() 0.0 1.0 1.0 1.0
Var.getIndex() 0.0 1.0 1.0 1.0
Var.getNum() 1.0 1.0 2.0 2.0
Var.getSymbol() 0.0 1.0 1.0 1.0
Var.getType() 0.0 1.0 1.0 1.0
Var.setSymbol(int) 0.0 1.0 1.0 1.0
Var.simplify() 8.0 4.0 5.0 8.0
Var.subAbs(Var) 2.0 2.0 1.0 3.0
Var.toString() 9.0 4.0 7.0 9.0
Var.Var(int) 1.0 1.0 1.0 2.0
Var.Var(int, BigInteger, Character, int) 0.0 1.0 1.0 1.0
Var.Var(int, BigInteger, Character, int, int) 0.0 1.0 1.0 1.0
Var.Var(int, BigInteger, Character, int, int, ArrayList\) 0.0 1.0 1.0 1.0
Var.Var(int, BigInteger, int, int) 0.0 1.0 1.0 1.0
Var.Var(int, Character, int, int) 0.0 1.0 1.0 1.0
Total 239.0 121.0 179.0 225.0
Average 3.6769230769230767 1.8615384615384616 2.753846153846154 3.4615384615384617

复杂度分析

可以看到在添加了三角函数后 Term 类的 similar 方法复杂度直接爆炸了…这主要是因为对三角函数的判断逻辑比较复杂。此外对原子项的语法解析也因为三角函数的加入而变得稍显臃肿。考虑改进的话可以将对三角函数的语法解析提取到单独的类中。

bug 分析

第二次作业的构建过程中没有遇到什么特别的 bug。强测互测也都顺利通过。

总结

第二周的压力比第一周小了很多,仿佛一切都在步上正轨,令人欣慰。虽然一度为弱智 bug 所苦恼,不过跟第一周的坐牢比起来已经幸福太多了。并且由于第一周架构比较合理(貌似是),我在本次的迭代开发的过程中并未遇到什么困难,整体架构也几乎没有变动。唯一最大的困难就是我本人捉急的码力(悲)