2014-02-10 44 views
1

我創建了一個Scala的解析器組合基於我到前面的問題How to parse a string with filter citeria in scala and use it to filter objectsScala的解析器組合基於計算器,也可以採取dataRecord

我想從加計算器解析器組合的回答來過濾數據記錄這個問題的答案 Operator Precedence with Scala Parser Combinators 到基於第一個問題創建的解析器組合器的底部。因此,計算器分析程序組合器需要接受一個dataRecord,以便像「(doubleValue1/10)* 2 + doubleValue2」這樣的表達式可以被解析爲一個隨後可以接受dataRecord的函數。

這就是我想到的,但加號,減號,除法分析器組合因爲+ - * /運算符是Double的成員而不是函數DataRecord => Double而被破壞。我怎樣才能修復這些解析器組合器,以便像「(doubleValue1/10)* 2 + doubleValue2」這樣的表達式能夠被成功地解析併產生一個可以接受dataRecord的函數?

import scala.util.parsing.combinator._ 
import scala.util.parsing.combinator.JavaTokenParsers 

object Main extends Arith with App { 

    val dataRecord = new DataRecord(100, 75) 
    val input = "(doubleValue1/10 ) * 2 + doubleValue2" 
    println(parseAll(arithmicExpr, input).get(dataRecord)) // prints 95 
} 

class DataRecord( val doubleValue1 : Double, val doubleValue2 : Double) 

class Arith extends JavaTokenParsers { 

    type D = Double 
    type Extractor[Double] = DataRecord => Double 


    //arithmic expression 
    def arithmicExpr:  Parser[Extractor[D]]    = term ~ rep(plus | minus)  ^^ {case a~b => (a /: b)((acc,f) => f(acc))} 
    def plus:    Parser[Extractor[D]=>Extractor[D]] = "+" ~ term     ^^ {case "+"~b => _ + b} 
    def minus:    Parser[Extractor[D]=>Extractor[D]] = "-" ~ term     ^^ {case "-"~b => _ - b} 
    def term:    Parser[Extractor[D]]    = factor ~ rep(times | divide) ^^ {case a~b => (a /: b)((acc,f) => f(acc))} 
    def times:    Parser[Extractor[D]=>Extractor[D]] = "*" ~ factor     ^^ {case "*"~b => _ * (b) } 
    def divide:    Parser[Extractor[D]=>Extractor[D]] = "/" ~ factor     ^^ {case "/"~b => _/b} 
    def factor:    Parser[Extractor[D]]    = fpn | "(" ~> arithmicExpr <~ ")" | intExtractor 
    def fpn:    Parser[Extractor[D]]    = floatingPointNumber   ^^ (s => Function.const(s.toDouble)_) 
    def intExtractor:  Parser[Extractor[D]]    = ("doubleValue1" | "doubleValue2")    ^^ { 
    case "doubleValue1" => _.doubleValue1                        
    case "doubleValue2" => _.doubleValue2 
    } 
} 
+1

作爲一個快速提示:嘗試Functions.const(...)。這會將函數返回一個Double轉換爲需要參數的函數(例如DataRecord),忽略該參數並始終返回相同的Double。 –

回答

1

避免左遞歸語法的方法很好,但是使得類型非常複雜。我更喜歡不同的方法:

object ArithParser extends JavaTokenParsers { 
    //arithmic expression 
    def arithmicExpr:  Parser[Extractor[D]] = plus 
    def plus:    Parser[Extractor[D]] = repsep(times, "+") ^^ { summands : List[Extractor[D]] => 
    (in : DataRecord) => summands.map((e : Extractor[D]) => e(in)).foldLeft(0d)(_ + _) 
    } 
    def times:    Parser[Extractor[D]] = repsep(division, "*") ^^ { factors : List[Extractor[D]] => 
    (in : DataRecord) => factors.map((e : Extractor[D]) => e(in)).foldLeft(1d)(_ * _) 
    } 

    def division :   Parser[Extractor[D]] = rep1sep(number, "/") ^^ {divisons : List[Extractor[D]] => 
    (in : DataRecord) => divisons.map((e : Extractor[D]) => e(in)).reduce(_/_) 
    } | number 
    def number :   Parser[Extractor[D]] = fpn | intExtractor 
    def fpn:    Parser[Extractor[D]] = floatingPointNumber   ^^ (s => Function.const(s.toDouble)_) 
    def intExtractor:  Parser[Extractor[D]] = ("doubleValue1" | "doubleValue2")    ^^ { 
    case "doubleValue1" => _.doubleValue1 
    case "doubleValue2" => _.doubleValue2 
    } 
} 

你可以找到一個live demo here

該代碼可以進一步改進:它包含大量的重複結構。也許這對Stack交易所的代碼評論網站來說是個好例子。

其他算術運算符,數學函數,尤其是花括號的增強功能非常簡單。

相關問題