| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- open Types
- type token = LPAREN | RPAREN | ID of string | HASH | EXCLAM | PLUS | MINUS
- let is_alnum c =
- let i = int_of_char c in
- i >= 48 & i <= 57 || i >= 65 & i <= 90 || i >= 97 & i <= 122
- let tokenize next_char emit =
- let buf = Buffer.create 32 in
- let lineno = ref 1 in
- let colno = ref 1 in
- let unexpected c =
- ParseError (Printf.sprintf
- "unexpected '%c' at line %d, character %d"
- c !lineno !colno
- )
- in
- let emit_buf () =
- if Buffer.length buf = 0 then
- ()
- else
- emit (ID (Buffer.contents buf));
- Buffer.clear buf
- in
- let nobuf c =
- if Buffer.length buf > 0 then raise (unexpected c)
- in
- let rec read_all () =
- match next_char () with
- | Some c ->
- begin
- match c with
- | '(' -> nobuf c; emit LPAREN
- | ')' -> emit_buf (); emit RPAREN
- | ';' -> emit_buf ()
- | '#' -> nobuf c; emit HASH
- | '!' -> nobuf c; emit EXCLAM
- | '+' -> nobuf c; emit PLUS
- | '-' -> nobuf c; emit MINUS
- | ' ' | '\t' | '\r' -> emit_buf ()
- | '\n' -> emit_buf (); incr lineno; colno := 0
- | c when is_alnum c -> Buffer.add_char buf c
- | _ -> raise (unexpected c)
- end;
- incr colno;
- read_all ()
- | None ->
- emit_buf ()
- in
- read_all ()
- let program_of_list = function
- | [] -> Empty
- | [p] -> p
- | p -> Concat p
- type exp = E_basic | E_jump | E_ptest | E_ntest
- let parse next_char =
- let stack = ref [ref []] in
- let expect = ref E_basic in
- let append p =
- let lst = List.hd !stack in
- lst := p :: !lst
- in
- let handler = function
- | EXCLAM -> append (Primitive Terminate)
- | HASH -> expect := E_jump
- | PLUS -> expect := E_ptest
- | MINUS -> expect := E_ntest
- | LPAREN -> stack := ref [] :: !stack
- | RPAREN ->
- if List.length !stack < 2 then begin
- raise (ParseError "too many closing parentheses")
- end;
- let body = List.rev !(List.hd !stack) in
- stack := List.tl !stack;
- append (Repeat (program_of_list body))
- | ID s ->
- let p =
- match !expect with
- | E_basic -> Basic s
- | E_jump -> Jump (int_of_string s)
- | E_ptest -> Ptest s
- | E_ntest -> Ntest s
- in
- append (Primitive p);
- expect := E_basic
- in
- tokenize next_char handler;
- if List.length !stack > 1 then
- raise (ParseError "missing closing parenthesis");
- Concat (List.rev !(List.hd !stack))
- let parse_string s =
- let i = ref 0 in
- let next_char () =
- if !i = String.length s
- then None
- else (incr i; Some (String.get s (!i - 1)))
- in
- parse next_char
|