セマンティクス

(*****************************************)
(** SEMANTICS *)
(*****************************************)

Require Import List.
Section ListAssoc.
Variable A B:Set.
Variable A_beq : A -> A -> bool.
Fixpoint List_assoc (l:list (A*B))(a:A){struct l} :=
  match l with
  | List.nil => None
  | List.cons (l_hd_left,l_hd_right) l_tl =>
      if A_beq l_hd_left a then Some l_hd_right
      else List_assoc l_tl a
  end.
End ListAssoc.

Definition store:Type := list (VAR * DATA).

Fixpoint nat_beq (m n:nat) {struct m} : bool :=
  match m, n with
  | O, O => true
  | S m', S n' => nat_beq m' n'
  | _, _ => false
  end.
Definition VAR_beq (v1 v2:VAR) : bool :=
  match v1, v2 with
  | X_IN, X_IN => true
  | X_OUT, X_OUT => true
  | X m, X n => nat_beq m n
  | _, _ => false
  end.
Fixpoint DATA_beq (d1 d2:DATA){struct d1} : bool :=
  match d1, d2 with
  | DNIL, DNIL => true
  | DCONS hd1 tl1, DCONS hd2 tl2 =>
     match DATA_beq hd1 hd2, DATA_beq tl1 tl2 with
     | true, true => true
     | _, _ => false
     end
  | _, _ => false
  end.

(* var -> store -> option DATA *)
Definition eval_VAR (v:VAR) (s:store) :=
  List_assoc VAR DATA VAR_beq s v.
Definition try_DCONS (d_opt1 d_opt2:option DATA) :=
  match d_opt1, d_opt2 with
  | Some d1, Some d2 => Some (DCONS d1 d2)
  | _,_ => None
  end.

Fixpoint eval_DATA_EQ_aux (d1 d2:DATA) {struct d1} :=
  match d1, d2 with
  | DCONS hd1 tl1, DCONS hd2 tl2 =>
      match eval_DATA_EQ_aux hd1 hd2, eval_DATA_EQ_aux tl1 tl2 with
      | true, true => true
      | _,_ => false
      end
  | DCONS _ _, DNIL => false
  | DNIL, DCONS _ _ => false
  | DNIL, DNIL => true
  end.
(* DATA -> DATA -> option bool *)
Definition eval_DATA_EQ d_opt1 d_opt2 :=
  match d_opt1, d_opt2 with
  | Some d1, Some d2 => Some (eval_DATA_EQ_aux d1 d2)
  | _,_ => None
  end.

(* EXPRESSION -> store -> option DATA *)
Fixpoint eval_EXPR (e:EXPRESSION) :=
  (fun s:store =>
    match e with
    | V v => eval_VAR v s
    | D d => Some d
    | CONS E F => try_DCONS (eval_EXPR E s)(eval_EXPR F s)
    | LEFT E => match eval_EXPR E s with
              | Some (DCONS head _) => Some head
	      | Some _ => Some DNIL
	      | None => None
	      end
    | RIGHT E => match eval_EXPR E s with
              | Some (DCONS _ tail) => Some tail
	      | Some _ => Some DNIL
	      | None => None
	      end
    | ISEQ E F => match eval_DATA_EQ (eval_EXPR E s) (eval_EXPR F s) with
                  | Some true => Some (DCONS DNIL DNIL)
		  | Some false => Some DNIL
		  | None => None
		  end
    end).


Fixpoint do_1CMD (C:COMMAND)(s:store) : option (option COMMAND * store) :=
  match C with
  | ASSIGN v E => match eval_EXPR E s with
                  | Some d => Some (None, List.cons (v,d) s)
		  | None => None
		  end
  | SEMI C1 C2 => match do_1CMD C1 s with
                  | Some (Some C1', s') => Some (Some (SEMI C1' C2), s')
		  | Some (None, s') => Some (Some C2, s')
	          | None => None
		  end
  | WHILE E C' => match eval_EXPR E s with
               	  | Some DNIL => Some (None, s)
		  | Some _ => match do_1CMD C' s with
		    	      | Some (Some C'', s') =>
			           Some (Some (SEMI C'' (WHILE E C')), s')
                              | Some (None, s') =>
         		      	   Some (Some (WHILE E C'), s')
			      | None => None
			      end
	          | None => None
		  end
  end.

Fixpoint do_CMD (count:nat)(c:COMMAND)(s:store){struct count} : option store :=
  match count with
  | O => None
  | S count' => match do_1CMD c s with
      	     	| Some (Some c', s') => do_CMD count' c' s'
		| Some (None, s') => Some s'
		| None => None
  		end
  end.

Definition COUNT_MAX := 100.

Definition eval (p:PROGRAM)(input:DATA) : option DATA :=
  match p with
  | MAIN cmds =>
     match do_CMD COUNT_MAX cmds ((X_IN, input)::nil) with
     | Some s' =>
          eval_EXPR (!X_OUT) s'
     | None => None
     end
  end.

Definition eval_debug (p:PROGRAM)(input:DATA) : option (store * option DATA) :=
  match p with
  | MAIN cmds =>
     match do_CMD COUNT_MAX cmds ((X_IN, input)::nil) with
     | Some s =>
         Some (s, eval_EXPR (!X_OUT) s)
     | None => None
     end
  end.