Why C-? ------------ The following features from the standard ‘ are not supported: Directives: #error, #import(has a different purpose in Flat C-), #include_next, #line, #pragma, #warning. No hash digraph ( <: <% etc). No inline, volatile, Complex, Generic, auto, register, restrict. Probably, I've forgotten to mention something. Why Flat? --------- The compiler has a built-in FASM engine for code generation, without macros and other features of FASM, and uses flat memory model. ============================================================= Flat C- produces 64-bit executables for Windows platform only. ============================================================= Flat C- directives. ------------------- #import "dllname" - imports function names from the DLL library for use in linking executable code. #include "filename" - opens file for compilation. The file name and path must be specified. The search function is not implemented. Examples: #include "kernel.h-" open file in current directory; "..\\xxx\\file.c" open file in subdirectory "xxx" of current directory. #list - listing the compiled program. #debug, #dbgall - create file with debugging information for the x64dbg debugger. The name of the file looks like: .exe.dd64. #debug - only global labels (variables and functions wil be included in .dd64. #deball - global labels, local labels and source lines, as comments. #gui - produce executables for gui. By default, console programs are created. #resource "file.res" - the specified resource file is used when compiling. Main features of Flat C-. ---------------------- 1. Built-in assembler with FASM syntax. You can freely use assembler code anywhere inside the functions. For example: void OutByte(char b){ xchg [outptr],rdi; mov al,[b]; stosb; xchg [outptr],rdi; if(f_list){ push rcx rdx rsi; sprintf(&info,"%2x ",b); fprint(outputfp,&info); add dword[LstStrLen],3; pop rsi rdx rcx; } mov al,[b]; } All supported instructions are listed in file mnem.txt. In assembler you can use all registers freely, except rax,rcx,eax,ecx,ax,cx and byte registers al,ah,cl,ch, which are used in expression processing. You can use registers in expression. For example: a+=edx; will be compiled as the following code: push rdx movsxd rax, dword[a] pop rcx add rax, rcx mov [a], eax 2. Conditional statement - 'docase'. Used for multiple coditional branching. Statements 'continue' and 'break' can be used inside. docase{ ÚÄÄÄ> some statements here ³ case(cond1){ ³ some statements here; ³ ................. >ÄÄÄÄ¿ ³ } ³ ³ case(cond2){ ³ ³ some statements here; ³ ³ break; >ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ> ³ some statements here; ³ ³ } ³ ³ ...... ³ ³ case(condN){ ³ ³ some statements here; ³ ÀÄÄÄÄÄÄÄ< continue; ³ some statements here; >ÄÄÄÄ> } ³ default: ³ some statements here; >ÄÄÄÄ> } ³ .... <ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ 3. Aliasing - used to replace local variables or function parameters or pointers with registers in expressions. :: - operation symbol (var::rdi or *ptr::rbx). For example, for a function typedef struct { int a; char c; } ZZZ; void func(ZZZ *z){ z->a+=4; } such code can be compiled: ; t.c(13): z->a+=4; ; push 4 ; mov rax , [ rbp + 16 ] ; movsxd rax , [ rax ] ; pop rcx ; add rax , rcx ; push rax ; mov rax , [ rbp + 16 ] ; pop rcx ; mov [ rax ] , ecx When assigning an alias to a parameter z, void func(ZZZ *z::r11){ z->a+=4; } the code will be different: ; t.c(13): z->a+=4; ; push 4 ; movsxd rax , [ r11 ] ; pop rcx ; add rax , rcx ; push rax ; pop rcx ; mov [ r11 ] , ecx If function has aliased parameters or variables, code for saving and initializing the registers, used in that function, will be placed into the function's prolog. Those registers will be restored in the end of the function. The following code will be in the beginning of the function: push r11; mov r11,qword[rbp+16], and the following code will be at the function's end: pop r11 for above example. 4. Key 'on' may be used for the 'switch' operator, as well as 'case': switch(bl){ case 'a' ... 'z': return 1; on '0' ... '9': return 0; } 5. Calling convention 'fastcall' is realized for functions. Parameters for this function are passed via registers rcx,rdx,r8,R9 for integers or xmm0..xmm3 for floating type values. For example: int fastcall main (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) function prolog will be: main: ; push rbp ; mov rbp , rsp ; mov qword [ rbp + 16 ] , rcx ; mov qword [ rbp + 24 ] , rdx ; mov qword [ rbp + 32 ] , r8 ; mov qword [ rbp + 40 ] , r9 6. Flat C- when compiled, unused functions are not included in the final executable. Thus, for example, the function a2() will not be included, since there are no calls to it: #list void main(int p){ a1(p+2); } int a2(int p2){ p2++; } int a1(int p1){ return p1-=10; } main: 00401000: 55 ; push rbp 00401001: 48 89 E5 ; mov rbp , rsp ;; t.c(13): a1(p+2); 00401004: 6A 02 ; push 2 00401006: 48 63 45 10 ; movsxd rax , [ rbp + 16 ] 0040100A: 59 ; pop rcx 0040100B: 48 01 C8 ; add rax , rcx 0040100E: 50 ; push rax 0040100F: E8 00000000 ; call a1 00401014: 48 83 C4 08 ; add rsp , 8 @L0: 00401018: 5D ; pop rbp 00401019: C3 ; ret a1: 0040101A: 55 ; push rbp 0040101B: 48 89 E5 ; mov rbp , rsp 0040101E: 6A 0A ; push 10 00401020: 48 63 45 10 ; movsxd rax , [ rbp + 16 ] 00401024: 59 ; pop rcx 00401025: 48 29 C8 ; sub rax , rcx 00401028: 89 45 10 ; mov [ rbp + 16 ] , eax @L1: 0040102B: 5D ; pop rbp 0040102C: C3 ; ret The same is applicable to global variables. 7. Flat C- is self-hosting.