{-
CP_cff (t' f (t x) {\overline{d}; \overline{b} }) = T' F (T X) {\overline{D'}; sw = entry; ign = go() ; return res; }
   where T' = t'   F = f    T = t    X = x
         \overline{D} = CD_cff \overline{d}
         (kenv, l_entry) = B_ssa \overline{b}
         S = CB_cff \overline{b} kenv
         D = void => void go() => { S } 
         \overline{D'} = \overline{D}; D; T res; int sw; void ign;
-}
ssa2cff :: (AST.CFunctionDef N.NodeInfo) -> SSA -> CFF 
ssa2cff fundef ssa@(SSA scopedDecls labelledBlocks sdom local_decl_vars fargs) = 
  let -- scraping the information from the top level function under obfuscation
      funName        = case getFunName fundef of { Just s -> s ; Nothing -> "unanmed" }
      formalArgDecls :: [AST.CDeclaration N.NodeInfo]
      formalArgDecls = getFormalArgs fundef
      formalArgIds :: [Ident]
      formalArgIds   = concatMap (\declaration -> getFormalArgIds declaration) formalArgDecls
      (returnTy,ptrArrs) = getFunReturnTy fundef
      isReturnVoid       = isVoidDeclSpec returnTy
      ctxtStructName     = funName ++ "Ctxt"
      
      -- the context struct declaration
      context         = mkContext ctxtStructName labelledBlocks formalArgDecls scopedDecls returnTy ptrArrs local_decl_vars fargs
      ctxtName        = map toLower ctxtStructName -- alias name is inlower case and will be used in the the rest of the code
      
      sw        = iid swParamName
      
      cases = cff_trans_blks isReturnVoid local_decl_vars fargs ctxtName (iid funName) labelledBlocks (M.toList labelledBlocks)
      main_decls = 
        -- 1. malloc the context obj in the main func
        -- ctxtTy * ctxt = (ctxtTy *) malloc(sizeof(ctxtTy));
        [ AST.CBlockDecl (AST.CDecl 
                          [AST.CTypeSpec (AST.CTypeDef (iid ctxtName) N.undefNode)] 
                          [(Just (AST.CDeclr (Just (iid ctxtParamName)) [AST.CPtrDeclr [] N.undefNode] Nothing [] N.undefNode),
                            Just (AST.CInitExpr 
                                  (AST.CCast (AST.CDecl [AST.CTypeSpec (AST.CTypeDef (iid ctxtName) N.undefNode)] 
                                              [(Just (AST.CDeclr Nothing [AST.CPtrDeclr [] N.undefNode] Nothing [] N.undefNode),Nothing,Nothing)] N.undefNode) 
                                   (AST.CCall (AST.CVar (iid "malloc") N.undefNode) 
                                    [AST.CSizeofType (AST.CDecl [AST.CTypeSpec (AST.CTypeDef (iid ctxtName) N.undefNode)] [] N.undefNode) N.undefNode] N.undefNode) N.undefNode) N.undefNode),Nothing)] N.undefNode)
        , AST.CBlockDecl (AST.CDecl
                          [AST.CTypeSpec intTy]
                          [(Just (AST.CDeclr (Just sw) [] Nothing [] N.undefNode), Just (AST.CInitExpr (AST.CConst (AST.CIntConst (cInteger 0) N.undefNode)) N.undefNode), Nothing)] N.undefNode)
        ] 
        
      main_stmts = 
        -- 2. initialize the counter-part  in the context of the formal args
        -- forall arg. ctxt->arg_label0 = arg 
        [ AST.CBlockStmt (AST.CExpr (Just (((cvar (iid ctxtParamName)) .->. (arg `app` (iid $ labPref ++ "0" ))) .=. (AST.CVar arg N.undefNode))) N.undefNode) | arg <- formalArgIds] ++ 
        -- 3. initialize the collection which are the local vars, e.g. a locally declared array
        --  int a[3];
        -- will be reinitialized as ctxt->a_0 = (int *)malloc(sizeof(int)*3);
        [ AST.CBlockStmt (AST.CExpr (Just (((cvar (iid ctxtParamName)) .->. (var `app` (iid $ labPref ++ "0" ))) .=. rhs)) N.undefNode) 
        | scopedDecl <- scopedDecls
        , isJust (containerDeclToInit scopedDecl)
        , let (Just (var,rhs)) = containerDeclToInit $ dropStorageQual $ dropConstTyQual scopedDecl ] ++ 
        
        -- 4. initialize the sw = 0;
        -- [ AST.CBlockStmt (AST.CExpr (Just ((cvar sw) .=. (AST.CConst (AST.CIntConst (cInteger 0) N.undefNode)))) N.undefNode) ] ++ 
        -- 5. constructing the while (1) { switch sw of { ... } }
        [ cWhile (AST.CConst (AST.CIntConst (cInteger 1) N.undefNode)) [cSwitch (cvar sw) cases] ]       
        
      main_func = case fundef of 
        { AST.CFunDef tySpecfs declarator decls _ nodeInfo -> 
             AST.CFunDef tySpecfs declarator decls (AST.CCompound [] (main_decls ++ main_stmts) N.undefNode) nodeInfo 
        }
                  
      -- io = unsafePerformIO $ print scopedDecls
  in CFF main_decls main_stmts context main_func
ssa2cff :: (AST.CFunctionDef N.NodeInfo) -> SSA -> CFF
ssa2cff fundef ssa@(SSA scopedDecls labelledBlocks sdom local_decl_vars fargs) = 
  let -- scraping the information from the top level function under obfuscation
      funName        = case getFunName fundef of { Just s -> s ; Nothing -> "unanmed" }
      formalArgDecls :: [AST.CDeclaration N.NodeInfo]
      formalArgDecls = getFormalArgs fundef
      formalArgIds :: [Ident]
      formalArgIds   = concatMap (\declaration -> getFormalArgIds declaration) formalArgDecls
      (returnTy,ptrArrs) = getFunReturnTy fundef
      isReturnVoid       = isVoidDeclSpec returnTy
      ctxtStructName     = funName ++ "Ctxt"
      
      -- the context struct declaration
      context         = mkContext ctxtStructName labelledBlocks formalArgDecls scopedDecls returnTy ptrArrs local_decl_vars fargs
      ctxtName        = map toLower ctxtStructName -- alias name is inlower case and will be used in the the rest of the code
      
      sw        = iid swParamName
      
      cases = cff_trans_blks isReturnVoid local_decl_vars fargs ctxtName (iid funName) labelledBlocks (M.toList labelledBlocks)
      main_decls = 
        -- 1. malloc the context obj in the main func
        -- ctxtTy * ctxt = (ctxtTy *) malloc(sizeof(ctxtTy));
        [ AST.CBlockDecl (AST.CDecl 
                          [AST.CTypeSpec (AST.CTypeDef (iid ctxtName) N.undefNode)] 
                          [(Just (AST.CDeclr (Just (iid ctxtParamName)) [AST.CPtrDeclr [] N.undefNode] Nothing [] N.undefNode),
                            Just (AST.CInitExpr 
                                  (AST.CCast (AST.CDecl [AST.CTypeSpec (AST.CTypeDef (iid ctxtName) N.undefNode)] 
                                              [(Just (AST.CDeclr Nothing [AST.CPtrDeclr [] N.undefNode] Nothing [] N.undefNode),Nothing,Nothing)] N.undefNode) 
                                   (AST.CCall (AST.CVar (iid "malloc") N.undefNode) 
                                    [AST.CSizeofType (AST.CDecl [AST.CTypeSpec (AST.CTypeDef (iid ctxtName) N.undefNode)] [] N.undefNode) N.undefNode] N.undefNode) N.undefNode) N.undefNode),Nothing)] N.undefNode)
        , AST.CBlockDecl (AST.CDecl
                          [AST.CTypeSpec intTy]
                          [(Just (AST.CDeclr (Just sw) [] Nothing [] N.undefNode), Just (AST.CInitExpr (AST.CConst (AST.CIntConst (cInteger 0) N.undefNode)) N.undefNode), Nothing)] N.undefNode)
        ] 
        
      main_stmts = 
        -- 2. initialize the counter-part  in the context of the formal args
        -- forall arg. ctxt->arg_label0 = arg 
        [ AST.CBlockStmt (AST.CExpr (Just (((cvar (iid ctxtParamName)) .->. (arg `app` (iid $ labPref ++ "0" ))) .=. (AST.CVar arg N.undefNode))) N.undefNode) | arg <- formalArgIds] ++ 
        -- 3. initialize the collection which are the local vars, e.g. a locally declared array
        --  int a[3];
        -- will be reinitialized as ctxt->a_0 = (int *)malloc(sizeof(int)*3);
        [ AST.CBlockStmt (AST.CExpr (Just (((cvar (iid ctxtParamName)) .->. (var `app` (iid $ labPref ++ "0" ))) .=. rhs)) N.undefNode) 
        | scopedDecl <- scopedDecls
        , isJust (containerDeclToInit scopedDecl)
        , let (Just (var,rhs)) = containerDeclToInit $ dropStorageQual $ dropConstTyQual scopedDecl ] ++ 
        
        -- 4. initialize the sw = 0;
        -- [ AST.CBlockStmt (AST.CExpr (Just ((cvar sw) .=. (AST.CConst (AST.CIntConst (cInteger 0) N.undefNode)))) N.undefNode) ] ++ 
        -- 5. constructing the while (1) { switch sw of { ... } }
        [ cWhile (AST.CConst (AST.CIntConst (cInteger 1) N.undefNode)) [cSwitch (cvar sw) cases] ]       
        
      main_func = case fundef of 
        { AST.CFunDef tySpecfs declarator decls _ nodeInfo -> 
             AST.CFunDef tySpecfs declarator decls (AST.CCompound [] (main_decls ++ main_stmts) N.undefNode) nodeInfo 
        }
                  
      -- io = unsafePerformIO $ print scopedDecls
  in CFF main_decls main_stmts context main_func
ssa2cff fundef ssa@(SSA scopedDecls labelledBlocks sdom local_decl_vars fargs) = 
  let -- scraping the information from the top level function under obfuscation
      funName        = case getFunName fundef of { Just s -> s ; Nothing -> "unanmed" }
      formalArgDecls :: [AST.CDeclaration N.NodeInfo]
      formalArgDecls = getFormalArgs fundef
      formalArgIds :: [Ident]
      formalArgIds   = concatMap (\declaration -> getFormalArgIds declaration) formalArgDecls
      (returnTy,ptrArrs) = getFunReturnTy fundef
      isReturnVoid       = isVoidDeclSpec returnTy
      ctxtStructName     = funName ++ "Ctxt"
      
      -- the context struct declaration
      context         = mkContext ctxtStructName labelledBlocks formalArgDecls scopedDecls returnTy ptrArrs local_decl_vars fargs
      ctxtName        = map toLower ctxtStructName -- alias name is inlower case and will be used in the the rest of the code
      
      sw        = iid swParamName
      
      cases = cff_trans_blks isReturnVoid local_decl_vars fargs ctxtName (iid funName) labelledBlocks (M.toList labelledBlocks)
      main_decls = 
        -- 1. malloc the context obj in the main func
        -- ctxtTy * ctxt = (ctxtTy *) malloc(sizeof(ctxtTy));
        [ AST.CBlockDecl (AST.CDecl 
                          [AST.CTypeSpec (AST.CTypeDef (iid ctxtName) N.undefNode)] 
                          [(Just (AST.CDeclr (Just (iid ctxtParamName)) [AST.CPtrDeclr [] N.undefNode] Nothing [] N.undefNode),
                            Just (AST.CInitExpr 
                                  (AST.CCast (AST.CDecl [AST.CTypeSpec (AST.CTypeDef (iid ctxtName) N.undefNode)] 
                                              [(Just (AST.CDeclr Nothing [AST.CPtrDeclr [] N.undefNode] Nothing [] N.undefNode),Nothing,Nothing)] N.undefNode) 
                                   (AST.CCall (AST.CVar (iid "malloc") N.undefNode) 
                                    [AST.CSizeofType (AST.CDecl [AST.CTypeSpec (AST.CTypeDef (iid ctxtName) N.undefNode)] [] N.undefNode) N.undefNode] N.undefNode) N.undefNode) N.undefNode),Nothing)] N.undefNode)
        , AST.CBlockDecl (AST.CDecl
                          [AST.CTypeSpec intTy]
                          [(Just (AST.CDeclr (Just sw) [] Nothing [] N.undefNode), Just (AST.CInitExpr (AST.CConst (AST.CIntConst (cInteger 0) N.undefNode)) N.undefNode), Nothing)] N.undefNode)
        ] 
        
      main_stmts = 
        -- 2. initialize the counter-part  in the context of the formal args
        -- forall arg. ctxt->arg_label0 = arg 
        [ AST.CBlockStmt (AST.CExpr (Just (((cvar (iid ctxtParamName)) .->. (arg `app` (iid $ labPref ++ "0" ))) .=. (AST.CVar arg N.undefNode))) N.undefNode) | arg <- formalArgIds] ++ 
        -- 3. initialize the collection which are the local vars, e.g. a locally declared array
        --  int a[3];
        -- will be reinitialized as ctxt->a_0 = (int *)malloc(sizeof(int)*3);
        [ AST.CBlockStmt (AST.CExpr (Just (((cvar (iid ctxtParamName)) .->. (var `app` (iid $ labPref ++ "0" ))) .=. rhs)) N.undefNode) 
        | scopedDecl <- scopedDecls
        , isJust (containerDeclToInit scopedDecl)
        , let (Just (var,rhs)) = containerDeclToInit $ dropStorageQual $ dropConstTyQual scopedDecl ] ++ 
        
        -- 4. initialize the sw = 0;
        -- [ AST.CBlockStmt (AST.CExpr (Just ((cvar sw) .=. (AST.CConst (AST.CIntConst (cInteger 0) N.undefNode)))) N.undefNode) ] ++ 
        -- 5. constructing the while (1) { switch sw of { ... } }
        [ cWhile (AST.CConst (AST.CIntConst (cInteger 1) N.undefNode)) [cSwitch (cvar sw) cases] ]       
        
      main_func = case fundef of 
        { AST.CFunDef tySpecfs declarator decls _ nodeInfo -> 
             AST.CFunDef tySpecfs declarator decls (AST.CCompound [] (main_decls ++ main_stmts) N.undefNode) nodeInfo 
        }
                  
      -- io = unsafePerformIO $ print scopedDecls
  in CFF main_decls main_stmts context main_func