簡易数式パーサ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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)")) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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