#include <stdio.h> #define TEXT_SIZE 20000#define DATA_SIZE 2000#define SYM_TABLE_SIZE 10000#define VAR_TABLE_SIZE 4096 /* vac: offset of variables vat: type of variables loc : local variable index glo : global variable index parm : parameter variable index ind : output code ptr lsym: loop symbol stack rsym: return symbol prog: output code astk: arg position stack*/int tok, *vac, *vat, *lsym, rsym, prog, ind, loc, glo, file, vt, vc, *macro_stack, *macro_stack_ptr;char *idtable, *idptr, *idlast; /* The current value can be: */#define VT_CONST 0x0002 /* constant in vc */#define VT_VAR 0x0004 /* value is in eax */#define VT_LOCAL 0x0008 /* offset on stack */ #define VT_LVAL 0x0010 /* const or var is an lvalue */#define VT_CMP 0x0020 /* the value is stored in processor flags (in vc) */#define VT_FORWARD 0x0040 /* value is forward reference (only used for functions) */#define VT_JMP 0x0080 /* value is the consequence of jmp. bit 0 is set if inv */ #define VT_LVALN -17 /* ~VT_LVAL */ /* * * VT_FUNC indicates a function. The return type is the stored type. A * function pointer is stored as a 'char' pointer. * * If VT_PTRMASK is non nul, then it indicates the number of pointer * iterations to reach the basic type. * * Basic types: * * VT_BYTE indicate a char * * * otherwise integer type is assumed. * */ #define VT_BYTE 0x00001 /* byte pointer. HARDCODED VALUE */#define VT_PTRMASK 0x00f00 /* pointer mask */#define VT_PTRINC 0x00100 /* pointer increment */#define VT_FUNC 0x01000 /* function type */#define VT_TYPE 0x01f01 /* type mask */ #define VT_TYPEN 0xffffe0fe /* ~VT_TYPE */#define VT_FUNCN -4097 /* Special infos */#define VT_DEFINE 0x02000 /* special value for #defined symbols */ /* token values */#define TOK_INT 256#define TOK_VOID 257#define TOK_CHAR 258#define TOK_IF 259#define TOK_ELSE 260#define TOK_WHILE 261#define TOK_BREAK 262#define TOK_RETURN 263#define TOK_DEFINE 264#define TOK_MAIN 265 #define TOK_EQ 0x94 /* warning: depend on asm code */#define TOK_NE 0x95 /* warning: depend on asm code */#define TOK_LT 0x9c /* warning: depend on asm code */#define TOK_GE 0x9d /* warning: depend on asm code */#define TOK_LE 0x9e /* warning: depend on asm code */#define TOK_GT 0x9f /* warning: depend on asm code */ #define TOK_LAND 0xa0#define TOK_LOR 0xa1 #define TOK_DEC 0xa2#define TOK_MID 0xa3 /* inc/dec, to void constant */#define TOK_INC 0xa4 #define TOK_SHL 0xe0 /* warning: depend on asm code */#define TOK_SHR 0xf8 /* warning: depend on asm code */ #ifdef TESTvoid error(char *msg){ printf("%d: %s\n", ftell(file), msg); exit(1);}void warning(char *msg){ printf("%d: warning: %s\n", ftell(file), msg);}#endif int inp(){#if 0 int c; c = fgetc(file); printf("c=%c\n", c); return c;#else return fgetc(file);#endif} int isid(c){ return (c >= 'a' & c <= 'z') | (c >= 'A' & c <= 'Z') | c == '_';} int isnum(c){ return c >= '0' & c <= '9';} #ifdef TESTvoid skip(c){ if (tok != c) { fprintf(stderr, "%d: '%c' expected\n", ftell(file), c); exit(1); } next();}#else#define skip(c) next()#endif void next(){ int c, v; char *q, *p; while(1) { c = inp(); if (c == 35) { /* preprocessor: we handle only define */ next(); if (tok == TOK_DEFINE) { next(); /* now tok is the macro symbol */ vat[tok] = VT_DEFINE; vac[tok] = ftell(file); } /* ignore preprocessor or shell */ while (c != '\n') c = inp(); } else if (c == '\n') { /* end of line : check if we are in macro state. if so, pop new file position */ if (macro_stack_ptr > macro_stack) fseek(file, *--macro_stack_ptr, 0); } else if (c != ' ' & c != 9) break; } if (isid(c)) { q = idptr; idlast = q; while(isid(c) | isnum(c)) { *q++ = c; c = inp(); } *q++ = '\0'; ungetc(c, file); p = idtable; tok = 256; while (p < idptr) { if (strcmp(p, idptr) == 0) break; while (*p++); tok++; } /* if not found, add symbol */ if (p == idptr) idptr = q; /* eval defines */ if (vat[tok] & VT_DEFINE) { *macro_stack_ptr++ = ftell(file); fseek(file, vac[tok], 0); next(); } } else { q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\340>>\370"; /* two chars */ v = inp(); while (*q) { if (*q == c & q[1] == v) { tok = q[2] & 0xff; return; } q = q + 3; } ungetc(v, file); /* single char substitutions */ if (c == '<') tok = TOK_LT; else if (c == '>') tok = TOK_GT; else tok = c; }} void g(c){ *(char *)ind++ = c;} void o(c){ while (c) { g(c); c = c / 256; }} /* output a symbol and patch all calls to it */void gsym(t){ int n; while (t) { n = *(int *)t; /* next value */ *(int *)t = ind - t - 4; t = n; }} /* psym is used to put an instruction with a data field which is a reference to a symbol. It is in fact the same as oad ! */#define psym oad /* instruction + 4 bytes data. Return the address of the data */int oad(c, s){ o(c); *(int *)ind = s; s = ind; ind = ind + 4; return s;} /* push to value stack */void vset(t, v){ vt = t; vc = v;} /* generate a value in eax from vt and vc */void gv(){#ifndef TINY int t;#endif if (vt & VT_LVAL) { if ((vt & VT_TYPE) == VT_BYTE) o(0xbe0f); /* movsbl x, %eax */ else o(0x8b); /* movl x,%eax */ if (vt & VT_CONST) oad(0x05, vc); else if (vt & VT_LOCAL) oad(0x85, vc); else g(0x00); } else { if (vt & VT_CONST) { oad(0xb8, vc); /* mov $xx, %eax */ } else if (vt & VT_LOCAL) { oad(0x858d, vc); /* lea xxx(%ebp), %eax */ } else if (vt & VT_CMP) { oad(0xb8, 0); /* mov $0, %eax */ o(0x0f); /* setxx %al */ o(vc); o(0xc0); }#ifndef TINY else if (vt & VT_JMP) { t = vt & 1; oad(0xb8, t); /* mov $1, %eax */ oad(0xe9, 5); /* jmp after */ gsym(vc); oad(0xb8, t ^ 1); /* mov $0, %eax */ }#endif } vt = (vt & VT_TYPE) | VT_VAR;} /* generate a test. set 'inv' to invert test *//* XXX: handle constant */int gtst(inv, t){ if (vt & VT_CMP) { /* fast case : can jump directly since flags are set */ g(0x0f); t = psym((vc - 16) ^ inv, t); } else #ifndef TINY if (vt & VT_JMP) { /* && or || optimization */ if ((vt & 1) == inv) t = vc; else { t = psym(0xe9, t); gsym(vc); } } else if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST) { /* constant jmp optimization */ if ((vc != 0) != inv) t = psym(0xe9, t); } else#endif { gv(); o(0xc085); /* test %eax, %eax */ g(0x0f); t = psym(0x85 ^ inv, t); } return t;} /* return the size (in bytes) of a given type */int type_size(t){ if ((t & VT_PTRMASK) > VT_PTRINC | (t & VT_TYPE) == VT_PTRINC) return 4; else return 1;} #define POST_ADD 0x1000#define PRE_ADD 0 /* a defines POST/PRE add. c is the token ++ or -- */void inc(a, c){#ifdef TEST if (!(vt & VT_LVAL)) error("lvalue expected\n");#endif vt = vt & VT_LVALN; gv(); o(0x018bc189); /* movl %eax, %ecx ; mov (%ecx), %eax */ o(0x408d | a); /* leal x(%eax), %eax/%edx */ g((c - TOK_MID) * type_size(vt)); o(0x0189 | a); /* mov %eax/%edx, (%ecx) */} /* op is '-' or '+' (or 0) *//* t is the type of the first operand *//* XXX: handle ptr sub and 'int + ptr' case (only 'ptr + int' handled) */void gen_op(op, t){ gv(); o(0x59); /* pop %ecx */ if (op == '+' | op == '-') { /* XXX: incorrect for short (futur!) */ if (type_size(t) != 1) o(0x02e0c1); /* shl $2, %eax */ if (op == '-') o(0xd8f7); /* neg %eax */ o(0xc801); /* add %ecx, %eax */ vt = t; } else if (op == '&') o(0xc821); else if (op == '^') o(0xc831); else if (op == '|') o(0xc809); else if (op == '*') o(0xc1af0f); /* imul %ecx, %eax */ else if (op == TOK_SHL | op == TOK_SHR) { o(0xd391); /* xchg %ecx, %eax, shl/sar %cl, %eax */ o(op); } else if (op == '/' | op == '%') { o(0xd231); /* xor %edx, %edx */ o(0xf9f791); /* xchg %ecx, %eax, idiv %ecx, %eax */ if (op == '%') o(0x92); /* xchg %edx, %eax */ } else { o(0xc139); /* cmp %eax,%ecx */ vset(VT_CMP, op); }} /* return 0 if no type declaration. otherwise, return the basic type and skip it. XXX: A '2' is ored to ensure non zero return if int type. */int ist(){ int t; if (tok == TOK_INT | tok == TOK_CHAR | tok == TOK_VOID) { t = tok; next(); return (t != TOK_INT) | 2; } else { return 0; }} /* Read a type declaration (except basic type), and return the type. If v is true, then also put variable name in 'vc' */int typ(v,t){ int u, p, n; t = t & -3; /* suppress the ored '2' */ while (tok == '*') { next(); t = t + VT_PTRINC; } /* recursive type */ /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ if (tok == '(') { next(); u = typ(v, 0); skip(')'); } else { u = 0; /* type identifier */ if (v) { vc = tok; next(); } } /* function declaration */ if (tok == '(') { next(); p = 4; n = vc; /* must save vc there */ while (tok != ')') { /* read param name and compute offset */ if (t = ist()) t = typ(1, t); /* XXX: should accept both arg/non arg if v == 0 */ else { vc = tok; t = 0; next(); } p = p + 4; vat[vc] = VT_LOCAL | VT_LVAL | t; vac[vc] = p; if (tok == ',') next(); } next(); /* skip ')' */ vc = n; if (u) t = u + VT_BYTE; else t = t | VT_FUNC; } return t;} int getq(n){ int c; if (n == '\\') { n = inp(); if (n == 'n') n = '\n'; else if (isnum(n)) { c = 0; while (isnum(n)) { c = c * 8 + n - '0'; n = inp(); } ungetc(n, file); return c; } } return n;} void unary(){ int n, t, ft, fc, p; if (isnum(tok)) { /* number */ n = 0;Lines 1–500 of 920. Load more
#include <stdio.h> #define TEXT_SIZE 20000 #define DATA_SIZE 2000 #define SYM_TABLE_SIZE 10000 #define VAR_TABLE_SIZE 4096 /* vac: offset of variables vat: type of variables loc : local variable index glo : global variable index parm : parameter variable index ind : output code ptr lsym: loop symbol stack rsym: return symbol prog: output code astk: arg position stack */ int tok, *vac, *vat, *lsym, rsym, prog, ind, loc, glo, file, vt, vc, *macro_stack, *macro_stack_ptr; char *idtable, *idptr, *idlast; /* The current value can be: */ #define VT_CONST 0x0002 /* constant in vc */ #define VT_VAR 0x0004 /* value is in eax */ #define VT_LOCAL 0x0008 /* offset on stack */ #define VT_LVAL 0x0010 /* const or var is an lvalue */ #define VT_CMP 0x0020 /* the value is stored in processor flags (in vc) */ #define VT_FORWARD 0x0040 /* value is forward reference (only used for functions) */ #define VT_JMP 0x0080 /* value is the consequence of jmp. bit 0 is set if inv */ #define VT_LVALN -17 /* ~VT_LVAL */ /* * * VT_FUNC indicates a function. The return type is the stored type. A * function pointer is stored as a 'char' pointer. * * If VT_PTRMASK is non nul, then it indicates the number of pointer * iterations to reach the basic type. * * Basic types: * * VT_BYTE indicate a char * * * otherwise integer type is assumed. * */ #define VT_BYTE 0x00001 /* byte pointer. HARDCODED VALUE */ #define VT_PTRMASK 0x00f00 /* pointer mask */ #define VT_PTRINC 0x00100 /* pointer increment */ #define VT_FUNC 0x01000 /* function type */ #define VT_TYPE 0x01f01 /* type mask */ #define VT_TYPEN 0xffffe0fe /* ~VT_TYPE */ #define VT_FUNCN -4097 /* Special infos */ #define VT_DEFINE 0x02000 /* special value for #defined symbols */ /* token values */ #define TOK_INT 256 #define TOK_VOID 257 #define TOK_CHAR 258 #define TOK_IF 259 #define TOK_ELSE 260 #define TOK_WHILE 261 #define TOK_BREAK 262 #define TOK_RETURN 263 #define TOK_DEFINE 264 #define TOK_MAIN 265 #define TOK_EQ 0x94 /* warning: depend on asm code */ #define TOK_NE 0x95 /* warning: depend on asm code */ #define TOK_LT 0x9c /* warning: depend on asm code */ #define TOK_GE 0x9d /* warning: depend on asm code */ #define TOK_LE 0x9e /* warning: depend on asm code */ #define TOK_GT 0x9f /* warning: depend on asm code */ #define TOK_LAND 0xa0 #define TOK_LOR 0xa1 #define TOK_DEC 0xa2 #define TOK_MID 0xa3 /* inc/dec, to void constant */ #define TOK_INC 0xa4 #define TOK_SHL 0xe0 /* warning: depend on asm code */ #define TOK_SHR 0xf8 /* warning: depend on asm code */ #ifdef TEST void error(char *msg) { printf("%d: %s\n", ftell(file), msg); exit(1); } void warning(char *msg) { printf("%d: warning: %s\n", ftell(file), msg); } #endif int inp() { #if 0 int c; c = fgetc(file); printf("c=%c\n", c); return c; #else return fgetc(file); #endif } int isid(c) { return (c >= 'a' & c <= 'z') | (c >= 'A' & c <= 'Z') | c == '_'; } int isnum(c) { return c >= '0' & c <= '9'; } #ifdef TEST void skip(c) { if (tok != c) { fprintf(stderr, "%d: '%c' expected\n", ftell(file), c); exit(1); } next(); } #else #define skip(c) next() #endif void next() { int c, v; char *q, *p; while(1) { c = inp(); if (c == 35) { /* preprocessor: we handle only define */ next(); if (tok == TOK_DEFINE) { next(); /* now tok is the macro symbol */ vat[tok] = VT_DEFINE; vac[tok] = ftell(file); } /* ignore preprocessor or shell */ while (c != '\n') c = inp(); } else if (c == '\n') { /* end of line : check if we are in macro state. if so, pop new file position */ if (macro_stack_ptr > macro_stack) fseek(file, *--macro_stack_ptr, 0); } else if (c != ' ' & c != 9) break; } if (isid(c)) { q = idptr; idlast = q; while(isid(c) | isnum(c)) { *q++ = c; c = inp(); } *q++ = '\0'; ungetc(c, file); p = idtable; tok = 256; while (p < idptr) { if (strcmp(p, idptr) == 0) break; while (*p++); tok++; } /* if not found, add symbol */ if (p == idptr) idptr = q; /* eval defines */ if (vat[tok] & VT_DEFINE) { *macro_stack_ptr++ = ftell(file); fseek(file, vac[tok], 0); next(); } } else { q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\340>>\370"; /* two chars */ v = inp(); while (*q) { if (*q == c & q[1] == v) { tok = q[2] & 0xff; return; } q = q + 3; } ungetc(v, file); /* single char substitutions */ if (c == '<') tok = TOK_LT; else if (c == '>') tok = TOK_GT; else tok = c; } } void g(c) { *(char *)ind++ = c; } void o(c) { while (c) { g(c); c = c / 256; } } /* output a symbol and patch all calls to it */ void gsym(t) { int n; while (t) { n = *(int *)t; /* next value */ *(int *)t = ind - t - 4; t = n; } } /* psym is used to put an instruction with a data field which is a reference to a symbol. It is in fact the same as oad ! */ #define psym oad /* instruction + 4 bytes data. Return the address of the data */ int oad(c, s) { o(c); *(int *)ind = s; s = ind; ind = ind + 4; return s; } /* push to value stack */ void vset(t, v) { vt = t; vc = v; } /* generate a value in eax from vt and vc */ void gv() { #ifndef TINY int t; #endif if (vt & VT_LVAL) { if ((vt & VT_TYPE) == VT_BYTE) o(0xbe0f); /* movsbl x, %eax */ else o(0x8b); /* movl x,%eax */ if (vt & VT_CONST) oad(0x05, vc); else if (vt & VT_LOCAL) oad(0x85, vc); else g(0x00); } else { if (vt & VT_CONST) { oad(0xb8, vc); /* mov $xx, %eax */ } else if (vt & VT_LOCAL) { oad(0x858d, vc); /* lea xxx(%ebp), %eax */ } else if (vt & VT_CMP) { oad(0xb8, 0); /* mov $0, %eax */ o(0x0f); /* setxx %al */ o(vc); o(0xc0); } #ifndef TINY else if (vt & VT_JMP) { t = vt & 1; oad(0xb8, t); /* mov $1, %eax */ oad(0xe9, 5); /* jmp after */ gsym(vc); oad(0xb8, t ^ 1); /* mov $0, %eax */ } #endif } vt = (vt & VT_TYPE) | VT_VAR; } /* generate a test. set 'inv' to invert test */ /* XXX: handle constant */ int gtst(inv, t) { if (vt & VT_CMP) { /* fast case : can jump directly since flags are set */ g(0x0f); t = psym((vc - 16) ^ inv, t); } else #ifndef TINY if (vt & VT_JMP) { /* && or || optimization */ if ((vt & 1) == inv) t = vc; else { t = psym(0xe9, t); gsym(vc); } } else if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST) { /* constant jmp optimization */ if ((vc != 0) != inv) t = psym(0xe9, t); } else #endif { gv(); o(0xc085); /* test %eax, %eax */ g(0x0f); t = psym(0x85 ^ inv, t); } return t; } /* return the size (in bytes) of a given type */ int type_size(t) { if ((t & VT_PTRMASK) > VT_PTRINC | (t & VT_TYPE) == VT_PTRINC) return 4; else return 1; } #define POST_ADD 0x1000 #define PRE_ADD 0 /* a defines POST/PRE add. c is the token ++ or -- */ void inc(a, c) { #ifdef TEST if (!(vt & VT_LVAL)) error("lvalue expected\n"); #endif vt = vt & VT_LVALN; gv(); o(0x018bc189); /* movl %eax, %ecx ; mov (%ecx), %eax */ o(0x408d | a); /* leal x(%eax), %eax/%edx */ g((c - TOK_MID) * type_size(vt)); o(0x0189 | a); /* mov %eax/%edx, (%ecx) */ } /* op is '-' or '+' (or 0) */ /* t is the type of the first operand */ /* XXX: handle ptr sub and 'int + ptr' case (only 'ptr + int' handled) */ void gen_op(op, t) { gv(); o(0x59); /* pop %ecx */ if (op == '+' | op == '-') { /* XXX: incorrect for short (futur!) */ if (type_size(t) != 1) o(0x02e0c1); /* shl $2, %eax */ if (op == '-') o(0xd8f7); /* neg %eax */ o(0xc801); /* add %ecx, %eax */ vt = t; } else if (op == '&') o(0xc821); else if (op == '^') o(0xc831); else if (op == '|') o(0xc809); else if (op == '*') o(0xc1af0f); /* imul %ecx, %eax */ else if (op == TOK_SHL | op == TOK_SHR) { o(0xd391); /* xchg %ecx, %eax, shl/sar %cl, %eax */ o(op); } else if (op == '/' | op == '%') { o(0xd231); /* xor %edx, %edx */ o(0xf9f791); /* xchg %ecx, %eax, idiv %ecx, %eax */ if (op == '%') o(0x92); /* xchg %edx, %eax */ } else { o(0xc139); /* cmp %eax,%ecx */ vset(VT_CMP, op); } } /* return 0 if no type declaration. otherwise, return the basic type and skip it. XXX: A '2' is ored to ensure non zero return if int type. */ int ist() { int t; if (tok == TOK_INT | tok == TOK_CHAR | tok == TOK_VOID) { t = tok; next(); return (t != TOK_INT) | 2; } else { return 0; } } /* Read a type declaration (except basic type), and return the type. If v is true, then also put variable name in 'vc' */ int typ(v,t) { int u, p, n; t = t & -3; /* suppress the ored '2' */ while (tok == '*') { next(); t = t + VT_PTRINC; } /* recursive type */ /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ if (tok == '(') { next(); u = typ(v, 0); skip(')'); } else { u = 0; /* type identifier */ if (v) { vc = tok; next(); } } /* function declaration */ if (tok == '(') { next(); p = 4; n = vc; /* must save vc there */ while (tok != ')') { /* read param name and compute offset */ if (t = ist()) t = typ(1, t); /* XXX: should accept both arg/non arg if v == 0 */ else { vc = tok; t = 0; next(); } p = p + 4; vat[vc] = VT_LOCAL | VT_LVAL | t; vac[vc] = p; if (tok == ',') next(); } next(); /* skip ')' */ vc = n; if (u) t = u + VT_BYTE; else t = t | VT_FUNC; } return t; } int getq(n) { int c; if (n == '\\') { n = inp(); if (n == 'n') n = '\n'; else if (isnum(n)) { c = 0; while (isnum(n)) { c = c * 8 + n - '0'; n = inp(); } ungetc(n, file); return c; } } return n; } void unary() { int n, t, ft, fc, p; if (isnum(tok)) { /* number */ n = 0;