小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

 碼農(nóng)書館 2019-04-10

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

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

2  t_generator類和t_generator_registry類

這個兩個類的主要功能就是為生成所有語言的代碼提供基礎(chǔ)信息和提供具體代碼生成器對象,上面就是調(diào)用這個兩個類的方法來生成具體語言的代碼生成器對象和執(zhí)行生成代碼的功能函數(shù)。下面主要分析兩個函數(shù)的功能,一個是t_generator_registry類的get_generator函數(shù),這個是一個靜態(tài)的函數(shù)可以直接通過類調(diào)用;另一個是t_generator類的generate_program函數(shù)。

1t_generator_registry類的get_generator函數(shù)

這個函數(shù)有兩個參數(shù),一個是表示程序的對象program,另一個是語言字符串參數(shù)(包括代表語言的簡短字符串和可選項的組合,有的沒有)。函數(shù)首先解析語言字符串參數(shù),參數(shù)字符串中是這樣組織的:在冒號(:)之前是代表語言的字符串,冒號之后是可選項的參數(shù),每一個可選項參數(shù)用逗號(,)分割,每一個可選項參數(shù)都是鍵值對并且鍵和值是用等號(=)分割。按照上面的字符串格式解析各個參數(shù)部分就可以了,可選項參數(shù)用map來保存鍵值對,代碼實現(xiàn)如下:

復(fù)制代碼
 1 string::size_type colon = options.find(':');
 2 
 3   string language = options.substr(0, colon);
 4 
 5   map<string, string> parsed_options;
 6 
 7   if (colon != string::npos) {
 8 
 9     string::size_type pos = colon+1;
10 
11     while (pos != string::npos && pos < options.size()) {
12 
13       string::size_type next_pos = options.find(',', pos);
14 
15       string option = options.substr(pos, next_pos-pos);
16 
17       pos = ((next_pos == string::npos) ? next_pos : next_pos+1);
18 
19       string::size_type separator = option.find('=');
20 
21       string key, value;
22 
23       if (separator == string::npos) {
24 
25         key = option;
26 
27        value = "";
28 
29       } else {
30 
31         key = option.substr(0, separator);
32 
33         value = option.substr(separator+1);
34 
35      }
36 
37       parsed_options[key] = value;
38 
39     }
40 
41   }
復(fù)制代碼

 

然后調(diào)用get_generator_map函數(shù)得到一個代表語言字符串和產(chǎn)生這種語言生成器對象的工廠對象的map對象:gen_map_t& the_map = get_generator_map(); gen_map_t的定義如下:

1 typedef std::map<std::string, t_generator_factory*> gen_map_t;

 

get_generator_map函數(shù)只有兩句代碼,一個是定義一個靜態(tài)局部變量并初始化(因為靜態(tài)局部變量必須并初始化并且只有第一次會執(zhí)行初始化,因為不初始化鏈接程序的時候會報錯),第二句就是返回這個靜態(tài)局部變量給調(diào)用者,代碼如下:

1 static gen_map_t* the_map = new gen_map_t();
2 
3   return *the_map;

 

然后在這個map對象中找到對應(yīng)語言的工廠對象,然后用這個工廠對象生產(chǎn)一個這種語言的代碼生成器對象并返回給調(diào)用者,代碼如下所示:

1    gen_map_t::iterator iter = the_map.find(language);
2 
3   return iter->second->get_generator(program, parsed_options, options);

 

本函數(shù)的功能已經(jīng)分析完畢,但是還存在著兩個問題(或是困難)。一個是最后一條返回一句是根據(jù)具體的語言來使用具體語言生產(chǎn)器的工廠對象生產(chǎn)代碼生成器,具體又是怎么生成的了?第二個就是從main函數(shù)執(zhí)行到現(xiàn)在還沒有發(fā)現(xiàn)在哪兒為get_generator_map函數(shù)里定義的靜態(tài)局部變量添加過任何鍵值對,那么我們查找具體語言必定會失敗,那么會返回一個NULL給調(diào)用者,那么程序就會執(zhí)行不下去了,但是程序確實能夠完完整整的執(zhí)行下去,這個問題困擾了我好一會兒。下面就這兩個問題繼續(xù)分析相關(guān)代碼并且解決問題。

第一個應(yīng)該不算是問題,但是必須要解決第二個問題以后才能夠解釋,因為沒有解決第二個問題,那么根本就不會執(zhí)行到最后一條返回語句這兒來,所以我先解決第二個問題。

第二個問題分析和解決思路如下:

我們通常認(rèn)為main函數(shù)是程序的入口函數(shù),那么所以程序的執(zhí)行都是從main函數(shù)開始的,所以我也選擇從main函數(shù)開始分析這部分的代碼,根據(jù)程序的執(zhí)行流程閱讀和分析代碼是我一貫的思路。但是這種情況在C++里面有例外,記得我在學(xué)習(xí)MFC的時候,分析MFC執(zhí)行過程就發(fā)現(xiàn)一個問題,那就是全局變量的初始化是在main函數(shù)開始之前的,也就是說全局類對象的構(gòu)造函數(shù)也是在main執(zhí)行之前執(zhí)行的。由于我反復(fù)從main開始一直詳細(xì)的閱讀每一行代碼,所以可以確定確實沒有在執(zhí)行的過程中初始化the_map靜態(tài)局部變量,所以唯一的可能就是在main函數(shù)開始之前已經(jīng)初始化好了。根據(jù)這一點思路自己開始著手查找初始化the_map的代碼,發(fā)現(xiàn)t_generator_registry類的register_generator函數(shù)為the_map添加鍵值對了,這個函數(shù)定義如下:

復(fù)制代碼
 1 void t_generator_registry::register_generator(t_generator_factory* factory) {
 2 
 3   gen_map_t& the_map = get_generator_map();
 4 
 5   if (the_map.find(factory->get_short_name()) != the_map.end()) {
 6 
 7     failure("Duplicate generators for language \"%s\"!\n", factory->get_short_name().c_str());
 8 
 9   }
10 
11   the_map[factory->get_short_name()] = factory;
12 
13 }
復(fù)制代碼

 

這個函數(shù)也首先調(diào)用get_generator_map函數(shù)得到那個靜態(tài)局部變量,然后查找要注冊的工程是否已經(jīng)在the_map中存在,如果存在就提示失敗信息,否則就把工廠的名字和工廠對象作為鍵值對添加到the_map中。

雖然找到了為the_map添加鍵值對的地方,但是還沒有找到調(diào)用這個注冊工廠函數(shù)的地方,所以繼續(xù)在代碼中搜索調(diào)用這個函數(shù)的地方。整個代碼就只有一處調(diào)用了這個函數(shù),而且是在一個類的構(gòu)造函數(shù)中,代碼如下:

復(fù)制代碼
 1 t_generator_factory::t_generator_factory(const std::string& short_name, const std::string& long_name,
 2 
 3     const std::string& documentation) : short_name_(short_name)
 4 
 5   , long_name_(long_name) , documentation_(documentation)
 6 
 7 {
 8 
 9   t_generator_registry::register_generator(this);
10 
11 }
復(fù)制代碼

 

t_generator_factory類是所有生產(chǎn)代碼生產(chǎn)器對象工廠的基類,每一種具體的語言都有自己的代碼生成器類和生產(chǎn)這種類的工廠類,上面的代碼是它的構(gòu)造函數(shù),功能就是把自己注冊到the_map中??吹竭@里是否有一種逐漸清晰的感覺,但是總是感覺還有少點什么,就是這個構(gòu)造函數(shù)被調(diào)用也必須有這個類的對象被定義或其子類的對象被定義。于是我又開始搜索哪些類是從這個類繼承的,發(fā)現(xiàn)兩處很重要的代碼,一處如下:

復(fù)制代碼
 1 template <typename generator>
 2 
 3 class t_generator_factory_impl : public t_generator_factory {
 4 
 5  public:
 6 
 7   t_generator_factory_impl(const std::string& short_name, const std::string& long_name,
 8 
 9          const std::string& documentation) : t_generator_factory(short_name, long_name, documentation)
10 
11   {}
12 
13 virtual t_generator* get_generator(t_program* program, 
14 
15  const std::map<std::string, std::string>& parsed_options, const std::string& option_string) {
16 
17     return new generator(program, parsed_options, option_string);
18 
19  }
20 
21 ……//此處省略了一些代碼
22 
23 };
復(fù)制代碼

 

t_generator_factory_impl類繼承了t_generator_factory類,而且在構(gòu)造函數(shù)的時候也調(diào)用了父類的構(gòu)造函數(shù),因為是帶參數(shù)的構(gòu)造函數(shù)所以必須手動調(diào)用父類的構(gòu)造函數(shù)。這個類是一個模板類,模板參數(shù)就是一個代碼生成器類,所以函數(shù)get_generator就能夠根據(jù)這個模板參數(shù)生成new一個對應(yīng)語言的代碼生成器對象了。這里就把上面提到的第一個問題也解決了,每一個工廠類把自己注冊到the_map,然后使用者通過代表語言的鍵(key)在the_map找到對應(yīng)的工廠對象,然后調(diào)用get_generator函數(shù)就生成具體的代碼生成器對象了,這就是第一個問題提到的最后一句返回語句的代碼執(zhí)行情況。

