#ifndef lint static const char RCSid[] = "$Id: trans.c,v 2.5 2003/11/15 17:54:06 schorsch Exp $"; #endif /* * Translator utilities * * Greg Ward */ #include #include #include #include "rterror.h" #include "trans.h" static int idcmp(ID *id1, ID *id2); static void fputidlist(IDLIST *qp, FILE *fp); static int qtype(char *qnm, register QLIST *qlp); extern int fgetid( /* read an id up to char in dls from fp */ ID *idp, char *dls, register FILE *fp ) { char dset[256/8]; char buf[MAXSTR]; register int c; register char *cp; /* create delimiter set */ for (cp = dset+sizeof(dset); cp-- > dset; ) *cp = 0; for (cp = dls; *cp; cp++) dset[*cp>>3] |= 1<<(*cp&7); /* get characters up to delimiter */ cp = buf; while ((c = getc(fp)) != EOF && !(dset[c>>3] & 1<<(c&7))) *cp++ = c; /* check for empty */ if (cp == buf) { if (c == EOF) return(EOF); idp->number = 0; idp->name = NULL; return(0); } /* truncate space at end */ while (cp[-1] == ' ' || cp[-1] == '\t') cp--; *cp = '\0'; /* skip white space at beginning */ for (cp = buf; *cp && (*cp == ' ' || *cp == '\t'); cp++) ; /* assign value */ idp->number = atoi(cp); idp->name = NULL; /* check for ghost string */ if (!*cp) return(0); /* check for name */ if (idp->number == 0 && *cp != '0') idp->name = savestr(cp); return(0); } extern int findid( /* find (or insert) id in list */ register IDLIST *idl, ID *idp, int insert ) { int upper, lower; register int cm, i; /* binary search */ lower = 0; upper = cm = idl->nids; while ((i = (lower + upper) >> 1) != cm) { cm = idcmp(idp, &idl->id[i]); if (cm > 0) lower = i; else if (cm < 0) upper = i; else return(i); cm = i; } if (!insert) return(-1); if (idl->nids == 0) { /* create new list */ idl->id = (ID *)malloc(sizeof(ID)); if (idl->id == NULL) goto memerr; } else { /* grow old list */ idl->id = (ID *)realloc((void *)idl->id,(idl->nids+1)*sizeof(ID)); if (idl->id == NULL) goto memerr; for (i = idl->nids; i > upper; i--) { idl->id[i].number = idl->id[i-1].number; idl->id[i].name = idl->id[i-1].name; } } idl->nids++; /* insert new element */ idl->id[i].number = idp->number; if (idp->name == NULL) idl->id[i].name = NULL; else idl->id[i].name = savestr(idp->name); return(i); memerr: eputs("Out of memory in findid\n"); quit(1); return -1; /* pro forma return */ } static int idcmp( /* compare two identifiers */ register ID *id1, register ID *id2 ) { /* names are greater than numbers */ if (id1->name == NULL) if (id2->name == NULL) return(id1->number - id2->number); else return(-1); else if (id2->name == NULL) return(1); else return(strcmp(id1->name, id2->name)); } extern void write_quals( /* write out qualifier lists */ QLIST *qlp, IDLIST idl[], FILE *fp ) { int i; for (i = 0; i < qlp->nquals; i++) if (idl[i].nids > 0) { fprintf(fp, "qualifier %s begin\n", qlp->qual[i]); fputidlist(&idl[i], fp); fprintf(fp, "end\n"); } } static void fputidlist( /* put id list out to fp */ IDLIST *qp, FILE *fp ) { int fi; register int i; /* print numbers/ranges */ fi = 0; for (i = 0; i < qp->nids && qp->id[i].name == NULL; i++) if (i > 0 && qp->id[i].number > qp->id[i-1].number+1) { if (i > fi+1) fprintf(fp, "[%d:%d]\n", qp->id[fi].number, qp->id[i-1].number); else fprintf(fp, "%d\n", qp->id[fi].number); fi = i; } if (i-1 > fi) fprintf(fp, "[%d:%d]\n", qp->id[fi].number, qp->id[i-1].number); else if (i > 0) fprintf(fp, "%d\n", qp->id[fi].number); for ( ; i < qp->nids; i++) fprintf(fp, "\"%s\"\n", qp->id[i].name); } RULEHD * getmapping( /* read in mapping file */ char *file, QLIST *qlp ) { char *err; register int c; RULEHD *mp = NULL; int nrules = 0; register RULEHD *rp; register int qt; char buf[MAXSTR]; FILE *fp; if ((fp = fopen(file, "r")) == NULL) { eputs(file); eputs(": cannot open\n"); quit(1); } /* get each rule */ while (fscanf(fp, " %[^ ;\n]", buf) == 1) { if (buf[0] == '#') { /* comment */ while ((c = getc(fp)) != EOF && c != '\n') ; continue; } rp = (RULEHD *)calloc(1, rulsiz(qlp->nquals)); if (rp == NULL) goto memerr; rp->mnam = savestr(buf); for ( ; ; ) { /* get conditions */ while ((c = getc(fp)) != '(') if (c == ';' || c == EOF) goto endloop; if (fscanf(fp, " %s ", buf) != 1) { err = "missing variable"; goto fmterr; } if ((qt = qtype(buf, qlp)) == -1) { err = "unknown variable"; goto fmterr; } if (rp->qflg & FL(qt)) { err = "variable repeated"; goto fmterr; } rp->qflg |= FL(qt); c = getc(fp); switch (c) { case '"': /* id name */ if (fscanf(fp, "%[^\"]\" )", buf) != 1) { err = "bad string value"; goto fmterr; } idm(rp)[qt].nam = savestr(buf); break; case '[': /* id range */ if (fscanf(fp, "%d : %d ] )", &idm(rp)[qt].min, &idm(rp)[qt].max) != 2) { err = "bad range value"; goto fmterr; } if (idm(rp)[qt].min > idm(rp)[qt].max) { err = "reverse range value"; goto fmterr; } break; default: /* id number? */ if ((c < '0' || c > '9') && c != '-') { err = "unrecognizable value"; goto fmterr; } ungetc(c, fp); if (fscanf(fp, "%d )", &idm(rp)[qt].min) != 1) { err = "bad number id"; goto fmterr; } idm(rp)[qt].max = idm(rp)[qt].min; break; } } endloop: rp->next = mp; mp = rp; nrules++; } fclose(fp); return(mp); fmterr: sprintf(buf, "%s: %s for rule %d\n", file, err, nrules+1); eputs(buf); quit(1); memerr: eputs("Out of memory in getmapping\n"); quit(1); return NULL; /* pro forma return */ } static int qtype( /* return number for qualifier name */ char *qnm, register QLIST *qlp ) { register int i; for (i = 0; i < qlp->nquals; i++) if (!strcmp(qnm, qlp->qual[i])) return(i); return(-1); } extern int matchid( /* see if we match an id */ register ID *it, register IDMATCH *im ) { if (it->name == NULL) { if (im->nam != NULL) return(0); return(it->number >= im->min && it->number <= im->max); } if (im->nam == NULL) return(0); return(!strcmp(it->name, im->nam)); }