|
| 1 | +## Automatic Translation Features |
| 2 | + |
| 3 | +#### Syntax |
| 4 | + |
| 5 | +* C and FB are similar enough to allow most declarations to be converted 1:1 by |
| 6 | +doing a pure syntax conversion, for example: |
| 7 | + |
| 8 | + ``` |
| 9 | + struct UDT { => type UDT |
| 10 | + float f; => f as single |
| 11 | + }; => end type |
| 12 | + void f(struct UDT *p); => declare sub f(byval p as UDT ptr) |
| 13 | + ``` |
| 14 | + |
| 15 | +* More complex C syntax cases: |
| 16 | + |
| 17 | + ``` |
| 18 | + Multiple declarations in single statement (FB is less flexible than C here): |
| 19 | + extern int a, b, *c, d(void); |
| 20 | + => |
| 21 | + extern as long a, b |
| 22 | + extern as long ptr c |
| 23 | + declare function d() as long |
| 24 | +
|
| 25 | + struct/union/enum bodies declared as part of other declarations: |
| 26 | + typedef struct { ... } A, *PA; |
| 27 | + => |
| 28 | + struct temp1 { ... }; |
| 29 | + typedef struct temp1 A; |
| 30 | + typedef struct temp1 *PA; |
| 31 | + => |
| 32 | + type temp1 : ... : end type |
| 33 | + type A as temp1 |
| 34 | + type PA as temp1 ptr |
| 35 | + => |
| 36 | + type A : ... : end type |
| 37 | + type PA as A ptr |
| 38 | +
|
| 39 | + Nested named UDT bodies are moved outside of the parent UDT (not supported in FB). |
| 40 | + struct A { |
| 41 | + struct B { }; /* gcc warning: declaration does not declare anything */ |
| 42 | + }; |
| 43 | + => |
| 44 | + struct B { }; |
| 45 | + struct A { }; |
| 46 | +
|
| 47 | + Nested function pointers: |
| 48 | + extern int (*(*f)(int (*a)(void)))(int b); |
| 49 | + => |
| 50 | + extern f as function(byval a as function() as long) as function(byval b as long) as long |
| 51 | + ``` |
| 52 | +
|
| 53 | +* Toplevel C assignment expressions are turned into FB assignment statements, |
| 54 | + even wrapped in scope block if it's inside a macro body, to enforce its use as |
| 55 | + statement, not expression. Otherwise, assignments could be mis-used as comparisons. |
| 56 | +* Toplevel comma operators are translated to a statement sequence: |
| 57 | +
|
| 58 | + ``` |
| 59 | + Example of statement or macro body with comma operators: |
| 60 | + (a, b, c) |
| 61 | + => |
| 62 | + scope |
| 63 | + a |
| 64 | + b |
| 65 | + [return?] c |
| 66 | + end scope |
| 67 | + ``` |
| 68 | +
|
| 69 | +* Unnecessary scope blocks (e.g. nested inside loop blocks) are solved out. |
| 70 | + C if blocks nested in else blocks are converted to FB elseif blocks. |
| 71 | + `while (0) ...` or `do ... while (0)` blocks are turned into FB scope blocks. |
| 72 | + Sometimes this can clean up macros or inline functions; rarely useful though. |
| 73 | +
|
| 74 | +#### Data types and structures |
| 75 | +
|
| 76 | +* The normal C data types and some common typedefs such as `size_t`, `int32_t` or `intptr_t` are translated to normal FB data types. |
| 77 | + There is special support for translating `char => byte`, `char* => zstring ptr` and `char[N] => zstring * N` (same for `wchar_t => wstring`). |
| 78 | + char/wchar_t typedefs are expanded in case they are used as string in some cases and byte in others. |
| 79 | + The `-string`/`-nostring` options can be used to override the automatic conversion. |
| 80 | + C's `long` and `long double` types are translated to `clong` and `clongdouble`. |
| 81 | + #includes for `crt/long[double].bi` or `crt/wchar.bi` are automatically added if needed. |
| 82 | +* Named enum => `type enumname as long` + anonymous enum, because C enums/ints stay 32bit on 64bit, |
| 83 | + so in FB we have to use the always-32bit LONG type instead of the default ENUM/INTEGER type. |
| 84 | +* Function/array typedefs (not supported in FB) => solved out |
| 85 | +* struct/union/enum tag names are solved out in favour of typedefs, if any. |
| 86 | + Exact-alias typedefs (`typedef struct A A`) or case-alias typedefs (`typedef struct a A`) are solved out, since FB doesn't have the separate tag namespace and is case-insensitive anyways. |
| 87 | +* Anonymous structs (not supported in FB) => named after first typedef that uses them, or auto-generated name |
| 88 | +* Forward-references to tags/types are handled by auto-adding forward declarations, |
| 89 | + but only if the referenced tag is actually declared in the API. This way, |
| 90 | + tags/types from other headers like `FILE`/`jmp_buf`/`time_t` or `struct tm` won't be |
| 91 | + forward-declared. |
| 92 | +
|
| 93 | +#### Macros and preprocessor directives |
| 94 | +
|
| 95 | +* Exact-alias-#defines (`#define A A`) are removed (neither needed nor possible in FB). |
| 96 | + Case-aliases (`#define a A`) are solved out since FB is case-insensitive anyways. |
| 97 | +* #defines with simple constant expression in their bodies => FB constants |
| 98 | +* Alias-#defines for constants/types/functions/variables are converted to declarations, |
| 99 | + using the ALIAS keyword where needed. |
| 100 | +
|
| 101 | + ``` |
| 102 | + const A = ... |
| 103 | + #define B A => const B = A |
| 104 | +
|
| 105 | + type A as ... |
| 106 | + #define B A => type B as A |
| 107 | +
|
| 108 | + declare sub/function A |
| 109 | + declare sub/function C alias "X" |
| 110 | + #define B A => declare sub/function B alias "A" |
| 111 | + #define D C => declare sub/function D alias "X" |
| 112 | +
|
| 113 | + extern A as ... |
| 114 | + extern C alias "X" as ... |
| 115 | + #define B A => extern B alias "A" |
| 116 | + #define D C => extern D alias "X" |
| 117 | + ``` |
| 118 | +
|
| 119 | +* Macro parameters which conflict with FB keywords or other identifiers (due to |
| 120 | + FB's case-insensitivity) in the macro body are automatically renamed (because fbc can't catch this as |
| 121 | + "duplicate definition" like name conflicts between symbol declarations). |
| 122 | +* #defines nested inside struct bodies => moved to toplevel (helps when converting #defines to constants, because FB scopes those inside UDTs) |
| 123 | +* `#define m(a, ...) __VA_ARGS__` => `#define m(a, __VA_ARGS__...) __VA_ARGS__` |
| 124 | +* `#pragma comment(lib, "foo.lib"|"libfoo.a")` => `#inclib "foo"` |
| 125 | +* `#include` statements are generally preserved if not expanded; .h is replaced by .bi. |
| 126 | +
|
| 127 | +#### Variables, Functions, Parameters |
| 128 | +
|
| 129 | +* Most used calling convention => Extern block. Other calling conventions (if header uses multiple ones) are emitted on the individual procedures. |
| 130 | + Extern blocks are also used to avoid the need for explicit case-preserving ALIAS'es on any extern declarations. |
| 131 | +* Array parameters (not supported in FB) => pointers (what they become in C behind the scenes anyways) |
| 132 | +* Special case for the occasionally used `jmp_buf` parameters: They're explicitly converted to pointers, |
| 133 | +* Arrays/strings declared with unknown size => "..." ellipsis |
| 134 | + because fbfrog usually doesn't see the CRT headers. `jmp_buf` is an array type in C, i.e. passed as pointer. `jmp_buf` is a UDT in FB's CRT binding. |
| 135 | +* Unsized extern array variables aren't allowed in FB, and require some tricks to be translated. |
| 136 | + However, if the array size is known, it's better to use `-setarraysize` to specify the exact array size, and get a cleaner translation. |
| 137 | +
|
| 138 | + ``` |
| 139 | + extern dtype array[]; |
| 140 | + extern char s[]; |
| 141 | + => |
| 142 | + extern array(0 to ...) as dtype |
| 143 | + extern s as zstring * ... |
| 144 | + => |
| 145 | + #define array(i) ((@__array)[i]) |
| 146 | + extern __array alias "array" as dtype |
| 147 | + extern __s alias "s" as ubyte; |
| 148 | + #define s (*cptr(zstring ptr, @__s)) |
| 149 | + ``` |
| 150 | +
|
| 151 | +* Simple (inline) functions are converted to macros, because FB doesn't have "proper" inline functions. |
| 152 | +
|
| 153 | +#### Expressions |
| 154 | +
|
| 155 | +* Boolean operations result in `1|0` in C. This is converted to FB's `-1|0` by inserting a negation if used in math context. C's logical NOT `!x` becomes FB's `x = 0`. |
| 156 | +* All 32bit unsigned int IIFs/BOPs/UOPs are wrapped in culng()/clng() casts, |
| 157 | + in order to make sure the result is truncated to 32bit properly in FB even on 64bit, |
| 158 | + where FB will do 64bit arithmetic. |
| 159 | +
|
| 160 | + ``` |
| 161 | + For example, in C: |
| 162 | + (0u - 100u) => 0xFFFFFF9Cu |
| 163 | + but in FB: |
| 164 | + (0ul - 100ul) => &hFFFFFF9Cu (32bit) |
| 165 | + (0ul - 100ul) => &hFFFFFFFFFFFFFF9Cu (64bit) |
| 166 | + and &hFFFFFFFFFFFFFF9Cu <> &hFFFFFF9Cu (no sign extension due to unsigned). |
| 167 | + In order to make sure we always get &hFFFFFF9Cu in FB, we have to truncate |
| 168 | + the operation's result to 32bit explicitly. |
| 169 | + ``` |
| 170 | +
|
| 171 | +* When type-casting string literals, an @ (address-of) operator is inserted, because string literals |
| 172 | + automatically become pointers in C, but not in FB. |
| 173 | +* `(void)` casts, which are common to ensure a function call or other expression can only be used as a statement, |
| 174 | + are automatically removed, because it's probably not worth it to translate to FB, |
| 175 | + even though it could be done by wrapping the statement in a scope block. |
| 176 | +
|
| 177 | +#### Error handling |
| 178 | +
|
| 179 | +Declarations which cannot be processed automatically (yet) will be embedded into |
| 180 | +the *.bi file in form of a "TODO" comment, for example: `'' TODO: #define FOO ...`. |
| 181 | +This affects complicated #defines ("arbitrary" token sequences), |
| 182 | +function bodies (inline functions), plus some others such as language features |
| 183 | +or compiler extensions not supported by fbfrog's parser (yet). |
0 commit comments