Grep可靠地所有C #defines

时间:2012-06-15 10:24:40

标签: python c regex macros

我需要分析一些C文件并打印出找到的所有#define。 使用正则表达式(例如)

并不难
def with_regexp(fname):
    print("{0}:".format(fname))
    for line in open(fname):
        match = macro_regexp.match(line)
        if match is not None:
            print(match.groups())

但是例如它不处理多行定义。

有一种很好的方法可以在C中执行此操作,例如使用

gcc -E -dM file.c

问题是它返回所有#defines,而不仅仅是给定文件中的#defines,而且我找不到任何只使用给定文件的选项..

任何提示? 感谢

编辑: 这是过滤掉不需要的定义的第一个解决方案,只需检查定义的名称实际上是原始文件的一部分,不完美但似乎很好用..

def with_gcc(fname):
    cmd = "gcc -dM -E {0}".format(fname)
    proc = Popen(cmd, shell=True, stdout=PIPE)
    out, err = proc.communicate()
    source = open(fname).read()
    res = set()

    for define in out.splitlines():
        name = define.split(' ')[1]
        if re.search(name, source):
            res.add(define)

    return res

3 个答案:

答案 0 :(得分:2)

听起来像是一个单一的贝壳工作!

我想要做的是从C文件中删除所有#include(因此我们不会从其他文件中获取垃圾),将其传递给gcc -E -dM,然后删除所有构建的在#define s中 - 以_开头,显然是linuxunix

如果您的#define以下划线开头,则无法完全按照承诺行事。

它是这样的:

sed -e '/#include/d' foo.c | gcc -E -dM - | sed -e '/#define \(linux\|unix\|_\)/d'

你也可以在几行Python中完成它。

答案 1 :(得分:1)

在PowerShell中,您可以执行以下操作:

function Get-Defines {
  param([string] $Path)

  "$Path`:"
  switch -regex -file $Path {
    '\\$' {
      if ($multiline) { $_ }
    }
    '^\s*#define(.*)$' {
      $multiline = $_.EndsWith('\');
      $_
    }
    default {
      if ($multiline) { $_ }
      $multiline = $false
    }
  }
}

使用以下示例文件

#define foo "bar"
blah
#define FOO \
  do { \
    do_stuff_here \
    do_more_stuff \
  } while (0)
blah
blah
    #define X

打印

\x.c:
#define foo "bar"
#define FOO \
  do { \
    do_stuff_here \
    do_more_stuff \
  } while (0)
        #define X

不理想,至少PowerShell函数应该如何工作,但应该能够很好地满足您的需求。

答案 2 :(得分:1)

在纯python中执行此操作我将使用一个小型状态机:

def getdefines(fname):
    """ return a list of all define statements in the file """
    lines = open(fname).read().split("\n") #read in the file as a list of lines
    result = [] #the result list
    current = []#a temp list that holds all lines belonging to a define
    lineContinuation = False #was the last line break escaped with a '\'?

    for line in lines:
        #is the current line the start or continuation of a define statement?
        isdefine = line.startswith("#define") or lineContinuation
        if isdefine:
            current.append(line) #append to current result
            lineContinuation = line.endswith("\\") #is the line break escaped?
            if not lineContinuation:
                #we reached the define statements end - append it to result list
                result.append('\n'.join(current))
                current = [] #empty the temp list

    return result