搜索工具从头文件中提取和操作C函数

时间:2018-03-31 17:30:35

标签: c parsing header c-preprocessor function-prototypes

我的问题似乎很简单......

问题:我有一个包含许多原型的头文件......(如示例所示)

...
// some docu...
MQ_EXTERN enum MqErrorE
MQ_DECL MqSlaveWorker (
  struct MqS * const    ctx,
  MQ_NUM const          id,
  MQ_CST                factory,
  struct MqBufferLS **  argsP
);
...

请求:工具生成第二个头文件,其中包含"包裹"原始头文件的定义......

....
#define MqSlaveWorkerE(ctx,id,factory,argsP) \
  MqErrorCheck(MqSlaveWorker(ctx,id,factory,argsP))
....

触发器返回类型 枚举MqErrorE ... 所有使用 return-type 枚举MqErrorE 的原型应该得到一个c-preprocessor-wrapper

2 个答案:

答案 0 :(得分:0)

您可能需要Program Transformation System (PTS)

这些工具可以读取源代码,构建程序的内部表示,并允许您编写源代码转换,这些转换在内部表示上运行以提高效率。当您完成应用转换后,该工具会将内部表示转换回文本并吐出已转换的源代码,即使保留了注释。

除非你的头文件很简单,否则你需要一个实际上有一个完整的C解析器,并且可以准确地捕获你的源代码。否则,它将无法读取您的文件,现在您无处可去。即使这还不够;它必须保留预处理器声明,以便可以操作它们而不是在预处理期间消失。前端还有很多东西;您通常需要名称解析和各种流量分析器。

没有很多具有生产能力的PTS。我们DMS Software Reengineering Toolkit是我所知道的唯一一个(并且我已经做了很长时间的事情),它有一个完整的C Front End,可以保留预处理器命令。

您的任务核心在此DMS重写规则中进行了总结:

rule generate-wrapper(extern: macro_name, decl: macro_name, function_name: IDENTIFIER, a: arguments):
    prototype_declaration)->preprocessor_declaration =
    " \extern enum MqErrorE \decl \function_name ( \a ) " ->
    "#define \generate_derived_macro_name\(\function_name\) (\extract_parameter_name\(\a\) ) \\
       \generate_derived_checker_name\(\function_name\)( (\extract_parameter_name\(\a\) )"

其中generate_derived_macro name,generate_derived_checker_name和extract_parameter_name_list是自定义函数。 generate_derived_macro基于您的示例的名称获取其参数并粘合" E"它。提取参数名称更有意义;它必须采用参数列表的interal(AST),挑选参数名称,并从这些名称构造一个参数列表。 DMS提供了帮助您对此进行编码的机制。

还有更多的工作要做:你实际上想要构建你的错误检查函数(这个重写会这样做),然后将它们混合到一个表示单独头文件的内部表单AST。这需要额外的自定义代码,但DMS可以轻松跟踪多个表示,并可以轻松移动树木。

如果您有50个这样的声明,坦率地说,您可以更好地咬住子弹并手动完成。如果您有数千,DMS可能会为您节省大量时间。 YMMV。

答案 1 :(得分:0)

编程~3h后...解决方案是一个使用了很多的(tcl)脚本 regexp 执行以下步骤...

一个。过滤掉所有通缉代码

湾将想要的代码转换为可用的部分

℃。将这些片段格式化为想要的 #define ... 预处理器代码

步骤1.进行转换

> ./sbin/parse_c_header.tcl
1. 221725 chars after read from 'msgque.h'
2. 221581 chars after '…\n'
2. 107796 chars after '//…$'
3. 57823 chars after '/*…*/'
4. 49701 chars after '{…}'
5. 48303 chars after '{…}'
6. 47839 chars after 'struct…XX…;'
7. 47653 chars after 'enum…XX…;'
8. 40458 chars after '#…'
9. 37707 chars after '\n'
10. 35346 chars after 'typedef…'
11. 35123 chars after 'struct…;'
12. 35053 chars after 'union…;'
13. 32820 chars after '__attribute__…;'
14. 32802 chars after 's+'
15. 32338 chars after '*'
16. 32332 chars after '[]'
17. 24076 chars after '(…,'
18. 20499 chars after ',…)'
19. 20499 chars after ',…,'
20. 17935 chars after '(…)'
21. 17979 chars after '__VA_ARGS__'
22. 17946 chars after 'XX;'
23. 17861 chars after ';'
24. 17861 chars after '…\n'
25. 17500 chars after ';\n'
write: msgqueE.h

步骤2.编写结果

//
//   this file was automatically created by 'sbin/parse_c_header.tcl'
//
//     : do NOT modify it
//
//   this file contains error-protected api-calls of libmsgque
//
//     : error-protected mean that all api-calls who return an 'enum MqErrorE'
//     : get a 'MqErrorCheck' wrapper. This wrapper check for the return code
//     : 'MQ_ERROR' and jump on error to a label called 'error:' to do proper
//     : error handing.
//
//   example: the following line of code..
//
//      > MqErrorCheck ( MqReadU (ctx, &buf));
//
//   can be rewritten with:
//
//      > #include "msgqueE.h"
//      > ...
//      > MqReadUE (ctx, &buf);
//
//
#define        MqConfigSetIoUdsFileE (ctx,file)          MqErrorCheck(MqConfigSetIoUdsFile(ctx,file))
#define            MqConfigSetIoTcpE (myhost,myport)     MqErrorCheck(MqConfigSetIoTcp(myhost,myport))
#define     MqConfigSetIoPipeSocketE (ctx,hdl)           MqErrorCheck(MqConfigSetIoPipeSocket(ctx,hdl))
#define           MqConfigSetDaemonE (ctx,pidfile)       MqErrorCheck(MqConfigSetDaemon(ctx,pidfile))
#define      MqFactoryDefaultCreateE (item,contextP)     MqErrorCheck(MqFactoryDefaultCreate(item,contextP))
#define             MqFactoryCtxSetE (ctx,item)          MqErrorCheck(MqFactoryCtxSet(ctx,item))
#define        MqFactoryCtxIdentSetE (ctx,ident)         MqErrorCheck(MqFactoryCtxIdentSet(ctx,ident))
#define MqCheckForLeftOverArgumentsE (ctx,argvP)         MqErrorCheck(MqCheckForLeftOverArguments(ctx,argvP))
#define               MqStorageOpenE (ctx,storageFile)   MqErrorCheck(MqStorageOpen(ctx,storageFile))
#define              MqStorageCloseE (ctx)               MqErrorCheck(MqStorageClose(ctx))
#define             MqStorageInsertE (ctx,transLIdP)     MqErrorCheck(MqStorageInsert(ctx,transLIdP))
#define             MqStorageSelectE (ctx,transLIdP)     MqErrorCheck(MqStorageSelect(ctx,transLIdP))
#define             MqStorageDeleteE (ctx,transLId)      MqErrorCheck(MqStorageDelete(ctx,transLId))
#define              MqStorageCountE (ctx,countP)        MqErrorCheck(MqStorageCount(ctx,countP))
#define                MqLinkCreateE (ctx,args)          MqErrorCheck(MqLinkCreate(ctx,args))
#define               MqLinkConnectE (ctx)               MqErrorCheck(MqLinkConnect(ctx))
#define           MqLinkCreateChildE (parent,args)       MqErrorCheck(MqLinkCreateChild(parent,args))
#define           MqLinkCreateRouteE (id,argvP)          MqErrorCheck(MqLinkCreateRoute(id,argvP))
#define               MqLinkDefaultE (ctx,args)          MqErrorCheck(MqLinkDefault(ctx,args))
#define               MqLinkGetPathE (ctx,pathP)         MqErrorCheck(MqLinkGetPath(ctx,pathP))
#define               MqLinkGetTreeE (ctx,tree)          MqErrorCheck(MqLinkGetTree(ctx,tree))
...