fork download
  1. open System
  2.  
  3. let satisfy p = function
  4. | c::cs when p c -> Some(c, cs)
  5. | _ -> None
  6.  
  7. let pstring cs s =
  8. let rec aux = function
  9. | [], s -> Some((), s)
  10. | x::xs, c::s when x = c -> aux (xs, s)
  11. | _ -> None
  12. aux (Seq.toList cs, s)
  13. let eos = function [] as xs -> Some((), xs) | _ -> None
  14.  
  15. let (|>>) p f = p >> Option.map (fun (x, s) -> f x, s)
  16. let (>>%) p x = p |>> fun _ -> x
  17. let (</>) p1 p2 s = p1 s |> Option.orElseWith (fun _ -> p2 s)
  18. let (.>>.) p1 p2 s = p1 s |> Option.bind (fun (x1, s) -> p2 s |> Option.map (fun (x2, s) -> (x1, x2), s))
  19. let (.>>) p1 p2 = (p1 .>>. p2) |>> fst
  20. let (>>.) p1 p2 = (p1 .>>. p2) |>> snd
  21.  
  22. let many p =
  23. let rec aux xs s =
  24. match p s with
  25. | None -> List.rev xs, s
  26. | Some(x, s) -> aux (x::xs) s
  27. aux [] >> Some
  28.  
  29. let many1 p = p .>>. many p |>> list.Cons
  30.  
  31. let chainl p op =
  32. p .>>. many (op .>>. p)
  33. |>> fun (x, xs) -> List.fold (fun x (op, y) -> op x y) x xs
  34.  
  35. let refParser() =
  36. let ref = ref <| fun _ -> failwith ""
  37. ref, fun s -> !ref s
  38.  
  39. let run p = Seq.toList >> p >> Option.map fst
  40.  
  41. let parser =
  42. let t = pstring
  43. let number = many1 (satisfy Char.IsDigit) |>> (List.toArray >> String >> double)
  44. let mulOp = (t"*" >>% (*)) </> (t"/" >>% (/)) </> (t"" >>% (*))
  45. let addOp = (t"+" >>% (+)) </> (t"-" >>% (-))
  46.  
  47. let _exp, exp = refParser()
  48. let prim = (t"(" >>. exp .>> t")") </> number
  49. let mul = chainl prim mulOp
  50. let add = chainl mul addOp
  51. _exp := add
  52.  
  53. add .>> eos
  54.  
  55. let eval s =
  56. if 1000 < String.length s then None
  57. else run parser s
  58. |> Option.map (truncate >> string)
  59. |> Option.defaultValue "Error"
  60. |> stdout.WriteLine
  61.  
  62. let rec aux () =
  63. match stdin.ReadLine() with
  64. | null -> ()
  65. | x -> eval x; aux()
  66. aux()
  67.  
  68. lazy
  69. eval "1+2*((3-4*5)/6+7)*8-9" // 58
  70. eval "100/2(3+4)" // 350
  71. eval "100/2*(3+4)" // 350
  72. eval "*10" // Error
  73. eval (String.replicate 1001 "0") // Error
  74. eval "1/3*3" // 1
  75.  
Success #stdin #stdout 0.08s 21820KB
stdin
1+2*((3-4*5)/6+7)*8-9
100/2(3+4)
100/2*(3+4)
*10
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1/3*3
stdout
58
350
350
Error
Error
1