Skip to content

Instantly share code, notes, and snippets.

@timmolderez
Created November 27, 2017 18:24
Show Gist options
  • Save timmolderez/6d1e5f25a8b59042658ad9d140ee709e to your computer and use it in GitHub Desktop.
Save timmolderez/6d1e5f25a8b59042658ad9d140ee709e to your computer and use it in GitHub Desktop.
Design patterns exercise: composite, iterator, visitor
import java.util
import ArithmeticParser.{BinaryOperators, Parentheses}
import ArithmeticParser.BinaryOperators.BinaryOperator
import scala.util.control.Breaks._
object ArithmeticParser {
object Parentheses extends Enumeration {
val LEFT, RIGHT = Value
}
object BinaryOperators {
sealed abstract class BinaryOperator(val symbol: Char, val precedence: Int) {
def eval(leftValue: Double, rightValue: Double): Double
}
case object ADD extends BinaryOperator('+', 1) {
def eval(l: Double, r: Double): Double = {
l + r
}
}
case object SUB extends BinaryOperator('-', 1) {
def eval(l: Double, r: Double): Double = {
l + r
}
}
case object MUL extends BinaryOperator('*', 2) {
def eval(l: Double, r: Double): Double = {
l * r
}
}
case object DIV extends BinaryOperator('/', 2) {
def eval(l: Double, r: Double): Double = {
l / r
}
}
val values = Set(ADD, SUB, MUL, DIV)
}
def main(args: Array[String]): Unit = {
val p = new ArithmeticParser
val testExpressions = Array("2+3", "2+3/4", "2*3-4", "2*(3+4)+5/6", "2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10")
for (testExpression <- testExpressions) {
val expression = p.parseExpression(testExpression)
System.out.println("Input: \"" + testExpression + "\", AST: \"" + expression + "\", eval=" + (if (expression.isInstanceOf[ArithmeticParser#BinaryExpression]) expression.asInstanceOf[ArithmeticParser#BinaryExpression].eval
else expression))
}
}
}
class ArithmeticParser {
class BinaryExpression(val leftOperand: Any, val operator: BinaryOperator, val rightOperand: Any) {
def eval: Double = {
val leftValue = if (leftOperand.isInstanceOf[BinaryExpression]) leftOperand.asInstanceOf[BinaryExpression].eval
else leftOperand.asInstanceOf[Double]
val rightValue = if (rightOperand.isInstanceOf[BinaryExpression]) rightOperand.asInstanceOf[BinaryExpression].eval
else rightOperand.asInstanceOf[Double]
operator.eval(leftValue, rightValue)
}
override def toString: String = "(" + leftOperand + " " + operator.symbol + " " + rightOperand + ")"
}
def createNewOperand(operator: BinaryOperator, operands: util.Stack[Any]): Unit = {
val rightOperand = operands.pop
operands.push(new BinaryExpression(operands.pop, operator, rightOperand))
}
def parseExpression(inputString: String): Any = {
var curIndex = 0
var afterOperand = false
val operands = new util.Stack[Any]
val operators = new util.Stack[AnyRef]
while (curIndex < inputString.length) {
breakable { // Using break() in this block jumps to the block's end
val startIndex = curIndex
curIndex += 1
var c = inputString.charAt(startIndex)
if (Character.isWhitespace(c)) break()
if (afterOperand) {
if (c == ')') {
while (!operators.isEmpty) {
val operator = operators.pop()
if (operator == Parentheses.LEFT) {
break()
}
}
break()
}
afterOperand = false
for (operator <- BinaryOperators.values) {
if (c == operator.symbol) {
while (!operators.isEmpty && (operators.peek ne Parentheses.LEFT)
&& (operators.peek.asInstanceOf[BinaryOperator].precedence >= operator.precedence))
createNewOperand(operators.pop.asInstanceOf[BinaryOperator], operands)
operators.push(operator)
break()
}
}
throw new IllegalArgumentException
}
if (c == '(') {
operators.push(ArithmeticParser.Parentheses.LEFT)
break()
}
afterOperand = true
var done = false
while (curIndex < inputString.length && !done) {
c = inputString.charAt(curIndex)
if (((c < '0') || (c > '9')) && (c != '.')) {
done = true
} else {
curIndex += 1
}
}
val op = inputString.substring(startIndex, curIndex).toDouble
operands.push(op)
}
}
while (!operators.isEmpty) {
val operator = operators.pop
createNewOperand(operator.asInstanceOf[BinaryOperator], operands)
}
val expression = operands.pop
return expression
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment