动态的去掉源代码中的条件编译宏

源代码中有很多的条件宏代码块,在代码发布到客户时,需要根据客户的配置动态去掉未定义的宏代码块,保留已经定义的宏代码块。


源代码中如果有“宏配置文件” 中没有出现过的条件编译宏,则必需保留!


以下代码使用栈结构完成,遇到#ifdef 或者 #ifndef就入栈,遇到#endif 就出栈。


/**********************************************************************
 * strip_macro.c
 *
 * Wang Dongquan <wdq347@163.com>
 * Time-stamp: <>
 * Description:
 *
 * strip undefined macro parts according to config_macro file
 *
 * gcc - O2 - W - Wall strip_macro.c - o strip_macro
 *
 * 1. config_macro file format is line by line which likes 'variable = value',
 * value must be 'y' or 'n', and 'y' means defined, 'n' means undefined
 *
 * 2. src_file contrains macro parts
 *
 * 3. dst_file is generated by stripping undefined macro parts of src_file
 ***********************************************************************/


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

#define MAX_STACK_LAYER 128
#define MAX_LINE_BUFFER 2048
#define MAX_MACRO_NUMBER 256
#define MAX_MACRO_CHAR 128

/* macro conf */
struct macro_def {
    char macro[MAX_MACRO_CHAR];
    unsigned char len;
    unsigned char defined;
    unsigned short value;
};

enum {
    MACRO_PUSH = 0,
    MACRO_POP,
    MACRO_ELSE,
    MACRO_SIMPLE, 
};

enum {
    MACRO_UNDEFINED = 0,
    MACRO_DEFINED,
    MACRO_IGNORED, 
};

static inline char *pass_space(char *line, int len)
{
    int i = 0;
    for (i = 0;i < len;i++) {
        if (line[i] != ' '
            && line[i] != '\t'
            && line[i] != '\n'
            && line[i] != '\r'
            && line[i] != '\0')
            break;
    }
    return line + i;
}

static inline char *pass_word(char *line, int len)
{
    int i = 0;

    for (i = 0;i < len;i++) {
        if (line[i] == ' '
            || line[i] == '\t'
            || line[i] == '\n'
            || line[i] == '\r'
            || line[i] == '\0')
            break;
    }
    return line + i;
}

static int line_word(char *line, int len, char **word, int *word_len)
{
    char *p = line;

    *word_len = 0;
    p = pass_space(line, len);
    if (p > line + len)
        return -1;

    *word = p;
    p = pass_word(p, line + len - p);
    if (p > line + len)
        return -1;
    *word_len = p - *word;
    return 0;
}

static void usage()
{
    printf("strip_macro config_file src_file dst_file\n");
    printf("config_file: file format is line by line which likes 'variable = value'\n");
    printf("src_file   : source file including variable macros defined or undefined in config_file\n");
    printf("dst_file   : output file stripped according to config_file\n");
}

static int config_macro(FILE *conf, struct macro_def **macro)
{
    char *p = NULL;
    char line[MAX_LINE_BUFFER];
    int i = 0, len = 0;

    char *v = NULL, *vv = NULL;
    int v_len = 0, vv_len = 0;

    while (fgets(line, MAX_LINE_BUFFER, conf)) {
        len = strlen(line);
        p = pass_space(line, len);
        if (p >= line + len)
            continue;
        if (*p == '#')
            continue;
        p = strchr(line, '=');
        if (p == NULL)
            continue;
        *p = '\0';
        line_word(line, len, &v, &v_len);
        line_word(p + 1, line + len - p - 1, &vv, &vv_len);
        if (v_len > 0 && vv_len > 0 && v && vv) {
            macro[i] = (struct macro_def *)calloc(1, sizeof(struct macro_def));
            if (macro[i] == NULL)
                return -1;
            strncpy(macro[i]->macro, v, v_len);
            macro[i]->len = v_len;
            if (*vv == 'y')
                macro[i]->defined = MACRO_DEFINED;
            else
                macro[i]->defined = MACRO_UNDEFINED;
            if (++i > MAX_MACRO_NUMBER)
                return -1;
        }
    }
    return 0;
}

