首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

面向 Java 開發者的 Scala 指南:構建計算器 DSL (第三部分)

     編輯:Java 相關知識

延續前兩部分,我們將計算器 DSL 從「能跑」推向「可擴展、生產就緒」。核心架構:

  • AST (抽象語法樹):Expr 密封類系,Number、Variable、UnaryOp、BinaryOp case class
  • 解釋器:simplify 化簡 + evaluate 求值
  • 解析器:Scala Parser Combinators 將字串轉 AST

關鍵重構:強制括號消除優先級歧義

原語法允許 5+5+5,擴充運算子時優先級/結合性極難處理。新語法強制所有二元運算加括號:(5+5)、((5+5)+5)。解析器組合子對應調整:

object ExprParser extends JavaTokenParsers {
    def expr: Parser[Expr] =
        (term ~ "+" ~ term) ^^ { case l~_~r => BinaryOp("+", l, r) } |
        (term ~ "-" ~ term) ^^ { case l~_~r => BinaryOp("-", l, r) } |
        term
    def term: Parser[Expr] =
        (factor ~ "*" ~ factor) ^^ { case l~_~r => BinaryOp("*", l, r) } |
        (factor ~ "/" ~ factor) ^^ { case l~_~r => BinaryOp("/", l, r) } |
        factor
    def factor: Parser[Expr] =
        "(" ~> expr <~ ")" |                           // 括號內容,丟棄括號
        floatingPointNumber ^^ (x => Number(x.toFloat)) // 數字轉 Number
    def parse(text: String) = parseAll(expr, text)
}
  • ^^ 組合子接收匿名函數,將解析結果映射為 AST 節點
  • ~> / <~ 選擇性保留/丟棄解析結果

單元測試驅動開發

@Test def parseAnExpr3 = assertEquals(
    BinaryOp("+", Number(5), Number(5)),
    Calc.parse("5 + 5")
)
@Test def add1 = assertEquals(2.0, Calc.evaluate("1 + 1"))

測試覆蓋解析、化簡、求值全鏈路。

一鍵完成:字串直達結果

def evaluate(text: String): Double = evaluate(parse(text).get)

擴展性實戰:加入冪運算 ^

  1. AST 無需變動:BinaryOp("^", x, y) 復用現有節點
  2. 擴充 evaluate:在模式匹配添加 case BinaryOp("^", x, y) => pow(evaluate(x), evaluate(y))
  3. 擴充解析器 term:添加 (factor ~ "^" ~ factor) ^^ { case l~_~r => BinaryOp("^", l, r) }
  4. 測試驗證:Calc.evaluate("2 ^ 2") == 4.0

全程零修改現有核心代碼,僅在擴充點添加 6 行邏輯,展現封裝與開放封閉原則威力。

未來增強方向

  • 支援 BigDecimal/BigInteger 任意精度運算
  • 支援十進制字面值、三角函數、變數賦值 x = y + 12
  • 將 Map[String, Double] 作為變數環境傳入 evaluate

結語

Scala 解析器組合子 + Case Class + 模式匹配 = 內建 DSL 引擎。Java 項目可直接調用 Scala 編譯的 DSL 模組,無需全面遷移語言。下期將深入泛型與更多語言特性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved