bellardInitial revision27f6e1625 years agoHistory
920 lines · 21.0 KB · C
RawDownload
#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.