$WW,1$$FG,5$$TX+CX,"CosmiC"$$FG$

* See $LK,"::/Doc/CompilerOverview.DD"$.

* See $LK,"Scoping and Linkage",A="FI:::/Doc/ScopingLinkage.DD"$ for details on $FG,2$extern$FG$, $FG,2$import$FG$, $FG,2$_extern$FG$, $FG,2$_import$FG$, etc.

* Built-in types include $FG,2$I0, I8, I16, I32, I64$FG$ for signed 0-8 byte ints and $FG,2$U0, U8, U16, U32, U64$FG$ for unsigned 0-8 byte ints and $FG,2$F64$FG$ for 8 byte floats.

$FG,2$	U0			void, but ZERO size!
	I8			char
	U8			unsigned char
	I16 		short
	U16 		unsigned short
	I32 		int
	U32 		unsigned int
	I64 		long (64-bit)
	U64 		unsigned long (64-bit)
	F64 		double$FG$
	$FG,4$no F32 float.$FG$

* Function with no args, or just default args can be called without parentheses.

	>$FG,2$Dir("*");$FG$
	>$FG,2$Dir();$FG$
	>$FG,2$Dir;$FG$

* Default args don't have to be on the end.  This code is valid:
$ID,2$$FG,2$U0 Test(I64 i=4, I64 j, I64 k=5)
{
	Print("%X %X %X\n", i, j, k);
}

Test(, 3);$FG$
$ID,-2$
* A char const all alone is sent to $LK,"PutChars",A="MN:PutChars"$().	A string with or without args is sent to $LK,"Print",A="MN:Print"$().  An empty string literal signals a variable format_str follows.

$ID,2$$FG,2$void DemoC(char drv, char *format, char *name, int age)
{
	printf("Hello World!\n");
	printf("%s age %d\n", name, age);
	printf(format, name, age);
	putchar(drv);
	putchar('*');
}

U0 DemoCosmiC(U8 drive, U8 *format, U8 *name, I64 age)
{
	"Hello World!\n";
	"%s age %d\n", name, age;
	"" format, name, age;
	'' drive;
	'*';
}
$FG$$ID,-2$
* When dealing with function addresses such as for callbacks, precede the name with "$FG,2$&$FG$".

* Type casting is postfix.	To typecast int or F64, use $LK,"ToI64",A="MN:ToI64"$(), $LK,"ToBool",A="MN:ToBool"$() or $LK,"ToF64",A="MN:ToF64"$(). (ZenithOS follows normal C float<-->int conversion, but sometimes you want to override.	These functions are better than multiplying by "1.0" to convert to float.)

* There is no $FG,2$main()$FG$ function.	Any code outside of functions gets executed upon start-up, in order.

* There are no bit fields, but there are $LK,"bit access",A="HI:Bit"$ routines and you can access bytes or words within any int.	See $LK,"I64 declaration",A="MN:I64"$.	A class can be accessed as a whole are subints, if you put a type in front of the $FG,2$class$FG$ declaration.
$ID,2$
$FG,2$public I64i union I64 	//"I64i" is intrinsic.	We are defining "I64".
{
	I8i i8[8];
	U8i u8[8];
	I16 i16[4];
	U16 u16[4];
	I32 i32[2];
	U32 u32[2];
};

I64 i = 0x123456780000DEF0;
i.u16[1] = 0x9ABC;
$FG$$ID,-2$
* Variable arg count functions ($FG,2$...$FG$) can access their args with built-in variables similar to '$FG,2$this$FG$' in C++.	They are '$FG,2$I64 argc$FG$' and '$FG,2$I64 argv[]$FG$'.
$ID,2$$WW,0$
$FG,2$I64 AddNums(...)
{
	I64 i, res = 0;

	for (i = 0; i < argc; i++)
		res += argv[i];

	return res;
}

$FG$>$FG,2$AddNums(1, 2, 3);$FG$
ans = 6
$FG,2$

public U0 GrPrint(CDC *dc, I64 x, I64 y, U8 *format, ...)
{
	U8 *buf = $LK,"StrPrintJoin",A="MN:StrPrintJoin"$(NULL, format, argc, argv); //SPrintF() with $LK,"MAlloc",A="MN:MAlloc"$()ed string.

	$LK,"GrPutS",A="MN:GrPutS"$(dc, x, y, buf); //Plot string at x,y pixels. GrPutS is not public.
	Free(buf);
}

	...

	GrPrint(gr.dc, (GR_WIDTH - 10 * FONT_WIDTH) >> 1, (GR_HEIGHT - FONT_HEIGHT) >> 1, "Score:%4d", score);
		//Print score in the center of the screen.
	...

$WW,1$$FG$$ID,-2$
* Allows "$FG,2$5 < i < j + 1 < 20$FG$" instead of "$FG,2$5 < i && i < j + 1 && j + 1 < 20$FG$".
$ID,2$
$FG,2$if (13 <= age < 20)
	"Teen-ager";
$FG$$ID,-2$
* if you know a switch stmt will not exceed the lowest or highest case values.	$FG,2$switch []$FG$ is a little faster because it doesn't check.

* $FG,2$switch$FG$ statements always use a jump table.	Don't use them with cases with really big, sparse ranges.

* Allows ranges like "$FG,2$case 4...7:$FG$" in $FG,2$switch$FG$ statements.

* A no case number causes next higher int case in $FG,2$switch$FG$ statements.	See $LK,"::/Demo/NullCase.CC"$.

$ID,2$$FG,2$I64 i;

for (i = 0; i < 20; i++)
	switch (i)
	{
		case: "Zero\n";		break; //Starts at zero
		case: "One\n";		break; //One plus prev case.
		case: "Two\n";		break;
		case: "Three\n";	break;
		case 10: "Ten\n"; 	break;
		case: "Eleven\n"; 	break; //One plus prev case.
	}$FG$$ID,-2$

* Switch statements can be nestled with a single switch expression!  This is known as a "sub_switch" statement.  $FG,2$start$FG$/$FG,2$end$FG$ are used to group cases.  Don't goto out of, throw an exception out of, or return out of the $FG,2$start$FG$ front porch area.  See $LK,"::/Demo/SubSwitch.CC"$.

$ID,2$$FG,2$I64 i;

for (i = 0; i < 10; i++)
	switch (i)
	{
		case 0: "Zero ";		break;
		case 2: "Two "; 		break;
		case 4: "Four ";		break;
		start:
			"[";
			case 1: "One";		break;
			case 3: "Three";	break;
			case 5: "Five"; 	break;
		end:
			"] ";
			break;
	}$FG$
$BG$OutPut:
>$FG,2$Zero [One] Two [Three] Four [Five]$FG$
$ID,-2$
* A $FG,2$no_warn$FG$ stmt will suppress an unused var warning.

* You can have multiple member vars of a class named "$FG,2$pad$FG$" or "$FG,2$reserved$FG$", and it won't issue warnings.

* $FG,2$noreg$FG$ or $FG,2$reg$FG$ can be placed before a function local var name.	You can, optionally, specify a reg after the $FG,2$reg$FG$ keyword.

$ID,2$$FG,2$U0 Main()
{
	//Only use $LK,"REGG_LOCAL_VARS",A="MN:REGG_LOCAL_VARS"$ or $LK,"REGG_LOCAL_NON_PTR_VARS",A="MN:REGG_LOCAL_NON_PTR_VARS"$ for reg vars or else clobbered.
	I64 reg R15 i = 5, noreg j = 4;
	no_warn i;
	asm {
				MOV 		RAX, R15
				CALL		&PUT_HEX_U64
				MOV 		RAX, '\n'
				CALL		&PUT_CHARS
				MOV 		RAX, U64 &j[RBP]
				CALL		&PUT_HEX_U64
				MOV 		RAX, '\n'
				CALL		&PUT_CHARS
	}
}
$FG$$ID,-2$
* $FG,2$interrupt$FG$, $FG,2$haserrcode$FG$, $FG,2$public$FG$, $FG,2$argpop$FG$ or $FG,2$noargpop$FG$ are function flags. See $LK,"IRQKbd",A="MN:IRQKbd"$().

