1、8. privatecalcdsl case class UnaryOp(operator : String, arg : Expr) extends Expr 9. privatecalcdsl case class BinaryOp(operator : String, left : Expr, right : Expr) 10. extends Expr 11. 12. 对此我们可以提供类似解释器的行为,它能最大限度地简化数学表达式 清单 2. 后端(解释器)5. object Calc 6. 7. def simplify(e: Expr): Expr = 8. / first sim
2、plify the subexpressions 9. val simpSubs = e match 10. / Ask each side to simplify 11. case BinaryOp(op, left, right) = BinaryOp(op, simplify(left), simplify(right) 12. / Ask the operand to simplify 13. case UnaryOp(op, operand) = UnaryOp(op, simplify(operand) 14. / Anything else doesnt have complex
3、ity (no operands to simplify) 15. case _ = e 16. 17. 18. / now simplify at the top, assuming the components are already simplified 19. def simplifyTop(x: Expr) = x match 20. / Double negation returns the original value 21. case UnaryOp(-, UnaryOp(, x) = x 22. 23. / Positive returns the original valu
4、e 24. case UnaryOp(+, x) =25. 26. / Multiplying x by 1 returns the original value 27. case BinaryOp(*, x, Number(1) =28. 29. / Multiplying 1 by x returns the original value 30. case BinaryOp(, Number(1), x) =31. 32. / Multiplying x by 0 returns zero 33. case BinaryOp(, x, Number(0) = Number(0) 34. 3
5、5. / Multiplying 0 by x returns zero 36. case BinaryOp(, Number(0), x) =37. 38. / Dividing x by 1 returns the original value 39. case BinaryOp(/40. 41. / Dividing x by x returns 1 42. case BinaryOp(, x1, x2) if x1 = x2 = Number(1) 43. 44. / Adding x to 0 returns the original value 45. case BinaryOp(
6、46. 47. / Adding 0 to x returns the original value 48. case BinaryOp(49. 50. / Anything else cannot (yet) be simplified 51. case e =52. 53. simplifyTop(simpSubs) 54. 55. 56. def evaluate(e : Expr) : Double = 57. 58. simplify(e) match 59. case Number(x) =60. case UnaryOp( -(evaluate(x) 61. case Binar
7、yOp(, x1, x2) = (evaluate(x1) + evaluate(x2) 62. case BinaryOp( (evaluate(x1) - evaluate(x2) 63. case BinaryOp( (evaluate(x1) * evaluate(x2) 64. case BinaryOp( (evaluate(x1) / evaluate(x2) 65. 66. 67. 68. 我们使用了一个由 Scala 解析器组合子构建的文本解析器,用于解析简单的数学表达式清单 3. 前端7. object ArithParser extends JavaTokenParser
8、s 8. 9. def expr: ParserAny = term rep(term | term) 10. def term : ParserAny = factor rep(factor | factor) 11. def factor : ParserAny = floatingPointNumber | (expr) 12. 13. def parse(text : String) = 14. 15. parseAll(expr, text) 17. 18. 19. / . 20. 21. 但在进行解析时,由于解析器组合子当前被编写为返回 ParserAny 类型,所以会生成 Str
9、ing 和 List 集合,实际上应该让解析器返回它需要的任意类型(我们可以看到,此时是一个 String 和 List 集合)。要让 DSL 成功,解析器需要返回 AST 中的对象,以便在解析完成时,执行引擎可以捕获该树并对它执行 evaluate()。对于该前端,我们需要更改解析器组合子实现,以便在解析期间生成不同的对象。清理语法对解析器做的第一个更改是修改其中一个语法。在原来的解析器中,可以接受像 “5 + 5 + 5” 这样的表达式,因为语法中为表达式(expr)和术语(term)定义了 rep() 组合子。但如果考虑扩展,这可能会引起一些关联性和操作符优先级问题。以后的运算可能会要求
10、使用括号来显式给出优先级,以避免这类问题。因此第一个更改是将语法改为要求在所有表达式中加 “()”。回想一下,这应该是我一开始就需要做的事情;事实上,放宽限制通常比在以后添加限制容易(如果最后不需要这些限制),但是解决运算符优先级和关联性问题比这要困难得多。如果您不清楚运算符的优先级和关联性;那么让我大致概述一下我们所处的环境将有多复杂。考虑 Java 语言本身和它支持的各种运算符(如 Java 语言规范中所示)或一些关联性难题(来自 Bloch 和 Gafter 提供的 Java Puzzlers),您将发现情况不容乐观。因此,我们需要逐步解决问题。首先是再次测试语法:清单 4. 采用括号7
11、. / . 8. 9. object OldAnyParser extends JavaTokenParsers 10. 11. def expr:12. def term :13. def factor :14. 15. def parse(text :16. 17. parseAll(expr, text) 18. 19. 20. object AnyParser extends JavaTokenParsers 21. 22. def expr: ParserAny = (termterm) | (termterm) | term 23. def term : ParserAny = (factorfactor) | (factorfactor) | factor 24. def factor : ParserAny = expr | floatingPointNumber 26. def parse(text :27. 28. parseAll(expr, text) 29. 30.
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1