3 ms·
I think this is a really interesting direction. That it can translate C23 to C89 means it has most of the work in place to translate C23 to C23, or C99 to C99
by JonChesterfield 3y ago
I think this is a really interesting direction.
That it can translate C23 to C89 means it has most of the work in place to translate C23 to C23, or C99 to C99 etc. If that is done in a (mostly) reversible fashion - successfully re-encode back to the original, where you `preprocess -> parse -> unparse -> re-preprocess` which is a nuisance but possible, then it opens the door to much more aggressive type systems.
In particular, the input can be C with the ownership annotations, and if they're valid, the output can be C with those annotations dropped to be fed into some other compiler. Or whatever other invariant systems the compiler dev is interested in.
Or the input could be C extended with namespace {} syntax, C++ style lambdas, contract checking - whatever you wish really, and the output can be the extensions desugared into C. Templates (possibly the D style ones) can be implemented as instantiating normal functions from said template.
That the output is C means this is usable in all the pipelines that already work with C.
Good stuff, thanks for posting.
- thradams 3y agoThe idea is to keep cake aligned with C, not a language fork. But Cake itself could have a fork to Cake++. :D
- JonChesterfield 3y agoA 'C' -> C compiler which preserves most source code unchanged (i.e. would be the identity transform on some input) and which implements something like constexpr on functions (by running the interpreter during the transform) could be argued to be a forward looking C implementation. Specifically C23 has constexpr, but in an extremely limited form, and aspires to extend that to be more useful later. Equally one which replaces 'auto' with the name of the type (and similar desugaring games) is still a C to C compiler, just running as a C23 to C99 or whatever. Resolve the branch in _Generic before emitting code as part of downgrading C11. The lifetime annotations are an interesting one because they're a different language which, if it typechecks, can be losslessly converted into C (by dropping the annotations on the way out). I'm not sure where in that design space the current implementation lies. In particular folding preprocessed code back into code that has the #defines and #includes in is a massive pain and only really valuable if you want to lean into the round trip capability.
- thradams 3y agoauto, typeof, _Generic are implemented in cake. Sometimes when they are used inside macros the macros needs to be expanded. Then cake has #pragma expand MACRO. for this task. Sample macro NEW using c23 typeof. #include <stdlib.h> #include <string.h> static inline void* allocate_and_copy(void* s, size_t n) { void* p = malloc(n); if (p) { memcpy(p, s, n); } return p; } #define NEW(...) (typeof(__VA_ARGS__)*) allocate_and_copy(&(__VA_ARGS__), sizeof(__VA_ARGS__)) #pragma expand NEW struct X { const int i; }; int main() { auto p = NEW((struct X) {}); } The generated code is #include <stdlib.h> #include <string.h> static inline void* allocate_and_copy(void* s, size_t n) { void* p = malloc(n); if (p) { memcpy(p, s, n); } return p; } #define NEW(...) (typeof(__VA_ARGS__)*) allocate_and_copy(&(__VA_ARGS__), sizeof(__VA_ARGS__)) #pragma expand NEW struct X { const int i; }; int main() { struct X * p = (struct X*) allocate_and_copy(&((struct X) {0}), sizeof((struct X) {0})); }