Mouse Programming Language Compiler in C

This C program translates Mouse into C.

/*

    MOUSE - A Language for Microcomputers (compiler)
    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 nprocparms[26];
int calstack[256], data[256], cal, chpos, level, offset, parnum, parbal, temp;
struct frame stack[256];
int nparms, lineno = 1;
char procname;
char ch;

#define num(ch) (ch - 'A')
#define val(ch) (ch - '0')
#define nextchar() (ch = prog[chpos++])

void load() {
    char this, last;
    int charnum;
    for (charnum = 0; charnum < 26; charnum++)
    {
       definitions[charnum] = 0;
       nprocparms[charnum] = 0;
    }
    charnum = 0;
    this = ' ';
    do {
       last = this;
       this = fgetc(infile);
       if (this == '\'') {
          do {
             this = fgetc(infile);
          } while (this != '\n');
       }
       else {
          prog[charnum] = this;
          if (this >= 'A' && this <= 'Z' && last == '$')
             definitions[num(this)] = charnum;
          charnum++;
       }
    } while (this != '$' || last != '$');
}

void main(int argc, char *argv[]) {
    int i, j;
    if (argc >= 0)
    {
       if (argc != 2) infile = stdin;
       else {
          infile = fopen(argv[1], "r");
          if (infile == NULL) {
             puts("Error: cannot load program file\n");
             return;
          }
       }
       printf("#line 1\n");
       printf("#include <stdio.h>\n");
       printf("int sp = 0;\n");
       printf("int stack[1024];\n");
       printf("void push(i) {stack[sp++] = i;}\n");
       printf("int pop() {return stack[--sp];}\n");
       printf("void main()\n");
       printf("{\n");
       printf("int data[256];\n");
       printf("int temp;\n");
       load();
       if (infile != stdin) fclose(infile);
       chpos = level = offset = cal = 0;
    }
    do {
       nextchar();
       switch (ch) {
       case '\n':
          lineno++;
          printf("#line %d\n", lineno);
          break;
       case ']': printf("}\n"); break;
       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();
          }
          printf("push(%d);\n", 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':
          printf("push(%d);\n", num(ch));
          break;
       case '?':
          printf("scanf(\"%%d\", &temp);\n");
          printf("push(temp);\n");
          break;
       case '!':
          printf("printf(\"%%d\", pop());\n");
          printf("fflush(stdout);\n");
          break;
       case '+':
          printf("push(pop() + pop());\n");
          break;
       case '-':
          printf("push(pop() - pop());\n");
          break;
       case '*':
          printf("push(pop() * pop());\n");
          break;
       case '/':
          printf("push(pop() / pop());\n");
          break;
       case '.':
          printf("push(data[pop()]);\n");
          break;
       case '=':
          printf("temp = pop();\n");
          printf("data[pop()] = temp;\n");
          break;
       case '"':
          printf("printf(\"");
          do {
             nextchar();
             if (ch == '!') printf("\\n");
             else if (ch == '\\') printf("\\\\");
             else if (ch != '\"') printf("%c", ch);
          } while (ch != '\"');
          printf("\");\n");
          break;
       case '[':
          printf("if (pop() > 0) {\n");
          break;
       case '(':
          printf("while (1) {\n");
          break;
       case '^':
          printf("if (pop() <= 0) break;\n");
          break;
       case ')':
          printf("}\n");
          break;
       case '#':
          nparms = 0;
          nextchar();
          procname = ch;
          main(-1, 0);
          printf("proc%c(", procname);
          nprocparms[procname - 'A'] = nparms;
          for (i=0; i<nparms; i++)
          {
             printf("pop()");
             if (i < nparms - 1) printf(",");
          }
          printf(");\n");
          break;
       case '@':
          printf("return;\n");
          break;
       case '%':
          nextchar();
          printf("push(parm%c);\n", ch);
          break;
       case ';':
          return;
       case ',': /* pop(); */ nparms++; break;
       }
    } while (ch != '$');
    printf("}\n");
    if (argc != -1)
    {
       for (i=0; i<26; i++)
       {
          if (definitions[i])
          {
             printf("int proc%c(", i + 'A');
             for (j=0; j<nprocparms[i]; j++)
             {
                printf("int parm%c", 
                   nprocparms[i] - j + 'A' - 1);
                if (j < nprocparms[i] - 1)
                   printf(",");
             }
             printf(") {\n");
             printf("int data[26];\n");
             printf("int temp;\n");
             chpos = definitions[i] + 1;
             main(-1, 0);
          }
       }
    }
}