Skip to main content

A Python tool for analyzing C code complexity using Halstead and Cyclomatic metrics.

Project description

Halstead++

A sophisticated Python library for analyzing Halstead complexity metrics of C code through AST parsing, with intelligent operator filtering for more accurate complexity assessment. Introduction

Halstead++ is a specialized static analysis tool that calculates Halstead complexity metrics for C programming language code. Unlike traditional Halstead metric tools, Halstead++ employs intelligent filtering to exclude common syntactic operators that tend to artificially inflate complexity scores, such as semicolons, parentheses, braces, and commas. This results in more accurate and meaningful complexity measurements that better reflect the actual cognitive complexity of the code.

The tool leverages pycparser to generate Abstract Syntax Trees (AST) from preprocessed C code and performs comprehensive analysis at both file and function levels, providing detailed metrics including program vocabulary, volume, difficulty, effort, and estimated bug counts.

Installation

From PyPI

pip install halsteadpp

From Source

git clone https://github.com/Morgadineo/Halsteadpp
cd halsteadpp
pip install -e .

Dependencies

Python >= 3.8

pycparser >= 2.21

rich >= 13.0 (for formatted output)

Usage

Prerequisites: Code Preprocessing

Before using Halstead++, C source files must be preprocessed using the provided Makefile. This step is necessary because Halstead++ uses pycparser which requires preprocessed C code and the fake-headers for the libraries.

Why fake headers are needed:

The code is preprocessed with -nostdinc to avoid platform-specific standard headers. Instead, we use pycparser's fake headers which provide minimal declarations (like int printf(const char*, ...);) without actual implementations.

This makes the parsing portable across different systems (Linux, Windows, macOS).

Using the Makefile

The repository includes a Makefile for easy preprocessing:

Preprocess a specific file

make main.i          # Creates main.i from main.c
make utils.i         # Creates utils.i from utils.c

Preprocess all .c files in current directory

make                 # Or: make preprocess

Preprocess all .c files in a subdirectory

make DIR=src         # Processes all .c files in ./src/
make DIR=Examples    # Processes all .c files in ./Examples/

Clean generated .i files

make clean           # Cleans .i files in current directory
make DIR=src clean   # Cleans .i files in ./src/

Basic Usage

from halsteadpp import ParsedCode

# Analyze a C file (without .c extension)
parser = ParsedCode("example_file", "path/to/preprocessed/code/")

# Display comprehensive complexity metrics
parser.print_complexities()

# Display function-level analysis
parser.print_functions()

Advanced Usage

from halsteadpp import ParsedCode

# Initialize parser for specific file
parser = ParsedCode(
    filename="algorithm",      # File name without extension
    file_dir="src/complex/"    # Directory containing preprocessed .i file
)

# Access metrics directly
print(f"Program Volume: {parser.volume}")
print(f"Estimated Bugs: {parser.delivered_bugs}")
print(f"Cyclomatic Complexity: {parser.total_mcc}")

# Access function-specific metrics
for function in parser.functions:
    print(f"Function: {function.func_name}")
    print(f"  - Halstead Effort: {function.effort}")
    print(f"  - McCabe Complexity: {function.total_mcc}")

Example 1: Simple Analysis

hello.c inside 'Example/' folder:

#include <stdio.h>

int main(void)
{
  printf("Hello, World!\n");
  
  return 0;
}

Pre-compile:

> make

Preprocessing Examples/hello.c...

Basic main.py:

from halsteadpp import ParsedCode

# Analyze a C file
hello_code = ParsedCode('hello', 'Examples/')

# Print table of complexities
hello_code.print_complexities()

Outputs

Complexities Table

Captura de tela de 2025-10-19 15-09-59

Functions complexity

Captura de tela de 2025-10-19 15-11-01

Operators

Captura de tela de 2025-10-19 15-11-45

Operands

Captura de tela de 2025-10-19 15-12-13

Key Features

Intelligent Operator Filtering

Halstead++ excludes the following syntactic operators from complexity calculations:

Semicolons (;)

Parentheses (())

Braces ({})

Commas (,)

This filtering provides more realistic complexity metrics by focusing on meaningful operators that contribute to actual cognitive load.

Comprehensive Metrics

Halstead Metrics: n1, n2, N1, N2, vocabulary, length, volume, difficulty, level, effort, time, bugs

Cyclomatic Complexity: McCabe complexity at function and file levels

Line Metrics: Total lines, effective lines (excluding comments and empty lines)

Function Analysis: Individual metrics for each function

Rich Visual Output

Formatted tables using the Rich library

Color-coded output for better readability

Detailed operator and operand listings

AST-Based Analysis

Accurate parsing using Python's AST capabilities

Support for complex C constructs (pointers, structs, function calls, etc.)

Real node detection to filter out compiler-generated code

Metric Definitions

n1: Number of distinct operators

n2: Number of distinct operands

N1: Total number of operators

N2: Total number of operands

Volume (V): Program size metric: (N1 + N2) × log₂(n1 + n2)

Difficulty (D): Program complexity: (n1 / 2) × (N2 / n2)

Effort (E): Mental effort required: D × V

Bugs (B): Estimated number of delivered bugs: E^(2/3) / 3000

License

MIT License - see LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

halsteadpp-0.1.3.tar.gz (16.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

halsteadpp-0.1.3-py3-none-any.whl (15.3 kB view details)

Uploaded Python 3

File details

Details for the file halsteadpp-0.1.3.tar.gz.

File metadata

  • Download URL: halsteadpp-0.1.3.tar.gz
  • Upload date:
  • Size: 16.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for halsteadpp-0.1.3.tar.gz
Algorithm Hash digest
SHA256 a5bcf52c5fff2e3d48c16dba77cd6499eb4ff1329ac597f919feda8bcfa78580
MD5 1818b167b7274a5146a73c92d555e486
BLAKE2b-256 be3ce08ac447a525f1b08f80611acab8acc9037c56ec6a94c35419d257fe7a6b

See more details on using hashes here.

File details

Details for the file halsteadpp-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: halsteadpp-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 15.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for halsteadpp-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 ff9b7408dc81d53c191bb0dddbaa5aed6b464367f16bb0a1348294ec9879e0f6
MD5 36c1187f0e9af4577bf97bf6fe80a569
BLAKE2b-256 17dc3695490a69694f14dec8a0bcc10474fb1cfd283953b17930005f789d0b43

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page