#define GDBARG "test/4" #include #include #include #include #include #include #include /* WORK IN PROGRESS: trying to generate low-level C as an alternative to native code generation for icode. I'm actually programming right here in this web directory, so this file is quoite liable to be broken at any time you might look at it, and indeed I might be editing it *right now*. So by all means browse to see how development is coming along, but don't take copies until it is released. You'll know when that is, because it will start having version numbers attached. */ #ifndef FALSE #define TRUE (0==0) #define FALSE (0!=0) #endif static int debug_input = FALSE; static char *indent = " "; FILE *icode_file; FILE *source_file; int source_line = 0; #define MAX_LINE 1024 char line[MAX_LINE + 1]; static int nest_proc = 0; /* depth of procedure/begin blocks */ static int nest_loop = 0; /* depth of structured loops */ #define MAX_LINENOS 256 static int lineno[MAX_LINENOS]; /* init to 0 means not used */ static char linetype[MAX_LINENOS]; /* init to 0 means not used */ /* bitset of flags */ #define FORWARD_LABEL 1 #define BACKWARD_LABEL 2 #define USER_LABEL 4 static int next_lineno = 0; int get_next_lineno (void) { return ++next_lineno; } char *cond[256]; char *rcond[256]; /* This is primarily for the old-style (as described in the thesis) icode, with any 'unused' opcodes plugged in with the newer description from http://www.gtoal.com/athome/edinburgh/imp/imp77/icode.html Lower case text in the array below means 'new style'. There are also all the new opcodes >= 128 which I have not yet incorporated - the coding can be found by grepping for ^c\( in file http://www.gtoal.com/athome/edinburgh/acorn/3l/COMPILERS/bend/imp/pass2 I think some of the old-style opcodes were redefined in an incompatible way for the new style. So be careful. For now this is really just old-style only, which I hope is all that is ever generated by the Mouses Imp77 V8.4 compiler which ABD is porting. */ static char *icode_name[256] = { "<0>", "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>", "<10>", "<11>", "<12>", "<13>", "<14>", "<15>", "<16>", "<17>", "<18>", "<19>", "<20>", "<21>", "<22>", "<23>", "<24>", "<25>", "<26>", "<27>", "<28>", "<29>", "<30>", "<31>", /* SP ! " # $ % & ' ( ) * + , - . / */ "<32>", "OR", "JUMPIFD", "BNE", "DEF", "XOR", "AND", "PUSHS", "<'('>", "<')'>", "MUL", "ADD", "+ ", "SUB", "CONCAT", "QUOT", /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ "<'0'>", "<'1'>", "<'2'>", "<'3'>", "<'4'>", "<'5'>", "<'6'>", "<'7'>", "<'8'>", "<'9'>", "LOCATE", "END", "<'<'>", "<'='>", "<'>'>", "JUMPIF", /* @ A B C D E F G H I J K L M N O */ "PUSH", "INIT", "REPEAT", "JUMPIFA", "PUSHR", "CALL", "GOTO", "ALIAS", "BEGIN", "<'I'>", "JUMP", "FALSE", "LABEL", "MAP", "PUSHI", "LINE", /* P Q R S T U V W X Y Z [ \ ] ^ _ */ "PLANT", "DIVIDE", "RETURN", "ASSVAL", "TRUE", "NEGATE", "RESULT", "SJUMP", "IEXP", "DEFAULT", "ASSREF", "LSH", "NOT", "RSH", "PROC", "SLABEL", /* ` a b c d e f g h i j k l m n o */ "<'`'>", "ACCESS", "BOUNDS", "MCODE", "DIM", "EVENT", "FOR", "<'g'>", "ALTBEG", "INDEX", "JAM", "<'k'>", "LANG", "MONITOR", "SELECT", "ON", /* p q r s t u v w x y z { | } ~ DEL */ "ASSPAR", "ALTEND", "RESOLVE", "STOP", "<'t'>", "ADDA", "MOD", "SUBA", "REXP", "DIAG", "CONTROL", "START", "ALT", "FINISH", "pending", "<127>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", "<128-255>", }; int get_icode (FILE * f) { int c = fgetc (f); if (c != EOF) { if (debug_input) { if ('!' <= c && c <= '~') { fprintf (stdout, "%c:\n", c); } else { fprintf (stdout, "%d:\n", c); } } } return (c); } static char *getname (void) { /* A Hack */ static char local[256]; int c; char *s = local; for (;;) { c = get_icode (icode_file); assert (c != EOF); if ((isalpha (c) && isupper (c)) || isdigit (c)) { } else break; *s++ = c; } *s = '\0'; ungetc (c, icode_file); return (local); } static char *getwordconst (void) { static char local[12]; int i, c; int word = 0; for (i = 0; i < 4; i++) { word = word << 8 | (c = get_icode (icode_file)); assert (c != EOF); } sprintf (local, "0x%08x", word); return (local); } static char *getbyte (void) { static char local[4]; int c; c = get_icode (icode_file); assert (c != EOF); sprintf (local, "%02x", c & 255); return (local); } static char *getcond (void) { int c; c = get_icode (icode_file); assert (c != EOF); c &= 255; return (cond[c]); } static char *getrcond (void) { int c; c = get_icode (icode_file); assert (c != EOF); c &= 255; return (rcond[c]); } static char *getimpstring (void) { static char local[256 * 2 + 3]; int i, c, len; char *s = local; len = get_icode (icode_file); assert (c != EOF); *s++ = '"'; for (i = 0; i < len; i++) { c = get_icode (icode_file); assert (c != EOF); if (c == '"') { *s++ = '\\'; *s++ = c; } else if (c == '\n') { *s++ = '\\'; /* just for display purposes */ *s++ = 'n'; } else *s++ = c; } *s++ = '"'; *s++ = '\0'; return (local); } static char *getshort (short int *sh) { static char local[7]; int i, c; int word = 0; for (i = 0; i < 2; i++) { word = word << 8 | (c = get_icode (icode_file)); assert (c != EOF); } if (sh != NULL) *sh = word; sprintf (local, "0x%04x", word); return (local); } static char *getshortdecimal (int *d) { static char local[7]; int i, c; int word = 0; for (i = 0; i < 2; i++) { word = word << 8 | (c = get_icode (icode_file)); assert (c != EOF); } if (d != NULL) *d = word; sprintf (local, "%0d", word); return (local); } static char *getlab (int *d, int labtype) { static char local[7]; int i, c; int word = 0; for (i = 0; i < 2; i++) { word = word << 8 | (c = get_icode (icode_file)); assert (c != EOF); } if (!((word >= 0) && (word < MAX_LINENOS))) { fprintf(stdout, "\n*** word = %04x\n\n", word); exit(0); } if (lineno[word] == 0) { lineno[word] = get_next_lineno (); linetype[word] = labtype; /* flag JUMPIF followed by LOCATE */ } if (d != NULL) *d = word; sprintf (local, "L_%04x", lineno[word]); return (local); } static char *nextlab (int d, int labtype) { static char local[7]; assert (lineno[d] == 0); lineno[d] = get_next_lineno (); linetype[d] = labtype; /* flag JUMPIF followed by LOCATE */ sprintf (local, "L_%04x", lineno[d]); return (local); } static char *setlab (int *d, int labtype) { static char local[7]; int i, c; int word = 0; for (i = 0; i < 2; i++) { word = word << 8 | (c = get_icode (icode_file)); assert (c != EOF); } if (lineno[word] == 0) { /* This LOCATE comes before any type of jump */ /* Could either be start of a loop, or a user label */ lineno[word] = get_next_lineno (); linetype[word] = labtype; } else { linetype[word] = linetype[word] & labtype; } sprintf (local, "L_%04x", lineno[word]); /* If you have the LOCATE first, the REPEAT clears it. */ /* but if we have already had a JUMPIF then this LOCATE clears it */ if (linetype[word] == FORWARD_LABEL) { linetype[word] = 0; lineno[word] = 0; } if (d != NULL) *d = word; return (local); } static char *getvar (void) { static char local[7]; int i, c; int word = 0; for (i = 0; i < 2; i++) { word = word << 8 | (c = get_icode (icode_file)); assert (c != EOF); } sprintf (local, "V_%04x", word); return (local); } void c (char *s, ...) { va_list ap; char *buff; FILE *nullfile; int string_length; va_start (ap, s); nullfile = fopen ("/dev/null", "w"); if (nullfile == NULL) { fprintf (stderr, "Major error - cannot open /dev/null\n"); exit (1); } string_length = vfprintf (nullfile, s, ap); fclose (nullfile); buff = malloc (string_length + 1); vsprintf (buff, s, ap); va_end (ap); fprintf (stdout, "%s%s;\n", indent, buff); free (buff); } int main (int argc, char **argv) { char *p1, *p2, *p3, *p4, *p5; int opcode, d; char icode_filename[256], source_filename[256]; #ifdef GDBARG argc = 2; argv[1] = GDBARG; #endif if (argc >= 2 && strcmp (argv[1], "-d") == 0) { debug_input = TRUE; argc -= 1; argv += 1; } if (argc != 2) { fprintf (stderr, "syntax: idec basename\n"); exit (1); } sprintf (icode_filename, "%s.icode", argv[1]); icode_file = fopen (icode_filename, "rb"); if (icode_file == NULL) { fprintf (stderr, "idec: cannot open '%s' - %s\n", icode_filename, strerror (errno)); exit (2); } sprintf (source_filename, "%s.i", argv[1]); source_file = fopen (source_filename, "r"); if (source_file != NULL) { fprintf (stdout, "\n/* %s\n\n*/\n", "Edinburgh IMP77 Compiler - Version 8.4"); } for (d = 0; d < 255; d++) { cond[d] = "*ERROR*"; rcond[d] = "*ERROR*"; } for (d = 0; d < MAX_LINENOS; d++) { lineno[d] = 0; linetype[d] = 0; } cond['<'] = "<"; cond['('] = "<="; cond['='] = "=="; cond['#'] = "!="; cond['>'] = ">"; cond[')'] = ">="; rcond['<'] = ">="; rcond['('] = ">"; rcond['='] = "!="; rcond['#'] = "=="; rcond['>'] = "<="; rcond[')'] = "<"; for (;;) { opcode = get_icode (icode_file); if (opcode == EOF) break; switch (opcode) { case '\n': break; case '$': /* DEF TAG TEXT TYPE FORM SIZE SPEC PREFIX */ { char *stype; short int tf; int type, form; p1 = getvar (); p2 = getname (); assert (get_icode (icode_file) == ','); p3 = strdup (getshort (&tf)); assert (get_icode (icode_file) == ','); p4 = strdup (getshort (NULL)); assert (get_icode (icode_file) == ','); p5 = getshort (NULL); type = tf >> 4; form = tf & 15; #define MAXTYPE 4 if (type == 1) { c ("int %s", p1); break; } if (type == 3) { c ("char %s[%s]", p1, p4); break; } if (type == 0 && form == 7) { nest_proc += 1; fprintf (stdout, "void %s", p1); break; /* params from START/FINISH */ } { if ((1 <= type) && (type <= MAXTYPE)) switch (type) { case 1: stype = "integers"; break; case 2: stype = "reals"; break; case 3: stype = "strings"; break; case 4: stype = "records"; break; } else { stype = p3; } fprintf (stdout, "%s%s %s %s type/form=%s size=%s spec/prefix=%s\n", indent, icode_name[opcode], p1, p2, stype, p4, p5); break; free (p3); free (p4); } } break; case ',': fprintf (stdout, "?%s%s %s\n", /* TEMP HACK */ indent, icode_name[opcode], getshort (NULL)); break; case '?': /* JUMPIF cond label */ /* if you have the jumpif first then the LOCATE clears it. */ /* if you have the LOCATE first then the REPEAT clears it. */ p1 = getcond (); p2 = getlab (NULL, FORWARD_LABEL); c ("if (pop() %s pop()) goto %s", p1, p2); break; case '"': /* JUMPIFD cond label */ case 'C': /* JUMPIFA cond label */ p1 = getcond (); p2 = getlab (NULL, FORWARD_LABEL); fprintf (stdout, "%s%s %s %s\n", indent, icode_name[opcode], p1, p2); break; case '\'': /* PUSHS sconst */ fprintf (stdout, "%s%s %s\n", indent, icode_name[opcode], getimpstring ()); break; case 'D': /* PUSHR rconst */ fprintf (stdout, "%s/* TODO */ %s %s\n", indent, icode_name[opcode], getwordconst ()); break; case 'N': /* PUSHI iconst */ c ("push(%s)", getwordconst ()); break; case 'L': /* LABEL label - permanent, not wiped? */ fprintf (stdout, "%s:\n", setlab (NULL, USER_LABEL)); break; case ':': /* LOCATE label */ fprintf (stdout, "%s:\n", setlab (NULL, FORWARD_LABEL | BACKWARD_LABEL)); break; case 'B': /* REPEAT label */ p1 = getlab (&d, BACKWARD_LABEL); c ("goto %s /* end of for loop and others? */", p1); lineno[d] = 0; linetype[d] = 0; /* won't be used again */ break; case 'F': /* GOTO label */ c ("goto %s /* GOTO */", getlab (NULL, USER_LABEL)); break; case 'J': /* JUMP label */ c ("goto %s /* JUMP */", getlab (NULL, USER_LABEL /* Maybe??? */)); break; case 'f': /* FOR label (label was missing from thesis description) */ c ("for_initial[%d] = pop()", nest_loop); c ("for_final[%d] = pop()", nest_loop); c ("for_increment[%d] = pop()", nest_loop); c ("for_control[%d] = pop()", nest_loop); c ("*for_control[%d] = for_initial[%d]", nest_loop, nest_loop); p1 = getlab (&d, BACKWARD_LABEL /* maybe */); p2 = nextlab (d+1, FORWARD_LABEL); /* ASSUME EXIT LABEL IS IMPLICITLY NEXT LABEL */ c ("if (*for_control_nest_level == for_final[%d]) goto %s", nest_loop, p2); fprintf(stdout, "%s:\n", p1); c ("*for_control[%d] += for_increment[%d]", nest_loop, nest_loop); nest_loop += 1; break; case 'O': /* LINE decimal */ p1 = getshortdecimal (&d); fprintf (stdout, "#line %d\n", d + 1); /* output source file up to line %d */ if (source_file != NULL) { while (source_line < d + 1) { if (fgets (line, MAX_LINE, source_file) == NULL) break; source_line += 1; fprintf (stdout, "// %6d ", source_line); line[MAX_LINE] = '\0'; fputs (line, stdout); } } break; case '@': /* PUSH tag */ c ("push(&%s)", getvar ()); break; case '^': /* PROC tag */ case 'n': /* SELECT tag */ fprintf (stdout, "%s%s %s\n", indent, icode_name[opcode], getvar ()); break; case 'W': /* SJUMP sd */ case '_': /* SLABEL sd */ fprintf (stdout, "%s%s %s\n", indent, icode_name[opcode], getshortdecimal (NULL)); break; break; case 'd': /* DIM short,short */ p1 = strdup (getshort (NULL)); assert (get_icode (icode_file) == ','); p2 = getshort (NULL); fprintf (stdout, "%s%s %s %s\n", indent, icode_name[opcode], p1, p2); free (p1); break; case 'Y': /* DEFAULT short */ case 'A': /* INIT short */ fprintf (stdout, "%s%s %s\n", indent, icode_name[opcode], getshortdecimal (NULL)); break; case 'e': /* EVENT short */ case 'l': /* LANG short */ fprintf (stdout, "// %s%s %s\n", indent, icode_name[opcode], getshort (NULL)); break; case 'o': /* ON short label */ fprintf (stdout, "%s%s %s %s\n", indent, icode_name[opcode], getshort (NULL), getlab (NULL, FORWARD_LABEL)); break; case 'r': /* RESOLVE m */ fprintf (stdout, "%s/* TODO */ %s %s\n", indent, icode_name[opcode], getbyte ()); break; break; case '!': /* OR */ c ("push(pop() | pop())"); break; case '%': /* XOR */ c ("push(pop() ^ pop())"); break; case '&': /* AND */ c ("push(pop() & pop())"); break; case '*': /* MUL */ c ("push(pop() * pop())"); break; case '+': /* ADD */ c ("push(pop() + pop())"); break; case '-': /* SUB */ c ("push(p1 = pop(), pop() - p1)"); break; case '/': /* QUOT */ c ("push(p1 = pop(), pop() / p1)"); break; case 'Q': /* DIVIDE (reversed params) */ c ("push(pop() / pop())"); break; case '[': /* LSH */ c ("push(p1 = pop(), pop() << p1)"); break; case '\\': /* NOT */ c ("push(~pop()"); break; case ']': /* RSH */ c ("push(pop() >> pop())"); break; case 'X': /* IEXP */ c ("push(exp(pop(), pop()))"); break; case 'S': /* ASSVAL */ c ("p1 = pop(); *(int *)pop() = p1"); break; case 'a': /* ACCESS */ c ("push(pop()*4+pop())"); break; case 'm': /* MONITOR *//* Should really invoke imp diag routine */ c ("assert(FALSE)"); break; case 'H': /* BEGIN *//* Assume main program for now, fix later */ nest_proc += 1; fprintf (stdout, "int main(int argc, char **argv) {\n"); break; case ';': /* END */ nest_proc -= 1; if (nest_proc < 0) { break; /* or exit? - end of program */ } fprintf (stdout, "}\n"); break; case '{': /* START */ fprintf (stdout, "("); break; case '}': /* FINISH */ fprintf (stdout, ") {\n"); break; case 'E': /* CALL */ c ("*(pop())() /* this is where it all falls down... */"); break; case '#': /* BNE */ case '.': /* CONCAT */ case 'G': /* ALIAS */ case 'K': /* FALSE */ case 'M': /* MAP */ case 'P': /* PLANT */ case 'R': /* RETURN */ case 'T': /* TRUE */ case 'U': /* NEGATE */ case 'V': /* RESULT */ case 'Z': /* ASSREF */ case 'b': /* BOUNDS */ case 'c': /* MCODE */ case 'h': /* ALTBEG */ case 'i': /* INDEX */ case 'j': /* JAM */ case 'p': /* ASSPAR */ case 'q': /* ALTEND */ case 's': /* STOP */ case 'u': /* ADDA */ case 'v': /* MOD */ case 'w': /* SUBA */ case 'x': /* REXP */ case 'y': /* DIAG */ case 'z': /* CONTROL */ case '|': /* ALT */ fprintf (stdout, "%s%s\n", indent, icode_name[opcode]); break; default: fprintf (stdout, "?%s%s\n", indent, icode_name[opcode]); break; } } exit (0); return (0); }