//
// Author: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
// Time: January, 2009
//

(*

M4 = (Q, Sigma, q0, delta, F)

Sigma = {a, b}

The start state is [s]

The transition function delta is

   |  a  b
------------------
s  | q1 q2
------------------
q1 | q1 q2
------------------
q2 | q1 q2
------------------
r1 | r2 r1
------------------
r2 | r2 r1
------------------

F = { q1, r1 }

*)

#define _s 0
#define _q1 1
#define _q2 2
#define _r1 3
#define _r2 4

typedef state_t = int
typedef letter_t = char

extern val start: state_t
extern fun delta (s: state_t, a: letter_t): state_t
extern fun isfinal (s: state_t): bool

implement start = _s
implement delta (s, a) = let
  fn err1 (a: letter_t): state_t = begin
    prerr "Illegal input letter: "; prerr a; prerr_newline (); exit (1)
  end // end of [err1]
in
  case+ s of
  | _s => begin case+ a of
    | 'a' => _q1 | 'b' => _r1 | _ => err1 (a)
    end // end of [_s]
  | _q1 => begin case+ a of
    | 'a' => _q1 | 'b' => _q2 | _ => err1 (a)
    end // end of [_q1]
  | _q2 => begin case+ a of
    | 'a' => _q1 | 'b' => _q2 | _ => err1 (a)
    end // end of [_q2]
  | _r1 => begin case+ a of
    | 'a' => _r2 | 'b' => _r1 | _ => err1 (a)
    end // end of [_r1]
  | _r2 => begin case+ a of
    | 'a' => _r2 | 'b' => _r1 | _ => err1 (a)
    end // end of [_r2]
  | _ => begin
      prerr "Illegal state s = "; prerr s; prerr_newline ();
      exit (1)
    end // end of [_]
end // end of [delta]

implement isfinal (s: state_t) = begin
  case+ s of _q1 => true | _r1 => true | _ => false
end // end of [isfinal]

(* ****** ****** *)

extern fun accept (s: string): bool

implement accept (str) = loop (str, start, 0) where {
  val str = string1_of_string (str)
  fun loop {n,i:nat | i <= n} .<n-i>.
    (str: string n, s: state_t, i: size_t i): bool =
    if string_is_atend (str, i) then isfinal (s) else let
      val a = str[i]; val s1 = delta (s, a) in loop (str, s1, i+1)
    end // end of [if]
  // end of [loop]
}

(* ****** ****** *)

implement main (argc, argv) = let
  val () = assert (argc >= 2)
  val str = argv.[1]
  val ans = accept (str)
in
  printf ("accept(%s) = ", @(str)); print ans; print_newline ()
end // end of [main]

(* ****** ****** *)

(* end of [DFA_example4.dats] *)