[分享] Cog, a python-based code generator

看板Python作者 (眠月)時間17年前 (2007/11/13 03:23), 編輯推噓6(601)
留言7則, 5人參與, 最新討論串1/1
Cog 是一個 python-based 的程式碼產生器,http://nedbatchelder.com/code/cog/ 讓使用者可以把 python 混在 C++ 的程式碼裡面來自動產生 C++ 程式碼, 舉個例子,這是一個 C++ 原始檔,'Actions.cpp' /*[[[cog import cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] for fn in fnames: cog.outl("void %s();" % fn) ]]]*/ //[[[end]]] 你可以看到,python 的程式碼,實際上是寫在 C++ 的註解裡面, 在我們用命令列執行過 cog 以後: python cog.py -r Actions.cpp 他就變成這樣: /*[[[cog import cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] for fn in fnames: cog.outl("void %s();" % fn) ]]]*/ void DoSomething(); void DoAnotherThing(); void DoLastThing(); //[[[end]]] 黃色的部份是被產生出來的 C++ 程式碼。 最後一行的 //[[[end]]] 是讓 cog 可以辨識出哪些是自動產生的程式碼, 這樣使用者就可以在同一個檔案重複來生成原始碼, 而不是去使用兩個檔案,一個來源檔跟一個目的檔。 這是一個不錯的方法來自動產生 Java 或是 C++ 的 setter/getter 成員函式。 對於大部分的類別而言,我們常常需要一大票的 setter/getter 方法。 舉個 Java 的例子好了: class Color { int red ; int green ; int blue ; void setRed (int r) { red = r; } void setGreen (int g) { green = r; } void setBlue (int b) { blue = r; } int getRed () { return red ; } int getGreen () { return green ; } int getBlue () { return blue ; } } 使用 cog 的話,我們可以這樣寫: class Color { /*[[[cog import cog data = ['red', 'green', 'blue'] for d in data: cog.outl("int %s;" % d) cog.outl("void set%s%s(int v){%s=v;}" % (d[0].upper(), d[1:], d) ) cog.outl("int get%s%s(){return %s;}" % (d[0].upper(), d[1:], d) ) ]]]*/ //[[[end]]] } 重新模組化一下,這樣寫也不錯 /*[[[cog import cog def data_member(d) : cog.outl("int %s;" % d) cog.outl("void set%s%s(int v){%s=v;}" % (d[0].upper(), d[1:], d) ) cog.outl("int get%s%s(){return %s;}" % (d[0].upper(), d[1:], d) ) ]]]*/ //[[[end]]] class Color { /*[[[cog map ( data_member, ['red', 'green', 'blue'] ) ]]]*/ //[[[end]]] } 這樣當你還有別的類別,你就可以直接使用 data_member 這個函數了。 甚至呢,我們可以維護一個自己常用的 python 模組,像是 'mycog.py': import cog import MySQLdb # create data member with setter/getter def data_member(d) : cog.outl("int %s;" % d) cog.outl("void set%s%s(int v){%s=v;}" % (d[0].upper(), d[1:], d) ) cog.outl("int get%s%s(){return %s;}" % (d[0].upper(), d[1:], d) ) # create a class according to a table in database def create_table_class(table_name) : c = MySQLdb.connect(...).cursor() res = c.query('describe ' + table_name).fetchall() cog.outl('class %s%s {' % (table_name[0].upper(), table_name[1:])) for field = res : cog.outl(...) cog.outl('};') 這樣,你就可以像這樣複用這個模組: class Color { /*[[[cog import mycog map ( mycog.data_member, ['red', 'green', 'blue'] ) ]]]*/ //[[[end]]] } /*[[[cog mycog.create_table_class(student) ]]]*/ //[[[end]]] 你大概會得到(根據你資料庫表格欄位而定): class Color { /*[[[cog import mycog ap ( mycog.data_member, ['red', 'green', 'blue'] ) ]]]*/ int red; void setRed(int v){red=v;} int getRed(){return red;} int green; void setGreen(int v){green=v;} int getGreen(){return green;} int blue; void setBlue(int v){blue=v;} int getBlue(){return blue;} //[[[end]]] } /*[[[cog mycog.create_table_class(Student) ]]]*/ class Student { String name ; Date dayOfBirth ; String gender ; String Department ; ... } ; //[[[end]]] -- To iterate is human, to recurse is divine. 遞迴只應天上有, 凡人該當用迴圈.   L. Peter Deutsch -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.114.78.40 ※ 編輯: yoco315 來自: 140.114.78.40 (11/13 03:37) ※ 編輯: yoco315 來自: 140.114.78.40 (11/13 03:37) ※ 編輯: yoco315 來自: 140.114.78.40 (11/13 03:40)

11/13 12:08, , 1F
推,可惜不熟 python XD
11/13 12:08, 1F

11/13 15:19, , 2F
cog.outl("//[[[end]]]")會處理嗎?
11/13 15:19, 2F

11/14 10:07, , 3F
如果能再搭配 target language 的 parser 就更方便了
11/14 10:07, 3F

11/14 20:33, , 4F
這個的意思是 @@?
11/14 20:33, 4F

11/14 21:34, , 5F
比方說 cog 可以分析 c++ 程式吧?
11/14 21:34, 5F

11/15 23:51, , 6F
例如說分析C code,遇到特定模式,就插入特定片段之類的
11/15 23:51, 6F

12/27 12:25, , 7F
推~
12/27 12:25, 7F
文章代碼(AID): #17EAWQmA (Python)
文章代碼(AID): #17EAWQmA (Python)