(*module Lexer = struct *) (***** parser abstract data data structure *****) exception ParserError of string;; type symbol = string;; type defn = symbol * exp and exp = | Bool of bool | Null | Num of int | Id of symbol | Prim of symbol | Uop of symbol * exp | Biop of symbol * exp * exp | Map of symbol list * exp | App of exp * exp list | If of exp * exp * exp | Let of defn list * exp | Block of exp list ;; let is_term = fun x -> match x with | Uop(a,b) -> true | App(a,b) -> true | Null -> true | Num(i) -> true | Bool(b) -> true | _ -> false ;; let is_exp = fun x -> (is_term x) or match x with | Biop(a,b,c) -> true | If(a,b,c) -> true | Let(a,b) -> true | Map(a,b) -> true | _ -> false ;; let rec string_of_exp = fun e -> match e with | Bool(true) -> "true" | Bool(false) -> "false" | Null -> "null" | Num(n) -> string_of_int n | Id(s) -> s | Prim(s) -> s | Uop(s,e1) -> s^" "^ (string_of_exp e1) | Biop(s,e1,e2)-> "("^(string_of_exp e1) ^" " ^s^" "^ (string_of_exp e2)^")" | Map(l,e) -> "map "^ (List.fold_left (fun s e -> if (String.length s) = 0 then e else s ^ "," ^ e ) "" l) ^ " to " ^ (string_of_exp e) | App(e,l) -> let se = string_of_exp e in (if (is_exp e) then "("^se^")" else se)^"(" ^ (List.fold_left (fun s e -> let se = (string_of_exp e) in if (String.length s) = 0 then se else s ^ ", " ^ se ) "" l) ^ ")" | If (a,b,c) -> "if " ^(string_of_exp a)^" then "^(string_of_exp b)^" else "^(string_of_exp c) | Let (l,exp) -> "let "^ (List.fold_left (fun s d -> match d with | (v,e) -> let se = v^" := "^(string_of_exp e)^";" in if (String.length s) = 0 then se else s ^" "^ se ) "" l) ^ " in " ^ (string_of_exp exp) | Block(l) -> "{"^ (List.fold_left (fun s e -> let se = (string_of_exp e) in if (String.length s) = 0 then se else s ^ "; " ^ se ) "" l) ^"}" ;; (*****************************************************) let id = fun x -> x exception LexerError of string let str = fun c -> let s = String.create 1 in ((String.set s 0 c); s) let primitiveList = ["number?";"function?";"arity"; "list?";"null?";"cons?";"cons";"first";"rest"] let keywordList = ["if";"then";"else";"map";"to";"let";"in";"null";"true";"false"] let operatorList = ['+';'-';'*';'/';'~';'=';'<';'>';'&';'|';':';'!'] let delimiterList = ['(';')';'[';']';',';';'] let whitespaceList = [' ';'\t';'\r';'\n'] let digit = fun x -> (let i = int_of_char x in (i >= 48) & (i<=57)) and alphanumeric= fun x-> let i = int_of_char x in ((i>=48) & (i<=57)) or ((i>=65) & (i<=90)) or ((i>=97) & (i<=122)) or (i = (int_of_char '_')) or (i = (int_of_char '?')) type token = Keyword of string | Primitive of string | Delimiter of string | Operator of string | Number of int | Variable of string | EOF let string_of_token = fun x -> match x with | Keyword (s) -> s | Primitive(s) -> s | Delimiter(s) -> s | Operator(s) -> s | Number(n) -> string_of_int n | Variable(s) -> s | EOF -> "" (* makeLexer : ('a -> Scanf.Scanning.scanbuf) -> 'a -> 'b -> token = *) let makeLexer = fun makeScanbuf -> fun input -> (* function temporary vars *) let rec scanbuf = (makeScanbuf input) and peek = ref ' ' and nextToken = ref EOF and updatePeek = (fun _-> if (Scanf.Scanning.end_of_input scanbuf) then peek := char_of_int 0 else peek := (Scanf.bscanf scanbuf "%c" id)) in (* main looping function *) let rec loop = fun _ -> if !peek = (char_of_int 0) then EOF else if (List.mem !peek operatorList) then let firstch = ref !peek in updatePeek(); if (List.mem !firstch [':';'!';'<';'>']) then (if (!peek = '=') then (* need to also add in '<', and '-' maybe *) let x = Operator ( (str !firstch) ^ (str !peek) ) in (updatePeek(); x) else if (List.mem !firstch ['!';':']) then raise (LexerError ("invalid char '" ^ str !firstch ^"'")) else Operator (str !firstch)) else if (!firstch = '/' & !peek ='/') then (let restLine = (Scanf.bscanf scanbuf "%s@\n" id) in (updatePeek(); loop())) else Operator (str !firstch) else if (List.mem !peek whitespaceList) then (updatePeek(); loop()) else if (List.mem !peek delimiterList) then (let ch = !peek in updatePeek(); Delimiter(str ch)) else if (alphanumeric !peek) then let firstch = ref !peek in let curr = ref "" in (while (alphanumeric !peek) do (curr := (!curr ^ str !peek); updatePeek()) done; try let intValue = (int_of_string !curr) in Number (intValue) with _ -> (if digit (! firstch) then raise (LexerError ("invalid lead character "^ str !firstch ^" in identifier ")) else if (List.mem !curr primitiveList) then Primitive !curr else if (List.mem !curr keywordList) then Keyword !curr (* else if (!curr = 'ref') Operator !curr *) else Variable !curr)) else raise (LexerError ("invalid char '"^ str !peek ^"'")) in (fun mode -> match (!nextToken, mode) with | (EOF, "peek") -> (nextToken := loop(); !nextToken) | (EOF, y) -> loop() | (x , "peek") -> !nextToken | (x , y) -> (nextToken := EOF; x)) (* val make_file_lexer : string -> string -> token = *) (* val make_string_lexer : string -> string -> token = *) let make_file_lexer = makeLexer (fun f -> Scanf.Scanning.from_file f) let make_string_lexer = makeLexer (fun f -> Scanf.Scanning.from_string f) let printToken = fun x -> match x with | Keyword (s) -> print_string ("K("^ s ^")") | Primitive(s) -> print_string ("P("^ s ^")") | Delimiter(s) -> print_string ("D("^ s ^")") | Operator(s) -> print_string ("O("^ s ^")") | Number(n) -> print_string ("N("^ (string_of_int n) ^")") | Variable(s) -> print_string ("V("^ s^")") | EOF -> print_string "EOF" (* end;; *) (* let x = make_file_lexer "tests/let.in";; let last = ref (Number(0)) in while not (!last =EOF) do last := (x("pop")); print_string ("found:"^ (string_of_token !last)^"\n") done;; print_string "\n\n"; *)