{
(* Auxiliary scanner for boolean expressions of the C# preprocessor *)

(* Concrete syntax of tokens. See module [Eparser]. *)

let string_of_token =
  let open Eparser
in function True -> "true"
      |    False -> "false"
      | Ident id -> id
      |       OR -> "||"
      |      AND -> "&&"
      |       EQ -> "=="
      |      NEQ -> "!="
      |      NOT -> "!"
      |     LPAR -> "("
      |     RPAR -> ")"
      |      EOL -> "EOL"

}

(* Regular expressions for literals *)

(* White space *)

let newline = '\n' | '\r' | "\r\n"
let blank = ' ' | '\t'

(* Unicode escape sequences *)

let digit = ['0'-'9']
let hexdigit = digit | ['A'-'F' 'a'-'f']
let four_hex = hexdigit hexdigit hexdigit hexdigit
let uni_esc = "\\u" four_hex | "\\U"  four_hex four_hex

(* Identifiers *)

let lowercase = ['a'-'z']
let uppercase = ['A'-'Z']
let letter = lowercase | uppercase | uni_esc
let start = '_' | letter
let alphanum = letter | digit | '_'
let ident = start alphanum*

(* Rules *)

rule token = parse
  blank+      { token lexbuf      }
| newline     { Lexing.new_line lexbuf; Eparser.EOL }
| eof         { Eparser.EOL       }
| "true"      { Eparser.True      }
| "false"     { Eparser.False     }
| ident as id { Eparser.Ident id  }
| '('         { Eparser.LPAR      }
| ')'         { Eparser.RPAR      }
| "||"        { Eparser.OR        }
| "&&"        { Eparser.AND       }
| "=="        { Eparser.EQ        }
| "!="        { Eparser.NEQ       }
| "!"         { Eparser.NOT       }
| "//"        { inline_com lexbuf }
| _ as c      { let code = Char.code c in
                let msg = "Invalid character " ^ String.make 1 c
                          ^ " (" ^ string_of_int code ^ ")."
                in raise Error.(Lexer (msg, mk_seg lexbuf, 1))
              }

and inline_com = parse
  newline { Lexing.new_line lexbuf; Eparser.EOL }
| eof     { Eparser.EOL }
| _       { inline_com lexbuf }

{
(* Standalone lexer for debugging purposes. See module [Topexp]. *)

type filename = string

let trace (name: filename) =
  match open_in name with
    cin ->
      let buffer = Lexing.from_channel cin
      and cout = stdout in
      let rec iter () =
        match token buffer with
          Eparser.EOL -> close_in cin; close_out cout
        |           t -> begin
                          output_string cout (string_of_token t);
                          output_string cout "\n";
                          flush cout;
                          iter ()
                        end
        | exception Error.Lexer diag -> Error.print "Lexical" diag
      in iter ()
  | exception Sys_error msg -> prerr_endline msg
}