📄 metrules.c
字号:
length = function.operator_length + function.operand_length; vocabulary = unique_operators + unique_operands; intelligence = level * volume + ROUND; lang_level = level * level * volume; is_logic = FALSE; } is_within_function = FALSE; update_module_stats(do_halstead, volume, level, effort, length, vocabulary, intelligence, lang_level); /* Do not just print summaries and there is at least one metric to print for a function. */ if (!summaries_only && print_fcn) print_function_summary(csv, do_halstead, volume, level, effort, length, vocabulary, intelligence, lang_level); if (function.gotos > 0) warn(W_GOTO, function.gotos, NUMBER(function.gotos)); if (function.continues > 0) warn(W_CONTINUE, function.continues, NUMBER(function.continues)); if (function.returns > 1) warn(W_RETURNS, function.returns); } /* Only apply these rules if calculating Halstead metrics. */ if (do_halstead) { /* Before an initializer in a function? */ if (is_within_function && stm.before_initializer) { ++function.operand_length; add_term(&operand_vocabulary, last_declarator()); is_logic = TRUE; } /* Past the declarations in a compound statement? */ if (stm.after_compound_declarations) is_logic = TRUE; /* End of an initializer or beginning of a compound block? */ if ((is_within_function && stm.after_initializer) || stm.before_compound_declarations) is_logic = FALSE; /* Count and record terms for Halstead metrics. */ if (is_logic) { if (grm.is_identifier || grm.is_type_name || grm.is_constant || grm.is_string) { ++function.operand_length; add_term(&operand_vocabulary, token()); } else if (keyword("break") || keyword("case") || keyword("continue") || keyword("default") || keyword("do") || keyword("else") || keyword("for") || keyword("goto") || keyword("if") || keyword("return") || keyword("sizeof") || keyword("switch") || keyword("while") || (grm.is_operator && !(oper("}") || oper(")") || oper("]")))) { ++function.operator_length; add_term(&operator_vocabulary, token()); } } /* Halstead says that labels are just to be considered comments, so "uncount" them. */ if (is_logic && stm.is_label) { /* Decrement length for both the label's identifier and colon. */ --function.operand_length; --function.operator_length; /* Decrement term count. If these were the only instances of the label's identifier and colon, remove them from the vocabulary table. */ if (--lookup_term(operand_vocabulary, last_identifier())->count == 0) remove_term(&operand_vocabulary, last_identifier()); if (--lookup_term(operator_vocabulary, ":")->count == 0) remove_term(&operator_vocabulary, ":"); } } /* At the end of each executable statement, record depth statistics. */ if (stm.end && !stm.is_decl) record_stat(&function.max_depth, stm.depth); /* Remember if line found with mixed indention (spaces and tabs). */ if (lin.is_mixed_indent) mixed_indent_lines = TRUE; /* Print warning if a line contains more than one statement. */ if (lin.statements > 0) warn(W_MULT_STATEMENTS, lin.statements + 1); /* Count compound statements to later subtract from high-statement total. This is because compound statements are counted as high-level statements in fcn.high, but SPR code-counting rules do not consider them to be statements, so they have to be subtracted back out when reporting executable statements. */ if (stm.is_comp) ++function.comp; /* Count (goto) labels because the SPR code-counting rules consider them to be executable statements. (Curiously, Halstead considers labels to be merely comments.) */ if (stm.is_label) ++function.label; /* Count empty statements, i.e., ";". According to Capers Jones, SPR does not consider this C anomoly to be a "statement" in its code-counting rules. Subtract from total later because fcn.low includes empty expressions. */ if (stm.is_empty_expr) ++function.empty_expr; /* Count gotos, continues, and returns. */ if (keyword("goto")) ++function.gotos; if (keyword("continue")) ++function.continues; if (keyword("return")) ++function.returns; /* Record identifier statistics at the function and module level. */ if (grm.is_identifier) { unsigned str_len = strlen(this_identifier()); record_stat(&function.idents, str_len); record_stat(&module.idents, str_len); } /* If character encountered that is not in Standard C's source character set, print warning. */ if (lex.nonstandard) warn(W_NONSTANDARD, lex.nonstandard);}/* Tell user how to use Metre and interpret its output. */static void print_help(void){ int i; unsigned column; out("-%c Summaries only " "-%c Halstead metrics\n", SUMMARY_OPT_CHAR, HALSTEAD_OPT_CHAR); out("-%c Adjust function points " "-%cN Stroud number [%d]\n", ADJUST_FP_OPT_CHAR, STROUD_OPT_CHAR, DEFAULT_STROUD_NUMBER); out("-%c Comma-separated-value " "-%cxxx Select specific metric\n", CSV_OPT_CHAR, SELECT_METRIC_OPT_CHAR); out("\nNotation and Abbreviations:\n"); out("< Minimum "); out("Cyclomatic Cyclomatic Complexity\n"); out("> Maximum "); out("Max Depth Max control-structure depth\n"); out("~ Average "); out("Exec Executable\n"); out("(nothing) Total "); out("Decl Declaration\n"); out("Lang Language "); out("PP Preprocessor\n"); column = out("\nFor -%c option: ", SELECT_METRIC_OPT_CHAR); for (i = 0; i < DIM_OF(metric); ++i) { if (column + strlen(metric[i].name) + 1 >= OUTPUT_WIDTH) { out("\n"); column = 0; } column += out("%s ", metric[i].name); } out("\n");}/* Mark which metrics to print in the metric[] array. */static BOOLEAN mark_metrics_to_print(void){ static BOOLEAN metric_selected_to_print = FALSE; int i, j; int arg_count = argc(); char **arg_values = argv(); /* Start off assuming that no metrics are to be printed. */ for (j = 0; j < DIM_OF(metric); ++j) metric[j].print = FALSE; for (i = 1; i < arg_count; ++i) if (strchr(OPT_INTRO_CHARS, arg_values[i][0]) != NULL && arg_values[i][OPTION_START] == SELECT_METRIC_OPT_CHAR) { for (j = 0; j < DIM_OF(metric); ++j) if (strcmp(metric[j].name, &arg_values[i][OPTION_STRING_START]) == 0) { metric[j].print = TRUE; metric_selected_to_print = TRUE; break; } if (j == DIM_OF(metric)) warn(W_BAD_METRIC, &arg_values[i][OPTION_STRING_START]); } /* If no metrics explicitly selected to print, print all metrics. */ if (!metric_selected_to_print) for (j = 0; j < DIM_OF(metric); ++j) metric[j].print = TRUE; return metric_selected_to_print;}/* Determine whether whole sections are to be printed. */static void mark_sections_to_print(BOOLEAN *print_fcn, BOOLEAN *print_mod_fcn, BOOLEAN *print_mod, BOOLEAN *print_prj_fcn, BOOLEAN *print_prj_mod, BOOLEAN *print_prj){ int i; /* Function metrics. */ *print_fcn = FALSE; for (i = 0; i < DIM_OF(metric); ++i) if (metric[i].print && metric[i].fcn) { *print_fcn = TRUE; break; } /* Function-related module metrics. */ *print_mod_fcn = FALSE; for (i = 0; i < DIM_OF(metric); ++i) if (metric[i].print && metric[i].mod_fcn) { *print_mod_fcn = TRUE; break; } /* Module-related module metrics. */ *print_mod = FALSE; for (i = 0; i < DIM_OF(metric); ++i) if (metric[i].print && metric[i].mod) { *print_mod = TRUE; break; } /* Function-related project metrics. */ *print_prj_fcn = FALSE; for (i = 0; i < DIM_OF(metric); ++i) if (metric[i].print && metric[i].prj_fcn) { *print_prj_fcn = TRUE; break; } /* Module-related project metrics. */ *print_prj_mod = FALSE; for (i = 0; i < DIM_OF(metric); ++i) if (metric[i].print && metric[i].prj_mod) { *print_prj_mod = TRUE; break; } /* Project-related project metrics. */ *print_prj = FALSE; for (i = 0; i < DIM_OF(metric); ++i) if (metric[i].print && metric[i].prj) { *print_prj = TRUE; break; }}/* Return whether to print the indicated metric. */static BOOLEAN print_metric(enum metric_type type){ BOOLEAN print_it = TRUE; int i; for (i = 0; i < DIM_OF(metric); ++i) if (metric[i].type == type) print_it = metric[i].print; return print_it;}/* Initialize project-level statistics. */static void init_project_stats(BOOLEAN do_halstead){ init_stat(&project.function.decisions); init_stat(&project.function.conditions); if (do_halstead) { init_stat(&project.function.length); init_stat(&project.function.vocabulary); init_stat(&project.function.volume); init_stat(&project.function.level); init_stat(&project.function.effort); init_stat(&project.function.intelligence); init_stat(&project.function.lang_level); } init_stat(&project.function.lines); init_stat(&project.function.code_lines); init_stat(&project.function.comment_lines); init_stat(&project.function.white_lines); init_stat(&project.function.decls); init_stat(&project.function.stmnts); init_stat(&project.function.max_depth); init_stat(&project.module.lines); init_stat(&project.module.code_lines); init_stat(&project.module.comment_lines); init_stat(&project.module.white_lines); init_stat(&project.module.decls); init_stat(&project.module.stmnts); init_stat(&project.module.pp); init_stat(&project.module.funcs); init_stat(&project.idents); project.modules = 0;}/* Print project summary. */static void print_project_summary(BOOLEAN csv, BOOLEAN print_prj_fcn, BOOLEAN print_prj_mod, BOOLEAN print_prj, BOOLEAN do_halstead, BOOLEAN adjust_function_points){ /* Executable + declaration + preprocessor statements. For function-point backfiring. */ float total_statements; /* Backfired function points. */ float function_points; out(csv ? "" : "\n****************************************************"); out(csv ? "prj" : "\n\nProject Summary\n"); /* Only print function-related stats if at least one function and there is at least one function-related metric to print for the project. */ if (tot_stat(&project.module.funcs) != 0 && print_prj_fcn) { out(csv ? "" : " -Function-\n"); if (print_metric(cyc)) out(csv ? ",%lu,%lu,%lu" : " Cyclomatic: <%lu >%lu ~%lu\n", min_stat(&project.function.decisions) + 1, max_stat(&project.function.decisions) + 1, avg_stat(&project.function.decisions) + 1); if (print_metric(exc)) out(csv ? ",%lu,%lu,%lu" : " Extended: <%lu >%lu ~%lu\n", min_stat(&project.function.conditions) + 1, max_stat(&project.function.conditions) + 1, avg_stat(&project.function.conditions) + 1); if (do_halstead) { if (print_metric(pln)) out(csv ? ",%lu,%lu,%lu" : " Halstead Length: <%lu >%lu ~%lu\n", min_stat(&project.function.length), max_stat(&project.function.length), avg_stat(&project.function.length)); if (print_metric(pvc)) out(csv ? ",%lu,%lu,%lu" : " Vocabulary: <%lu >%lu ~%lu\n", min_stat(&project.function.vocabulary), max_stat(&project.function.vocabulary), avg_stat(&project.function.vocabulary)); if (print_metric(pvl)) out(csv ? ",%lu,%lu,%lu" : " Volume: <%lu >%lu ~%lu\n", min_stat(&project.function.volume), max_stat(&project.function.volume), avg_stat(&project.function.volume)); if (print_metric(plv)) out(csv ? ",%.3f,%.3f,%.3f" : " Level: <%.3f >%.3f ~%.3f\n", min_stat(&project.function.level) / 1000.0, max_stat(&project.function.level) / 1000.0, avg_stat(&project.function.level) / 1000.0); if (print_metric(pef)) out(csv ? ",%lu,%lu,%lu" : " Effort: <%lu >%lu ~%lu\n", min_stat(&project.function.effort), max_stat(&project.function.effort), avg_stat(&project.function.effort)); if (print_metric(inc)) out(csv ? ",%lu,%lu,%lu" : " Intelligence: <%lu >%lu ~%lu\n", min_stat(&project.function.intelligence), max_stat(&project.function.intelligence), avg_stat(&project.function.intelligence)); if (print_metric(ptm)) out(csv ? ",%.1f,%.1f,%.1f,%.1f" : " Time (hours): <%.1f >%.1f ~%.1f %.1f\n", min_stat(&project.function.effort) / moments_per_hour, max_stat(&project.function.effort) / moments_per_hour, avg_stat(&project.function.effort) / moments_per_hour, tot_stat(&project.function.effort) / moments_per_hour); if (print_metric(llv)) out(csv ? ",%.2f,%.2f,%.2f" : " Lang Level: <%.2f >%.2f ~%.2f\n", min_stat(&project.function.lang_level) / 100.0, max_stat(&project.function.lang_level) / 100.0, avg_stat(&project.function.lang_level) / 100.0); } if (print_metric(scl))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -