Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php C Parser Laravel Package

ircmaxell/php-c-parser

Parse C source files into an AST in PHP (PHP 8.4+), including preprocessing resolution. Use a Context to set #define values (ints, strings, identifiers) before parsing. Great for analysis tools, code inspection, and experimentation.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation: Add the package via Composer:

    composer require ircmaxell/php-c-parser
    

    Ensure your project uses PHP 8.4+ (check php -v and composer.json constraints).

  2. First Parse: Parse a C file into an AST:

    use PHPCParser\CParser;
    
    $parser = new CParser();
    $ast = $parser->parse(__DIR__ . '/path/to/your/file.c');
    

    Verify the AST structure (e.g., print_r($ast) or var_dump($ast)).

  3. Preprocessor Context (Optional): For files with #define directives, create a Context:

    use PHPCParser\Context;
    
    $context = new Context();
    $context->defineInt('DEBUG', 1); // Simulate `#define DEBUG 1`
    $ast = $parser->parse('file.c', $context);
    

Where to Look First

  • AST Structure: Inspect the parsed output to understand node types (e.g., FunctionDefinition, VariableDeclaration). Refer to the package’s internal classes (e.g., PHPCParser\Node\*).
  • Preprocessor Handling: Test with files containing #include, #ifdef, or complex macros to validate directive resolution.
  • Error Cases: Parse invalid C files to observe error handling (e.g., undefined macros, syntax errors).

First Use Case: Extract Function Signatures

$ast = $parser->parse('example.c');
$functions = collect($ast->children())
    ->where(fn ($node) => $node instanceof PHPCParser\Node\FunctionDefinition)
    ->map(fn ($node) => $node->name->toString());

// Output: ["foo", "bar", ...]

Use this to generate PHP FFI bindings or documentation.


Implementation Patterns

Core Workflows

1. Parsing with Dynamic Contexts

  • Use Case: Parse the same file with different preprocessor defines (e.g., for debug/release builds).
  • Pattern:
    $contexts = [
        (new Context())->defineInt('DEBUG', 1),
        (new Context())->defineInt('DEBUG', 0),
    ];
    
    $asts = collect($contexts)->map(fn ($ctx) => $parser->parse('file.c', $ctx));
    
  • Integration Tip: Store contexts in a database or config for reusable builds.

2. AST Traversal with Visitors

  • Use Case: Transform or analyze the AST (e.g., find all buffer allocations).
  • Pattern:
    class BufferAllocationVisitor implements PHPCParser\Visitor {
        public function visitNode(PHPCParser\Node $node) {
            if ($node instanceof PHPCParser\Node\CallExpression) {
                $callee = $node->callee;
                if ($callee->name->toString() === 'malloc') {
                    echo "Found malloc at line {$node->startLine}\n";
                }
            }
            return $node; // Continue traversal
        }
    }
    
    $visitor = new BufferAllocationVisitor();
    $parser->parse('file.c')->accept($visitor);
    
  • Integration Tip: Use Laravel’s service container to bind the visitor for dependency injection.

3. Incremental Parsing

  • Use Case: Parse large codebases (e.g., Linux kernel headers) without memory issues.
  • Pattern:
    $files = glob('src/*.c');
    foreach ($files as $file) {
        $ast = $parser->parse($file);
        // Process AST in chunks or stream results
        yield $ast;
    }
    
  • Integration Tip: Pair with Laravel Queues to process files asynchronously.

4. Code Generation from AST

  • Use Case: Generate PHP wrappers for C functions (e.g., for FFI).
  • Pattern:
    $ast = $parser->parse('lib.c');
    $functions = $ast->children()
        ->filter(fn ($node) => $node instanceof PHPCParser\Node\FunctionDefinition);
    
    foreach ($functions as $func) {
        $ffiType = match ($func->returnType->toString()) {
            'int' => 'int',
            'char*' => 'string',
            default => 'mixed',
        };
        echo "FFI::cdef('{$ffiType} {$func->name}(...);');\n";
    }
    
  • Integration Tip: Store generated code in Laravel’s storage/framework/views or use Blade templates.

