let rec checkAexp (ex: aexp) (dect: dec_table) (proct: proc_table) :sType = match ex with
          N(_)          ->  DInt
        | R(_)          ->  DFloat
        | Var(i)        ->  let (_,_,t) = (getVarDeclaration i dect) in (getType t)
        | Vec(i,x)      ->  if ((checkAexp x dect proct) = DIntthen (
                                let (_,_,t) = (getVarDeclaration i dect) in (getType t)
                            ) else (
                                raise (SEMANTIC_ERROR "Invalid Index")
                            )
        | Mat(i,x,y)    ->  if (((checkAexp x dect proct) = DInt& ((checkAexp y dect proct) = DInt)) then (
                                let (_,_,t) = (getVarDeclaration i dect) in (getType t)
                            ) else (
                                raise (SEMANTIC_ERROR "Invalid Index")
                            )
        
        (** For now are only allowed arithmetical operations between int and int or float and float, not mixed operations*)

        | Sum(ex1,ex2)  ->  (
                             let t1 = (checkAexp ex1 dect proct) and
                             t2 = (checkAexp ex2 dect proct) in
                             match (t1,t2) with
                                (DIntDInt)        ->  DInt
                              | (DFloatDFloat)    ->  DFloat
                              | _                   ->  raise (SEMANTIC_ERROR "Different Types")
                            )
        | Sub(ex1,ex2)  ->  (
                             let t1 = (checkAexp ex1 dect proct) and
                             t2 = (checkAexp ex2 dect proct) in
                             match (t1,t2) with
                                (DIntDInt)        ->  DInt
                              | (DFloatDFloat)    ->  DFloat
                              | _                   ->  raise (SEMANTIC_ERROR "Different Types")
                            )
        | Mul(ex1,ex2)  ->  (
                             let t1 = (checkAexp ex1 dect proct) and
                             t2 = (checkAexp ex2 dect proct) in
                             match (t1,t2) with
                                (DIntDInt)        ->  DInt
                              | (DFloatDFloat)    ->  DFloat
                              | _                   ->  raise (SEMANTIC_ERROR "Different Types")
                            )
        | Div(ex1,ex2)  ->  (
                             let t1 = (checkAexp ex1 dect proct) and
                             t2 = (checkAexp ex2 dect proct) in
                             match (t1,t2) with
                                (DIntDInt)        ->  DInt
                              | (DFloatDFloat)    ->  DFloat
                              | _                   ->  raise (SEMANTIC_ERROR "Different Types")
                            )
        | FCall(i,el)   ->  (
                             let pten = (Hashtbl.find proct i) in match pten with
                                Building(t, plist)              ->  (
                                                                     if (checkParTypes (List.rev plist) (List.rev el) dect proct)
                                                                     then (
                                                                         match t with
                                                                             SRet(Int)   -> DInt
                                                                           | SRet(Float-> DFloat
                                                                           | Void        -> raise (SEMANTIC_ERROR "Void function")
                                                                     )
                                                                     else raise (SEMANTIC_ERROR "Different Parameters Types")
                                                                    )
                              | Subroutine(t,plist,_,_)   ->  (
                                                                     if (checkParTypes (List.rev plist) (List.rev el) dect proct)
                                                                     then (
                                                                         match t with
                                                                             SRet(Int)   -> DInt
                                                                           | SRet(Float-> DFloat
                                                                           | Void        -> raise (SEMANTIC_ERROR "Void function")
                                                                     )
                                                                     else raise (SEMANTIC_ERROR "Different Parameters Types")
                                                                    )
                            )
(** Checks the semantic type of a list of parameters @param plist The list of formal parameters @param el The list of actual parameters @param dect The declarations table @param proct The procedures table @return True if the formal parameters types match with the actual parameters type, False otherwise *)

and checkParTypes (plist: dec list) (el: aexp list) (dect: dec_table) (proct: proc_table) = match (plist,el) with
          ([],[])               ->  true
        | ([x],[])              ->  true
        | (Dec(id,Basic(t))::ps,e::es)  ->  (
                                     match t with
                                         Int    ->  ((checkAexp e dect proct) = DInt& checkParTypes ps es dect proct
                                       | Float  ->  ((checkAexp e dect proct) = DFloat& checkParTypes ps es dect proct
                                    )
        | _                     ->  raise (SEMANTIC_ERROR "Wrong Parameters Number")

(** Checks the semantic type of boolean operations (compare is only allowed betrween int and int or float and float, not mixed operations) @param b The boolean operation to check @param dect The declarations table @param proct The procedures table @return The sematic type of b *)

and checkBool (b: bexp) (dect: dec_table) (proct: proc_table) = match b with
          B(b)          ->  DBool
        | Equ(ex1,ex2)  ->  (
                             let t1 = (checkAexp ex1 dect proct) and
                             t2 = (checkAexp ex2 dect proct) in
                             match (t1,t2) with
                                (DIntDInt)        ->  DBool
                              | (DFloatDFloat)    ->  DBool
                              | _                   ->  raise (SEMANTIC_ERROR "Different Types")
                            )
        | LE(ex1,ex2)   ->  (
                             let t1 = (checkAexp ex1 dect proct) and
                             t2 = (checkAexp ex2 dect proct) in
                             match (t1,t2) with
                                (DIntDInt)        ->  DBool
                              | (DFloatDFloat)    ->  DBool
                              | _                   ->  raise (SEMANTIC_ERROR "Different Types")
                            )
        | LT(ex1,ex2)   ->  (
                             let t1 = (checkAexp ex1 dect proct) and
                             t2 = (checkAexp ex2 dect proct) in
                             match (t1,t2) with
                                (DIntDInt)        ->  DBool
                              | (DFloatDFloat)    ->  DBool
                              | _                   ->  raise (SEMANTIC_ERROR "Different Types")
                            )
        | Not(bx)       ->  if ((checkBool bx dect proct) = DBoolthen DBool else raise (SEMANTIC_ERROR "Different Types")
        | And(bx1,bx2)  ->  (
                             let t1 = (checkBool bx1 dect proct) and
                             t2 = (checkBool bx2 dect proct) in
                             match (t1,t2) with
                                (DBoolDBool)      ->  DBool
                              | _                   ->  raise (SEMANTIC_ERROR "Different Types")
                            )
        | Or(bx1,bx2)   ->  (
                             let t1 = (checkBool bx1 dect proct) and
                             t2 = (checkBool bx2 dect proct) in
                             match (t1,t2) with
                                (DBoolDBool)      ->  DBool
                              | _                   ->  raise (SEMANTIC_ERROR "Different Types")
                            )