tags:

views:

110

answers:

2

I am experimenting with writing a toy compiler in ocaml. Currently, I am trying to implement the offside rule for my lexer. However, I am having some trouble with the ocaml syntax (the compiler errors are extremely un-informative). The code below (33 lines of it) causes an error on line 34, beyond the end of the source code. I am unsure what is causing this error.

open Printf

let s = (Stack.create():int Stack.t);

let rec check x =
    (
        if Stack.is_empty s then
            Stack.push x s
        else if Stack.top s < x then
            (
                Stack.push x s;
                printf "INDENT\n";
            )
        else if Stack.top s > x then
            (
                printf "DEDENT\n";
                Stack.pop s;
                check x;
            )
        else
            printf "MATCHED\n";
     );

let main () =
    (
        check 0;
        check 4;
        check 6;
        check 8;
        check 5;
    );

let _ = Printexc.print main ()

Ocaml output:

File "lexer.ml", line 34, characters 0-0:
Error: Syntax error

Can someone help me work out what the error is caused by and help me on my way to fixing it?

+7  A: 

The trailing ; after the definitions of main, check and s are erroneous.

Replace these 3 occurences with ;; as follows:

let s = (Stack.create():int Stack.t);;

let rec check x =
  (
      (* ...sequence of imperative statements... *)
  );;

let main () =
  (
      (* ...sequence of imperative statements... *)
  );;


; is used in the following cases:

  • to sequence imperative statements
  • as a separator between list elements
  • as a separator between array elements
  • as a separator between record fields


Some examples:

let hello_world1 () =
  print_endline "Hello";
  print_endline "World !"
;;

let hello_world2 () =
  begin
    print_endline "Hello";
    print_endline "World !"
  end
;;

let hello_world3 () =
  (
    print_endline "Hello";
    print_endline "World !";
  )
;;

let some_list =
  [1; 2; 3]
;;

let some_array =
  [| 'a'; 'b'; 'c' |]
;;

type my_process =
  {
    pid: int;
    executable_path: string;
  }
;;

let p1 = { pid = 142; executable_path = "./my_exec" };;
bltxd
Thanks for that, and also for clearing up for me where I should / should not use the single semi-colon.
a_m0d
although in this particular case, all of those double-semicolons are optional, since your file is all definitions. only when you have a bare statement at the top level, are you required to have a double-semicolon before it
newacct
I still like using the double-semis for noob examples because otherwise it can be confusing. OCaml's semicolon rules are easily the most confusing part of the language IMO, followed by the slashdot operators.
Chuck
I *think* I understand the slashdot operators, but those semi-colon rules keep tripping me up. I figured at first that double semi-colons after every statement, function call, etc. would work, but it turns out I need to put even more effort into it :-/
a_m0d
a_m0d; you should put less effort into it. Just avoid semicolons expect when dealing with imperative statements, and dealing with the toplevel (even imperative statements can avoid semicolon use, `let () = ... in`).
nlucaroni
+2  A: 

Just removing the ; works:

open Printf

let (s:int Stack.t) = Stack.create() 

let rec check x =
    (
        if Stack.is_empty s then
            Stack.push x s
        else if Stack.top s < x then
            (
                Stack.push x s;
                printf "INDENT\n";
            )
        else if Stack.top s > x then
            (
                printf "DEDENT\n";
                Stack.pop s;
                check x;
            )
        else
            printf "MATCHED\n";
     )  

let main () =
    (
        check 0;
        check 4;
        check 6;
        check 8;
        check 5;
    ) 

let _ = 
  Printexc.print main ()

Running it:

gaius@debian:~/Projects/TestCase$ ./lexer 
INDENT
INDENT
INDENT
DEDENT
DEDENT
INDENT
Gaius
How could you not mention your blog post on the subject? (I'm sure in response to this, no?) http://gaiustech.wordpress.com/2010/09/20/ocaml-compiler-errors/
nlucaroni
Actually I found this question while researching that post :-)
Gaius