Scala的解析器组合基于计算器,也可以乘坐dataRecord(Scala parser comb

2019-10-19 08:03发布

我创建了一个Scala的解析器组合过滤基于我到前面问题的答案数据记录如何分析与斯卡拉过滤citeria一个字符串,并用它来过滤对象

我想从答案添加计算器解析器组合这个问题与Scala的解析器组合运算符优先级 ,以我创建基于第一个问题解析器组合的底部。 因此,计算器解析器组合需要接受一个dataRecord使得象“(doubleValue1 / 10)* 2 + doubleValue2”的表达可以被解析以其随后可以采取dataRecord的功能。

这是我想出了,但加,减,时间和分解析器组合正在打破,因为在+ - * /运营商双的成员,而不是功能DataRecord =>双。 如何解决这些解析器组合,使得像一个表达式“(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 
  }
}

Answer 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
  }
}

你可以找到一个在这里现场演示 。

此代码可以进一步改善:它包含大量的重复结构。 也许这是堆栈交易所代码审查的网站一个很好的案例。

其他算术运算符,数学函数尤其是对大括号的增强是直线前进。



文章来源: Scala parser combinator based calculator that can also take a dataRecord