The CC_* language family is a subset of the C language designed to be written in Assembly (such as M0 macro assembly) but complete enough to make it easy to write a real C compiler written in the C subset that it does actually support. The standard convention is to replace * with the short form of the assembly language it outputs not the assembly language it is written in. For example if written in RISC-V assembly but outputting x86 assembly it would be named cc_x86 but a RISC-V(64bit) output written in x86 would be called cc_riscv64 (as RISC-V(64bit) and RISC-V(32bit) are incompatible assembly languages).
You must support the following primitive types:
void (and void*) int (and int*) char (char* and char**) FILE (and FILE*) FUNCTION (and FUNCTION*) unsigned (and unsigned*) long (and long*)
Which can be combined with struct and within structs, one may union members.
To support #define declarations; the keyword CONSTANT can be used as # starts line comments and // is ignored. Thus one can write:
//CONSTANT foo 4 #define foo 4
and the code will behave the same way in both GCC and cc_*
For conditional execution, if and else are available.
if(foo) do_something(); else if(bar) do_it_differently(); else something_different();
For looping primitives, there is for, do and while loops; with continue (treated like a NOP) and break (behaves like C)
For flow control there is goto and the ability to have labels: just like in regular C. With the only warning to make sure not to define variables inside of a goto loop.
For those needing something special like system calls; asm("add r0 r1 r2" "sub r3 r2 r1"); is supported and not fully gcc compatible so you will likely want uses of it in separate files, so that an alternate which works with gcc can be used for development.
For those needing to do allocation of memory sizeof(type) behaves exactly like C.
For those doing common C code, +, -, /, %, <, >, <<, >>, <=, >=, ==, !=, &, &&, |, || and ^ behave the same as C (signed version of the instructions; should you require the unsigned behavior, leverage the later M2-Planet stage)
For those dealing with assignment = works exactly like in C.
For those dealing with structs or arrays. both array[index] and structure->member work exactly like in C.
No other parts of the C language need to be supported.
An example implementation can be found here
And an example program written in that C subset can be found here