在進(jìn)行C#代碼注入的過程中,寫的比較復(fù)雜的邏輯,但是reflector注入只能一個個函數(shù)來進(jìn)行,而且添加paramter非常復(fù)雜,這里做了一個簡單的代碼分析器,幫助所有代碼集中到一個函數(shù)中。
雖然感覺上比較簡單,但做的過程中,花費(fèi)了大半天的時間,這里把遇到的問題總結(jié)一下,給大家后續(xù)開發(fā)一些啟示。
理論上C語言格式的都可以用這個解析把多個函數(shù)包含在一個函數(shù)里面
因?yàn)閞elector一次只支持注入一個函數(shù),而我們寫的顯示代碼是有多個函數(shù)的。
即使新加入一個類,也需要在這個類里面單獨(dú)加入各個函數(shù)。
同時代碼里面有互相的嵌套,而且有返回值和各個參數(shù),如果單個的加非常的麻煩,而且reflector不支持返回值,相關(guān)的值只能放入輸出參數(shù),和原有的代碼就大大違背了。
所以這里寫了一個簡單的代碼分析器,用這個解析把多個函數(shù)包含在一個函數(shù)里面。
首先讀入的代碼要編譯通過
需要一些簡單的約束:
1子函數(shù)必須有返回值,且返回值不能用和次子函數(shù)的參數(shù)相同。只有一個返回的出口。上支持上任意返回類型,只是父函數(shù)必須調(diào)用一下子函數(shù)返回的值。2 調(diào)用函數(shù)的參數(shù)中不支持嵌套調(diào)用自己寫的函數(shù)。3 除非是返回值,否則臨時變量需要自行設(shè)的是unique的。否則會重復(fù)定義。4 “{}”這種單獨(dú)占一行,一般C#編輯器會自動解析成這樣。5 函數(shù)不能循環(huán)調(diào)用,解析會進(jìn)入循環(huán)。6 目前只支持+=和+,如果需要其他運(yùn)算符,在tpl_func_split中加。 特殊的運(yùn)算序列沒有做支持,當(dāng)時這個分析器只是為了輸出日志方便用的。
//(joint為已知的Joint數(shù)據(jù)結(jié)構(gòu)) public string A(string p) { string tmpA = "add a" + p; return tmpA; } public string B(Jointjoint, string c) { string tmp = "add b/n"; tmp += A(joint.format) + joint; return tmp; } public void Jump() { string tmp = "start ===/n"; //tmp += "A " + A("12"); //tmp += B("34", "12"); tmp += " A B" + A("12") + B(joint, "c") + A("34"); }輸出格式
會經(jīng)過代碼分析器分析為:
public void Jump() { string tmp ="start ===/n"; string _result_6_ ="add a"+"12"; string _result_7_ ="add b/n"; string _result_8_ ="add a"+joint.format; _result_7_ +=_result_8_+joint; string _result_9_ ="add a"+"34"; tmp +=" A B"+_result_6_+_result_7_+_result_9_; } 思路
整體思路:
分治法。
每個函數(shù)有多行語句,每行語句包含多個函數(shù),經(jīng)過相互調(diào)用就相當(dāng)于減了一層調(diào)用。無論有多少層調(diào)用,最終都可以解析為只包含一層可以輸出的序列。
如 tmp += A(cc)
就會變?yōu)椋?/p>
<<A相關(guān)的表達(dá)式,同時更新所有的輸入為cc輸出為_result_1_>>
Tmp += _result_1_;
1 將每個函數(shù)解析為結(jié)構(gòu)FuncDesc, 存入一個整體的FUNC_DICT中。
class FuncDesc(object): def __init__(self): self.params_list = [] self.func_desc = [] self.func_desc_split = [] self.func_name = "" self.out_name = "" 2 每個out_name和params_list的表示都用一個特殊的完全不同的字符串代替。方便以后在調(diào)用的時候,整體替換。
3 其中每個func_desc表示一行代碼。
每行代碼再生成一個結(jié)構(gòu)
class DescFuncSplit(object): def __init__(self, desc_str): self.desc_str = desc_str # (type, funcname, params), type0:normal, 1 func self.func_list = [] self.opeartor_list = [] self.has_semicolon = False4 在調(diào)用到單個func_desc的時候,判斷各個函數(shù),調(diào)用到FuncDesc,賦值params和return_value。
在FuncDesc在依次調(diào)用每個func_desc_split。最終會得到一系列字符串。
經(jīng)過相互調(diào)用,最終會在最簡單層中停止:
如code中A
這一系列的字符串就是最后希望得到的函數(shù)。
輸出是最終的函數(shù)內(nèi)部的內(nèi)容。
需要自己加上函數(shù)頭,可以放在C#編輯器里面format一下。
下附代碼
#-*- coding:utf-8 -*-"""python XX.py inputfilename.cs out_func_name第一個參數(shù)是要讀入的文件名稱第二個參數(shù)是要輸出的函數(shù)名"""import os, sysimport reTOTAL_NUM = 0;FUNC_DICT = {}def GetIndexNum(): global TOTAL_NUM TOTAL_NUM += 1 return TOTAL_NUMdef replacer(search_obj, replace_str): groups = search_obj.groups() return groups[0] + replace_str + groups[1] def change_descs(init_str, change_param, replace_param): cal = r"(/W)%s(/W)" % change_param; replacer2 = lambda search_obj: replacer(search_obj, replace_param) return re.sub(cal, replacer2, init_str) class DescFuncSplit(object): def __init__(self, desc_str): self.desc_str = desc_str # (type, funcname, params), type0:normal, 1 func self.func_list = [] self.opeartor_list = [] self.has_semicolon = False def debug_info(self): PRint "==============" print "debug_info: ", self.desc_str print self.func_list print self.opeartor_list def get_split_out_result(self, param_dict): print "get_split_out_result" , param_dict total_len = len(self.func_list) out_str = "" out_list = [] for idx in xrange(total_len): func_tuple = self.func_list[idx] if func_tuple[0] == 0: out_str += func_tuple[1] else: func_result_name = "_result_%s_" % GetIndexNum() func_desc = FUNC_DICT[func_tuple[1]] params = func_tuple[2] new_params = [] for new_param in params: for k,v in param_dict.items(): new_param = new_param.replace(k, v) new_params.append(new_param) tmp_list = func_desc.get_end_result(new_params, func_result_name) out_list.extend(tmp_list) out_str += func_result_name if idx < total_len - 1: out_str += self.opeartor_list[idx] if self.has_semicolon: out_str += ";" out_str += "/n" out_list.append(out_str) return out_list def tpl_func_split(self): total_split = [] out_str = "" if self.desc_str.find("+=") >= 0: self.func_list.append((0, self.desc_str[:self.desc_str.find("+=")])) out_str = self.desc_str[self.desc_str.find("+=") + 2:] self.opeartor_list.append("+=") elif self.desc_str.find("=") >= 0: self.func_list.append((0, self.desc_str[:self.desc_str.find("=")])) out_str = self.desc_str[self.desc_str.find("=") + 1:] self.opeartor_list.append("=") else: out_str = self.desc_str #鍘婚櫎瀛楃涓插唴閮ㄧ殑+ -> _ total_len = len(out_str) idx = 0 while(idx < total_len): if out_str[idx] == "/"": idy = idx + 1 while(idy < total_len): if out_str[idy] == "+": out_str[idy] = "_" if out_str[idy] == "/"": idy += 1 break idy += 1 idx = idy else: idx += 1 func_split = out_str.split("+") for sp in func_split: sp = sp.strip() if sp[-1] == ";": sp = sp[:-1].strip() self.has_semicolon = True if sp[0] == "/"": self.func_list.append((0, sp)) self.opeartor_list.append("+") elif sp[-1] == ")": l = sp.find("(") funcname = sp[:l].strip() if not FUNC_DICT.has_key(funcname): self.func_list.append((0, sp)) self.opeartor_list.append("+") continue params_str = sp[l+1:-1] params_split = params_str.split(",") params = [] for param in params_split: param = param.strip() params.append(param) self.func_list.append((1, funcname, params)) self.opeartor_list.append("+") else: self.func_list.append((0, sp)) self.opeartor_list.append("+") return class FuncDesc(object): def __init__(self): self.params_list = [] self.func_desc = [] self.func_desc_split = [] self.func_name = "" self.out_name = "" def debug_info(self): print "========" print "params_list:", self.params_list print "func_desc:" print self.func_desc print "func_name: %s, out_name: %s" % (self.func_name, self.out_name) def get_func_name(self, fs): fp = fs.split("(") tmp_list = fp[0].split(" ") self.func_name = tmp_list[-1]; fp[1] = fp[1].replace(")", "") tmp_list = fp[1].split(",") for tmp in tmp_list: tt = tmp.split(" ") for idtt in xrange(len(tt) - 1, -1, -1): if tt[idtt].strip() != "": self.params_list.append(tt[idtt].strip()) break def change_params_to_unique(self): for params_key in xrange(len(self.params_list)): new_param = "_param_%s_" % GetIndexNum() param = self.params_list[params_key] self.params_list[params_key] = new_param for desc_key in xrange(len(self.func_desc)): desc = self.func_desc[desc_key] new_desc = change_descs(desc, param, new_param) self.func_desc[desc_key] = new_desc return def change_out_name_to_unique(self): return_desc = self.func_desc[-1] new_desc = return_desc.replace(";", "") if new_desc.find("return") < 0: return out_name = new_desc[new_desc.find("return") + 6:].strip() if out_name == "": self.func_desc.pop() return self.out_name = "_result_%s_" % GetIndexNum() for desc_key in xrange(len(self.func_desc)): desc = self.func_desc[desc_key] new_desc = change_descs(desc, out_name, self.out_name) self.func_desc[desc_key] = new_desc self.func_desc.pop() return def change_desc_value_to_func_split(self): for desc in self.func_desc: desc_func_split = DescFuncSplit(desc) desc_func_split.tpl_func_split() self.func_desc_split.append(desc_func_split) def get_end_result(self, params, func_result_name): print "get_end_result ", params, func_result_name if self.out_name != "" and func_result_name == "": print "error %s has no func_result_name" % self.func_name raise 1 if len(params) != len(self.params_list): print "error %s params error %s %s" % (self.func_name, self.params_list, params) raise 1 param_dict = {} for idx in xrange(len(self.params_list)): param_dict[self.params_list[idx]] = params[idx] out_list = [] for func_split in self.func_desc_split: func_split.debug_info() func_str_list = func_split.get_split_out_result(param_dict) for func_str in func_str_list: out_str = func_str; for k,v in param_dict.items(): out_str = out_str.replace(k,v) out_list.append(out_str) if self.out_name != "": for idx in xrange(len(out_list)): out_str = out_list[idx] out_list[idx] = out_str.replace(self.out_name, func_result_name) return out_listdef main(filename, out_func_name): f = open(filename, "r") lines = f.readlines(); f.close(); total_line = len(lines) for line in lines: if line.startswith("{") or line.endswith("}"): if len(line.strip()) != 1: print "not strip one line", line raise 1 cur_num = 0 while(cur_num < total_line): if lines[cur_num].find("public") < 0: cur_num += 1 continue func_desc = FuncDesc() func_desc.get_func_name(lines[cur_num]) cur_num += 1 while(cur_num < total_line): if lines[cur_num].strip() == "{": break cur_num += 1 cur_num += 1 cur_left = 1 while(cur_num < total_line): if lines[cur_num].strip() == "{": cur_left += 1 if lines[cur_num].strip() == "}": cur_left -= 1 if cur_left == 0: break strip_line = lines[cur_num].strip() if strip_line != "" and not strip_line.startswith("//"): func_desc.func_desc.append(lines[cur_num]) cur_num += 1 FUNC_DICT[func_desc.func_name] = func_desc cur_num += 1 print FUNC_DICT.keys() for func_desc in FUNC_DICT.values(): func_desc.change_params_to_unique() func_desc.change_out_name_to_unique() func_desc.change_desc_value_to_func_split() func_desc.debug_info() if not FUNC_DICT.has_key(out_func_name): print "error outfuncname in readfile", filename return out_str_list = [] out_str_list = FUNC_DICT[out_func_name].get_end_result([], "") f = open("out.txt", "w") for out_str in out_str_list: f.write(out_str) f.close() if __name__ == "__main__": if len(sys.argv) < 3: print "please input: readfilename outfuncname" exit() out_func_name = sys.argv[2] filename = sys.argv[1] main(filename, out_func_name)
新聞熱點(diǎn)
疑難解答