parse.ml 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. open Types
  2. type token = LPAREN | RPAREN | ID of string | HASH | EXCLAM | PLUS | MINUS
  3. let tokenize next_char emit =
  4. let buf = Buffer.create 32 in
  5. let emit_buf () =
  6. match Buffer.length buf with
  7. | 0 -> ()
  8. | _ ->
  9. emit (ID (Buffer.contents buf));
  10. Buffer.clear buf
  11. in
  12. let nobuf () =
  13. assert (Buffer.length buf = 0)
  14. in
  15. let rec n () =
  16. match next_char () with
  17. | Some '(' -> nobuf (); emit LPAREN; n ()
  18. | Some ')' -> emit_buf (); emit RPAREN; n ()
  19. | Some ';' -> emit_buf (); n ()
  20. | Some '#' -> nobuf (); emit HASH; n ()
  21. | Some '!' -> nobuf (); emit EXCLAM; n ()
  22. | Some '+' -> nobuf (); emit PLUS; n ()
  23. | Some '-' -> nobuf (); emit MINUS; n ()
  24. | Some (' ' | '\t') -> emit_buf (); n ()
  25. | Some c -> Buffer.add_char buf c; n ()
  26. | None -> emit_buf ()
  27. in n ()
  28. let program_of_list = function
  29. | [] -> Empty
  30. | [p] -> p
  31. | p -> Concat p
  32. type exp = E_basic | E_jump | E_ptest | E_ntest
  33. let parse tokenize =
  34. let stack = ref [ref []] in
  35. let expect = ref E_basic in
  36. let append p =
  37. let lst = List.hd !stack in
  38. lst := p :: !lst
  39. in
  40. let handler = function
  41. | ID s ->
  42. let p =
  43. match !expect with
  44. | E_basic -> Basic s
  45. | E_jump -> Jump (int_of_string s)
  46. | E_ptest -> Ptest s
  47. | E_ntest -> Ntest s
  48. in
  49. append (Primitive p);
  50. expect := E_basic
  51. | EXCLAM ->
  52. append (Primitive Terminate)
  53. | HASH ->
  54. expect := E_jump
  55. | PLUS ->
  56. expect := E_ptest
  57. | MINUS ->
  58. expect := E_ntest
  59. | LPAREN ->
  60. stack := ref [] :: !stack
  61. | RPAREN ->
  62. let body = List.rev !(List.hd !stack) in
  63. stack := List.tl !stack;
  64. append (Repeat (program_of_list body))
  65. in
  66. tokenize handler;
  67. Concat (List.rev !(List.hd !stack))
  68. let parse_string s =
  69. let i = ref 0 in
  70. let next_char () =
  71. if !i = String.length s
  72. then None
  73. else (incr i; Some (String.get s (!i - 1)))
  74. in
  75. parse (tokenize next_char)