但是還是沒有看到定義具體的工廠對象呀,那么還需要看下面一處的代碼:

復(fù)制代碼
 1 #define THRIFT_REGISTER_GENERATOR(language, long_name, doc)         2 
 3 class t_##language##_generator_factory_impl                       4 
 5     : public t_generator_factory_impl<t_##language##_generator>     6 
 7   {                                                                 8 
 9    public:                                                         10 
11     t_##language##_generator_factory_impl()                        12 
13       : t_generator_factory_impl<t_##language##_generator>(        14 
15           #language, long_name, doc)                               16 
17     {}                                                             18 
19   };                                                               20 
21   static t_##language##_generator_factory_impl _registerer;
復(fù)制代碼

 

這是一個宏定義,它根據(jù)參數(shù)language定義一個生產(chǎn)具體語言的代碼生成器的工廠類,并從t_generator_factory_impl類繼承,傳遞的模板參數(shù)也是對應(yīng)語言的代碼生成器類,構(gòu)造函數(shù)同樣調(diào)用了父類的構(gòu)造函數(shù);最后還定義了一個對應(yīng)的靜態(tài)的類全局變量(千呼萬喚始出來,終于找到定義類的全局變量了)。但是還是存在同樣的問題就是定義了宏函數(shù)還是需要調(diào)用才執(zhí)行吧,所以就在代碼中搜索調(diào)用了這個宏函數(shù)的代碼,最終發(fā)現(xiàn)這個每一個具體的語言代碼生成器的文件都調(diào)用了一次,如下面是C++的文件t_cpp_generator.cc中調(diào)用的代碼:

復(fù)制代碼
1 THRIFT_REGISTER_GENERATOR(cpp, "C++",
2 
3 "    pure_enums:      Generate pure enums instead of wrapper classes.\n"
4 
5 "    dense:           Generate type specifications for the dense protocol.\n"
6 
7 "    include_prefix:  Use full include paths in generated files.\n"
8 
9 )
復(fù)制代碼

 

其他語言的代碼生成器類的定義文件中都有類似的調(diào)用,這樣每一個語言生成器對象的生產(chǎn)工廠就被注冊到the_map中了,由此問題得到解決。

2t_generator類的generate_program函數(shù)

這個函數(shù)是生成具體語言代碼的頂層函數(shù),它會調(diào)用子類定義的各個子函數(shù)來做具體代碼的生成過程,后面會詳細(xì)解析C++、javapython代碼生成的過程。

首先調(diào)用代碼生成器的初始化函數(shù)來初始化代碼生成器,然后依次調(diào)用各種基本數(shù)據(jù)類型和服務(wù)的生成函數(shù)來生成相應(yīng)的代碼,最后關(guān)閉代碼生成器。代碼實現(xiàn)如下:

 

復(fù)制代碼
 1  init_generator();
 2 
 3   vector<t_enum*> enums = program_->get_enums();
 4 
 5   vector<t_enum*>::iterator en_iter;
 6 
 7   for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
 8 
 9     generate_enum(*en_iter);
10 
11   }
12 
13   vector<t_typedef*> typedefs = program_->get_typedefs();
14 
15   vector<t_typedef*>::iterator td_iter;
16 
17   for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
18 
19     generate_typedef(*td_iter);
20 
21   }
22 
23   vector<t_const*> consts = program_->get_consts();
24 
25   generate_consts(consts);
26 
27   vector<t_struct*> objects = program_->get_objects();
28 
29   vector<t_struct*>::iterator o_iter;
30 
31   for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
32 
33     if ((*o_iter)->is_xception()) {
34 
35       generate_xception(*o_iter);
36 
37     } else {
38 
39       generate_struct(*o_iter);
40 
41     }
42 
43   }
44 
45   vector<t_service*> services = program_->get_services();
46 
47   vector<t_service*>::iterator sv_iter;
48 
49   for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
50 
51     service_name_ = get_service_name(*sv_iter);
52 
53     generate_service(*sv_iter);
54 
55   }
56 
57   close_generator();
復(fù)制代碼

 

此函數(shù)使用的是詞法和語法分析結(jié)果的一些符號,這些符號都保持在t_program對象的對于數(shù)據(jù)結(jié)構(gòu)里面,所以上面的函數(shù)依次從t_program對象中取得各種數(shù)據(jù)類型的符號和服務(wù)的符號,并依次生成。

3t_generator類的其它功能簡介

這個類是所有具體語言代碼生成器的共同基類,所以定義了很多各種語言代碼生成需要的共同功能,例如生成代碼的格式控制、命名空間的有效性檢查、駝峰標(biāo)識符和下劃線標(biāo)識符的相互轉(zhuǎn)換等等。這些功能比較簡單,需要可以直接查看源代碼。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多