/*$WW,1$ $TR,"Main Compiler"$ $ID,2$The mini compiler is like the main compiler, except the main compiler's lexical analyser removes comments and does preprocessing. See $LK,"Lex","MN:Lex"$(). Set $LK,"Echo","MN:Echo"$(ON) or $LK,"LTrace","MN:LTrace"$(ON), to see the output of the lexical analyser. The main compiler generates $LK,"Intermediate Code","FF:::/SparrowOS/Compiler/CmpDefs.HPP.Z,IC_END"$ at the parser stage. See $LK,"PrsExpression","MN:PrsExpression"$(), $LK,"PrsStatement","MN:PrsStatement"$(). Set $LK,"PTrace","MN:PTrace"$(ON) to see the output of the parser. The main compiler optimizes See $LK,"Intermediate Code Attributes","FF:D:/SparrowOS/Compiler/CmpInit.CPP.Z,ST_INTERMEDIATE_CODE"$, $LK,"Combining Constants","FF:::/SparrowOS/Compiler/OptPass012.CPP.Z,IC_MUL"$, $LK,"Choosing Reg Vars","FF:::/SparrowOS/Compiler/OptPass3.CPP.Z,num_reg_vars"$. Set $LK,"OTrace","MN:OTrace"$(ON) to see the optimization stages. The main compiler makes machine code in the back end. See $LK,"IC Struct","MN:CIntermediateCode"$, $LK,"CBCompile","MN:CBCompile"$ and $LK,"OptPass789A","FF:::/SparrowOS/Compiler/OptPass789A.CPP.Z,IC_MUL"$(), $LK,"BackEnd","FF:::/SparrowOS/Compiler/BackEnd.CPP.Z,ICMul"$. Set $LK,"CTrace","MN:CTrace"$(ON) to see the output of the backend. $ID,-2$ $TR,"Mini Compiler"$ $ID,2$For this mini compiler, some things you should know about 64-bit asm: * Putting a 0x48, known as the REX byte, in front of an instruction makes it 64-bit size. * "PUSH EAX", "POP EAX" and "XOR EAX,EAX" will behave as 64-bit even without REX because the stk is always 64 bit and because the XOR clears the upper 32-bits. It is okay in SparrowOS to change RAX, RBX, RCX, RDX, R8 and R9 without restoring them to their original values. $ID,-2$$WW,0$*/ #define TK_EOF 0 #define TK_NUM 1 #define TK_OP 2 #define TK_LEFT 3 #define TK_RIGHT 4 #define OP_MUL 1 #define OP_DIV 2 #define OP_ADD 3 #define OP_SUB 4 I64 Lex(U8 **_src,I64 *num) { //See $LK,"Lex","MN:Lex"$(). U8 *src=*_src; I64 i; while (TRUE) { switch (*src) { case 0: case ';': *_src=src; return TK_EOF; case CH_SPACE: case CH_CARRIAGE_RETURN: case CH_NEW_LINE: src++; break; case '0'...'9': i=0; do { i=i*10+*src-'0'; src++; } while ('0'<=*src<='9'); *num=i; *_src=src; return TK_NUM; case '*': *num=OP_MUL; *_src=src+1; return TK_OP; case '/': *num=OP_DIV; *_src=src+1; return TK_OP; case '+': *num=OP_ADD; *_src=src+1; return TK_OP; case '-': *num=OP_SUB; *_src=src+1; return TK_OP; case '(': *_src=src+1; return TK_LEFT; case ')': *_src=src+1; return TK_RIGHT; default: throw; } } } #define PREC_EOF 0 #define PREC_TERM 1 #define PREC_MUL 2 #define PREC_ADD 3 #define PREC_PAREN 4 extern I64 Parse(U8 **_src,U8 **_dst); U0 PrsTerm(U8 **_src,U8 **_dst,I64 prec) { //See $LK,"PrsExpression","MN:PrsExpression"$(). I64 i; U8 *src2; U8 *dst2; if (Parse(_src,_dst)==PREC_TERM) { src2=*_src; dst2=*_dst; while (TRUE) { //This is inefficient. The main compiler doesn't back-up. i=Parse(&src2,&dst2); if (PREC_MUL<=icode_heap); while (TRUE) { "This will compile an expression\n" "consisting of integers, parentheses\n" "and the operators +,-,* and /.\n"; src=MGetS; if (*src) { src2=src; dst=code; try { PrsTerm(&src2,&dst,PREC_PAREN); if (Parse(&src2,&dst)!=PREC_EOF) throw; "$$FG,RED$$This code is not efficient, but the compiler is simple.$$FG$$\n"; Un(code,dst-code); //Unassemble the code we created. //$LK,"Call","MN:Call"$() is a function. See $LK,"_CALL","FF:::/SparrowOS/OSMain/Utils1a.CPP.Z,_CALL"$:: //See also $LK,"CallInd","MN:CallInd"$(). See $LK,"_CALLIND","FF:::/SparrowOS/OSMain/Utils1a.CPP.Z,_CALLIND"$:: "$$FG,LTBLUE$$Answer:%d$$FG$$\n",Call(code); } catch { "$$FG,RED$$Error$$FG$$\n"; CatchAll; } Free(src); } else { Free(src); break; } } Free(code); } Main;