static int judge_macro_var(char *var, int var_len, struct macro_def **macro)
{
    int defined = MACRO_IGNORED, i = 0;

    for (i = 0;macro[i] != NULL;i++) {
        if (var_len == macro[i]->len && memcmp(var, macro[i]->macro, var_len) == 0) {
            defined = macro[i]->defined;
            break;
        }
    }

    return defined;
}

static int judge_macro(char *def, int def_len, char *var, int var_len, struct macro_def **macro, int *defined)
{
    int ret = MACRO_SIMPLE;

    if ((def_len == sizeof("#ifdef") - 1)
        && memcmp(def, "#ifdef", sizeof("#ifdef") - 1) == 0) {
        *defined = judge_macro_var(var, var_len, macro);
        ret = MACRO_PUSH;
    }
    else if ((def_len == sizeof("#ifndef") - 1)
        && memcmp(def, "#ifndef", sizeof("#ifndef") - 1) == 0) {
        *defined = judge_macro_var(var, var_len, macro);
        if (*defined != MACRO_IGNORED)
            *defined = ((*defined == MACRO_DEFINED) ? MACRO_UNDEFINED : MACRO_DEFINED);
        ret = MACRO_PUSH;
    }
    else if ((def_len == sizeof("#endif") - 1)
        && memcmp(def, "#endif", sizeof("#endif") - 1) == 0) {
        ret = MACRO_POP;
    }
    else if ((def_len == sizeof("#else") - 1)
        && memcmp(def, "#else", sizeof("#else") - 1) == 0) {
        ret = MACRO_ELSE;
    }

    return ret;
}


static void judge_printf_line(FILE *dst, char *line, char *stack, int curr_stack, int simple_string)
{
    int i = 0;

    if (simple_string == 1
        || stack[curr_stack] == MACRO_IGNORED) {
        for (i = 1;i <= curr_stack;i++) {
            if (stack[i] == MACRO_UNDEFINED)
                break;
        }
        if (i > curr_stack)
            fprintf(dst, "%s", line);
    }
}


static int strip_macro(struct macro_def **macro, FILE *src, FILE *dst)
{
    int ret = 0, defined = MACRO_IGNORED;

    char line[MAX_LINE_BUFFER];
    int len = 0;

    char *def = NULL, *var = NULL;
    int def_len = 0, var_len = 0;

    char stack[MAX_STACK_LAYER];
    int curr_stack = 0;

    while (fgets(line, MAX_LINE_BUFFER, src)) {
        len = strlen(line);
        if (line_word(line, len, &def, &def_len))
            return -1;
        if (line_word(def + def_len, line + len - def - def_len, &var, &var_len))
            return -1;

        ret = judge_macro(def, def_len, var, var_len, macro, &defined);
        switch (ret) {
        case MACRO_PUSH:
            if (curr_stack >= MAX_STACK_LAYER - 1)
                return -1;
            stack[++curr_stack] = defined;
            judge_printf_line(dst, line, stack, curr_stack, 0);
            break;

        case MACRO_POP:
            judge_printf_line(dst, line, stack, curr_stack, 0);
            curr_stack--;
            break;

        case MACRO_ELSE:
            judge_printf_line(dst, line, stack, curr_stack, 0);
            if (stack[curr_stack] != MACRO_IGNORED)
                stack[curr_stack] =
                    ((stack[curr_stack] == MACRO_DEFINED) ? MACRO_UNDEFINED : MACRO_DEFINED);
            break;

        default:
            judge_printf_line(dst, line, stack, curr_stack, 1);
            break;
        }
    }

    return 0;
}


