Chinaunix首页 | 论坛 | 博客
  • 博客访问: 367713
  • 博文数量: 73
  • 博客积分: 3574
  • 博客等级: 中校
  • 技术积分: 1503
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-26 11:17
文章分类

全部博文(73)

文章存档

2012年(14)

2011年(15)

2010年(44)

分类: Python/Ruby

2012-09-11 23:15:20

    原始需求是在调试代码的过程中,经常需要插入一些printk或printf调试语句,而如果被调试的对象是一个结构体,并且结构体所包含的变量还比较多的时候,手写打印结构体内变量的函数就成了一个琐碎而又无聊的工作。

    那么,有没有什么办法能够自动生成这些打印函数,在需要的时候直接编译,而不需要手动去一行行的敲代码呢。
    当然,这个问题绝对不是我第一次遇到,网上查了一下,有不少人在问同样的问题,而在开源界也有一个实现此功能的开源软件,它的原理是利用gcc -g编译生成的二进制代码中已经存在打印每个结构体变量的函数,通过某种方法把这些code码直接抠出来使用。
    
    这个方法当然比较高明了,恰巧最近在学习python的正则表达式,便想着能不能通过正则表达式去解析代码,生成一个.h或者.c文件,文件中包含针对每个结构体的打印函数,下面就可以直接在需要的位置添加这些函数,重新编译时把生成的文件编译进工程就可以了。
    针对这个需求,有了以下的代码:

点击(此处)折叠或打开

  1. #!/usr/bin/env python
  2. #-*-coding:UTF--*-

  3. import re
  4. import os
  5. import sys
  6. import getopt


  7. print_symbol = {} #保存打印符号信息

  8. print_func = {} #保存每一个结构体对应的打印函数

  9. define_store = [] #保存分解出的所有typedef定义
  10. struct_store = [] #保存分解出的所有struct结构列表
  11.     
  12. #默认写入文件为temp.c
  13. target_file = './temp.c'


  14. = re.compile(r'struct\s*\w[\w_]*?\s*?{.*?}',re.S) #匹配struct(不支持嵌套)
  15. = re.compile(r'typedef.*?(?=;)') #匹配typedef定义
  16. m1 = re.compile(r'/\*.*?\*/',re.S) #匹配/*...*/的注释
  17. n1 = re.compile(r'//.*(?=\n)') #匹配//..的注释
  18. m2 = re.compile(r'#if\s*?0.*?#endif',re.S) #匹配#if 0的注释(不支持嵌套)


  19. #设置打印符号的默认配置
  20. def set_default_conf():
  21.     #后期可考虑默认打印符号的自动化生成,如生成组合,确定打印类型等
  22.     print_symbol['int'] = '%d'
  23.     print_symbol['unsigned int'] = '%u'
  24.     print_symbol['long'] = '%l'
  25.     print_symbol['unsigned long'] = '%lu'
  26.     
  27.     print_symbol['short'] = '%d'
  28.     print_symbol['unsigned short'] = '%u'
  29.     
  30.     print_symbol['char'] = '%c'
  31.     print_symbol['unsigned char'] = '%u'

  32.     print_symbol['float'] = '%f'
  33.     print_symbol['double'] = '%f'

  34.     print_symbol['void *'] = '%p'
  35.     print_symbol['int *'] = '%p'
  36.     print_symbol['char *'] = '%p'


  37. #处理单个define
  38. def collect_each_define(define_item):
  39.     define_store.append(define_item)


  40. #处理单个struct
  41. def collect_each_struct(struct_item):
  42.     #删除注释应放到最前面,防止解析到已经注释到的结构体    
  43.     #删除注释
  44.     #struct_item = m1.sub('',struct_item)
  45.     #struct_item = n1.sub('',struct_item)
  46.     
  47.     struct_store.append(struct_item)


  48. #处理数组赋值
  49. def process_array(head,fp,line):
  50.     #print 'array\t' + line
  51.     #指针数组
  52.     if '*' in line:
  53.         flag_match = re.compile(r'\*+')
  54.         flag = ''.join(flag_match.findall(line))
  55.         style = flag_match.split(line)[0]
  56.         name_value = flag_match.split(line)[-1]
  57.         array_match1 = re.compile(r'\w\w*?(?=\[)')
  58.         array_match2 = re.compile(r'(?<=\[)\d+(?=\])')
  59.         name = array_match1.findall(line.split()[-1].strip())
  60.         value = array_match2.findall(line.split()[-1].strip())
  61.         name = ''.join(name).strip()
  62.         value = ''.join(value).strip()

  63.         style += flag
  64.     #普通数组
  65.     else:
  66.         style = (' '.join(line.split()[:-1])).strip()
  67.         #print style
  68.         #print line.split()[-1].strip()
  69.         array_match1 = re.compile(r'\w\w*?(?=\[)')
  70.         array_match2 = re.compile(r'(?<=\[)\d+(?=\])')
  71.         name = array_match1.findall(line.split()[-1].strip())
  72.         value = array_match2.findall(line.split()[-1].strip())
  73.         name = ''.join(name).strip()
  74.         value = ''.join(value).strip()

  75.     #style为类型,name为变量名,value为数组大小
  76.     if style in print_symbol.keys():
  77.         if '%' in print_symbol[style]:
  78.             fp.write('\n')    
  79.             fp.write('''\tfor(i = 0 ; i < %s; i++)\n''' %value)
  80.             fp.write('''\t{\n''')
  81.             fp.write('''\t\tprintf("%s.%s <==> %s\\n",item.%s);\n''' %(head,name,print_symbol[style],name))
  82.             fp.write('''\t}\n''')
  83.     #不在打印符号表内的指针统一按照%p打印
  84.     elif '*' in style:
  85.         fp.write('\n')    
  86.         fp.write('''\tfor(i = 0 ; i < %s; i++)\n''' %value)
  87.         fp.write('''\t{\n''')
  88.         fp.write('''\t\tprintf("%s.%s <==> %%p\\n",item.%s);\n''' %(head,name,name))
  89.         #print ('''\t\tprintf("%s.%s <==> %%p\\n",item.%s);\n''' %(head,name,print_symbol[style],name))
  90.         fp.write('''\t}\n''')



  91. #处理位域赋值
  92. def process_bit(head,fp,line):
  93.     #print 'bit\t' + line
  94.     bit_match = re.compile(r'\w+:\d+')
  95.     style_match = re.compile(r'\w+')

  96.     bit_list = bit_match.findall(line)
  97.     style = ''.join(style_match.findall(bit_match.sub('',line)))

  98.     if style in print_symbol.keys():
  99.         if '%' in print_symbol[style]:
  100.             for it in bit_list:
  101.                 its = str(it)
  102.                 fp.write('''\tprintf("%s.%s <==> %s\\n",item.%s);\n''' %(head,its[:its.index(':')],print_symbol[style],its[:its.index(':')]))
  103.     else:
  104.             fp.write('''printf("sizeof(%s.%s) %%d\n",sizeof(%s.%s));\n''' %(head,name,head,name))



  105. #处理指针赋值
  106. def process_pointer(head,fp,line):
  107.     #print 'pointer\t' + line
  108.     #数组处理优先级更高,确保在这个地方已经不存在指针数组
  109.     if '*' in line:
  110.         #print line        
  111.         flag_match = re.compile(r'\*+')
  112.         flag = ''.join(flag_match.findall(line))
  113.         style = flag_match.split(line)[0]
  114.         name = flag_match.split(line)[-1]

  115.         style += flag
  116.     
  117.         if style in print_symbol.keys():
  118.             if '%' in print_symbol[style]:
  119.                 fp.write('''\tprintf("%s.%s <==> %s\\n",item.%s);\n''' %(head,name,print_symbol[style],name))
  120.         else:
  121.             fp.write('''\tprintf("%s.%s <==>%%p\\n",item.%s);\n''' %(head,name,name))


  122. #处理标准赋值
  123. def process_normal(head,fp,line):
  124.     #print 'normal\t' + line
  125.     style = (' '.join(line.split()[:-1])).strip()
  126.     name = line.split()[-1].strip()
  127.     if style in print_symbol.keys():
  128.         #如果已经存在%*的打印格式
  129.         if '%' in print_symbol[style]:
  130.             fp.write('''\tprintf("%s.%s <==> %s\\n",item.%s);\n''' %(head,name,print_symbol[style],name))
  131.             #pass
  132.     #这种情形应该为结构体中包含别的结构体变量
  133.     else:
  134.         #先规避,打印结构体大小,后续可直接嵌套打印函数
  135.         fp.write('''\tprintf("sizeof(%s.%s) %%d\\n",sizeof(%s.%s));\n''' %(head,name,head,name))
  136.         #pass



  137. #解析struct中每一个定义语句
  138. def process_line(head,fp,line):

  139.     #判断是否为位域定义(假定位域的定义中包含,)
  140.     if ',' in line:
  141.         process_bit(head,fp,line)
  142.     #判断是否为数组(数组的定义为包含一对中括号[]),对于指针数组优先为数组
  143.     elif '[' in line and ']' in line:
  144.         process_array(head,fp,line)
  145.     #判断指针
  146.     elif '*' in line:
  147.         process_pointer(head,fp,line)
  148.     #正常赋值(还有没有其他情况?)
  149.     else:
  150.         process_normal(head,fp,line)

  151. #解析define
  152. def reslove_each_define():
  153.     for item in define_store:
  154.         temp_match = re.compile('typedef')
  155.         item = temp_match.sub('',item)

  156.         #这块解析的好烂啊,复杂点的都解析不出来
  157.         #怎么解析指针类赋值,尤其函数指针???
  158.         temp_list = item.split(' ')
  159.         s = (' '.join(temp_list[:-1])).strip()

  160.         if s in print_symbol.keys():
  161.                 print_symbol[temp_list[-1]] = print_symbol[s]
  162.         else:
  163.             #先保存define定义,在生成打印时再查找确认一次
  164.             print_symbol[temp_list[-1]] = s


  165. #解析struct
  166. def reslove_each_struct():
  167.     for item in struct_store:
  168.         #获取struct的名字
  169.         name_match = re.compile(r'(?<=struct)\s*\w\w*(?=\s*?{)')
  170.         name = name_match.findall(item)
  171.         name = (''.join(name)).strip()
  172.         #假设{}之间的为正文
  173.         index1 = item.find('{')
  174.         if index1 == -1:
  175.             print 'reslove failed for the error farmat struct'
  176.             return
  177.         index2 = item.find('}')
  178.         if index2 == -1:
  179.             print 'reslove failed for the error farmat struct'
  180.             return
  181.         
  182.         fp = open(target_file,'a+')
  183.         fp.write('\n')
  184.         fp.write('void print_%s(%s item)\n'%(name,name))
  185.         fp.write('{\n')
  186.         fp.write('\tint i = 0; \n')
  187.         #print ('void print_%s(struct %s item)\n'%(name,name))
  188.         
  189.         date = item[index1 +: index2]

  190.         item_match = re.compile(r'\w.*?(?=;)',re.S)
  191.         for line in item_match.findall(date):
  192.             process_line(name,fp,line)

  193.         fp.write('}\n')
  194.         fp.close()

  195. #完成对单个文件的解析
  196. def handle_file(test_file):
  197.     fp = open(test_file,'r')
  198.     context = fp.readlines()
  199.     context = ''.join(context)

  200.     context = m2.sub('',context)
  201.     context = m1.sub('',context)
  202.     context = n1.sub('',context)

  203.     file_define = []
  204.     file_struct = []
  205.     for i in n.findall(context):
  206.         collect_each_define(i)

  207.     for j in m.findall(context):
  208.         collect_each_struct(j)

  209. '''
  210. def write_to_file(target):
  211.     pass
  212. '''

  213. def print_help_info():
  214.     '''print function help information'''
  215.     print 'Usage: python get_struct.py [-f file -d directory -o target_file -h --help]'
  216.     print '-f 待解析的源文件'
  217.     print '-d 待解析的目录,将解析目录下所有的.c以及.h'
  218.     print '-o 打印函数保留文件,默认保留在当前目录下的temp.c文件中'
  219.     print '-h/--help 打印帮助信息'


  220. if __name__ == '__main__':
  221.     if(len(sys.argv) <= 1):
  222.             print 'input the error args format'

  223.     try:
  224.         opts,args = getopt.getopt(sys.argv[1:],'f:d:ho:',['help'])
  225.     except getopt.GetoptError,err:
  226.         print str(err)
  227.         sys.exit(-1)
  228.     
  229.     reslove_file = 0
  230.     reslove_dir = 0
  231.     
  232.     for k,in opts:
  233.         if k == '-f':
  234.             reslove_file = v
  235.             print reslove_file
  236.         elif k == '-d':
  237.             reslove_dir = v
  238.             print reslove_dir
  239.         elif k == '-o':
  240.             target_file = v
  241.             print target_file
  242.         elif k in ('-h','--help'):
  243.             print_help_info()
  244.             sys.exit()
  245.         else:
  246.             print 'Error,unhandled option'
  247.             sys.exit(-1)
  248.     
  249.     set_default_conf()

  250.     if(reslove_file):
  251.         handle_file(reslove_file)
  252.     if(reslove_dir):
  253.         #文件夹支持
  254.         pass

  255.     #print print_symbol
  256.     #解析define以及struct
  257.     reslove_each_define()
  258.     reslove_each_struct()

  259.     #将解析结果写入文件
  260.     #write_to_file(reslove_file)
 
     代码中注释自认为还是比较详细的,代码也不长,看懂应该没什么问题。
     一共300行左右的代码,花了自己两个晚上看电影的时间,不过如果用C实现,用字符串去解析,那这个工程的复杂性还会增加,由此可见,python在效率(编码 + 调试 + 运行)上还是有一定的优势。

     当然了,代码中也存在不少的问题,而且有一些严重的硬伤,究其愿意还在于用正则的语义去完成词法分析、语法分析的逻辑,还是稍有差别的。
     如果有机会,以后会慢慢完善它;如果谁有一些好的建议,也可以交流~
     
阅读(6178) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~