|
|
@@ -1,108 +1,23 @@
|
|
|
+open Lexing
|
|
|
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
|
|
|
+let loc_from_lexpos pstart pend =
|
|
|
+ let (fname, ystart, xstart) = begin
|
|
|
+ pstart.pos_fname,
|
|
|
+ pstart.pos_lnum,
|
|
|
+ (pstart.pos_cnum - pstart.pos_bol + 1)
|
|
|
+ end in
|
|
|
+ (fname, ystart, xstart)
|
|
|
+
|
|
|
+let loc_msg lexbuf msg =
|
|
|
+ let p = lexbuf.lex_curr_p in
|
|
|
+ let y = p.pos_lnum in
|
|
|
+ let x = p.pos_cnum - p.pos_bol in
|
|
|
+ Printf.sprintf "%s at line %d, character %d" msg y x
|
|
|
+
|
|
|
+let parse_with_error lexbuf =
|
|
|
+ try Parser.program Lexer.token lexbuf with
|
|
|
+ | Lexer.SyntaxError msg ->
|
|
|
+ raise (FatalError (loc_msg lexbuf msg))
|
|
|
+ | Parser.Error ->
|
|
|
+ raise (FatalError (loc_msg lexbuf "syntax error"))
|