모든 C 주석을 별도의 텍스트 파일로 인쇄

모든 C 주석을 별도의 텍스트 파일로 인쇄

모든 C 주석을 별도의 텍스트 파일로 인쇄하고 싶습니다.

  • awk, sed, grep 또는 bash를 사용하세요.
  • /* ... */(포함) 사이의 모든 여러 줄 C 주석을 출력합니다.
  • // 주석이 포함된 출력 라인
  • 선택사항: 줄 번호 인쇄

이 솔루션을 시도했지만 Ubuntu에서는 작동하지 않습니다

제가 요청한 목적은 소스 코드 주석을 좋은 문서화의 출발점으로 빠르게 사용할 수 있도록 하는 것입니다. 나는 전용 문서 프로그램(예: Doxygen)의 복잡하고 독점적인 내장 명령을 좋아하지 않습니다. 예를 들어, 각 소스 코드 함수에 적절하게 주석을 달고 피상적인 주석 줄을 제거하면 많은 시간이 절약되고 거의 완전한 참조가 제공됩니다. 이는 또한 더 나은 소스 코드 주석을 장려할 것입니다.

답변1

shell-magic을 사용하면 이미 많은 답변이 있지만 이미 가지고 있는 도구를 사용하면 더 쉽게 할 수 있다고 생각합니다. 즉, GCC입니다.

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

다음 사항을 고려하면 이는 생각만큼 간단하지 않습니다. s가 에 나타날 수 있다는 점을 puts("string with /*")기억하세요 ."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" */

줄 번호를 얻으려면 입력을 한 번에 한 줄씩 처리하는 대신 주제가 전체 입력인 후루룩 소리 모드에서 실행하고 있기 때문에 약간 까다롭습니다. (?{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)

관련 정보