mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-27 14:22:11 +00:00
494 lines
11 KiB
C
494 lines
11 KiB
C
#include <time.h>
|
|
#include <ctype.h>
|
|
#include "c.h"
|
|
|
|
#define I(f) s_##f
|
|
|
|
static Node *tail;
|
|
static int off, maxoff, uid = 0, verbose = 0, html = 0;
|
|
|
|
static const char *yyBEGIN(const char *tag) {
|
|
if (html)
|
|
print("<%s>", tag);
|
|
return tag;
|
|
}
|
|
|
|
static void yyEND(const char *tag) {
|
|
if (html)
|
|
print("</%s>", tag);
|
|
if (isupper(*tag))
|
|
print("\n");
|
|
}
|
|
|
|
#define BEGIN(tag) do { const char *yytag=yyBEGIN(#tag);
|
|
#define END yyEND(yytag); } while (0)
|
|
#define ITEM BEGIN(li)
|
|
#define START BEGIN(LI)
|
|
#define ANCHOR(attr,code) do { const char *yytag="a"; if (html) { printf("<a " #attr "=\""); code; print("\">"); }
|
|
#define NEWLINE print(html ? "<br>\n" : "\n")
|
|
|
|
static void emitCoord(Coordinate src) {
|
|
if (src.file && *src.file) {
|
|
ANCHOR(href,print("%s", src.file)); print("%s", src.file); END;
|
|
print(":");
|
|
}
|
|
print("%d.%d", src.y, src.x);
|
|
}
|
|
|
|
static void emitString(int len, const char *s) {
|
|
for ( ; len-- > 0; s++)
|
|
if (*s == '&' && html)
|
|
print("&");
|
|
else if (*s == '<' && html)
|
|
print("<");
|
|
else if (*s == '>' && html)
|
|
print("<");
|
|
else if (*s == '"' || *s == '\\')
|
|
print("\\%c", *s);
|
|
else if (*s >= ' ' && *s < 0177)
|
|
print("%c", *s);
|
|
else
|
|
print("\\%d%d%d", (*s>>6)&3, (*s>>3)&7, *s&7);
|
|
}
|
|
|
|
static void emitSymRef(Symbol p) {
|
|
(*IR->defsymbol)(p);
|
|
ANCHOR(href,print("#%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
|
|
}
|
|
|
|
static void emitSymbol(Symbol p) {
|
|
(*IR->defsymbol)(p);
|
|
ANCHOR(name,print("%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
|
|
BEGIN(ul);
|
|
#define xx(field,code) ITEM; if (!html) print(" "); print(#field "="); code; END
|
|
if (verbose && (src.y || src.x))
|
|
xx(src,emitCoord(p->src));
|
|
xx(type,print("%t", p->type));
|
|
xx(sclass,print("%k", p->sclass));
|
|
switch (p->scope) {
|
|
case CONSTANTS: xx(scope,print("CONSTANTS")); break;
|
|
case LABELS: xx(scope,print("LABELS")); break;
|
|
case GLOBAL: xx(scope,print("GLOBAL")); break;
|
|
case PARAM: xx(scope,print("PARAM")); break;
|
|
case LOCAL: xx(scope,print("LOCAL")); break;
|
|
default:
|
|
if (p->scope > LOCAL)
|
|
xx(scope,print("LOCAL+%d", p->scope-LOCAL));
|
|
else
|
|
xx(scope,print("%d", p->scope));
|
|
}
|
|
if (p->scope >= PARAM && p->sclass != STATIC)
|
|
xx(offset,print("%d", p->x.offset));
|
|
xx(ref,print("%f", p->ref));
|
|
if (p->temporary && p->u.t.cse)
|
|
xx(u.t.cse,print("%p", p->u.t.cse));
|
|
END;
|
|
#undef xx
|
|
}
|
|
|
|
/* address - initialize q for addressing expression p+n */
|
|
static void I(address)(Symbol q, Symbol p, long n) {
|
|
q->name = stringf("%s%s%D", p->name, n > 0 ? "+" : "", n);
|
|
(*IR->defsymbol)(q);
|
|
START; print("address "); emitSymbol(q); END;
|
|
}
|
|
|
|
/* blockbeg - start a block */
|
|
static void I(blockbeg)(Env *e) {
|
|
e->offset = off;
|
|
START; print("blockbeg off=%d", off); END;
|
|
}
|
|
|
|
/* blockend - start a block */
|
|
static void I(blockend)(Env *e) {
|
|
if (off > maxoff)
|
|
maxoff = off;
|
|
START; print("blockend off=%d", off); END;
|
|
off = e->offset;
|
|
}
|
|
|
|
/* defaddress - initialize an address */
|
|
static void I(defaddress)(Symbol p){
|
|
START; print("defaddress "); emitSymRef(p); END;
|
|
}
|
|
|
|
/* defconst - define a constant */
|
|
static void I(defconst)(int suffix, int size, Value v) {
|
|
START;
|
|
print("defconst ");
|
|
switch (suffix) {
|
|
case I:
|
|
print("int.%d ", size);
|
|
BEGIN(code);
|
|
if (size > sizeof (int))
|
|
print("%D", v.i);
|
|
else
|
|
print("%d", (int)v.i);
|
|
END;
|
|
break;
|
|
case U:
|
|
print("unsigned.%d ", size);
|
|
BEGIN(code);
|
|
if (size > sizeof (unsigned))
|
|
print("%U", v.u);
|
|
else
|
|
print("%u", (unsigned)v.u);
|
|
END;
|
|
break;
|
|
case P: print("void*.%d ", size); BEGIN(code); print("%p", v.p); END; break;
|
|
case F: print("float.%d ", size); BEGIN(code); print("%g", (double)v.d); END; break;
|
|
default: assert(0);
|
|
}
|
|
END;
|
|
}
|
|
|
|
/* defstring - emit a string constant */
|
|
static void I(defstring)(int len, char *s) {
|
|
START; print("defstring ");
|
|
BEGIN(code); print("\""); emitString(len, s); print("\""); END;
|
|
END;
|
|
}
|
|
|
|
/* defsymbol - define a symbol: initialize p->x */
|
|
static void I(defsymbol)(Symbol p) {
|
|
if (p->x.name == NULL)
|
|
p->x.name = stringd(++uid);
|
|
}
|
|
|
|
/* emit - emit the dags on list p */
|
|
static void I(emit)(Node p){
|
|
ITEM;
|
|
if (!html)
|
|
print(" ");
|
|
for (; p; p = p->x.next) {
|
|
if (p->op == LABEL+V) {
|
|
assert(p->syms[0]);
|
|
ANCHOR(name,print("%s", p->syms[0]->x.name));
|
|
BEGIN(code); print("%s", p->syms[0]->name); END;
|
|
END;
|
|
print(":");
|
|
} else {
|
|
int i;
|
|
if (p->x.listed) {
|
|
BEGIN(strong); print("%d", p->x.inst); END; print("'");
|
|
print(" %s", opname(p->op));
|
|
} else
|
|
print("%d. %s", p->x.inst, opname(p->op));
|
|
if (p->count > 1)
|
|
print(" count=%d", p->count);
|
|
for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
|
|
print(" #%d", p->kids[i]->x.inst);
|
|
if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
|
|
print(" {%t}", p->syms[0]->type);
|
|
else
|
|
for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) {
|
|
print(" ");
|
|
if (p->syms[i]->scope == CONSTANTS)
|
|
print(p->syms[i]->name);
|
|
else
|
|
emitSymRef(p->syms[i]);
|
|
}
|
|
}
|
|
NEWLINE;
|
|
}
|
|
END;
|
|
}
|
|
|
|
/* export - announce p as exported */
|
|
static void I(export)(Symbol p) {
|
|
START; print("export "); emitSymRef(p); END;
|
|
}
|
|
|
|
/* function - generate code for a function */
|
|
static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
|
|
int i;
|
|
|
|
(*IR->defsymbol)(f);
|
|
off = 0;
|
|
for (i = 0; caller[i] && callee[i]; i++) {
|
|
off = roundup(off, caller[i]->type->align);
|
|
caller[i]->x.offset = callee[i]->x.offset = off;
|
|
off += caller[i]->type->size;
|
|
}
|
|
if (!html) {
|
|
print("function ");
|
|
emitSymbol(f);
|
|
print(" ncalls=%d\n", ncalls);
|
|
for (i = 0; caller[i]; i++)
|
|
START; print("caller "); emitSymbol(caller[i]); END;
|
|
for (i = 0; callee[i]; i++)
|
|
START; print("callee "); emitSymbol(callee[i]); END;
|
|
} else {
|
|
START;
|
|
print("function");
|
|
BEGIN(UL);
|
|
#define xx(field,code) ITEM; print(#field "="); code; END
|
|
xx(f,emitSymbol(f));
|
|
xx(ncalls,print("%d", ncalls));
|
|
if (caller[0]) {
|
|
ITEM; print("caller"); BEGIN(OL);
|
|
for (i = 0; caller[i]; i++)
|
|
ITEM; emitSymbol(caller[i]); END;
|
|
END; END;
|
|
ITEM; print("callee"); BEGIN(OL);
|
|
for (i = 0; callee[i]; i++)
|
|
ITEM; emitSymbol(callee[i]); END;
|
|
END; END;
|
|
} else {
|
|
xx(caller,BEGIN(em); print("empty"); END);
|
|
xx(callee,BEGIN(em); print("empty"); END);
|
|
}
|
|
END;
|
|
END;
|
|
}
|
|
maxoff = off = 0;
|
|
gencode(caller, callee);
|
|
if (html)
|
|
START; print("emitcode"); BEGIN(ul); emitcode(); END; END;
|
|
else
|
|
emitcode();
|
|
START; print("maxoff=%d", maxoff); END;
|
|
#undef xx
|
|
}
|
|
|
|
/* visit - generate code for *p */
|
|
static int visit(Node p, int n) {
|
|
if (p && p->x.inst == 0) {
|
|
p->x.inst = ++n;
|
|
n = visit(p->kids[0], n);
|
|
n = visit(p->kids[1], n);
|
|
*tail = p;
|
|
tail = &p->x.next;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/* gen0 - generate code for the dags on list p */
|
|
static Node I(gen)(Node p) {
|
|
int n;
|
|
Node nodelist;
|
|
|
|
tail = &nodelist;
|
|
for (n = 0; p; p = p->link) {
|
|
switch (generic(p->op)) { /* check for valid forest */
|
|
case CALL:
|
|
assert(IR->wants_dag || p->count == 0);
|
|
break;
|
|
case ARG:
|
|
case ASGN: case JUMP: case LABEL: case RET:
|
|
case EQ: case GE: case GT: case LE: case LT: case NE:
|
|
assert(p->count == 0);
|
|
break;
|
|
case INDIR:
|
|
assert(IR->wants_dag && p->count > 0);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
check(p);
|
|
p->x.listed = 1;
|
|
n = visit(p, n);
|
|
}
|
|
*tail = 0;
|
|
return nodelist;
|
|
}
|
|
|
|
/* global - announce a global */
|
|
static void I(global)(Symbol p) {
|
|
START; print("global "); emitSymbol(p); END;
|
|
}
|
|
|
|
/* import - import a symbol */
|
|
static void I(import)(Symbol p) {
|
|
START; print("import "); emitSymRef(p); END;
|
|
}
|
|
|
|
/* local - local variable */
|
|
static void I(local)(Symbol p) {
|
|
if (p->temporary)
|
|
p->name = stringf("t%s", p->name);
|
|
(*IR->defsymbol)(p);
|
|
off = roundup(off, p->type->align);
|
|
p->x.offset = off;
|
|
off += p->type->size;
|
|
START; print(p->temporary ? "temporary " : "local "); emitSymbol(p); END;
|
|
}
|
|
|
|
/* progbeg - beginning of program */
|
|
static void I(progbeg)(int argc, char *argv[]) {
|
|
int i;
|
|
|
|
for (i = 1; i < argc; i++)
|
|
if (strcmp(argv[i], "-v") == 0)
|
|
verbose++;
|
|
else if (strcmp(argv[i], "-html") == 0)
|
|
html++;
|
|
if (html) {
|
|
print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
|
|
print("<html>");
|
|
BEGIN(head);
|
|
if (firstfile && *firstfile)
|
|
BEGIN(title); emitString(strlen(firstfile), firstfile); END;
|
|
print("<link rev=made href=\"mailto:drh@microsoft.com\">\n");
|
|
END;
|
|
print("<body>\n");
|
|
if (firstfile && *firstfile)
|
|
BEGIN(h1); emitString(strlen(firstfile), firstfile); END;
|
|
BEGIN(P); BEGIN(em);
|
|
print("Links lead from uses of identifiers and labels to their definitions.");
|
|
END; END;
|
|
print("<ul>\n");
|
|
START;
|
|
print("progbeg");
|
|
BEGIN(ol);
|
|
for (i = 1; i < argc; i++) {
|
|
ITEM;
|
|
BEGIN(code); print("\""); emitString(strlen(argv[i]), argv[i]); print("\""); END;
|
|
END;
|
|
}
|
|
END;
|
|
END;
|
|
}
|
|
}
|
|
|
|
/* progend - end of program */
|
|
static void I(progend)(void) {
|
|
START; print("progend"); END;
|
|
if (html) {
|
|
time_t t;
|
|
print("</ul>\n");
|
|
time(&t);
|
|
print("<hr><address>%s</address>\n", ctime(&t));
|
|
print("</body></html>\n");
|
|
}
|
|
}
|
|
|
|
/* segment - switch to segment s */
|
|
static void I(segment)(int s) {
|
|
START; print("segment %s", &"text\0bss\0.data\0lit\0.sym\0."[5*s-5]); END;
|
|
}
|
|
|
|
/* space - initialize n bytes of space */
|
|
static void I(space)(int n) {
|
|
START; print("space %d", n); END;
|
|
}
|
|
|
|
static void I(stabblock)(int brace, int lev, Symbol *p) {}
|
|
|
|
/* stabend - finalize stab output */
|
|
static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
|
|
int i;
|
|
|
|
if (p)
|
|
emitSymRef(p);
|
|
print("\n");
|
|
if (cpp && sp)
|
|
for (i = 0; cpp[i] && sp[i]; i++) {
|
|
print("%w.%d: ", cpp[i], cpp[i]->x);
|
|
emitSymRef(sp[i]);
|
|
print("\n");
|
|
}
|
|
}
|
|
|
|
static void I(stabfend)(Symbol p, int lineno) {}
|
|
static void I(stabinit)(char *file, int argc, char *argv[]) {}
|
|
|
|
/* stabline - emit line number information for source coordinate *cp */
|
|
static void I(stabline)(Coordinate *cp) {
|
|
if (cp->file)
|
|
print("%s:", cp->file);
|
|
print("%d.%d:\n", cp->y, cp->x);
|
|
}
|
|
|
|
static void I(stabsym)(Symbol p) {}
|
|
static void I(stabtype)(Symbol p) {}
|
|
|
|
Interface symbolicIR = {
|
|
{1, 1, 0}, /* char */
|
|
{2, 2, 0}, /* short */
|
|
{4, 4, 0}, /* int */
|
|
{4, 4, 0}, /* long */
|
|
{4, 4, 0}, /* long long */
|
|
{4, 4, 1}, /* float */
|
|
{8, 8, 1}, /* double */
|
|
{8, 8, 1}, /* long double */
|
|
{4, 4, 0}, /* T* */
|
|
{0, 4, 0}, /* struct */
|
|
0, /* little_endian */
|
|
0, /* mulops_calls */
|
|
0, /* wants_callb */
|
|
1, /* wants_argb */
|
|
1, /* left_to_right */
|
|
1, /* wants_dag */
|
|
0, /* unsigned_char */
|
|
I(address),
|
|
I(blockbeg),
|
|
I(blockend),
|
|
I(defaddress),
|
|
I(defconst),
|
|
I(defstring),
|
|
I(defsymbol),
|
|
I(emit),
|
|
I(export),
|
|
I(function),
|
|
I(gen),
|
|
I(global),
|
|
I(import),
|
|
I(local),
|
|
I(progbeg),
|
|
I(progend),
|
|
I(segment),
|
|
I(space),
|
|
I(stabblock),
|
|
I(stabend),
|
|
I(stabfend),
|
|
I(stabinit),
|
|
I(stabline),
|
|
I(stabsym),
|
|
I(stabtype)
|
|
};
|
|
|
|
Interface symbolic64IR = {
|
|
{1, 1, 0}, /* char */
|
|
{2, 2, 0}, /* short */
|
|
{4, 4, 0}, /* int */
|
|
{8, 8, 0}, /* long */
|
|
{8, 8, 0}, /* long long */
|
|
{4, 4, 1}, /* float */
|
|
{8, 8, 1}, /* double */
|
|
{8, 8, 1}, /* long double */
|
|
{8, 8, 0}, /* T* */
|
|
{0, 1, 0}, /* struct */
|
|
1, /* little_endian */
|
|
0, /* mulops_calls */
|
|
0, /* wants_callb */
|
|
1, /* wants_argb */
|
|
1, /* left_to_right */
|
|
1, /* wants_dag */
|
|
0, /* unsigned_char */
|
|
I(address),
|
|
I(blockbeg),
|
|
I(blockend),
|
|
I(defaddress),
|
|
I(defconst),
|
|
I(defstring),
|
|
I(defsymbol),
|
|
I(emit),
|
|
I(export),
|
|
I(function),
|
|
I(gen),
|
|
I(global),
|
|
I(import),
|
|
I(local),
|
|
I(progbeg),
|
|
I(progend),
|
|
I(segment),
|
|
I(space),
|
|
I(stabblock),
|
|
I(stabend),
|
|
I(stabfend),
|
|
I(stabinit),
|
|
I(stabline),
|
|
I(stabsym),
|
|
I(stabtype)
|
|
};
|