|
| 1 | +# Simple C-lang Preprocessor |
| 2 | + |
| 3 | +This implementation of a preprocessor based in part on |
| 4 | +[ISO/IEC 9899:TC2](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf). |
| 5 | + |
| 6 | +## Requirements |
| 7 | + |
| 8 | +- PHP >= 8.0 |
| 9 | + |
| 10 | +## Installation |
| 11 | + |
| 12 | +Library is available as composer repository and can be installed using the |
| 13 | +following command in a root of your project. |
| 14 | + |
| 15 | +```sh |
| 16 | +$ composer require ffi/preprocessor |
| 17 | +``` |
| 18 | + |
| 19 | +## Usage |
| 20 | + |
| 21 | +```php |
| 22 | +use FFI\Preprocessor\Preprocessor; |
| 23 | + |
| 24 | +$pre = new Preprocessor(); |
| 25 | + |
| 26 | +echo $pre->process(' |
| 27 | + #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; |
| 28 | + |
| 29 | + #if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE) |
| 30 | + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) |
| 31 | + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; |
| 32 | + #else |
| 33 | + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; |
| 34 | + #endif |
| 35 | + #endif |
| 36 | + |
| 37 | + VK_DEFINE_HANDLE(VkInstance) |
| 38 | + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) |
| 39 | +'); |
| 40 | + |
| 41 | +// |
| 42 | +// Expected Output: |
| 43 | +// |
| 44 | +// typedef struct VkInstance_T* VkInstance; |
| 45 | +// typedef uint64_t VkSemaphore; |
| 46 | +// |
| 47 | +``` |
| 48 | + |
| 49 | +## Directives |
| 50 | + |
| 51 | +### Supported Directives |
| 52 | + |
| 53 | +- [x] `#include "file.h"` local-first include |
| 54 | +- [x] `#include <file.h>` global-first include |
| 55 | +- [x] `#define name` defining directives |
| 56 | + - [x] `#define name value` object-like macro |
| 57 | + - [x] `#define name(arg) value` function-like macro |
| 58 | + - [x] `#define name(arg) xxx##arg` concatenation |
| 59 | + - [x] `#define name(arg) #arg` stringizing |
| 60 | +- [x] `#undef name` removing directives |
| 61 | +- [x] `#ifdef name` "if directive defined" condition |
| 62 | +- [x] `#ifndef name` "if directive not defined" condition |
| 63 | +- [x] `#if EXPRESSION` if condition |
| 64 | +- [x] `#elif EXPRESSION` else if condition |
| 65 | +- [x] `#else` else condition |
| 66 | +- [x] `#endif` completion of a condition |
| 67 | +- [x] `#error message` error message directive |
| 68 | +- [x] `#warning message` warning message directive |
| 69 | +- [ ] `#line 66 "filename"` line and file override |
| 70 | +- [ ] `#pragma XXX` compiler control |
| 71 | + - [ ] `#pragma once` |
| 72 | +- [ ] `#assert XXX` compiler assertion |
| 73 | + - [ ] `#unassert XXX` compiler assertion |
| 74 | +- [ ] `#ident XXX` |
| 75 | + - [ ] `#sccs XXX` |
| 76 | + |
| 77 | +### Expression Grammar |
| 78 | + |
| 79 | +#### Comparison Operators |
| 80 | + |
| 81 | +- [x] `A > B` greater than |
| 82 | +- [x] `A < B` less than |
| 83 | +- [x] `A == B` equal |
| 84 | +- [x] `A != B` not equal |
| 85 | +- [x] `A >= B` greater than or equal |
| 86 | +- [x] `A <= B` less than or equal |
| 87 | + |
| 88 | +#### Logical Operators |
| 89 | + |
| 90 | +- [x] `! A` logical NOT |
| 91 | +- [x] `A && B` conjunction |
| 92 | +- [x] `A || B` disjunction |
| 93 | +- [x] `(...)` grouping |
| 94 | + |
| 95 | +#### Arithmetic Operators |
| 96 | + |
| 97 | +- [x] `A + B` math addition |
| 98 | +- [x] `A - B` math subtraction |
| 99 | +- [x] `A * B` math multiplication |
| 100 | +- [x] `A / B` math division |
| 101 | +- [x] `A % B` modulo |
| 102 | +- [ ] `A++` increment |
| 103 | + - [x] `++A` prefix form |
| 104 | +- [ ] `A--` decrement |
| 105 | + - [x] `--A` prefix form |
| 106 | +- [x] `+A` unary plus |
| 107 | +- [x] `-A` unary minus |
| 108 | +- [ ] `&A` unary addr |
| 109 | +- [ ] `*A` unary pointer |
| 110 | + |
| 111 | +#### Bitwise Operators |
| 112 | + |
| 113 | +- [x] `~A` bitwise NOT |
| 114 | +- [x] `A & B` bitwise AND |
| 115 | +- [x] `A | B` bitwise OR |
| 116 | +- [x] `A ^ B` bitwise XOR |
| 117 | +- [x] `A << B` bitwise left shift |
| 118 | +- [x] `A >> B` bitwise right shift |
| 119 | + |
| 120 | +#### Other Operators |
| 121 | + |
| 122 | +- [x] `defined(X)` defined macro |
| 123 | +- [ ] `A ? B : C` ternary |
| 124 | +- [ ] `sizeof VALUE` sizeof |
| 125 | + - [ ] `sizeof(TYPE)` sizeof type |
| 126 | + |
| 127 | +### Literals |
| 128 | + |
| 129 | +- [x] `true`, `false` boolean |
| 130 | +- [x] `42` decimal integer literal |
| 131 | + - [x] `42u`, `42U` unsigned int |
| 132 | + - [x] `42l`, `42L` long int |
| 133 | + - [x] `42ul`, `42UL` unsigned long int |
| 134 | + - [x] `42ll`, `42LL` long long int |
| 135 | + - [x] `42ull`, `42ULL` unsigned long long int |
| 136 | +- [x] `042` octal integer literal |
| 137 | +- [x] `0x42` hexadecimal integer literal |
| 138 | +- [x] `0b42` binary integer literal |
| 139 | +- [x] `"string"` string (char array) |
| 140 | + - [x] `L"string"` string (wide char array) |
| 141 | + - [x] `"\•"` escape sequences in strings |
| 142 | + - [ ] `"\•••"` arbitrary octal value in strings |
| 143 | + - [ ] `"\X••"` arbitrary hexadecimal value in strings |
| 144 | +- [ ] `'x'` char literal |
| 145 | + - [ ] `'\•'` escape sequences |
| 146 | + - [ ] `'\•••'` arbitrary octal value |
| 147 | + - [ ] `'\X••'` arbitrary hexadecimal value |
| 148 | + - [ ] `L'x'` wide character literal |
| 149 | +- [ ] `42.0` double |
| 150 | + - [ ] `42f`, `42F` float |
| 151 | + - [ ] `42l`, `42L` long double |
| 152 | + - [ ] `42E` exponential form |
| 153 | + - [ ] `0.42e23` exponential form |
| 154 | +- [ ] `NULL` null macro |
| 155 | + |
| 156 | +### Type Casting |
| 157 | + |
| 158 | +- [x] `(char)42` |
| 159 | +- [x] `(short)42` |
| 160 | +- [x] `(int)42` |
| 161 | +- [x] `(long)42` |
| 162 | +- [x] `(float)42` |
| 163 | +- [x] `(double)42` |
| 164 | +- [x] `(bool)42` (Out of ISO/IEC 9899:TC2 specification) |
| 165 | +- [x] `(string)42` (Out of ISO/IEC 9899:TC2 specification) |
| 166 | +- [ ] `(void)42` |
| 167 | +- [ ] `(long type)42` Casting to a long type (`long int`, `long double`, etc) |
| 168 | +- [ ] `(const type)42` Casting to a constant type (`const char`, etc) |
| 169 | +- [ ] `(unsigned type)42` Casting to unsigned type (`unsigned int`, `unsigned long`, etc) |
| 170 | +- [ ] `(signed type)42` Casting to signed type (`signed int`, `signed long`, etc) |
| 171 | +- [ ] Pointers (`void *`, etc) |
| 172 | +- [ ] References (`unsigned int`, `unsigned long`, etc) |
| 173 | + |
| 174 | +### Object Like Directive |
| 175 | + |
| 176 | +```php |
| 177 | +use FFI\Preprocessor\Preprocessor; |
| 178 | +use FFI\Preprocessor\Directive\ObjectLikeDirective; |
| 179 | + |
| 180 | +$pre = new Preprocessor(); |
| 181 | + |
| 182 | +// #define A |
| 183 | +$pre->define('A'); |
| 184 | + |
| 185 | +// #define B 42 |
| 186 | +$pre->define('B', '42'); |
| 187 | + |
| 188 | +// #define С 42 |
| 189 | +$pre->define('С', new ObjectLikeDirective('42')); |
| 190 | +``` |
| 191 | + |
| 192 | +## Function Like Directive |
| 193 | + |
| 194 | +```php |
| 195 | +use FFI\Preprocessor\Preprocessor; |
| 196 | +use FFI\Preprocessor\Directive\FunctionLikeDirective; |
| 197 | + |
| 198 | +$pre = new Preprocessor(); |
| 199 | + |
| 200 | +// #define C(object) object##_T* object; |
| 201 | +$pre->define('C', function (string $arg) { |
| 202 | + return "${arg}_T* ${arg};"; |
| 203 | +}); |
| 204 | + |
| 205 | +// #define D(object) object##_T* object; |
| 206 | +$pre->define('D', new FunctionLikeDirective(['object'], 'object##_T* object')); |
| 207 | +``` |
| 208 | + |
| 209 | +## Include Directories |
| 210 | + |
| 211 | +```php |
| 212 | +use FFI\Preprocessor\Preprocessor; |
| 213 | + |
| 214 | +$pre = new Preprocessor(); |
| 215 | + |
| 216 | +$pre->include('/path/to/directory'); |
| 217 | +$pre->exclude('some'); |
| 218 | +``` |
| 219 | + |
| 220 | +## Message Handling |
| 221 | + |
| 222 | +```php |
| 223 | +use FFI\Preprocessor\Preprocessor; |
| 224 | + |
| 225 | +$logger = new Psr3LoggerImplementation(); |
| 226 | + |
| 227 | +$pre = new Preprocessor($logger); |
| 228 | + |
| 229 | +$pre->process(' |
| 230 | + #error Error message |
| 231 | + // Will be sent to the logger: |
| 232 | + // - LoggerInterface::error("Error message") |
| 233 | + |
| 234 | + #warning Warning message |
| 235 | + // Will be sent to the logger: |
| 236 | + // - LoggerInterface::warning("Warning message") |
| 237 | +'); |
| 238 | +``` |
0 commit comments