Думаю, что на данном этапе я приостановлю эту работу. Вылизывать можно до безконечности, но вроде сейчас инструмент уже более-менее сносно работает. Идея в том, что можно печатать либо объект (ANY), используя динамическую инфу о его типе, либо модуль (состояние модуля), либо стек выполнения, снятый за счёт вставки особого вызова в код процедуры.
При этом рекурсивно печатается граф объектов, записей и массивов с отслеживанием повторов. Если какой-то адрес один раз напечатался, то при повторной печати вместо рекурсивной печати содержимого по этому адресу выводится просто ^адрес.
Некоторые типы данных не печатаются.
Также можно задать ограничение на глубину рекурсии и на длину массивов. При превышении глубины печатается некий замещающий текст. Идея в целом позаимствована из лиспового print, print-length, print-circle и т.п. См, напр,
http://filonenko-mikhail.github.io/cltl ... 139-188031Печать выделяет (как я надеюсь) данные только на стеке, поэтому теоретически можно применять её в обработчике TRAPов вместо стандартной.
Пример модуля Proba:
Код:
MODULE Proba; IMPORT Commands, Modules, PodrobnajaPechatq, Streams, Objects (* ,Debugging ,SYSTEM , Heaps, Reflection *);
TYPE myRec1* = POINTER TO RECORD
txt* : ARRAY 7 OF CHAR END;
TYPE myRecPtrType* = POINTER TO myRecType;
myRecType* = RECORD
text* : ARRAY 4 OF CHAR;
pointerToArrayOfAny* : POINTER TO ARRAY OF ANY END;
TYPE myObjType* = OBJECT
VAR mrt* : myRecType;
END myObjType;
PROCEDURE zin() : myRecPtrType;
VAR item : myRec1; res : myRecPtrType;
BEGIN
NEW(res);
NEW(res.pointerToArrayOfAny, 2);
NEW(item);
item.txt := "ITEM0";
res.pointerToArrayOfAny[0] := item;
NEW(item);
item.txt := "ITEM1";
res.pointerToArrayOfAny[1] := item;
RETURN res END zin;
VAR ptr0 : POINTER TO ARRAY OF myRecPtrType;
VAR ptr0a : POINTER TO ARRAY OF myRecType;
VAR ptr1 : POINTER TO ARRAY 4 OF POINTER TO ARRAY 3 OF CHAR;
VAR ptr2 : POINTER TO ARRAY OF CHAR;
VAR ptr3 : POINTER TO ARRAY 4 OF CHAR;
VAR a3 : ARRAY 5 OF CHAR;
VAR ptr5 : POINTER TO ARRAY 5 OF BOOLEAN;
VAR a5 : ARRAY 5 OF BOOLEAN;
VAR p6 : POINTER TO ARRAY OF ARRAY 4 OF CHAR;
VAR p9 : POINTER TO ARRAY OF ANY;
VAR any10 : ANY;
VAR any11 : ANY;
PROCEDURE z*(context : Commands.Context);
VAR m: Modules.Module;
VAR res : LONGINT; msg : ARRAY 4096 OF CHAR; o : Streams.Writer;
(* ty : Modules.TypeDesc; *)
k : PodrobnajaPechatq.KontekstPechati;
LOCALobj7 : myObjType;
LOCALany8 : ANY;
BEGIN
o := context.out;
PodrobnajaPechatq.ZadajjKontekstPechatiPoUmolch(k);
k.w := o;
PrimerStackTraceBack(o);
o.Ln; o.String("======== TraceBack END =========");
o.String("Loading the module"); o.Ln;
m := Modules.ThisModule("Proba", res, msg);
IF (m = NIL) OR (res # 0) THEN
o.String("z: Failed to load module:"); o.String(msg); o.Ln;
RETURN END;
NEW(ptr0, 3);
NEW(ptr0[0]);
ptr0[0].text := "LLL";
NEW(ptr0[2]);
ptr0[2].text := "SSS";
o.Ln; o.String("======= PodrobnajaPechatq.PechVKontektse ptr0 ========: "); o.Ln; PodrobnajaPechatq.PechVKontekste(k, ptr0);
NEW(ptr0a,3);
ptr0a[0].text := "LLL";
ptr0a[2].text := "SSS";
o.Ln; o.String("======= PodrobnajaPechatq.PechVKontektse ptr0a ========: "); o.Ln; PodrobnajaPechatq.PechVKontekste(k, ptr0a);
NEW(ptr1);
(* o.String("Address of ptr1 = "); o.Address(SYSTEM.VAL(ADDRESS, ptr1)); o.Ln; *)
NEW(ptr1[0]);
(* o.String("Value of ptr1[0] = "); o.Address(SYSTEM.VAL(ADDRESS, ptr1[0])); o.Ln; *)
ptr1[0]^ := "AB";
NEW(ptr1[2]);
(* o.String("Value of ptr.1[2] = "); o.Address(SYSTEM.VAL(ADDRESS, ptr1[1])); o.Ln; *)
ptr1[2]^ := "CD";
ptr1[3] := ptr1[2];
o.Ln; o.String("======= PodrobnajaPechatq.PechVKontektse ptr1 ========: "); o.Ln; PodrobnajaPechatq.PechVKontekste(k, ptr1);
NEW(ptr2,3);
ptr2^ := "AB";
o.Ln; o.String("======= PodrobnajaPechatq.PechVKontektse ptr2 ========: "); o.Ln; PodrobnajaPechatq.PechVKontekste(k, ptr2);
NEW(ptr3);
ptr3^ := "DEF";
o.Ln; o.String("======= PodrobnajaPechatq.PechVKontektse ptr3 ========: "); o.Ln; PodrobnajaPechatq.PechVKontekste(k, ptr3);
a3 := "ABC";
NEW(ptr5);
ptr5[0] := TRUE;
ptr5[4] := TRUE;
a5[0] := TRUE;
a5[4] := TRUE;
(* o.String("========= PodrobnajaPechatq.Report ==========="); o.Ln;
Reflection.Report(o, m.refs, 0); *)
NEW(p6, 2);
p6[0] := "AAA";
p6[1] := "BBB";
NEW(LOCALobj7);
LOCALany8 := LOCALobj7;
NEW(LOCALobj7);
NEW(p9, 2);
p9[0] := LOCALobj7;
p9[1] := LOCALany8;
any10 := zin();
any11 := Objects.ActiveObject();
(* o.Ln; o.String("========= PodrobnajaPechatq.Pech(o, obj) ======="); o.Ln;
PodrobnajaPechatq.Pech(o, obj); *)
o.Ln; o.String("========= PodrobnajaPechatq.ModuleState ======="); o.Ln;
PodrobnajaPechatq.ModuleState(o, m);
(* o.String("====== Printing individual values =========="); o.Ln;
ASSERT(SYSTEM.TYPECODE(myPtrToRecordVar) = SYSTEM.TYPECODE(myPtrToRecordType));
PodrobnajaPechatq.Pech(o, myPtrToRecordVar);
(* Alqternativa:
PodrobnajaPechatq.PechPoAdr(o, SYSTEM.VAL(ADDRESS,myPtrToRecordVar), SYSTEM.TYPECODE(myPtrToRecordVar)); *)
PodrobnajaPechatq.PechPoAdr(o, ADDRESS OF myRecordVar, SYSTEM.TYPECODE(myRecordVar)); *)
END z;
PROCEDURE PrimerStackTraceBack(o : Streams.Writer);
VAR m : ARRAY 5 OF INTEGER;
BEGIN
m[0] := 5;
m[4] := 33;
PodrobnajaPechatq.TraceBack(o, 1, 1);
END PrimerStackTraceBack;
END Proba.
(SystemTools.DoCommands
SystemTools.FreeDownTo PodrobnajaPechatq~
Proba.z~
WMKernelLog.Open~~)
В результате выполнения команды печатается примерно такая простыня.
Код:
(StackTraceBack 1 1
(KADR 0 PodrobnajaPechatq.TraceBack:28 pc=248280478 [0ECC759EH] = 248280450 + 28 crc=00000000
)
(KADR 1 Proba.PrimerStackTraceBack:41 pc=248332873 [0ECD4249H] = 248332832 + 41 crc=00000000
v o
( r.STz &0EABE160 Streams.Writer ~(
f tail 67
f buf (&0EABE1A0 [128] CHAR : "")
f res 0
f send (DELEGATE)
f sent 394))
v m (&0B8DAED2 [5] INTEGER : (
0: 5
1: 0
2: 0
3: 0
4: 33))
)
(KADR 2 Proba.z:86 pc=248330487 [0ECD38F7H] = 248330401 + 86 crc=00000000
)
(KADR 3 Commands.Runner.@Body:718 pc=4430640 [00439B30H] = 4429922 + 718 crc=00000000
){ [P 13896 Commands.Runner] 22:38:43}
======== TraceBack END =========Loading the module
======= PodrobnajaPechatq.PechVKontektse ptr0 ========:
(&0ECD5420 DT[3] : (
0: (&0ECD5460 :vidObjqekta 6 :type Proba.myRecType (
f text "LLL"
f pointerToArrayOfAny NIL))
1: NIL
2: (&0ECD54A0 :vidObjqekta 6 :type Proba.myRecType (
f text "SSS"
f pointerToArrayOfAny NIL)))
======= PodrobnajaPechatq.PechVKontektse ptr0a ========:
(IzuchiMassivSUkazateljamiVElemente: vidObjqektaMassivSElementamiIzvestnogoTipa)
(&0ECD54E0 :vidObjqekta 5 :type Proba.myRecType (
f text ""
f pointerToArrayOfAny NIL))
======= PodrobnajaPechatq.PechVKontektse ptr1 ========:
(&0ECD5540 DT[4] : (
0: (neKhvataetST 0ECD5580)
1: NIL
2: (neKhvataetST 0ECD55C0)
3: (neKhvataetST 0ECD55C0))
======= PodrobnajaPechatq.PechVKontektse ptr2 ========:
(neKhvataetST 0ECD5600)
======= PodrobnajaPechatq.PechVKontektse ptr3 ========:
(neKhvataetST 0ECD5640)
========= PodrobnajaPechatq.ModuleState =======
(SOSTOJANIE MODULJA 'Proba'
v ptr0 (&0ECD5420 [3] (POINTER TO DT RECORD)) : (
0:
( r.STz &0ECD5460 Proba.myRecType ~(
f text "LLL"
f pointerToArrayOfAny NIL))
1: NIL
2:
( r.STz &0ECD54A0 Proba.myRecType ~(
f text "SSS"
f pointerToArrayOfAny NIL))))
v ptr0a (&0ECD54E0 [3] (RECORD Proba.myRecType) : (
0: Record ((
f text "LLL"
f pointerToArrayOfAny NIL))
1: Record ((
f text ""
f pointerToArrayOfAny NIL))
2: Record ((
f text "SSS"
f pointerToArrayOfAny NIL))))
v ptr1 (&0ECD5540 [4] POINTER TOARRAY 3 OF CHAR : (
0: (&0ECD5580 [3] CHAR : "AB")
1: NIL
2: (&0ECD55C0 [3] CHAR : "CD")
3: (^0ECD55C0)))
v ptr2 (&0ECD5600 [3] CHAR : "AB")
v ptr3 (&0ECD5640 [4] CHAR : "DEF")
v a3 "ABC"
v ptr5 (&0ECD5680 [5] BOOLEAN : (
0: true
1: false
2: false
3: false
4: true))
v a5 (&0ECD42B0 [5] BOOLEAN : (
0: true
1: false
2: false
3: false
4: true))
)