(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* File: Coverage.m3 *) (* Last modified on Mon Oct 12 09:13:29 PDT 1992 by kalsow *) (* modified on Wed Mar 13 01:32:19 1991 by muller *) MODULE Coverage; IMPORT Value, Host, Scanner, String, Emit, Target; TYPE ProcHead = REF RECORD next: ProcHead; proc: Value.T; END; CONST Header = "<<< MaxLine) THEN RETURN END; IF (file # Host.filename) THEN RETURN END; minLine := MIN (minLine, line); maxLine := MAX (maxLine, line); WHILE (used = NIL) OR (LAST (used^) < line) DO Expand () END; used[line] := LineSeen.yes; END NoteLine; PROCEDURE Expand () = BEGIN IF (used = NIL) THEN used := NEW (REF ARRAY OF LineSeen, 100); ELSE WITH new = NEW (REF ARRAY OF LineSeen, 2 * NUMBER (used^)) DO FOR i := 0 TO LAST (used^) DO new[i] := used[i] END; used := new; END; END; END Expand; PROCEDURE NoteProcedure (v: Value.T) = BEGIN IF (NOT Host.coverage) THEN RETURN END; WITH p = NEW (ProcHead) DO p.next := procs; p.proc := v; procs := p; END; INC (nProcs); END NoteProcedure; PROCEDURE GenerateTables () = VAR nLines := MAX (0, maxLine - minLine) + 1; header := String.Add (Header); trailer := String.Add (Trailer); p : ProcHead; i: INTEGER; pname: String.T; fname: String.T; BEGIN IF (NOT Host.coverage) THEN RETURN END; fname := String.FileTail (Host.filename); (* generate the coverage tables *) Emit.Op ("_PRIVATE _VOLATILE struct {\001\n"); Emit.OpI ("char header [@];\n", SLen (header)); Emit.Op ("int timestamp;\n"); Emit.Op ("int fileLen;\n"); Emit.OpI ("char file [@];\n", SLen (fname)); Emit.Op ("int firstLine;\n"); Emit.Op ("int nLines;\n"); Emit.OpI ("int lines[@];\n", nLines); Emit.Op ("int nProcs;\n"); p := procs; i := 0; WHILE (p # NIL) DO IF (p.proc # NIL) THEN pname := Value.CName (p.proc); INC (i); Emit.OpI ("int len@;\n", i); Emit.OpII ("char name@ [@];\n", i, SLen (pname)); Emit.OpN ("int cnt_@;", p.proc); END; p := p.next; END; Emit.OpI ("char trailer [@];\n", SLen (trailer)); Emit.Op ("\002} _coverage = {\001\n"); EmitChars (header); Emit.OpI ("@, /* timestamp */\n", 0); Emit.OpI ("@, /* fileLen */\n", String.Length (fname)); EmitChars (fname); Emit.OpI ("@, /* firstLine */\n", minLine); Emit.OpI ("@, /* nLines */\n", nLines); Emit.Op ("{\001 /* lines */\n"); FOR x := 0 TO nLines-1 DO IF (used # NIL) AND (used [x+minLine] # LineSeen.no) THEN Emit.Op ("0,\n"); ELSE Emit.Op ("-1,\n"); END; END; Emit.Op ("\002}, /* lines */\n"); Emit.OpI ("@, /* nProcs */\n", i); p := procs; i := 0; WHILE (p # NIL) DO IF (p.proc # NIL) THEN pname := Value.CName (p.proc); INC (i); Emit.OpII ("@, /* len@ */\n", String.Length (pname), i); EmitChars (pname); Emit.Op ("0,\n"); END; p := p.next; END; EmitChars (trailer); Emit.Op ("\002};"); END GenerateTables; PROCEDURE SLen (s: String.T): INTEGER = CONST Grain = Target.INTSIZE DIV Target.CHARSIZE; BEGIN RETURN (String.Length (s) + Grain-1) DIV Grain * Grain; END SLen; PROCEDURE EmitChars (s: String.T) = BEGIN Emit.OpQ ("{ @", s); FOR i := 1 TO SLen (s) - String.Length (s) DO Emit.Op (",0") END; Emit.Op ("},\n"); END EmitChars; PROCEDURE CountLine () = VAR line: INTEGER; file: String.T; BEGIN IF (NOT Host.coverage) THEN RETURN END; Scanner.Here (file, line); IF (line > MaxLine) THEN RETURN END; IF (file # Host.filename) THEN RETURN END; IF used [line] = LineSeen.generated THEN RETURN END; Emit.OpI ("_coverage.lines[@]++;\n", line - minLine); used [line] := LineSeen.generated; END CountLine; PROCEDURE CountProcedure (v: Value.T) = BEGIN IF (NOT Host.coverage) THEN RETURN END; Emit.OpN ("_coverage.cnt_@++;\n", v); END CountProcedure; PROCEDURE Reset () = BEGIN minLine := LAST (INTEGER); maxLine := FIRST (INTEGER); procs := NIL; nProcs := 0; END Reset; BEGIN END Coverage.