diff --git a/src/parser/parser.mly b/src/parser/parser.mly
index 60950c414e0ed7a2d70fc63103208f7bb7092506..dcba8f8421c9d9537f8a22f4d1651fff56e1d083 100644
--- a/src/parser/parser.mly
+++ b/src/parser/parser.mly
@@ -30,6 +30,8 @@
   let mk_pp d = mk_ppl (loc ()) d
   let mk_pp_i i d = mk_ppl (loc_i i) d
 		    
+  let mk_pat p = { pat_loc = loc (); pat_desc = p }
+
   let infix_ppl loc a i b = mk_ppl loc (PPinfix (a, i, b))
   let infix_pp a i b = infix_ppl (loc ()) a i b
 
@@ -461,9 +463,16 @@ match_case:
 | pattern ARROW lexpr { ($1,$3) }
 ;
 
+list1_pat_sep_comma:
+| pattern                           { [$1] }
+| pattern COMMA list1_pat_sep_comma { $1::$3 }
+
 pattern:
-| uqualid                                         { ($1, [], loc ()) }
-| uqualid LEFTPAR list1_lident_sep_comma RIGHTPAR  { ($1, $3, loc ()) }
+| UNDERSCORE                                    { mk_pat (PPpwild) }
+| lident                                        { mk_pat (PPpvar $1) }
+| uqualid                                       { mk_pat (PPpapp ($1, [])) }
+| uqualid LEFTPAR list1_pat_sep_comma RIGHTPAR  { mk_pat (PPpapp ($1, $3)) }
+| pattern AS lident                             { mk_pat (PPpas ($1,$3)) }
 ;
 
 triggers:
diff --git a/src/parser/ptree.mli b/src/parser/ptree.mli
index 5155cb4bb0449ad9a7daf8841be8a5c93398c293..39e7856504cb073afc8c4f9734bf200df4d349a8 100644
--- a/src/parser/ptree.mli
+++ b/src/parser/ptree.mli
@@ -45,6 +45,15 @@ type pty =
   | PPTtyvar of ident
   | PPTtyapp of pty list * qualid
 
+type pattern =
+  { pat_loc : loc; pat_desc : pat_desc }
+
+and pat_desc =
+  | PPpwild
+  | PPpvar of ident
+  | PPpapp of qualid * pattern list
+  | PPpas of pattern * ident
+
 type uquant =
   ident list * pty
 
@@ -63,7 +72,7 @@ and pp_desc =
   | PPquant of pp_quant * uquant list * lexpr list list * lexpr
   | PPnamed of string * lexpr
   | PPlet of ident * lexpr * lexpr
-  | PPmatch of lexpr * ((qualid * ident list * loc) * lexpr) list
+  | PPmatch of lexpr * (pattern * lexpr) list
 
 (*s Declarations. *)
 
diff --git a/src/parser/typing.ml b/src/parser/typing.ml
index 2549baaea02c05a3094718dddb6db52065373fd9..90fffc38ddea0f297e8c5f83990cb36d983f0645 100644
--- a/src/parser/typing.ml
+++ b/src/parser/typing.ml
@@ -367,6 +367,14 @@ let rec ty_of_dty = function
 
 (** Typing terms and formulas *)
 
+type dpattern = { dp_node : dpattern_node; dp_ty : dty }
+
+and dpattern_node =
+  | Pwild
+  | Pvar of string
+  | Papp of lsymbol * dpattern list
+  | Pas of dpattern * string
+
 type uquant = string list * dty
 
 type dterm = { dt_node : dterm_node; dt_ty : dty }
@@ -376,7 +384,7 @@ and dterm_node =
   | Tconst of constant
   | Tapp of lsymbol * dterm list
   | Tlet of dterm * string * dterm
-(*   | Tcase of dterm * tbranch list *)
+  | Tmatch of dterm * (dpattern * dterm) list
   | Tnamed of string * dterm
   | Teps of string * dfmla
 
@@ -389,7 +397,7 @@ and dfmla =
   | Ffalse
   | Fif of dfmla * dfmla * dfmla
   | Flet of dterm * string * dfmla
-(*   | Fcase of dterm * (pattern * dfmla) list *)
+  | Fmatch of dterm * (dpattern * dfmla) list
   | Fnamed of string * dfmla
 
 and dtrigger =
@@ -402,6 +410,52 @@ let binop = function
   | PPimplies -> Fimplies
   | PPiff -> Fiff
 
+let rec dpat env pat =
+  let env, n, ty = dpat_node pat.pat_loc env pat.pat_desc in
+  env, { dp_node = n; dp_ty = ty }
+
+and dpat_node loc env = function
+  | PPpwild -> 
+      let tv = create_tvsymbol (id_user "a" loc) in
+      let ty = Tyvar (create_type_var ~loc ~user:false tv) in
+      env, Pwild, ty
+  | PPpvar {id=x} ->
+      if M.mem x env.dvars then assert false; (* FIXME? *)
+      let tv = create_tvsymbol (id_user "a" loc) in
+      let ty = Tyvar (create_type_var ~loc ~user:false tv) in
+      let env = { env with dvars = M.add x ty env.dvars } in
+      env, Pvar x, ty
+  | PPpapp (x, pl) ->
+      let s = find_lsymbol x env.th in
+      let s, tyl, ty = specialize_fsymbol ~loc s in
+      let env, pl = dpat_args s.ls_name loc env tyl pl in
+      env, Papp (s, pl), ty
+  | PPpas (p, {id=x}) ->
+      let env, p = dpat env p in
+      if M.mem x env.dvars then assert false; (* FIXME? *)
+      let env = { env with dvars = M.add x p.dp_ty env.dvars } in
+      env, Pas (p,x), p.dp_ty
+
+and dpat_args s loc env el pl = assert false (* TODO *)
+(*
+  let n = List.length el and m = List.length tl in
+  if n <> m then error ~loc (BadNumberOfArguments (s, m, n));
+  let rec check_arg = function
+    | [], [] -> 
+	[]
+    | a :: al, t :: bl ->
+	let loc = t.pp_loc in
+	let t = dterm env t in
+	if not (unify a t.dt_ty) then
+	  error ~loc (TermExpectedType ((fun f -> print_dty f t.dt_ty),
+					(fun f -> print_dty f a)));
+	t :: check_arg (al, bl)
+    | _ ->
+	assert false
+  in
+  check_arg (el, tl)
+*)
+
 let rec trigger_not_a_term_exn = function
   | Error (TermExpected | UnboundSymbol _) -> true
   | Loc.Located (_, exn) -> trigger_not_a_term_exn exn
@@ -438,8 +492,16 @@ and dterm_node loc env = function
       let env = { env with dvars = M.add x ty env.dvars } in
       let e2 = dterm env e2 in
       Tlet (e1, x, e2), e2.dt_ty
-  | PPmatch _ ->
-      assert false (* TODO *)
+  | PPmatch (e1, bl) ->
+      (* TODO: unify e1.type with patterns *)
+      (* TODO: unify branch types with each other *)
+      let branch (pat, e) =
+        let env, pat = dpat env pat in
+        pat, dterm env e
+      in
+      let bl = List.map branch bl in
+      let ty = (snd (List.hd bl)).dt_ty in
+      Tmatch (dterm env e1, bl), ty
   | PPnamed (x, e1) ->
       let e1 = dterm env e1 in
       Tnamed (x, e1), e1.dt_ty
@@ -492,8 +554,14 @@ and dfmla env e = match e.pp_desc with
       let env = { env with dvars = M.add x ty env.dvars } in
       let e2 = dfmla env e2 in
       Flet (e1, x, e2)
-  | PPmatch _ ->
-      assert false (* TODO *)
+  | PPmatch (e1, bl) ->
+      (* TODO: unify e1.type with patterns *)
+      (* TODO: unify branch types with each other *)
+      let branch (pat, e) =
+        let env, pat = dpat env pat in
+        pat, dfmla env e
+      in
+      Fmatch (dterm env e1, List.map branch bl)
   | PPnamed (x, f1) ->
       let f1 = dfmla env f1 in
       Fnamed (x, f1)
@@ -520,6 +588,23 @@ and dtype_args s loc env el tl =
   in
   check_arg (el, tl)
 
+let rec pattern env p = 
+  let ty = ty_of_dty p.dp_ty in
+  match p.dp_node with
+  | Pwild -> env, pat_wild ty
+  | Pvar x -> 
+      if M.mem x env then assert false; (* FIXME? *)
+      let v = create_vsymbol (id_fresh x) ty in
+      M.add x v env, pat_var v
+  | Papp (s, pl) -> 
+      let env, pl = map_fold_left pattern env pl in
+      env, pat_app s pl ty
+  | Pas (p, x) ->
+      if M.mem x env then assert false; (* FIXME? *)
+      let v = create_vsymbol (id_fresh x) ty in
+      let env, p = pattern (M.add x v env) p in
+      env, pat_as p v
+
 let rec term env t = match t.dt_node with
   | Tvar x ->
       assert (M.mem x env);
@@ -535,6 +620,14 @@ let rec term env t = match t.dt_node with
       let env = M.add x v env in
       let e2 = term env e2 in
       t_let v e1 e2
+  | Tmatch (e1, bl) ->
+      let branch (pat,e) =
+        let env, pat = pattern env pat in
+        (pat, term env e)
+      in
+      let bl = List.map branch bl in
+      let ty = (snd (List.hd bl)).t_ty in
+      t_case (term env e1) bl ty
   | Tnamed (x, e1) ->
       let e1 = term env e1 in
       t_label_add x e1
@@ -573,6 +666,12 @@ and fmla env = function
       let env = M.add x v env in
       let f2 = fmla env f2 in
       f_let v e1 f2
+  | Fmatch (e1, bl) ->
+      let branch (pat,e) =
+        let env, pat = pattern env pat in
+        (pat, fmla env e)
+      in
+      f_case (term env e1) (List.map branch bl)
   | Fnamed (x, f1) ->
       let f1 = fmla env f1 in
       f_label_add x f1