Skip to content

php-ffi/preprocessor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

6d4b506 · Dec 17, 2024

History

28 Commits
Dec 17, 2024
Dec 17, 2024
Dec 17, 2024
Dec 16, 2024
Dec 16, 2024
Dec 17, 2024
Dec 17, 2024
Jun 13, 2021
Dec 16, 2024
Jun 13, 2021
Aug 7, 2021
Dec 17, 2024
Dec 17, 2024
Dec 16, 2024

Repository files navigation

Simple C-lang Preprocessor

This implementation of a preprocessor based in part on ISO/IEC 9899:TC2.

Requirements

  • PHP >= 7.4

Installation

Library is available as composer repository and can be installed using the following command in a root of your project.

$ composer require ffi/preprocessor

Usage

use FFI\Preprocessor\Preprocessor;

$pre = new Preprocessor();

echo $pre->process('
    #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;

    #if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE)
        #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
            #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
        #else
            #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
        #endif
    #endif

    VK_DEFINE_HANDLE(VkInstance)
    VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore)
');

//
// Expected Output:
//
//  typedef struct VkInstance_T* VkInstance;
//  typedef uint64_t VkSemaphore;
//

Directives

Supported Directives

  • #include "file.h" local-first include
  • #include <file.h> global-first include
  • #define name defining directives
    • #define name value object-like macro
    • #define name(arg) value function-like macro
    • #define name(arg) xxx##arg concatenation
    • #define name(arg) #arg stringizing
  • #undef name removing directives
  • #ifdef name "if directive defined" condition
  • #ifndef name "if directive not defined" condition
  • #if EXPRESSION if condition
  • #elif EXPRESSION else if condition
  • #else else condition
  • #endif completion of a condition
  • #error message error message directive
  • #warning message warning message directive
  • #line 66 "filename" line and file override
  • #pragma XXX compiler control
    • #pragma once
  • #assert XXX compiler assertion
    • #unassert XXX compiler assertion
  • #ident XXX
    • #sccs XXX

Expression Grammar

Comparison Operators

  • A > B greater than
  • A < B less than
  • A == B equal
  • A != B not equal
  • A >= B greater than or equal
  • A <= B less than or equal

Logical Operators

  • ! A logical NOT
  • A && B conjunction
  • A || B disjunction
  • (...) grouping

Arithmetic Operators

  • A + B math addition
  • A - B math subtraction
  • A * B math multiplication
  • A / B math division
  • A % B modulo
  • A++ increment
    • ++A prefix form
  • A-- decrement
    • --A prefix form
  • +A unary plus
  • -A unary minus
  • &A unary addr
  • *A unary pointer

Bitwise Operators

  • ~A bitwise NOT
  • A & B bitwise AND
  • A | B bitwise OR
  • A ^ B bitwise XOR
  • A << B bitwise left shift
  • A >> B bitwise right shift

Other Operators

  • defined(X) defined macro
  • A ? B : C ternary
  • sizeof VALUE sizeof
    • sizeof(TYPE) sizeof type

Literals

  • true, false boolean
  • 42 decimal integer literal
    • 42u, 42U unsigned int
    • 42l, 42L long int
    • 42ul, 42UL unsigned long int
    • 42ll, 42LL long long int
    • 42ull, 42ULL unsigned long long int
  • 042 octal integer literal
  • 0x42 hexadecimal integer literal
  • 0b42 binary integer literal
  • "string" string (char array)
    • L"string" string (wide char array)
    • "\•" escape sequences in strings
    • "\•••" arbitrary octal value in strings
    • "\X••" arbitrary hexadecimal value in strings
  • 'x' char literal
    • '\•' escape sequences
    • '\•••' arbitrary octal value
    • '\X••' arbitrary hexadecimal value
    • L'x' wide character literal
  • 42.0 double
    • 42f, 42F float
    • 42l, 42L long double
    • 42E exponential form
    • 0.42e23 exponential form
  • NULL null macro

Type Casting

  • (char)42
  • (short)42
  • (int)42
  • (long)42
  • (float)42
  • (double)42
  • (bool)42 (Out of ISO/IEC 9899:TC2 specification)
  • (string)42 (Out of ISO/IEC 9899:TC2 specification)
  • (void)42
  • (long type)42 Casting to a long type (long int, long double, etc)
  • (const type)42 Casting to a constant type (const char, etc)
  • (unsigned type)42 Casting to unsigned type (unsigned int, unsigned long, etc)
  • (signed type)42 Casting to signed type (signed int, signed long, etc)
  • Pointers (void *, etc)
  • References (unsigned int, unsigned long, etc)

Object Like Directive

use FFI\Preprocessor\Preprocessor;
use FFI\Preprocessor\Directive\ObjectLikeDirective;

$pre = new Preprocessor();

// #define A
$pre->define('A');

// #define B 42
$pre->define('B', '42');

// #define С 42
$pre->define('С', new ObjectLikeDirective('42'));

Function Like Directive

use FFI\Preprocessor\Preprocessor;
use FFI\Preprocessor\Directive\FunctionLikeDirective;

$pre = new Preprocessor();

// #define C(object) object##_T* object;
$pre->define('C', function (string $arg) {
    return "${arg}_T* ${arg};";
});

// #define D(object) object##_T* object;
$pre->define('D', new FunctionLikeDirective(['object'], 'object##_T* object'));

Include Directories

use FFI\Preprocessor\Preprocessor;

$pre = new Preprocessor();

$pre->include('/path/to/directory');
$pre->exclude('some');

Message Handling

use FFI\Preprocessor\Preprocessor;

$logger = new Psr3LoggerImplementation();

$pre = new Preprocessor($logger);

$pre->process('
    #error Error message
    // Will be sent to the logger:
    //  - LoggerInterface::error("Error message")
    
    #warning Warning message
    // Will be sent to the logger: 
    //  - LoggerInterface::warning("Warning message")
');