int main(int argc, char *argv[])
{
    int ret = -1;
    struct macro_def **macro = NULL;
    FILE *conf = NULL, *src = NULL, *dst = NULL;

    if (argc != 4) {
        usage();
        return -1;
    }

    conf = fopen(argv[1], "r");
    if (conf == NULL)
        goto end;

    src = fopen(argv[2], "r");
    if (src == NULL)
        goto end;

    dst = fopen(argv[3], "w+");
    if (dst == NULL)
        goto end;

    macro = (struct macro_def **)calloc(MAX_MACRO_NUMBER, sizeof(struct macro_def *));
    if (macro == NULL)
        goto end;

    /* get all config macros */
    ret = config_macro(conf, macro);
    if (ret != 0) {
        ret = -1;
        goto end;
    }

    ret = strip_macro(macro, src, dst);
    
end:
    if (conf)
        fclose(conf);
    if (src)
        fclose(src);
    if (dst)
        fclose(dst);

    if (macro) {
        int i = 0;
        for (i = 0;i < MAX_MACRO_NUMBER;i++) {
            if (macro[i])
                free(macro[i]);
            else
                break;
        }
        free(macro);
    }
    return ret;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 计算VHDL源代码行数的工具是一种用于统计代码行数的辅助工具。它可以帮助开发人员快速准确地计算出VHDL源代码的行数,以便于代码审核、性能优化、代码量统计等工作。 计算VHDL源代码行数的工具一般采用以下步骤: 1. 文件读取:该工具可以读取VHDL源代码文件,通常以.vhd为后缀。读取文件的方式可以通过命令行参数或文件选择对话框来实现,用户可以根据需要进行选择。 2. 代码过滤:读取文件后,工具会对源代码进行过滤操作,筛选出有效的代码行。例如,过滤掉注释、空行以及预处理指令等行,只保留执行指令的代码行。 3. 统计行数:经过过滤后,工具会统计有效代码行的数量,并将结果输出。可以根据用户需求,输出总行数、语句行数、函数定义行数等不同的统计信息。 4. 错误处理:在处理源代码时,工具还需要考虑到错误情况的处理。例如,文件不存在、文件格式错误等情况都需要进行适当的提示和处理。 计算VHDL源代码行数的工具可以提高开发效率,帮助开发人员更好地管理代码量,评估项目进度,优化代码结构等。同时,它也可以帮助团队领导或技术经理进行代码审查,评估代码质量。 总之,计算VHDL源代码行数的工具是一种简单实用的开发辅助工具,能够方便地帮助开发人员进行代码统计和质量评估。 ### 回答2: 计算VHDL的源代码行数是一项对于代码量统计的工作。可以采用以下方法实现: 1. 通过编程语言,例如Python,找到VHDL源代码文件所在的目录。 2. 遍历目录的文件,筛选出以".vhd"或".vhdl"为扩展名的文件。 3. 逐行读取文件内容,并进行行数统计。可以使用文件读取的函数,例如open()和readlines()。 4. 排除注释行和空行的统计。可以通过判断行的开头字符是否为注释符号(如"--")或行的内容是否为空来实现。 5. 统计完成后,输出结果。可以使用print()函数将结果打印出来,或者将结果保存到文件。 此外,为了使统计更加准确,还可以考虑以下问题: - 是否对文件夹进行递归遍历,以统计嵌套文件夹的代码行数。 - 是否需要排除特定的文件或文件夹,例如测试文件或版本控制文件夹。 - 如何处理多行注释,以确保统计的准确性。 需要注意的是,该方法只统计源代码的行数,不包括空行、注释和其他无关信息的行数。对于某些特殊情况,例如使用展开或条件编译等,可能需要特殊处理。 ### 回答3: 计算VHDL源代码行数工具可以帮助程序员快速统计VHDL代码的行数,便于代码管理和项目进度评估。 实现这个工具的方法有几种。一种简单的方法是使用脚本语言编写一个程序,遍历代码文件的每一行,并计算非空行的数量。这个程序可以使用Python或者其他脚本语言编写。具体步骤如下: 1. 遍历指定文件夹下的所有VHDL源代码文件。 2. 对于每个文件,逐行读取代码内容。 3. 对于每一行,去除前后的空格和注释,并判断是否为空行。 4. 如果不是空行,则计数器加1。 5. 统计完成后,输出总行数。 另一种方法是使用专门的工具,例如GNU wc命令。该命令可用于统计文件的字节数、代码行数等。使用该命令统计VHDL代码行数的命令如下: ```shell wc -l *.vhdl ``` 该命令会统计当前文件夹下所有扩展名为.vhdl的文件的代码行数,并输出总行数。 无论是使用自编写的脚本程序还是GNU wc命令,都可以有效地计算VHDL源代码行数,提高代码管理和项目进度评估的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值