【问题标题】:Using regular expressions in python to determine C++ functions and their parameters在python中使用正则表达式来确定C++函数及其参数
【发布时间】:2011-07-31 10:47:55
【问题描述】:

所以我在这个 python 脚本中做错了,但它变得令人费解,我忘记了我做错了什么。

我想要一个脚本遍历一个文件,找到所有的函数定义,然后拉出函数的名称、返回类型、参数,输出一个“doxygen”风格的注释,如下所示:

/******************************************************************************/
  /*!
    \brief
      Main function for the file

    \return
      The exit code for the program
  */
/******************************************************************************/

但是我在尝试解析参数时对正则表达式做错了......这是到目前为止的脚本:

import re
import sys

f = open(sys.argv[1])

functions = []

for line in f:
  match = re.search(r'([\w]+)\s+([\S]+)\(([\w+\s+\w+])+\)',line)
  if line.find("\\fn") < 0:
    if match:
      returntype = match.group(1)
      funcname = match.group(2)
      print '/********************************************************************'
      print "  \\fn " + match.group()
      print ''
      print '  \\brief'
      print '    Function description for ' + funcname
      print ''
      if len(match.groups()) > 2:
        params = []
        count = len(match.groups()) - 2
        while count > 0:
          matchingstring = match.group(count + 2)
          if matchingstring.find("void") < 0:
            params.append(matchingstring)
          count -= 1
        for parameter in params:
          print "  \\param " + parameter
          print '    Description of ' + parameter
          print ''
      print '  \\return'
      print '    ' + returntype
      print '********************************************************************/'
      print ''

任何帮助将不胜感激。谢谢

【问题讨论】:

  • 出了什么问题?有什么症状?
  • 你不应该为此使用解析器吗?
  • C++ 源代码不能很好地与正则表达式配合使用。尝试查看返回指向成员函数类型的函数的签名。为什么不直接使用 doxygen?它是可定制的。
  • 嗯,是的。我想用doxygen。我只想编写一个脚本,它会为我完成并爆出一些 doxygen cmets 的模板。就问题的“症状”而言,它只是没有正确获取参数,这可能是因为我开始遇到问题并且表达式变得复杂。我想我不太明白如何将多个参数提取到 match.group() 中。无论如何,感谢任何人都可以提供的任何帮助
  • 如果有人有更好的方法建议,也很感兴趣。

标签: c++ python regex parsing doxygen


【解决方案1】:

C++ 的语法过于复杂,无法简单处理 常用表达。您至少需要一个最小的解析器。 我发现对于我不关心的受限情况 一般用 C++,但只有我自己的风格,我经常可以逃脱 带有一个基于 flex 的标记器和一个简单的状态机。这 在许多合法的 C++ 情况下会失败——对于初学者来说, 当然,如果有人使用预处理器来修改语法; 但也因为&lt; 可以有不同的含义,具体取决于 它前面的名称是否为模板。但是很多时候 足以胜任特定工作。

【讨论】:

  • 哇,谢谢,我以前从未见过像 flex 这样的东西。非常感谢。
【解决方案2】:

在尝试进行简单格式解析时,我使用了 PEG 解析器并取得了巨大成功。 pyPeg 是用 Python 编写的这种解析器的一个非常简单的实现。

C++ 函数解析器的 Python 代码示例:

编辑:地址模板参数。经 SK-logic 输入测试,输出正确。

import pyPEG
from pyPEG import parseLine
import re

def symbol(): return re.compile(r"[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&*][\w:]+")
def type(): return symbol
def functionName(): return symbol
def templatedType(): return symbol, "<", -1, [templatedType, symbol, ","], ">"
def parameter(): return [templatedType, type], symbol
def template(): return "<", -1, [symbol, template], ">"
def function(): return [type, templatedType], functionName, -1, template, "(", -1, [",", parameter], ")" # -1 -> zero or more repetitions.


sourceCode = "std::string foobar(std::vector<int> &A, std::map<std::string, std::vector<std::string> > &B)"
results = parseLine(sourceCode, function(), [], packrat=True)

执行时的结果是:

([(u'type', [(u'symbol', 'std::string')]), (u'functionName', [(u'symbol', 'foobar')]), (u'parameter', [(u'templatedType', [(u'symbol', 'std::vector'), (u'symbol', 'int')]), (u'symbol', '&A')]), (u'parameter', [(u'templatedType', [(u'symbol', 'std::map'), (u'symbol', 'std::string'), (u'templatedType', [(u'symbol', 'std::vector'), (u'symbol', 'std::string')])]), (u'symbol', '&B')])], '')

【讨论】:

  • 祝你好运用这个解析模板参数。
  • 授予的 PEG 不能做所有事情,但 OP 的问题是函数参数而不是模板参数。
  • 函数参数和返回值可以是模板实例类型。
  • 如果无法解析所有可能的 C++ 类型,您甚至无法检测函数定义。尝试解析:std::string foobar(std::vector&lt;int&gt; &amp;A, std::map&lt;std::string, std::vector&lt;std::string&gt; &gt; &amp;B)
  • @SK-logic: 只需要最后一个字:)
【解决方案3】:

C++ 不能真正被(正常的)正则表达式解析:一旦涉及到嵌套,它们就是一场噩梦。

还有另一个问题,决定什么时候解析,什么时候不解析。可以声明一个函数:

  • 在文件范围内
  • 在命名空间中
  • 在课堂上

最后两个可以嵌套在任意深度。

我建议在这里使用CLang。它是一个真正的 C++ 前端,带有一个功能齐全的解析器,并且有:

  • 一个 C API,带有(特别是)索引库的 API
  • 基于 C API 的 Python 绑定

C API 和 Python 绑定远未完全公开底层 C++ 模型,但对于像列出函数这样简单的任务来说,这应该足够了。


也就是说,我会质疑该项目的实用性:如果文档可以由简单的解析器生成,那么它与代码是多余的。冗余充其量是无用的,也是最危险的:它引入了不同步的潜在威胁......

如果该函数足够棘手,以至于它的使用需要文档,那么了解限制和其他方面的开发人员必须编写此文档。

【讨论】:

  • 是的。我的意思是,我计划编写实现,但我只是想如果我能写一些东西来为这个文档制定框架,我可以节省一些时间。例如,如果脚本可以确定返回类型、参数等(特别是为了 doxygen),那么我所要做的就是运行并添加对函数正在执行的操作的描述。显然,对于更复杂的功能,我还是需要逐行去判断需要cmet的地方。
  • @罗伯特:啊!知道了。你有花哨的 IDE 吗?我自己不使用 doxygen,但在我看来,许多 IDE 支持自动生成这些骨架。也许您可以为您的 IDE 询问这个问题:)
猜你喜欢
  • 2017-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-15
相关资源
最近更新 更多