shunting-yard_algorithm.sf 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/Parsing/Shunting-yard_algorithm
  4. #
  5. var prec = Hash(
  6. '^' => 4,
  7. '*' => 3,
  8. '/' => 3,
  9. '+' => 2,
  10. '-' => 2,
  11. '(' => 1,
  12. );
  13. var assoc = Hash(
  14. '^' => 'right',
  15. '*' => 'left',
  16. '/' => 'left',
  17. '+' => 'left',
  18. '-' => 'left',
  19. );
  20. func shunting_yard(prog) {
  21. var inp = prog.words;
  22. var ops = [];
  23. var res = [];
  24. func report (op) { printf("%25s %-7s %10s %s\n", res.join(' '), ops.join(' '), op, inp.join(' ')) }
  25. func shift (t) { report( "shift #{t}"); ops << t }
  26. func reduce (t) { report("reduce #{t}"); res << t }
  27. while (inp) {
  28. given (inp.shift) { |t|
  29. when (/\d/) { reduce(t) }
  30. when ('(') { shift(t) }
  31. when (')') { var x; while (ops && (x = ops.pop) && (x != '(')) { reduce(x) } }
  32. default {
  33. var newprec = prec{t};
  34. while (ops) {
  35. var oldprec = prec{ops[-1]};
  36. break if (newprec > oldprec)
  37. break if ((newprec == oldprec) && (assoc{t} == 'right'))
  38. reduce(ops.pop);
  39. }
  40. shift(t);
  41. }
  42. }
  43. }
  44. while (ops) { reduce(ops.pop) }
  45. return res
  46. }
  47. say shunting_yard('3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3').join(' ');