/* * File: main.c * * Main file for IMP80 compiler * * Bob Eager August 2002 * */ #include "imp.h" #include "opcode.h" #include "global.h" #include "global2.h" #include "lput.h" #include "sntabs.h" #include "snames.h" #include #include #include #include #include #ifndef LIBHASSTRLWR #include char *strlwr(char *inplace) { int c; char *orig = inplace; while ((c = *inplace) != '\0') { if (isalpha(c) && isupper(c)) c = tolower(c); *inplace++ = c; } return(orig); } #endif #define DEFFILESIZE 64000 /* Default input file size */ #define DEFWORK 128 /* Default workfile size (K) */ #define MAXFILE 63 /* Maximum length of filename */ #define MAXWORK 256 /* Maximum workfile size (K) */ #define MINWORK 128 /* Minimum workfile size (K) */ #define PATHSEP1 '\\' #define PATHSEP2 '/' #ifdef __OS2__ #define PATHSEP PATHSEP1 #else #define PATHSEP PATHSEP2 #endif /* Forward references */ static VOID error(PUCHAR, ...); static FILE *openio(PUCHAR, PUCHAR); static VOID usage(VOID); INT main(INT argc, PUCHAR argv[]) { PUCHAR argp; /* Used to process arguments */ clock_t cptime; /* Time at start of compilation */ LONG filesize; /* Size of input file (bytes) */ INT i, j, k; /* Miscellaneous counters */ UCHAR listfile[MAXFILE]; /* Name of listing file */ UCHAR modnwork[MAXFILE]; /* Module name work area */ PUCHAR modulename = modnwork; /* Module name */ UCHAR objfile[MAXFILE]; /* Name of object file */ FILE *objfp; /* File pointer for object file */ PUCHAR sp; /* Miscellaneous pointer */ INT snum; /* Special name declaration counter */ UCHAR sourcefile[MAXFILE] ;/* Name of source file */ struct stat stbuf; /* Contains source file info */ INT maxulab; INT plabel; INT stlimit; INT glaca; INT glacabuf; INT glacurr; INT ustptr; INT auxst; INT iocpdisp; INT sstl; INT levelinf; #if 0 INT bfflag; INT bimstr; INT cdcount; INT contlab; INT crefhead; INT exitlab; INT ldptr; INT n; INT nmax; INT rbase; INT rectb; INT rlevel; INT sflabel; #endif progname = argv[0]; /* Massage the program name into an acceptable form */ sp = strrchr(progname, PATHSEP); if(sp != (PUCHAR) NULL) progname = ++sp; (VOID) strlwr(progname); cptime = clock(); #if 0 /* Initialise memory pointers in case of early exit */ aslist = (LISTF *) NULL; cc = (PUCHAR) NULL; display = (PINT) NULL; dvheads = (PINT) NULL; lett = (PUCHAR) NULL; mainep = (PUCHAR) NULL; sfs = (PINT) NULL; tags = (UINT *) NULL; tline = (PUCHAR) NULL; wkfilead = (PUCHAR) NULL; word = (PINT) NULL; #endif /* Set option defaults */ dcomp = NO; faulty = 0; freeformat = NO; list = NO; parmarr = YES; parmchk = YES; parmdbug = NO; parmdiag = YES; parmlet = NO; parmline = YES; parmmax = NO; parmopt = NO; parmprof = NO; parmtrace = YES; parmx = NO; parmy = NO; #if DEBUG smap = NO; #endif stack = NO; listfile[0] = '\0'; objfile[0] = '\0'; sourcefile[0] = '\0'; wkfilek = DEFWORK; /* Process arguments */ i = 1; while(i < argc) { argp = argv[i++]; if(*argp == '-') { /* Flag */ argp++; while(*argp != '\0') { switch(*argp++) { case 'a': /* NOARRAY */ parmarr = NO; break; case 'c': /* CODE */ dcomp = YES; break; case 'd': /* NODIAG */ parmdiag = NO; break; case 'f': /* FREE */ freeformat = YES; break; case 'g': /* DEBUG */ parmdbug = YES; break; case 'i': /* LET */ parmlet = YES; break; case 'k': /* NOCHECK */ parmchk = NO; break; case 'l': /* Listing file */ if(listfile[0] != '\0') error("listing file" " specified more than" " once"); (VOID) strcpy(listfile, argp); list = YES; argp += strlen(argp); break; case 'm': /* MAXDICT */ parmmax = YES; break; case 'n': /* NOLINE */ parmline = NO; break; case 'o': if(*argp != '\0') { /* Object file */ if(objfile[0] != '\0') error("object file specified more than once"); (VOID) strcpy(objfile, argp); argp += strlen(argp); } else { parmopt = YES; } break; case 'p': /* PROFILE */ parmprof = YES; break; case 's': /* STACK */ stack = YES; break; case 't': /* NOTRACE */ parmtrace = NO; parmdiag = NO; break; case 'w': /* Workfile size */ if(*argp == '\0') wkfilek = DEFWORK; else { INT temp = atoi(argp); if(temp < 0) temp = INT_MAX; wkfilek = temp; if((wkfilek < MINWORK) || (wkfilek > MAXWORK)) error("workfile size must be between %d and %d", MINWORK, MAXWORK); argp += strlen(argp); } break; case 'x': /* PARMX */ parmx = YES; break; case 'y': /* PARMY */ parmy = YES; break; #if DEBUG case 'z': /* PARMZ */ smap = YES; break; #endif default: error("unknown option '%c'", argp[-1]); } } } else { /* Is an input file */ if(sourcefile[0] != '\0') error("source file already specified"); (VOID) strcpy(sourcefile, argp); } } if((parmtrace == NO) && (parmopt == NO)) parmtrace = YES; /* Allow NOTRACE only with OPT */ if(parmopt == YES) { parmarr = NO; parmopt = NO; parmline = NO; parmchk = NO; parmdiag = NO; } /* Open source file */ if(sourcefile[0] == '\0') error("no source file specified"); (VOID) strlwr(sourcefile); sp = strrchr(sourcefile, '.'); if(sp == (PUCHAR) NULL) (VOID) strcat(sourcefile, ".imp"); infp = openio(sourcefile, "r"); filesize = -1; /* In case of stat error */ if(stat(sourcefile, &stbuf) == 0) filesize = stbuf.st_size; if(filesize < 0) filesize = DEFFILESIZE; /* Open object file */ (VOID) strlwr(objfile); if(objfile[0] == '\0') { /* Derive name from source file */ (VOID) strcpy(objfile, sourcefile); sp = strrchr(objfile, '.'); if(sp != (PUCHAR) NULL) *sp = '\0'; /* Truncate extension */ } sp = strrchr(objfile, '.'); if(sp == (PUCHAR) NULL) /* Default to .OBJ */ (VOID) strcat(objfile, ".obj"); objfp = openio(objfile, "wb"); /* Open listing file, or use NUL */ if(list == YES) { (VOID) strlwr(listfile); if(listfile[0] == '\0') { /* Derive name from source file */ (VOID) strcpy(listfile, sourcefile); sp = strrchr(listfile, '.'); if(sp != (PUCHAR) NULL) *sp = '\0'; /* Truncate extension */ } sp = strrchr(listfile, '.'); if(sp == (PUCHAR) NULL) /* Default to .LST */ (VOID) strcat(listfile, ".lst"); } else (VOID) strcpy(listfile, "/dev/null"); listfp = openio(listfile, "w"); /* Generate module name. This is derived from the base source file name. */ sp = strrchr(sourcefile, PATHSEP1); if(sp == (PUCHAR) NULL) sp = strrchr(sourcefile, PATHSEP2); /* Strip any directory path */ if(sp == (PUCHAR) NULL) sp = sourcefile; else sp++; strcpy(modulename, sp); /* Strip filename extension */ sp = strrchr(modulename, '.'); if(sp != (PUCHAR) NULL) *sp = '\0'; #ifdef __OS2__ sp = strchr(modulename, ':'); /* Strip drive name */ if(sp != (PUCHAR) NULL) modulename = ++sp; #endif /* Set up compilation options and tables */ wkfilead = (PUCHAR) xalloc(wkfilek*1024); nnames = 255; if(filesize > 10000) nnames = 511; if(filesize > 32000) nnames = 1023; if((filesize > 262144) || (parmmax == YES) || (wkfilek > 512)) nnames = 2047; asl = 3*nnames; if((asl > 4095) && (wkfilek < 512) && (parmmax == NO)) asl = 4095; /* Stay within 128K auxstack (!!) */ arsize = wkfilek*768 - 300; aslist = (LISTF *) xalloc(sizeof(LISTF)*(asl+1)); word = (PINT) xalloc(sizeof(INT)*(nnames+1)); tags = (PUINT) xalloc(sizeof(INT)*(nnames+1)); dvheads = (PINT) xalloc(sizeof(INT)*13); sfs = (PINT) xalloc(sizeof(INT)*(MAXLEVELS+1)); display = (PINT) xalloc(sizeof(INT)*(MAXLEVELS+1)); mainep = xalloc(32); /* Start of compilation */ a = wkfilead + 256*wkfilek; /* a[] is 25% into workfile */ /* Initialise compiler scalars and arrays */ dsize = 7*nnames; ccsize = 256*(wkfilek-1); if(parmmax == YES) dsize += nnames; lett = (PUCHAR) xalloc(dsize+21); tline = (PUCHAR) xalloc(276); tline = &tline[20]; /* Make array -20:... */ cc = (PUCHAR) xalloc(ccsize); imax = INT_MAX; plabel = 24999; lett[0] = 0; #if 0 n = 12; #endif maxulab = nnames+16384; /* Largest valid user label */ glacurr = 0; glaca = FIXEDGLALEN; glacabuf = glaca; #if 0 sflabel = 20999; exitlab = 0; contlab = 0; nmax = 0; #endif ppcurr = 0; cabuf = 0; oldline = 0; compiler = NO; ustptr = 0; level = 0; ca = 0; lastat = 0; #if 0 bfflag = 0; ldptr = 0; #endif cprmode = 0; next = 1; iocpdisp = 0; auxst = 0; #if 0 crefhead = 0; rbase = 10; rlevel = 0; rectb = 0; #endif logepdisp = 0; expepdisp = 0; strlink = 0; ihead = 0; idepth = 0; sstl = 0; levelinf = 0; #if 0 cdcount = 0; bimstr = 0; #endif strcpy(mainep, "S#GO"); /* Default main entry */ dictbase = &lett[0]; { LPUT0 l0; (VOID) strcpy(l0.compiler_id, COMPILER); l0.version = (RELEASE << 16) | EDIT; (VOID) strcpy(l0.compiler_ladate, LADATE); lput(0, (INT) modulename, (INT) objfp, (INT) &l0); } stlimit = 0x1f000; if(list == YES) { fprintf(listfp, "\n\n\n 80x86 Imp80 compiler release %d.%d" " Version %s\n\n\n", RELEASE, EDIT, LADATE); fprintf(listfp, "%5d %5d\n", nnames, asl); } aslwarn = 0; aslcurbtm = asl - 240; const_limit = sizeof(LISTF)*aslcurbtm - 8; /* Top of constant list - bottom of asl */ for(i = aslcurbtm; i <= asl - 1; i++) aslist[i+1].link = i; aslist[0].s1 = -1; aslist[0].s2 = -1; aslist[0].s3 = -1; aslist[0].link = 0; for(i = 0; i <= nnames; i++) { word[i] = 0; tags[i] = 0; } for(i = 0; i <= 12; i++) dvheads[i] = 0; for(i = 0; i <= MAXLEVELS; i++) sfs[i] = 0; /* Now declare the special names which are in the array 'ilett' */ snum = 0; /* Number of first name */ k = 0; /* Index of first name */ i = ilett[k]; /* Length of first name */ while(i < 255) { for(j = 1; j <= i; j++) cc[j] = ilett[k+j]; cc[i+1] = ';'; /* Copy and terminate */ r = 2; /* Dummy place in 'a' */ q = 1; /* Start of name in 'cc' */ pname(1); /* Declare new name */ push((PINT) (PVOID) &tags[lastname], (SNPT<<16) | 0x8000, 0, snum << 16); snum++; /* Increment special name number */ k = k + i + 1; /* Index of next name */ i = ilett[k]; } pass1(); /* Do syntactic analysis */ if(level > 1) fault(15, level-1, 0); /* %ENDs are missing */ if(faulty == 0) { cptime = clock() - cptime; /* 100ths of secs used */ fprintf(listfp, "\n %d lines analysed in %ld0 msecs - size = %d", line, cptime, p1size); if((line > 90) && (list == YES)) fputc('\f', listfp); else fputc('\n', listfp); } else { fputs("\n Code generation not attempted\n", listfp); iexit(EXIT_FAILURE); } #if 0 pass2(); #endif iexit(EXIT_SUCCESS); return(EXIT_SUCCESS); } /* * Routine to output an error message and stop. * */ static VOID error(PUCHAR message, ...) { va_list ap; fprintf(stderr, "%s: ", progname); va_start(ap, message); vfprintf(stderr, message, ap); va_end(ap); fputc('\n', stderr); faulty = -1; usage(); } /* * Routine to perform tidy exit. * Returns any allocated memory. * */ VOID iexit(INT n) { if(faulty == 0) { fputs("Compilation successful\n", stderr); } else { if(faulty > 0) fprintf(stderr, "Program contains %d fault%s\n", faulty, faulty == 1 ? "" : "s"); } exit(n); } /* * Function to open a file in a specified mode * Does not return if there is a failure, but outputs an error * message and exits * */ static FILE *openio(PUCHAR file, PUCHAR mode) { FILE *fp; fp = fopen(file, mode); if(fp == (FILE *) NULL) { fprintf(stderr, "%s: cannot open '%s'\n", progname, file); iexit(EXIT_FAILURE); } return(fp); } /* * Routine to output brief usage information, then exit. * */ static VOID usage(VOID) { fprintf(stderr, "%s: usage: %s [flags] file\n", progname, progname); iexit(EXIT_SUCCESS); } /* * End of file: main.c * */