-
-
Save lyricallogical/3837249 to your computer and use it in GitHub Desktop.
RPN expression parser, derived from http://d.hatena.ne.jp/hideshi_o/20120925/1348562081
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
$ scala rpnparser.scala | |
1 1 + = 2 | |
3 1 - = -2 | |
3 2 * = 6 | |
8 2 / = 0 | |
2 (2 2 +) + = 6 | |
2 2 2 + + = 6 | |
(2 2 +) 2 + = 6 | |
(2 2 +) (4 2 +) * = 24 | |
((2 2 +) (4 2 +) *) 2 / = 0 |
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 scala.util.parsing.combinator._ | |
class RPNParser extends JavaTokenParsers { | |
def parse(data: String) = parseAll(expression, data) | |
val operator: Parser[String] = "+" | "-" | "*" | "/" | |
val literal: Parser[Operand] = ("""[0-9]+""".r) ^^ { lit => Operand(lit.toInt) } | |
val inParenExpr: Parser[OperatorApplication] = "(" ~> expression <~ ")" | |
val factor: Parser[Ast] = literal | inParenExpr | |
val expression: Parser[OperatorApplication] = { | |
def consumeFactor(stack: List[Ast]): Parser[OperatorApplication] = factor into { expr => aux(expr :: stack) } | |
lazy val aux: List[Ast] => Parser[OperatorApplication] = { | |
case stack @ rhs :: lhs :: rest => { | |
val consumeOperands: Parser[OperatorApplication] = operator ^^ { op => OperatorApplication(op, lhs, rhs) } into { opapp => | |
rest match { | |
case Nil => success(opapp) | |
case rest => aux(opapp :: rest) | |
} | |
} | |
consumeOperands | consumeFactor(stack) | |
} | |
case stack => consumeFactor(stack) | |
} | |
aux(Nil) | |
} | |
} | |
abstract sealed class Ast | |
case class OperatorApplication(operator: String, lhs: Ast, rhs: Ast) extends Ast | |
case class Operand(value: Int) extends Ast | |
val opToFun: String => (Int, Int) => Int = { | |
case "+" => _ + _ | |
case "-" => _ - _ | |
case "*" => _ * _ | |
case "/" => _ / _ | |
} | |
val eval: Ast => Int = { | |
case OperatorApplication(operator, lhs, rhs) => opToFun(operator)(eval(lhs), eval(rhs)) | |
case Operand(value) => value | |
} | |
val inputs = List( | |
"1 1 +" | |
,"3 1 -" | |
,"3 2 *" | |
,"8 2 /" | |
,"2 (2 2 +) +" | |
,"2 2 2 + +" | |
,"(2 2 +) 2 +" | |
,"(2 2 +) (4 2 +) *" | |
,"((2 2 +) (4 2 +) *) 2 /" | |
) | |
val parsers = new RPNParser | |
inputs.map{i => (i, parsers.parse(i))}.filter{_._2.successful}.foreach { case (i, r) => | |
printf("%s = %d%n", i, eval(r.get)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment