<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Thrift之代碼生成器Compiler原理及源碼詳細(xì)解析3

      我的新浪微博:http://weibo.com/freshairbrucewoo

      歡迎大家相互交流,共同提高技術(shù)。

       

      生成C++語(yǔ)言代碼的代碼詳解

       

      這個(gè)功能是由t_cpp_generator類實(shí)現(xiàn)(在文件t_cpp_generator.cc定義和實(shí)現(xiàn)),直接繼承至t_oop_generator類(這個(gè)類是所有面向?qū)ο笳Z(yǔ)言生成器類的直接基類,封裝了面向?qū)ο笳Z(yǔ)言生成器共有的特征與行為),而t_oop_generator又從t_generator繼承(上面已經(jīng)介紹),下面詳細(xì)分析這個(gè)類是怎樣生成C++語(yǔ)言的代碼文件的。這個(gè)還有從上面介紹的generate_program函數(shù)開(kāi)始說(shuō)起,因?yàn)檫@個(gè)函數(shù)才是控制整個(gè)代碼生成的總樞紐。

      首先執(zhí)行的是構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)做了一些最基本的初始化,一個(gè)是傳遞擁有生成代碼的符號(hào)資源的t_program對(duì)象到父類,第二個(gè)功能就是根據(jù)可選項(xiàng)參數(shù)初始化一些bool變量,以便后面根據(jù)這些bool變量做相應(yīng)的處理,代碼很簡(jiǎn)單就不列出來(lái)了,下面用一個(gè)表格說(shuō)明各個(gè)bool變量的作用(或功能)。

       

      gen_pure_enums_

      是否生成純凈的枚舉類型,而不是采用類包裝的形式

      gen_dense_

      是否應(yīng)該TDenseProtocol生成本地反射的元數(shù)據(jù)。

      gen_templates_

      是否要生成模板化的讀/寫方法

      use_include_prefix_

      是否應(yīng)該為了thrift生成的其他頭文件在#include中使用前綴路徑

      gen_cob_style_

      是否應(yīng)該生成繼承擴(kuò)展功能類(主要是異步)

      gen_no_client_completion_

      是否應(yīng)該省略客戶端類調(diào)用completion__()

       

      構(gòu)造函數(shù)只是做了最基本的初始化,更詳細(xì)的初始化是上面介紹的代碼生成器初始化函數(shù)init_generator,那我們看看C++代碼生成器是怎么詳細(xì)初始化的,都做了一些什么樣的工作和實(shí)現(xiàn)了一些什么的功能。我們分步驟介紹這一個(gè)函數(shù):

      第一步:制作代碼文件的輸出目錄:MKDIR(get_out_dir().c_str());MKDIR是一個(gè)宏函數(shù),調(diào)用了mkdir來(lái)創(chuàng)建目錄;

      第二部:創(chuàng)建代碼頭文件和實(shí)現(xiàn)文件,如果需要生成模板化的讀和寫的方法還會(huì)創(chuàng)建一個(gè)文件單獨(dú)實(shí)現(xiàn),代碼如下:

       1 string f_types_name = get_out_dir()+program_name_+"_types.h";
       2 
       3   f_types_.open(f_types_name.c_str());
       4 
       5   string f_types_impl_name = get_out_dir()+program_name_+"_types.cpp";
       6 
       7   f_types_impl_.open(f_types_impl_name.c_str());
       8 
       9   if (gen_templates_) {
      10 
      11     string f_types_tcc_name = get_out_dir()+program_name_+"_types.tcc";
      12 
      13     f_types_tcc_.open(f_types_tcc_name.c_str());
      14 
      15   }

       

      這里需要說(shuō)明幾個(gè)用于輸出流的成員變量,之所以定義成員變量是因?yàn)楹芏嗪瘮?shù)會(huì)用到,這樣就不用用參數(shù)來(lái)傳遞它們了,它們定義和說(shuō)明如下:

       1 std::ofstream f_types_;//專門用于類型聲明的輸出流,也就是頭文件(.h文件)
       2 
       3 std::ofstream f_types_impl_;//專門用于類型實(shí)現(xiàn)的輸出流,也就是實(shí)現(xiàn)文件(.cpp文件)
       4 
       5   std::ofstream f_types_tcc_;//專門用于模板化的讀和寫方法實(shí)現(xiàn)的輸出流
       6 
       7   std::ofstream f_header_;//專門用于服務(wù)聲明生成的輸出流
       8 
       9   std::ofstream f_service_;//專門用于服務(wù)實(shí)現(xiàn)生成的輸出流
      10 
      11   std::ofstream f_service_tcc_;//專門用于模板的服務(wù)的輸出流

       

      第三步:為每個(gè)文件打印頭部注釋,注釋的作用就是說(shuō)明這個(gè)文件是由Thrift自動(dòng)生成的,代碼如下:

      1 f_types_ << autogen_comment();
      2 
      3 f_types_impl_ << autogen_comment();
      4 
      5 f_types_tcc_ << autogen_comment();

       

      第四步:開(kāi)始ifndef

      第五步:包含各種頭文件

      第六步:打開(kāi)命名空間,生成的代碼都是在一個(gè)命令空間里面的。

      以上步驟的功能都比較簡(jiǎn)單,主要就是注意輸出格式和邏輯處理。通過(guò)這些功能基本內(nèi)容都做好了,下面就是真正開(kāi)始生成具體類型和服務(wù)的時(shí)候了,每一種數(shù)據(jù)類型都由一個(gè)單獨(dú)的函數(shù)來(lái)負(fù)責(zé)生成為代碼。

      1)枚舉類型生成函數(shù)generate_enum

      首先在頭文件中生成定義枚舉類型的代碼,具體的過(guò)程就是得到枚舉的所有常量值和枚舉類型的名稱,然后根據(jù)C++定義枚舉類型的語(yǔ)法輸出代碼到頭文件,輸出過(guò)程中根據(jù)是否需要用類來(lái)包裝而所有不同,同時(shí)生成的代碼也需要格式控制。具體實(shí)現(xiàn)如下:

       1 vector<t_enum_value*> constants = tenum->get_constants();
       2 
       3   std::string enum_name = tenum->get_name();
       4 
       5   if (!gen_pure_enums_) {
       6 
       7     enum_name = "type";
       8 
       9     f_types_ << indent() << "struct " << tenum->get_name() << " {" << endl;
      10 
      11     indent_up();
      12 
      13   }
      14 
      15   f_types_ << indent() << "enum " << enum_name;
      16 
      17   generate_enum_constant_list(f_types_, constants, "", "", true);
      18 
      19  if (!gen_pure_enums_) {
      20 
      21     indent_down();
      22 
      23     f_types_ << "};" << endl;
      24 
      25   }
      26 
      27   f_types_ << endl;

       

      接著在后面在實(shí)現(xiàn)文件中定義一個(gè)整型數(shù)組和一個(gè)字符的數(shù)組并用定義的枚舉類型的常量值來(lái)初始化這兩個(gè)數(shù)組,后然在說(shuō)這兩個(gè)數(shù)組的值初始化一個(gè)map,其實(shí)這么做的目的就是為了測(cè)試這個(gè)枚舉類型定義是否正確。

      最后調(diào)用函數(shù)generate_local_reflection決定是否為TDenseProtocol協(xié)議生成對(duì)應(yīng)類型的本地反射類型。這個(gè)函數(shù)功能比較復(fù)雜,后面單獨(dú)詳細(xì)講解。

      2)類型定義生成函數(shù)generate_typedef

      此函數(shù)功能簡(jiǎn)單,就是在頭文件中生成一個(gè)typedef的定義,就只有一句實(shí)現(xiàn):

      1 f_types_ <<  indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " 
      2 
      3 << ttypedef->get_symbolic() << ";" << endl << endl;

       

      3)常量類型生成函數(shù)generate_consts

      常量類型的實(shí)現(xiàn)是采用一個(gè)類來(lái)包裝所有的常量并且使用單獨(dú)的文件來(lái)實(shí)現(xiàn),所有首先創(chuàng)建常量類型定義頭文件和實(shí)現(xiàn)文件,代碼如下:

       1 string f_consts_name = get_out_dir()+program_name_+"_constants.h";
       2 
       3 ofstream f_consts;
       4 
       5 f_consts.open(f_consts_name.c_str());
       6 
       7 string f_consts_impl_name = get_out_dir()+program_name_+"_constants.cpp";
       8 
       9 ofstream f_consts_impl;
      10 
      11 f_consts_impl.open(f_consts_impl_name.c_str());

       

      接著按照就開(kāi)始按照類的定義格式在頭文件中生成定義類的代碼并在實(shí)現(xiàn)文件中定義這個(gè)類的常量類型;在這個(gè)類的構(gòu)造函數(shù)中給定義的數(shù)據(jù)類型賦值:

       1 f_consts_impl << "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
       2 
       3     endl << program_name_ << "Constants::" << program_name_ << "Constants() {" << endl;
       4 
       5 indent_up();
       6 
       7 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
       8 
       9     print_const_value(f_consts_impl, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value());
      10 
      11   }
      12 
      13 indent_down();
      14 
      15 indent(f_consts_impl) << "}" << endl;

       

      其中調(diào)用了print_const_value函數(shù)來(lái)根據(jù)數(shù)據(jù)類型來(lái)賦值,這些定義在類中的成員變量本身不是常量類型,只是在實(shí)現(xiàn)文件中定義了一個(gè)類的全局常量對(duì)象,在頭文件中聲明,以便其他地方可以被使用。

      4)異常類型生成函數(shù)generate_xception

      這個(gè)函數(shù)其實(shí)調(diào)用下面需要詳細(xì)分析的一個(gè)函數(shù)實(shí)現(xiàn)的,就是generate_struct函數(shù),因?yàn)楫惓R彩峭ㄟ^(guò)結(jié)構(gòu)體來(lái)定義和實(shí)現(xiàn)的。不過(guò)C++語(yǔ)言生成器中也自己實(shí)現(xiàn)了這個(gè)函數(shù),不過(guò)它是調(diào)用generate_cpp_struct函數(shù)實(shí)現(xiàn),C++generate_struct函數(shù)也是調(diào)用這個(gè)函數(shù)實(shí)現(xiàn),只是傳遞一個(gè)bool變量來(lái)區(qū)分是否是異常類型,具體的實(shí)現(xiàn)在分析generate_struct函數(shù)時(shí)一起詳細(xì)分析了,因?yàn)樗鼈兊幕緦?shí)現(xiàn)功能都是相同的。

      5)結(jié)構(gòu)體類型生成函數(shù)generate_struct

      上面已經(jīng)說(shuō)了這個(gè)函數(shù)也是調(diào)用generate_cpp_struct函數(shù)實(shí)現(xiàn),也就是說(shuō)異常類型和結(jié)構(gòu)體類型都是用同樣的流程實(shí)現(xiàn)的,它們都是定義為一個(gè)類,只是異常都從TException繼承,而一般的結(jié)構(gòu)體沒(méi)有。首先調(diào)用函數(shù)generate_struct_definition在頭文件中生成定義類的代碼,這個(gè)過(guò)程如下:

      第一步:得到所有的成員變量;

      第二步:根據(jù)是否有可選成員決定是否定義一個(gè)結(jié)構(gòu)體_XXX_isset,這個(gè)結(jié)果主要針對(duì)需要定義的類的可選成員而定義一些bool變量,來(lái)標(biāo)識(shí)這些可選成員變量是否存在。設(shè)計(jì)這個(gè)功能的目的是為了靈活控制數(shù)據(jù)傳輸?shù)慕Y(jié)構(gòu);

      第三步:開(kāi)始生成定義類(IDL文件中定義的structC++都是用class來(lái)實(shí)現(xiàn))的代碼,生成的代碼主要包括默認(rèn)的構(gòu)造函數(shù)、析構(gòu)函數(shù)、各個(gè)字段、比較函數(shù)(等于、不等于和小于)等;

      第四步:最后一步生成一個(gè)模板的讀和寫數(shù)據(jù)的函數(shù)的聲明,模板參數(shù)是協(xié)議類型,實(shí)現(xiàn)代碼如下:

       1 if (read) {//讀數(shù)據(jù)的模板函數(shù)
       2 
       3     if (gen_templates_) {
       4 
       5       out <<indent() << "template <class Protocol_>" << endl <<
       6 
       7         indent() << "uint32_t read(Protocol_* iprot);" << endl;
       8 
       9     } else {
      10 
      11       out << indent() << "uint32_t read(" << "::apache::thrift::protocol::TProtocol* iprot);" << endl;
      12 
      13     }
      14 
      15 }
      16 
      17 if (write) {//寫數(shù)據(jù)的模板函數(shù)
      18 
      19     if (gen_templates_) {
      20 
      21       out << indent() << "template <class Protocol_>" << endl <<
      22 
      23         indent() << "uint32_t write(Protocol_* oprot) const;" << endl;
      24 
      25     } else {
      26 
      27       out << indent() << "uint32_t write(" << "::apache::thrift::protocol::TProtocol* oprot) const;" << endl;
      28 
      29     }
      30 
      31 }

       

      然后調(diào)用函數(shù)generate_struct_fingerprint在實(shí)現(xiàn)文件中初始化兩個(gè)靜態(tài)變量,一個(gè)是字符串,一個(gè)是8位的整型數(shù)組,這兩個(gè)變量都是用來(lái)唯一的標(biāo)識(shí)一個(gè)類。這個(gè)歌標(biāo)識(shí)符的作用就是用于生成本地的反射類型,當(dāng)使用TDenseProtocol協(xié)議傳輸數(shù)據(jù)時(shí)會(huì)用到。

      接著兩次調(diào)用generate_local_reflection函數(shù)分別來(lái)聲明和定義用于類的本地反射的類型,調(diào)用generate_local_reflection_pointer函數(shù)來(lái)生成一個(gè)類的靜態(tài)指針的本地反射類型。

      最后分別調(diào)用函數(shù)generate_struct_reader和generate_struct_writer實(shí)現(xiàn)數(shù)據(jù)讀和寫函數(shù)。到此整個(gè)IDL定義的struct類型生成為C++的代碼就完成了。

      6)服務(wù)類型生成函數(shù)generate_service

      這個(gè)函數(shù)的功能是最復(fù)雜的,它會(huì)做很多的工作(分別調(diào)用其它函數(shù)來(lái)實(shí)現(xiàn)),也會(huì)生成單獨(dú)的頭文件和實(shí)現(xiàn)文件。生成頭文件的代碼如下:

      1 string f_header_name = get_out_dir()+svcname+".h";
      2 
      3   f_header_.open(f_header_name.c_str());

       

      下面就開(kāi)始在頭文件中生成一些包含頭文件的代碼。

      生成實(shí)現(xiàn)文件的代碼:

      1 string f_service_name = get_out_dir()+svcname+".cpp";
      2 
      3   f_service_.open(f_service_name.c_str());

       

      后面也是生成一些包含頭文件的代碼。接著就開(kāi)始生成正在的各種實(shí)現(xiàn)這個(gè)服務(wù)的代碼了,如下:

       1 generate_service_interface(tservice, "");//生成服務(wù)的接口類(在C++為抽象類)
       2 
       3   generate_service_null(tservice, "");//生成一個(gè)空實(shí)現(xiàn)服務(wù)接口類的類
       4 
       5   generate_service_helpers(tservice);//生成一些幫助類,如參數(shù)類、返回結(jié)果類等
       6 
       7   generate_service_client(tservice, "");//生成一個(gè)客戶類
       8 
       9   generate_service_processor(tservice, "");//生成處理數(shù)據(jù)的類(就是生成用于遠(yuǎn)程調(diào)用)
      10 
      11   generate_service_multiface(tservice);//生成一個(gè)實(shí)現(xiàn)多接口的單一的服務(wù)器類
      12 
      13   generate_service_skeleton(tservice);//生成一個(gè)服務(wù)器的框架文件

       

      如果gen_cob_style_為true,還會(huì)生成一些擴(kuò)展功能的類,代碼如下:

       1 if (gen_cob_style_) {
       2 
       3     generate_service_interface(tservice, "CobCl");
       4 
       5     generate_service_interface(tservice, "CobSv");
       6 
       7     generate_service_null(tservice, "CobSv");
       8 
       9     generate_service_client(tservice, "Cob");
      10 
      11     generate_service_processor(tservice, "Cob");
      12 
      13     generate_service_async_skeleton(tservice);
      14 
      15 }

       

      到此C++的代碼的生成全部結(jié)束,最后調(diào)用close_generator函數(shù)來(lái)完成收尾工作和清理一些資源,如果關(guān)閉文件。

      7)總結(jié)

      對(duì)于生成C++代碼這一塊內(nèi)容把基本的生成過(guò)程詳細(xì)分析了一遍,主要集中在整個(gè)流程中。但是很多功能還沒(méi)有詳細(xì)分析或還沒(méi)有涉及到,因?yàn)檎麄€(gè)代碼有4千多行,要完全詳細(xì)用文字分析下來(lái)工作量很多(代碼肯定都看了一遍),而且也覺(jué)得沒(méi)有必要,因?yàn)楹芏喙δ軐?shí)現(xiàn)都挺簡(jiǎn)單,只要一看代碼便能夠理解。

      上面分析過(guò)程沒(méi)有提到的功能主要包括:數(shù)據(jù)的序列化和反序列化、具體生成服務(wù)需要的每一個(gè)類等等。其實(shí)整個(gè)代碼并沒(méi)有什么難點(diǎn),主要是必須要思考周全,還有就是注意生成C++代碼的合理性。下面把這個(gè)C++代碼生成過(guò)程函數(shù)的調(diào)用層次用圖形表示如下:

       

      本來(lái)打算繼續(xù)詳細(xì)分析JavaPython的代碼生成的代碼,但是我閱讀了這部分代碼,發(fā)現(xiàn)和C++基本相同,只是由于各種語(yǔ)言語(yǔ)法不相同而在生成代碼的時(shí)候處理不同,但是處理方法和流程都是一樣的,所以就不詳細(xì)分析了,可以參照C++的生成代碼對(duì)照分析。

      posted @ 2012-04-25 23:06  薔薇理想人生  閱讀(4287)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 久久三级国内外久久三级| 永靖县| 成人午夜av在线播放| 亚洲综合国产一区二区三区| 亚洲码和欧洲码一二三四| 国产精品天干天干综合网| 在线观看特色大片免费视频| 国产精品免费AⅤ片在线观看| 精品免费看国产一区二区| 亚洲国产av无码精品无广告 | 亚洲伊人精品久视频国产| 久久久久综合一本久道| 波多野结衣网站| 97成人碰碰久久人人超级碰oo| 婷婷久久香蕉五月综合加勒比 | 老少配老妇老熟女中文普通话 | 亚洲国产美女精品久久久| 国产精品三级中文字幕| 亚洲第一极品精品无码久久| 黄网站色视频免费观看| 99在线精品视频观看免费| 奇米影视7777狠狠狠狠色 | 西西人体44www大胆无码| 亚洲精品中文字幕在线观| 777奇米四色成人影视色区| 午夜DY888国产精品影院| 久久综合激情网| 国产在线观看黄| 亚洲嫩模一区二区三区| 亚洲男女羞羞无遮挡久久丫| 撕开奶罩揉吮奶头高潮av| 中国xxx农村性视频| 亚洲精品自拍视频在线看| 精品亚洲没码中文字幕| 中文字幕日韩人妻一区| 视频一区二区三区刚刚碰| 在线观看亚洲欧美日本| 国产精品国产精品国产专区不卡| 东方市| 欧美变态另类牲交| 久久综合亚洲鲁鲁九月天|