|         |      1 // Shunting Yard Algorithm  | 
|         |      2 // including Associativity for Operators  | 
|         |      3 // ===================================== | 
|         |      4  | 
|         |      5 object CW8b {  | 
|         |      6  | 
|         |      7 // type of tokens | 
|         |      8 type Toks = List[String] | 
|         |      9  | 
|         |     10 // helper function for splitting strings into tokens | 
|         |     11 def split(s: String) : Toks = s.split(" ").toList | 
|         |     12  | 
|         |     13 // left- and right-associativity | 
|         |     14 abstract class Assoc | 
|         |     15 case object LA extends Assoc | 
|         |     16 case object RA extends Assoc | 
|         |     17  | 
|         |     18 // power is right-associative, | 
|         |     19 // everything else is left-associative | 
|         |     20 def assoc(s: String) : Assoc = s match { | 
|         |     21   case "^" => RA | 
|         |     22   case _ => LA | 
|         |     23 } | 
|         |     24  | 
|         |     25 // the precedences of the operators | 
|         |     26 val precs = Map("+" -> 1, | 
|         |     27   		 "-" -> 1, | 
|         |     28 		 "*" -> 2, | 
|         |     29 		 "/" -> 2, | 
|         |     30                  "^" -> 4) | 
|         |     31  | 
|         |     32 // the operations in the basic version of the algorithm | 
|         |     33 val ops = List("+", "-", "*", "/", "^") | 
|         |     34  | 
|         |     35 // (8) Implement the extended version of the shunting yard algorithm. | 
|         |     36 // This version should properly account for the fact that the power  | 
|         |     37 // operation is right-associative. Apart from the extension to include | 
|         |     38 // the power operation, you can make the same assumptions as in  | 
|         |     39 // basic version. | 
|         |     40  | 
|         |     41 def is_op(op: String) : Boolean = ops.contains(op) | 
|         |     42  | 
|         |     43 def prec(op1: String, op2: String) : Boolean = assoc(op1) match { | 
|         |     44   case LA => precs(op1) <= precs(op2) | 
|         |     45   case RA => precs(op1) < precs(op2) | 
|         |     46 } | 
|         |     47  | 
|         |     48 def syard(toks: Toks, st: Toks = Nil, out: Toks = Nil) : Toks = (toks, st, out) match { | 
|         |     49   case (Nil, _, _) => out.reverse ::: st | 
|         |     50   case (num::in, st, out) if (num.forall(_.isDigit)) =>  | 
|         |     51     syard(in, st, num :: out) | 
|         |     52   case (op1::in, op2::st, out) if (is_op(op1) && is_op(op2) && prec(op1, op2)) => | 
|         |     53     syard(op1::in, st, op2 :: out)  | 
|         |     54   case (op1::in, st, out) if (is_op(op1)) => syard(in, op1::st, out) | 
|         |     55   case ("("::in, st, out) => syard(in, "("::st, out) | 
|         |     56   case (")"::in, op2::st, out) => | 
|         |     57     if (op2 == "(") syard(in, st, out) else syard(")"::in, st, op2 :: out) | 
|         |     58   case (in, st, out) => { | 
|         |     59     println(s"in: ${in}   st: ${st}   out: ${out.reverse}") | 
|         |     60     Nil | 
|         |     61   }   | 
|         |     62 }  | 
|         |     63  | 
|         |     64 def op_comp(s: String, n1: Long, n2: Long) = s match { | 
|         |     65   case "+" => n2 + n1 | 
|         |     66   case "-" => n2 - n1 | 
|         |     67   case "*" => n2 * n1 | 
|         |     68   case "/" => n2 / n1 | 
|         |     69   case "^" => Math.pow(n2, n1).toLong | 
|         |     70 }  | 
|         |     71  | 
|         |     72 def compute(toks: Toks, st: List[Long] = Nil) : Long = (toks, st) match { | 
|         |     73   case (Nil, st) => st.head | 
|         |     74   case (op::in, n1::n2::st) if (is_op(op)) => compute(in, op_comp(op, n1, n2)::st) | 
|         |     75   case (num::in, st) => compute(in, num.toInt::st)   | 
|         |     76 } | 
|         |     77  | 
|         |     78  | 
|         |     79  | 
|         |     80  | 
|         |     81 //compute(syard(split("3 + 4 * ( 2 - 1 )")))   // 7 | 
|         |     82 //compute(syard(split("10 + 12 * 33")))       // 406 | 
|         |     83 //compute(syard(split("( 5 + 7 ) * 2")))      // 24 | 
|         |     84 //compute(syard(split("5 + 7 / 2")))          // 8 | 
|         |     85 //compute(syard(split("5 * 7 / 2")))          // 17 | 
|         |     86 //compute(syard(split("9 + 24 / ( 7 - 3 )"))) // 15 | 
|         |     87  | 
|         |     88 //compute(syard(split("4 ^ 3 ^ 2")))      // 262144 | 
|         |     89 //compute(syard(split("4 ^ ( 3 ^ 2 )")))  // 262144 | 
|         |     90 //compute(syard(split("( 4 ^ 3 ) ^ 2")))  // 4096 | 
|         |     91 //compute(syard(split("( 3 + 1 ) ^ 2 ^ 3")))   // 65536 | 
|         |     92  | 
|         |     93 //syard(split("3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3"))  // 3 4 8 * 5 1 - 2 3 ^ ^ / + | 
|         |     94 //compute(syard(split("3 + 4 * 8 / ( 5 - 1 ) ^ 2 ^ 3"))) // 3 | 
|         |     95  | 
|         |     96 //compute(syard(split("( 3 + 1 ) ^ 2 ^ 3")))   // 65536 | 
|         |     97  | 
|         |     98  | 
|         |     99  | 
|         |    100 } |