hschumann2/TempleOS-Source-Code
0847
1 2/*3-] Main Compiler4 The mini compiler is like the main compiler, except the main compiler's5 lexical analyser removes comments and does preprocessing. Lex(),Echo(ON).6 7 The main compiler generates Intermediate Code at the parser stage. See8 PrsExpression(), PrsStmt().9 10 The main compiler optimizes See Intermediate Code Attributes,11 Combining Consts, Choosing Reg Vars. Use PassTrace() to see the optimization12 stages.13 14 The main compiler makes machine code in the back end. See IC Struct,15 COCCompile and OptPass789A(), BackEnd. Set Trace(ON) to see the output of the16 backend.17 18-] Mini Compiler19 For this mini compiler, some things you should know about 64-bit asm:20 21 * Putting a 0x48, known as the REX byte, in front of an inst makes it 64-bit22 size.23 24 * "PUSH EAX", "POP EAX" and "XOR EAX,EAX" will behave as 64-bit even without25 REX because the stk is always 64 bit and because the XOR clears the upper26 32-bits.27 28 It is okay in TempleOS to change RAX, RBX, RCX, RDX, R8 and R9 without29 restoring them to their original values.30*/31 32#define TK_EOF 033#define TK_NUM 134#define TK_OP 235#define TK_LEFT 336#define TK_RIGHT 437 38#define OP_MUL 139#define OP_DIV 240#define OP_ADD 341#define OP_SUB 442 43I64 Lex(U8 **_src,I64 *num)44{//See Lex().45 U8 *src=*_src;46 I64 i;47 while (TRUE) {48 switch (*src) {49 case 0:50 case ';':51 *_src=src;52 return TK_EOF;53 case CH_SPACE:54 case '\r':55 case '\n':56 src++;57 break;58 case '0'...'9':59 i=0;60 do {61 i=i*10+*src-'0';62 src++;63 } while ('0'<=*src<='9');64 *num=i;65 *_src=src;66 return TK_NUM;67 case '*':68 *num=OP_MUL;69 *_src=src+1;70 return TK_OP;71 case '/':72 *num=OP_DIV;73 *_src=src+1;74 return TK_OP;75 case '+':76 *num=OP_ADD;77 *_src=src+1;78 return TK_OP;79 case '-':80 *num=OP_SUB;81 *_src=src+1;82 return TK_OP;83 case '(':84 *_src=src+1;85 return TK_LEFT;86 case ')':87 *_src=src+1;88 return TK_RIGHT;89 default:90 throw;91 }92 }93}94 95#define PREC_EOF 096#define PREC_TERM 197#define PREC_MUL 298#define PREC_ADD 399#define PREC_PAREN 4100 101extern I64 Parse(U8 **_src,U8 **_dst);102 103U0 PrsTerm(U8 **_src,U8 **_dst,I64 prec)104{//See PrsExpression().105 I64 i;106 U8 *src2;107 U8 *dst2;108 if (Parse(_src,_dst)==PREC_TERM) {109 src2=*_src;110 dst2=*_dst;111 while (TRUE) {112//This is inefficient. The main compiler doesn't back-up like this.113 i=Parse(&src2,&dst2);114 if (PREC_MUL<=i<prec) {115 *_src=src2;116 *_dst=dst2;117 } else118 break;119 }120 } else121 throw;122}123 124I64 Parse(U8 **_src,U8 **_dst)125{//See PrsExpression().126//See Opcode Fmts for details on asm insts.127 I64 i;128 U8 *dst=*_dst;129 switch (Lex(_src,&i)) {130 case TK_EOF:131 *dst++=0x58; //POP RAX132 *dst++=0xC3; //RET133 *_dst=dst;134 return PREC_EOF;135 case TK_NUM:136 *dst++=0x48; //REX137 *dst++=0xB8; //MOV RAX,immediate num138 *dst(I64 *)++=i;139 140 *dst++=0x50; //PUSH RAX141 *_dst=dst;142 return PREC_TERM;143 case TK_LEFT:144 PrsTerm(_src,_dst,PREC_PAREN);145 if (Parse(_src,_dst)!=PREC_PAREN)146 throw;147 return PREC_TERM;148 case TK_RIGHT:149 return PREC_PAREN;150 case TK_OP:151 switch (i) {152 case OP_MUL:153 PrsTerm(_src,&dst,PREC_MUL);154 *dst++=0x5A; //POP RDX155 *dst++=0x58; //POP RAX156 157 *dst++=0x48; //REX158 *dst++=0x0F;159 *dst++=0xAF; //IMUL RAX,RDX160 *dst++=0xC2;161 162 *dst++=0x50; //PUSH RAX163 *_dst=dst;164 return PREC_MUL;165 case OP_DIV:166 PrsTerm(_src,&dst,PREC_MUL);167 *dst++=0x5B; //POP RBX168 *dst++=0x58; //POP RAX169 170 *dst++=0x33; //XOR RDX,RDX171 *dst++=0xD2;172 173 *dst++=0x48; //REX174 *dst++=0xF7; //IDIV RBX175 *dst++=0xFB;176 177 *dst++=0x50; //PUSH RAX178 *_dst=dst;179 return PREC_MUL;180 case OP_ADD:181 PrsTerm(_src,&dst,PREC_ADD);182 *dst++=0x5A; //POP RDX183 *dst++=0x58; //POP RAX184 185 *dst++=0x48; //REX186 *dst++=0x03; //ADD RAX,RDX187 *dst++=0xC2;188 189 *dst++=0x50; //PUSH RAX190 *_dst=dst;191 return PREC_ADD;192 case OP_SUB:193 PrsTerm(_src,&dst,PREC_ADD);194 *dst++=0x5A; //POP RDX195 *dst++=0x58; //POP RAX196 197 *dst++=0x48; //REX198 *dst++=0x2B; //SUB RAX,RDX199 *dst++=0xC2;200 201 *dst++=0x50; //PUSH RAX202 *_dst=dst;203 return PREC_ADD;204 }205 }206}207 208U0 Main()209{210 U8 *src,*src2,*code,*dst;211 212 //Fixed size, no buffer overrun check.213 //You can make it fancier if you like.214 code=MAlloc(512,Fs->code_heap);215 216 while (TRUE) {217 "This will compile an expression\n"218 "consisting of ints, parentheses\n"219 "and the operators +,-,* and /.\n";220 src=GetStr;221 if (*src) {222 src2=src;223 dst=code;224 try {225 PrsTerm(&src2,&dst,PREC_PAREN);226 if (Parse(&src2,&dst)!=PREC_EOF)227 throw;228 "$RED$This code is not efficient, but the compiler is simple.$FG$\n";229 Un(code,dst-code); //Unassemble the code we created.230//Call() is a function. See _CALL::231 //See also CallInd(). See _CALL_IND::232 "$LTBLUE$Answer:%d$FG$\n",Call(code);233 } catch {234 "$RED$Error$FG$\n";235 PutExcept;236 }237 Free(src);238 } else {239 Free(src);240 break;241 }242 }243 Free(code);244}245 246Main;247 248 