Laravel-Specific Patterns

Artisan Commands for CLI Tools

// app/Console/Commands/ParseCHeaders.php
namespace App\Console\Commands;

use Illuminate\Console\Command;
use PHPCParser\CParser;

class ParseCHeaders extends Command {
    protected $signature = 'c:parse {file}';
    protected $description = 'Parse a C file and output its AST';

    public function handle(CParser $parser) {
        $ast = $parser->parse($this->argument('file'));
        $this->info(json_encode($ast, JSON_PRETTY_PRINT));
    }
}

Register in app/Console/Kernel.php:

protected $commands = [
    \App\Console\Commands\ParseCHeaders::class,
];

Service Provider Binding

// app/Providers/AppServiceProvider.php
use Illuminate\Support\ServiceProvider;
use PHPCParser\CParser;

class AppServiceProvider extends ServiceProvider {
    public function register() {
        $this->app->singleton(CParser::class, fn () => new CParser());
    }
}

Testing AST Outputs

// tests/Feature/CParserTest.php
use PHPCParser\CParser;
use Tests\TestCase;

class CParserTest extends TestCase {
    public function testParsesSimpleFunction() {
        $parser = new CParser();
        $ast = $parser->parse(__DIR__ . '/fixtures/simple.c');

        $this->assertInstanceOf(
            PHPCParser\Node\FunctionDefinition::class,
            $ast->children()[0]
        );
    }
}

Gotchas and Tips

Pitfalls

  1. Preprocessor Directive Limits

    • Issue: Complex macros (e.g., recursive or stringifying) may not resolve correctly.
    • Fix: Test with your codebase’s most intricate macros. Fall back to clang -E for preprocessing if needed.
  2. Memory Intensive Parsing

    • Issue: Large files (e.g., linux/kernel.h) may exhaust memory.
    • Fix:
      • Parse incrementally (e.g., per-header file).
      • Use ini_set('memory_limit', '2G') temporarily.
      • Offload to a queue worker.
  3. AST Node Instability

    • Issue: Node classes may change between versions (e.g., PHPCParser\Node\Type renames).
    • Fix: Pin the package version (composer.lock) and abstract node access behind interfaces:
      interface ASTNode {
          public function toString();
      }
      
  4. Undefined Macro Errors

    • Issue: Missing #define directives cause parsing to fail silently or throw exceptions.
    • Fix: Provide a default Context with common macros or validate files pre-parsing:
      try {
          $ast = $parser->parse('file.c', $context);
      } catch (\PHPCParser\Exception $e) {
          $this->handleMissingMacro($e->getMessage());
      }
      
  5. Cross-Platform Path Handling

    • Issue: Windows/Linux path separators (\ vs /) may break file resolution.
    • Fix: Normalize paths:
      $filePath = str_replace('\\', '/', realpath('path/to/file.c'));
      

Debugging Tips

  • Enable Parser Logging:
    $parser = new CParser();
    $parser->setLogger(new \Monolog\Logger('c_parser', [
        new \Monolog\Handler\StreamHandler(storage_path('logs/c_parser.log'))
    ]));
    
  • Compare with Clang: Use clang -cc1 -ast-dump file.c to validate the parser’s AST structure matches expectations.
  • Inspect Node Types: Dump the AST to identify node classes:
    $this->dumpAst($ast);
    private function dumpAst($node, string $indent = '') {
        echo $indent . get_class($node) . "\n";
        foreach ($node->children() as $child) {
            $this->dumpAst($child, $indent . '  ');
        }
    }
    

Extension Points

  1. Custom Node Visitors
    • Extend PHPCParser\Visitor to add domain-specific logic (e.g., security checks):
      class SecurityVisitor implements Visitor {
          public function visitNode(Node $node) {
              if ($node instanceof CallExpression && $node->callee->name === 'memcpy') {
                  $this->flagUnsafeCopy($node);
              }
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity