This C program interprets the Mouse language while dumping out the internal interpreter state after each line.
/* MOUSE - A Language for Microcomputers (interpreter) as described by Peter Grogono in July 1979 BYTE Magazine */ #include <stdio.h> enum tagtype { MACRO, PARAM, LOOP }; struct frame { enum tagtype tag; int pos, off; }; FILE *infile; char prog[5000]; int definitions[26]; int calstack[256], data[256], cal, chpos, level, offset, parnum, parbal, temp; struct frame stack[256]; char ch; int end; #define num(ch) (ch - 'A') #define val(ch) (ch - '0') #define nextchar() (ch = prog[chpos++]) void dumpline() { int p = chpos, l = 0, a = 0, i; char buf[256]; while (p >= 0 && prog[p] != '\n' && prog[p] != '\r') p--; p++; printf("\n###data "); for (i=0; i<13; i++) printf("%c=%d ",i+'A',data[i + offset]); printf("\n "); for (; i<26; i++) printf("%c=%d ",i+'A',data[i + offset]); printf("\n###stack "); if (cal > 0) { for (i=0; i<cal; i++) printf("%d ", calstack[i]); } else printf("<empty>"); printf("\n###"); do { printf("%c", prog[p]); if (p == chpos) a = l; p++; l++; } while (prog[p] != '\n' && prog[p] != '\r' && p < end); printf("\n###"); for (i=0; i<l; i++) if (i == a) printf("^"); else printf(" "); printf("?"); fgets(buf, 256, stdin); } void pushcal(int datum) { calstack[cal++] = datum; } int popcal() { return calstack[--cal]; } void push(enum tagtype tagval) { stack[level].tag = tagval; stack[level].pos = chpos; stack[level++].off = offset; } void pop() { chpos = stack[--level].pos; offset = stack[level].off; } void skip(char lch, char rch) { int cnt = 1; do { nextchar(); if (ch == lch) cnt++; else if (ch == rch) cnt--; } while (cnt != 0); } void load() { char this, last; int charnum; for (charnum = 0; charnum < 26; charnum++) definitions[charnum] = 0; charnum = 0; this = ' '; do { last = this; this = fgetc(infile); if (this == '\'') { do { this = fgetc(infile); } while (this != '\n'); prog[charnum++] = this; } else { prog[charnum] = this; if (this >= 'A' && this <= 'Z' && last == '$') { definitions[num(this)] = charnum + 1; printf("defined $%c\n", this); } charnum++; } } while (this != '$' || last != '$'); end = charnum; } void main(int argc, char *argv[]) { if (argc < 2) infile = stdin; else { infile = fopen(argv[1], "r"); if (infile == NULL) { puts("Error: cannot load program file\n"); return; } } load(); if (infile != stdin) fclose(infile); chpos = level = offset = cal = 0; do { if (!strchr("\n\t\r ", ch)) dumpline(); nextchar(); switch (ch) { case ' ': case ']': case '$': break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': temp = 0; while (ch >= '0' && ch <= '9') { temp = 10 * temp + val(ch); nextchar(); } pushcal(temp); chpos--; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': pushcal(num(ch) + offset); break; case '?': scanf("%d", &temp); pushcal(temp); break; case '!': printf("%d", popcal()); fflush(stdout); break; case '+': pushcal(popcal() + popcal()); break; case '-': pushcal(popcal() - popcal()); break; case '*': pushcal(popcal() * popcal()); break; case '/': pushcal(popcal() / popcal()); break; case '.': pushcal(data[popcal()]); break; case '=': temp = popcal(); data[popcal()] = temp; break; case '"': do { nextchar(); if (ch == '!') putchar('\n'); else if (ch != '"') putchar(ch); } while (ch != '"'); break; case '[': if (popcal() <= 0) skip('[', ']'); break; case '(': push(LOOP); break; case '^': if (popcal() <= 0) { pop(); skip('(', ')'); } break; case ')': chpos = stack[level - 1].pos; break; case '#': nextchar(); if (definitions[num(ch)] > 0) { push(MACRO); chpos = definitions[num(ch)]; offset += 26; } else skip('#', ';'); break; case '@': case '}': pop(); skip('#', ';'); break; case '%': nextchar(); parnum = num(ch); push(PARAM); parbal = 1; temp = level - 1; do { temp--; switch (stack[temp].tag) { case MACRO: parbal--; break; case PARAM: parbal--; break; case LOOP: break; } } while (parbal != 0); chpos = stack[temp].pos; offset = stack[temp].off; do { if (!strchr("\n\t\r ", ch)) dumpline(); nextchar(); if (ch == '#') { skip('#', ';'); if (!strchr("\n\t\r ", ch)) dumpline(); nextchar(); } if (ch == ',') parnum--; } while (parnum >= 0 && ch != ';'); if (ch == ';') pop(); break; case ',': case ';': pop(); break; } } while (ch != '$'); }