/*$WW,1$ $TR-C,"Main Compiler"$ $ID,2$The mini compiler is like the main compiler, except the main compiler's lexical analyser removes comments and does preprocessing. $LK,"Lex",A="MN:Lex"$(),$LK,"Echo",A="MN:Echo"$(ON). The main compiler generates $LK,"Intermediate Code",A="FF:::/Compiler/CompilerA.HH,IC_END"$ at the parser stage. See $LK,"ParseExpression",A="MN:ParseExpression"$(), $LK,"ParseStatement",A="MN:ParseStatement"$(). The main compiler optimizes See $LK,"Intermediate Code Attributes",A="MN:intermediate_code_table"$, $LK,"Combining Consts",A="FF:::/Compiler/OptPass012.CC,case IC_MUL"$, $LK,"Choosing Reg Vars",A="FF:::/Compiler/OptPass3.CC,cmp.num_reg_vars"$. Use $LK,"PassTrace",A="MN:PassTrace"$() to see the optimization stages. The main compiler makes machine code in the back end. See $LK,"IC Struct",A="MN:CIntermediateCode"$, $LK,"COCCompile",A="MN:COCCompile"$ and $LK,"OptPass789A",A="FF:::/Compiler/OptPass789A.CC,IC_MUL"$(), $LK,"BackEnd",A="FF:::/Compiler/BackA.CC,ICMul"$. Set $LK,"Trace",A="MN:Trace"$(ON) to see the output of the backend. $ID,-2$ $TR-C,"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 inst makes it 64-bit size. * "PUSH EAX", "POP EAX" and "XOR EAX,EAX" will behave as 64-bit even without REX because the stack is always 64 bit and because the XOR clears the upper 32-bits. It is okay in ZenithOS 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",A="MN:Lex"$(). U8 *src=*_src; I64 i; while (TRUE) { switch (*src) { case 0: case ';': *_src=src; return TK_EOF; case CH_SPACE: case '\r': case '\n': 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 ParseTerm(U8 **_src,U8 **_dst,I64 prec) {//See $LK,"ParseExpression",A="MN:ParseExpression"$(). 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 like this. i=Parse(&src2,&dst2); if (PREC_MUL<=icode_heap); while (TRUE) { "This will compile an expression\n" "consisting of ints, parentheses\n" "and the operators +,-,* and /.\n"; src=StrGet; if (*src) { src2=src; dst=code; try { ParseTerm(&src2,&dst,PREC_PAREN); if (Parse(&src2,&dst)!=PREC_EOF) throw; "$$RED$$This code is not efficient, but the compiler is simple.$$FG$$\n"; Un(code,dst-code); //Unassemble the code we created. //$LK,"Call",A="MN:Call"$() is a function. See $LK,"_CALL",A="FF:::/Kernel/KUtils.CC,_CALL"$:: //See also $LK,"CallInd",A="MN:CallInd"$(). See $LK,"_CALL_IND",A="FF:::/Kernel/KUtils.CC,_CALL_IND"$:: "$$LTBLUE$$Answer:%d$$FG$$\n",Call(code); } catch { "$$RED$$Error$$FG$$\n"; PutExcept; } Free(src); } else { Free(src); break; } } Free(code); } Main;