Scala – 创建基本的动态函数解析器
我是
Scala的新手,但我想知道在语言中实现一个简单的Equation解析器是可能的.
假设我有一些功能(很像Excel功能): IF(Cond a = b,val_true,val_false) MID(String,Start_pos,num_chars) – 字符串提取 LEN(String) – 字符串的长度 或(cond1,cond2,… condn) AND(cond1,… condn) 所以我的想法是,我可以在运行时传递一个公式作为来自用户的字符串作为命令行参数以及任何其他参数说IF(LEN(param1)= 4,MID(param1,2,1),MID( param1,LEN(参数1))) 这个想法是评估函数,所以如果用户提供上面的公式和字符串“scat”,那么输出将是“a”.如果给出字符串“scala”,那么输出将是“scala”… 在Scala中实现这有多容易?什么是最好的设计方法?我知道没有函数指针(在C中我会将公式字符串解析为func点的集合并从那里消失)… 任何有关如何以高效的Scala风格处理此问题的建议都将受到赞赏. 干杯! 解决方法
这个问题有动力试验
combinator parsers.鉴于代表表达式子集的以下代数数据类型:
import scala.util.parsing.combinator._ object Expr { type VARS = Map[String,Any] } import Expr._ sealed trait Expr { def eval(v: VARS) : Any } case class If(cond: Cond,ifTrue: Expr,ifFalse: Expr) extends Expr { def eval(v: VARS) = if (cond.eval(v)) ifTrue.eval(v) else ifFalse.eval(v) } case class Cond(left: Expr,right: Expr) extends Expr { def eval(v: VARS) = left.eval(v) == right.eval(v) } case class Len(ident: String) extends Expr { def eval(v: VARS) = v(ident).toString.size } case class Mid(ident: String,start: Expr,count: Expr) extends Expr { def eval(v: VARS) = { val s = start.eval(v).asInstanceOf[Int] val e = s + count.eval(v).asInstanceOf[Int] v(ident).asInstanceOf[String].substring(s,e) } } case class Ident(ident: String) extends Expr { def eval(v:VARS) = v(ident) } case class StringLit(value: String) extends Expr { def eval(v:VARS) = value } case class Number(value: String) extends Expr { def eval(v:VARS) = value.toInt } 以下解析器定义将解析您的给定表达式并返回Expr对象: class Equation extends JavaTokenParsers { def IF: Parser[If] = "IF" ~ "(" ~ booleanExpr ~","~ expr ~","~ expr ~ ")" ^^ { case "IF" ~ "(" ~ booleanExpr ~ "," ~ ifTrue ~ "," ~ ifFalse ~ ")" => If(booleanExpr,ifTrue,ifFalse) } def LEN: Parser[Len] = "LEN" ~> "(" ~> ident <~ ")" ^^ (Len(_)) def MID: Parser[Mid] = "MID" ~ "(" ~ ident ~ "," ~ expr ~ "," ~ expr ~ ")" ^^ { case "MID" ~ "(" ~ ident ~ "," ~ expr1 ~ "," ~ expr2 ~ ")" => Mid(ident,expr1,expr2) } def expr: Parser[Expr] = ( stringLiteral ^^ (StringLit(_)) | wholeNumber ^^ (Number(_)) | LEN | MID | IF | ident ^^ (Ident(_)) ) def booleanExpr: Parser[Cond] = expr ~ "=" ~ expr ^^ { case expr1 ~ "=" ~ expr2 => Cond(expr1,expr2) } } 然后解析和评估结果可以这样做: val equation = new Equation val parsed = equation.parseAll(equation.expr,"""IF(LEN(param1)=4,LEN(param1)))""") parsed match { case equation.Success(expr,_) => println(expr) // If(Cond(Len(param1),Number(4)),// Mid(param1,Number(2),Number(1)),Number(0),Len(param1))) println(expr.eval(Map("param1" -> "scala"))) // prints scala println(expr.eval(Map("param1" -> "scat"))) // prints a case _ => println("cannot parse") } 请注意,我提供的语法只是使您的示例解析的最小值,并且绝对没有错误管理或类型检查.顺便说一句,我首先提出了一个没有生成的语法^^ …会解析你的例子,然后添加Expr类型但没有eval方法,然后生成^^ …,然后我最后添加了eval Expr特征和子类的方法. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |