-
-
Save bencz/79d4738afe962b5479d1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// -- Download all the include files and compiled binary | |
// -- https://drive.google.com/folderview?id=0B1nFzHmmj-jCaUJiVTVZUXd5WVk&usp | |
// | |
#include <ctype.h> | |
#include <io.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <windows.h> | |
enum | |
{ | |
oSRC = 1, oTOKEN = 2, oASM = 4, oTRACE = 8, oDEBUG = 16, | |
oDLL = 32, oLINES = 64, oUOPT = 128, oNAME = 256 | |
}; | |
#define OPERATOR2 "== != <= >= |= += -= *= /= %= &= ^= >> << ++ -- && || -> " | |
enum | |
{ | |
TK_SYMBOL = 0, TK_NAME, TK_NUMBER, TK_STRING, | |
TK_CHAR, TK_SHORT, TK_INT, TK_FLOAT, TK_DOUBLE | |
}; | |
#define HASHSIZE_TOKEN 9973 | |
enum { VAL = 0, ADDR }; | |
#define globTable 0 | |
#define AT_TYPE 0x01000000 | |
#define AT_USER 0x02000000 | |
#define AT_IMPT 0x04000000 | |
#define AT_EXPT 0x08000000 | |
#define AT_ADDR 0x00FFFFFF | |
enum { ST_FUNC = 1, ST_GVAR, ST_STRUCT, ST_ENUM }; | |
enum { AD_CODE = 1, AD_DATA, AD_ZERO, AD_STACK, AD_IMPORT, AD_CONST }; | |
#define NM_CDECL 0x0001 | |
#define NM_WINAPI 0x0002 | |
#define NM_VAR 0x0004 | |
#define NM_EXPORT 0x0008 | |
#define NM_FUNC (NM_CDECL | NM_WINAPI | NM_EXPORT) | |
#define NM_STRUCT 0x0010 | |
#define NM_ATTR 0x0020 | |
#define NM_ENUM 0x0040 | |
#define MEMALIGN 0x1000 | |
#define RAWALIGN 0x0200 | |
#define MEMALIGN1 0x0fff // MEMALIGN - 1 | |
#define RAWALIGN1 0x01ff // RAWALIGN - 1 | |
#define IMAGEBASE 0x00400000 | |
#define DLLBASE 0x10000000 | |
typedef struct _CMDPARAM | |
{ | |
int nSrc; | |
char *srcfile[8]; | |
char outfile[MAX_PATH]; | |
char impfiles[522]; | |
char MCCDIR[MAX_PATH]; | |
} CMDPARAM; | |
typedef struct _HDATA | |
{ | |
char *key; | |
void *val; | |
int seq; | |
} HDATA; | |
typedef struct _HASH | |
{ | |
HDATA *tbl; | |
int type; | |
int size, entries; | |
struct _HASH *pNext; | |
} HASH; | |
typedef struct _SRCLINE | |
{ | |
int filenumber, linenumber; | |
char *srccode; | |
} SRCLINE; | |
typedef struct _TOKEN | |
{ | |
int type; | |
int ival; | |
double dval; | |
char *token; | |
int filenumber, linenumber; | |
} TOKEN; | |
typedef struct _MCC | |
{ | |
char *srcFile[128]; | |
int lines[128]; | |
int totalLines; | |
int nSrcFile; | |
int mainfile; | |
SRCLINE *pSrcLine; | |
int sizeSrcLine; | |
int nSrcLine; | |
HASH hash; | |
int typeApp; | |
int nPreFile; | |
} MCC; | |
typedef struct _PTRS_TYPE | |
{ | |
int ptrs, type; | |
} PTRS_TYPE; | |
typedef struct _Name | |
{ | |
int type; | |
int idName; | |
int dataType; | |
int addrType; | |
int address; | |
int ptrs; | |
int size[8]; | |
PTRS_TYPE *argpt; | |
int argc; | |
struct _Name *pBgn, *pEnd; | |
struct _Name *pNext; | |
} Name; | |
typedef struct _Block | |
{ | |
int idFunc; | |
int blockDepth; | |
HASH hash; | |
} Block; | |
typedef struct _INSTRUCTION | |
{ | |
int opcode; | |
char *hexcode, *hexcode2, *mnemonic; | |
int regs_size; | |
} INSTRUCTION; | |
typedef struct _INSTRUCT | |
{ | |
int inst, num, attr, offset, size, refs; | |
double dval; | |
char *sval; | |
int regs; | |
} INSTRUCT; | |
typedef struct _HID | |
{ | |
int CHAR, SHORT, INT, FLOAT, DOUBLE, HVOID; | |
int STRUCT, TYPEDEF, IF, ELSE, WHILE, DO, FOR, RETURN, CONTINUE, BREAK, SWITCH, CASE, | |
DEFAULT, SIZEOF, DOTS3, HWINAPI, HCONST, EXTERN, DECLSP, DLLIMPT, DLLEXPT, STATIC, ENUM; | |
} HID; | |
typedef struct _INDEX | |
{ | |
int tix; | |
int ixCode, ixData, ixZero, ixString; | |
int ixLoc; | |
} INDEX; | |
typedef struct _VALUE | |
{ | |
int mode; | |
int ptrs, type; | |
int ival; | |
double rval; | |
int fConst, fAddr; | |
} VALUE; | |
typedef struct _CODE | |
{ | |
TOKEN *token; | |
int nToken; | |
HASH hash; | |
INSTRUCT *pCode; | |
int sizeCode; | |
int currTable; | |
Block block[100]; | |
int baseSpace; | |
int offset; | |
} CODE; | |
typedef struct _SECTION | |
{ | |
int CodeAddr, CodeSize, DataAddr, DataSize; | |
int ImptAddr, ImptSize, ExptAddr, ExptSize, RelocAddr, RelocSize; | |
} SECTION; | |
typedef struct _DLL | |
{ | |
char *dllname; | |
int idFunc[64]; | |
int nFunc; | |
} DLL; | |
typedef struct _EXE | |
{ | |
int base, entryPoint; | |
int lenImpt, lenExpt, sizeImage; | |
DLL dll[32]; | |
int nDLL, useDLL; | |
int useFunc; | |
int locs[1000], nLocs; | |
int cnt[100], nPages; | |
} EXE; | |
void infixOperation(int op, VALUE *v1, VALUE *v2, int left_bgn, int left_end); | |
void expression(int mode, VALUE *pv); | |
void assignExpression(int mode, VALUE *pv); | |
void conditionalExpression(int mode, VALUE *pv); | |
void logicalOrExpression(int mode, VALUE *pv); | |
void logicalAndExpression(int mode, VALUE *pv); | |
void orExpression(int mode, VALUE *pv); | |
void xorExpression(int mode, VALUE *pv); | |
void andExpression(int mode, VALUE *pv); | |
void equalityExpression(int mode, VALUE *pv); | |
void relationalExpression(int mode, VALUE *pv); | |
void shiftExpression(int mode, VALUE *pv); | |
void addExpression(int mode, VALUE *pv); | |
void mulExpression(int mode, VALUE *pv); | |
void castExpression(int mode, VALUE *pv); | |
void unaryExpression(int mode, VALUE *pv); | |
void primaryExpression(int mode, VALUE *pv); | |
int opt; | |
MCC mcc; | |
CMDPARAM cmd; | |
HID ID; | |
INDEX ix; | |
CODE cd; | |
SECTION mem, raw; | |
EXE exe; | |
void error(const char *loc, const char *format, ...) | |
{ | |
if ((opt&oDEBUG) && loc != NULL) fprintf(stderr, "%s: ", loc); | |
if (0 <= ix.tix && ix.tix < cd.nToken) | |
{ | |
int filenumber = cd.token[ix.tix].filenumber; | |
char *srcfile = filenumber >= 0 ? mcc.srcFile[filenumber] : "startup"; | |
fprintf(stderr, "%s:%d: ", srcfile, cd.token[ix.tix].linenumber); | |
} | |
else if (mcc.nPreFile >= 0) | |
{ | |
fprintf(stderr, "%s:%d: ", mcc.srcFile[mcc.nPreFile], mcc.lines[mcc.nPreFile]); | |
} | |
vfprintf(stderr, format, (char*)&format + sizeof(char*)); | |
exit(1); | |
} | |
int htoi(int c) | |
{ | |
return c >= 'A' ? (c - 'A' + 10) : (c - '0'); | |
} | |
int esc_char(char *p) | |
{ | |
if (*p == 'x' || *p == 'X') return (htoi(p[1]) << 4) + htoi(p[2]); | |
return *p == '0' ? '\0' : *p == 'r' ? '\r' : *p == 'n' ? '\n' : *p == 't' ? '\t' : *p; | |
} // 0->\0, r->\r, ..., t->\t, \'->\', \"->\", \\->\\. | |
int isAlpha(int c) | |
{ | |
return (isalpha(c) || c == '_'); | |
} | |
int isAlNum(int c) | |
{ | |
return isAlpha(c) || isdigit(c); | |
} | |
int isKanji(int c) | |
{ | |
return (c >= 0x81 && c <= 0x9F) || (c >= 0xE0 && c <= 0xFC); | |
} | |
char *endOfQuote(char *p) | |
{ | |
int delim = *p++; // '"' or '\'' | |
while (*p != '\0' && *p != delim) | |
p += (*p == '\\' || isKanji(*p & 0xff)) ? 2 : 1; | |
if (*p != delim) error("endOfQuote", "missing terminating %c character", delim); | |
return ++p; | |
} | |
void *xcheck(void *p) | |
{ | |
if (p == NULL) error("xcheck", ""); | |
return p; | |
} | |
void *xalloc(int size) | |
{ | |
return xcheck(calloc(1, size)); | |
} | |
void *xrealloc(void *ptr, size_t size) | |
{ | |
return xcheck(realloc(ptr, size)); | |
} | |
char *xstrdup(char *q) | |
{ | |
return xcheck(strdup(q)); | |
} | |
void initHash(int type, int size, HASH *pHash) | |
{ | |
pHash->type = type; | |
pHash->size = size; | |
pHash->tbl = xalloc(size * sizeof(HDATA)); | |
pHash->entries = 0; | |
} | |
int put(char *key, void *val, HASH *pHash); | |
void reallocHash(int newSize, HASH *pHash) | |
{ | |
int n, oldSize = pHash->size; | |
HDATA *oldTbl = pHash->tbl; | |
initHash(pHash->type, newSize, pHash); | |
for (n = 0; n < oldSize; n++) | |
{ | |
if (oldTbl[n].key != NULL) put(oldTbl[n].key, oldTbl[n].val, pHash); | |
} | |
free(oldTbl); | |
} | |
void freeHash(HASH *pHash) | |
{ | |
int n; | |
for (n = 0; n < pHash->size; n++) | |
{ | |
if (pHash->tbl[n].key != NULL) free(pHash->tbl[n].key); | |
if ((pHash->type == 's' || pHash->type == 'n') && pHash->tbl[n].val != 0) | |
free(pHash->tbl[n].val); | |
} | |
free(pHash->tbl); | |
} | |
int hash(char *key, int size) | |
{ | |
int n, h = 0; | |
for (n = 0; key[n] != '\0'; n++) | |
h = (h * 137 + (key[n] & 0xff)) % size; | |
return h; | |
} | |
int put(char *key, void *val, HASH *pHash) | |
{ | |
int n, h = hash(key, pHash->size); | |
for (n = 0; n < pHash->size; n++) | |
{ | |
int ix = (h + n) % pHash->size; | |
if (pHash->tbl[ix].key == NULL) | |
{ | |
pHash->tbl[ix].key = xstrdup(key); | |
pHash->tbl[ix].val = pHash->type == 's' ? xstrdup(val) : val; | |
pHash->tbl[ix].seq = pHash->entries++; | |
if (pHash->type != 'x' && pHash->entries > pHash->size / 2) | |
reallocHash(pHash->size * 2, pHash); | |
return ix; | |
} | |
else if (strcmp(pHash->tbl[ix].key, key) == 0) | |
{ | |
return ix; | |
} | |
} | |
error("lib.put", "Hash Table full!"); | |
} | |
void *get(char *key, HASH *pHash) | |
{ | |
int n, h = hash(key, pHash->size); | |
for (n = 0; n < pHash->size; n++) | |
{ | |
int ix = (h + n) % pHash->size; | |
if (pHash->tbl[ix].key == NULL) break; | |
if (strcmp(pHash->tbl[ix].key, key) == 0) | |
return pHash->tbl[ix].val; | |
} | |
return NULL; | |
} | |
void printHash(HASH *pHash) | |
{ | |
char *fmt = pHash->type == 's' ? "%4d %-8s %s\n" : "%4d %-8s %08X\n"; | |
int n; | |
for (n = 0; n < pHash->size; n++) | |
{ | |
if (pHash->tbl[n].key != NULL) | |
printf(fmt, n, pHash->tbl[n].key, pHash->tbl[n].val); | |
} | |
} | |
void prepro(char *srcfile); | |
int parseline(char *p, char *q) | |
{ | |
while (*p != '\0' && *p != '\n') | |
{ | |
if (p[0] == '/' && p[1] == '/') break; // "//" | |
if (p[0] == '/' && p[1] == '*') | |
{ | |
char *r = strstr(p + 2, "*/"); | |
if (r == NULL) | |
{ | |
*q = '\0'; | |
return 1; | |
} | |
strcpy(p, r + 2); | |
} | |
else if (*p == '\'' || *p == '"') | |
{ | |
char *pEnd = endOfQuote(p); | |
while (p < pEnd) *q++ = *p++; | |
} | |
else | |
{ | |
*q++ = *p++; | |
} | |
} | |
*q = '\0'; | |
return 0; | |
} | |
void procInclude(char *src, char *p) | |
{ | |
char *q, *r, *s, path[260]; | |
if ((q = strchr(p, '<')) != NULL && (r = strchr(q, '>')) != NULL) | |
{ | |
sprintf(path, "%s\\include\\%.*s", cmd.MCCDIR, r - q - 1, q + 1); | |
} | |
else if ((q = strchr(p, '"')) != NULL && (r = strchr(q + 1, '"')) != NULL) | |
{ | |
if ((s = strrchr(src, '/')) == NULL) s = strrchr(src, '\\'); | |
if (s == NULL) sprintf(path, "%.*s", r - q - 1, q + 1); | |
else sprintf(path, "%.*s%.*s", s - src + 1, src, r - q - 1, q + 1); | |
} | |
else | |
{ | |
return; | |
} | |
if (get(path, &mcc.hash) == NULL) | |
{ | |
put(path, p, &mcc.hash); | |
prepro(path); | |
} | |
} | |
void procDefine(char *str, HASH *pHash) | |
{ | |
char *p = strtok(str, " \t"); | |
char *q = strtok(NULL, ""); | |
while (*q <= ' ') q++; | |
put(p, q, pHash); | |
} | |
void procPragma(char *p) // #pragma comment(lib, "comctl32.lib") | |
{ | |
strtok(p, "\""); // '"' | |
char *q = strtok(NULL, "."); // '.' | |
sprintf(cmd.impfiles + strlen(cmd.impfiles), "%s.dll;", q); | |
} | |
void addLine(char *srccode, int nFile, int nLine) | |
{ | |
if (mcc.nSrcLine >= mcc.sizeSrcLine) | |
{ | |
mcc.sizeSrcLine = mcc.sizeSrcLine * 3 / 2; | |
mcc.pSrcLine = xrealloc(mcc.pSrcLine, mcc.sizeSrcLine*sizeof(SRCLINE)); | |
} | |
SRCLINE *pSL = &mcc.pSrcLine[mcc.nSrcLine++]; | |
pSL->filenumber = nFile; | |
pSL->linenumber = nLine; | |
pSL->srccode = xstrdup(srccode); | |
if (opt&oSRC) printf("%2d %3d: %s\n", nFile, nLine, srccode); | |
} | |
void prepro(char *srcfile) | |
{ | |
char buf[512], out[512], key[64], *p, *pBgn, *q; | |
int nLine, nFile = mcc.nSrcFile++; | |
FILE *fpSrc = fopen(srcfile, "r"); | |
if (fpSrc == NULL) error("prepro", "file '%s' not found", srcfile); | |
mcc.srcFile[nFile] = xstrdup(srcfile); | |
int fComment = 0; // "*/" | |
for (nLine = 1; fgets(buf, sizeof(buf), fpSrc) != NULL; nLine++) | |
{ | |
mcc.nPreFile = nFile; | |
mcc.lines[nFile] = nLine; | |
if (fComment) | |
{ | |
if ((p = strstr(buf, "*/")) == NULL) continue; | |
strcpy(buf, p + 2); | |
fComment = 0; | |
} | |
fComment = parseline(buf, out); | |
for (p = out; *p != '\0' && *p <= ' '; p++); | |
if (*p == '\0') continue; | |
if (strncmp(out, "#include", 8) == 0) | |
{ | |
procInclude(srcfile, out + 8); | |
} | |
else if (strncmp(out, "#define", 7) == 0) | |
{ | |
procDefine(out + 7, &mcc.hash); | |
} | |
else if (strncmp(out, "#pragma", 7) == 0) | |
{ | |
procPragma(out + 7); | |
} | |
else | |
{ | |
for (p = out; *p != '\0';) | |
{ | |
if (*p == '"' || *p == '\'') | |
{ | |
p = endOfQuote(p); | |
} | |
else if (!isAlpha(*p)) | |
{ | |
if (*p++ == '(' && (strcmp(key, "main") == 0 || strcmp(key, "WinMain") == 0)) | |
{ | |
mcc.typeApp = *key == 'm' ? 3 : 2; | |
mcc.mainfile = nFile; | |
} | |
} | |
else | |
{ | |
for (q = key, pBgn = p; isAlNum(*p);) *q++ = *p++; | |
*q = '\0'; | |
char *val = get(key, &mcc.hash); | |
if (val != NULL) | |
{ | |
int vlen = strlen(val); | |
memmove(pBgn + vlen, p, strlen(p) + 1); | |
memmove(pBgn, val, vlen); | |
p = pBgn; | |
} | |
} | |
} | |
addLine(out, nFile, nLine); | |
} | |
} | |
if (opt&oDLL) mcc.typeApp = 0; | |
if (opt&oLINES && strstr(srcfile, "include\\") == NULL) | |
{ | |
mcc.totalLines += nLine; | |
printf("%-24s\t%5d\n", srcfile, nLine - 1); | |
} | |
} | |
void initPrepro() | |
{ | |
mcc.sizeSrcLine = 1000; | |
mcc.pSrcLine = xalloc(mcc.sizeSrcLine * sizeof(SRCLINE)); | |
addLine("short _RoundNear = 0x137F;", -1, 1); | |
addLine("short _RoundChop = 0x1F7F;", -1, 2); | |
} | |
void addStartup() | |
{ | |
int n = 3; | |
addLine("void _main() {", -1, n++); | |
if (mcc.typeApp == 3) // CUI | |
{ | |
addLine(" char **argv, **env;", -1, n++); | |
addLine(" int argc, new_mode = 0;", -1, n++); | |
addLine(" __set_app_type(1);", -1, n++); | |
addLine(" _controlfp(0x10000, 0x30000);", -1, n++); // _PC_53, _MCW_PC | |
addLine(" __getmainargs(&argc, &argv, &env, 0, &new_mode);", -1, n++); | |
addLine(" exit(main(argc, argv, env));", -1, n++); | |
} | |
else if (mcc.typeApp == 2) // GUI | |
{ | |
addLine(" STARTUPINFOA si;", -1, n++); | |
addLine(" __set_app_type(2);", -1, n++); | |
addLine(" _controlfp(0x10000, 0x30000);", -1, n++); | |
addLine(" char *p = GetCommandLineA();", -1, n++); | |
addLine(" int c = (*p++ == '\"') ? '\"' : ' ';", -1, n++); | |
addLine(" while (*p != c && *p != 0) p++;", -1, n++); | |
addLine(" if (*p != 0) p++;", -1, n++); | |
addLine(" while (*p <= ' ' && *p != 0) p++;", -1, n++); | |
addLine(" GetStartupInfoA(&si);", -1, n++); | |
addLine(" exit(WinMain(GetModuleHandleA((void*)0), (void*)0,", -1, n++); | |
addLine(" p, (si.dwFlags&1) ? si.wShowWindow : 10));", -1, n++); | |
} | |
else // DLL | |
{ | |
addLine(" return 1;", -1, n++); | |
} | |
addLine("}", -1, n++); | |
} | |
void printToken(int n) | |
{ | |
printf("%3d %2d:%03d %d \t%s\n", n + 1, cd.token[n].filenumber, | |
cd.token[n].linenumber, cd.token[n].type, cd.token[n].token); | |
} | |
void lex() | |
{ | |
char *p, *pBgn, op2[4], token[256]; | |
int n, type, nToken = 0, sizeToken = 1000; | |
cd.token = xalloc(sizeToken * sizeof(TOKEN)); | |
for (n = 0; n < mcc.nSrcLine; n++) | |
{ | |
SRCLINE *pSrc = &mcc.pSrcLine[n]; | |
for (p = pSrc->srccode; *p != '\0';) | |
{ | |
if (*p <= ' ') | |
{ | |
p++; | |
continue; | |
} | |
pBgn = p; | |
if (*p == '\"' || *p == '\'') | |
{ | |
type = TK_STRING; | |
p = endOfQuote(pBgn); | |
} | |
else if (isdigit(*p)) | |
{ | |
type = TK_NUMBER; | |
if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) strtol(p, &p, 16); | |
else strtod(p, &p); | |
} | |
else if (isAlpha(*p)) | |
{ | |
type = TK_NAME; | |
for (p++; *p != '\0' && isAlNum(*p);) p++; | |
} | |
else if (strncmp(p, "...", 3) == 0) | |
{ | |
type = TK_NAME; | |
p += 3; | |
} | |
else | |
{ | |
type = TK_SYMBOL; | |
sprintf(op2, "%c%c ", p[0], p[1]); | |
p += strstr(OPERATOR2, op2) != NULL ? 2 : 1; | |
} | |
if (nToken >= sizeToken - 1) | |
{ | |
sizeToken = sizeToken * 3 / 2; | |
cd.token = xrealloc(cd.token, sizeToken * sizeof(TOKEN)); | |
} | |
sprintf(token, "%.*s", p - pBgn, pBgn); | |
if (nToken > 0 && cd.token[nToken - 1].type == TK_STRING && type == TK_STRING) | |
{ | |
char *tk1 = cd.token[nToken - 1].token; | |
int len = strlen(tk1); | |
char *tk = xrealloc(tk1, len + (p - pBgn)); | |
strcpy(tk + len - 1, token + 1); | |
free(tk1); | |
cd.token[nToken - 1].token = tk; | |
} | |
else | |
{ | |
TOKEN tkn = { type, 0, 0.0, xstrdup(token), pSrc->filenumber, pSrc->linenumber }; | |
memcpy(&cd.token[nToken++], &tkn, sizeof(TOKEN)); | |
} | |
} | |
} | |
cd.nToken = nToken; | |
} | |
enum | |
{ | |
push = 1, push_eax, push_ecx, push_pbp, pop_eax, pop_ecx, pop_edx, inc_dbp, dec_dbp, | |
add_eax_ecx, add_eax_edx, add_eax, add_ecx, add_pcx_eax, add_pcx_ax, add_pcx_al, add_esp, | |
add_dax, add_dcx, add_ddx, add_bax, add_bcx, add_bdx, add_eax_pbp, add_ecx_pbp, | |
add_pbp_eax, add_pbp_ecx, sub_pbp_ecx, sub_pbp_eax, and_pbp_eax, or_pbp_eax, xor_pbp_eax, | |
sub_eax, sub_eax_pbp, sub_eax_ecx, sub_pcx_eax, sub_pcx_ax, sub_pcx_al, sub_esp, sub_dax, | |
sub_dcx, sub_ddx, sub_bax, sub_bcx, sub_bdx, imul_eax_ecx, imul_eax_eax, imul_edx_edx, | |
imul_eax_pbp, xdiv_dbp, cmp_eax_ecx, cmp_ecx_eax, cmp_eax, cmp_eax_pbp, cmp_ah, test_ah, | |
test_eax_eax, and_eax_ecx, and_pcx_eax, and_pcx_ax, and_pcx_al, and_ah, or_eax_ecx, | |
or_pcx_eax, or_pcx_ax, or_pcx_al, xor_eax_eax, xor_pcx_eax, xor_pcx_ax, xor_pcx_al, | |
xor_eax_ecx, xor_ah, shl_eax, shl_edx, shl_eax_cl, shr_eax_cl, neg_eax, mov_ecx_eax, | |
mov_edx_eax, mov_eax_edx, mov_eax, mov_ecx, mov_dax, mov_wax, mov_bax, mov_eax_pax, | |
mov_eax_pcx, mov_pcx_eax, mov_pcx_ax, mov_pcx_al, mov_pax_ecx, mov_pax_cx, mov_pax_cl, | |
mov_eax_pbp, mov_ecx_pbp, mov_pbp_ecx, mov_ecx_pax, mov_edx_pax, mov_edx_pbp, mov_pbp_eax, | |
mov_pbp_al, mov_psp_eax, mov_eax_psp, movsx_eax_wax, movsx_eax_bax, movsx_ecx_wcx, | |
movsx_ecx_bcx, lea_eax_pbp, lea_ecx_pbp, lea_edx_pbp, mov_eax_ad1, mov_eax_ad2, | |
mov_eax_ad4, mov_eax_ad8, mov_eax_da1, mov_eax_da2, mov_eax_da4, mov_eax_da8, lea_eax_ad1, | |
lea_eax_ad2, lea_eax_ad4, | |
lea_eax_ad8, lea_eax_da1, lea_eax_da2, lea_eax_da4, lea_eax_da8, lea_ecx_da1, lea_ecx_da2, | |
lea_ecx_da4, lea_ecx_da8, xchg_eax_ecx, cwde, jmp, jz, jnz, jl, jge, jle, jg, call, | |
xent, xret, sete_eax, setne_eax, setl_eax, setge_eax, setle_eax, setg_eax, fchs, fxch_st1, | |
fld_qax, fld_qcx, fld_qbp, fld_qp, fldcw, fstp_qsp, fstsw, fst_qax, fst_qcx, fst_qbp, | |
fadd_qbp, fadd_qp, fsub_qbp, fsub_qp, fmul_qbp, fmul_qp, fdiv_qbp, fdiv_qp, fstp_st1, | |
faddp_st1_st, fsubrp_st1_st, fmulp_st1_st, fdivrp_st1_st, fucompp, fistp_dsp, fild_dax, | |
fild_dsp, xdiv_ecx, xmod_ecx, setint, setreal, setstr, fn_, exp_, loc_ | |
}; | |
#define Z ((void*)0) | |
enum { A = 0x0100, C = 0x0200, D = 0x0400, AC = 0x0300, AD = 0x0500, CD = 0x0600, ACD = 0x0700, X = 0x0700 }; | |
INSTRUCTION instruction[] = { | |
{ push, "68", Z, "push %d", 4 }, | |
{ push_pbp, "FFB5", "FF75", "push [ebp%+d]", 5 }, | |
{ push_eax, "50", Z, "push eax", A }, | |
{ push_ecx, "51", Z, "push ecx", C }, | |
{ pop_eax, "58", Z, "pop eax", A }, | |
{ pop_ecx, "59", Z, "pop ecx", C }, | |
{ pop_edx, "5A", Z, "pop edx", D }, | |
{ inc_dbp, "FF85", "FF45", "inc dp[ebp%+d]", 5 }, | |
{ dec_dbp, "FF8D", "FF4D", "dec dp[ebp%+d]", 5 }, | |
{ add_eax_ecx, "03C1", Z, "add eax,ecx", AC }, | |
{ add_eax_edx, "03C2", Z, "add eax,edx", AD }, | |
{ add_eax, "05", "83C0", "add eax,%d", 5 | A }, | |
{ add_ecx, "81C1", "83C1", "add ecx,%d", 5 | C }, | |
{ add_pcx_eax, "0101", Z, "add [ecx],eax", AC }, | |
{ add_pcx_ax, "660101", Z, "add [ecx],ax", AC }, | |
{ add_pcx_al, "0001", Z, "add [ecx],al", AC }, | |
{ add_esp, "81C4", "83C4", "add esp,%d", 5 }, | |
{ add_bax, "8000", Z, "add bp[eax]", A }, | |
{ add_bcx, "8001", Z, "add bp[ecx]", C }, | |
{ add_bdx, "8002", Z, "add bp[edx]", D }, | |
{ add_dax, "8100", "8300", "add dp[eax],%d", 5 | A }, | |
{ add_dcx, "8101", "8301", "add dp[ecx],%d", 5 | C }, | |
{ add_ddx, "8102", "8302", "add dp[edx],%d", 5 | D }, | |
{ add_eax_pbp, "0385", "0345", "add eax,[ebp%+d]", 5 | A }, | |
{ add_ecx_pbp, "038D", "034D", "add ecx,[ebp%+d]", 5 | C }, | |
{ add_pbp_eax, "0185", "0145", "add [ebp%+d],eax", 5 | A }, | |
{ add_pbp_ecx, "018D", "014D", "add [ebp%+d],ecx", 5 | C }, | |
{ sub_pbp_eax, "2985", "2945", "sub [ebp%+d],eax", 5 | A }, | |
{ or_pbp_eax, "0985", "0945", "or [ebp%+d],eax", 5 | A }, | |
{ xor_pbp_eax, "3185", "3145", "xor [ebp%+d],eax", 5 | A }, | |
{ sub_pbp_ecx, "298D", "294D", "sub [ebp%+d],ecx", 5 | C }, | |
{ sub_eax, "2D", "83E8", "sub eax,%d", 5 | A }, | |
{ sub_eax_pbp, "2B85", "2B45", "sub eax,[ebp%+d]", 5 | A }, | |
{ sub_eax_ecx, "2BC1", Z, "sub eax,ecx", AC }, | |
{ sub_pcx_eax, "2901", Z, "sub [ecx],eax", AC }, | |
{ sub_pcx_ax, "662901", Z, "sub [ecx],ax", AC }, | |
{ sub_pcx_al, "2801", Z, "sub [ecx],al", AC }, | |
{ sub_esp, "81EC", "83EC", "sub esp,%d", 5 }, | |
{ sub_dax, "8128", "8328", "sub dp[eax],%d", 5 | A }, | |
{ sub_dcx, "8129", "8329", "sub dp[ecx],%d", 5 | C }, | |
{ sub_ddx, "812A", "832A", "sub dp[edx],%d", 5 | D }, | |
{ sub_bax, Z, "8028", "sub bp[eax],%d", 1 | A }, | |
{ sub_bcx, Z, "8029", "sub bp[ecx],%d", 1 | C }, | |
{ sub_bdx, Z, "802A", "sub bp[edx],%d", 1 | D }, | |
{ imul_eax_ecx, "0FAFC1", Z, "imul eax,ecx", ACD }, // •„†•tÂæŽZ | |
{ imul_eax_eax, "69C0", "6BC0", "imul eax,eax,%d", 5 | AD }, // R <- R*imm | |
{ imul_edx_edx, "69D2", "6BD2", "imul edx,edx,%d", 5 | AD }, // R <- R*imm | |
{ imul_eax_pbp, "0FAF85", "0FAF45", "imul eax,[ebp%+d]", 5 | A }, | |
{ xdiv_dbp, "99F7BD", "99F77D", "cdq&idiv dp[ebp%+d]", 5 | AD }, | |
{ cmp_eax_ecx, "39C8", Z, "cmp eax,ecx", AC }, | |
{ cmp_ecx_eax, "3BC8", Z, "cmp ecx,eax", AC }, | |
{ cmp_eax, "81F8", "83F8", "cmp eax,%d", 5 | A }, | |
{ cmp_eax_pbp, "3B85", "3B45", "cmp eax,[ebp%+d]", 5 | A }, | |
{ cmp_ah, Z, "80FC", "cmp ah,%d", 1 | A }, | |
{ test_ah, Z, "F6C4", "test ah,%d", 1 | A }, | |
{ test_eax_eax, "85C0", Z, "test eax,eax", A }, | |
{ and_pbp_eax, "2185", "2145", "and [ebp%+d],eax", 5 | A }, | |
{ and_eax_ecx, "23C1", Z, "and eax,ecx", AC }, | |
{ and_pcx_eax, "2101", Z, "and [ecx],eax", AC }, | |
{ and_pcx_ax, "662101", Z, "and [ecx],ax", AC }, | |
{ and_pcx_al, "2001", Z, "and [ecx],al", AC }, | |
{ and_ah, Z, "80E4", "and ah,%d", 1 | A }, | |
{ or_eax_ecx, "0BC1", Z, "or eax,ecx", AC }, | |
{ or_pcx_eax, "0901", Z, "or [ecx],eax", AC }, | |
{ or_pcx_ax, "660901", Z, "or [ecx],ax", AC }, | |
{ or_pcx_al, "0801", Z, "or [ecx],al", AC }, | |
{ xor_eax_eax, "31C0", Z, "xor eax,eax", A }, | |
{ xor_ah, Z, "80F4", "xor ah,%d", 1 | A }, | |
{ xor_pcx_ax, "663101", Z, "xor [ecx],ax", AC }, | |
{ xor_pcx_eax, "3101", Z, "xor [ecx],eax", AC }, | |
{ xor_eax_ecx, "33C1", Z, "xor eax,ecx", AC }, | |
{ xor_pcx_al, "3001", Z, "xor [ecx],al", AC }, | |
{ shl_eax, Z, "C1E0", "shl eax,%d", 1 | A }, | |
{ shl_edx, Z, "C1E2", "shl edx,%d", 1 | D }, | |
{ shl_eax_cl, "D3E0", Z, "shl eax,cl", AC }, | |
{ shr_eax_cl, "D3E8", Z, "shr eax,cl", AC }, | |
{ neg_eax, "F7D8", Z, "neg eax", A }, | |
{ mov_eax_edx, "8BC2", Z, "mov eax,edx", AD }, | |
{ mov_ecx_eax, "8BC8", Z, "mov ecx,eax", AC }, | |
{ mov_edx_eax, "8BD0", Z, "mov edx,eax", AD }, | |
{ mov_eax, "B8", Z, "mov eax,%d", 4 | A }, | |
{ mov_ecx, "B9", Z, "mov ecx,%d", 4 | C }, | |
{ mov_dax, "C700", Z, "mov dp[eax],%d", 4 | A }, | |
{ mov_wax, "66C700", Z, "mov wp[eax],%d", 2 | A }, | |
{ mov_bax, Z, "C600", "mov bp[eax],%d", 1 | A }, | |
{ mov_eax_pax, "8B00", Z, "mov eax,[eax]", A }, | |
{ mov_eax_pcx, "8B01", Z, "mov eax,[ecx]", AC }, | |
{ mov_pcx_eax, "8901", Z, "mov [ecx],eax", AC }, | |
{ mov_pcx_ax, "668901", Z, "mov [ecx],ax", AC }, | |
{ mov_pax_cx, "668908", Z, "mov [eax],cx", AC }, | |
{ mov_pcx_al, "8801", Z, "mov [ecx],al", AC }, | |
{ mov_pax_cl, "8808", Z, "mov [eax],cl", AC }, | |
{ mov_pax_ecx, "8908", Z, "mov [eax],ecx", AC }, | |
{ mov_ecx_pax, "8B08", Z, "mov ecx,[eax]", AC }, | |
{ mov_edx_pax, "8B10", Z, "mov edx,[eax]", AD }, | |
{ mov_eax_pbp, "8B85", "8B45", "mov eax,[ebp%+d]", 5 | A }, | |
{ mov_ecx_pbp, "8B8D", "8B4D", "mov ecx,[ebp%+d]", 5 | C }, | |
{ mov_edx_pbp, "8B95", "8B55", "mov edx,[ebp%+d]", 5 | D }, | |
{ mov_pbp_ecx, "898D", "894D", "mov [ebp%+d],ecx", 5 | C }, | |
{ mov_pbp_eax, "8985", "8945", "mov [ebp%+d],eax", 5 | A }, | |
{ mov_pbp_al, "8885", "8845", "mov [ebp%+d],al", 5 | A }, | |
{ mov_psp_eax, "898424", "894424", "mov [esp%+d],eax", 5 | A }, | |
{ mov_eax_psp, Z, "8B4424", "mov eax,[esp%+d]", 1 | X }, | |
{ movsx_eax_wax, "0FBF00", Z, "movsx eax,wp[eax]", A }, | |
{ movsx_eax_bax, "0FBE00", Z, "movsx eax,bp[eax]", A }, | |
{ movsx_ecx_wcx, "0FBF09", Z, "movsx ecx,wp[ecx]", C }, // •„†Šg’£ | |
{ movsx_ecx_bcx, "0FBE09", Z, "movsx ecx,bp[ecx]", C }, // •„†Šg’£ | |
{ lea_eax_pbp, "8D85", "8D45", "lea eax,[ebp%+d]", 5 | A }, | |
{ lea_ecx_pbp, "8D8D", "8D4D", "lea ecx,[ebp%+d]", 5 | C }, | |
{ lea_edx_pbp, "8D95", "8D55", "lea edx,[ebp%+d]", 5 | D }, | |
{ mov_eax_ad1, "8B0402", Z, "mov eax,[eax+edx]", AD }, | |
{ mov_eax_ad2, "8B0450", Z, "mov eax,[eax+edx*2]", AD }, | |
{ mov_eax_ad4, "8B0490", Z, "mov eax,[eax+edx*4]", AD }, | |
{ mov_eax_ad8, "8B04D0", Z, "mov eax,[eax+edx*8]", AD }, | |
{ mov_eax_da1, "8B0410", Z, "mov eax,[edx+eax]", AD }, | |
{ mov_eax_da2, "8B0442", Z, "mov eax,[edx+eax*2]", AD }, | |
{ mov_eax_da4, "8B0482", Z, "mov eax,[edx+eax*4]", AD }, | |
{ mov_eax_da8, "8B04C2", Z, "mov eax,[edx+eax*8]", AD }, | |
{ lea_eax_ad1, "8D0402", Z, "lea eax,[eax+edx]", AD }, | |
{ lea_eax_ad2, "8D0450", Z, "lea eax,[eax+edx*2]", AD }, | |
{ lea_eax_ad4, "8D0490", Z, "lea eax,[eax+edx*4]", AD }, | |
{ lea_eax_ad8, "8D04D0", Z, "lea eax,[eax+edx*8]", AD }, | |
{ lea_eax_da1, "8D0410", Z, "lea eax,[edx+eax]", AD }, | |
{ lea_eax_da2, "8D0442", Z, "lea eax,[edx+eax*2]", AD }, | |
{ lea_eax_da4, "8D0482", Z, "lea eax,[edx+eax*4]", AD }, | |
{ lea_eax_da8, "8D04C2", Z, "lea eax,[edx+eax*8]", AD }, | |
{ lea_ecx_da1, "8D0C10", Z, "lea ecx,[edx+eax]", ACD }, | |
{ lea_ecx_da2, "8D0C42", Z, "lea ecx,[edx+eax*2]", ACD }, | |
{ lea_ecx_da4, "8D0C82", Z, "lea ecx,[edx+eax*4]", ACD }, | |
{ lea_ecx_da8, "8D0CC2", Z, "lea ecx,[edx+eax*8]", ACD }, | |
{ xchg_eax_ecx, "91", Z, "xchg eax,ecx", AC }, | |
{ cwde, "98", Z, "cwde", A }, // eax <- ax | |
{ jmp, "E9", "EB", "jmp ", 5 | X }, | |
{ jz, "0F84", "74", "jz ", 5 | X }, | |
{ jnz, "0F85", "75", "jnz ", 5 | X }, | |
{ jl, "0F8C", "7C", "jl ", 5 | X }, | |
{ jge, "0F8D", "7D", "jge ", 5 | X }, | |
{ jle, "0F8E", "7E", "jle ", 5 | X }, | |
{ jg, "0F8F", "7F", "jg ", 5 | X }, | |
{ call, "E8", Z, "call fn_%04d", 4 | X }, | |
{ xent, "5589E5", Z, "push ebp&mov ebp,esp" }, | |
{ xret, "C9C3", "C9C2", "leave&ret", X }, | |
{ sete_eax, "B8000000000F94C0", Z, "sete eax", X }, // mov eax,0/sete_al | |
{ setne_eax, "B8000000000F95C0", Z, "setne eax", X }, // mov eax,0/setne_al | |
{ setl_eax, "B8000000000F9CC0", Z, "setl eax", X }, | |
{ setge_eax, "B8000000000F9DC0", Z, "setge eax", X }, | |
{ setle_eax, "B8000000000F9EC0", Z, "setle eax", X }, | |
{ setg_eax, "B8000000000F9FC0", Z, "setg eax", X }, | |
{ fchs, "D9E0", Z, "fchs" }, | |
{ fxch_st1, "D9C9", Z, "fxch st(1)" }, | |
{ fld_qax, "DD00", Z, "fld qp[eax]", A }, | |
{ fld_qcx, "DD01", Z, "fld qp[ecx]", C }, | |
{ fst_qax, "DD10", Z, "fst qp[eax]", A }, | |
{ fst_qcx, "DD11", Z, "fst qp[ecx]", C }, | |
{ fld_qbp, "DD85", "DD45", "fld qp[ebp%+d]", 5 }, | |
{ fld_qp, "DD05", Z, "fld qp[off_%p]", 4 }, | |
{ fldcw, "D92D", Z, "fldcw [off_%p]", 4 }, | |
{ fstp_qsp, "DD5C2400", Z, "fstp qp[esp]" }, | |
{ fstsw, "DFE0", Z, "fstsw" }, | |
{ fstp_st1, "DDD9", Z, "fstp st1" }, | |
{ fst_qbp, "DD95", "DD55", "fst qp[ebp%+d]", 5 }, | |
{ fadd_qbp, "DC85", "DC45", "fadd qp[ebp%+d]", 5 }, | |
{ fsub_qbp, "DCA5", "DC65", "fsub qp[ebp%+d]", 5 }, | |
{ fmul_qbp, "DC8D", "DC4D", "fmul qp[ebp%+d]", 5 }, | |
{ fdiv_qbp, "DCB5", "DC75", "fdiv qp[ebp%+d]", 5 }, | |
{ fadd_qp, "DC05", Z, "fadd qp[%d]", 4 }, | |
{ fsub_qp, "DC25", Z, "fsub qp[%d]", 4 }, | |
{ fmul_qp, "DC0D", Z, "fmul qp[%d]", 4 }, | |
{ fdiv_qp, "DC35", Z, "fdiv qp[%d]", 4 }, | |
{ faddp_st1_st, "DEC1", Z, "faddp st1,st" }, | |
{ fmulp_st1_st, "DEC9", Z, "fmulp st1,st" }, | |
{ fsubrp_st1_st, "DEE9", Z, "fsubrp st1,st" }, | |
{ fdivrp_st1_st, "DEF9", Z, "fdivrp st1,st" }, | |
{ fistp_dsp, Z, "DB5C24", "fistp dp[esp%+d]", 1 }, | |
{ fild_dax, "DB00", Z, "fild dp[eax]", A }, | |
{ fild_dsp, "DB8424", "DB4424", "fild dp[esp%+d]", 5 }, | |
{ fucompp, "DAE9", Z, "fucompp" }, | |
{ xdiv_ecx, "99F7F9", Z, "cdq&idiv ecx", X }, | |
{ xmod_ecx, "99F7F989D0", Z, "cdq&idiv ecx&mov eax,edx", X }, | |
{ setint, "", Z, "setint %d @%d" }, | |
{ setreal, "", Z, "setreal %.3f @%d" }, | |
{ setstr, "", Z, "setstr '%s' @%d" }, | |
{ fn_, Z, Z, "fn_%04d:", 4 }, | |
{ exp_, Z, Z, "exp fn_%04d:", 4 }, | |
{ loc_, Z, Z, "loc_%03d:", 4 }, | |
}; | |
int cmpInst(const void *a, const void *b) | |
{ | |
return ((INSTRUCTION*)a)->opcode - ((INSTRUCTION*)b)->opcode; | |
} | |
void initInstruction() | |
{ | |
int n, size1 = sizeof(INSTRUCTION); | |
qsort(instruction, sizeof(instruction) / size1, size1, cmpInst); | |
for (n = 0; n < sizeof(instruction) / size1; n++) | |
{ | |
INSTRUCTION *pI = &instruction[n]; | |
//printf("%s opcode=%d n+1=%d\n", pI->mnemonic, pI->opcode, n+1); | |
if (pI->opcode != n + 1) | |
error("INST", "mismatch! %s opcode=%d n+1=%d", pI->mnemonic, pI->opcode, n + 1); | |
} | |
} | |
char *toStr(int tix) | |
{ | |
return cd.token[tix].token; | |
} | |
char *toString(int id) | |
{ | |
return cd.hash.tbl[id].key; | |
} | |
int cmpSeq(const void *a, const void *b) | |
{ | |
return ((HDATA*)a)->seq - ((HDATA*)b)->seq; | |
} | |
void printNameTable(int ixBlk) | |
{ | |
Block blk = cd.block[ixBlk]; | |
printf("------ %-16s#%d [%2d]-------\n", toString(blk.idFunc), blk.blockDepth, ixBlk); | |
printf("%25s %-25s %s\n", "dtype", "name", "ptrs atype addr size"); | |
qsort(blk.hash.tbl, blk.hash.size, sizeof(HDATA), cmpSeq); | |
int n; | |
for (n = 0; n < blk.hash.size; n++) | |
{ | |
Name *e = blk.hash.tbl[n].val; | |
if (e == NULL) continue; | |
char *fmt = strlen(toString(e->dataType)) < 26 ? "%25s %-25s" : "%.23s.. %.23s.."; | |
printf(fmt, toString(e->dataType), toString(e->idName)); | |
printf(" %d%5d%9d%8d\n", e->ptrs, e->addrType, e->address, e->size[0]); | |
} | |
} | |
void createNameTable(int idFunc) | |
{ | |
if (++cd.currTable > 1) idFunc = cd.block[cd.currTable - 1].idFunc; | |
cd.block[cd.currTable].idFunc = idFunc; | |
cd.block[cd.currTable].blockDepth = cd.currTable; | |
initHash('n', cd.currTable == 0 ? 1000 : 4, &cd.block[cd.currTable].hash); | |
} | |
void deleteNameTable() | |
{ | |
if (opt&oNAME) printNameTable(cd.currTable); | |
freeHash(&cd.block[cd.currTable--].hash); | |
} | |
Name *newName(int type, int dataType, int name, int addrType, int address) | |
{ | |
Name buf = { type, name, dataType, addrType, address }; | |
Name *pNew = xalloc(sizeof(Name)); | |
memcpy(pNew, &buf, sizeof(Name)); | |
pNew->argc = -1; | |
return pNew; | |
} | |
Name *putName(int ixBlk, Name *pName) | |
{ | |
char key[128]; | |
int type = pName->type; | |
char *name = toString((type&NM_STRUCT) ? pName->dataType : pName->idName); | |
sprintf(key, "%s%s", (type&NM_FUNC) ? "@" : (type&NM_STRUCT) ? "$" : "", name); | |
put(key, pName, &cd.block[ixBlk].hash); | |
return pName; | |
} | |
Name *appendName(int ixBlk, int type, int dataType, int name, int addrType, int address) | |
{ | |
return putName(ixBlk, newName(type, dataType, name, addrType, address)); | |
} | |
Name *getNameFromTable(int ixBlk, int type, int name) | |
{ | |
char key[128]; | |
sprintf(key, "%s%s", (type&NM_FUNC) ? "@" : (type&NM_STRUCT) ? "$" : "", toString(name)); | |
return get(key, &cd.block[ixBlk].hash); | |
} | |
Name *getNameFromAllTable(int ixBlk, int type, int name) | |
{ | |
for (; ixBlk >= 0; ixBlk--) | |
{ | |
Name *e = getNameFromTable(ixBlk, type, name); | |
if (e != NULL) return e; | |
} | |
return NULL; | |
} | |
Name *getStruct(int type) | |
{ | |
return getNameFromTable(globTable, NM_STRUCT, type); | |
} | |
int getPtr(int type) | |
{ | |
Name *pStruct = getStruct(type); | |
return pStruct != NULL ? pStruct->ptrs : 0; | |
} | |
Name *getAttr(int type, int name) | |
{ | |
Name *e = getStruct(type)->pBgn; | |
while (e != NULL && e->idName != name) e = e->pNext; | |
return e; | |
} | |
Name *getMember(int type, int n) | |
{ | |
Name *e = getStruct(type)->pBgn; | |
while (n-- > 0 && e != NULL) e = e->pNext; | |
return e; | |
} | |
void reallocCode(int size) | |
{ | |
if (ix.ixCode + size + 10 < cd.sizeCode) return; | |
cd.sizeCode = cd.sizeCode * 3 / 2; | |
cd.pCode = xrealloc(cd.pCode, cd.sizeCode*sizeof(INSTRUCT)); | |
} | |
void outCode3(int code, int num, int attr) | |
{ | |
if (code <= 0) error("outCode3", "code = %d", code); | |
reallocCode(1); | |
INSTRUCT inst = { code, num, attr }; | |
memcpy(&cd.pCode[ix.ixCode], &inst, sizeof(inst)); | |
cd.pCode[ix.ixCode++].regs = instruction[code - 1].regs_size & 0xFF00; | |
} | |
void outCode2(int code, int num) | |
{ | |
outCode3(code, num, 0); | |
} | |
void outCode1(int code) | |
{ | |
outCode3(code, 0, 0); | |
} | |
void delCodes(int from, int to) | |
{ | |
memmove(&cd.pCode[from], &cd.pCode[to], (ix.ixCode - to)*sizeof(INSTRUCT)); | |
ix.ixCode -= (to - from); | |
} | |
void delCode(int n) | |
{ | |
delCodes(n, n + 1); | |
} | |
void jumpFalse(int loc, char *msg) | |
{ | |
int in = cd.pCode[ix.ixCode - 1].inst; | |
if (in >= sete_eax && in <= setg_eax) // jNCC loc | |
{ | |
cd.pCode[ix.ixCode - 1].inst = in == setg_eax ? jle : in == setge_eax ? jl | |
: in == setl_eax ? jge : in == setle_eax ? jg : in == sete_eax ? jnz : jz; | |
cd.pCode[ix.ixCode - 1].num = loc; | |
//printf("jumpFalse %s\n", msg); | |
} | |
else // setCC/test eax,eax/jz loc | |
{ | |
outCode1(test_eax_eax); | |
outCode2(jz, loc); | |
} | |
} | |
void jumpTrue(int loc, char *msg) | |
{ | |
int in = cd.pCode[ix.ixCode - 1].inst; | |
if (in >= sete_eax && in <= setg_eax) // jCC loc | |
{ | |
cd.pCode[ix.ixCode - 1].inst = in == setg_eax ? jg : in == setge_eax ? jge | |
: in == setl_eax ? jl : in == setle_eax ? jle : in == sete_eax ? jz : jnz; | |
cd.pCode[ix.ixCode - 1].num = loc; | |
//printf("jumpTrue %s\n", msg); | |
} | |
else // setCC/test eax,eax/jnz loc | |
{ | |
outCode1(test_eax_eax); | |
outCode2(jnz, loc); | |
} | |
} | |
void outData(int inst, int offset) | |
{ | |
reallocCode(1); | |
cd.pCode[ix.ixCode].inst = inst; | |
cd.pCode[ix.ixCode].offset = offset; | |
} | |
void outInteger(int offset, int size, int ival) | |
{ | |
outData(setint, offset); | |
cd.pCode[ix.ixCode].attr = size; | |
cd.pCode[ix.ixCode++].num = ival; | |
} | |
void outReal(int offset, double dval) // setreal dval,offset | |
{ | |
outData(setreal, offset); | |
cd.pCode[ix.ixCode++].dval = dval; | |
} | |
int outString(int offset, char *sval) | |
{ | |
outData(setstr, offset); | |
cd.pCode[ix.ixCode++].sval = sval; | |
return xstrlen(sval); | |
} | |
void outDataChar(int c) | |
{ | |
outInteger(ix.ixData, 1, c); | |
ix.ixData++; | |
} | |
void outDataShort(int n) | |
{ | |
outInteger(ix.ixData, 2, n); | |
ix.ixData += 2; | |
} | |
void outDataInt(int n) | |
{ | |
outInteger(ix.ixData, 4, n); | |
ix.ixData += 4; | |
} | |
void outDataAddr(int p) | |
{ | |
outInteger(ix.ixData, 0, p); | |
ix.ixData += 4; | |
} | |
void outDataDouble(double d) | |
{ | |
outReal(ix.ixData, d); | |
ix.ixData += 8; | |
} | |
int xstrcpy(char *p, char *q) | |
{ | |
int len = 0; | |
while (*q) | |
{ | |
int fKanji = isKanji(*q & 0xff); | |
len += fKanji ? 2 : 1; | |
if (p != NULL && fKanji) | |
{ | |
*p++ = *q; | |
*p++ = q[1]; | |
} | |
else if (p != NULL) | |
{ | |
*p++ = *q == '\\' ? esc_char(q + 1) : *q; | |
} | |
q += *q == '\\' ? (q[1] == 'x' ? 4 : 2) : (fKanji ? 2 : 1); | |
} | |
return len; | |
} | |
int xstrlen(char *p) | |
{ | |
return xstrcpy(NULL, p); | |
} | |
void loadAddr(type, addr) | |
{ | |
if (type == AD_STACK) outCode2(lea_eax_pbp, addr); | |
else outCode3(mov_eax, addr, type); | |
} | |
void loadValue(int type, int fPtr) | |
{ | |
int *pI = &cd.pCode[ix.ixCode - 1].inst; | |
if (type == ID.INT || fPtr) | |
{ | |
if (*pI >= lea_eax_ad1 && *pI <= lea_eax_ad8) | |
*pI = mov_eax_ad1 + (*pI - lea_eax_ad1); | |
else if (*pI == lea_eax_pbp) *pI = mov_eax_pbp; | |
else outCode1(mov_eax_pax); | |
} | |
else if (type == ID.CHAR) | |
{ | |
outCode1(movsx_eax_bax); | |
} | |
else if (type == ID.SHORT) | |
{ | |
outCode1(movsx_eax_wax); | |
} | |
else if (type == ID.DOUBLE) | |
{ | |
if (*pI == lea_eax_pbp) *pI = fld_qbp; | |
else if (*pI == mov_eax) *pI = fld_qp; | |
else outCode1(fld_qax); | |
} | |
else | |
{ | |
error("code.loadValue", "undefined type '%s'", toString(type)); | |
} | |
} | |
void setFpuStack2(int type1, int type2) | |
{ | |
if (type1 == ID.INT) | |
{ | |
outCode2(fild_dsp, 0); | |
outCode2(add_esp, 4); | |
outCode1(fxch_st1); | |
} | |
else if (type2 == ID.INT) | |
{ | |
outCode2(mov_psp_eax, -4); // outCode1(push_eax); | |
outCode2(fild_dsp, -4); // outCode2(fild_dsp, 0); outCode2(add_esp, 4); | |
} | |
} | |
int loc() | |
{ | |
return ++ix.ixLoc; | |
} | |
int id2(char* op) | |
{ | |
return (op[0] * 137 + op[1]) % cd.hash.size; | |
} | |
int isId(int n) | |
{ | |
return cd.token[ix.tix + n].type <= TK_NAME; // TK_SYMBOL or TK_NAME | |
} | |
int is(int id) | |
{ | |
return isId(0) && cd.token[ix.tix].ival == id; | |
} | |
int isN(int id, int n) | |
{ | |
return isId(n) && cd.token[ix.tix + n].ival == id; | |
} | |
int is2(char *op) | |
{ | |
return isId(0) && cd.token[ix.tix].ival == id2(op); | |
} | |
int id(char* str) | |
{ | |
return put(str, NULL, &cd.hash); | |
} | |
int ispp(int id) | |
{ | |
if (is(id)) | |
{ | |
ix.tix++; | |
return 1; | |
} | |
else return 0; | |
} | |
int is2pp(char *op) | |
{ | |
if (is2(op)) | |
{ | |
ix.tix++; | |
return 1; | |
} | |
else return 0; | |
} | |
void skip(int id) | |
{ | |
if (!ispp(id)) error("code.skip", "'%s' expected", toString(id)); | |
} | |
void setValue(int mode, int ptrs, int type, VALUE *pv) | |
{ | |
VALUE val = { mode, ptrs, type }; | |
memcpy(pv, &val, sizeof(VALUE)); | |
} | |
int sizeOfDataType(int type) | |
{ | |
if (type == ID.CHAR || type == ID.HVOID) return 1; | |
if (type == ID.SHORT) return 2; | |
if (type == ID.INT || type == ID.FLOAT) return 4; | |
if (type == ID.DOUBLE) return 8; | |
Name *pName = getStruct(type); | |
return pName != NULL ? pName->size[0] : 0; | |
} | |
typedef struct _Variable | |
{ | |
int tag, type, id; | |
int width; | |
int pointers, arrays; | |
int size[8], length; | |
} Variable; | |
Variable var; | |
void init(); | |
void setToken(TOKEN *token, HASH *pHash); | |
void program(); | |
void functionDefinition(); | |
void variableDeclaration(Name *pStruct, int status); | |
void structDeclaration(); | |
void enumDefinition(); | |
void parse() | |
{ | |
int n; | |
cd.sizeCode = 10000; | |
cd.pCode = xalloc(cd.sizeCode * sizeof(INSTRUCT)); | |
init(); | |
for (n = 0; n < cd.nToken; n++) | |
{ | |
setToken(&cd.token[n], &cd.hash); | |
if (opt&oTOKEN) printToken(n); | |
} | |
cd.currTable = -1; | |
createNameTable(id("<global>")); | |
program(); | |
for (n = 0; n < ix.ixCode - 2; n++) // 160: jz loc_018 jnz loc_017 | |
{ | |
int inst = cd.pCode[n].inst; // 161: jmp loc_017 jmp loc_018 | |
int num = cd.pCode[n].num; // 162: loc_018:[48] loc_018 | |
if ((inst == jge || inst == jl || inst == jz || inst == jnz) | |
&& cd.pCode[n + 1].inst == jmp && cd.pCode[n + 2].num == num) | |
{ | |
cd.pCode[n].num = cd.pCode[n + 1].num; | |
cd.pCode[n + 1].num = num; | |
cd.pCode[n].inst = inst == jge ? jl : inst == jl ? jge : inst == jz ? jnz : jz; | |
} | |
} | |
for (n = 0; n < ix.ixCode - 1; n++) // jmp 0 | |
{ | |
if (cd.pCode[n].inst == jmp && cd.pCode[n + 1].inst == loc_ | |
&& cd.pCode[n].num == cd.pCode[n + 1].num) delCode(n); | |
} | |
} | |
int isFunctionDefinition() | |
{ | |
int n = is(ID.DECLSP) ? 5 : 1; | |
if (is(ID.STATIC)) return FALSE; | |
if (n == 1 && !isTypeSpecifier(ix.tix)) return FALSE; | |
while (ix.tix + n < cd.nToken && cd.token[ix.tix + n].ival == '*') | |
n++; | |
if (cd.token[ix.tix + n].ival == ID.HWINAPI) return TRUE; | |
return cd.token[ix.tix + n + 1].ival == '('; | |
} | |
/// Program ::= (FunctionDefinition | VariableDeclaration ";")* | |
void program() | |
{ | |
for (ix.tix = 0; ix.tix + 2 < cd.nToken;) | |
{ | |
if (opt&oTRACE) printToken(ix.tix); | |
if (is(ID.TYPEDEF) && ix.tix + 5 < cd.nToken | |
&& cd.token[ix.tix + 3].ival != '{') | |
{ | |
ix.tix += 5; // typedef struct <tag-name> <type-name>; | |
} | |
else if (is(ID.TYPEDEF)) | |
{ | |
structDeclaration(); | |
} | |
else if (is(ID.ENUM)) | |
{ | |
enumDefinition(); // enum | |
} | |
else if (isFunctionDefinition()) | |
{ | |
functionDefinition(); | |
} | |
else | |
{ | |
variableDeclaration(NULL, ST_GVAR); | |
skip(';'); | |
} | |
} | |
} | |
/// TypeSpecifier ::= "void" | "char" | "short" | "int" | "float" | "double" | |
void typeSpecifier() | |
{ | |
if (is(ID.DECLSP)) ix.tix += 4; // __declspec(dllexport) | __declspec(dllimport) | |
int fStruct = is(ID.STRUCT); | |
if (fStruct || is(ID.TYPEDEF) || is(ID.HCONST)) ix.tix++; | |
if (!fStruct && !isTypeSpecifier(ix.tix)) | |
error("typeSpecifier", "'%s' undeclared", toStr(ix.tix)); | |
var.type = cd.token[ix.tix++].ival; | |
} | |
int isTypeSpecifier(int ix) | |
{ | |
int hix = cd.token[ix].ival; | |
return cd.token[ix].type == TK_NAME && ((int)cd.hash.tbl[hix].val)&AT_TYPE; | |
} | |
void setAttr(Name *pName) | |
{ | |
int n = var.size[0] == 0 ? 0 : var.arrays; | |
pName->ptrs = var.pointers + var.arrays; | |
pName->size[n] = var.width; | |
while (--n >= 0) pName->size[n] = pName->size[n + 1] * var.size[n]; | |
} // int d[5][3][6] { 5*3*6*4, 3*6*4, 6*4, 4 } | |
void countMember(int depth, int *dim) | |
{ | |
VALUE v; | |
int n; | |
for (n = 0; !is('}'); n++) | |
{ | |
if (ispp('{')) countMember(depth + 1, dim); | |
else assignExpression(VAL, &v); | |
if (!ispp(',')) break; | |
} | |
skip('}'); | |
if (++n > dim[depth]) dim[depth] = n; | |
} | |
void constExpression(VALUE *pv) | |
{ | |
int ixCodeSave = ix.ixCode; | |
int ixDataSave = ix.ixData; | |
conditionalExpression(VAL, pv); | |
ix.ixCode = ixCodeSave; // mov eax,imm | |
ix.ixData = ixDataSave; | |
} | |
int constIntExpression() | |
{ | |
VALUE v; | |
constExpression(&v); | |
if (!v.fConst || v.type != ID.INT) | |
error("parser", "constant expression expected"); | |
return v.ival; | |
} | |
/// VarDeclarator ::= ("*")* ["WINAPI"] Identifier ("[" [Constant] "]")* | |
int varDeclarator(int fParam) | |
{ | |
int n, fCount = FALSE, callConv = NM_CDECL; | |
for (var.pointers = 0; ix.tix < cd.nToken && ispp('*');) | |
var.pointers++; | |
if (ispp(ID.HWINAPI)) callConv = NM_WINAPI; | |
if (cd.token[ix.tix].type == TK_SYMBOL) var.id = -1; | |
else var.id = cd.token[ix.tix++].ival; | |
memset(&var.size, 0, sizeof(var.size)); | |
for (var.arrays = 0; var.arrays < 8 && ix.tix < cd.nToken && ispp('['); var.arrays++) | |
{ | |
if (is(']')) | |
{ | |
if (!fParam) fCount = TRUE; | |
} | |
else | |
{ | |
var.size[var.arrays] = constIntExpression(); | |
} | |
skip(']'); | |
} | |
if (is('=') && fCount) | |
{ | |
INDEX ixSave = ix; | |
memset(var.size, 0, sizeof(var.size)); | |
if (cd.token[ix.tix + 1].type == TK_STRING) | |
{ | |
var.size[0] = xstrlen(toString(cd.token[ix.tix + 1].ival)) + 1; | |
} | |
else | |
{ | |
ix.tix += 2; // '=' ‚ '{' | |
countMember(0, var.size); | |
} | |
ix = ixSave; | |
} | |
if (fParam) | |
{ | |
var.pointers += var.arrays; | |
var.arrays = 0; | |
} | |
var.width = var.pointers > 0 ? 4 : sizeOfDataType(var.type); | |
var.length = 1; | |
for (n = 0; n < var.arrays; n++) | |
var.length *= var.size[n]; | |
return callConv; | |
} | |
void initializer(Name *name, int atype, int depth, int addr); | |
int align(int pos, int width) | |
{ | |
if (pos == 0) return 0; | |
if ((width & 7) == 0) return (pos + 7) & ~7; // 8byte | |
if ((width & 3) == 0) return (pos + 3) & ~3; // 4byte. | |
if ((width & 1) == 0) return (pos + 1) & ~1; // 2byte | |
return pos; | |
} | |
/// VariableDeclaration ::= TypeSpecifier VarDeclarator ["=" Initializer] | |
/// ("," VarDeclarator ["=" Initializer])* | |
void variableDeclaration(Name *pStruct, int status) | |
{ | |
Name *pName; | |
int fStatic = ispp(ID.STATIC); | |
int fImp = is(ID.DECLSP); // Import | |
typeSpecifier(); | |
do | |
{ | |
varDeclarator(FALSE); | |
if (status == ST_FUNC) | |
{ | |
if (!fStatic) | |
{ | |
cd.baseSpace = -align(-cd.baseSpace, var.width); | |
cd.baseSpace -= var.width * var.length; | |
pName = newName(NM_VAR, var.type, var.id, AD_STACK, cd.baseSpace); | |
} | |
else // Ex. static int n; | |
{ | |
ix.ixData = align(ix.ixData, var.width); | |
pName = newName(NM_VAR, var.type, var.id, AD_DATA, ix.ixData); | |
} | |
putName(cd.currTable, pName); | |
} | |
else if (fImp && status == ST_GVAR) | |
{ | |
pName = appendName(globTable, NM_VAR, var.type, var.id, AD_IMPORT, 0); | |
} | |
else if (status == ST_GVAR) | |
{ | |
ix.ixData = align(ix.ixData, var.width); | |
pName = appendName(globTable, NM_VAR, var.type, var.id, AD_DATA, ix.ixData); | |
} | |
else // status==ST_STRUCT | |
{ | |
cd.offset = align(cd.offset, var.width); | |
pName = xalloc(sizeof(Name)); | |
Name buf = { NM_ATTR, var.id, var.type, 0, cd.offset }; | |
memcpy(pName, &buf, sizeof(Name)); | |
if (pStruct->pBgn == NULL) pStruct->pBgn = pName; | |
else pStruct->pEnd->pNext = pName; | |
pStruct->pEnd = pName; | |
cd.offset += var.width * var.length; | |
} | |
setAttr(pName); | |
if (ispp('=')) | |
{ | |
int ixString = ix.ixData + pName->size[0]; | |
if (status == ST_GVAR) ix.ixString = ixString; | |
initializer(pName, pName->addrType, 0, pName->address); | |
if (ix.ixString > ixString) ix.ixData = ix.ixString; | |
} | |
else if (!fImp && (status == ST_GVAR || fStatic)) | |
{ | |
ix.ixZero = align(ix.ixZero, var.width); | |
pName->addrType = AD_ZERO; | |
pName->address = ix.ixZero; | |
ix.ixZero += pName->size[0]; | |
} | |
} while (ispp(',')); | |
} | |
void initMember(Name *pName, int atype, int depth, int addr) | |
{ | |
VALUE v1, v2; | |
setValue(VAL, pName->ptrs, pName->dataType, &v1); | |
if (atype == AD_STACK) | |
{ | |
int left_bgn = ix.ixCode; | |
loadAddr(AD_STACK, addr); | |
int left_end = ix.ixCode; | |
outCode1(push_eax); | |
assignExpression(VAL, &v2); | |
infixOperation('=', &v1, &v2, left_bgn, left_end); | |
} | |
else // type == AD_DATA: | |
{ | |
if (v1.ptrs - depth == 1 && v1.type == ID.CHAR) // char *s = "abc"; | |
{ | |
if (cd.token[ix.tix].type == TK_STRING) | |
{ | |
int ival = cd.token[ix.tix++].ival; | |
outDataAddr(ix.ixString); | |
outString(ix.ixString, toString(ival)); | |
ix.ixString += xstrlen(toString(ival)) + 1; | |
} | |
else | |
{ | |
constExpression(&v2); | |
outDataInt(v2.ival); | |
} | |
} | |
else | |
{ | |
constExpression(&v2); | |
if (!v2.fConst) error("initMember", "constant expression expected"); | |
else if (v1.type == ID.DOUBLE) | |
outDataDouble(v2.type == ID.DOUBLE ? v2.rval : (double)v2.ival); | |
else if (v2.type != ID.INT) error("initMember", "type mismatch"); | |
else if (v1.type == ID.INT) outDataInt(v2.ival); | |
else if (v1.type == ID.SHORT) outDataShort(v2.ival); | |
else if (v1.type == ID.CHAR) outDataChar(v2.ival); | |
else error("initMember", "v1.type=%d", v1.type); | |
} | |
} | |
} | |
void clear(int bgn, int end) | |
{ | |
outCode2(push, end - bgn); | |
outCode2(push, 0); | |
outCode2(lea_eax_pbp, bgn); | |
outCode1(push_eax); | |
outCode2(call, id("memset")); | |
outCode2(add_esp, 12); | |
} | |
/// Initializer ::= AssignExpression | "{" Initializer ( "," Initializer )* "}" | |
void initializer(Name *pName, int atype, int depth, int addr) | |
{ | |
int n, bgn; | |
int fArray = (pName->size[depth + 1] > 0); | |
if (!ispp('{')) | |
{ | |
if (fArray && pName->dataType == ID.CHAR && cd.token[ix.tix].type == TK_STRING) | |
{ | |
int ival = cd.token[ix.tix++].ival; // char s[] = "abc"; | |
if (atype == AD_DATA) | |
{ | |
ix.ixData += outString(ix.ixData, toString(ival)) + 1; | |
} | |
else | |
{ | |
int size = pName->size[depth] / pName->size[depth + 1]; | |
int length = xstrlen(toString(ival)) + 1; | |
if (length > size) error("init'r", "initializer-string too long"); | |
char *buf = xalloc(length); | |
xstrcpy(buf, toString(ival)); | |
for (n = 0; n < size; n++) | |
{ | |
outCode2(mov_eax, n < length ? buf[n] & 0xff : 0); | |
outCode2(mov_pbp_al, addr + n); // mov [ebp-disp],al | |
} | |
free(buf); | |
} | |
return; | |
} | |
initMember(pName, atype, depth, addr); | |
return; | |
} | |
if (fArray) | |
{ | |
int size1 = pName->size[depth + 1]; | |
int num = pName->size[depth] / size1; | |
for (n = 0; !is('}');) | |
{ | |
if (n >= num) error("init'r", "index too large"); | |
initializer(pName, atype, depth + 1, addr + size1*n++); | |
if (!ispp(',')) break; | |
} | |
bgn = size1 * n; | |
} | |
else | |
{ | |
bgn = pName->size[depth]; | |
for (n = 0; !is('}');) | |
{ | |
Name *pChild = getMember(pName->dataType, n++); | |
if (pChild == NULL) error("init'r", "too many field init"); | |
initializer(pChild, atype, 0, addr + pChild->address); | |
bgn = pChild->address + pChild->size[0]; | |
if (!ispp(',')) break; | |
} | |
} | |
if (atype == AD_STACK && bgn < pName->size[depth]) | |
clear(addr + bgn, addr + pName->size[depth]); | |
skip('}'); | |
} | |
/// StructDecl ::= "typedef" "struct" Identifier "{" (VarDecl)* ";" "}" Identifier ";" | |
void structDeclaration() | |
{ | |
ix.tix += 2; // "typedef" "struct" | |
int tagId = cd.token[ix.tix++].ival; | |
Name *pName = newName(NM_STRUCT, 0, tagId, -1, 0); | |
cd.offset = 0; | |
int sizeAlign = 1; | |
for (skip('{'); !ispp('}'); skip(';')) | |
{ | |
variableDeclaration(pName, ST_STRUCT); | |
if (var.type == ID.SHORT && sizeAlign < 2) sizeAlign = 2; | |
if ((var.type == ID.INT || var.type == ID.FLOAT) && sizeAlign < 4) sizeAlign = 4; | |
if (var.type == ID.DOUBLE && sizeAlign < 8) sizeAlign = 8; | |
} | |
if (sizeAlign > 1) | |
cd.offset = align(cd.offset, sizeAlign); | |
pName->size[0] = cd.offset; | |
if (ispp('*')) pName->ptrs = 1; | |
int nameId = cd.token[ix.tix++].ival; | |
pName->dataType = nameId; | |
putName(globTable, pName); | |
cd.hash.tbl[nameId].val = (void*)((int)cd.hash.tbl[nameId].val | AT_TYPE);// Æ’fÂ[Æ’^Å’^. | |
skip(';'); | |
} | |
/// ParameterDeclaration ::= TypeSpecifier VarDeclarator ["(" ")"] | "..." | |
void parameterDeclaration() | |
{ | |
typeSpecifier(); | |
varDeclarator(TRUE); | |
if (ispp('(') && !ispp(')')) | |
error("paramDecl", "')' expected"); | |
Name *pName = appendName(cd.currTable, NM_VAR, var.type, var.id, AD_STACK, cd.baseSpace); | |
setAttr(pName); | |
cd.baseSpace += var.width; | |
} | |
/// FunctionDefinition ::= TypeSpecifier VarDeclarator | |
/// "(" [ VarDeclaration ("," VarDeclaration)* ] ")" (CompoundStatement | ";") | |
void functionDefinition() | |
{ | |
int callConv = NM_CDECL; // Calling Convention | |
int fRtnStmt = FALSE; | |
int fProtoType = FALSE; | |
int ixCodeSave = ix.ixCode; | |
int ixSp, n, argc, ptrs; | |
PTRS_TYPE argpt[256]; | |
int fExp = is(ID.DECLSP); // Export | |
typeSpecifier(); | |
if (varDeclarator(FALSE) == NM_WINAPI) callConv = NM_WINAPI; | |
int idFunc = var.id; | |
createNameTable(var.id); | |
outCode2((fExp ? exp_ : fn_), var.id); | |
Name *pName = getNameFromTable(globTable, NM_CDECL, var.id); | |
if (pName == NULL) | |
{ | |
pName = appendName(globTable, callConv, var.type, var.id, AD_CODE, 0); | |
pName->ptrs = var.pointers + var.arrays + getPtr(var.type); | |
} | |
else if (pName->dataType != var.type || pName->type != callConv) | |
{ | |
error("funcDef", "incompatible types for redefinition of '%s'", toString(var.id)); | |
} | |
cd.baseSpace = 4 * 2; | |
outCode1(xent); // push ebp, mov ebp,esp | |
ixSp = ix.ixCode; | |
outCode2(sub_esp, 0); | |
argc = 0; | |
for (skip('('); !ispp(')'); ispp(',')) | |
{ | |
int fD3 = ispp(ID.DOTS3); | |
if (!fD3) | |
{ | |
parameterDeclaration(); | |
ptrs = var.pointers + var.arrays + getPtr(var.type); | |
} | |
argpt[argc].ptrs = fD3 ? 0 : ptrs; | |
argpt[argc++].type = fD3 ? ID.DOTS3 : var.type; | |
} | |
pName->argc = argc; | |
int sizeRet = callConv == NM_WINAPI ? (cd.baseSpace - 8) : 0; | |
if (argc > 0) | |
{ | |
pName->argpt = calloc(argc, sizeof(PTRS_TYPE)); | |
memcpy(pName->argpt, argpt, argc * sizeof(PTRS_TYPE)); | |
} | |
cd.baseSpace = 0; | |
if (ispp(';')) fProtoType = TRUE; | |
else fRtnStmt = compoundStatement(0, 0, sizeRet); | |
if (cd.baseSpace < 0) | |
cd.baseSpace = -align(-cd.baseSpace, 4); | |
if (cd.baseSpace != 0) | |
cd.pCode[ixSp].num = -cd.baseSpace; | |
else | |
memmove(&cd.pCode[ixSp], &cd.pCode[ixSp + 1], (--ix.ixCode - ixSp)*sizeof(INSTRUCT)); | |
if (!fRtnStmt) outCode2(xret, sizeRet); | |
deleteNameTable(); | |
if (fProtoType) ix.ixCode = ixCodeSave; | |
else cd.hash.tbl[idFunc].val += (fExp ? AT_EXPT : AT_USER); | |
} | |
void setToken(TOKEN *token, HASH *pHash) | |
{ | |
char *tkstr = token->token; | |
if (token->type == TK_SYMBOL || token->type == TK_NAME) | |
{ | |
token->ival = put(tkstr, NULL, pHash); | |
} | |
else if (token->type == TK_NUMBER) | |
{ | |
token->type = strchr(tkstr, '.') != NULL ? TK_DOUBLE : TK_INT; | |
if (token->type == TK_DOUBLE) token->dval = strtod(tkstr, NULL); | |
else token->ival = strtoul(tkstr, NULL, tolower(tkstr[1]) == 'x' ? 16 : 10); | |
} | |
else if (tkstr[0] == '\'') | |
{ | |
token->type = TK_CHAR; | |
token->ival = tkstr[1] != '\\' ? tkstr[1] : esc_char(tkstr + 2); | |
} | |
else | |
{ | |
char *pTail = &tkstr[strlen(tkstr) - 1]; | |
if (*pTail == '\"') *pTail = '\0'; | |
token->ival = put(tkstr + 1, NULL, pHash); | |
} | |
} | |
void enumDefinition() | |
{ | |
int val = 0; | |
skip(ID.ENUM); | |
for (skip('{'); !ispp('}'); ispp(',')) | |
{ | |
int hid = cd.token[ix.tix++].ival; | |
Name *pName = appendName(globTable, NM_ENUM, 0, hid, -1, val++); | |
if (ispp('=')) | |
{ | |
val = cd.token[ix.tix++].ival; | |
pName->address = val++; | |
} | |
} | |
skip(';'); | |
} | |
typedef struct _Keyword | |
{ | |
int *id; | |
char *name; | |
} Keyword; | |
void init() | |
{ | |
int n; | |
char *op2 = OPERATOR2, s[2] = { 0, '\0' }, s2[3]; | |
Keyword dataType[] = | |
{ | |
{ &ID.HVOID, "void" }, { &ID.CHAR, "char" }, { &ID.SHORT, "short" }, | |
{ &ID.INT, "int" }, { &ID.FLOAT, "float" }, { &ID.DOUBLE, "double" }, | |
{ &ID.STATIC, "static" }, { &ID.STRUCT, "struct" } | |
}; | |
Keyword keyword[] = | |
{ | |
{ &ID.IF, "if" }, { &ID.ELSE, "else" }, { &ID.WHILE, "while" }, | |
{ &ID.DO, "do" }, { &ID.FOR, "for" }, | |
{ &ID.RETURN, "return" }, { &ID.CONTINUE, "continue" }, { &ID.BREAK, "break" }, | |
{ &ID.SWITCH, "switch" }, { &ID.CASE, "case" }, { &ID.DEFAULT, "default" }, | |
{ &ID.SIZEOF, "sizeof" }, { &ID.DOTS3, "..." }, | |
{ &ID.TYPEDEF, "typedef" }, { &ID.HWINAPI, "WINAPI" }, { &ID.ENUM, "enum" }, | |
{ &ID.HCONST, "const" }, { &ID.EXTERN, "extern" }, { &ID.DECLSP, "__declspec" }, | |
{ &ID.DLLIMPT, "dllimport" }, { &ID.DLLEXPT, "dllexport" } | |
}; | |
for (*s = ' ' + 1; *s < 127; (*s)++) | |
{ | |
if (isgraph(*s) && !isdigit(*s)) put(s, NULL, &cd.hash); | |
} | |
for (n = 0; op2[n] != '\0'; n += 3) | |
{ | |
sprintf(s2, "%c%c", op2[n], op2[n + 1]); | |
if (id2(&op2[n]) != put(s2, NULL, &cd.hash)) | |
error("parser.init", "ÂÕ“Ë!! Æ’nÆ’bÆ’Vƒ…ƒTÆ’CÆ’Y‚ðˆá‚¤‘fÂâ€â€šÃ‰â€¢Ã‚¦‚é"); | |
} | |
for (n = 0; n < sizeof(dataType) / sizeof(Keyword); n++) | |
*(dataType[n].id) = put(dataType[n].name, (void*)AT_TYPE, &cd.hash); | |
for (n = 0; n < sizeof(keyword) / sizeof(Keyword); n++) | |
*(keyword[n].id) = put(keyword[n].name, NULL, &cd.hash); | |
} | |
//------------------------------------------------------------------------// | |
// Statement // | |
//------------------------------------------------------------------------// | |
void statement(int locBreak, int locContinue, int sizeRet); | |
void expr(int mode) | |
{ | |
VALUE v; | |
expression(mode, &v); | |
} | |
void expr2(int mode) | |
{ | |
skip('('); | |
expr(mode); | |
skip(')'); | |
} | |
/// CompoundStatement :== "{" (VariableDeclaration ";" | Statement)* "}" | |
int compoundStatement(int locBreak, int locContinue, int sizeRet) | |
{ | |
createNameTable(-1); | |
for (skip('{'); !ispp('}');) | |
{ | |
if (cd.token[ix.tix + 1].ival != '(' && isTypeSpecifier(ix.tix)) | |
{ | |
variableDeclaration(NULL, ST_FUNC); | |
skip(';'); | |
} | |
else | |
{ | |
statement(locBreak, locContinue, sizeRet); | |
} | |
} | |
deleteNameTable(); | |
int n = ix.ixCode; | |
while (--n > 0 && (cd.pCode[n].inst == loc_ || cd.pCode[n].inst == fn_)); | |
return cd.pCode[n].inst == xret; | |
} | |
/// IfStatement ::= "if" "(" Expression ")" Statement [ "else" Statement ] | |
void ifStatement(int locBreak, int locContinue, int sizeRet) | |
{ | |
int locElse = loc(), locEnd = -1; | |
ix.tix++; | |
expr2(VAL); | |
jumpFalse(locElse, "if"); | |
int fReturn = is(ID.RETURN); | |
statement(locBreak, locContinue, sizeRet); // then_statement | |
if (is(ID.ELSE) && !fReturn) outCode2(jmp, locEnd = loc()); | |
outCode3(loc_, locElse, 'E'); | |
if (ispp(ID.ELSE)) | |
{ | |
statement(locBreak, locContinue, sizeRet); // else_statement | |
if (locEnd >= 0) outCode2(loc_, locEnd); | |
} | |
} | |
/// ForStatement ::= "for" "(" [Expr1] ";" [Expr2] ";" [Expr3] ")" Statement | |
void forStatement(int isFOR, int sizeRet) | |
{ | |
int locExpr2 = loc(), locExpr3 = 0, locStmt = loc(), locNext = loc(); | |
ix.tix++; // for | |
skip('('); | |
if (isFOR) | |
{ | |
if (!is(';')) expr(VAL); | |
skip(';'); | |
} | |
outCode2(loc_, locExpr2); | |
int bgn = ix.ixCode; | |
if (!is(';')) expr(VAL); | |
else outCode2(mov_eax, 1); | |
if (isFOR) skip(';'); | |
jumpFalse(locNext, "for"); | |
outCode2(jmp, locStmt); | |
if (cd.pCode[bgn].inst == mov_eax && cd.pCode[bgn + 1].inst == test_eax_eax) | |
{ | |
ix.ixCode = bgn; | |
outCode2(jmp, cd.pCode[bgn].num == 0 ? locNext : locStmt); | |
} | |
int bgnExpr = ix.ixCode; | |
outCode2(loc_, locExpr3 = loc()); | |
if (isFOR && !is(')')) expr(VAL); | |
skip(')'); | |
int bgnStmt = ix.ixCode; | |
outCode3(loc_, locStmt, '1'); | |
statement(locNext, locExpr3, sizeRet); | |
int endStmt = ix.ixCode; | |
int lenStmt = endStmt - bgnStmt; | |
int lenBoth = endStmt - bgnExpr; | |
if (bgnStmt - bgnExpr > 0 && lenStmt > 0) | |
{ | |
reallocCode(lenStmt); | |
memmove(&cd.pCode[bgnExpr + lenStmt], &cd.pCode[bgnExpr], lenBoth*sizeof(INSTRUCT)); | |
memmove(&cd.pCode[bgnExpr], &cd.pCode[bgnStmt + lenStmt], lenStmt*sizeof(INSTRUCT)); | |
} | |
outCode2(jmp, locExpr2); | |
outCode3(loc_, locNext, '0'); | |
} | |
/// WhileStatement ::= "while" "(" Expression ")" Statement | |
void whileStatement(int sizeRet) | |
{ | |
forStatement(FALSE, sizeRet); | |
} | |
/// DoStatement ::= "do" CompoundStatement "while" "(" Expression ")" ";" | |
void doStatement(int sizeRet) | |
{ | |
int locStmt = loc(), locBreak = loc(); | |
ix.tix++; | |
outCode2(loc_, locStmt); | |
compoundStatement(locBreak, locStmt, sizeRet); | |
if (!ispp(ID.WHILE)) error("doStmt", "while ‚ª‚ ‚è‚Ü‚¹‚ñ"); | |
expr2(VAL); | |
skip(';'); | |
jumpTrue(locStmt, "do"); //outCode1(test_eax_eax); outCode2(jnz,locStmt); | |
outCode2(loc_, locBreak); | |
} | |
/// ReturnStatement ::= "return" [Expression] ";" | |
void returnStatement(int sizeRet) | |
{ | |
ix.tix++; // "return" | |
if (!is(';')) | |
{ | |
VALUE v; | |
expression(VAL, &v); | |
} | |
skip(';'); | |
outCode2(xret, sizeRet); | |
} | |
/// ContinueStatement := "continue" ";" | |
void continueStatement(int locContinue) | |
{ | |
if (locContinue <= 0) | |
error("", "continue statement not within a loop"); | |
ix.tix++; | |
skip(';'); | |
outCode2(jmp, locContinue); | |
} | |
/// BreakStatement := "break" ";" | |
void breakStatement(int locBreak) | |
{ | |
if (locBreak <= 0) | |
error("", "break statement not within loop or switch"); | |
ix.tix++; | |
skip(';'); | |
outCode2(jmp, locBreak); | |
} | |
/// SwitchStatement ::= "switch" "(" Expression ")" "{" (LabeledStatement)+ "}" | |
/// LabeledStatement ::= "case" Expression ":" | Statement | "default" ":" | |
void switchStatement(int sizeRet) | |
{ | |
int locCase = loc(), locStmt = loc(), locBreak; | |
int fDefault = 0; | |
ix.tix++; // switch | |
expr2(VAL); // eax: sw_expr | |
skip('{'); | |
locBreak = loc(); | |
while (!ispp('}')) | |
{ | |
if (ispp(ID.CASE)) | |
{ | |
outCode2(loc_, locCase); | |
outCode2(cmp_eax, constIntExpression()); | |
skip(':'); | |
outCode2(jnz, locCase = loc()); | |
outCode2(loc_, locStmt); | |
if (!is(ID.CASE)) | |
{ | |
do | |
{ | |
statement(locBreak, -1, sizeRet); // break | |
} while (!is(ID.CASE) && !is(ID.DEFAULT) && !is('}')); | |
} | |
outCode2(jmp, locStmt = loc()); | |
} | |
else if ((fDefault = ispp(ID.DEFAULT))) | |
{ | |
outCode2(loc_, locCase); | |
skip(':'); | |
outCode2(loc_, locStmt); | |
do | |
{ | |
statement(locBreak, -1, sizeRet); | |
} while (!is('}')); | |
} | |
else // error | |
{ | |
error("switchStmt", "'case' or 'default' expected"); | |
} | |
} | |
if (!fDefault) | |
{ | |
outCode2(loc_, locCase); | |
outCode2(loc_, locStmt); | |
} | |
outCode2(loc_, locBreak); | |
} | |
/// Statement ::= CompoundStmt | IfStmt | ForStmt | WhileStmt | DoStmt | ReturnStmt | |
/// | BreakStmt | ContinueStmt | SwitchStmt | Expression ";" | ";" | |
void statement(int locBreak, int locContinue, int sizeRet) | |
{ | |
if (is(';')) ix.tix++; // null statement | |
else if (is('{')) compoundStatement(locBreak, locContinue, sizeRet); | |
else if (is(ID.IF)) ifStatement(locBreak, locContinue, sizeRet); | |
else if (is(ID.FOR)) forStatement(TRUE, sizeRet); | |
else if (is(ID.WHILE)) whileStatement(sizeRet); | |
else if (is(ID.DO)) doStatement(sizeRet); | |
else if (is(ID.RETURN)) returnStatement(sizeRet); | |
else if (is(ID.BREAK)) breakStatement(locBreak); | |
else if (is(ID.CONTINUE)) continueStatement(locContinue); | |
else if (is(ID.SWITCH)) switchStatement(sizeRet); | |
else | |
{ | |
expr(VAL); | |
skip(';'); | |
} | |
} | |
void infixOperation(int op, VALUE *v1, VALUE *v2, int lbgn, int lend) | |
{ | |
if (v1->fConst && v2->fConst) | |
{ | |
if (v1->type == ID.INT && v2->type == ID.INT) | |
{ | |
if (op == '+') v1->ival += v2->ival; | |
else if (op == '-') v1->ival -= v2->ival; | |
else if (op == '*') v1->ival *= v2->ival; | |
else if (op == '/') v1->ival /= v2->ival; | |
else if (op == '%') v1->ival %= v2->ival; | |
else if (op == '|') v1->ival |= v2->ival; | |
else if (op == '&') v1->ival &= v2->ival; | |
else if (op == '^') v1->ival ^= v2->ival; | |
else v1->fConst = FALSE; | |
} | |
else if (v1->type == ID.DOUBLE || v2->type == ID.DOUBLE) | |
{ | |
double d1 = v1->type == ID.DOUBLE ? v1->rval : (double)v1->ival; | |
double d2 = v2->type == ID.DOUBLE ? v2->rval : (double)v2->ival; | |
v1->type = ID.DOUBLE; | |
if (op == '+') v1->rval = d1 + d2; | |
else if (op == '-') v1->rval = d1 - d2; | |
else if (op == '*') v1->rval = d1 * d2; | |
else if (op == '/') v1->rval = d1 / d2; | |
else v1->fConst = FALSE; | |
} | |
else | |
{ | |
v1->fConst = FALSE; | |
} | |
} | |
else if (v2->fConst && lend > 0 && v1->type == ID.INT && v2->type == ID.INT) | |
{ | |
if (v1->ptrs == 0 && (op == '+' || op == '-')) | |
{ | |
ix.ixCode = lend; | |
outCode2(op == '+' ? add_eax : sub_eax, v2->ival); | |
return; | |
} | |
else if (op == '<' || op == '>' || op == id2("<=") || op == id2(">=") || op == id2("==") || op == id2("!=")) | |
{ | |
ix.ixCode = lend; | |
outCode2(cmp_eax, v2->ival); | |
outCode1(op == '<' ? setl_eax : op == '>' ? setg_eax : op == id2("<=") ? setle_eax : | |
op == id2(">=") ? setge_eax : op == id2("==") ? sete_eax : setne_eax); | |
return; | |
} | |
else if (op == '*') | |
{ | |
ix.ixCode = lend; | |
outCode2(imul_eax_eax, v2->ival); | |
return; | |
} | |
else | |
{ | |
v1->fConst = FALSE; | |
} | |
} | |
else | |
{ | |
v1->fConst = FALSE; | |
} | |
if ((v1->ptrs == 0 && v1->type == ID.DOUBLE) || (v2->ptrs == 0 && v2->type == ID.DOUBLE)) | |
{ | |
setFpuStack2(v1->type, v2->type); | |
if (op == '=') | |
{ | |
int fLV = (lend == lbgn + 1 && cd.pCode[lbgn].inst == lea_eax_pbp); | |
if (fLV) | |
{ | |
outCode3(fst_qbp, cd.pCode[lbgn].num, cd.pCode[lbgn].attr); | |
delCodes(lbgn, lbgn + 2); // lea_eax_pbp, push_eax ‚ðÂÃÂÅ“ | |
} | |
else | |
{ | |
outCode1(pop_ecx); | |
outCode1(fst_qcx); // [ecx] <- st0 | |
} | |
outCode1(fstp_st1); | |
v1->type = ID.DOUBLE; | |
} | |
else if (op == id2("==") || op == id2("!=")) | |
{ | |
outCode1(fucompp); | |
outCode1(fstsw); | |
outCode2(and_ah, 0x45); | |
outCode2(op == id2("==") ? cmp_ah : xor_ah, 0x40); | |
outCode1(op == id2("==") ? sete_eax : setne_eax); | |
v1->type = ID.INT; | |
} | |
else if (op == '<' || op == '>' || op == id2("<=") || op == id2(">=")) | |
{ | |
if (op == '>' || op == id2(">=")) outCode1(fxch_st1); | |
outCode1(fucompp); | |
outCode1(fstsw); | |
outCode2(test_ah, (op == '<' || op == '>') ? 0x45 : 0x05); | |
outCode1(sete_eax); // eax = ZF. | |
v1->type = ID.INT; | |
} | |
else if (op == '+' || op == '-' || op == '*' || op == '/') | |
{ | |
int *pI = &cd.pCode[ix.ixCode - 1].inst; | |
if (*pI == fld_qbp) // fld qp[ebp-8]/fadd qp[ebp-16] | |
{ | |
*pI = op == '+' ? fadd_qbp : op == '-' ? fsub_qbp : op == '*' ? fmul_qbp : fdiv_qbp; | |
} | |
else if (*pI == fld_qp) | |
{ | |
*pI = op == '+' ? fadd_qp : op == '-' ? fsub_qp : op == '*' ? fmul_qp : fdiv_qp; | |
} | |
else // fld qp[ebp-8]/fld qp[ebp-16]/faddp st1,st | |
{ | |
outCode1(op == '+' ? faddp_st1_st : op == '-' ? fsubrp_st1_st : | |
op == '*' ? fmulp_st1_st : fdivrp_st1_st); | |
} | |
v1->type = ID.DOUBLE; | |
} | |
else | |
{ | |
error("infixOp", "unsuported infixOp '%s'", toString(op)); | |
} | |
} | |
else | |
{ | |
int n = v1->ptrs > 0 ? 4 : sizeOfDataType(v1->type); | |
int k = ix.ixCode - 1; | |
int fLV4 = (n == 4 && lend == lbgn + 1 && cd.pCode[lbgn].inst == lea_eax_pbp); | |
if (fLV4 && (op == '=' || op == id2("+=") || op == id2("-="))) | |
{ | |
int num = cd.pCode[lbgn].num; // x = exp, x += exp, x -= exp | |
int attr = cd.pCode[lbgn].attr; | |
int inst = op == '=' ? mov_pbp_eax : op == id2("+=") ? add_pbp_eax : sub_pbp_eax; | |
delCodes(lbgn, lbgn + 2); // lea_eax_pbp‚Æpush_eax‚ðÂÃÂÅ“. | |
outCode3(inst, num, attr); | |
return; | |
} | |
int fECX = 1; | |
if (lend > 0 && cd.pCode[lend].inst == push_eax) | |
{ | |
int i; | |
for (i = lend + 1; i < ix.ixCode && !(cd.pCode[i].regs & C); i++); | |
if (i == ix.ixCode) fECX = 0; | |
} | |
if (fECX) | |
{ | |
outCode1(pop_ecx); | |
} | |
else | |
{ | |
int *pI = &cd.pCode[lend - 1].inst; | |
if (*pI == mov_eax) | |
{ | |
*pI = mov_ecx; | |
delCode(lend); // push_eax ‚val | |
} | |
else if (*pI == mov_eax_pbp) | |
{ | |
*pI = mov_ecx_pbp; | |
delCode(lend); // push_eax ‚val | |
} | |
else if (*pI == mov_eax_pax) | |
{ | |
*pI = mov_ecx_pax; | |
delCode(lend); // push_eax ‚val | |
} | |
else if (*pI >= lea_eax_da1 && *pI <= lea_eax_da8) | |
{ | |
*pI = lea_ecx_da1 + (*pI - lea_eax_da1); | |
delCode(lend); // push_eax ‚val | |
} | |
else | |
{ | |
cd.pCode[lend].inst = mov_ecx_eax; // <- push_eax | |
} | |
} | |
if (op == '=') outCode1(n == 4 ? mov_pcx_eax : n == 2 ? mov_pcx_ax : mov_pcx_al); | |
else if (op == id2("+=")) outCode1(n == 4 ? add_pcx_eax : n == 2 ? add_pcx_ax : add_pcx_al); | |
else if (op == id2("-=")) outCode1(n == 4 ? sub_pcx_eax : n == 2 ? sub_pcx_ax : sub_pcx_al); | |
else if (op == id2("&=")) outCode1(n == 4 ? and_pcx_eax : n == 2 ? and_pcx_ax : and_pcx_al); | |
else if (op == id2("|=")) outCode1(n == 4 ? or_pcx_eax : n == 2 ? or_pcx_ax : or_pcx_al); | |
else if (op == id2("^=")) outCode1(n == 4 ? xor_pcx_eax : n == 2 ? xor_pcx_ax : xor_pcx_al); | |
else if (op == id2("==") || op == id2("!=")) | |
{ | |
outCode1(cmp_eax_ecx); | |
outCode1(op == id2("==") ? sete_eax : setne_eax); | |
} | |
else if (op == '<' || op == '>' || op == id2("<=") || op == id2(">=")) | |
{ | |
outCode1(cmp_ecx_eax); | |
outCode1(op == '<' ? setl_eax : op == '>' ? setg_eax : op == id2("<=") ? setle_eax : setge_eax); | |
} | |
else if (op == '+' || op == '-') | |
{ | |
n = v1->ptrs > 1 ? 4 : sizeOfDataType(v1->type); | |
if (v1->ptrs > 0 && v2->ptrs == 0 && n > 1) outCode2(imul_eax_eax, n); | |
if (op == '+') | |
{ | |
outCode1(add_eax_ecx); // eax: operand_1 + operand_2 | |
} | |
else | |
{ | |
outCode1(xchg_eax_ecx); // ecx: operand_2 | |
outCode1(sub_eax_ecx); // eax: operand_1 - operand_2 | |
if (v1->ptrs > 0 && v2->ptrs > 0) | |
{ | |
outCode2(mov_ecx, n); | |
outCode1(xdiv_ecx); // eax: (operand_1 - operand_2)/size | |
} | |
} | |
return; | |
} | |
else if (op == '*') | |
{ | |
int k = ix.ixCode - 1; | |
if (cd.pCode[k - 1].inst == mov_ecx_pbp && cd.pCode[k].inst == mov_eax_pbp) | |
{ | |
cd.pCode[k - 1].inst = mov_eax_pbp; | |
cd.pCode[k].inst = imul_eax_pbp; | |
} | |
else | |
{ | |
outCode1(imul_eax_ecx); | |
} | |
} | |
else if (op == '/' || op == '%') | |
{ | |
outCode1(xchg_eax_ecx); | |
outCode1(op == '/' ? xdiv_ecx : xmod_ecx); | |
} | |
else if (op == '|' || op == '&' || op == '^') | |
{ | |
outCode1(op == '|' ? or_eax_ecx : op == '&' ? and_eax_ecx : xor_eax_ecx); | |
} | |
else if (op == id2("<<") || op == id2(">>")) | |
{ | |
outCode1(xchg_eax_ecx); | |
outCode1(op == id2("<<") ? shl_eax_cl : shr_eax_cl); | |
} | |
else | |
{ | |
error("infixOp", "unsuported infixOp '%s'", toString(op)); | |
} | |
v1->type = ID.INT; | |
} | |
} | |
void incdec(int type, int fPtr, int fI, int reg) // ++, -- | |
{ | |
if (type == ID.INT || fPtr) outCode2(reg == 'a' ? (fI ? add_dax : sub_dax) : (fI ? add_ddx : sub_ddx), 1); | |
else if (type == ID.CHAR) outCode2(reg == 'a' ? (fI ? add_bax : sub_bax) : (fI ? add_bdx : sub_bdx), 1); | |
else error("expr.incdec", "wrong use of ++ or --", toString(type)); | |
} | |
/// Expression ::= AssignExpression ("," AssignExpression)* | |
void expression(int mode, VALUE *pv) | |
{ | |
assignExpression(mode, pv); | |
while (ispp(',')) assignExpression(mode, pv); | |
} | |
/// AssignExpr ::= CondExpr | CastExpr ("=" | "|=" | "+=" | "-=" | "&=" | "^=") AssignExpr | |
void assignExpression(int mode, VALUE *pv) | |
{ | |
VALUE vr; | |
INDEX ixSave = ix; | |
castExpression(ADDR, pv); | |
char *t = cd.token[ix.tix].token; | |
if (strchr(";,])", *t) != NULL && pv->mode == VAL) return; | |
ix = ixSave; | |
int fAssign = (*t == '=' && t[1] == '\0') || (strchr("+-/*%|&^", *t) != NULL && t[1] == '='); | |
if (!fAssign) | |
{ | |
conditionalExpression(mode, pv); | |
return; | |
} | |
castExpression(ADDR, pv); | |
if (pv->mode != ADDR) error("assignExpr", "lvalue expected"); | |
int op = cd.token[ix.tix].ival; | |
t = cd.token[ix.tix++].token; | |
int ixOp2 = ix.ixCode; | |
outCode1(push_eax); | |
if ((pv->ptrs > 0 || pv->type != ID.DOUBLE) | |
&& op != id2("*=") && op != id2("/=") && op != id2("%=")) | |
{ | |
assignExpression(VAL, &vr); | |
infixOperation(op, pv, &vr, ixSave.ixCode, ixOp2); | |
int k = ix.ixCode - 1; | |
if (op == '=' && cd.pCode[k - 1].inst == pop_ecx && cd.pCode[k].inst == mov_pcx_eax) | |
{ | |
if (k - ixOp2 == 3 && cd.pCode[ixOp2 + 1].inst == mov_eax) | |
{ | |
cd.pCode[ixOp2 + 1].inst = mov_dax; | |
delCode(k); | |
delCode(k - 1); // pop_ecx‚val | |
delCode(ixOp2); // push_eax‚val | |
} | |
} | |
return; | |
} | |
if (t[1] != '\0') | |
{ | |
int size = pv->ptrs > 0 ? 4 : sizeOfDataType(pv->type); | |
if (size == 8) | |
{ | |
outCode1(fld_qax); | |
} | |
else | |
{ | |
outCode1(size == 4 ? mov_eax_pax : size == 2 ? movsx_eax_wax : movsx_eax_bax); | |
outCode1(push_eax); | |
} | |
} | |
assignExpression(VAL, &vr); | |
if (t[0] != '=') | |
{ | |
infixOperation(t[0], pv, &vr, -1, -1); | |
infixOperation('=', pv, &vr, -1, -1); | |
} | |
else | |
{ | |
infixOperation('=', pv, &vr, ixSave.ixCode, ixOp2); | |
} | |
} | |
/// ConditionalExpression := LogicOrExpr ["?" AssignExpr ":" AssignExpr] | |
void conditionalExpression(int mode, VALUE *pv) | |
{ | |
int locFalse, locEnd; | |
INDEX ixBgn = ix; | |
logicalOrExpression(mode, pv); | |
if (ispp('?')) | |
{ | |
outCode1(test_eax_eax); | |
outCode2(jz, locFalse = loc()); | |
INSTRUCT *pC = &cd.pCode[ix.ixCode - 3]; | |
if (pC[0].inst == sete_eax && pC[1].inst == test_eax_eax && pC[2].inst == jz) | |
{ | |
pC[2].inst = jnz; | |
delCodes(ix.ixCode - 3, ix.ixCode - 1); // sete eax/test eax,eax ‚ðÂÃÂÅ“. | |
} | |
assignExpression(VAL, pv); | |
outCode2(jmp, locEnd = loc()); | |
skip(':'); | |
outCode2(loc_, locFalse); | |
assignExpression(VAL, pv); | |
outCode2(loc_, locEnd); | |
pv->fConst = FALSE; | |
} | |
if (pv->fConst) | |
{ | |
int tixCurr = ix.tix; | |
ix = ixBgn; | |
ix.tix = tixCurr; | |
if (pv->ptrs > 0) | |
{ | |
outCode3(mov_eax, pv->ival, AD_CONST); | |
} | |
else if (pv->type == ID.INT) | |
{ | |
outCode3(mov_eax, pv->ival, cd.pCode[ix.ixCode].attr); | |
} | |
else | |
{ | |
loadAddr(AD_DATA, ix.ixData); | |
outDataDouble(pv->rval); | |
outCode1(fld_qax); | |
} | |
} | |
} | |
/// LogicalOrExpression ::= LogicalAndExpr ( "||" LogicalAndExpr )* | |
void logicalOrExpression(int mode, VALUE *pv) | |
{ | |
logicalAndExpression(mode, pv); | |
if (!is2("||")) return; | |
int locTRUE = loc(); | |
int locNext = loc(); | |
while (is2pp("||")) | |
{ | |
jumpTrue(locTRUE, "||"); // Â^(eax!=0) | |
logicalAndExpression(mode, pv); | |
pv->type = ID.INT; | |
} | |
jumpTrue(locTRUE, "||"); | |
outCode2(mov_eax, 0); | |
outCode2(jmp, locNext); | |
outCode2(loc_, locTRUE); | |
outCode2(mov_eax, 1); | |
outCode2(loc_, locNext); | |
} | |
/// LogicalAndExpression ::= OrExpression ( "&&" OrExpression )* | |
void logicalAndExpression(int mode, VALUE *pv) | |
{ | |
orExpression(mode, pv); | |
if (!is2("&&")) return; | |
int locFalse = loc(); | |
int locNext = loc(); | |
while (is2pp("&&")) | |
{ | |
jumpFalse(locFalse, "&&"); | |
orExpression(mode, pv); | |
pv->type = ID.INT; | |
} | |
jumpFalse(locFalse, "&&"); | |
outCode2(mov_eax, 1); | |
outCode2(jmp, locNext); | |
outCode3(loc_, locFalse, 'F'); | |
outCode2(mov_eax, 0); | |
outCode3(loc_, locNext, 'N'); | |
} | |
/// OrExpression ::= ExclusiveOrExpression ( "|" ExclusiveOrExpression )* | |
void orExpression(int mode, VALUE *pv) | |
{ | |
xorExpression(mode, pv); | |
while (ispp('|')) | |
{ | |
VALUE v2; | |
outCode1(push_eax); | |
xorExpression(mode, &v2); | |
infixOperation('|', pv, &v2, -1, -1); | |
} | |
} | |
/// ExclusiveOrExpression ::= AndExpression ( "^" AndExpression )* | |
void xorExpression(int mode, VALUE *pv) | |
{ | |
andExpression(mode, pv); | |
while (ispp('^')) | |
{ | |
VALUE v2; | |
outCode1(push_eax); | |
andExpression(mode, &v2); | |
infixOperation('^', pv, &v2, -1, -1); | |
} | |
} | |
/// AndExpression ::= EqualityExpression ( "&" EqualityExpression )* | |
void andExpression(int mode, VALUE *pv) | |
{ | |
equalityExpression(mode, pv); | |
while (ispp('&')) | |
{ | |
VALUE v2; | |
int ixOp2 = ix.ixCode; | |
outCode1(push_eax); | |
equalityExpression(mode, &v2); | |
infixOperation('&', pv, &v2, -1, ixOp2); | |
} | |
} | |
/// EqualityExpression ::= RelationalExpr [ ("==" | "!=") RelationalExpr ] | |
void equalityExpression(int mode, VALUE *pv) | |
{ | |
int fEQ; | |
relationalExpression(mode, pv); | |
if ((fEQ = is2pp("==")) || is2pp("!=")) | |
{ | |
VALUE v2; | |
int ixOp2 = ix.ixCode; | |
if (pv->type != ID.DOUBLE) outCode1(push_eax); | |
relationalExpression(mode, &v2); | |
if (ix.ixCode - ixOp2 == 2 && cd.pCode[ix.ixCode - 1].inst == mov_eax_pbp) | |
{ | |
cd.pCode[ix.ixCode - 1].inst = cmp_eax_pbp; | |
outCode1(fEQ ? sete_eax : setne_eax); | |
delCode(ixOp2); | |
} | |
else | |
{ | |
infixOperation(fEQ ? id2("==") : id2("!="), pv, &v2, -1, ixOp2); | |
} | |
} | |
} | |
/// RelationalExpression ::= UnaryExpr [("<" | ">" | "<=" | ">=") UnaryExpr] | |
void relationalExpression(int mode, VALUE *pv) | |
{ | |
int fLT = 0, fGT = 0, fLE = 0; | |
shiftExpression(mode, pv); | |
if ((fLT = ispp('<')) || (fGT = ispp('>')) || (fLE = is2pp("<=")) || is2pp(">=")) | |
{ | |
VALUE v2; | |
int ixOp2 = ix.ixCode; | |
if (pv->type != ID.DOUBLE) outCode1(push_eax); | |
shiftExpression(mode, &v2); | |
if (ix.ixCode - ixOp2 == 2 && cd.pCode[ix.ixCode - 1].inst == mov_eax_pbp) | |
{ | |
cd.pCode[ix.ixCode - 1].inst = cmp_eax_pbp; | |
outCode1(fLT ? setl_eax : fGT ? setg_eax : fLE ? setle_eax : setge_eax); | |
delCode(ixOp2); | |
} | |
else | |
{ | |
infixOperation(fLT ? '<' : fGT ? '>' : fLE ? id2("<=") : id2(">="), pv, &v2, -1, ixOp2); | |
} | |
} | |
} | |
/// ShiftExpression ::= AddExpression [ ("<<" | ">>") AddExpression ] | |
void shiftExpression(int mode, VALUE *pv) | |
{ | |
int fShl; | |
addExpression(mode, pv); | |
if ((fShl = is2pp("<<")) || is2pp(">>")) | |
{ | |
VALUE v2; | |
int ixOp2 = ix.ixCode; | |
outCode1(push_eax); | |
addExpression(mode, &v2); | |
infixOperation(fShl ? id2("<<") : id2(">>"), pv, &v2, -1, -1); | |
} | |
} | |
/// AddExpression ::= MulExpression ( ("+" | "-") MulExpression )* | |
void addExpression(int mode, VALUE *pv) | |
{ | |
int fAdd; | |
mulExpression(mode, pv); // operand_1 | |
while ((fAdd = ispp('+')) || ispp('-')) | |
{ | |
VALUE v2; | |
int ixOp2 = ix.ixCode; | |
if (pv->type != ID.DOUBLE) outCode1(push_eax); | |
mulExpression(mode, &v2); // operand_2 | |
infixOperation(fAdd ? '+' : '-', pv, &v2, -1, ixOp2); | |
} | |
} | |
/// MulExpression ::= CastExpression ( ("*" | "/" | "%") CastExpression )* | |
void mulExpression(int mode, VALUE *pv) | |
{ | |
int fMul = 0, fDiv = 0; | |
castExpression(mode, pv); // operand_1 | |
while ((fMul = ispp('*')) || (fDiv = ispp('/')) || ispp('%')) | |
{ | |
VALUE v2; | |
int ixOp2 = ix.ixCode; | |
if (pv->type != ID.DOUBLE) outCode1(push_eax); | |
castExpression(mode, &v2); // eax/st: operand_2 | |
infixOperation(fMul ? '*' : fDiv ? '/' : '%', pv, &v2, -1, ixOp2); | |
} | |
} | |
/// CastExpression := UnaryExpression | "(" TypeName ")" UnaryExpression | |
void castExpression(int mode, VALUE *pv) // | |
{ | |
if (!is('(') || !(isTypeSpecifier(ix.tix + 1) && !isN('(', 2))) | |
{ | |
unaryExpression(mode, pv); | |
return; // (_stat( | |
} | |
int idCastType = cd.token[++ix.tix].ival; | |
int ptr = getPtr(idCastType); | |
for (ix.tix++; ispp('*');) ptr++; | |
skip(')'); | |
unaryExpression(mode, pv); | |
if (ptr > 0) | |
{ | |
; | |
} | |
else if (idCastType == ID.INT && pv->type == ID.DOUBLE) // (int)v | |
{ | |
outCode3(fldcw, 2, AD_DATA); // _RoundNear | |
outCode2(fistp_dsp, -4); | |
outCode2(mov_eax_psp, -4); | |
outCode3(fldcw, 0, AD_DATA); // _RoundChop | |
if (pv->fConst) pv->ival = (int)pv->rval; | |
} | |
else if (idCastType == ID.SHORT && pv->type == ID.INT) | |
{ | |
outCode1(cwde); | |
if (pv->fConst) pv->ival = (short)pv->ival; | |
} | |
else if (idCastType == ID.DOUBLE && pv->type != ID.DOUBLE) // (double)n | |
{ | |
outCode2(mov_psp_eax, -4); //outCode1(push_eax); | |
outCode2(fild_dsp, -4); //outCode2(fild_dsp,0); outCode2(add_esp, 4); | |
if (pv->fConst) pv->rval = (double)pv->ival; | |
} | |
else if (idCastType != ID.INT) | |
{ | |
error("castExpr", "unsupported cast(casttype=%s type=%s)\n", | |
toString(idCastType), toString(pv->type)); | |
} | |
pv->ptrs = ptr; | |
pv->type = idCastType; | |
} | |
/// UnaryExpression ::= ["+" | "-" | "!" | "++" | "--" | "&" | "*" ] PrimExpr | |
void unaryExpression(int mode, VALUE *pv) | |
{ | |
int fNEG = 0, fNOT = 0, fINC = 0; | |
if (ispp('+') || (fNEG = ispp('-')) || (fNOT = ispp('!'))) | |
{ | |
int bgn = ix.ixCode; | |
primaryExpression(VAL, pv); | |
if (fNEG) | |
{ | |
if (pv->fConst && pv->type == ID.INT) | |
{ | |
cd.pCode[ix.ixCode - 1].num = (pv->ival = -pv->ival); | |
} | |
else if (pv->fConst && pv->type == ID.DOUBLE) | |
{ | |
cd.pCode[bgn].dval = (pv->rval = -pv->rval); | |
} | |
else | |
{ | |
outCode1(pv->type == ID.DOUBLE ? fchs : neg_eax); | |
} | |
} | |
else if (fNOT) | |
{ | |
if (pv->fConst) pv->ival = !pv->ival; | |
outCode1(test_eax_eax); | |
outCode1(sete_eax); // mov eax,0 & sete_al | |
} | |
} | |
else if ((fINC = is2pp("++")) || is2pp("--")) | |
{ | |
primaryExpression(ADDR, pv); | |
incdec(pv->type, pv->ptrs > 0, fINC, 'a'); | |
loadValue(pv->type, pv->ptrs > 0); | |
} | |
else if (ispp('&')) | |
{ | |
primaryExpression(ADDR, pv); | |
pv->fAddr = TRUE; | |
pv->ptrs++; | |
} | |
else if (ispp('*')) | |
{ | |
primaryExpression(VAL, pv); | |
pv->mode = ADDR; | |
pv->ptrs--; | |
if (mode == VAL) loadValue(pv->type, pv->ptrs > 0); | |
} | |
else | |
{ | |
primaryExpression(mode, pv); | |
} | |
} | |
int checkarg(int pt1, int type1, int pt2, int type2, char *name, int nArg) | |
{ | |
char *f = "%s arg#%d assignment makes %s from %s"; | |
char *g = "%s arg#%d assignment from incompatible pointer type"; | |
if (type2 == ID.DOTS3) return FALSE; | |
if (pt1 > 0 && pt2 == 0) error("chk", f, name, nArg, "integer", "pointer"); | |
if (pt1 == 0 && pt2 > 0) error("chk", f, name, nArg, "pointer", "integer"); | |
if (pt1 != pt2 && type1 != ID.HVOID && type2 != ID.HVOID) error("chk", g, name, nArg); | |
return TRUE; | |
} | |
/// FunctionCall ::= Identifier "(" [AssignExpression ("," AssignExpression)*] ")" | |
void functionCall(VALUE *pv) | |
{ | |
int n, nSize, nP, p[20], depth = 0; | |
int fid = cd.token[ix.tix++].ival; | |
Name *pName = getNameFromTable(globTable, NM_FUNC, fid); | |
if (pName == NULL) | |
{ | |
char *func = toString(fid); | |
if (isupper(*func)) error("funcCall", "'%s' undeclared", func); | |
pName = appendName(globTable, NM_CDECL, ID.INT, fid, AD_CODE, 0); | |
} | |
skip('('); | |
int fCheck = (pName->argc >= 0 && fid != id("main")); | |
for (nP = 0; !ispp(')'); nP++) | |
{ | |
p[nP] = ix.ixCode; | |
assignExpression(VAL, pv); | |
if (fCheck && nP < pName->argc) | |
fCheck = checkarg(pv->ptrs, pv->type, pName->argpt[nP].ptrs, | |
pName->argpt[nP].type, toString(pName->idName), nP); | |
if (pv->ptrs > 0 || pv->fAddr || pv->type != ID.DOUBLE) | |
{ | |
outCode1(push_eax); | |
depth += 4; | |
} | |
else | |
{ | |
outCode2(sub_esp, 8); | |
outCode1(fstp_qsp); //outCode1(fst_qsp); | |
depth += 8; | |
} | |
ispp(','); | |
} | |
int diff = pName->argc - nP; | |
if (diff > 0 && pName->argpt[nP].type == ID.DOTS3) fCheck = FALSE; | |
if (fCheck && diff != 0) | |
error("funcCall", "too %s arguments", diff < 0 ? "many" : "few"); | |
if (nP > 1) | |
{ | |
int mv = ix.ixCode - p[1]; | |
reallocCode(mv + 1); | |
memmove(&cd.pCode[*p + mv], &cd.pCode[*p], (ix.ixCode - *p)*sizeof(INSTRUCT)); | |
int dst = p[0]; | |
for (n = nP; --n > 0; dst += nSize) | |
{ | |
nSize = (n + 1 < nP ? p[n + 1] : ix.ixCode) - p[n]; | |
memmove(&cd.pCode[dst], &cd.pCode[mv + p[n]], nSize*sizeof(INSTRUCT)); | |
} | |
} | |
outCode2(call, pName->idName); | |
if ((pName->type&NM_CDECL) && depth > 0) | |
outCode2(add_esp, depth); | |
setValue(VAL, pName->ptrs, pName->dataType, pv); | |
} | |
void sizeOf(VALUE *pv) | |
{ | |
int cnt = 0, pointers = 0; | |
ix.tix++; | |
while (ispp('(')) cnt++; | |
int id = cd.token[ix.tix++].ival; | |
while (ispp('*')) pointers++; | |
int size = pointers > 0 ? 4 : sizeOfDataType(id); | |
if (size == 0) | |
{ | |
Name *pName = getNameFromAllTable(cd.currTable, NM_VAR, id); | |
if (pName != NULL) size = pName->size[0]; | |
} | |
outCode2(mov_eax, size); | |
while (cnt-- > 0) skip(')'); | |
setValue(VAL, 0, ID.INT, pv); | |
pv->ival = size; | |
pv->fConst = TRUE; | |
} | |
/// Constant ::= Number | String | Character | |
void constant(VALUE *pv) | |
{ | |
switch (cd.token[ix.tix].type) | |
{ | |
case TK_STRING: | |
loadAddr(AD_DATA, ix.ixData); | |
ix.ixData += outString(ix.ixData, toString(cd.token[ix.tix++].ival)) + 1; | |
setValue(VAL, 1, ID.CHAR, pv); | |
break; | |
case TK_DOUBLE: | |
setValue(VAL, 0, ID.DOUBLE, pv); | |
pv->rval = cd.token[ix.tix++].dval; | |
pv->fConst = TRUE; | |
outDataDouble(pv->rval); // setreal 0.000 @100 | |
outCode3(fld_qp, ix.ixData - 8, AD_DATA); | |
break; | |
case TK_INT: | |
case TK_CHAR: | |
setValue(VAL, 0, ID.INT, pv); | |
pv->ival = cd.token[ix.tix++].ival; | |
pv->fConst = TRUE; | |
outCode2(mov_eax, pv->ival); | |
break; | |
default: | |
error("expr.constant", "type=%d\n", cd.token[ix.tix].type); | |
} | |
} | |
/// PrimExpression ::= Id | "(" Expression ")" | Constant | FunctionCall | |
int pot[] = { 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4 }; | |
void primExpr(int mode, VALUE *pv) | |
{ | |
Name *pName = NULL; | |
int ptrs, depth, type, size; | |
int fInc = 0, fArray = 0, fDot = 0, fArrow = 0, fDone = 0; | |
int hid = cd.token[ix.tix].ival; | |
if (ispp('(')) // "(" Expression ")" | |
{ | |
expression(mode, pv); // eax: Expression | |
skip(')'); // Id | "(" "(" Id "*" ")" Id ")" | |
if (!is2("->")) return; | |
ptrs = pv->ptrs; | |
type = pv->type; | |
fDone = 1; // outCode("mov eax,[eax]"); | |
} | |
else // NM_VAR|NM_CDECL|NM_WINAPI|NM_ENUM | |
{ | |
pName = getNameFromAllTable(cd.currTable, NM_VAR | NM_ENUM, hid); | |
if (pName == NULL) | |
pName = getNameFromTable(globTable, NM_FUNC, hid); | |
if (pName == NULL) | |
error("primExpr", "'%s' undeclared", toString(hid)); | |
ix.tix++; | |
if (pName->type == NM_ENUM) | |
{ | |
outCode2(mov_eax, pName->address); | |
setValue(VAL, 0, ID.INT, pv); | |
pv->ival = pName->address; | |
pv->fConst = TRUE; | |
return; | |
} | |
type = pName->dataType; | |
ptrs = pName->ptrs + getPtr(type); | |
if (pName->addrType == AD_CODE) | |
{ | |
loadAddr(AD_CODE, hid); | |
setValue(VAL, ptrs + 1, type, pv); | |
return; | |
} | |
loadAddr(pName->addrType, pName->addrType == AD_IMPORT ? hid : pName->address); | |
} | |
depth = 0; | |
while ((fArray = ispp('[')) || (fDot = ispp('.')) || (fArrow = is2pp("->"))) | |
{ | |
if (fArray) | |
{ | |
ptrs--; | |
size = pName->size[++depth]; | |
if (size == 0) size = ptrs > 0 ? 4 : sizeOfDataType(pName->dataType); | |
if (pName->size[depth] == 0) | |
{ | |
int *pI = &cd.pCode[ix.ixCode - 1].inst; | |
if (*pI == lea_eax_pbp) *pI = mov_eax_pbp; | |
else outCode1(mov_eax_pax); | |
} | |
int ixAddr = ix.ixCode - 1; | |
outCode1(push_eax); | |
int bgn = ix.ixCode; | |
expression(VAL, pv); | |
skip(']'); | |
if (pv->fConst) | |
{ | |
ix.ixCode = bgn - 1; | |
outCode2(add_eax, pv->ival*size); | |
continue; | |
} | |
int fLocVar = ix.ixCode == bgn + 1 && cd.pCode[ix.ixCode - 1].inst == mov_eax_pbp; | |
if (fLocVar) | |
{ | |
delCode(bgn - 1); | |
cd.pCode[ix.ixCode - 1].inst = mov_edx_pbp; | |
if (size == 1 || (size <= 8 && pot[size] > 0)) | |
{ | |
outCode1(lea_eax_ad1 + pot[size]); | |
} | |
else | |
{ | |
if (size > 1) outCode2(imul_edx_edx, size); | |
outCode1(add_eax_edx); | |
} | |
} | |
else | |
{ | |
if (cd.pCode[ixAddr].inst == mov_eax_pbp) | |
{ | |
outCode3(mov_edx_pbp, cd.pCode[ixAddr].num, cd.pCode[ixAddr].attr); | |
delCodes(ixAddr, ixAddr + 2); | |
} | |
else | |
{ | |
outCode1(pop_edx); | |
} | |
if (size == 1 || (size <= 8 && pot[size] > 0)) | |
{ | |
outCode1(lea_eax_da1 + pot[size]); | |
} | |
else | |
{ | |
if (size > 1) outCode2(imul_eax_eax, size); | |
outCode1(add_eax_edx); | |
} | |
} | |
} | |
else // ("." | "->") Identifier | |
{ | |
int id = cd.token[ix.tix++].ival; | |
pName = getAttr(type, id); | |
if (pName == NULL) | |
error("prim", "'%s' not struct member", toString(id)); | |
if (!fDone && fArrow) outCode1(mov_eax_pax); | |
fDone = 0; | |
fArrow = 0; | |
ptrs = pName->ptrs; | |
type = pName->dataType; | |
depth = 0; | |
outCode2(add_eax, pName->address); | |
} | |
} | |
if (((fInc = is2pp("++")) || is2pp("--")) && mode == VAL) | |
{ | |
outCode1(mov_edx_eax); | |
loadValue(type, ptrs > 0); | |
incdec(type, ptrs > 0, fInc, 'd'); | |
int k = ix.ixCode - 1; | |
int inst = cd.pCode[k].inst; | |
if (cd.pCode[k - 3].inst == lea_eax_pbp && cd.pCode[k - 2].inst == mov_edx_eax | |
&& cd.pCode[k - 1].inst == mov_eax_pax && cd.pCode[k].num == 1 | |
&& (inst == add_ddx || inst == sub_ddx)) | |
{ | |
cd.pCode[k - 3].inst = mov_eax_pbp; | |
cd.pCode[k - 2] = cd.pCode[k - 3]; | |
cd.pCode[k - 2].inst = inst == add_ddx ? inc_dbp : dec_dbp; | |
ix.ixCode -= 2; | |
} | |
} | |
else if (pName->size[depth + 1] == 0 && mode == VAL) | |
{ | |
loadValue(type, ptrs > 0); | |
} | |
setValue(mode, ptrs, type, pv); | |
} | |
void primaryExpression(int mode, VALUE *pv) | |
{ | |
if (cd.token[ix.tix].type >= TK_STRING) | |
{ | |
constant(pv); | |
} | |
else if (is(ID.SIZEOF)) | |
{ | |
sizeOf(pv); | |
} | |
else if (!is('(') && isN('(', 1)) | |
{ | |
functionCall(pv); | |
if (pv->type == ID.DOUBLE) | |
outCode1(fstp_st1); | |
} | |
else | |
{ | |
primExpr(mode, pv); | |
} | |
} | |
void initDLL(char *dllnames) | |
{ | |
int i, n; | |
char *dllname = strtok(dllnames, ";"); | |
for (n = 0; dllname != NULL; dllname = strtok(NULL, ";")) | |
{ | |
ULONG hM = (ULONG)LoadLibrary(dllname); | |
if (hM == 0) error("exe.initDLL", "DLL '%s' Æ’ÂÂ[Æ’hÆ’Gƒ‰Â[", dllname); | |
IMAGE_DOS_HEADER *pDOSHeader = (IMAGE_DOS_HEADER *)hM; | |
IMAGE_NT_HEADERS *pPEHeader = (IMAGE_NT_HEADERS *)(hM + pDOSHeader->e_lfanew); | |
IMAGE_DATA_DIRECTORY *pD = pPEHeader->OptionalHeader.DataDirectory; | |
IMAGE_EXPORT_DIRECTORY *pE = (IMAGE_EXPORT_DIRECTORY*)(hM + pD[0].VirtualAddress); | |
char **ppszFunctionName = (char**)((int)pE->AddressOfNames + hM); | |
for (i = 0; i < pE->NumberOfNames; i++) | |
{ | |
char *name = (char*)(ppszFunctionName[i] + hM); | |
int ix = put(strncmp(name, "__p_", 4) == 0 ? (name + 4) : name, NULL, &cd.hash); | |
cd.hash.tbl[ix].val = (void*)(AT_IMPT | n); | |
} | |
FreeLibrary((HMODULE)hM); | |
exe.dll[n++].dllname = dllname; | |
} | |
exe.nDLL = n; | |
} | |
int importDLL() | |
{ | |
int k, n, size = 0; | |
for (n = 0; n < exe.nDLL; n++) | |
{ | |
if (exe.dll[n].nFunc == 0) continue; | |
size += strlen(exe.dll[n].dllname) + 1; | |
exe.useDLL++; | |
for (k = 0; k < exe.dll[n].nFunc; k++) | |
size += strlen(toString(exe.dll[n].idFunc[k])) + 3; | |
exe.useFunc += exe.dll[n].nFunc; | |
} | |
size += exe.useDLL * 20 + 20; | |
size += (exe.useFunc + exe.useDLL) * 4 * 2; | |
size = ((size - 1) / 16 + 1) * 16; | |
return size; | |
} | |
BYTE *getImport() | |
{ | |
int i, n = 0, k; | |
DWORD *pImpt = calloc(exe.lenImpt, 1); | |
if (pImpt == NULL) error("exe.getImport", "Error to import function"); | |
int nLookup = (exe.useDLL + 1) * 5; | |
int nImptAddr = nLookup + (exe.useDLL + exe.useFunc); | |
int nName = (nImptAddr + (exe.useDLL + exe.useFunc)) * 4; | |
for (i = 0; i < exe.nDLL; i++) | |
{ | |
if (exe.dll[i].nFunc == 0) continue; | |
pImpt[n * 5] = mem.ImptAddr + nLookup * 4; | |
pImpt[n * 5 + 4] = mem.ImptAddr + nImptAddr * 4; | |
for (k = 0; k < exe.dll[i].nFunc; k++) | |
{ | |
int ix = exe.dll[i].idFunc[k]; | |
char *fname = toString(ix); | |
cd.hash.tbl[ix].val = (void*)(AT_IMPT | (pImpt[n * 5 + 4] + k * 4)); | |
pImpt[nLookup++] = mem.ImptAddr + nName; | |
pImpt[nImptAddr++] = mem.ImptAddr + nName; | |
strcpy((char*)pImpt + nName + 2, fname); | |
nName += strlen(fname) + 3; | |
} | |
nLookup++; | |
nImptAddr++; | |
pImpt[n * 5 + 3] = mem.ImptAddr + nName; | |
strcpy((char*)pImpt + nName, exe.dll[i].dllname); | |
nName += strlen(exe.dll[i].dllname) + 1; | |
n++; | |
} | |
return (BYTE*)pImpt; | |
} | |
typedef struct _Export | |
{ | |
int addr; | |
char *name; | |
} Export; | |
Export export[100]; | |
int nExport; | |
int cmpName(const void *a, const void *b) | |
{ | |
return strcmp(((Export *)a)->name, ((Export *)b)->name); | |
} | |
int cmpAddr(const void *a, const void *b) | |
{ | |
return *((int *)a) - *((int *)b); | |
} | |
int initExport() | |
{ | |
int n; | |
int size = strlen(cmd.outfile) + 1; | |
for (n = 0; n < cd.hash.size; n++) | |
{ | |
char *name = cd.hash.tbl[n].key; | |
int val = (int)cd.hash.tbl[n].val; | |
if (name != NULL && (val&AT_EXPT) != 0) | |
{ | |
export[nExport].addr = mem.CodeAddr + (val&AT_ADDR); | |
export[nExport++].name = name; | |
size += 10 + strlen(name) + 1; | |
} | |
} | |
qsort(export, nExport, sizeof(Export), cmpName); | |
return sizeof(IMAGE_EXPORT_DIRECTORY) + size; | |
} | |
BYTE *getExport() | |
{ | |
int n; | |
int sizeIED = sizeof(IMAGE_EXPORT_DIRECTORY); | |
int baseMem = mem.ExptAddr; | |
int baseRVA = baseMem + sizeIED; | |
char *buf = xalloc(exe.lenExpt); | |
IMAGE_EXPORT_DIRECTORY *pIed = (IMAGE_EXPORT_DIRECTORY *)buf; | |
IMAGE_EXPORT_DIRECTORY ied = | |
{ | |
0, 0, 0, 0, baseRVA + 10 * nExport, | |
1, nExport, nExport, baseRVA, baseRVA + 4 * nExport, baseRVA + 8 * nExport | |
}; | |
memcpy(buf, &ied, sizeof(ied)); | |
DWORD *pAddr = (DWORD*)(buf + sizeIED); | |
DWORD *pName = (DWORD*)(buf + sizeIED + 4 * nExport); | |
WORD *pOrd = (WORD*)(buf + sizeIED + 8 * nExport); | |
char *pStr = buf + sizeIED + 10 * nExport; | |
for (n = 0; n < nExport; n++) | |
pAddr[n] = export[n].addr; | |
strcpy(pStr, cmd.outfile); | |
pStr += strlen(cmd.outfile) + 1; | |
for (n = 0; n < nExport; n++) | |
{ | |
pName[n] = baseMem + (pStr - buf); | |
strcpy(pStr, export[n].name); | |
pStr += strlen(export[n].name) + 1; | |
pOrd[n] = n; | |
} | |
return (BYTE*)buf; | |
} | |
void initReloc() | |
{ | |
int n; | |
qsort(exe.locs, exe.nLocs, sizeof(int), cmpAddr); | |
exe.nPages = exe.nLocs > 0 ? (exe.locs[exe.nLocs - 1] - 1) / 4096 : 0; | |
for (n = 0; n < exe.nLocs; n++) | |
exe.cnt[exe.locs[n] / 4096 - 1]++; | |
mem.RelocAddr = mem.DataAddr + (mem.DataSize + MEMALIGN1) & ~MEMALIGN1; | |
mem.RelocSize = exe.nPages * 8 + exe.nLocs * 2; | |
raw.RelocAddr = raw.DataAddr + raw.DataSize; | |
raw.RelocSize = (mem.RelocSize + RAWALIGN1) & ~RAWALIGN1; | |
} | |
BYTE *getReloc() | |
{ | |
int n, k, ix = 0; | |
BYTE *buf = xalloc(raw.RelocSize); | |
WORD *p = (WORD*)buf; | |
for (n = 0; n < exe.nPages; n++) | |
{ | |
int *q = (int*)p; | |
*q++ = (n + 1) * 4096; // addr | |
*q++ = 8 + exe.cnt[n] * 2; // size | |
p = (WORD*)q; | |
for (k = 0; k < exe.cnt[n]; k++) | |
*p++ = 0x3000 + (exe.locs[ix++] & 0x0FFF); | |
} | |
return buf; | |
} | |
typedef struct _EXE_HEADER | |
{ | |
IMAGE_DOS_HEADER DosHeader; | |
BYTE DosStub[64]; | |
DWORD Signature; // "PE\0\0" | |
IMAGE_FILE_HEADER FileHeader; | |
IMAGE_OPTIONAL_HEADER OptionalHeader; | |
IMAGE_SECTION_HEADER SectionHeaders[2]; | |
} EXE_HEADER; | |
void writeExe(BYTE *bufImport, BYTE *bufExport, BYTE *CodeBuffer, | |
int lenCode, BYTE *DataBuffer, int lenData) | |
{ | |
BYTE *bufReloc = NULL; | |
int sizeImptAddrTable = (exe.useDLL + exe.useFunc) * 4; | |
int posImptAddrTable = mem.DataAddr + (exe.useDLL + 1) * 20 + sizeImptAddrTable; | |
int numSections = mcc.typeApp == 0 ? 3 : 2; // dll: 3 exe: 2 | |
int typeApp = mcc.typeApp == 0 ? 2 : mcc.typeApp; | |
int exptAddr = mcc.typeApp == 0 ? mem.ExptAddr : 0; | |
EXE_HEADER exeHeader = | |
{ | |
{ | |
// IMAGE_DOS_HEADER | |
0x5A4D, 0x90, 3, 0, 4, // "MZ", ... | |
0, 0xFFFF, 0, 0xB8, // min-, maxalloc, ss, sp | |
0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0x0080, | |
}, | |
"\x0E\x1F\xBA\x0E\x00\xB4\x09\xCD\x21\xB8\x01\x4C\xCD\x21" | |
"This program cannot be run in DOS mode.\r\r\n$", // DosStub | |
0x00004550, // "PE\0\0" | |
{ | |
// IMAGE_FILE_HEADER; | |
0x014c, numSections, 0, 0, 0, // Intel 386 | |
sizeof(IMAGE_OPTIONAL_HEADER), 0x030F // 0x00E0, Characteristics | |
}, { // IMAGE_OPTIONAL_HEADER | |
0x010B, 0x06, 0x00, // Magic, Linker Version | |
0, 0, 0, exe.entryPoint, // AddressOfEntryPoint | |
mem.CodeAddr, mem.DataAddr, // Base of Code, Data. | |
exe.base, MEMALIGN, RAWALIGN, // ImageBase, Section-, File-Alignment | |
4, 0, 0, 0, 4, 0, 0, // OS, Image, Subsystem Version | |
exe.sizeImage, RAWALIGN, 0, // Image size, Header size, ... | |
typeApp, 0, // 2/3: gui/console, DllCharacteristics | |
0x100000, 0x1000, 0x100000, 0x1000, // stack & heap reserve, commit | |
0, 0x10, | |
{ { exptAddr, exe.lenExpt }, { mem.ImptAddr, (exe.useDLL + 1) * 20 }, // 0,1 | |
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, | |
{ posImptAddrTable, sizeImptAddrTable }, { 0, 0 }, { 0, 0 }, { 0, 0 } | |
} // 12 | |
}, { { | |
".text", { mem.CodeSize }, mem.CodeAddr, raw.CodeSize, | |
raw.CodeAddr, 0, 0, 0, 0, 0x60000020 // Code | Executable | Readable | |
}, { | |
".data", { mem.DataSize }, mem.DataAddr, raw.DataSize, | |
raw.DataAddr, 0, 0, 0, 0, 0xC0000040 // InitializedData|Readable|Writeable | |
} | |
} | |
}; | |
IMAGE_SECTION_HEADER reloc = // 0x1C8-0x1EF | |
{ | |
".reloc", { mem.RelocSize }, mem.RelocAddr, raw.RelocSize, raw.RelocAddr, | |
0, 0, 0, 0, 0x42000040 // Initialized Data | Discardable | Readable | |
}; | |
BYTE *bufEXE = xalloc(raw.DataAddr + raw.DataSize); | |
memcpy(bufEXE, &exeHeader, sizeof(exeHeader)); | |
if (mcc.typeApp == 0) | |
{ | |
memcpy(bufEXE + sizeof(exeHeader), &reloc, sizeof(reloc)); | |
bufReloc = getReloc(); | |
} | |
memcpy(bufEXE + RAWALIGN, CodeBuffer, lenCode); | |
memcpy(bufEXE + raw.ImptAddr, bufImport, exe.lenImpt); | |
if (bufExport != NULL) | |
memcpy(bufEXE + raw.ImptAddr + exe.lenImpt, bufExport, exe.lenExpt); | |
memcpy(bufEXE + raw.ImptAddr + exe.lenImpt + exe.lenExpt, DataBuffer, lenData); | |
FILE *fpDst = fopen(cmd.outfile, "wb"); | |
if (fpDst == NULL) error("writeExe", "'%s' open error", cmd.outfile); | |
fwrite(bufEXE, raw.DataAddr + raw.DataSize, 1, fpDst); | |
if (bufReloc != NULL) fwrite(bufReloc, raw.RelocSize, 1, fpDst); | |
fclose(fpDst); | |
} | |
void setDLL(int ixDLL, int id) | |
{ | |
int n = 0; | |
while (n < exe.dll[ixDLL].nFunc && exe.dll[ixDLL].idFunc[n] != id) | |
n++; | |
if (n >= exe.dll[ixDLL].nFunc) | |
{ | |
exe.dll[ixDLL].nFunc++; | |
exe.dll[ixDLL].idFunc[n] = id; | |
} | |
} | |
void instAt(int n, int *pinst, int *pnum, int *pattr, int *psize) | |
{ | |
*pinst = cd.pCode[n].inst; | |
*pnum = cd.pCode[n].num; | |
*pattr = cd.pCode[n].attr; | |
*psize = cd.pCode[n].size; | |
} | |
int setOffset(int *pLoc, int *pOffCode, int cnt) | |
{ | |
int n, inst, num, attr, size, nChg = 0; | |
int offCode = 0; | |
for (n = 0; n < ix.ixCode; n++) | |
{ | |
instAt(n, &inst, &num, &attr, &size); | |
INSTRUCTION *pI = &instruction[inst - 1]; | |
char *fmt = pI->mnemonic; | |
if ((opt&oASM) && cnt == 0) | |
{ | |
printf((strchr(fmt, ':') != NULL ? "%4d: " : "%4d: "), n); | |
if (inst == setreal) | |
printf(fmt, cd.pCode[n].dval, cd.pCode[n].offset); | |
else if (inst == setstr) | |
printf(fmt, cd.pCode[n].sval, cd.pCode[n].offset); | |
else | |
printf(fmt, num, cd.pCode[n].offset); | |
if (fmt[0] == 'j') printf(attr == AD_CONST ? "%d" : "loc_%03d", num); | |
else if (inst == xret && num > 0) printf(" %d", num); | |
else if (attr != 0) printf("[%d]", attr); | |
if (pI->opcode == fn_ || pI->opcode == call) | |
printf("[%s]", cd.hash.tbl[num].key); | |
printf("\n"); | |
} | |
if (setint <= inst && inst <= setstr) continue; | |
if (cnt == 0) cd.pCode[n].size = 0; // default | |
cd.pCode[n].offset = offCode; | |
if (pI->opcode == loc_ && num <= ix.ixLoc) | |
{ | |
pLoc[num] = offCode; | |
} | |
else if (pI->opcode == fn_ || pI->opcode == exp_) | |
{ | |
if (strcmp(cd.hash.tbl[num].key, "_main") == 0) | |
exe.entryPoint = offCode; | |
int at = ((int)cd.hash.tbl[num].val) & 0xFF000000; | |
cd.hash.tbl[num].val = (void*)(at + offCode); | |
} | |
else if (pI->mnemonic[0] == 'j') | |
{ | |
int fByte = abs(pLoc[num] - offCode - 2) < 128; | |
int fS = (opt&oUOPT) ? (pLoc[num] > 0 && fByte) : (cnt == 0 || fByte); | |
fS = (fS || attr == AD_CONST); | |
offCode += strlen(fS ? pI->hexcode2 : pI->hexcode) / 2 + (fS ? 1 : 4); | |
int sizeOld = cd.pCode[n].size; | |
cd.pCode[n].size = fS ? 1 : 4; | |
if (cd.pCode[n].size != sizeOld) nChg++; | |
} | |
else if (pI->opcode == call) | |
{ | |
int fImpt = ((int)cd.hash.tbl[num].val) & AT_IMPT; | |
offCode += fImpt ? 6 : 5; | |
if (fImpt && cnt == 0) setDLL((int)cd.hash.tbl[num].val & AT_ADDR, num); | |
} | |
else if (pI->opcode == xret) // C20400 ret 4 | |
{ | |
offCode += num == 0 ? 2 : 4; | |
cd.pCode[n].size = num == 0 ? 0 : 2; | |
} | |
else if (abs(num) < 128 && (pI->regs_size & 0x01) == 1) | |
{ | |
offCode += strlen(pI->hexcode2) / 2 + 1; | |
cd.pCode[n].size = 1; | |
} | |
else if (abs(num) < (1 << 15) && (pI->regs_size & 0x02) == 2) | |
{ | |
offCode += strlen(pI->hexcode2) / 2 + 2; | |
cd.pCode[n].size = 2; | |
} | |
else if (pI->hexcode != NULL && pI->hexcode[0] != '\0') | |
{ | |
offCode += strlen(pI->hexcode) / 2 + (pI->regs_size & 0x04); | |
cd.pCode[n].size = pI->regs_size & 0x04; | |
} | |
else | |
{ | |
error("linker", "mnemonic=%s, num=%d", pI->mnemonic, num); | |
} | |
if (cnt == 0 && attr == AD_IMPORT) | |
setDLL((int)cd.hash.tbl[num].val & AT_ADDR, num); | |
} | |
*pOffCode = offCode; | |
return nChg; | |
} | |
void link() | |
{ | |
int n, inst, num, attr, size, offset, offCode, cnt = 0, nChg; | |
char *p, *hexcode, *caText; | |
int *pLoc = xalloc((ix.ixLoc + 1) * sizeof(int)); | |
initDLL(cmd.impfiles); | |
do | |
{ | |
nChg = setOffset(pLoc, &offCode, cnt++); | |
} while (!(opt&oUOPT) && nChg > 0); | |
mem.CodeAddr = MEMALIGN; | |
mem.CodeSize = offCode; | |
raw.CodeAddr = RAWALIGN; | |
raw.CodeSize = (offCode + RAWALIGN1) & ~RAWALIGN1; | |
exe.lenImpt = importDLL(); | |
exe.lenExpt = (opt&oDLL) ? initExport() : 0; | |
int posData = exe.lenImpt + exe.lenExpt; | |
mem.DataAddr = mem.CodeAddr + (offCode + MEMALIGN1) & ~MEMALIGN1; | |
mem.DataSize = exe.lenImpt + exe.lenExpt + ix.ixData + ix.ixZero; | |
raw.DataAddr = raw.CodeAddr + raw.CodeSize; | |
raw.DataSize = (exe.lenImpt + exe.lenExpt + ix.ixData + RAWALIGN1) & ~RAWALIGN1; | |
mem.ImptAddr = mem.DataAddr; | |
raw.ImptAddr = raw.DataAddr; | |
mem.ExptAddr = mem.ImptAddr + exe.lenImpt; | |
raw.ExptAddr = raw.ImptAddr + exe.lenImpt; | |
exe.base = (opt&oDLL) ? DLLBASE : IMAGEBASE; | |
exe.entryPoint += mem.CodeAddr; | |
BYTE *bufImport = getImport(); | |
BYTE *bufExport = (opt&oDLL) ? getExport() : NULL; | |
p = caText = xalloc(raw.CodeSize); | |
int dataAddr = exe.base + mem.DataAddr + posData; | |
for (n = 0; n < ix.ixCode; n++) | |
{ | |
BYTE *q; | |
instAt(n, &inst, &num, &attr, &size); | |
offset = cd.pCode[n].offset; | |
INSTRUCTION *pI = &instruction[inst - 1]; | |
hexcode = size == 1 ? pI->hexcode2 : pI->hexcode; | |
if (hexcode == NULL) continue; | |
int fReloc = TRUE; | |
if (pI->opcode == call) | |
{ | |
int fImpt = (int)cd.hash.tbl[num].val & AT_IMPT; // FF10:call dwdptr[eax] | |
int fUser = (int)cd.hash.tbl[num].val & AT_USER; | |
int addr = (int)cd.hash.tbl[num].val & AT_ADDR; | |
if (!fImpt && !fUser) error("linker", "'%s' undeclared", toString(num)); | |
num = fImpt ? (exe.base + addr) : (addr - cd.pCode[n + 1].offset); | |
hexcode = fImpt ? "FF15" : "E8"; | |
if (!fImpt) fReloc = FALSE; | |
size = 4; | |
} | |
else if (pI->mnemonic[0] == 'j') | |
{ | |
int sizeInst = size == 1 ? 2 : inst == jmp ? 5 : 6; | |
if (attr != AD_CONST) num = pLoc[num] - (cd.pCode[n].offset + sizeInst); | |
fReloc = FALSE; | |
} | |
else if (attr == AD_CODE) | |
{ | |
int foffset = (int)cd.hash.tbl[num].val & AT_ADDR; | |
num = exe.base + mem.CodeAddr + foffset; | |
} | |
else if (attr == AD_DATA) | |
{ | |
num += dataAddr; | |
} | |
else if (attr == AD_ZERO) | |
{ | |
num += dataAddr + ix.ixData; | |
} | |
else if (attr == AD_IMPORT) | |
{ | |
num = exe.base + ((int)cd.hash.tbl[num].val&AT_ADDR); | |
} | |
else | |
{ | |
fReloc = FALSE; | |
} | |
for (q = hexcode; *q != '\0'; q += 2) | |
*p++ = (htoi(*q) << 4) + htoi(q[1]); | |
if (size == 1) *p = num; | |
else if (size == 2) *((short*)p) = num; | |
else if (size == 4) *((int*)p) = num; | |
if (fReloc) exe.locs[exe.nLocs++] = num - exe.base; | |
p += size; | |
} | |
char *caData = calloc(ix.ixData + 1, sizeof(char)); | |
for (n = 0; n < ix.ixCode; n++) | |
{ | |
instAt(n, &inst, &num, &attr, &size); | |
offset = cd.pCode[n].offset; | |
if (inst < setint || setstr < inst) continue; | |
if (inst == setint && attr == 1) caData[offset] = num; | |
else if (inst == setint && attr == 2) *((short*)&caData[offset]) = num; | |
else if (inst == setint && attr == 4) *((int*)&caData[offset]) = num; | |
else if (inst == setint) *((int*)&caData[offset]) = num + dataAddr; | |
else if (inst == setreal) *((double*)&caData[offset]) = cd.pCode[n].dval; | |
else xstrcpy(&caData[offset], cd.pCode[n].sval); // setstr | |
} | |
if (opt&oDLL) | |
{ | |
initReloc(); | |
exe.sizeImage = mem.RelocAddr + (mem.RelocSize + MEMALIGN1) & ~MEMALIGN1; | |
} | |
else | |
{ | |
exe.sizeImage = mem.DataAddr + (mem.DataSize + MEMALIGN1) & ~MEMALIGN1; | |
} | |
writeExe(bufImport, bufExport, caText, offCode, caData, ix.ixData); | |
} | |
void printUsage() | |
{ | |
printf("%s", "Usage: cc [options] file...\n" | |
"Options:\n" | |
" -shared Generate a DLL file\n" | |
" -o <file> ÂSet output file name\n" | |
" -l<name> DLL <name>.dll ‚ link with a dll\n" | |
" -E Expression tree\n" | |
" -token Tokens list\n" | |
" -asm Generate ASM code\n" | |
" --lines ÂLine count\n"); | |
exit(0); | |
} | |
void main(int argc, char *argv[]) | |
{ | |
char *impfiles = "msvcrt.dll;kernel32.dll;user32.dll;gdi32.dll;"; | |
char *opts[] = { "-E", "-shared", "-token", "-asm", "--lines", "-trace", "-debug", "-name", "--opt" }; | |
int flags[] = { oSRC, oDLL, oTOKEN, oASM, oLINES, oTRACE, oDEBUG, oNAME, oUOPT, 0 }; | |
int k, n, len; | |
mcc.nPreFile = -1; | |
strcpy(cmd.impfiles, impfiles); | |
GetModuleFileName(NULL, cmd.MCCDIR, MAX_PATH); | |
if ((len = strlen(cmd.MCCDIR)) <= 12) | |
error("main", "ModulePath=%s", cmd.MCCDIR); | |
cmd.MCCDIR[len - 12] = '\0'; // <CC>\bin\mcc.exe | |
for (n = 1; n < argc; n++) | |
{ | |
for (k = 0; flags[k] > 0 && strcmp(argv[n], opts[k]) != 0; k++); | |
if (flags[k] > 0) opt |= flags[k]; | |
else if (strcmp(argv[n], "-o") == 0) strcpy(cmd.outfile, argv[++n]); | |
else if (strncmp(argv[n], "-l", 2) == 0) | |
sprintf(cmd.impfiles + strlen(cmd.impfiles), "%s.dll;", argv[n] + 2); | |
else if (argv[n][0] != '-') cmd.srcfile[cmd.nSrc++] = argv[n]; | |
else error("main", "invalid option -- '%s'", argv[n]); | |
} | |
if (argc == 1) printUsage(); | |
if (cmd.nSrc == 0) error("main", "No source files to build"); | |
opt |= oUOPT; | |
ix.tix = -1; | |
char path[MAX_PATH], *p, *q; | |
initHash('s', 1000, &mcc.hash); | |
initPrepro(); | |
for (n = 0; n < cmd.nSrc; n++) | |
{ | |
struct _finddata_t fdata; | |
int hFile = _findfirst((q = cmd.srcfile[n]), &fdata); | |
if (hFile == -1) error("mcc.main", "file '%s' not found", q); | |
if ((p = strrchr(q, '/')) == NULL) p = strrchr(q, '\\'); | |
do | |
{ | |
sprintf(path, "%.*s%s", p == NULL ? 0 : p - q + 1, q, fdata.name); | |
prepro(path); | |
} while (_findnext(hFile, &fdata) == 0); | |
} | |
mcc.nPreFile = -1; | |
addStartup(); | |
if (opt&oSRC) exit(0); | |
if (opt&oLINES) | |
{ | |
printf("%-24s\t%5d\n", " ‡ Œv ", mcc.totalLines); | |
exit(0); | |
} | |
if (cmd.outfile[0] == '\0') | |
{ | |
q = mcc.srcFile[mcc.mainfile]; | |
if ((p = strrchr(q, '/')) == NULL) p = strrchr(q, '\\'); | |
strcpy(cmd.outfile, p != NULL ? p + 1 : q); | |
p = strrchr(cmd.outfile, '.'); | |
strcpy(p, (opt&oDLL) ? ".dll" : ".exe"); | |
} | |
freeHash(&mcc.hash); | |
lex(); | |
initInstruction(); | |
initHash('x', HASHSIZE_TOKEN, &cd.hash); | |
parse(); | |
if (opt&oNAME) printNameTable(globTable); | |
link(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment