Advertisement
Guest User

Untitled

a guest
Dec 19th, 2014
149
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.36 KB | None | 0 0
  1. open System.Collections
  2. open System.Collections.Generic
  3. open System.Text.RegularExpressions
  4.  
  5. type Token =
  6. | Num of float
  7. | Plus
  8. | Minus
  9. | Star
  10. | Hat
  11. | Sqrt
  12. | Slash
  13. | Negative
  14. | RParen
  15. | LParen
  16.  
  17. let hasAny (list: Stack<'T>) =
  18. list.Count <> 0
  19.  
  20. let tokenize (input:string) =
  21. let tokens = new Stack<Token>()
  22. let push tok = tokens.Push tok
  23. let regex = new Regex(@"[0-9]+(.+d*)?|+|-|*|/|^|)|(|pi|e|sqrt")
  24. for x in regex.Matches(input.ToLower()) do
  25. match x.Value with
  26. | "+" -> push Plus
  27. | "*" -> push Star
  28. | "/" -> push Slash
  29. | ")" -> push LParen
  30. | "(" -> push RParen
  31. | "^" -> push Hat
  32. | "sqrt" -> push Sqrt
  33. | "pi" -> push (Num System.Math.PI)
  34. | "e" -> push (Num System.Math.E)
  35. | "-" ->
  36. if tokens |> hasAny then
  37. match tokens.Peek() with
  38. | LParen -> push Minus
  39. | Num v -> push Minus
  40. | _ -> push Negative
  41. else
  42. push Negative
  43.  
  44. | value -> push (Num (float value))
  45. tokens.ToArray() |> Array.rev |> Array.toList
  46.  
  47.  
  48.  
  49. let isUnary = function
  50. | Negative | Sqrt -> true
  51. | _ -> false
  52.  
  53.  
  54. let prec = function
  55. | Hat -> 3
  56. | Star | Slash -> 2
  57. | Plus | Minus -> 1
  58. | _ -> 0
  59.  
  60.  
  61.  
  62. let toRPN src =
  63. let output = new ResizeArray<Token>()
  64. let stack = new Stack<Token>()
  65. let rec loop = function
  66. | Num v::tokens ->
  67. output.Add(Num v)
  68. loop tokens
  69. | RParen::tokens ->
  70. stack.Push RParen
  71. loop tokens
  72. | LParen::tokens ->
  73. while stack.Peek() <> RParen do
  74. output.Add(stack.Pop())
  75. stack.Pop() |> ignore // pop the "("
  76. loop tokens
  77. | op::tokens when op |> isUnary ->
  78. stack.Push op
  79. loop tokens
  80. | op::tokens ->
  81. if stack |> hasAny then
  82. if prec(stack.Peek()) >= prec op then
  83. output.Add(stack.Pop())
  84. stack.Push op
  85. loop tokens
  86. | [] ->
  87. output.AddRange(stack.ToArray())
  88. output
  89. (loop src).ToArray()
  90.  
  91. let (@) op tok =
  92. match tok with
  93. | Num v ->
  94. match op with
  95. | Sqrt -> Num (sqrt v)
  96. | Negative -> Num (v * -1.0)
  97. | _ -> failwith "input error"
  98. | _ -> failwith "input error"
  99.  
  100. let (@@) op toks =
  101. match toks with
  102. | Num v,Num u ->
  103. match op with
  104. | Plus -> Num(v + u)
  105. | Minus -> Num(v - u)
  106. | Star -> Num(v * u)
  107. | Slash -> Num(u / v)
  108. | Hat -> Num(u ** v)
  109. | _ -> failwith "input error"
  110. | _ -> failwith "inpur error"
  111.  
  112.  
  113. let evalRPN src =
  114. let stack = new Stack<Token>()
  115. let rec loop = function
  116. | Num v::tokens ->
  117. stack.Push(Num v)
  118. loop tokens
  119. | op::tokens when op |> isUnary ->
  120. let result = op @ stack.Pop()
  121. stack.Push result
  122. loop tokens
  123. | op::tokens ->
  124. let result = op @@ (stack.Pop(),stack.Pop())
  125. stack.Push result
  126. loop tokens
  127. | [] -> stack
  128. if loop src |> hasAny then
  129. match stack.Pop() with
  130. | Num v -> v
  131. | _ -> failwith "input error"
  132. else failwith "input error"
  133.  
  134. let eval input =
  135. input |> (tokenize >> toRPN >> Array.toList >> evalRPN)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement