/* * crate a dfa table. */ #ifdef __ORCAC__ #pragma lint -1 #pragma debug 0x8000 #pragma optimize -1 #endif #include #include #include #include #ifdef HAVE_GETOPT #include #endif #ifdef __ORCAC__ #include #include #undef fputc #undef feof #endif #include "omf.h" #ifdef __BIG_ENDIAN #define LE_16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) #define LE_32(x) ((LE_16(x) << 16) | (LE_16((x) >> 16))) #else #define LE_16(x) x #define LE_32(x) x #endif #ifdef __ORCAC__ void SetFileType(const char *path, Word fileType, LongWord auxType) { FileInfoRecGS fileDCB; fileDCB.pCount = 4; fileDCB.pathname = (GSString255Ptr)__C2GSMALLOC(path); if (!fileDCB.pathname) return; GetFileInfoGS(&fileDCB); if (!_toolErr) { fileDCB.fileType = fileType; fileDCB.auxType = auxType; SetFileInfoGS(&fileDCB); } free(fileDCB.pathname); } #endif int alloc; int next; struct key { Word next; Word value; }; struct line { Word low; Word high; struct key data[256]; }; struct line **dfa; void insert(const char *str, int value) { int i; int c; int oldc; struct line *l; struct line *oldl; Word n; Word flag; const char *cp = str; if (!str || !*str) return; l = dfa[0]; while (c = *str++) { if (islower(c)) c = toupper(c); oldc = c; oldl = l; n = l->data[c].next; flag = n & 0x8000; // keep track if terminal. if (n & 0x7fff) //already there. { l = dfa[n]; } else if (*str) { struct line *newline; newline = (struct line *)malloc(sizeof(struct line)); if (!newline) { fprintf(stderr, "memory allocation error\n"); exit(0); } memset(newline, 0, sizeof(struct line)); n = next++; if (next == alloc) { alloc += 16; dfa = (struct line **)realloc(dfa, alloc * sizeof(struct line *)); if (!dfa) { fprintf(stderr, "memory allocation error\n"); exit(0); } for (i = next; i < alloc; i++) dfa[i] = NULL; } dfa[n] = newline; l->data[c].next = n | flag; l = newline; } } if (oldl->data[oldc].next & 0x8000) { fprintf(stderr, "error: duplicate string: %s (%d, was %d)\n", cp, value, oldl->data[oldc].value); } else { oldl->data[oldc].next |= 0x8000; oldl->data[oldc].value = value; } } void compact(void) { struct line *l; int i, j; for (i = 0; i < next; i++) { l = dfa[i]; for (j = 0; j < 256; j++) if (l->data[j].next) { l->low = j; break; } for (j = 255; j; j--) if (l->data[j].next) { l->high = j; break; } } } enum { format_c = 0, format_asm, format_omf, format_bin }; /* * nb -- for bin or OMF, the values need to be little-endian... */ void dump(const char *var_name, const char *path, int format) { struct line *l; int i, j; int offset; FILE *fp; omf *O; fp = stdout; if (path) { fp = fopen(path, format >= format_omf ? "wb" : "w"); if (!fp) { fprintf(stderr, "unable to open file %s\n", path); return; } } #ifdef __GNO__ if (format == format_bin || format == format_omf) { fsetbinary(fp); } #endif if (format == format_omf) { int len; O = (omf *)malloc(sizeof(omf)); memset(O, 0, sizeof(omf)); O->numLen = 4; O->version = 2; O->kind = LE_16(omfData); O->dispName = LE_16((Word)&((omf *)0)->loadName); for (i = 0; i < 10; i++) O->loadName[i] = ' '; fwrite(O, sizeof(omf), 1, fp); // now the segment name... len = strlen(var_name); fputc(len, fp); fwrite(var_name, len, 1, fp); O->dispData = sizeof(omf) + len + 1; // lconst record. fputc(0xF2, fp); fputc(0, fp); fputc(0, fp); fputc(0, fp); fputc(0, fp); } if (format == format_c) fprintf(fp, "unsigned %s[] = {\n", var_name); else if (format == format_asm) fprintf(fp, "%s\tDATA\n", var_name); // build offset table offset = next * 2; for (i = 0; i < next; i++) { l = dfa[i]; if (format == format_c) fprintf(fp,"\t%d,\t/* offset to state %d */\n", offset, i); else if (format == format_asm) fprintf(fp,"\tdc i2'%d'\t;offset to state %d\n", offset, i); else if (format >= format_omf) { fputc(offset & 0xff, fp); fputc(offset >> 8,fp); } offset += 4 + 4 * (l->high - l->low + 1); } for (i = 0; i < next; i++) { l = dfa[i]; if (format == format_c) { fprintf(fp, "\n/* state %d */\n", i); fprintf(fp, "\t%d, %d,\n", l->low, l->high); } else if (format == format_asm) { fprintf(fp, "\n* state %d\n", i); fprintf(fp,"\tdc i2'%d,%d'\n", l->low, l->high); } else if (format >= format_omf) { fputc(l->low & 0xff, fp); fputc(l->low >> 8,fp); fputc(l->high & 0xff, fp); fputc(l->high >> 8,fp); } for (j = l->low; j < l->high + 1; j++) { if (format == format_c) { fprintf(fp,"\t0x%x, 0x%x,", l->data[j].next, l->data[j].value); if (isprint(j)) fprintf(fp, "\t/* %c --> %d */", j, 0x7fff & l->data[j].next); fputs("\n",fp); } else if (format == format_asm) { fprintf(fp,"\tdc i2'$%x,$%x'", l->data[j].next, l->data[j].value); if (isprint(j)) fprintf(fp, "\t; %c --> %d", j, 0x7fff & l->data[j].next); fputs("\n",fp); } else if (format == format_bin || format == format_omf) { fputc(l->data[j].next & 0xff, fp); fputc(l->data[j].next >> 8, fp); fputc(l->data[j].value & 0xff, fp); fputc(l->data[j].value >> 8, fp); } } } if (format == format_c) fputs("};\n", fp); else if (format == format_asm) fputs("\tEND\n", fp); if (format == format_omf) { LongWord lconst; fputc(0x00, fp); // end of segment indicator. // backfill some of the values... // bytecount = header + data size + 5 bytes (lconst) + 1 byte (eof) O->byteCount = LE_32(O->dispData + offset + 5 + 1); O->length = LE_32(offset); fseek(fp, 0, SEEK_SET); fwrite(O, sizeof(omf), 1, fp); lconst = LE_32(offset); fseek(fp, O->dispData + 1, SEEK_SET); fwrite(&lconst, 4, 1, fp); free(O); } fflush(fp); if (path) { fclose(fp); #ifdef __ORCAC__ if (format == format_bin) SetFileType(path, 6, 0); else if (format == format_omf) SetFileType(path, 0xB1, 0); #endif } } void usage(void) { puts("dfa [-h] [-v] [-V] [-f format] [-o outfile] table_name file"); puts(" -h: show help information"); puts(" -v: be verbose"); puts(" -V: show version information"); puts(" -f {asm|c|omf|bin}: select output format"); puts(" -o file: output to file"); } int main(int argc, char **argv) { int i; struct line *l; int c; int value; char *cp; char *str; int format = format_c; const char *var_name = NULL; const char *pathname = NULL; FILE *ifile = stdin; while ((c = getopt(argc, argv, "hicvVo:f:")) != EOF) { switch(c) { case 'h': usage(); exit(0); break; case 'o': pathname = optarg; break; case 'f': if (stricmp(optarg, "asm") == 0) format = format_asm; else if (stricmp(optarg, "bin") == 0) format = format_bin; else if (stricmp(optarg, "c") == 0) format = format_c; else if (stricmp(optarg, "omf") == 0) format = format_omf; else { fprintf(stderr, "unrecognized format: %s\n", optarg); } break; } } argc -= optind; argv += optind; switch(argc) { case 2: ifile = fopen(argv[1], "r"); if (!ifile) { fprintf(stderr, "unable to open file %s\n", optarg); exit(0); } case 1: var_name = argv[0]; break; default: usage(); exit(0); } next = 1; alloc = 16; dfa = (struct line **)malloc(alloc * sizeof(struct line *)); if (!dfa) { fprintf(stderr, "memory allocation error\n"); exit(0); } for (i = 0; i < alloc; i++) dfa[i] = NULL; l = (struct line *)malloc(sizeof(struct line)); if (!l) { fprintf(stderr, "memory allocation error\n"); exit(0); } memset(l, 0, sizeof(struct line)); dfa[0] = l; // format: // "text" number for (;;) { static char buffer[1024]; fgets(buffer, 1024, ifile); if (feof(ifile)) break; cp = buffer; if (*cp == '#') continue; if (*cp == '\n') continue; while (*cp && *cp != '"') cp++; if (!cp) continue; *cp++; str = cp; // find end of string while (*cp && *cp != '"') cp++; if (!*cp) { fprintf(stderr, "warning: invalid line: %s\n", buffer); continue; } *cp = 0; cp++; while (isspace(*cp)) cp++; if (*cp == '$' && isxdigit(cp[1])) { sscanf(cp + 1, "%x", &value); } else if (*cp == '0' && cp[1] == 'x' && isxdigit(cp[2])) { sscanf(cp + 2, "%x", &value); } else if (isdigit(*cp)) { value = atoi(cp); } else { fprintf(stderr, "invalid number: %s\n", cp); continue; } insert(str, value); } compact(); dump(var_name, pathname, format); if (ifile != stdin) fclose(ifile); free(dfa); for (i = 0; i < next; i++) free(dfa[i]); exit(0); }