This project is NOT usable yet (check TODO)
An embeddable C-like JIT compiler.
Warning
This compiler is NOT suited for real-world C code. It's intentionally incomplete and implements only a small subset of C23 (see below). It's meant to compile small files written in C to provide a scripting interface for host programs like game engines.
Fill the hole where there's no lightweight, embeddable C JIT compiler that makes interop near plug and play.
- Parameters/varargs/returns in function prolog and epilog
- Short circuiting
- Switch statements
- Initializers
- Compound expressions
- Preprocessor
- Windows support
Calling it done here, the things below are planned but not guaranteed
- Implement
goto - aarch64 support
- Rewrite IR into SSA
- Implement custom extensions
- GNU statement expressions
- GNU ternary syntax (
x ? : y) - switch expressions
- Zig's
deferor GNU__attribute__((cleanup)), either one of the two - C++ lambdas
- C++ templates (won't blow up to the complexity of C++)
- C++ operator overloading (also won't blow up to C++'s complexity)
Note to self: When implementing extension features, still make programs as explicit as possible (minimal implicit behavior cough cough C++ cough)
If a feature is not on this list, it's very likely not supported.
- All binary and unary operators (including comma operator)
- Overflow wraps (modulo 2^n where n is the bit width of the type)
- Usual type promotion rules (rule 3 overrides rule 2, rule 2 overrides rule 1, etc.)
- Types smaller than 32 bits get promoted to
int - If any type is 64-bit, everything else is 64-bit
- If any type is unsigned, everything else is unsigned
- Does not apply to comparsions
- If any type is a
float, everything else is afloat - If any type is a
double, everything else is adouble
- Types smaller than 32 bits get promoted to
- Floating point behavior (dividing by zero, operating on
NaNorInfinity) depends on the architecture
- Ternary expressions (
?:) - Integer, float, character, bool and string literals
- Multicharacter character constants
- Escape sequences (
\a,\b,\e,\f,\n,\r,\t,\v,\",\\,\',\xNN,\uNNNN,\UNNNNNNNN,\NNN) - String literals are concatted
trueis the same as(bool)1andfalseis the same as(bool)00x,0band0integer prefixes- Scientific notation for floats and hex floats
L,LL,U,UL,ULLandFsuffixes for integer and float constants- Case insensitive
- String literals are static, but read-write
- Comments
- Structs and unions
- Can be anonymous and nest
- Fields get aligned
- Enums
- Can be anonymous
- Underlying type is
intby default, can be overriden via: typesyntax
- Incomplete struct/union/enum types
- All basic types
char- Signed 8-bit integershort- Signed 16-bit integerint- Signed 32-bit integerlong- Signed 64-bit integerlong long- Signed 64-bit integerfloat- 32-bit floating pointdouble- 64-bit floating pointlong double- 64-bit floating pointbool- Unsigned 8-bit integer (_Boolunsupported)unsignedandconstqualifiersconstis enforced but can be casted away
void- Pointers, arrays and functions
- Arrays and functions cannot be assigned to even if non-const
- Decays into pointers
- Casting rules
- Pointer <-> 64-bit integer
- Pointer <-> Pointer
- Pointer <-> Non 64-bit integer
- Only if the cast is explicit
- 0 integer literal -> Pointer
- Integer <-> Integer
- Struct/union <-> Struct/union
- Must be the exact same struct type
- lvalues
- Variables
- Dereferences (and as a result, array subscripts)
- Struct fields
- Compound expressions
- Everything else is an rvalue
- Variadic arguments (varargs)
- Initializers
- Designated initializers
- Initialized to 0
- Compound expressions
- Integer constant expressions (
1 - 1is the same as0, also applies to casting rules) typedef,staticandexternstaticvariables are initialized to 0
sizeof,typeofandalignof(_Alignofunsupported)- Must have parentheses,
sizeof xis invalid
- Must have parentheses,
- Basic control flow (
if,else,while,do,for,break,continue,return,switch,case,default)caseis integer constant only- Cases fall through without
break - Function calls must have visible prototypes
- Fixed argument count must match
- Empty parameter list is the same as
void
- Preprocessor directives
#error,#warning,#pragmaand#linenot supported__STDC_HOSTED__-1__STDC_NO_ATOMICS____STDC_NO_COMPLEX____STDC_NO_THREADS____STDC_NO_VLA____JITC____x86_64__- Defined only on x86_64 architectures__aarch64__- Defined only on aarch64 architectures_WIN32- Defined only on Windows__APPLE__- Defined only on macOS__linux__- Defined only on Linux__unix__- Defined only on macOS and Linux__LINE__- Current line number__FILE__- Current file (string literal)__FUNCTION__- Current function (string literal)__func__unsupported
__DATE__- Compilation date__TIME__- Compilation time__VA_ARGS__- Set of varargs__VA_OPT__- Expands to parameter if there are any varargs__COUNTER__- Expands to a value of counter, then increments it__COUNTER_NOINC__- Expands to a value of counter, but doesn't increment it- Includes and defines pasted during lexing as a series of tokens
Explicitly unsupported features
volatile,register,restrict,inline,auto,constexpr,signedkeywordsgoto- VLAs (including
alloca) - Bitfields
- Variable shadowing
- Wide strings/characters
#error,#warning,#pragmaand#line- Attributes
- Both GNU
__attribute__and C23[[attribute]]
- Both GNU
- All underscore-prefixed keywords
_Alignas,_Alignof(supported viaalignof),_Atomic,_Bool(supported viabool),_Complex,_DecimalX,_Generic,_Imaginary,_Noreturn,_Static_assert,_Thread_local
asmandfortran- K&R-style function definitions and syntax
-
struct jitc_error_tconst char* msg- Error messageconst char* file- Name of the file where the error occuredint row- Line number of the error locationint col- Column number of the error location- It is the caller's responsibility to
freethe object if it receives it fromjitc_parseorjitc_parse_file
-
jitc_context_t* jitc_create_context()- Creates a new context
-
bool jitc_include(jitc_context_t* context, const char* file)- Includes a header into the context
- Returns
trueon success,falseif the header isn't found or if it was already included
-
jitc_error_t* jitc_parse(jitc_context_t* context, const char* code, const char* filename)- Parses source code from memory, returns
NULLif successful, an error object if not filename: Can beNULL, specifies the filename for the lexer
- Parses source code from memory, returns
-
jitc_error_t* jitc_parse_file(jitc_context* context, const char* file)- Reads a file from the filesystem and parses its contents, returns
NULLif successful, an error object if not
- Reads a file from the filesystem and parses its contents, returns
-
void* jitc_get(jitc_context* context, const char* name)- Returns a symbol from the context,
NULLif it doesn't exist
- Returns a symbol from the context,
-
void jitc_destroy_context(jitc_context_t* context)- Destroys a context and all the variables and functions declared with it
-
void jitc_create_header(const char* name, const char* content)- Creates a virtual header
To use a symbol from the host, use extern. extern cannot be used to reference symbols from other contexts.