* A single quote can encompass multiple characters.  $FG,2$'ABC'$FG$ is equ to $FG,2$0x434241$FG$.	$LK,"PutChars",A="MN:PutChars"$() takes multiple characters.

$ID,2$$FG,2$asm {
HELLO_WORLD::
				PUSH		RBP
				MOV 		RBP, RSP
				MOV 		RAX, 'Hello '
				CALL		&PUT_CHARS
				MOV 		RAX, 'World\n'
				CALL		&PUT_CHARS
				LEAVE
				RET
}
Call(HELLO_WORLD);
PutChars('Hello ');
PutChars('World\n');
$FG$$ID,-2$
* The "$FG,2$`$FG$" operator raises a base to a power.

* There is no question-colon operator.

* ZenithOS $LK,"operator precedence",A="FF:::/Compiler/CInit.CC,cmp.binary_ops"$
	$FG,2$`$FG$, $FG,2$>>$FG$, $FG,2$<<$FG$
	$FG,2$*$FG$, $FG,2$/$FG$, $FG,2$%$FG$
	$FG,2$&$FG$
	$FG,2$^$FG$
	$FG,2$|$FG$
	$FG,2$+$FG$, $FG,2$-$FG$
	$FG,2$<$FG$, $FG,2$>$FG$, $FG,2$<=$FG$, $FG,2$>=$FG$
	$FG,2$==$FG$, $FG,2$!=$FG$
	$FG,2$&&$FG$
	$FG,2$^^$FG$
	$FG,2$||$FG$
	$FG,2$=$FG$, $FG,2$<<=$FG$, $FG,2$>>=$FG$, $FG,2$*=$FG$, $FG,2$/=$FG$, $FG,2$&=$FG$, $FG,2$|=$FG$, $FG,2$^=$FG$, $FG,2$+=$FG$, $FG,2$-=$FG$

* You can use $LK,"Option",A="MN:Option"$($LK,"OPTf_WARN_PAREN",A="MN:OPTf_WARN_PAREN"$, ON) to find unnecessary parentheses in code.

* You can use $LK,"Option",A="MN:Option"$($LK,"OPTf_WARN_DUP_TYPES",A="MN:OPTf_WARN_DUP_TYPES"$, ON) to find dup local var type statements.

* With the $FG,2$#exe{}$FG$ feature in your src code, you can place programs that insert text into the stream of code being compiled.  See $LK,"#exe {}",A="FF:::/Kernel/KMain.CC,#exe {"$ for an example where the date/time and compile-time prompting for configuration data is placed into a program.  $LK,"StreamPrint",A="MN:StreamPrint"$() places text into a src program stream following the conclusion of the $FG,2$#exe{}$FG$ blk.

* No $FG,2$#define$FG$ functions exist (I'm not a fan)

* No $FG,2$typedef$FG$, use $FG,2$class$FG$.

* No type-checking

* Can't use $FG,2$<>$FG$ with $FG,2$#include$FG$, use $FG,2$""$FG$.

* "$FG,2$$$$FG$" is an escape character.	Two dollar signs signify an ordinary $$.	See $LK,"DolDoc",A="FI:::/Doc/DolDocOverview.DD"$.	In $FG,2$asm$FG$ or $LK,"CosmiC",A="FI:::/Doc/CosmiC.DD"$ code, it also refers to the inst's address or the offset in a $FG,2$class$FG$ definition.

* $FG,2$union$FG$ is more like a class, so you don't reference it with a $FG,2$union$FG$ label after you define it.  Some common unions are declared in $LK,"KernelA.HH",A="MN:U16"$ for 1,2,4 and 8 byte objects.	If you place a type in front of a union declaration, that is the type when used by itself.	See $LK,"::/Demo/SubIntAccess.CC"$.

* $FG,2$class$FG$ member vars can have meta data. $FG,2$format$FG$ and $FG,2$data$FG$ are two meta data types now used.  All compiler structures are saved and you can access the compiler's info about classes and vars.  See $LK,"::/Demo/ClassMeta.CC"$ and	$LK,"DocForm",A="MN:DocForm"$().

* There is a keyword $FG,2$lastclass$FG$ you use as a default arg.	It is set to the class name of the prev arg.	See $LK,"::/Demo/LastClass.CC"$, $LK,"ClassRep",A="MN:ClassRep"$(), $LK,"DocForm",A="MN:DocForm"$()  and $LK,"::/Demo/Disk/BlkDevRep.CC"$.

* See $LK,"::/Demo/Exceptions.CC"$.  $FG,2$try{} catch{}$FG$ and $FG,2$throw$FG$ are different from C++. $FG,2$throw$FG$ is a function with an 8-byte or less char arg.  The char string passed in $FG,2$throw()$FG$ can be accessed from within a $FG,2$catch{}$FG$ using the $FG,2$Fs->except_ch$FG$.  Within a $FG,2$catch {}$FG$ blk, set the var $FG,2$Fs->catch_except$FG$ to $FG,2$TRUE$FG$ if you want to terminate the search for a handler.  Use $LK,"PutExcept",A="MN:PutExcept"$() as a handler, if you like.

* A function is available similar to $FG,2$sizeof$FG$ which provides the offset of a member of a class.  It's called $FG,2$offset$FG$.	You place the class name and member inside as in $FG,2$offset(classname.membername)$FG$.	It has nothing to do with 16-bit code.	Both $FG,2$sizeof$FG$ and $FG,2$offset$FG$ only accept one level of member vars.	That is, you can't do $FG,2$sizeof(classname.membername.submembername)$FG$.$FG$

* There is no $FG,2$continue$FG$ stmt.	Use $FG,2$goto$FG$.

* $FG,2$lock{}$FG$ can be used to apply asm $FG,2$LOCK$FG$ prefixes to code for safe multicore read-modify-write accesses.	The code bracked with have $FG,2$LOCK$FG$ asm prefix's applied to relevant insts within.	It's a little shoddy.  See $LK,"::/Demo/MultiCore/Lock.CC"$.

* There is a function called $LK,"MSize",A="MN:MSize"$() which gives the size of an object alloced off the heap.	For larger size allocations, the system rounds-up to a power of two, so $FG,2$MSize()$FG$ lets you know the real size and you can take full advantage of it.

* You CAN $LK,"Free",A="MN:Free"$() a $FG,2$NULL$FG$ ptr.  Useful variants of $LK,"MAlloc",A="MN:MAlloc"$() can be found $LK,"Here",A="MN:CAlloc"$.  Each task has a heap and you can $FG,2$MAlloc$FG$ and $FG,2$Free$FG$ off-of other task's heaps, or make an independent heap with $LK,"HeapCtrlInit",A="MN:HeapCtrlInit"$().	See $LK,"HeapLog",A="MN:HeapLog"$() for an example.

* The stack does not grow because virtual mem is not used.	I recommend allocating large local vars from the heap.	You can change $LK,"MEM_DEFAULT_STACK",A="MN:MEM_DEFAULT_STACK"$ and recompile $FG,2$Kernel$FG$ or request more when doing a $LK,"Spawn",A="MN:Spawn"$().  You can use $LK,"CallStackGrow",A="MN:CallStackGrow"$(), but it's odd.  See $LK,"::/Demo/StackGrow.CC"$.

* Only one base class is allowed.

* $FG,2$printf()$FG$ has new codes.  See $LK,"Print(\"\") Format Strings",A="FI:::/Doc/Print.DD"$.

* All values are extended to 64-bit when accessed.	Intermediate calculations are done with 64-bit values.

$ID,2$$FG,2$U0 Main()
{
	I16 i1;
	I32 j1;

	j1 = i1 = 0x12345678;	//Resulting i1 is 0x5678 but j1 is 0x12345678

	I64 i2 = 0x8000000000000000;
	Print("%X\n", i2 >> 1);	//Res is 0xC000000000000000 as expected

	U64 u3 = 0x8000000000000000;
	Print("%X\n", u3 >> 1);	//Res is 0x4000000000000000 as expected

	I32 i4 = 0x80000000;	//const is loaded into a 64-bit reg var.
	Print("%X\n", i4 >> 1);	//Res is 0x40000000

	I32 i5 = -0x80000000;
	Print("%X\n", i5 >> 1);	//Res is 0xFFFFFFFFC0000000
}
$ID,-2$$FG$
