(* Copyright (C) 1989, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* File: Coverage.m3 *) (* Last modified on Wed Jun 6 09:39:00 1990 by muller *) (* modified on Wed Feb 14 09:00:50 1990 by kalsow *) MODULE Coverage; IMPORT Value, ValueRep, Host, Scanner, String, Emit, Error, Target; IMPORT M3toC; 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] := TRUE; END NoteLine; PROCEDURE Expand () = BEGIN IF (used = NIL) THEN used := NEW (REF ARRAY OF BOOLEAN, 100); ELSE WITH new = NEW (REF ARRAY OF BOOLEAN, 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; BEGIN IF (NOT Host.coverage) THEN RETURN END; (* generate the coverage tables *) Emit.Op ("PRIVATE 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 (Host.filename)); 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 INC (i); Emit.OpI ("int len@;\n", i); Emit.OpII ("char name@ [@];\n", i, SLen (p.proc.name)); 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 (Host.filename)); EmitChars (Host.filename); 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]) 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 INC (i); Emit.OpII ("@, /* len@ */\n", String.Length (p.proc.name), i); EmitChars (p.proc.name); 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; Emit.OpI ("coverage.lines[@]++;\n", line - minLine); <* ASSERT used[line] *> END CountLine; PROCEDURE CountProcedure (v: Value.T) = BEGIN IF (NOT Host.coverage) THEN RETURN END; Emit.OpN ("coverage.cnt_@++;\n", v); END CountProcedure; BEGIN END Coverage.