home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Moscow ML 1.42 / src / lex / Lexgen.sml < prev    next >
Encoding:
Text File  |  1997-08-18  |  6.8 KB  |  255 lines  |  [TEXT/R*ch]

  1. (* Compiling a lexer definition *)
  2.  
  3. local
  4.   open List Fnlib Syntax;
  5. in
  6.  
  7. (* Deep abstract syntax for regular expressions *)
  8.  
  9. datatype regexp =
  10.     Empty
  11.   | Chars of int
  12.   | Action of int
  13.   | Seq of regexp * regexp
  14.   | Alt of regexp * regexp
  15.   | Star of regexp
  16. ;
  17.  
  18. (* From shallow to deep syntax *)
  19.  
  20. val chars = ref ([] : char list list);
  21. val chars_count = ref 0;
  22. val actions_count = ref 0;
  23.  
  24. fun encode_regexp Epsilon = Empty
  25.   | encode_regexp (Characters cl) =
  26.       let val n = !chars_count in
  27.         chars := cl :: !chars;
  28.         incr chars_count;
  29.         Chars(n)
  30.       end
  31.   | encode_regexp (Sequence(r1,r2)) =
  32.       Seq(encode_regexp r1, encode_regexp r2)
  33.   | encode_regexp (Alternative(r1,r2)) =
  34.       Alt(encode_regexp r1, encode_regexp r2)
  35.   | encode_regexp (Repetition r) =
  36.       Star (encode_regexp r)
  37. ;
  38.  
  39. fun encode_casedef casedef =
  40.     let val actions = ref ([] : (int * location) list)
  41.     fun addact (expr, act) reg =
  42.         let val act_num = !actions_count in
  43.         incr actions_count;
  44.         actions := (act_num, act) :: !actions;
  45.         Alt(reg, Seq(encode_regexp expr, Action act_num))
  46.         end
  47.     val regexp = foldL addact Empty casedef
  48.     in (regexp, !actions) end;
  49.  
  50. (*
  51.   This function simulates map as defined in Caml Light,
  52.   to ensure the evaluation order from right to left!
  53.   This is essential, if f may produce side-effects.
  54.  
  55.   The goal is to get mosmllex to produce exactly the same
  56.   result, as its version written in Caml Light.
  57. *)
  58.  
  59. fun caml_map f [] = []
  60.   | caml_map f (x::xs) =
  61.       let val ys = caml_map f xs
  62.           val y  = f x
  63.       in y :: ys end
  64.  
  65. fun encode_lexdef (Lexdef(_, ld)) =
  66. (
  67.   chars := [];
  68.   chars_count := 0;
  69.   actions_count := 0;
  70.   let val name_regexp_actdef_list =
  71.           caml_map (fn (name, casedef) => (name, encode_casedef casedef)) ld
  72.       val chr = Array.fromList (rev (!chars))
  73.       val name_regexp_list = 
  74.       map (fn (n, (r, _)) => (n, r)) name_regexp_actdef_list
  75.       val act = 
  76.       map (fn (_, (_, a)) => a) name_regexp_actdef_list
  77.   in
  78.     chars := [];
  79.     (chr, name_regexp_list, act)
  80.   end
  81. );
  82.  
  83. (* To generate directly a NFA from a regular expression.
  84.    Confer Aho-Sethi-Ullman, dragon book, chap. 3 *)
  85.  
  86. datatype transition =
  87.     OnChars of int
  88.   | ToAction of int
  89. ;
  90.  
  91. fun merge_trans [] s2 = s2
  92.   | merge_trans s1 [] = s1
  93.   | merge_trans (s1 as (t1 as OnChars n1) :: r1)
  94.                 (s2 as (t2 as OnChars n2) :: r2) =
  95.       if n1 = n2 then t1 :: merge_trans r1 r2 else
  96.       if n1 < n2 then t1 :: merge_trans r1 s2 else
  97.                       t2 :: merge_trans s1 r2
  98.   | merge_trans (s1 as (t1 as ToAction n1) :: r1)
  99.                 (s2 as (t2 as ToAction n2) :: r2) =
  100.       if n1 = n2 then t1 :: merge_trans r1 r2 else
  101.       if n1 < n2 then t1 :: merge_trans r1 s2 else
  102.                       t2 :: merge_trans s1 r2
  103.   | merge_trans (s1 as (t1 as OnChars n1) :: r1)
  104.                 (s2 as (t2 as ToAction n2) :: r2) =
  105.       t1 :: merge_trans r1 s2
  106.   | merge_trans (s1 as (t1 as ToAction n1) :: r1)
  107.                 (s2 as (t2 as OnChars n2) :: r2) =
  108.       t2 :: merge_trans s1 r2
  109. ;
  110.  
  111. fun nullable Empty        = true
  112.   | nullable (Chars _)    = false
  113.   | nullable (Action _)   = false
  114.   | nullable (Seq(r1,r2)) = nullable r1 andalso nullable r2
  115.   | nullable (Alt(r1,r2)) = nullable r1 orelse nullable r2
  116.   | nullable (Star r)     = true
  117. ;
  118.  
  119. fun firstpos Empty        = []
  120.   | firstpos (Chars pos)  = [OnChars pos]
  121.   | firstpos (Action act) = [ToAction act]
  122.   | firstpos (Seq(r1,r2)) =
  123.                   if nullable r1
  124.                   then merge_trans (firstpos r1) (firstpos r2)
  125.                   else firstpos r1
  126.   | firstpos (Alt(r1,r2)) = merge_trans (firstpos r1) (firstpos r2)
  127.   | firstpos (Star r)     = firstpos r
  128. ;
  129.  
  130. fun lastpos Empty        = []
  131.   | lastpos (Chars pos)  = [OnChars pos]
  132.   | lastpos (Action act) = [ToAction act]
  133.   | lastpos (Seq(r1,r2)) =
  134.                   if nullable r2
  135.                   then merge_trans (lastpos r1) (lastpos r2)
  136.                   else lastpos r2
  137.   | lastpos (Alt(r1,r2)) = merge_trans (lastpos r1) (lastpos r2)
  138.   | lastpos (Star r)     = lastpos r
  139. ;
  140.  
  141. fun followpos size name_regexp_list =
  142.   let open Array infix 9 sub
  143.       val v = array(size, [])
  144.       fun fill_pos first = fn
  145.               OnChars pos => update(v, pos, merge_trans first (v sub pos))
  146.             | ToAction _  => ()
  147.       fun fill (Seq(r1,r2)) =
  148.             (fill r1; fill r2;
  149.              List.app (fill_pos (firstpos r2)) (lastpos r1))
  150.         | fill (Alt(r1,r2)) =
  151.             (fill r1; fill r2)
  152.         | fill (Star r) =
  153.             (fill r;
  154.              List.app (fill_pos (firstpos r)) (lastpos r))
  155.         | fill _ = ()
  156.   in
  157.     List.app (fn (name, regexp) => fill regexp) name_regexp_list;
  158.     v
  159.   end
  160. ;
  161.  
  162. val no_action = 32767;
  163.  
  164. val split_trans_set =
  165.   foldL
  166.     (fn trans => fn (act_pos_set as (act, pos_set)) =>
  167.        case trans of
  168.            OnChars pos   => (act, pos :: pos_set)
  169.          | ToAction act1 => if act1 < act then (act1, pos_set)
  170.                                           else act_pos_set)
  171.     (no_action, [])
  172. ;
  173.  
  174. val memory  = (Hasht.new 131 : (transition list, int) Hasht.t);
  175. val todo    = ref ([] : (transition list * int) list);
  176. val next    = ref 0;
  177.  
  178. fun reset_state_mem () =
  179.   (Hasht.clear memory; todo := []; next := 0)
  180. ;
  181.  
  182. fun get_state st =
  183.   Hasht.find memory st
  184.   handle Subscript =>
  185.     let val nbr = !next in
  186.       incr next;
  187.       Hasht.insert memory st nbr;
  188.       todo := (st, nbr) :: !todo;
  189.       nbr
  190.     end
  191. ;
  192.  
  193. fun map_on_states f =
  194.   case !todo of
  195.       []  => []
  196.     | (st,i)::r =>
  197.         (todo := r; let val res = f st in (res,i) :: map_on_states f end)
  198. ;
  199.  
  200. fun number_of_states () =
  201.   !next
  202. ;
  203.  
  204. fun goto_state [] = Backtrack
  205.   | goto_state ps = Goto (get_state ps)
  206. ;
  207.  
  208. fun transition_from chars follow pos_set =
  209.   let open Array infix 9 sub
  210.       val tr = array(256, [])
  211.       val shift = array(256, Backtrack)
  212.   in
  213.     List.app (fn pos =>
  214.           List.app (fn c =>
  215.                  update(tr, Char.ord c,
  216.                    merge_trans (tr sub (Char.ord c)) (follow sub pos)))
  217.               (chars sub pos))
  218.         pos_set;
  219.     for (fn i => update(shift, i, goto_state (tr sub i)))
  220.         0 255;
  221.     shift
  222.   end
  223. ;
  224.  
  225. fun translate_state chars follow state =
  226.   case split_trans_set state of
  227.       (n, []) => Perform n
  228.     | (n, ps) => Shift( (if n = no_action then No_remember else Remember n),
  229.                         transition_from chars follow ps)
  230. ;
  231.  
  232. fun make_dfa lexdef =
  233.   let open Array infix 9 sub
  234.       val (chars, name_regexp_list, actions) =
  235.         encode_lexdef lexdef
  236.       val follow =
  237.         followpos (length chars) name_regexp_list
  238.       val () = reset_state_mem()
  239.       val initial_states =
  240.         caml_map
  241.             (fn (name, regexp) => (name, get_state(firstpos regexp)))
  242.             name_regexp_list
  243.       val states =
  244.         map_on_states (translate_state chars follow)
  245.       val v =
  246.         array(number_of_states(), Perform 0)
  247.   in
  248.     List.app (fn (auto, i) => update(v, i, auto)) states;
  249.     reset_state_mem();
  250.     (initial_states, v, actions)
  251.   end
  252. ;
  253.  
  254. end;
  255.