/* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". * */ #include "ip_spec.h" #include #include #include #include #include #include /* This program reads the human readable interpreter specification and produces a efficient machine representation that can be translated by a C-compiler. */ #define NOTAB 600 /* The max no of interpreter specs */ #define ESCAP 256 struct opform intable[NOTAB]; struct opform *lastform = intable - 1; int nerror = 0; int atend = 0; int line = 1; int maxinsl = 0; extern char em_mnem[][4]; char esca[] = "escape"; #define ename(no) ((no)==ESCAP?esca:em_mnem[(no)]) extern char em_flag[]; /* Forward declarations */ static int readchar(void); static void pushback(int); static void readin(void); static char *ident(void); static int getmnem(char *); static void writeout(void); static void checkall(void); static void chkc(int, int, int); static void ckop(int, int, int, int); static int oplength(struct opform *); static void check(int); static int decflag(char *); int compare(const void *, const void *); static void error(char *format, ...); static void mess(char *format, ...); static void fatal(char *format, ...); int main(int argc, char **argv) { if (argc > 1) { if (freopen(argv[1], "r", stdin) == NULL) { fatal("Cannot open %s", argv[1]); } } if (argc > 2) { if (freopen(argv[2], "w", stdout) == NULL) { fatal("Cannot create %s", argv[2]); } } if (argc > 3) { fatal("%s [ file [ file ] ]", argv[0]); } atend = 0; readin(); atend = 1; checkall(); if (nerror == 0) { writeout(); } exit(nerror); } static void readin(void) { register struct opform *nextform; char *firstid; register int maxl; maxl = 0; for (nextform = intable; !feof(stdin) && nextform < &intable[NOTAB];) { firstid = ident(); if (*firstid == '\n' || feof(stdin)) continue; lastform = nextform; nextform->i_opcode = getmnem(firstid); nextform->i_flag = decflag(ident()); switch (nextform->i_flag & OPTYPE) { case OPMINI: case OPSHORT: nextform->i_num = atoi(ident()); break; } nextform->i_low = atoi(ident()); if (*ident() != '\n') { int c; error("End of line expected"); while ((c = readchar()) != '\n' && c != EOF) ; } if (oplength(nextform) > maxl) maxl = oplength(nextform); nextform++; } if (!feof(stdin)) fatal("Internal table too small"); maxinsl = maxl; } static char *ident(void) { /* skip spaces and tabs, anything up to space,tab or eof is a identifier. Anything from # to end-of-line is an end-of-line. End-of-line is an identifier all by itself. */ static char array[200]; register int c; register char *cc; do { c = readchar(); } while (c == ' ' || c == '\t'); for (cc = array; cc < &array[(sizeof array) - 1]; cc++) { if (c == '#') { do { c = readchar(); } while (c != '\n' && c != EOF); } *cc = c; if (c == '\n' && cc == array) break; c = readchar(); if (c == '\n') { pushback(c); break; } if (c == ' ' || c == '\t' || c == EOF) break; } *++cc = 0; return array; } static int getmnem(char *str) { char (*ptr)[4]; for (ptr = em_mnem; *ptr <= &em_mnem[sp_lmnem - sp_fmnem][0]; ptr++) { if (strcmp(*ptr, str) == 0) return (ptr - em_mnem); } error("Illegal mnemonic"); return 0; } /* VARARGS1 */ static void error(char *format, ...) { va_list argptr; if (!atend) fprintf(stderr, "line %d: ", line); va_start(argptr, format); vfprintf(stderr, format, argptr); va_end(argptr); fprintf(stderr, "\n"); nerror++; } /* VARARGS1 */ static void mess(char *format, ...) { va_list argptr; if (!atend) fprintf(stderr, "line %d: ", line); va_start(argptr, format); vfprintf(stderr, format, argptr); va_end(argptr); fprintf(stderr, "\n"); } /* VARARGS1 */ static void fatal(char *format, ...) { va_list argptr; if (!atend) fprintf(stderr, "line %d: ", line); va_start(argptr, format); vfprintf(stderr, format, argptr); va_end(argptr); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } #define ILLGL -1 static void check(int val) { if (val != ILLGL) error("Illegal flag combination"); } static int decflag(char *str) { int type; int escape; int range; int wordm; int notzero; type = escape = range = wordm = notzero = ILLGL; while (*str) switch (*str++) { case 'm': check(type); type = OPMINI; break; case 's': check(type); type = OPSHORT; break; case '-': check(type); type = OPNO; break; case '1': check(type); type = OP8; break; case '2': check(type); type = OP16; break; case '4': check(type); type = OP32; break; case '8': check(type); type = OP64; break; case 'u': check(type); type = OP16U; break; case 'e': check(escape); escape = 0; break; case 'N': check(range); range = 2; break; case 'P': check(range); range = 1; break; case 'w': check(wordm); wordm = 0; break; case 'o': check(notzero); notzero = 0; break; default: error("Unknown flag"); } if (type == ILLGL) error("Type must be specified"); switch (type) { case OP64: case OP32: if (escape != ILLGL) error("Conflicting escapes"); escape = ILLGL; case OP16: case OP16U: case OP8: case OPSHORT: case OPNO: if (notzero != ILLGL) mess("Improbable OPNZ"); if (type == OPNO && range != ILLGL) { mess("No operand in range"); } } if (escape != ILLGL) type |= OPESC; if (wordm != ILLGL) type |= OPWORD; switch (range) { case ILLGL: type |= OP_BOTH; if (type == OPMINI || type == OPSHORT) error("Minies and shorties must have P or N"); break; case 1: type |= OP_POS; break; case 2: type |= OP_NEG; break; } if (notzero != ILLGL) type |= OPNZ; return type; } static void writeout(void) { register struct opform *next; int elem[sp_lmnem - sp_fmnem + 1 + 1]; /* for each op points to first of descr. */ register int i, currop; int nch; qsort(intable, (lastform - intable) + 1, sizeof intable[0], compare); printf("int\tmaxinsl\t= %d ;\n", maxinsl); currop = -1; nch = 0; printf("char opchoice[] = {\n"); for (next = intable; next <= lastform; next++) { if ((next->i_opcode & 0377) != currop) { for (currop++; currop < (next->i_opcode & 0377); currop++) { elem[currop] = nch; error("Missing opcode %s", em_mnem[currop]); } elem[currop] = nch; } printf("%d, %d,", next->i_flag & 0377, next->i_low & 0377); nch += 2; switch (next->i_flag & OPTYPE) { case OPMINI: case OPSHORT: printf("%d,", next->i_num & 0377); nch++; } printf("\n"); } for (currop++; currop <= sp_lmnem - sp_fmnem; currop++) { elem[currop] = nch; error("Missing opcode %s", em_mnem[currop]); } elem[sp_lmnem - sp_fmnem + 1] = nch; printf("0 } ;\n\nchar *opindex[] = {\n"); for (i = 0; i <= sp_lmnem - sp_fmnem + 1; i++) { printf(" &opchoice[%d], /* %d = %s */\n", elem[i], i, em_mnem[i]); } printf("} ;\n"); } int compare(const void *a1, const void *b1) { struct opform *a = (struct opform *)(a1); struct opform *b = (struct opform *)(b1); if (a->i_opcode != b->i_opcode) { return (a->i_opcode & 0377) - (b->i_opcode & 0377); } return oplength(a) - oplength(b); } static int oplength(struct opform *a) { int cnt; cnt = 1; if (a->i_flag & OPESC) cnt++; switch (a->i_flag & OPTYPE) { case OPNO: case OPMINI: break; case OP8: case OPSHORT: cnt++; break; case OP16U: case OP16: cnt += 2; break; case OP32: cnt += 5; break; case OP64: cnt += 9; break; } return cnt; } /* ----------- checking --------------*/ int ecodes[256], codes[256], lcodes[256]; #define NMNEM (sp_lmnem-sp_fmnem+1) #define MUST 1 #define MAY 2 #define FORB 3 char negc[NMNEM], zc[NMNEM], posc[NMNEM]; static void checkall(void) { register int i, flag; register struct opform *next; int opc, low; for (i = 0; i < NMNEM; i++) negc[i] = zc[i] = posc[i] = 0; for (i = 0; i < 256; i++) lcodes[i] = codes[i] = ecodes[i] = -1; codes[254] = codes[255] = ESCAP; atend = 0; line = 0; for (next = intable; next <= lastform; next++) { line++; flag = next->i_flag & 0377; opc = next->i_opcode & 0377; low = next->i_low & 0377; chkc(flag, low, opc); switch (flag & OPTYPE) { case OPNO: zc[opc]++; break; case OPMINI: case OPSHORT: for (i = 1; i < ((next->i_num) & 0377); i++) { chkc(flag, low + i, opc); } if (!(em_flag[opc] & PAR_G) && (flag & OPRANGE) == OP_BOTH) { mess("Mini's and shorties should have P or N"); } break; case OP8: error("OP8 is removed"); break; case OP16: if (flag & OP_NEG) negc[opc]++; else if (flag & OP_POS) posc[opc]++; break; case OP16U: case OP32: case OP64: break; default: error("Illegal type"); break; } } atend = 1; for (i = 0; i < 256; i++) if (codes[i] == -1) { mess("interpreter opcode %d not used", i); } for (opc = 0; opc < NMNEM; opc++) { switch (em_flag[opc] & EM_PAR) { case PAR_NO: ckop(opc, MUST, FORB, FORB); break; case PAR_C: case PAR_D: case PAR_F: case PAR_B: ckop(opc, FORB, MAY, MAY); break; case PAR_N: case PAR_G: case PAR_S: case PAR_Z: case PAR_O: case PAR_P: ckop(opc, FORB, MAY, FORB); break; case PAR_R: ckop(opc, FORB, MAY, FORB); break; case PAR_L: ckop(opc, FORB, MUST, MUST); break; case PAR_W: ckop(opc, MUST, MAY, FORB); break; default: error("Unknown instruction type of %s", ename(opc)); break; } } } static void chkc(int flag, int icode, int emc) { if (flag & OPESC) { if (ecodes[icode] != -1) { mess("Escaped opcode %d used by %s and %s", icode, ename(emc), ename(ecodes[icode])); } ecodes[icode] = emc; } else switch (flag & OPTYPE) { default: if (codes[icode] != -1) { mess("Opcode %d used by %s and %s", icode, ename(emc), ename(codes[icode])); } codes[icode] = emc; break; case OP32: case OP64: if (lcodes[icode] != -1) { mess("Long opcode %d used by %s and %s", icode, ename(emc), ename(codes[icode])); } lcodes[icode] = emc; break; } } static void ckop(int emc, int zf, int pf, int nf) { if (zc[emc] > 1) mess("More then one OPNO for %s", ename(emc)); if (posc[emc] > 1) mess("More then one OP16(pos) for %s", ename(emc)); if (negc[emc] > 1) mess("More then one OP16(neg) for %s", ename(emc)); switch (zf) { case MUST: if (zc[emc] == 0) mess("No OPNO for %s", ename(emc)); break; case FORB: if (zc[emc] == 1) mess("Forbidden OPNO for %s", ename(emc)); break; } switch (pf) { case MUST: if (posc[emc] == 0) mess("No OP16(pos) for %s", ename(emc)); break; case FORB: if (posc[emc] == 1) mess("Forbidden OP16(pos) for %s", ename(emc)); break; } switch (nf) { case MUST: if (negc[emc] == 0) mess("No OP16(neg) for %s", ename(emc)); break; case FORB: if (negc[emc] == 1) mess("Forbidden OP16(neg) for %s", ename(emc)); break; } } static int pushchar; static int pushf; static int readchar(void) { int c; if (pushf) { pushf = 0; c = pushchar; } else { if (feof(stdin)) return EOF; c = getc(stdin); } if (c == '\n') line++; return c; } static void pushback(int c) { if (pushf) { fatal("Double pushback"); } pushf++; pushchar = c; if (c == '\n') line--; }