parse.ml 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. open Types
  2. type token = LPAREN | RPAREN | ID of string | HASH | EXCLAM | PLUS | MINUS
  3. let is_alnum c =
  4. let i = int_of_char c in
  5. i >= 48 & i <= 57 || i >= 65 & i <= 90 || i >= 97 & i <= 122
  6. let tokenize next_char emit =
  7. let buf = Buffer.create 32 in
  8. let lineno = ref 1 in
  9. let colno = ref 1 in
  10. let unexpected c =
  11. ParseError (Printf.sprintf
  12. "unexpected '%c' at line %d, character %d"
  13. c !lineno !colno
  14. )
  15. in
  16. let emit_buf () =
  17. if Buffer.length buf = 0 then
  18. ()
  19. else
  20. emit (ID (Buffer.contents buf));
  21. Buffer.clear buf
  22. in
  23. let nobuf c =
  24. if Buffer.length buf > 0 then raise (unexpected c)
  25. in
  26. let rec read_all () =
  27. match next_char () with
  28. | Some c ->
  29. begin
  30. match c with
  31. | '(' -> nobuf c; emit LPAREN
  32. | ')' -> emit_buf (); emit RPAREN
  33. | ';' -> emit_buf ()
  34. | '#' -> nobuf c; emit HASH
  35. | '!' -> nobuf c; emit EXCLAM
  36. | '+' -> nobuf c; emit PLUS
  37. | '-' -> nobuf c; emit MINUS
  38. | ' ' | '\t' | '\r' -> emit_buf ()
  39. | '\n' -> emit_buf (); incr lineno; colno := 0
  40. | c when is_alnum c -> Buffer.add_char buf c
  41. | _ -> raise (unexpected c)
  42. end;
  43. incr colno;
  44. read_all ()
  45. | None ->
  46. emit_buf ()
  47. in
  48. read_all ()
  49. let program_of_list = function
  50. | [] -> Empty
  51. | [p] -> p
  52. | p -> Concat p
  53. type exp = E_basic | E_jump | E_ptest | E_ntest
  54. let parse next_char =
  55. let stack = ref [ref []] in
  56. let expect = ref E_basic in
  57. let append p =
  58. let lst = List.hd !stack in
  59. lst := p :: !lst
  60. in
  61. let handler = function
  62. | EXCLAM -> append (Primitive Terminate)
  63. | HASH -> expect := E_jump
  64. | PLUS -> expect := E_ptest
  65. | MINUS -> expect := E_ntest
  66. | LPAREN -> stack := ref [] :: !stack
  67. | RPAREN ->
  68. if List.length !stack < 2 then begin
  69. raise (ParseError "too many closing parentheses")
  70. end;
  71. let body = List.rev !(List.hd !stack) in
  72. stack := List.tl !stack;
  73. append (Repeat (program_of_list body))
  74. | ID s ->
  75. let p =
  76. match !expect with
  77. | E_basic -> Basic s
  78. | E_jump -> Jump (int_of_string s)
  79. | E_ptest -> Ptest s
  80. | E_ntest -> Ntest s
  81. in
  82. append (Primitive p);
  83. expect := E_basic
  84. in
  85. tokenize next_char handler;
  86. if List.length !stack > 1 then
  87. raise (ParseError "missing closing parenthesis");
  88. Concat (List.rev !(List.hd !stack))
  89. let parse_string s =
  90. let i = ref 0 in
  91. let next_char () =
  92. if !i = String.length s
  93. then None
  94. else (incr i; Some (String.get s (!i - 1)))
  95. in
  96. parse next_char