fork download
  1. Status = Struct.new(:text, :pos, :matched, :named, :group_stack, :data)
  2.  
  3. def deepcopy(a)
  4. Marshal.load Marshal.dump a
  5. end
  6. class Object
  7. unless method_defined?(:tap)
  8. def tap
  9. yield self
  10. self
  11. end
  12. end
  13. end
  14.  
  15. def match_string(str)
  16. len = str.size
  17. lambda{|nextpart|
  18. lambda{|status|
  19. if status.text[status.pos, len] == str
  20. nextpart.call(deepcopy(status).tap{|s|
  21. s.pos += len
  22. s.matched << str
  23. })
  24. end
  25. }
  26. }
  27. end
  28.  
  29. def match_eos
  30. lambda{|nextpart|
  31. lambda{|status|
  32. if status.pos == status.text.size
  33. nextpart.call(status)
  34. end
  35. }
  36. }
  37. end
  38.  
  39. def match_charset(str)
  40. lambda{|nextpart|
  41. lambda{|status|
  42. next if status.pos == status.text.size
  43. if str[status.text[status.pos, 1]]
  44. nextpart.call(deepcopy(status).tap{|s|
  45. s.matched << s.text[s.pos, 1]
  46. s.pos += 1
  47. })
  48. end
  49. }
  50. }
  51. end
  52.  
  53. def match_ok()
  54. lambda{|nextpart|
  55. lambda{|status|
  56. p status
  57. }
  58. }
  59. end
  60.  
  61. class Proc
  62. def >>(rhs)
  63. lambda{|nextpart|
  64. self.call(rhs.call(nextpart))
  65. }
  66. end
  67. alias & >>
  68.  
  69. def |(rhs)
  70. lambda{|np|
  71. lambda{|status|
  72. self.call(np).call(deepcopy(status))
  73. rhs.call(np).call(deepcopy(status))
  74. }
  75. }
  76. end
  77.  
  78. def *(rep = nil)
  79. f = lambda{|np|
  80. lambda{|s|
  81. (self >> f).call(np).call(deepcopy(s))
  82. np.call(deepcopy(s))
  83. }
  84. }
  85. end
  86.  
  87. def nocapture
  88. self >> lambda{|np| lambda{|s| s.matched.pop; np.call(s)}}
  89. end
  90.  
  91.  
  92. end
  93.  
  94. def match_any
  95. lambda{|np| lambda{|s| yield(np, s) } }
  96. end
  97.  
  98. def match_nil
  99. lambda{|np| lambda{|s| np.call(s)}}
  100. end
  101.  
  102. def group_begin(name)
  103. lambda{|np| lambda{|s|
  104. s.group_stack.push([name, s.matched.length]);
  105. np.call(s)}
  106. }
  107. end
  108.  
  109. def group_end
  110. lambda{|np| lambda{|s|
  111. name, start = s.group_stack.pop
  112. s.named[name] = s.matched[start..-1].join
  113. np.call(s)
  114. } }
  115. end
  116.  
  117. def eval_expr(str)
  118. st = Status.new
  119. st.pos = 0
  120. st.matched = []
  121. st.named = {}
  122. st.group_stack = []
  123. st.text = str
  124. st.data = []
  125. expr, additive, multitive, num,expr_bracket, single, calc = 'decl'
  126.  
  127. expr = match_any{|np, st| additive.call(np).call(st) }
  128. expr_bracket = match_string("(") & expr & match_string(")") & match_any{|np, st|
  129. a,b,c=st.matched.slice!(-3..-1);
  130. st.matched.push calc[b]
  131. np.call(st)
  132. }
  133.  
  134. calc = lambda{|b|
  135. next b unless Array === b
  136. ret = b[1]
  137. i = 2
  138. while i < b.size
  139. ret = ret.send(b[i], b[i+1]) rescue p(b)
  140. i += 2
  141. end
  142. ret
  143. }
  144.  
  145. additive = match_any{|np, st|
  146. (
  147. multitive |
  148. multitive & match_charset("+-") & additive & match_any{|np, st|
  149. a,b,c = st.matched.slice!(-3..-1);
  150. a = calc[a] if Array === a && a[0] == :mul
  151. c = calc[c] if Array === c && c[0] == :mul
  152. arr = [:add, a, b, c]
  153. arr = [:add, a, b, *c[1..-1]] if Array === c && c[0] == :add
  154. st.matched.push arr
  155. np.call(st)
  156. }
  157. ).call(np).call(st)
  158. }
  159.  
  160.  
  161. multitive = match_any{|np, st|
  162. (
  163. single |
  164. single & match_charset("*/") & multitive & match_any{|np, st|
  165. a,b,c = st.matched.slice!(-3..-1)
  166. arr = [:mul, a, b, c]
  167. arr = [:mul, a, b, *c[1..-1]] if Array === c && c[0] == :mul
  168. st.matched.push arr
  169. np.call(st)
  170. }
  171. ).call(np).call(st)
  172. }
  173.  
  174. num = match_any{|np, st|
  175. if a = st.text[st.pos..-1][/^(\d+)/, 1]
  176. s = deepcopy(st)
  177. s.matched << a.to_i
  178. s.pos += a.length
  179. np.call(s)
  180. end
  181. }
  182. single = expr_bracket | num
  183. ret = nil
  184. (expr >> match_eos).call(lambda{|st|ret = st.matched[-1]}).call(st)
  185. calc[ret]
  186. end
  187.  
  188. p eval_expr("222*67+192*(37-48)")
  189.  
Success #stdin #stdout 0.03s 7432KB
stdin
Standard input is empty
stdout
12762