Last active
July 14, 2021 10:19
-
-
Save kmizu/a9f9c29262d19f6110cfde4f12104109 to your computer and use it in GitHub Desktop.
8÷2(3+1) に対する二通りのパーザ(あるいはインタプリタ)作ってみた
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
import com.github.kmizu.scomb._ | |
object Calculator1 extends SCombinator[Int] { | |
def root: Parser[Int] = expression | |
def expression: Parser[Int] = rule(A) | |
def A: Parser[Int] = rule(chainl(M) { | |
$("+").map { op => (lhs: Int, rhs: Int) => lhs + rhs } | | |
$("-").map { op => (lhs: Int, rhs: Int) => lhs - rhs } | |
}) | |
def M: Parser[Int] = rule( | |
chainl(N) { | |
$("×").map { op => (lhs: Int, rhs: Int) => lhs * rhs } | | |
$("÷").map { op => (lhs: Int, rhs: Int) => lhs / rhs } | |
} | |
) | |
def N: Parser[Int] = rule { | |
(P ~ P.*).map{ case a ~ bs => bs.foldLeft(a){_ * _} } | |
} | |
def P: P[Int] = rule{ K | number } | |
def K: P[Int] = | |
(for { | |
_ <- string("("); e <- expression; _ <- string(")")} yield e) | |
def number: P[Int] = rule(set('0'to'9').+.map{ digits => digits.mkString.toInt}) | |
} |
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
import com.github.kmizu.scomb._ | |
object Calculator2 extends SCombinator[Int] { | |
def root: Parser[Int] = expression | |
def expression: Parser[Int] = rule(A) | |
def A: Parser[Int] = rule(chainl(N) { | |
$("+").map { op => (lhs: Int, rhs: Int) => lhs + rhs } | | |
$("-").map { op => (lhs: Int, rhs: Int) => lhs - rhs } | |
}) | |
def N: Parser[Int] = rule { | |
(M ~ M.*).map{ case a ~ bs => bs.foldLeft(a){_ * _} } | |
} | |
def M: Parser[Int] = rule( | |
chainl(P) { | |
$("×").map { op => (lhs: Int, rhs: Int) => lhs * rhs } | | |
$("÷").map { op => (lhs: Int, rhs: Int) => lhs / rhs } | |
} | |
) | |
def P: P[Int] = rule{ K | number } | |
def K: P[Int] = | |
(for { | |
_ <- string("("); e <- expression; _ <- string(")")} yield e) | |
def number: P[Int] = rule(set('0'to'9').+.map{ digits => digits.mkString.toInt}) | |
} |
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
[mizushima]$ sbt console | |
warning: ignoring extraneous `sbt-` prefix in version `sbt-1.5.2` | |
(set by /home/mizushima/work/implicit_multiplication/project/build.properties) | |
[info] welcome to sbt 1.5.2 (Ubuntu Java 11.0.9.1) | |
[info] loading project definition from /home/mizushima/work/implicit_multiplication/project | |
[info] loading settings for project implicit_multiplication from build.sbt ... | |
[info] set current project to implicit_multiplication (in build file:/home/mizushima/work/implicit_multiplication/) | |
[info] Starting scala interpreter... | |
Welcome to Scala 2.13.4 (OpenJDK 64-Bit Server VM, Java 11.0.9.1). | |
Type in expressions for evaluation. Or try :help. | |
scala> Calculator1.parse("8÷2(3+1)") | |
val res0: com.github.kmizu.scomb.Result[Int] = Success(1) // 暗黙の乗算を優先した場合 | |
scala> Calculator2.parse("8÷2(3+1)") | |
val res1: com.github.kmizu.scomb.Result[Int] = Success(16) // 除算を優先した場合 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment