Created
November 27, 2017 18:24
-
-
Save timmolderez/6d1e5f25a8b59042658ad9d140ee709e to your computer and use it in GitHub Desktop.
Design patterns exercise: composite, iterator, visitor
This file contains hidden or 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 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