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.4.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.4-py3-none-any.whl (15.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: halsteadpp-0.1.4.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.4.tar.gz
Algorithm Hash digest
SHA256 4c7501a46789189032ab1ffbda96590ef6560951a79060097fe0170539158db0
MD5 d5362846a06acbd1a2ba71980c06ff93
BLAKE2b-256 555406ef01304e2d8378d8c12e6bb3e2035afccf189739a8d010411064a5c0ca

See more details on using hashes here.

File details

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

File metadata

  • Download URL: halsteadpp-0.1.4-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.4-py3-none-any.whl
Algorithm Hash digest
SHA256 ec7a8a6d76cf675d2941c368ea2c4c69a9900b4a1871495124e0b9fa9537a71c
MD5 5b14d6a23b3b6f7559091d899db9e6a5
BLAKE2b-256 06b4bf918c07eb24e05a1f756bc60faf4eefa7758311c64852e0901e0b3dc236

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