Skip to content

Instantly share code, notes, and snippets.

@kamiyaowl
Last active August 29, 2015 14:15
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save kamiyaowl/13c3baf5b6678c9e7511 to your computer and use it in GitHub Desktop.
簡易数式パーサ
/**
* Created by kamiya on 2015/02/11.
*/
import util.parsing.combinator._
object Main {
class Expr
class Literal extends Expr
case class ConstNumber[+A](num: A) extends Literal
case class BoolLiteral(b: Boolean) extends Literal
case class Variable(name: String) extends Literal
case class ArgsList(args:List[Expr]) extends Literal
case class Func(a: Variable, args: ArgsList) extends Literal
class BinaryOp(a: Expr, b: Expr) extends Expr
case class Assign(a: Expr, b: Expr) extends BinaryOp(a, b)
case class AssignFunc(a: Expr, b: Expr) extends BinaryOp(a, b)
case class BitAnd(a: Expr, b: Expr) extends BinaryOp(a, b)
case class BitOr(a: Expr, b: Expr) extends BinaryOp(a, b)
case class BitXor(a: Expr, b: Expr) extends BinaryOp(a, b)
case class BitLeftShift(a: Expr, b: Expr) extends BinaryOp(a, b)
case class BitRightShift(a: Expr, b: Expr) extends BinaryOp(a, b)
case class LogicAnd(a: Expr, b: Expr) extends BinaryOp(a, b)
case class LogicOr(a: Expr, b: Expr) extends BinaryOp(a, b)
case class Over(a: Expr, b: Expr) extends BinaryOp(a, b)
case class AndOver(a: Expr, b: Expr) extends BinaryOp(a, b)
case class Equal(a: Expr, b: Expr) extends BinaryOp(a, b)
case class NotEqual(a: Expr, b: Expr) extends BinaryOp(a, b)
case class AndLess(a: Expr, b: Expr) extends BinaryOp(a, b)
case class Less(a: Expr, b: Expr) extends BinaryOp(a, b)
case class Add(a: Expr, b: Expr) extends BinaryOp(a, b)
case class Sub(a: Expr, b: Expr) extends BinaryOp(a, b)
case class Mul(a: Expr, b: Expr) extends BinaryOp(a, b)
case class Div(a: Expr, b: Expr) extends BinaryOp(a, b)
case class Rest(a: Expr, b: Expr) extends BinaryOp(a, b)
class UnaryOp(a: Expr) extends Expr
case class BitNot(a: Expr) extends UnaryOp(a)
case class BitInv(a: Expr) extends UnaryOp(a)
object ExprParser extends RegexParsers {
def intNumber = "[0-9]+".r ^^ { r => ConstNumber[Int](r.toInt)}
def hexNumber = "0x[0-9a-fA-F]+".r ^^ {r => ConstNumber(Integer.parseInt(r.replace("0x",""),16)) }
def binNumber = "0b[01]+".r ^^ {r => ConstNumber(Integer.parseInt(r.replace("0b",""),2)) }
def doubleNumber = ("[0-9]+".r <~ ".") ~ "[0-9]+".r ^^ { case a ~ b => ConstNumber[Double](s"$a.$b".toDouble)}
def boolean = ("[Tt]rue".r | "[Ff]alse".r) ^^ { r => BoolLiteral(r.toBoolean) }
def variable = "[a-zA-Z0-9]+".r ^^ { r => Variable(r)}
def args = (("(" ~> variable) ~ rep("," ~> variable)) <~ ")" ^^ { case head ~ tail => ArgsList(head :: tail) }
def function : Parser[Literal] = variable ~ args ^^ { case name ~ argv => Func(name,argv) }
def literal : Parser[Literal] = hexNumber | binNumber | doubleNumber | intNumber | function | boolean | variable
def bitTerm : Parser[String] = "<<" | ">>" | "&" | "|" | "^"
def logicTerm : Parser[String] = "&&" | "||"
def compTerm : Parser[String] = ">=" | ">" | "==" | "!=" | "<=" | "<"
def exprTerm : Parser[String] = "+" | "-"
def opTerm: Parser[String] = "*" | "/" | "%"
def singleTerm : Parser[String] = "!" | "~"
def assignFunc : Parser[Expr] = ((args | variable) <~ "=>") ~ assign ^^ {
case argv~ body => AssignFunc(argv,body)
}
def assign : Parser[Expr] = bit ~ rep("=" ~ bit) ^^ {
case n ~ body => (n /: body){ (s,x) => { x._1 match {
case "=" => Assign(s,x._2)
}}}
}
def bit : Parser[Expr] = logic ~ rep(bitTerm ~ logic) ^^ {
case n ~ body => (n /: body){ (s,x) => { x._1 match {
case "<<" => BitLeftShift(s,x._2)
case ">>" => BitRightShift(s,x._2)
case "&" => BitAnd(s,x._2)
case "|" => BitOr(s,x._2)
case "^" => BitXor(s,x._2)
}}}
}
def logic : Parser[Expr] = comp ~ rep(logicTerm ~ comp) ^^ {
case n ~ body => (n /: body){ (s,x) => { x._1 match {
case "&&" => LogicAnd(s,x._2)
case "||" => LogicOr(s,x._2)
}}}
}
def comp : Parser[Expr] = expr ~ rep(compTerm ~ expr) ^^ {
case n ~ body => (n /: body){ (s,x) => { x._1 match {
case ">" => Over(s, x._2)
case ">=" => AndOver(s, x._2)
case "==" => Equal(s,x._2)
case "!=" => NotEqual(s,x._2)
case "<=" => AndLess(s,x._2)
case "<" => Less(s,x._2)
}}}
}
def expr : Parser[Expr] = term ~ rep(exprTerm ~ term) ^^ {
case n ~ body => (n /: body){ (s,x) => { x._1 match {
case "+" => Add(s, x._2)
case "-" => Sub(s, x._2)
}}}
}
def term: Parser[Expr] = unary ~ rep(opTerm ~ unary) ^^ {
case n ~ body => ((n.asInstanceOf[Expr]) /: body){ (s,x) => { x._1 match {
case "*" => Mul(s, x._2)
case "/" => Div(s, x._2)
case "%" => Rest(s,x._2)
}}}
}
def unary = single | literal
def single: Parser[Expr] = singleTerm ~ unary ^^ {
case ("!" ~ literal) => BitNot(literal)
case ("~" ~ literal) => BitInv(literal)
}
}
def main(args: Array[String]) = {
println(ExprParser.parseAll(ExprParser.intNumber, "123"))
println(ExprParser.parseAll(ExprParser.doubleNumber, "123.456"))
println(ExprParser.parseAll(ExprParser.variable, "deltaX"))
println(ExprParser.parseAll(ExprParser.literal, "123"))
println(ExprParser.parseAll(ExprParser.literal, "123.456"))
println(ExprParser.parseAll(ExprParser.literal, "deltaX"))
println(ExprParser.parseAll(ExprParser.term, "deltaX * 100"))
println(ExprParser.parseAll(ExprParser.term, "deltaX * 100 / n"))
println(ExprParser.parseAll(ExprParser.expr, "a * a + b * b"))
println(ExprParser.parseAll(ExprParser.expr, "a + b + 10 * b"))
println(ExprParser.parseAll(ExprParser.comp, "a + b + 10 * b == z"))
println(ExprParser.parseAll(ExprParser.comp, "a < b + 10 * b == z > f"))
println(ExprParser.parseAll(ExprParser.comp, "1 < 2 <= 3 == 4 + 5 != 6 > 7 > 8 + 9 * x"))
println(ExprParser.parseAll(ExprParser.comp, "1 <= 2 + 3"))
println(ExprParser.parseAll(ExprParser.logic, "1 == 2 && 3 < 1 * 5"))
println(ExprParser.parseAll(ExprParser.logic, "true || false && true"))
println(ExprParser.parseAll(ExprParser.logic, "1 < 2 || 3 || 4 > 5 && 6"))
println(ExprParser.parseAll(ExprParser.logic, "true || False"))
println(ExprParser.parseAll(ExprParser.logic, "False && True"))
println(ExprParser.parseAll(ExprParser.bit, "x << 5"))
println(ExprParser.parseAll(ExprParser.bit, "x << 5 >> 5"))
println(ExprParser.parseAll(ExprParser.bit, "x << 5 >> 5 ^ y"))
println(ExprParser.parseAll(ExprParser.bit, "x << 5 >> 5 ^ y == z & A"))
println(ExprParser.parseAll(ExprParser.bit, "x << 5 >> 5 ^ y == z & A && B | z || false"))
println(ExprParser.parseAll(ExprParser.bit, "0xfe"))
println(ExprParser.parseAll(ExprParser.bit, "0x80"))
println(ExprParser.parseAll(ExprParser.bit, "0b1010110"))
println(ExprParser.parseAll(ExprParser.bit, "0b1010110 & 0b11110000"))
println(ExprParser.parseAll(ExprParser.bit, "~0xff"))
println(ExprParser.parseAll(ExprParser.bit, "!!!!!!!!!!true || ~~~~~~~~~~0xff"))
println(ExprParser.parseAll(ExprParser.bit, "!true != false"))
println(ExprParser.parseAll(ExprParser.assign, "hoge = false"))
println(ExprParser.parseAll(ExprParser.assignFunc, "foo => x * x"))
println(ExprParser.parseAll(ExprParser.assignFunc, "(a,b,c) => d = a + b < c == true"))
println(ExprParser.parseAll(ExprParser.assignFunc, "(a,b,c) => sin(a) + cos(b) + tan(c)"))
println(ExprParser.parseAll(ExprParser.assignFunc, "(x,y,r) => pow(x,2) + pow(y,2) <= pow(r,2)"))
}
}
[1.4] parsed: ConstNumber(123)
[1.8] parsed: ConstNumber(123.456)
[1.7] parsed: Variable(deltaX)
[1.4] parsed: ConstNumber(123)
[1.8] parsed: ConstNumber(123.456)
[1.7] parsed: Variable(deltaX)
[1.13] parsed: Mul(Variable(deltaX),ConstNumber(100))
[1.17] parsed: Div(Mul(Variable(deltaX),ConstNumber(100)),Variable(n))
[1.14] parsed: Add(Mul(Variable(a),Variable(a)),Mul(Variable(b),Variable(b)))
[1.15] parsed: Add(Add(Variable(a),Variable(b)),Mul(ConstNumber(10),Variable(b)))
[1.20] parsed: Equal(Add(Add(Variable(a),Variable(b)),Mul(ConstNumber(10),Variable(b))),Variable(z))
[1.24] parsed: Over(Equal(Less(Variable(a),Add(Variable(b),Mul(ConstNumber(10),Variable(b)))),Variable(z)),Variable(f))
[1.41] parsed: Over(Over(NotEqual(Equal(AndLess(Less(ConstNumber(1),ConstNumber(2)),ConstNumber(3)),Add(ConstNumber(4),ConstNumber(5))),ConstNumber(6)),ConstNumber(7)),Add(ConstNumber(8),Mul(ConstNumber(9),Variable(x))))
[1.11] parsed: AndLess(ConstNumber(1),Add(ConstNumber(2),ConstNumber(3)))
[1.22] parsed: LogicAnd(Equal(ConstNumber(1),ConstNumber(2)),Less(ConstNumber(3),Mul(ConstNumber(1),ConstNumber(5))))
[1.22] parsed: LogicAnd(LogicOr(BoolLiteral(true),BoolLiteral(false)),BoolLiteral(true))
[1.25] parsed: LogicAnd(LogicOr(LogicOr(Less(ConstNumber(1),ConstNumber(2)),ConstNumber(3)),Over(ConstNumber(4),ConstNumber(5))),ConstNumber(6))
[1.14] parsed: LogicOr(BoolLiteral(true),BoolLiteral(false))
[1.14] parsed: LogicAnd(BoolLiteral(false),BoolLiteral(true))
[1.7] parsed: BitLeftShift(Variable(x),ConstNumber(5))
[1.12] parsed: BitRightShift(BitLeftShift(Variable(x),ConstNumber(5)),ConstNumber(5))
[1.16] parsed: BitXor(BitRightShift(BitLeftShift(Variable(x),ConstNumber(5)),ConstNumber(5)),Variable(y))
[1.25] parsed: BitAnd(BitXor(BitRightShift(BitLeftShift(Variable(x),ConstNumber(5)),ConstNumber(5)),Equal(Variable(y),Variable(z))),Variable(A))
[1.43] parsed: BitOr(BitAnd(BitXor(BitRightShift(BitLeftShift(Variable(x),ConstNumber(5)),ConstNumber(5)),Equal(Variable(y),Variable(z))),LogicAnd(Variable(A),Variable(B))),LogicOr(Variable(z),BoolLiteral(false)))
[1.5] parsed: ConstNumber(254)
[1.5] parsed: ConstNumber(128)
[1.10] parsed: ConstNumber(86)
[1.23] parsed: BitAnd(ConstNumber(86),ConstNumber(240))
[1.6] parsed: BitInv(ConstNumber(255))
[1.33] parsed: LogicOr(BitNot(BitNot(BitNot(BitNot(BitNot(BitNot(BitNot(BitNot(BitNot(BitNot(BoolLiteral(true))))))))))),BitInv(BitInv(BitInv(BitInv(BitInv(BitInv(BitInv(BitInv(BitInv(BitInv(ConstNumber(255))))))))))))
[1.15] parsed: NotEqual(BitNot(BoolLiteral(true)),BoolLiteral(false))
[1.13] parsed: Assign(Variable(hoge),BoolLiteral(false))
[1.13] parsed: AssignFunc(Variable(foo),Mul(Variable(x),Variable(x)))
[1.33] parsed: AssignFunc(ArgsList(List(Variable(a), Variable(b), Variable(c))),Assign(Variable(d),Equal(Less(Add(Variable(a),Variable(b)),Variable(c)),BoolLiteral(true))))
[1.36] parsed: AssignFunc(ArgsList(List(Variable(a), Variable(b), Variable(c))),Add(Add(Func(Variable(sin),ArgsList(List(Variable(a)))),Func(Variable(cos),ArgsList(List(Variable(b))))),Func(Variable(tan),ArgsList(List(Variable(c))))))
[1.43] parsed: AssignFunc(ArgsList(List(Variable(x), Variable(y), Variable(r))),AndLess(Add(Func(Variable(pow),ArgsList(List(Variable(x), Variable(2)))),Func(Variable(pow),ArgsList(List(Variable(y), Variable(2))))),Func(Variable(pow),ArgsList(List(Variable(r), Variable(2))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment