let rec translate_field e1 id typ =
  match e1.expr_t with
    CTTexpPtrDeref(e2) ->
      CTTMlvPtr(translate e2), [id, typ]
  | CTTexpVar(id2) ->
      CTTMlvVar(id2, e1.expr_type), [id, typ]
  | CTTexpInvoke(e2, args) ->
      CTTMlvInvoke(translate_invoke_lhs e2, List.map translate args, e1.expr_type), [id, typ]
  | CTTexpField(e2, id2) ->
      let l, r = translate_field e2 id2 e1.expr_type in
      l, (r @ [id, typ])
  | _ -> failwith "invalid LHS for . operator"

and translate (e : expr) : mexpr = 
  let body : mexpr_desc = match e.expr_t with
    CTTexpComma(e1,e2) -> CTTMexpComma(translate e1, translate e2)
  | CTTexpConditional(e1,e2,e3) -> CTTMexpConditional(translate e1, translate e2, translate e3)
  | CTTexpBinExpr(binop,e1,e2) -> CTTMexpBinExpr(binop, translate e1, translate e2)
  | CTTexpCoerce(t,e1) -> CTTMexpCoerce(t, translate e1)
  | CTTexpUnaryExpr(u,e1) -> CTTMexpUnaryExpr(u, translate e1)
  | CTTexpInvoke(e1,args) -> CTTMexpInvoke(translate_invoke_lhs e1, List.map translate args)
  | CTTexpConstant(c) -> CTTMexpConstant(c)
        
  | CTTexpAddress(e) -> translate_address e
  | CTTexpPtrDeref(e) -> CTTMexpRead(CTTMlvPtr (translate e),[])
  | CTTexpAssign(e1,e2) -> translate_assign e1 (translate e2) None
  | CTTexpBinAssign(binop,e1,tcast,e2) -> translate_assign e1 (translate e2) (Some (binop, tcast))
  | CTTexpField(e1,id) -> 
      let l,r = translate_field e1 id e.expr_type in
      CTTMexpRead(l,r)
  | CTTexpVar(id) -> begin
      match e.expr_type.ct_ty with
        Tarray(_) ->
          CTTMexpAddress(CTTMlvVar(id, e.expr_type), [])
      | _ ->
          CTTMexpRead(CTTMlvVar(id, e.expr_type), [])
  end
  in
  { mexpr_type = e.expr_type; mexpr_t = body }
    
and translate_address e =
  match e.expr_t with
    CTTexpPtrDeref(e) -> (translate e).mexpr_t
  | CTTexpVar(id) -> CTTMexpAddress(CTTMlvVar(id, e.expr_type), [])
  | CTTexpField(e1,id) ->
      let l, r = translate_field e1 id e1.expr_type in
      CTTMexpAddress(l,r)
  | _ -> raise (TypeError_typed(e,"not an lvalue"))

and translate_invoke_lhs e1 =
  match e1.expr_t with
    CTTexpPtrDeref(e) -> CTTMlvPtr(translate e)
  | CTTexpVar(id) -> CTTMlvVar(id, e1.expr_type)
  | CTTexpField _ -> assert false
  | _ -> assert false

and translate_assign e1 rhs binop =
  match e1.expr_t with
    CTTexpPtrDeref(e) -> CTTMexpWrite(CTTMlvPtr(translate e), [], binop, rhs)
  | CTTexpVar(id) -> CTTMexpWrite(CTTMlvVar(id, e1.expr_type), [], binop, rhs)
  | CTTexpField(e1,id) ->
      let l, r = translate_field e1 id e1.expr_type in
      CTTMexpWrite(l,r, binop, rhs)
  | _ -> raise (TypeError_typed(e1,"not an lvalue"))