我的新浪微博:http://weibo.com/freshairbrucewoo。 歡迎大家相互交流,共同提高技術(shù)。 2 t_generator類和t_generator_registry類這個(gè)兩個(gè)類的主要功能就是為生成所有語言的代碼提供基礎(chǔ)信息和提供具體代碼生成器對(duì)象,上面就是調(diào)用這個(gè)兩個(gè)類的方法來生成具體語言的代碼生成器對(duì)象和執(zhí)行生成代碼的功能函數(shù)。下面主要分析兩個(gè)函數(shù)的功能,一個(gè)是t_generator_registry類的get_generator函數(shù),這個(gè)是一個(gè)靜態(tài)的函數(shù)可以直接通過類調(diào)用;另一個(gè)是t_generator類的generate_program函數(shù)。 (1)t_generator_registry類的get_generator函數(shù) 這個(gè)函數(shù)有兩個(gè)參數(shù),一個(gè)是表示程序的對(duì)象program,另一個(gè)是語言字符串參數(shù)(包括代表語言的簡(jiǎn)短字符串和可選項(xiàng)的組合,有的沒有)。函數(shù)首先解析語言字符串參數(shù),參數(shù)字符串中是這樣組織的:在冒號(hào)(:)之前是代表語言的字符串,冒號(hào)之后是可選項(xiàng)的參數(shù),每一個(gè)可選項(xiàng)參數(shù)用逗號(hào)(,)分割,每一個(gè)可選項(xiàng)參數(shù)都是鍵值對(duì)并且鍵和值是用等號(hào)(=)分割。按照上面的字符串格式解析各個(gè)參數(shù)部分就可以了,可選項(xiàng)參數(shù)用map來保存鍵值對(duì),代碼實(shí)現(xiàn)如下: 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 }
然后調(diào)用get_generator_map函數(shù)得到一個(gè)代表語言字符串和產(chǎn)生這種語言生成器對(duì)象的工廠對(duì)象的map對(duì)象: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ù)只有兩句代碼,一個(gè)是定義一個(gè)靜態(tài)局部變量并初始化(因?yàn)殪o態(tài)局部變量必須并初始化并且只有第一次會(huì)執(zhí)行初始化,因?yàn)椴怀跏蓟溄映绦虻臅r(shí)候會(huì)報(bào)錯(cuò)),第二句就是返回這個(gè)靜態(tài)局部變量給調(diào)用者,代碼如下: 1 static gen_map_t* the_map = new gen_map_t(); 2 3 return *the_map;
然后在這個(gè)map對(duì)象中找到對(duì)應(yīng)語言的工廠對(duì)象,然后用這個(gè)工廠對(duì)象生產(chǎn)一個(gè)這種語言的代碼生成器對(duì)象并返回給調(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)分析完畢,但是還存在著兩個(gè)問題(或是困難)。一個(gè)是最后一條返回一句是根據(jù)具體的語言來使用具體語言生產(chǎn)器的工廠對(duì)象生產(chǎn)代碼生成器,具體又是怎么生成的了?第二個(gè)就是從main函數(shù)執(zhí)行到現(xiàn)在還沒有發(fā)現(xiàn)在哪兒為get_generator_map函數(shù)里定義的靜態(tài)局部變量添加過任何鍵值對(duì),那么我們查找具體語言必定會(huì)失敗,那么會(huì)返回一個(gè)NULL給調(diào)用者,那么程序就會(huì)執(zhí)行不下去了,但是程序確實(shí)能夠完完整整的執(zhí)行下去,這個(gè)問題困擾了我好一會(huì)兒。下面就這兩個(gè)問題繼續(xù)分析相關(guān)代碼并且解決問題。 第一個(gè)應(yīng)該不算是問題,但是必須要解決第二個(gè)問題以后才能夠解釋,因?yàn)闆]有解決第二個(gè)問題,那么根本就不會(huì)執(zhí)行到最后一條返回語句這兒來,所以我先解決第二個(gè)問題。 第二個(gè)問題分析和解決思路如下: 我們通常認(rèn)為main函數(shù)是程序的入口函數(shù),那么所以程序的執(zhí)行都是從main函數(shù)開始的,所以我也選擇從main函數(shù)開始分析這部分的代碼,根據(jù)程序的執(zhí)行流程閱讀和分析代碼是我一貫的思路。但是這種情況在C++里面有例外,記得我在學(xué)習(xí)MFC的時(shí)候,分析MFC執(zhí)行過程就發(fā)現(xiàn)一個(gè)問題,那就是全局變量的初始化是在main函數(shù)開始之前的,也就是說全局類對(duì)象的構(gòu)造函數(shù)也是在main執(zhí)行之前執(zhí)行的。由于我反復(fù)從main開始一直詳細(xì)的閱讀每一行代碼,所以可以確定確實(shí)沒有在執(zhí)行的過程中初始化the_map靜態(tài)局部變量,所以唯一的可能就是在main函數(shù)開始之前已經(jīng)初始化好了。根據(jù)這一點(diǎn)思路自己開始著手查找初始化the_map的代碼,發(fā)現(xiàn)t_generator_registry類的register_generator函數(shù)為the_map添加鍵值對(duì)了,這個(gè)函數(shù)定義如下: 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 }
這個(gè)函數(shù)也首先調(diào)用get_generator_map函數(shù)得到那個(gè)靜態(tài)局部變量,然后查找要注冊(cè)的工程是否已經(jīng)在the_map中存在,如果存在就提示失敗信息,否則就把工廠的名字和工廠對(duì)象作為鍵值對(duì)添加到the_map中。 雖然找到了為the_map添加鍵值對(duì)的地方,但是還沒有找到調(diào)用這個(gè)注冊(cè)工廠函數(shù)的地方,所以繼續(xù)在代碼中搜索調(diào)用這個(gè)函數(shù)的地方。整個(gè)代碼就只有一處調(diào)用了這個(gè)函數(shù),而且是在一個(gè)類的構(gòu)造函數(shù)中,代碼如下: 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 }
t_generator_factory類是所有生產(chǎn)代碼生產(chǎn)器對(duì)象工廠的基類,每一種具體的語言都有自己的代碼生成器類和生產(chǎn)這種類的工廠類,上面的代碼是它的構(gòu)造函數(shù),功能就是把自己注冊(cè)到the_map中??吹竭@里是否有一種逐漸清晰的感覺,但是總是感覺還有少點(diǎn)什么,就是這個(gè)構(gòu)造函數(shù)被調(diào)用也必須有這個(gè)類的對(duì)象被定義或其子類的對(duì)象被定義。于是我又開始搜索哪些類是從這個(gè)類繼承的,發(fā)現(xiàn)兩處很重要的代碼,一處如下: 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 };
t_generator_factory_impl類繼承了t_generator_factory類,而且在構(gòu)造函數(shù)的時(shí)候也調(diào)用了父類的構(gòu)造函數(shù),因?yàn)槭菐?shù)的構(gòu)造函數(shù)所以必須手動(dòng)調(diào)用父類的構(gòu)造函數(shù)。這個(gè)類是一個(gè)模板類,模板參數(shù)就是一個(gè)代碼生成器類,所以函數(shù)get_generator就能夠根據(jù)這個(gè)模板參數(shù)生成new一個(gè)對(duì)應(yīng)語言的代碼生成器對(duì)象了。這里就把上面提到的第一個(gè)問題也解決了,每一個(gè)工廠類把自己注冊(cè)到the_map,然后使用者通過代表語言的鍵(key)在the_map找到對(duì)應(yīng)的工廠對(duì)象,然后調(diào)用get_generator函數(shù)就生成具體的代碼生成器對(duì)象了,這就是第一個(gè)問題提到的最后一句返回語句的代碼執(zhí)行情況。 但是還是沒有看到定義具體的工廠對(duì)象呀,那么還需要看下面一處的代碼: 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;
這是一個(gè)宏定義,它根據(jù)參數(shù)language定義一個(gè)生產(chǎn)具體語言的代碼生成器的工廠類,并從t_generator_factory_impl類繼承,傳遞的模板參數(shù)也是對(duì)應(yīng)語言的代碼生成器類,構(gòu)造函數(shù)同樣調(diào)用了父類的構(gòu)造函數(shù);最后還定義了一個(gè)對(duì)應(yīng)的靜態(tài)的類全局變量(千呼萬喚始出來,終于找到定義類的全局變量了)。但是還是存在同樣的問題就是定義了宏函數(shù)還是需要調(diào)用才執(zhí)行吧,所以就在代碼中搜索調(diào)用了這個(gè)宏函數(shù)的代碼,最終發(fā)現(xiàn)這個(gè)每一個(gè)具體的語言代碼生成器的文件都調(diào)用了一次,如下面是C++的文件t_cpp_generator.cc中調(diào)用的代碼: 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 )
其他語言的代碼生成器類的定義文件中都有類似的調(diào)用,這樣每一個(gè)語言生成器對(duì)象的生產(chǎn)工廠就被注冊(cè)到the_map中了,由此問題得到解決。 (2)t_generator類的generate_program函數(shù) 這個(gè)函數(shù)是生成具體語言代碼的頂層函數(shù),它會(huì)調(diào)用子類定義的各個(gè)子函數(shù)來做具體代碼的生成過程,后面會(huì)詳細(xì)解析C++、java和python代碼生成的過程。 首先調(diào)用代碼生成器的初始化函數(shù)來初始化代碼生成器,然后依次調(diào)用各種基本數(shù)據(jù)類型和服務(wù)的生成函數(shù)來生成相應(yīng)的代碼,最后關(guān)閉代碼生成器。代碼實(shí)現(xiàn)如下:
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();
此函數(shù)使用的是詞法和語法分析結(jié)果的一些符號(hào),這些符號(hào)都保持在t_program對(duì)象的對(duì)于數(shù)據(jù)結(jié)構(gòu)里面,所以上面的函數(shù)依次從t_program對(duì)象中取得各種數(shù)據(jù)類型的符號(hào)和服務(wù)的符號(hào),并依次生成。 (3)t_generator類的其它功能簡(jiǎn)介 這個(gè)類是所有具體語言代碼生成器的共同基類,所以定義了很多各種語言代碼生成需要的共同功能,例如生成代碼的格式控制、命名空間的有效性檢查、駝峰標(biāo)識(shí)符和下劃線標(biāo)識(shí)符的相互轉(zhuǎn)換等等。這些功能比較簡(jiǎn)單,需要可以直接查看源代碼。 |
|