#include #include #include #include #include #include "art.h" #include "utils.h" #define DEBUG 0 #if DEBUG #define HIDE(x) x #else #define HIDE(x) #endif #define MAX_STRING 1024 FILE *HatFile, *OutputFile, *BridgeFile; FileOffset errorRoot, errorMsg,remoteStartNode=0; int ignoreErrors=False; unsigned filesize=0, outputsize=0; char* progname, *dir; extern int browserport; char* rmext (char* word, char* ext) { if (ext==(char*)0) return word; else { char *e = ext; char *i = strdup(word); char *c = i; while (*c) c++; while (*e) e++; while ((*--c==*--e) && e!=ext) ; if ((e==ext) && (*c==*e)) *c='\0'; return i; } } char* basename (char* path, char* ext) { char *c = path; while (*c) c++; while (*c!='/' && c!=path) c--; if (c==path) return rmext(path,ext); else { c++; return rmext(strdup(c),ext); } } char* dirname (char* path) { char *start, *c; start = strdup(path); c = start; while (*c) c++; while (*c!='/' && c!=start) c--; if (c==start) { return "."; } else { *c='\0'; return start; } } /* The initialise() routine ensures that all files are available, * and opens them ready for further action. It also fills in the * errorRoot and errorMsg globals. */ void initialise (int argc, char **argv, int *browserport) { int err; char header[8]; char *arg; if (browserport) { if ((argc==5)&&(strcmp(argv[3],"-remote")==0)) { *browserport=atoi(argv[1]); arg=argv[2]; remoteStartNode = atoi(argv[4]); } else { if ((argc!=3)&&(argc!=4)) { fprintf(stderr," [%s]\n",argv[0]); fprintf(stderr,"\tUsage: %s portno [-o] program[.hat] [-remote node]\n", basename(argv[0],0)); exit(1); } if ((argc==4)&&!strcmp(argv[2],"-o")) { ignoreErrors=True; *browserport=atoi(argv[1]); arg=argv[3]; } else { *browserport=atoi(argv[1]); arg=argv[2]; } } } else { if (argc!=2) { fprintf(stderr," [%s]\n",argv[0]); fprintf(stderr,"\tUsage: %s program[.hat]\n",basename(argv[0],0)); exit(1); } arg=argv[1]; } dir = dirname(arg); arg = basename(arg,".hat"); chdir(dir); progname = basename(argv[0],0); /* for error messages - /not/ the prog being debugged */ filesize = sizeFile(arg,".hat"); outputsize = sizeFile(arg,".hat.output"); HatFile = openFile(arg,".hat"); OutputFile = openFile(arg,".hat.output"); BridgeFile = openFile(arg,".hat.bridge"); err = fread(header,sizeof(char),8,HatFile); if (err!=8) { fprintf(stderr,"%s (error): file %s/%s is too short\n",progname,dir,arg); exit(1); } if (strncmp(header,"Hat",3)) { fprintf(stderr,"%s (error): file %s in directory %s\n",progname,arg,dir); fprintf(stderr," does not appear to be a Hat archive. Quitting.\n"); exit(1); } if (strncmp(header+3,VERSION,4)) { fprintf(stderr,"%s (warning): file %s in directory %s\n",progname,arg,dir); fprintf(stderr," appears to be a Hat archive in format %s\n",header+3); fprintf(stderr," but this tool deals with format version %s\n",VERSION); fprintf(stderr," I'm continuing, but there may be unexpected errors.\n"); } errorRoot = readFO(); errorMsg = readFO(); } void finalise (void) { fclose(HatFile); fclose(OutputFile); fclose(BridgeFile); } /* Open a file for reading, given: * the base name of the file * the file extension */ FILE* openFile (char* base, char* ext) { char filename[MAX_STRING]; FILE* file; struct stat buf; strcpy(filename,base); strcat(filename,ext); if (file = fopen(filename,"r")) { return file; } else { system("stty sane"); fprintf(stderr,"%s: cannot open %s/%s\n",progname,dir,filename); exit(1); } } /* Determine the size of a file, given: * the base name of the file * the file extension */ int sizeFile (char* base, char* ext) { char filename[MAX_STRING]; struct stat buf; strcpy(filename,base); strcat(filename,ext); stat(filename,&buf); return buf.st_size; } /* readFO() reads a single FileOffset from the file and ensures it is * in host-endian order. */ FileOffset readFO (void) { FileOffset fo; fread(&fo,sizeof(FileOffset),1,HatFile); HIDE(fprintf(stderr,"readFO -> 0x%x\n",ntohl(fo));) return ntohl(fo); } /* freadAt() is just like fread(), except it seeks to a specific * file location first. */ int freadAt (FileOffset fo, void* ptr, int size, int nmemb, FILE* stream) { int err; if (fo > filesize) { system("stty sane"); fprintf(stderr,"%s: attempt to read beyond end of file\n",progname); fprintf(stderr,"%s: offset = 0x%x, filesize = 0x%x\n",progname,fo,filesize); fprintf(stderr,"%s: errno = %d (%s)\n",progname,errno,strerror(errno)); exit(1); } if (fseek(stream, fo, SEEK_SET)) { system("stty sane"); fprintf(stderr,"%s: seek error on file\n",progname); fprintf(stderr,"%s: errno = %d (%s)\n",progname,errno,strerror(errno)); exit(1); } return fread(ptr,size,nmemb,stream); } /* readString() reads a null-terminated string from the current position * in the file. */ char* readString (void) { char c, buf[MAX_STRING]; int i; i=0; while (c=fgetc(HatFile)) { buf[i++] = c; } buf[i] = '\0'; HIDE(fprintf(stderr,"readString -> %s\n",buf);) return strdup(buf); } /* readModuleAt() fills in the name of the module and its source file, * given the location of the module descriptor in the file. */ void readModuleAt (FileOffset fo, char** modname, char** srcname) { char c; freadAt(fo,&c,sizeof(char),1,HatFile); if ((c!=0x20) && (c!=0x21)) { system("stty sane"); fprintf(stderr,"%s: expected a Module descriptor at position 0x%x\n" ,progname,fo); exit(1); } *modname = readString(); *srcname = readString(); HIDE(fprintf(stderr,"readModuleAt 0x%x -> %s %s\n",fo,*modname,*srcname);) } /* readIdentifierAt() fills in the name of the variable or constructor, * as well as its module, source file, priority, and definition position, * given the location of the NTId/NTConstr descriptor in the file. */ Ident* readIdentifierAt (FileOffset fo) { char c; FileOffset modpos; Ident* id; int defnpos; freadAt(fo,&c,sizeof(char),1,HatFile); if ((c!=0x46) && (c!=0x47) && (c!=0x56)) { system("stty sane"); fprintf(stderr,"%s: expected an Identifier descriptor at position 0x%x\n" ,progname,fo); exit(1); } id = (Ident*)malloc(sizeof(Ident)); id->idname = readString(); modpos = readFO(); fread(&(id->priority),sizeof(char),1,HatFile); fread(&defnpos,sizeof(int),1,HatFile); id->defnline = ntohl(defnpos)/10000; id->defncolumn = ntohl(defnpos)%10000; id->isIdentifier = False; /* filled in by caller */ id->isConstr = False; /* filled in by caller */ readModuleAt(modpos,&(id->modname),&(id->srcname)); HIDE(fprintf(stderr,"readIdentifierAt 0x%x -> %s %s %s %d %d %d\n",fo,id->idname,id->modname,id->srcname,id->defnline,id->defncolumn,id->priority);) return id; } /* readSRAt() fills in a struct containing the filename and usage * position of a source reference, given the location of the * SR descriptor in the file. */ SrcRef * readSRAt (FileOffset fo) { FileOffset modpos; char *modname, *srcname; int usepos; char c; SrcRef *sr; HIDE(fprintf(stderr,"readSRAt 0x%x\n",fo);) if (fo) { freadAt(fo,&c,sizeof(char),1,HatFile); if (c!=0x60) { system("stty sane"); fprintf(stderr,"%s: expected a SrcRef descriptor at position 0x%x\n" ,progname,fo); fprintf(stderr,"%s: got a 0x%x\n",progname,c); exit(1); } sr = (SrcRef*)malloc(sizeof(SrcRef)); modpos = readFO(); fread(&usepos,sizeof(int),1,HatFile); usepos = ntohl(usepos); readModuleAt(modpos, &modname, &(sr->srcname)); sr->line = usepos/10000; sr->column = usepos%10000; return sr; } else { return (SrcRef*)0; } } /* readNmTypeAt() returns a struct containing a readable notation of the * NmType stored at the given location in the file. */ Ident* readNmTypeAt (FileOffset fo) { char c, buf[MAX_STRING]; Ident *id = (Ident*)malloc(sizeof(Ident)); /* defaults */ id->idname = (char*)0; id->modname = strdup("Prelude"); id->srcname = strdup("Prelude.hs"); id->priority = (char)3; id->defnline = 0; id->defncolumn = 0; id->isIdentifier = False; id->isConstr = False; freadAt(fo,&c,sizeof(char),1,HatFile); if ((c<0x40) || (c>0x50) && (c!=0x56)) { system("stty sane"); fprintf(stderr,"%s: expected a NmType descriptor at position 0x%x\n" ,progname,fo); exit(1); } HIDE(fprintf(stderr,"readNmTypeAt 0x%x -> tag 0x%x\n",fo,c);) switch (c&0x1f) { case NTInt: { int i; fread(&i,sizeof(int),1,HatFile); sprintf(buf,"%d",ntohl(i)); id->idname = strdup(buf); } break; case NTChar: { fread(&c,sizeof(char),1,HatFile); if ((c>31) && (c!='\'')) sprintf(buf,"'%c'",c); else switch(c) { case '\n': sprintf(buf,"'\\n'"); break; case '\t': sprintf(buf,"'\\t'"); break; case '\255' : sprintf(buf,"'\\e'"); break; default : sprintf(buf,"'\\0%X'",c); break; } id->idname = strdup(buf); } break; case NTInteger: { char size; int n; fread(&size,sizeof(char),1,HatFile); if (size==0) sprintf(buf,"0"); else if (size==1) { int n; fread(&n,sizeof(int),1,HatFile); sprintf(buf,"%d",ntohl(n)); } else if (size==-1) { int n; fread(&n,sizeof(int),1,HatFile); sprintf(buf,"-%d",ntohl(n)); } else sprintf(buf,""); id->idname = strdup(buf); } break; case NTRational: { sprintf(buf,""); id->idname = strdup(buf); } break; case NTFloat: { float f; fread(&f,sizeof(float),1,HatFile); sprintf(buf,"%.6f",f); id->idname = strdup(buf); } break; case NTDouble: { double d; fread(&d,sizeof(double),1,HatFile); sprintf(buf,"%.15f",d); id->idname = strdup(buf); } break; case NTConstr: { free(id->modname); free(id->srcname); free(id); id = readIdentifierAt(fo); id->isConstr = True; } break; case NTId: case NTToplevelId: { free(id->modname); free(id->srcname); free(id); id = readIdentifierAt(fo); id->isIdentifier = True; } break; case NTTuple: { sprintf(buf,","); id->idname = strdup(buf); } break; case NTFun: { sprintf(buf,""); id->idname = strdup(buf); } break; case NTCase: { sprintf(buf,"case"); id->idname = strdup(buf); } break; case NTLambda: { sprintf(buf,"\\"); id->idname = strdup(buf); } break; case NTDummy: { sprintf(buf,"{IO}"); id->idname = strdup(buf); sprintf(buf,"Unknown"); id->modname = strdup(buf); } break; case NTCString: { id->idname = readString(); sprintf(buf,"\"%s\"",id->idname); free(id->idname); id->idname = strdup(buf); } break; case NTIf: { sprintf(buf,"if"); id->idname = strdup(buf); } break; case NTGuard: { sprintf(buf,"|"); id->idname = strdup(buf); } break; case NTContainer: { sprintf(buf,"?"); id->idname = strdup(buf); sprintf(buf,"Unknown"); id->modname = strdup(buf); } break; default: break; } HIDE(fprintf(stderr,"readNmTypeAt 0x%x -> %s %s %s %d %d %d\n",fo,id->idname,id->modname,id->srcname,id->defnline,id->defncolumn,id->priority);) if (!id->idname) id->idname = strdup("Problem"); return id; } /* readNmTypeAt2() is identical to readNmTypeAt(), except for the * actual strings returned for the lambda etc. readNmTypeAt2() is used * by hat-explore, whereas readNmTypeAt() is used by hat-trail. */ Ident* readNmTypeAt2 (FileOffset fo) { char c, buf[MAX_STRING]; Ident *id = (Ident*)malloc(sizeof(Ident)); /* defaults */ id->idname = (char*)0; id->modname = strdup("Prelude"); id->srcname = strdup("Prelude.hs"); id->priority = (char)3; id->defnline = 0; id->defncolumn = 0; id->isIdentifier = False; id->isConstr = False; freadAt(fo,&c,sizeof(char),1,HatFile); if ((c<0x40) || (c>0x50) && (c!=0x56)) { system("stty sane"); fprintf(stderr,"%s: expected a NmType descriptor at position 0x%x\n" ,progname,fo); exit(1); } HIDE(fprintf(stderr,"readNmTypeAt2 0x%x -> tag 0x%x\n",fo,c);) switch (c&0x1f) { case NTInt: { int i; fread(&i,sizeof(int),1,HatFile); sprintf(buf,"%d",ntohl(i)); id->idname = strdup(buf); } break; case NTChar: { fread(&c,sizeof(char),1,HatFile); if ((c>31) && (c!='\'')) sprintf(buf,"'%c'",c); else switch(c) { case '\n': sprintf(buf,"'\\n'"); break; case '\t': sprintf(buf,"'\\t'"); break; case '\255' : sprintf(buf,"'\\e'"); break; default : sprintf(buf,"'\\0%X'",c); break; } id->idname = strdup(buf); } break; case NTInteger: { char size; int n; fread(&size,sizeof(char),1,HatFile); if (size==0) sprintf(buf,"0"); else if (size==1) { int n; fread(&n,sizeof(int),1,HatFile); sprintf(buf,"%d",ntohl(n)); } else if (size==-1) { int n; fread(&n,sizeof(int),1,HatFile); sprintf(buf,"-%d",ntohl(n)); } else sprintf(buf,""); id->idname = strdup(buf); } break; case NTRational: { sprintf(buf,""); id->idname = strdup(buf); } break; case NTFloat: { float f; fread(&f,sizeof(float),1,HatFile); sprintf(buf,"%.6f",f); id->idname = strdup(buf); } break; case NTDouble: { double d; fread(&d,sizeof(double),1,HatFile); sprintf(buf,"%.15f",d); id->idname = strdup(buf); } break; case NTConstr: { free(id->modname); free(id->srcname); free(id); id = readIdentifierAt(fo); id->isConstr = True; } break; case NTId: case NTToplevelId: { free(id->modname); free(id->srcname); free(id); id = readIdentifierAt(fo); id->isIdentifier = True; } break; case NTTuple: { sprintf(buf,","); id->idname = strdup(buf); } break; case NTFun: { sprintf(buf,""); id->idname = strdup(buf); } break; case NTCase: { sprintf(buf,"case"); id->idname = strdup(buf); } break; case NTLambda: { sprintf(buf,"(\\..)"); id->idname = strdup(buf); } break; case NTDummy: { sprintf(buf,"{IO}"); id->idname = strdup(buf); sprintf(buf,"Unknown"); id->modname = strdup(buf); } break; case NTCString: { id->idname = readString(); sprintf(buf,"\"%s\"",id->idname); free(id->idname); id->idname = strdup(buf); } break; case NTIf: { sprintf(buf,"if"); id->idname = strdup(buf); } break; case NTGuard: { sprintf(buf,"|"); id->idname = strdup(buf); } break; case NTContainer: { sprintf(buf,"?"); id->idname = strdup(buf); sprintf(buf,"Unknown"); id->modname = strdup(buf); } break; default: break; } HIDE(fprintf(stderr,"readNmTypeAt2 0x%x -> %s %s %s %d %d %d\n",fo,id->idname,id->modname,id->srcname,id->defnline,id->defncolumn,id->priority);) if (!id->idname) id->idname = strdup("Problem"); return id; } /* readTraceAt() fills in a string containing a readable notation of the * Trace stored at the given location in the file. It returns the * parent trace. This routine is only currently used by the "virtual * stack trace" program. */ FileOffset readTraceAt (FileOffset fo, char** expr, SrcRef** sr, int* infix ,int followHidden, int depth) { char c, buf[10000]; /* fixed size no final solution */ FileOffset parent; *infix = 3; /* default */ if (depth <= 0) { *expr = strdup("·"); return fo; } if (fo) { freadAt(fo,&c,sizeof(char),1,HatFile); if ((c<0x00) || (c>0xe) || ((c > 0x7) && (c < 0xc))) { system("stty sane"); fprintf(stderr,"%s: expected a Trace descriptor at position 0x%x\n" ,progname,fo,c); exit(1); } HIDE(fprintf(stderr,"readTraceAt 0x%x -> tag 0x%x\n",fo,c);) switch (c&0x17) { /* consider only lower bits 0,1,2 and 4 */ case TAp: { int i, dummy; FileOffset foExprs[20], foSR; char* exprs[20]; int fixexp[20]; fread(&c,sizeof(char),1,HatFile); parent = readFO(); HIDE(fprintf(stderr,"enter parent of 0x%x -> 0x%x\n",fo,parent);) for (i=0; i<=c; i++) { foExprs[i] = readFO(); } foSR = readFO(); for (i=0; i<=c; i++) { (void)readTraceAt(foExprs[i],&(exprs[i]),sr,&(fixexp[i]) ,False,depth-1); } *infix = fixexp[0]; if (isInfix(fixexp[0]) && c >= 2) { sprintf(buf,"%s" ,infixPrint(exprs[1],fixexp[1],exprs[0],fixexp[0] ,exprs[2],fixexp[2])); for (i=3; i<=c; i++) { strcat(buf," "); strcat(buf,exprs[i]); } } else { /* no fixity */ if (strcmp(exprs[0],"if")==0 || strcmp(exprs[0],"|")==0 || strcmp(exprs[0],"case")==0) { c = 1; } sprintf(buf,"(%s",exprs[0]); for (i=1; i<=c; i++) { strcat(buf," "); if (isInfix(fixexp[i])) { strcat(buf,"("); strcat(buf,exprs[i]); strcat(buf,")"); } else strcat(buf,exprs[i]); } strcat(buf,")"); } *expr = strdup(buf); *sr = readSRAt(foSR); HIDE(fprintf(stderr,"return parent of 0x%x -> 0x%x\n",fo,parent);) return parent; } break; case TNm: { FileOffset foExpr, foSR; Ident *id; parent = readFO(); foExpr = readFO(); foSR = readFO(); id = readNmTypeAt(foExpr); *infix = id->priority; sprintf(buf,"%s",id->idname); *expr = strdup(buf); *sr = readSRAt(foSR); return parent; } break; case TInd: { parent = readFO(); /* throw first away */ parent = readFO(); return readTraceAt(parent, expr, sr, infix, followHidden ,depth); } break; case THidden: { parent = readFO(); if (!followHidden) { sprintf(buf,"·"); *expr = strdup(buf); return parent; } else { return readTraceAt(parent, expr, sr, infix, followHidden ,depth); } } break; case TSatA: case TSatAL: { parent = readFO(); return readTraceAt(parent, expr, sr, infix, followHidden ,depth); } break; case TSatB: case TSatBL: { parent = readFO(); sprintf(buf,"_L"); *expr = strdup(buf); return parent; } break; case TSatC: case TSatCL: { parent = readFO(); return readTraceAt(parent, expr, sr, infix, followHidden ,depth); } break; default: break; } } else { sprintf(buf,""); *expr = strdup(buf); return fo; } } /* NOT USED */ /* checkSATkind() returns 0==error, 1==A, 2==B, 3==C, for the kind of * SAT pointed to by fo. The trace must already be a SAT. */ int checkSATkind (FileOffset fo) { char c; freadAt(fo,&c,sizeof(char),1,HatFile); switch (c) { case 0x04: return 1; break; case 0x05: return 2; break; case 0x06: return 3; break; default: fprintf(stderr,"%s: expected a SAT at position 0x%x\n" ,progname,fo); return 0; break; } } /* print an infix expression correctly according to the given priorities. */ char* infixPrint (char* str1, int arg1, char* strfn, int fn, char* str2, int arg2) { char buf[10000]; /* fixed size no final solution */ if (!isInfix(arg1)) sprintf(buf,"%s",str1); else if (priority(arg1) > priority(fn)) sprintf(buf,"%s",str1); else if (priority(arg1) < priority(fn)) sprintf(buf,"(%s)",str1); else if (isInfixN(fn)) sprintf(buf,"(%s)",str1); else sprintf(buf,"%s",str1); strcat(buf,strfn); if (!isInfix(arg2)) { strcat(buf,str2); } else if (priority(arg2) > priority(fn)) { strcat(buf,str2); } else if (priority(arg2) < priority(fn)) { strcat(buf,"("); strcat(buf,str2); strcat(buf,")"); } else if (isInfixN(fn)) { strcat(buf,"("); strcat(buf,str2); strcat(buf,")"); } else { strcat(buf,str2); } return strdup(buf); } /* From here on down, everything is utility functions for hat-explore. */ /* Open the .hat file */ void openHatFile (char* arg) { HatFile = openFile(arg, ""); filesize = sizeFile(arg, ""); } /* Open the bridge file */ void openBridgeFile (char* arg) { BridgeFile = openFile(arg,".bridge"); } /* Return the contents of the bridge file, one item at a time. */ FileOffset getBridgeValue (void) { int err; FileOffset fo; err = fread(&fo,sizeof(FileOffset),1,BridgeFile); if (err==0) { fclose(BridgeFile); return 0; } else return ntohl(fo); } /* Get the trace reference for an error, and the string associated with it. */ FileOffset getErrorLoc (void) { FileOffset fo; fseek(HatFile,8,SEEK_SET); fo = readFO(); return fo; } char * errorMessage (void) { FileOffset fo; char c; fseek(HatFile,12,SEEK_SET); fo = readFO(); freadAt(fo,&c,sizeof(char),1,HatFile); if (c==0x4d) return readString(); else return ""; } /* Read the tag bits and report the NodeType. */ int getNodeType (FileOffset fo) { char c; freadAt(fo,&c,sizeof(char),1,HatFile); return (int)(c>>5); /* upper 3 bits of the tag identify the NodeType */ } /* Read the tag bits of a Trace tag and report the TraceType. */ int getTraceType (FileOffset fo) { char c; freadAt(fo,&c,sizeof(char),1,HatFile); return (int)(c&0x1f); /* lower 5 bits of a Trace tag identify the TraceType */ } /* For any node type, get its parent. If it doesn't have one, we give 0. */ FileOffset parentNode (FileOffset fo) { char c; FileOffset parent; freadAt(fo,&c,sizeof(char),1,HatFile); switch ((int)(c>>5)) { /* upper 3 bits identify the NodeType */ case Trace: switch ((int)(c&0x1f)) {/* lower 5 bits identify the TraceType */ case TAp: fread(&c,sizeof(char),1,HatFile); /* skip arity */ parent = readFO(); return parent; break; case TNm: case TInd: case THidden: case TSatA: case TSatAL: case TSatB: case TSatBL: case TSatC: case TSatCL: parent = readFO(); return parent; break; } break; case ModuleInfo: case NmType: case SR: return 0; break; } } /* Only for Trace nodes of kind TNm, we follow the NmType pointer and get * back a string representation of the name (identifier, Integer, Double, etc), * and its fixity. The predicate isLiteral reports True for values of basic * types like Int, Char, Double etc, and isConstructor identifies Constrs. */ Ident * getNmInfo (FileOffset fo) { char c; FileOffset ptr; Ident *name; freadAt(fo,&c,sizeof(char),1,HatFile); switch ((int)(c>>5)) { /* upper 3 bits identify the NodeType */ case Trace: switch ((int)(c&0x1f)) {/* lower 5 bits identify the TraceType */ case TNm: readFO(); /* skip parent */ ptr = readFO(); /* get NmType addr */ name = readNmTypeAt2(ptr); return name; break; default: return (Ident*)0; break; } default: return (Ident*)0; break; } } char * getNm (FileOffset fo) { char *id; Ident *name = getNmInfo(fo); if (name) { id = name->idname; free(name); return id; } else return ""; } char * getNmMod (FileOffset fo) { char *id; Ident *name = getNmInfo(fo); if (name) { id = name->modname; free(name); return id; } else return ""; } int getFixity (FileOffset fo) { int f; Ident *name = getNmInfo(fo); if (name) { f = name->priority; free(name); return f; } else return 3; } int isLiteral (FileOffset fo) { int l; Ident *name = getNmInfo(fo); if (name) { l = !name->isIdentifier && !name->isConstr; free(name); return l; } else return False; } int isConstructor (FileOffset fo) { int l; Ident *name = getNmInfo(fo); if (name) { l = name->isConstr; free(name); return l; } else return False; } /* For Trace nodes excluding kind TNm, get number and values of arguments. */ int getApArity (FileOffset fo) { char c; int arity=0; freadAt(fo,&c,sizeof(char),1,HatFile); switch ((int)(c>>5)) { /* upper 3 bits identify the NodeType */ case Trace: switch ((int)(c&0x1f)) {/* lower 5 bits identify the TraceType */ case TAp: fread(&c,sizeof(char),1,HatFile); /* get arity */ return (int)c; break; case TNm: return 0; break; case TInd: return 1; break; case THidden: case TSatA: case TSatAL: case TSatB: case TSatBL: case TSatC: case TSatCL: return 0; break; } break; case ModuleInfo: case NmType: case SR: return 0; break; } } FileOffset getApArg (FileOffset fo, int n) { char c; int i=0; FileOffset ptr; freadAt(fo,&c,sizeof(char),1,HatFile); switch ((int)(c>>5)) { /* upper 3 bits identify the NodeType */ case Trace: switch ((int)(c&0x1f)) {/* lower 5 bits identify the TraceType */ case TAp: fread(&c,sizeof(char),1,HatFile); /* get arity */ if (n<=c) { readFO(); /* skip parent */ for (i=0; i>5)) { /* upper 3 bits identify the NodeType */ case Trace: switch ((int)(c&0x1f)) {/* lower 5 bits identify the TraceType */ case TAp: fread(&c,sizeof(char),1,HatFile); /* get arity */ readFO(); /* skip parent */ for (i=0; i<=c; i++) { readFO(); }/* skip fun and args */ ptr = readFO(); /* get SrcRef */ return ptr; break; case TNm: readFO(); /* skip parent */ readFO(); /* skip NmType */ ptr = readFO(); /* get SrcRef */ return ptr; break; case TInd: case THidden: case TSatA: case TSatAL: case TSatB: case TSatBL: case TSatC: case TSatCL: return 0; break; } break; case ModuleInfo: case NmType: case SR: return 0; break; } } /* Get information out of a SrcRef node. */ char * getSrcRefFile (FileOffset fo) { SrcRef *sr; char *id; if (fo==0) return ""; sr = readSRAt(fo); id = sr->srcname; free(sr); return id; } int srcRefLine (FileOffset fo) { SrcRef *sr; int line; if (fo==0) return 0; sr = readSRAt(fo); line = sr->line; free(sr); return line; } int srcRefCol (FileOffset fo) { SrcRef *sr; int col; if (fo==0) return 0; sr = readSRAt(fo); col = sr->column; free(sr); return col; } /* Get the Ident node for the fun position of an expression. * If the node doesn't look right, we give back a 0 reference. */ FileOffset getDefnRef (FileOffset fo) { char c; int i; FileOffset ptr; if (fo==0) return 0; freadAt(fo,&c,sizeof(char),1,HatFile); switch ((int)(c>>5)) { /* upper 3 bits identify the NodeType */ case Trace: switch ((int)(c&0x1f)) {/* lower 5 bits identify the TraceType */ case TAp: fread(&c,sizeof(char),1,HatFile); /* get arity */ readFO(); /* skip parent */ ptr = readFO(); /* get fun */ return getDefnRef(ptr); /* and follow it */ break; case TNm: readFO(); /* skip parent */ ptr = readFO(); /* get NmType */ return ptr; break; case TInd: case THidden: case TSatA: case TSatAL: case TSatB: case TSatBL: case TSatC: case TSatCL: return 0; break; } break; case NmType: return fo; break; case ModuleInfo: case SR: return 0; break; } } /* Get information out of an identifier (TNm) node. */ char * getDefnFile (FileOffset fo) { Ident *i; char *id; if (fo==0) return ""; i = readNmTypeAt2(fo); id = i->srcname; free(i); return id; } int defnLine (FileOffset fo) { Ident *i; int line; if (fo==0) return 0; i = readNmTypeAt2(fo); line = i->defnline; free(i); return line; } int defnCol (FileOffset fo) { Ident *i; int col; if (fo==0) return 0; i = readNmTypeAt2(fo); col = i->defncolumn; free(i); return col; } /* peekTrace() takes a peek backwards at a trace (or indirection), skipping * over any THidden or TInd nodes to find the nearest "real" trace. * Hence, it is somewhat similar to followTrace() in browsercomms.c. */ FileOffset peekTrace(FileOffset fo) { char c; while (1) { if (fo==0) return 0; /* when trace is Root */ freadAt(fo,&c,sizeof(char),1,HatFile); switch (c&8 ? c-8 : c) { /* clear `lonely' bit (if set) */ case TInd: fo = readFO(); /* fst of indirection */ (void)readFO(); /* snd of indirection */ break; case TSatA: case TSatB: case TSatC: case TSatAL: case TSatBL: case TSatCL: fo = readFO(); break; case TAp: case TNm: return fo; break; case THidden: fo = readFO(); break; default: system("stty sane"); fprintf(stderr,"peekTrace failed\n"); exit(1); } } } /* getResult() looks at the node immediately following a TAp node, checks * whether it is a (non-lonely) SAT, and if so, returns the SAT pointer, * which represents the result of the application. If no SAT follows * the application, then we follow the parent pointer and get its result * instead. (Olaf guarantees this to be safe.) */ FileOffset getResult (FileOffset fo) { char c; int i; FileOffset parent,result; if (fo==0) return 0; /* when trace is Root */ freadAt(fo,&c,sizeof(char),1,HatFile); switch ((int)(c>>5)) { /* upper 3 bits identify the NodeType */ case Trace: switch ((int)(c&0x1f)) {/* lower 5 bits identify the TraceType */ case TAp: fread(&c,sizeof(char),1,HatFile); /* get arity */ parent = readFO(); /* skip parent */ for (i=0; i<=c; i++) { readFO(); }/* skip fun and args */ readFO(); /* skip SrcRef */ fread(&c,sizeof(char),1,HatFile); /* get next node */ switch ((int)(c>>5)) { case Trace: switch ((int)(c&0x1f)) { case TSatA: case TSatB: return 0; break; case TSatC: result = readFO(); return result; break; default: return getResult(parent); break; } break; default: return getResult(parent); break; } break; case TNm: parent = readFO(); /* skip parent */ readFO(); /* skip NmType ptr */ readFO(); /* skip SrcRef */ fread(&c,sizeof(char),1,HatFile); /* get next node */ switch ((int)(c>>5)) { /* code is identical as above */ case Trace: switch ((int)(c&0x1f)) { case TSatA: case TSatB: return 0; break; case TSatC: result = readFO(); return result; break; default: return getResult(parent); break; } break; default: return getResult(parent); break; } default: break; } break; default: break; } return 0; /* if anything goes wrong */ }