/* * File: genps.c * * Program to generate phrase structure tables for the IMP80 compiler * * Bob Eager August 2002 * */ /* * Compile time options * * Define exactly one target language name to be 1; all the rest should be 0. * */ #define C 1 /* C language */ #define IMP 0 /* IMP80 language */ #ifdef __IBMC__ #pragma strings(readonly) #endif #include #include #include #include #include #define FALSE 0 #define TRUE 1 #define MAXCC 300 /* Size of 'cc' array */ #define MAXCLETT 1000 /* Size of 'clett' array */ #define MAXCWORD 200 /* Size of 'cword' array */ #define MAXDLETT 1000 /* Size of 'dlett' array */ #define MAXDWORD 1200 /* Size of 'dword' array */ #define MAXSYMBOL 3000 /* Size of 'symbol' array */ #define MINDWORD 1000 /* Starting point of 'dword' array */ #define MINSYMBOL 1300 /* Starting point of 'symbol' array */ /* Type definitions */ typedef void VOID, *PVOID; typedef int BOOL, *PBOOL; typedef char CHAR, *PCHAR; typedef unsigned char UCHAR, *PUCHAR; typedef int INT, *PINT; typedef unsigned int UINT, *PUINT; typedef long LONG, *PLONG; typedef unsigned long ULONG, *PULONG; /* Forward references */ static VOID lookup(INT [], INT[], INT, INT, INT, PINT, INT, INT, CHAR); static FILE *openio(PUCHAR, PUCHAR); static VOID pcdict(VOID); static VOID pddict(VOID); static VOID printstr(INT [], INT); static int readn(VOID); static VOID readstring(INT); static VOID record(INT [], INT[], PINT, PINT, INT, INT, CHAR); static VOID usage(VOID); /* Local data */ static INT cc[MAXCC+1]; /* Input string buffer */ static INT clett[MAXCLETT+1]; /* Literal dictionary word list */ static INT cnext = 0; /* Points to next free slot in 'clett' */ static INT cnum = 0; /* Number of items in literal dictionary */ static INT cword[MAXCWORD+1]; /* List of literal dictionary word pointers */ static INT dlett[MAXDLETT+1]; /* List of dictionary words */ static INT dnext = 0; /* Points to next free slot in 'dlett' */ static INT dnum; /* Number of items in dictionary + 1000 */ static INT dword[MAXDWORD+1]; /* List of dictionary word pointers */ static FILE *infp; /* File pointer for input file */ static INT kk[MAXDWORD+1]; /* Dictionary subsidiary array */ static FILE *listfp; /* File pointer for listing file */ static INT nbip; /* Number of BIPs */ static INT nidflag = 0; /* Count of phrases not in dictionary */ static FILE *outfp; /* File pointer for output file */ static PUCHAR progname; /* Program name */ static INT ss; /* Table root */ static INT symbol[MAXSYMBOL+1]; /* Final form of main table */ INT main(INT argc, PUCHAR argv[]) { INT asl = MINSYMBOL; /* Main table free pointer */ INT ch; /* Character temporary */ INT i; INT alt; INT def; INT phrase = 0; FILE *fp; /* Temporary I/O file pointer */ time_t now; /* Binary date and time */ UCHAR s_now[26]; /* String date and time */ PUCHAR ptr; /* Miscellaneous pointer */ progname = argv[0]; ptr = strrchr(progname, '\\'); if(ptr != (PUCHAR) NULL) progname = ++ptr; for(i = 0; progname[i] != '\0'; i++) progname[i] = (UCHAR) tolower(progname[i]); if(argc != 4) usage(); infp = openio(argv[1], "r"); outfp = openio(argv[2], "w"); listfp = openio(argv[3], "w"); now = time((time_t *) NULL); /* Get binary date and time */ strcpy(s_now, ctime(&now)); /* Copy string version */ s_now[24] = '\0'; /* Truncate to remove newline */ dnum = MINDWORD; nbip = readn(); /* Get number of BIPs */ fprintf(listfp, "\nIMP80 phrase structure generated on %s\n\n", s_now); fputs("Built in phrases\n\n", listfp); /* Main loop */ for(;;) { ch = fgetc(infp); if(isalpha(ch)) ch = toupper(ch); /* Comment */ if(ch == '!') { while(ch != '\n') ch = fgetc(infp); /* Skip rest of line */ continue; } /* Dictionary definition */ if(ch == 'D') { ch = fgetc(infp); /* Skip the '(' */ readstring(')'); if(dnum < MINDWORD + nbip) { /* BIP - list it */ fprintf(listfp, "%6d ", dnum+1); printstr(cc, 0); fputc('\n', listfp); } record(dword, dlett, &dnum, &dnext, MAXDLETT, MAXDWORD, 'd'); continue; } if((ch != 'P') && (ch != 'E')) continue; /* Ignore others */ if(ch == 'E') break; /* Finished */ /* Phrase definition */ if(!phrase) { phrase++; fputs("\f\n\nPhrase definitions\n\n", listfp); } fprintf(listfp, "\n\n%c%c", ch, fgetc(infp)); readstring(')'); /* Read the phrase name */ printstr(cc, 0); /* Copy to listing file */ fputc(')', listfp); /* Finish it off */ lookup(dword, dlett, MINDWORD+1+nbip, dnum, TRUE, &i, MAXDLETT, MAXDWORD, 'd'); /* Get offset in 'dword' of dict entry, */ /* and store in 'i' */ kk[i] = asl; def = asl++; alt = asl++; /* Loop to handle all alternates for current phrase */ for(;;) { ch = fgetc(infp); fputc(ch, listfp); switch(ch) { case ',': /* End of alternate */ symbol[alt] = asl; alt = asl++; break; case '0': /* Always success alternate */ symbol[asl++] = MINDWORD; break; case '*': /* Repeated phrase */ symbol[asl++] = MINDWORD - 1; break; case '(': /* Dictionary item */ readstring(')'); /* Read the name */ printstr(cc, 0); fputc(')', listfp); lookup(dword, dlett, MINDWORD+1, dnum, FALSE, &i, MAXDLETT, MAXDWORD, 'd'); symbol[asl++] = i; break; case '\'': /* Literal */ readstring('\''); /* Read the literal */ printstr(cc, 0); fputc('\'', listfp); lookup(cword, clett, 1, cnum, TRUE, &i, MAXCLETT, MAXCWORD, 'c'); symbol[asl++] = i; break; case ';': /* End of alternates */ symbol[alt] = asl; symbol[def] = asl; goto nexts; } } nexts:; } pcdict(); pddict(); for(i = MINSYMBOL; i < asl; i++) { if((1 <= symbol[i]) && (symbol[i] <= cnum)) { symbol[i] = cword[symbol[i]]; } if((1001 + nbip <= symbol[i]) && (symbol[i] <= dnum)) { symbol[i] = kk[symbol[i]]; } } ss = kk[dnum]; fputs("\n\f\n", listfp); for(fp = listfp;;) { #if C fprintf(fp, "/*\n * File: %s\n *\n * Produced by GENPS" " from %s on %s\n *\n */\n\n", argv[2], argv[1], s_now); fprintf(fp, "const\tunsigned char\tclett[%d] = {", cnext); for(i = 0; i <= cnext - 1; i++) { fprintf(fp, "%4d%s", clett[i], (i == cnext - 1) ? "\n};" : ","); if((i != cnext -1) && (i%14 == 0)) fputc('\n', fp); } fprintf(fp, "\n\n"); fprintf(fp, "const\tshort\tx_symbol[%d] = {", asl - MINSYMBOL); for(i = MINSYMBOL; i < asl; i++) { fprintf(fp, "%5d%s", symbol[i], (i == asl - 1) ? "\n};" : ","); if((i != asl - 1) && ((i-MINSYMBOL+1)%10 == 1)) fputc('\n', fp); } fprintf(fp, "\n\nconst\tshort\t*symbol = &x_symbol[-%d];\n", MINSYMBOL); fprintf(fp, "\n#define\tSS\t\t%d\n\n", ss); fprintf(fp, "/*\n * End of file: %s\n *\n */\n", argv[2]); #endif #if IMP fprintf(fp, "!\n! Produced by GENPS from %s on %s\n!\n", argv[1], s_now); fprintf(fp, "%%constantbyteintegerarray clett(0:%d) = ", cnext-1); for(i = 0; i <= cnext - 1; i++) { fprintf(fp, "%4d%c", clett[i], (i == cnext - 1) ? ';' : ','); if((i != cnext -1) && (i%14 == 0)) fputc('\n', fp); } fprintf(fp, "\n!\n"); fprintf(fp, "%%constantintegerarray symbol(%d:%d) = ", MINSYMBOL, asl - 1); for(i = MINSYMBOL; i < asl; i++) { fprintf(fp, "%5d%c", symbol[i], (i == asl - 1) ? ';' : ','); if((i != asl - 1) && ((i-MINSYMBOL+1)%10 == 1)) fputc('\n', fp); } fprintf(fp, "\n!\n%%constantinteger ss = %d\n!\n", ss); #endif if(nidflag != 0) { fprintf(stderr, "%s: %d phrase%s not found in" " dictionary\n", progname, nidflag, nidflag == 1 ? "" : "s"); exit(EXIT_FAILURE); } if(fp == outfp) break; fp = outfp; } fprintf(stderr, "%s: no errors\n", progname); return(EXIT_SUCCESS); } /* * Routine to look up the item in 'cc' in the tables specified by * 'word' and 'lett'. * */ static VOID lookup(INT word[], INT lett[], INT first, INT last, INT insert, PINT i, INT maxlett, INT maxword, CHAR atype) { INT j, k; *i = first; while(*i <= last) { j = word[*i]; for(k = 0; k <= lett[j]; k++) if(lett[j+k] != cc[k]) goto nxt; return; nxt: (*i)++; } if(insert == FALSE) { fprintf(listfp, "\n**************** Phrase not in dictionary *********** "); printstr(cc, 0); nidflag++; return; } record(word, lett, &cnum, &cnext, maxlett, maxword, atype); /* Insert into C dictionary */ *i = cnum; } /* * 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); exit(EXIT_FAILURE); } return(fp); } /* * Routine to list contents of literal dictionary * */ static VOID pcdict(VOID) { INT i, j, k; fputs("\n\f\n\nKey to literal dictionary (CLETT)\n\n", listfp); for(j = 1; j <= cnum; j++) { k = cword[j]; fprintf(listfp, "%4d ", k); printstr(clett, k); for(i = 0; i < 17 - ss; i++) fputc(' ', listfp); if(j%3 == 0) fputc('\n', listfp); } } /* * Routine to list contents of main table * */ static VOID pddict(VOID) { INT i, j; fputs("\n\n\nKey to main table (SYMBOL)\n\n", listfp); for(j = 1001; j <= dnum; j++) { if(j <= (1000+nbip)) { fprintf(listfp, "%4d ", j); } else { fprintf(listfp, "%4d ", kk[j]); } printstr(dlett, dword[j]); for(i = 0; i < 17 - ss; i++) fputc(' ', listfp); if(((j-1000)%3) == 0) fputc('\n', listfp); } } /* * Outputs, to the listing file, the string stored in 'cc', * starting at 'ptr'. Handles underlined characters and generates * '%' as required. * */ static VOID printstr(INT cc[], INT ptr) { INT ch; INT i, k; INT del; ss = cc[ptr]; k = ss; del = 0; for(i = 1; i <= k; i++) { ch = cc[ptr+i]; if((del == 0) && (ch > 128)) { ss++; del = 1; fputc('%', listfp); } ch &= 0x7f; fputc(ch, listfp); } } /* * Function to read a number from input 'fp' and return its value. * */ static INT readn(VOID) { INT res; INT ch = '0'; for(res = 0; isdigit(ch); ch = fgetc(infp)) { res = res*10 + (ch - '0'); } return(res); } /* * Routine to read a string from the input file into 'cc', stopping * when the character 'terminator' is encountered. Underlined characters * are generated as required. * * On exit, 'cc' contains the string, with the length in cc[0]. * */ static VOID readstring(INT terminator) { INT under = 0; INT ch; INT count = 0; for(;;) { ch = fgetc(infp); if(ch == '%') { under = 128; continue; } if(isalpha(ch)) { ch = toupper(ch); ch += under; } else under = 0; if(ch == ' ') continue; /* Ignore spaces */ if(ch == terminator) { cc[0] = count; break; } cc[++count] = ch; } } /* * Records the item in 'cc' in the tables specified by 'word' and 'lett'. * 'word' holds the offset in 'lett' where the item starts. * Updates 'next', the table free pointer, by adding the length of the item. * Updates 'num', the number of dictionary items, by adding one. * */ static VOID record(INT word[], INT lett[], PINT num, PINT next, INT maxlett, INT maxword, CHAR atype) { INT i; (*num)++; if(*num >= maxword) { fprintf(stderr, "%s: %cword array overflow\n", progname, atype); exit(EXIT_FAILURE); } word[*num] = *next; if((*next + cc[0] + 1) >= maxlett) { fprintf(stderr, "%s: %clett array overflow\n", progname, atype); exit(EXIT_FAILURE); } for(i = 0; i <= cc[0]; i++) { lett[*next+i] = cc[i]; } *next += (cc[0]+1); } /* * Routine to output brief usage information, then exit. * */ static VOID usage(VOID) { fprintf(stderr, "Usage: %s input output listing\n", progname); exit(EXIT_SUCCESS); } /* * End of file: genps.c * */