$WW,1$$FG,5$$TX+CX,"HolyC"$$FG$ * See $LK,"Scoping and Linkages",A="FI:::/Doc/ImportExports.TXT"$ for details on $FG,2$extern$FG$, $FG,2$import$FG$, $FG,2$_extern$FG$, $FG,2$_import$FG$, etc. * See $LK,"::/Doc/CompilerOverview.TXT"$. * 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) I64 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 fmt_str follows. $ID,2$$FG,2$void DemoC(char drv,char *fmt,char *name,int age) { printf("Hello World!\n"); printf("%s age %d\n",name,age); printf(fmt,name,age); putchar(drv); putchar('*'); } U0 DemoHolyC(U8 drv,U8 *fmt,U8 *name,I64 age) { "Hello World!\n"; "%s age %d\n",name,age; "" fmt,name,age; '' drv; '*'; } $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"$(). (TempleOS 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,result=0; for (i=0;i$FG,2$AddNums(1,2,3);$FG$ ans=6 $FG,2$ public U0 GrPrint(CDC *dc,I64 x,I64 y,U8 *fmt,...) { U8 *buf=$LK,"StrPrintJoin",A="MN:StrPrintJoin"$(NULL,fmt,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$FG,2$Zero [One] Two [Three] Four [Five]$FG$ $ID,-2$ * A $FG,2$nounusedwarn$FG$ statement 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,"REG_VARS_MASK",A="MN:REG_VARS_MASK"$ or $LK,"REG_NON_PTR_MASK",A="MN:REG_NON_PTR_MASK"$ for reg vars or else clobbered. I64 reg R15 i=5, noreg j=4; nounusedwarn 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,"::/Demo/Lectures/PageTableEntries2.CPP"$. * A single quote can encompass multiple characters. $FG,2$'ABC'$FG$ is equal 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. * TempleOS $LK,"operator precedence",A="FF:::/Compiler/CmpInit.CPP,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,2$<$FG$,$FG,2$>$FG$,$FG,2$<=$FG$,$FG,2$>=$FG$ $FG,2$==$FG$,$FG,2$!=$FG$ $FG,2$&&$FG$ $FG,2$$FG,2$^^$FG$ $FG,2$||$FG$$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,"OptOn",A="MN:OptOn"$($LK,"OPTf_WARN_PAREN",A="MN:OPTf_WARN_PAREN"$) to find unnecessary parentheses in code. * You can use $LK,"OptOn",A="MN:OptOn"$($LK,"OPTf_WARN_DUP_TYPES",A="MN:OPTf_WARN_DUP_TYPES"$) 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/KEnd.CPP,#exe {"$ for an example where the date/time and compile-time prompting for cfguration 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.TXT"$. In $FG,2$asm$FG$ or $LK,"HolyC",A="FI:::/Doc/HolyC.TXT"$ code, it also refers to the instruction'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,"Adam1a.HPP",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.CPP"$. * $FG,2$class$FG$ member vars can have meta data. $FG,2$fmtstr$FG$ and $FG,2$fmtdata$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.CPP"$ and $LK,"DocFormDo",A="MN:DocFormDo"$(). * There is a keyword $FG,2$lastclass$FG$ you use as a dft arg. It is set to the class name of the previous arg. See $LK,"::/Demo/LastClass.CPP"$, $LK,"ClassRep",A="MN:ClassRep"$(), $LK,"DocFormDo",A="MN:DocFormDo"$() and $LK,"::/Demo/Dsk/BlkDevRep.CPP"$. * See $LK,"::/Demo/Exceptions.CPP"$. $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$ statement. 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 instructions within. It's a little shoddy. See $LK,"::/Demo/MultiCore/Lock.CPP"$. * There is a function called $LK,"MSize",A="MN:MSize"$() which gives the size of an object allocated 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,"HeapCtrlBPInit",A="MN:HeapCtrlBPInit"$(). * The stk does not grow because virtual mem is not used. I recommend allocating large local vars from the heap. You can change $LK,"DFT_STK",A="MN:DFT_STK"$ and recompile $FG,2$Kernel$FG$ or request more when doing a $LK,"Spawn",A="MN:Spawn"$(). You can use $LK,"CallStkGrow",A="MN:CallStkGrow"$(), but it's odd. See $LK,"::/Demo/StkGrow.CPP"$. * Only one base class is allowed. * $FG,2$printf()$FG$ has new codes. See $LK,"Print(\"\") Fmt Strings",A="FI:::/Doc/Print.TXT"$. * 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); //Result is 0xC000000000000000 as expected U64 u3=0x8000000000000000; Print("%X\n",u3>>1); //Result is 0x4000000000000000 as expected I32 i4=0x80000000; //const is loaded into a 64-bit reg var. Print("%X\n",i4>>1); //Result is 0x40000000 I32 i5=-0x80000000; Print("%X\n",i5>>1); //Result is 0xFFFFFFFFC0000000 } $ID,-2$$FG$