将所有 C 注释打印到单独的文本文件中

将所有 C 注释打印到单独的文本文件中

我想将所有 C 注释打印到单独的文本文件中。

  • 使用 awk、sed、grep 或 bash
  • 输出 /* ... */ 之间的所有多行 C 注释(包含)
  • 带有 // 注释的输出行
  • 可选:打印行号

我尝试了这些解决方案,但在 Ubuntu 上不起作用

我的请求的目的是能够快速使用源代码注释作为良好文档的起点。我不喜欢专用文档程序的额外混乱和专有嵌入式命令(即 Doxygen)。例如,正确注释每个源代码函数并删除表面的一行注释将节省大量时间,并提供近乎完整的参考。这也将鼓励更好的源代码注释。

答案1

已经有很多使用 shell-magic 的答案,但我认为通过使用您可能已经拥有的工具可以更容易地完成。即,海湾合作委员会。

diff -u <(gcc -fpreprocessed -dD -E main.c) main.c | grep '^+' | cut -c 2-

怎么运行的?

  1. gcc -fpreprocessed -dD -E main.c 删除文件中的所有注释并将其放在标准输出上

  2. diff -u <(...) main.c 从 stdout 获取输入并将其与原始数据进行比较

  3. grep '^+' 过滤以 . 开头的所有行+。换句话说:过滤之前确定的评论

  4. cut -c 2-+从输出中 删除符号

不需要超级复杂的正则表达式、perl 或 awk 的东西,同时还涵盖其他答案可能错过的所有边缘情况。

答案2

如果您考虑以下因素,这并不像看起来那么微不足道:puts("string with /*")记住"s 可以出现在 中ch = '"'

或者续行:

printf("...");    /\
* yes, this is a comment */
/\
/ and this as well

或者三字母组

为了解决这些问题,我们可以调整这是对相反问题的回答使其打印而不是删除注释:

perl -0777 -pe '
  s{
    (?<comment>
      # /* ... */ C comments
      / (?<lc> # line continuation
          (?<bs> # backslash in its regular or trigraph form
            \\ | \?\?/
          )
          (?: \n | \r\n?) # handling LF, CR and CRLF line delimiters
        )* \* .*? \* (?&lc)* /
      | / (?&lc)* / (?:(?&lc) | [^\r\n])* # // C++/C99 comments
    ) |
       "(?:(?&bs)(?&lc)*.|.)*?" # "strings" literals
       | '\''(?&lc)*(?:(?&bs)(?&lc)*(?:\?\?.|.))?(?:\?\?.|.)*?'\'' # (w)char literals
       | \?\?'\'' # trigraph form of ^
       | .[^'\''"/?]* # anything else
  }{$+{comment} eq "" ? "" : "$+{comment}\n"}exsg'

在另一个问题中的人为示例中,涵盖了大多数极端情况:

#include <stdio.h>
int main()
{
  printf("%d %s %s %c%c%c%c%c %s %s %d\n",
  1-/* comment */-1,
  /\
* comment */
  "/* not a comment */",
  /* multiline
  comment */
  // comment
  /\
/ comment
  // multiline\
comment
  "// not a comment",
  '"' /* comment */ , '"',
  '\'','"'/* comment */,
  '\
\
"', /* comment */
  "\\
" /* not a comment */ ",
  "??/" /* not a comment */ ",
  '??''+'"' /* "comment" */);
  return 0;
}

给出:

/* comment */
/\
* comment */
/* multiline
  comment */
// comment
/\
/ comment
// multiline\
comment
/* comment */
/* comment */
/* comment */
/* "comment" */

为了获取行号,因为我们在 slurp 模式下运行,其中主题是整个输入,而不是一次处理一行输入,所以有点棘手。我们可以通过使用(?{code})正则表达式运算符在每次找到行分隔符(C 中的 CR、LF 或 CRLF)时增加计数器来做到这一点:

perl -0777 -pe '
  s{
    (?<comment>(?{$l=$n+1})
      /
      (?<lc>  # line continuation
        (?<bs> # backslash in its regular or trigraph form
          \\ | \?\?/
        ) (?<nl>(?:\n|\r\n?) (?{$n++})) # handling LF, CR and CRLF line delimiters
      )*
      (?:
        \* (?: (?&nl) | .)*? \* (?&lc)* / # /* ... */ C comments
        | / (?:(?&lc) | [^\r\n])*         # // C++/C99 comments
      )
    ) |
       "(?:(?&bs)(?&lc)*.|.)*?" # "strings" literals
       | '\''(?&lc)*(?:(?&bs)(?&lc)*(?:\?\?.|.))?(?:\?\?.|.)*?'\'' # (w)char literals
       | \?\?'\'' # trigraph form of ^
       | (?&nl)
       | .[^'\''"/?\r\n]* # anything else
  }{$+{comment} eq "" ? "" : sprintf("%5d %s\n", $l, $+{comment})}exsg'

在同一个样本上给出:

    5 /* comment */
    6 /\
* comment */
    9 /* multiline
  comment */
   11 // comment
   12 /\
/ comment
   14 // multiline\
comment
   17 /* comment */
   18 /* comment */
   21 /* comment */
   26 /* "comment" */

答案3

可以按awk如下方式完成:

#!/bin/awk

# Handles case where both /* and */ are on the same line
{ line_printed = 0; }

# Find the beginning of a multiline comment
/^[[:space:]]*\/\*/ {
    multiline = 1;

    # Remove leading spaces
    sub(/^[[:space:]]+/,"");
    printf "[%d] %s\n", NR, $0;
    line_printed = 1;
}

# Find the end of a multiline comment
/\*\/[[:space:]]*$/ {
    multiline = 0;
    if (line_printed == 0)
        printf "%s", $0;

    print "\n"
    next;
}

# The content between /* and */
{
    if ( multiline == 1 && line_printed == 0 )
    {
        print $0;
        next
    }
}

# A single line comment
/^[[:space:]]*\/\// {
    # Remove leading spaces
    sub(/^[[:space:]]+/,"");
    printf "[%d] %s\n\n", NR, $0;
}

将此脚本保存为foo.awk(或任何其他名称;扩展名是可选的),然后使用awk -f foo.awk input.c.该脚本将打印所有注释(由额外的换行符分隔),并在每个注释之前添加行号。

答案4

更新 2/15/24 - 在学习使用 Raylib 时,我遇到了他们的软件套件中包含的 C“解析器”,它似乎完全符合我的需要,请参阅:https://github.com/raysan5/raylib它还有一个额外的好处,可以查找并很好地格式化所有结构、定义、函数、回调等。

典型例子

Function 232: DrawRectangleRounded() (4 input parameters)
  Name: DrawRectangleRounded
  Return type: void
  Description: Draw rectangle with rounded edges
  Param[1]: rec (type: Rectangle)
  Param[2]: roundness (type: float)
  Param[3]: segments (type: int)
  Param[4]: color (type: Color)

相关内容