基于Scala解析器组合器的计算器,也可以获取dataRecord [英] Scala parser combinator based calculator that can also take a dataRecord
问题描述
我创建了一个Scala解析器组合器,用于根据对上一个问题的回答过滤数据记录
I have created a Scala parser combinator to filter data records based on the answer I got to an previous question How to parse a string with filter citeria in scala and use it to filter objects
我想从这个问题的答案中添加计算器解析器组合器 使用Scala Parser组合器的运算符优先级 到我根据第一个问题创建的解析器组合器的底部.因此,计算器解析器组合器需要接受dataRecord,以便可以将类似((doubleValue1/10)* 2 + doubleValue2")的表达式解析为随后可以采用dataRecord的函数.
I would like to add the calculator parser combinator from the answer to this question Operator Precedence with Scala Parser Combinators to the bottom of the parser combinator that I created based on the first question. The calculator parser combinator therefore needs to accept a dataRecord so that an expression like "( doubleValue1 / 10 ) * 2 + doubleValue2" can be parsed to an function that subsequently can take a dataRecord.
这是我想出的,但是加号,减号,时间和除法解析器组合器现在被破坏了,因为+-*/运算符是Double的成员,而不是DataRecord => Double函数.如何修复这些解析器组合器,以便可以成功解析(doubleValue1/10)* 2 + doubleValue2"之类的表达式,并生成可以采用dataRecord的函数?
This is what I came up with but the plus, minus, times and divide parser combinators are now broken because the + - * / operators are members of Double and not the function DataRecord => Double. How can I fix these parser combinators so that an expression like "( doubleValue1 / 10 ) * 2 + doubleValue2" can be succesfully parsed and results in an function that can take a 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
}
}
推荐答案
您使用的避免左递归语法的方法不错,但是会使类型真正复杂.我更喜欢另一种方法:
Your approach to avoid a left recursive grammar is nice, but makes the types really complex. I prefer a different approach:
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
}
}
您可以在此处找到实时演示.
此代码可以进一步改进:它包含许多重复结构.对于Stack Exchange的代码审查站点来说,这也许是个好例子.
This code can be further improved: It contains lots of repeating structures. Perhaps this is a good case for Stack exchange's code review site.
其他算术运算符,数学函数,尤其是括号的增强是直接的.
Enhancements for other arithmetic operators, for mathematical functions and especially for braces are straight forward.
这篇关于基于Scala解析器组合器的计算器,也可以获取dataRecord的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!