ffi/preprocessor

简单的C预处理器

0.2.2 2023-08-08 21:26 UTC

This package is auto-updated.

Last update: 2024-09-08 23:50:27 UTC


README

本实现基于部分ISO/IEC 9899:TC2的预处理器。

要求

  • PHP >= 7.4

安装

库作为composer存储库可用,您可以使用以下命令在项目根目录中安装。

$ composer require ffi/preprocessor

用法

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;
//

指令

支持的指令

  • #include "file.h" 本地优先包含
  • #include <file.h> 全局优先包含
  • #define name 定义指令
    • #define name value 对象型宏
    • #define name(arg) value 函数型宏
    • #define name(arg) xxx##arg 连接
    • #define name(arg) #arg 字符串化
  • #undef name 移除指令
  • #ifdef name "指令已定义" 条件
  • #ifndef name "指令未定义" 条件
  • #if EXPRESSION 如果条件
  • #elif EXPRESSION 否则如果条件
  • #else 否则条件
  • #endif 条件完成
  • #error message 错误消息指令
  • #warning message 警告消息指令
  • #line 66 "filename" 覆盖行和文件
  • #pragma XXX 编译器控制
    • #pragma once
  • #assert XXX 编译器断言
    • #unassert XXX 编译器断言
  • #ident XXX
    • #sccs XXX

表达式语法

比较运算符

  • A > B 大于
  • A < B 小于
  • A == B 等于
  • A != B 不等于
  • A >= B 大于等于
  • A <= B 小于等于

逻辑运算符

  • ! A 逻辑非
  • A && B 逻辑与
  • A || B 逻辑或
  • (...) 分组

算术运算符

  • A + B 数学加法
  • A - B 数学减法
  • A * B 数学乘法
  • A / B 数学除法
  • A % B 取模
  • A++ 自增
    • ++A 前缀形式
  • A-- 自减
    • --A 前缀形式
  • +A 一元加
  • -A 一元减
  • &A 一元地址
  • *A 一元指针

位运算符

  • ~A 位非
  • A & B 位与
  • A | B 位或
  • A ^ B 位异或
  • A << B 位左移
  • A >> B 位右移

其他运算符

  • defined(X) 已定义宏
  • A ? B : C 三元
  • sizeof VALUE sizeof
    • sizeof(TYPE) sizeof 类型

字面量

  • true, false 布尔
  • 42 十进制整数字面量
    • 42u, 42U 无符号整型
    • 42l, 42L 长整型
    • 42ul, 42UL 无符号长整型
    • 42ll, 42LL 长长整型
    • 42ull, 42ULL 无符号长长整型
  • 042 八进制整数字面量
  • 0x42 十六进制整数字面量
  • 0b42 二进制整数字面量
  • "string" 字符串(字符数组)
    • L"string" 字符串(宽字符数组)
    • "\•" 字符串中的转义序列
    • "\•••" 字符串中的任意八进制值
    • "\X••" 字符串中的任意十六进制值
  • 'x' 字符字面量
    • '\•' 转义序列
    • '\•••'任意的八进制值
    • '\X••'任意的十六进制值
    • L'x'宽字符字面量
  • 42.0双精度浮点数
    • 42f42F浮点数
    • 42l42L长双精度浮点数
    • 42E指数形式
    • 0.42e23指数形式
  • NULL空宏

类型转换

  • (char)42
  • (short)42
  • (int)42
  • (long)42
  • (float)42
  • (double)42
  • (bool)42(超出ISO/IEC 9899:TC2规范)
  • (string)42(超出ISO/IEC 9899:TC2规范)
  • (void)42
  • (long type)42转换为长类型(long intlong double等)
  • (const type)42转换为常量类型(const char等)
  • (unsigned type)42转换为无符号类型(unsigned intunsigned long等)
  • (signed type)42转换为有符号类型(signed intsigned long等)
  • 指针(void *等)
  • 引用(unsigned intunsigned long等)

对象类指令

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'));

函数类指令

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'));

包含目录

use FFI\Preprocessor\Preprocessor;

$pre = new Preprocessor();

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

消息处理

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")
');