计算C函数的源代码长度

问题描述 投票:1回答:2

我想为大学课程部分自动化C代码(ANSI C99)的分级。我想要计算的一个属性是每个C函数的行数(可选择排除空白和注释行)。

我知道有几个工具可以过滤出文件中的空白行和注释行,但这只能解决我的一半问题。我想分离属于单个C函数的行。

我被告知正则表达式不起作用。有没有一种聪明的方法来使用gcc预处理器?

c function c-preprocessor
2个回答
3
投票

Clang有一个用于打印语法树的开关。

例如,如果我跑

clang -Xclang -ast-dump -fsyntax-only lc.c 

lc.c:

int main()
{


}

void f()
{
}

我明白了:

...
|-FunctionDecl 0x558d2c812890 <lc.c:1:1, line:5:1> line:1:5 main 'int ()'
| `-CompoundStmt 0x558d2c812970 <line:2:1, line:5:1>
 `-FunctionDecl 0x558d2c8129c8 <line:7:1, line:9:1> line:7:6 f 'void ()'
   `-CompoundStmt 0x558d2c812a68 <line:8:1, line:9:1>

如果你编写一个脚本,从那些以CompoundStmt(FunctionDecl + CompoundStmt ==函数定义)开头的深度= 1 FunctionDecl中提取行号并减去​​它们,你得到的函数的行长减去1。

预处理器只不过是一个标记器。你需要一个合适的解析器。


0
投票

您可以通过两个步骤解决此问题:

  • 编写一个可以删除注释的C解析器
  • 使用此解析器检测函数名称和主体并计算有意义的代码行。你应该考虑空白行和由括号和标点符号组成的行无意义({{,; ......)。这将使您的计数减少程序员使用的编码风格。

这是第一步的帮助:一个剥离注释的解析器:

/* strip C comments by chqrlie */

#include <errno.h>
#include <stdio.h>
#include <string.h>

/* read the next byte from the C source file, handing escaped newlines */
int getcpp(FILE *fp, int *lineno_p) {
    int ch;
    while ((ch = getc(fp)) == '\\') {
        if ((ch = getc(fp)) != '\n') {
            ungetc(ch, fp);
            return '\\';
        }
        *lineno_p += 1;
    }
    if (ch == '\n')
        *lineno_p += 1;
    return ch;
}

int main(int argc, char *argv[]) {
    FILE *fp = stdin, *ft = stdout;
    const char *filename = "<stdin>";
    int ch, lineno;

    if (argc > 1) {
        if ((fp = fopen(filename = argv[1], "r")) == NULL) {
            fprintf(stderr, "Cannot open input file %s: %s\n",
                    filename, strerror(errno));
            return 1;
        }
    }
    if (argc > 2) {
        if ((ft = fopen(argv[2], "w")) == NULL) {
            fprintf(stderr, "Cannot open output file %s: %s\n",
                    argv[2], strerror(errno));
            return 1;
        }
    }
    lineno = 1;
    while ((ch = getcpp(fp, &lineno)) != EOF) {
        int startline = lineno;
        if (ch == '/') {
            if ((ch = getcpp(fp, &lineno)) == '/') {
                /* single-line comment */
                while ((ch = getcpp(fp, &lineno)) != EOF && ch != '\n')
                    continue;
                if (ch == EOF) {
                    fprintf(stderr, "%s:%d: unterminated single line comment\n",
                            filename, startline);
                    break;
                }
                putc('\n', ft);  /* replace comment with newline */
                continue;
            }
            if (ch == '*') {
                /* multi-line comment */
                int lastc = 0;
                while ((ch = getcpp(fp, &lineno)) != EOF) {
                    if (ch == '/' && lastc == '*') {
                        break;
                    }
                    lastc = ch;
                }
                if (ch == EOF) {
                    fprintf(stderr, "%s:%d: unterminated comment\n",
                            filename, startline);
                    break;
                }
                putc(' ', ft);  /* replace comment with single space */
                continue;
            }
            putc('/', ft);
            /* keep parsing to handle n/"a//"[i] */
        }
        if (ch == '\'' || ch == '"') {
            int sep = ch;
            const char *const_type = (ch == '"') ? "string" : "character";

            putc(sep, ft);
            while ((ch = getcpp(fp, &lineno)) != EOF) {
                putc(ch, ft);
                if (ch == sep)
                    break;;
                if (ch == '\\') {
                    if ((ch = getcpp(fp, &lineno)) == EOF)
                        break;
                    putc(ch, ft);
                }
                if (ch == '\n') {
                    fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
                            filename, lineno - 1, const_type);
                    /* This is a syntax error but keep going as if constant was terminated */
                    break;
                }
            }
            if (ch == EOF) {
                fprintf(stderr, "%s:%d: unterminated %s constant\n",
                        filename, startline, const_type);
                break;
            }
            continue;
        }
        putc(ch, ft);
    }
    if (fp != stdin)
        fclose(fp);
    if (ft != stdout)
        fclose(ft);
    return 0;
}
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.