Generic.Reflection.Mod 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  1. MODULE Reflection;
  2. (** (c) Felix Friedrich, ETH Zurich, 2016 -- Reflection with more structured references section emitted by FoxCompiler *)
  3. IMPORT Modules, Streams, SYSTEM, Machine, Heaps, Objects, Trace;
  4. CONST
  5. ShowAllProcs = TRUE;
  6. MaxFrames = 128;
  7. MaxString = 64;
  8. MaxArray = 8;
  9. MaxCols = 70;
  10. Sep = " ";
  11. SepLen = 2;
  12. LineDelay = 0;
  13. CONST
  14. sfTypeNone* = 0X;
  15. sfTypeCHAR* = 01X;
  16. sfTypeCHAR8* = 02X;
  17. sfTypeCHAR16* = 03X;
  18. sfTypeCHAR32* = 04X;
  19. sfTypeRANGE* = 05X;
  20. sfTypeSHORTINT* = 06X;
  21. sfTypeINTEGER* = 07X;
  22. sfTypeLONGINT* = 08X;
  23. sfTypeHUGEINT* = 09X;
  24. sfTypeWORD* = 0AX;
  25. sfTypeLONGWORD* = 0BX;
  26. sfTypeSIGNED8* = 0CX;
  27. sfTypeSIGNED16* = 0DX;
  28. sfTypeSIGNED32* = 0EX;
  29. sfTypeSIGNED64* = 0FX;
  30. sfTypeUNSIGNED8* = 10X;
  31. sfTypeUNSIGNED16* = 11X;
  32. sfTypeUNSIGNED32* = 12X;
  33. sfTypeUNSIGNED64* = 13X;
  34. sfTypeREAL* = 14X;
  35. sfTypeLONGREAL* = 15X;
  36. sfTypeCOMPLEX* = 16X;
  37. sfTypeLONGCOMPLEX* = 17X;
  38. sfTypeBOOLEAN* = 18X;
  39. sfTypeSET* = 19X;
  40. sfTypeANY* = 1AX;
  41. sfTypeOBJECT* = 1BX;
  42. sfTypeBYTE* = 1CX;
  43. sfTypeADDRESS* = 1DX;
  44. sfTypeSIZE* = 1EX;
  45. sfTypeRecord* = 20X;
  46. sfTypePointerToRecord* = 21X;
  47. sfTypePointerToArray* = 22X;
  48. sfTypeOpenArray* = 23X;
  49. sfTypeStaticArray* = 24X;
  50. sfTypeDynamicArray* = 25X;
  51. sfTypeMathStaticArray* = 26X;
  52. sfTypeMathOpenArray* = 27X;
  53. sfTypeMathTensor* = 28X;
  54. sfTypeDelegate* = 29X;
  55. sfTypeENUM* = 2AX;
  56. sfTypeCell = 2BX;
  57. sfTypePort = 2CX;
  58. sfInPort = 0X;
  59. sfOutPort = 1X;
  60. sfValPar* = 0X;
  61. sfVarPar* = 1X;
  62. sfConstPar* = 2X;
  63. sfScopeBegin* = 0F0X;
  64. sfScopeEnd* = 0F1X;
  65. sfProcedure* = 0F2X;
  66. sfVariable* = 0F3X;
  67. sfParameter* = 0F4X;
  68. sfTypeDeclaration* = 0F5X;
  69. (*
  70. References section format:
  71. Scope = sfScopeBegin {variable:Variable} {procedure:Procedure} {typeDecl:TypeDeclaration} sfScopeEnd
  72. Procedure = sfProcedure prevSymbolOffset:SIZE name:String start:ADR end:ADR returnType:Type {parameter:Parameter} Scope
  73. Variable = sfVariable prevSymbolOffset:SIZE name:String (address:ADDRESS | offset:SIZE) type:Type
  74. Parameter = sfParameter prevSymbolOffset:SIZE name:String (rfVar | rfConst | rfVal) offset:SIZE type:Type
  75. TypeDeclaration = sfTypeDeclaration prevSymbolOffset:SIZE name:String typeInfo:ADR Scope
  76. *)
  77. VAR
  78. modes: ARRAY 25 OF CHAR;
  79. TYPE
  80. Name = ARRAY 128 OF CHAR;
  81. PROCEDURE CheckHeapAddress(address: ADDRESS): BOOLEAN;
  82. BEGIN
  83. RETURN Machine.ValidHeapAddress(address);
  84. END CheckHeapAddress;
  85. PROCEDURE Wait(w: Streams.Writer);
  86. VAR i: LONGINT;
  87. BEGIN
  88. IF LineDelay > 0 THEN
  89. FOR i := 0 TO LineDelay DO END;
  90. w.Update
  91. END;
  92. END Wait;
  93. PROCEDURE Expect(b: BOOLEAN): BOOLEAN;
  94. BEGIN
  95. IF ~b THEN Trace.String("Format error in references section"); Trace.Ln END;
  96. RETURN b;
  97. END Expect;
  98. (* consume a char from the byte stream *)
  99. PROCEDURE GetChar*(refs: Modules.Bytes; VAR offset: LONGINT): CHAR;
  100. VAR c: CHAR;
  101. BEGIN
  102. IF ~Expect(offset < LEN(refs)) THEN RETURN 0X END;
  103. c := refs[offset];
  104. INC(offset);
  105. RETURN c;
  106. END GetChar;
  107. (* skip a char in the byte stream *)
  108. PROCEDURE SkipChar*(VAR offset: LONGINT);
  109. BEGIN
  110. INC(offset, SIZEOF(CHAR));
  111. END SkipChar;
  112. (* consume an address in the byte stream *)
  113. PROCEDURE GetAddress*(refs: Modules.Bytes; VAR offset: LONGINT): ADDRESS;
  114. VAR adr: ADDRESS; i: LONGINT;
  115. BEGIN
  116. IF ~Expect(offset < LEN(refs)) THEN RETURN 0 END;
  117. FOR i := 0 TO SIZEOF(ADDRESS)-1 DO
  118. SYSTEM.PUT8(ADDRESSOF(adr)+i, GetChar(refs, offset));
  119. END;
  120. RETURN adr;
  121. END GetAddress;
  122. (* skip an address in the byte stream *)
  123. PROCEDURE SkipAddress*(VAR offset: LONGINT);
  124. BEGIN
  125. INC(offset, SIZEOF(ADDRESS));
  126. END SkipAddress;
  127. (* consume a size in the byte stream *)
  128. PROCEDURE GetSize*(refs: Modules.Bytes; VAR offset: LONGINT): SIZE;
  129. VAR size: SIZE; i: LONGINT;
  130. BEGIN
  131. IF ~Expect(offset < LEN(refs)) THEN RETURN 0 END;
  132. FOR i := 0 TO SIZEOF(SIZE)-1 DO
  133. SYSTEM.PUT8(ADDRESSOF(size)+i, refs[offset]);
  134. INC(offset);
  135. END;
  136. RETURN size;
  137. END GetSize;
  138. (* skip a size in the byte stream *)
  139. PROCEDURE SkipSize*(VAR offset: LONGINT);
  140. BEGIN
  141. INC(offset, SIZEOF(SIZE));
  142. END SkipSize;
  143. (* consume a string in the byte stream *)
  144. PROCEDURE GetString*(refs: Modules.Bytes; VAR offset: LONGINT; VAR string: ARRAY OF CHAR);
  145. VAR ch: CHAR; i: LONGINT;
  146. BEGIN
  147. i := 0;
  148. REPEAT
  149. ch := GetChar(refs, offset);
  150. string[i] := ch;
  151. INC(i);
  152. UNTIL ch = 0X;
  153. END GetString;
  154. (* skip a string in the byte stream *)
  155. PROCEDURE SkipString*(refs: Modules.Bytes; VAR offset: LONGINT);
  156. BEGIN
  157. WHILE(refs[offset] # 0X) DO INC(offset) END; INC(offset);
  158. END SkipString;
  159. (* extract a full name from the byte stream by traversing up the symbols in their scopes *)
  160. PROCEDURE GetFullName*(refs: Modules.Bytes; offset: LONGINT; VAR name: ARRAY OF CHAR);
  161. VAR n: LONGINT;
  162. PROCEDURE Traverse(offset: LONGINT);
  163. VAR c: CHAR;
  164. BEGIN
  165. IF offset >= 0 THEN
  166. c := GetChar(refs, offset);
  167. IF (c = sfProcedure) OR (c=sfVariable) OR (c=sfParameter) OR (c=sfTypeDeclaration) THEN
  168. Traverse(GetSize(refs, offset));
  169. END;
  170. IF (n > 0) & (n<LEN(name)) THEN name[n] := "."; INC(n); END;
  171. WHILE (n<LEN(name)) & (refs[offset] # 0X) DO
  172. name[n] := refs[offset];
  173. INC(n); INC(offset);
  174. END;
  175. END;
  176. END Traverse;
  177. BEGIN
  178. n := 0;
  179. Traverse(offset);
  180. name[n] := 0X;
  181. END GetFullName;
  182. (* "lock free" version of Modules.ThisTypeByAdr *)
  183. PROCEDURE ThisTypeByAdr(adr: ADDRESS; VAR m: Modules.Module; VAR t: Modules.TypeDesc);
  184. BEGIN
  185. IF adr # 0 THEN
  186. SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
  187. IF CheckHeapAddress(adr) THEN
  188. t := SYSTEM.VAL(Modules.TypeDesc, adr);
  189. m := t.mod;
  190. ELSE
  191. m := NIL; t := NIL
  192. END
  193. ELSE
  194. m := NIL; t := NIL
  195. END
  196. END ThisTypeByAdr;
  197. (* output type descriptor information *)
  198. PROCEDURE WriteType*(w: Streams.Writer; adr: ADDRESS);
  199. VAR module: Modules.Module; typeDesc: Modules.TypeDesc;
  200. BEGIN
  201. IF CheckHeapAddress(adr) THEN
  202. ThisTypeByAdr(adr, module, typeDesc);
  203. IF module # NIL THEN
  204. w.String(module.name);
  205. ELSE
  206. w.String("NIL"); RETURN
  207. END;
  208. w.String(".");
  209. IF typeDesc # NIL THEN
  210. IF typeDesc.name = "" THEN
  211. w.String("ANONYMOUS")
  212. ELSE
  213. w.String(typeDesc.name);
  214. END;
  215. ELSE
  216. w.String("NIL");
  217. END;
  218. ELSE
  219. w.String("UNKNOWN");
  220. END;
  221. END WriteType;
  222. (* Write the specified procedure name and returns parameters for use with Variables *)
  223. PROCEDURE WriteProc0(w: Streams.Writer; mod: Modules.Module; pc, fp: ADDRESS; VAR refs: Modules.Bytes; VAR refpos: LONGINT; VAR base: ADDRESS);
  224. VAR ch: CHAR; startpc, end: ADDRESS; offset: LONGINT; name: Name;
  225. BEGIN
  226. refpos := -1;
  227. IF mod = NIL THEN
  228. IF pc = 0 THEN w.String("NIL")
  229. ELSE
  230. w.String("Unknown PC="); w.Address(pc); w.Char("H")
  231. END;
  232. IF fp # -1 THEN
  233. w.String(" FP="); w.Address(fp); w.Char("H")
  234. END
  235. ELSE
  236. w.String(mod.name);
  237. TRACE(pc);
  238. refs := mod.refs;
  239. IF FindByAdr(refs, refpos, pc) THEN
  240. offset := refpos;
  241. IF GetChar(refs, offset) = sfProcedure THEN
  242. w.Char(".");
  243. SkipSize(offset);
  244. SkipString(refs, offset);
  245. GetFullName(refs, refpos, name);
  246. startpc := GetAddress(refs, offset);
  247. end := GetAddress(refs, offset);
  248. w.String(name);
  249. w.Char(":"); w.Int(LONGINT(pc-startpc),1);
  250. base := fp; (*! only for local !! *)
  251. refpos := offset;
  252. END;
  253. END;
  254. w.String(" pc="); w.Int(LONGINT(pc),1); w.String(" ["); w.Address (pc); w.String("H]");
  255. w.String(" = "); w.Int(LONGINT(startpc),1); w.String(" + "); w.Int(LONGINT(pc-startpc),1);
  256. w.String(" crc="); w.Hex(mod.crc,-8);
  257. (*Wait(w);*)
  258. END
  259. END WriteProc0;
  260. PROCEDURE WriteBasicValue*(w: Streams.Writer; type: CHAR; adr: ADDRESS; VAR size: SIZE);
  261. VAR
  262. b: BOOLEAN;
  263. c: CHAR; c8: CHAR8; c16: CHAR16; c32: CHAR32;
  264. s: SHORTINT; i: INTEGER; l: LONGINT; h: HUGEINT;
  265. sz: SIZE; a: ADDRESS;
  266. word: WORD; lword: LONGWORD;
  267. s8: SIGNED8; s16: SIGNED16; s32: SIGNED32; s64: SIGNED64;
  268. u8: UNSIGNED8; u16: UNSIGNED16; u32: UNSIGNED32; u64: UNSIGNED64;
  269. r: REAL; x: LONGREAL;
  270. cplx: COMPLEX; lcplx: LONGCOMPLEX;
  271. set: SET;
  272. byte: SYSTEM.BYTE;
  273. PROCEDURE Signed(i: HUGEINT);
  274. BEGIN
  275. w.Int(i,1);
  276. END Signed;
  277. PROCEDURE Unsigned(i: HUGEINT; size: LONGINT);
  278. BEGIN
  279. w.Hex(i,-2*size);
  280. END Unsigned;
  281. BEGIN
  282. CASE type OF
  283. | sfTypePointerToRecord, sfTypeANY, sfTypeOBJECT:
  284. size := SIZEOF(ADDRESS);
  285. SYSTEM.GET(adr, a); Unsigned(a, SIZEOF(ADDRESS));
  286. | sfTypeBOOLEAN:
  287. size := SIZEOF(BOOLEAN);
  288. SYSTEM.GET(adr, b); IF b THEN w.String("true") ELSE w.String("false") END;
  289. | sfTypeCHAR, sfTypeCHAR8:
  290. size := SIZEOF(CHAR);
  291. SYSTEM.GET(adr, c); IF (c > " ") & (c <= "~") THEN w.Char( c ); ELSE w.Hex( ORD( c ), -2 ); w.Char( "X" ) END;
  292. | sfTypeCHAR16:
  293. size := SIZEOF(CHAR16);
  294. SYSTEM.GET(adr, i); w.Hex(i,-4); w.Char("X");
  295. | sfTypeCHAR32:
  296. size := SIZEOF(CHAR32);
  297. SYSTEM.GET(adr, l); w.Hex(l,-8); w.Char("X");
  298. | sfTypeSHORTINT:
  299. size := SIZEOF(SHORTINT);
  300. SYSTEM.GET(adr, s); Signed(s);
  301. | sfTypeINTEGER:
  302. size := SIZEOF(INTEGER);
  303. SYSTEM.GET(adr, i); Signed(i);
  304. | sfTypeLONGINT:
  305. size := SIZEOF(LONGINT);
  306. SYSTEM.GET(adr, l); Signed(l);
  307. | sfTypeHUGEINT:
  308. size := SIZEOF(HUGEINT);
  309. SYSTEM.GET(adr, h); Signed(h);
  310. | sfTypeWORD:
  311. size := SIZEOF(WORD);
  312. SYSTEM.GET(adr, word); Signed(word);
  313. | sfTypeLONGWORD:
  314. size := SIZEOF(LONGWORD);
  315. SYSTEM.GET(adr, lword); Signed(lword);;
  316. | sfTypeSIGNED8:
  317. size := SIZEOF(SIGNED8);
  318. SYSTEM.GET(adr, s8); Signed(s8);
  319. | sfTypeSIGNED16:
  320. size := SIZEOF(SIGNED16);
  321. SYSTEM.GET(adr, s16); Signed(s16);
  322. | sfTypeSIGNED32:
  323. size := SIZEOF(SIGNED32);
  324. SYSTEM.GET(adr, s32); Signed(s32);
  325. | sfTypeSIGNED64:
  326. size := SIZEOF(SIGNED64);
  327. SYSTEM.GET(adr, s64); Signed(s64);
  328. | sfTypeUNSIGNED8:
  329. size := SIZEOF(UNSIGNED8);
  330. SYSTEM.GET(adr, u8); Unsigned(u8, SIZEOF(UNSIGNED8));
  331. | sfTypeUNSIGNED16:
  332. size := SIZEOF(UNSIGNED16);
  333. SYSTEM.GET(adr, u16); Unsigned(u8, SIZEOF(UNSIGNED16));
  334. | sfTypeUNSIGNED32:
  335. size := SIZEOF(UNSIGNED32);
  336. SYSTEM.GET(adr, u32); Unsigned(u8, SIZEOF(UNSIGNED32));
  337. | sfTypeUNSIGNED64:
  338. size := SIZEOF(UNSIGNED64);
  339. SYSTEM.GET(adr, u64); Unsigned(u8, SIZEOF(UNSIGNED64));
  340. | sfTypeREAL:
  341. size := SIZEOF(REAL);
  342. SYSTEM.GET(adr, r); w.Float(r,7);
  343. | sfTypeLONGREAL:
  344. size := SIZEOF(LONGREAL);
  345. SYSTEM.GET(adr, x); w.Float(x,13);
  346. | sfTypeCOMPLEX:
  347. size := SIZEOF(COMPLEX);
  348. SYSTEM.GET(adr, cplx); w.Float(RE(cplx),7); w.String("+ i*"); w.Float(IM(cplx),7);
  349. | sfTypeLONGCOMPLEX:
  350. size := SIZEOF(LONGCOMPLEX);
  351. SYSTEM.GET(adr, x); w.Float(x,13); SYSTEM.GET(adr + SIZEOF(LONGREAL), x); w.String("+ i*"); w.Float(x,13);
  352. | sfTypeSET:
  353. size := SIZEOF(SET);
  354. SYSTEM.GET(adr, set); w.Set(set);
  355. | sfTypeBYTE:
  356. size := SIZEOF(SYSTEM.BYTE);
  357. SYSTEM.GET(adr, c); Unsigned(ORD(c), 1);
  358. | sfTypeRANGE:
  359. size := SIZEOF(RANGE);
  360. SYSTEM.GET(adr, sz); Unsigned(sz,SIZEOF(SIZE)); w.String(".."); Unsigned(sz, SIZEOF(SIZE));
  361. | sfTypeADDRESS:
  362. size := SIZEOF(ADDRESS);
  363. SYSTEM.GET(adr, a); Unsigned(a, SIZEOF(ADDRESS));
  364. | sfTypeSIZE:
  365. size := SIZEOF(SIZE);
  366. SYSTEM.GET(adr, sz); Signed(sz); w.String("["); Unsigned(sz, SIZEOF(SIZE)); w.String("]");
  367. | sfTypeENUM:
  368. SYSTEM.GET(adr, word); Signed(word);
  369. | sfTypePort:
  370. SYSTEM.GET(adr, a); Unsigned(a, SIZEOF(ADDRESS));
  371. ELSE
  372. w.String("UNKOWN TYPE "); Unsigned(ORD(type),1);
  373. END;
  374. w.Update;
  375. END WriteBasicValue;
  376. PROCEDURE WriteValueString*(w: Streams.Writer; adr: ADDRESS; maxLen: LONGINT);
  377. CONST MaxString = 32;
  378. VAR ch: CHAR;
  379. BEGIN
  380. IF maxLen > MaxString THEN maxLen := MaxString END;
  381. w.Char('"');
  382. IF CheckHeapAddress(adr) THEN
  383. LOOP
  384. IF maxLen <= 0 THEN EXIT END;
  385. SYSTEM.GET(adr, ch);
  386. IF (ch < " ") OR (ch > "~") THEN EXIT END;
  387. w.Char(ch);
  388. INC(adr);
  389. DEC(maxLen);
  390. END;
  391. END;
  392. w.Char('"');
  393. END WriteValueString;
  394. PROCEDURE WriteValue*(w: Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT; adr: ADDRESS);
  395. VAR type: CHAR; a: ADDRESS; size: SIZE; len: SIZE;
  396. BEGIN
  397. type := GetChar(refs, offset);
  398. CASE type OF
  399. sfTypeNone:
  400. | sfTypePointerToRecord, sfTypeANY, sfTypeOBJECT:
  401. WriteBasicValue(w,type, adr, size);
  402. SYSTEM.GET(adr, a);
  403. IF CheckHeapAddress(a) THEN
  404. SYSTEM.GET(a + Heaps.TypeDescOffset, a);
  405. w.String(" (");
  406. WriteType(w,a);
  407. w.String(")");
  408. END;
  409. | sfTypePointerToArray:
  410. WriteBasicValue(w, sfTypeANY, adr, size);
  411. w.String("->");
  412. SYSTEM.GET(adr, a);
  413. WriteValue(w,refs,offset, a);
  414. (*SkipType(refs, offset);*)
  415. | sfTypeOpenArray:
  416. IF refs[offset] = sfTypeCHAR THEN (* ARRAY OF CHAR *)
  417. WriteValueString(w, adr, MaxString);
  418. END;
  419. SkipType(refs, offset);
  420. | sfTypeStaticArray:
  421. len := GetSize(refs, offset);
  422. IF refs[offset] = sfTypeCHAR THEN (* ARRAY x OF CHAR *)
  423. WriteValueString(w, adr, len);
  424. END;
  425. SkipType(refs, offset);
  426. | sfTypeDynamicArray:
  427. w.String("...");
  428. SkipType(refs, offset);
  429. | sfTypeMathOpenArray:
  430. w.String("...");
  431. SkipType(refs, offset);
  432. | sfTypeMathStaticArray:
  433. w.String("...");
  434. SkipSize(offset); SkipType(refs, offset);
  435. | sfTypeMathTensor:
  436. w.String("...");
  437. SkipType(refs, offset);
  438. | sfTypeRecord:
  439. w.String("...");
  440. w.String("(");
  441. a := GetAddress(refs, offset);
  442. WriteType(w,a);
  443. w.String(")");
  444. | sfTypeDelegate:
  445. WHILE refs[offset] = sfParameter DO SkipParameter(refs, offset) END;
  446. SkipType(refs, offset);
  447. | sfTypePort:
  448. WriteBasicValue(w, type, adr, size);
  449. SkipChar(offset);
  450. ELSE
  451. WriteBasicValue(w, type, adr, size);
  452. END;
  453. w.Update;
  454. END WriteValue;
  455. PROCEDURE WriteVariable*(w: Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT; base: ADDRESS);
  456. VAR name: ARRAY 128 OF CHAR; adr: LONGINT; prevScope: SIZE;
  457. BEGIN
  458. IF ~Expect(GetChar(refs, offset) = sfVariable) THEN RETURN END;
  459. prevScope := GetSize(refs, offset);
  460. GetString(refs, offset, name);
  461. w.String(Sep); w.String(name); w.Char("=");
  462. adr := GetSize(refs, offset);
  463. IF prevScope <0 THEN (* module scope *)
  464. base := 0
  465. END;
  466. WriteValue(w, refs, offset, adr+base);
  467. END WriteVariable;
  468. PROCEDURE WriteParameter*(w: Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT; base: ADDRESS);
  469. VAR name: ARRAY 128 OF CHAR; adr: LONGINT; prevScope: SIZE; c: CHAR;
  470. BEGIN
  471. IF ~Expect(GetChar(refs, offset) = sfParameter) THEN RETURN END;
  472. prevScope := GetSize(refs, offset);
  473. GetString(refs, offset, name);
  474. w.String(Sep); w.String(name); w.Char("=");
  475. adr := GetSize(refs, offset);
  476. c := GetChar(refs, offset); (*! check for varpar *)
  477. WriteValue(w, refs, offset, adr+base);
  478. END WriteParameter;
  479. (* write variables taking meta information from stream in stream at offset, potentially stored at base address
  480. *)
  481. PROCEDURE WriteVariables*(w: Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT; base: ADDRESS);
  482. VAR count: LONGINT;
  483. BEGIN
  484. WHILE refs[offset] = sfVariable DO
  485. WriteVariable(w, refs, offset, base); w.Ln;
  486. (*INC(count); *)
  487. END;
  488. IF count > 0 THEN w.Ln; Wait(w); END;
  489. END WriteVariables;
  490. (* write variables taking meta information from stream in stream at offset, potentially stored at base address
  491. *)
  492. PROCEDURE WriteParameters*(w: Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT; base: ADDRESS);
  493. VAR count: LONGINT;
  494. BEGIN
  495. WHILE refs[offset] = sfParameter DO
  496. WriteParameter(w, refs, offset, base); w.Ln;
  497. (*INC(count); *)
  498. END;
  499. IF count > 0 THEN w.Ln; Wait(w); END;
  500. END WriteParameters;
  501. (* skip type metadata in stream *)
  502. PROCEDURE SkipType*(refs: Modules.Bytes; VAR offset: LONGINT);
  503. VAR size: SIZE; adr: LONGINT; c: CHAR;
  504. BEGIN
  505. c := GetChar(refs, offset);
  506. CASE c OF
  507. sfTypeNone .. sfTypeSIZE:
  508. | sfTypePointerToRecord:
  509. | sfTypePointerToArray: SkipType(refs, offset);
  510. | sfTypeOpenArray: SkipType(refs, offset);
  511. | sfTypeStaticArray: SkipSize(offset); SkipType(refs, offset);
  512. | sfTypeDynamicArray: SkipType(refs, offset);
  513. | sfTypeMathOpenArray: SkipType(refs, offset);
  514. | sfTypeMathStaticArray: SkipSize(offset); SkipType(refs, offset);
  515. | sfTypeMathTensor: SkipType(refs, offset);
  516. | sfTypeRecord: SkipSize(offset);
  517. | sfTypeDelegate:
  518. WHILE refs[offset] = sfParameter DO SkipParameter(refs, offset) END;
  519. SkipType(refs, offset);
  520. | sfTypeENUM:
  521. | sfTypePort: SkipChar(offset);
  522. ELSE (* ?? *)
  523. END;
  524. END SkipType;
  525. (* skip procedure metadata in stream *)
  526. PROCEDURE SkipProcedure*(refs: Modules.Bytes; VAR offset: LONGINT);
  527. BEGIN
  528. IF ~Expect(GetChar(refs, offset) = sfProcedure) THEN RETURN END;
  529. SkipSize(offset);
  530. SkipString(refs, offset);
  531. SkipAddress(offset);
  532. SkipAddress(offset);
  533. WHILE (refs[offset] = sfParameter) DO SkipParameter(refs, offset) END;
  534. SkipType(refs, offset);
  535. SkipScope(refs, offset);
  536. END SkipProcedure;
  537. (* skip parameter meta data in stream *)
  538. PROCEDURE SkipParameter*(refs: Modules.Bytes; VAR offset: LONGINT);
  539. VAR name: ARRAY 128 OF CHAR; adr: LONGINT; c: CHAR;
  540. BEGIN
  541. IF ~Expect(GetChar(refs, offset) = sfParameter) THEN RETURN END;
  542. SkipSize(offset);
  543. SkipString(refs, offset);
  544. SkipSize(offset);
  545. SkipChar(offset);
  546. SkipType(refs, offset);
  547. END SkipParameter;
  548. (* skip variable metadata in stream *)
  549. PROCEDURE SkipVariable*(refs: Modules.Bytes; VAR offset: LONGINT);
  550. BEGIN
  551. IF ~Expect(GetChar(refs, offset) = sfVariable) THEN RETURN END;
  552. SkipSize(offset);
  553. SkipString(refs, offset);
  554. SkipSize(offset);
  555. SkipType(refs, offset);
  556. END SkipVariable;
  557. (* skip type declaration meta data in stream *)
  558. PROCEDURE SkipTypeDeclaration*(refs: Modules.Bytes; VAR offset: LONGINT);
  559. BEGIN
  560. IF ~Expect(GetChar(refs, offset) = sfTypeDeclaration) THEN RETURN END;
  561. SkipSize(offset);
  562. SkipString(refs, offset);
  563. SkipAddress(offset);
  564. IF refs[offset] = sfScopeBegin THEN SkipScope(refs, offset) END;
  565. END SkipTypeDeclaration;
  566. (* skip a scope in stream *)
  567. PROCEDURE SkipScope*(refs: Modules.Bytes; VAR offset: LONGINT);
  568. BEGIN
  569. IF ~Expect(GetChar(refs, offset) = sfScopeBegin) THEN RETURN END;
  570. WHILE (refs[offset] = sfVariable) DO SkipVariable(refs, offset) END;
  571. WHILE (refs[offset] = sfProcedure) DO SkipProcedure(refs, offset) END;
  572. WHILE (refs[offset] = sfTypeDeclaration) DO SkipTypeDeclaration(refs, offset) END;
  573. IF ~Expect(GetChar(refs, offset) = sfScopeEnd) THEN RETURN END;
  574. END SkipScope;
  575. TYPE
  576. Search = RECORD
  577. name: ARRAY 256 OF CHAR; (* for search by name *)
  578. nameOffset: LONGINT; (* to incrementally search through scopes *)
  579. minLevel: LONGINT; (* in order to stop scope search *)
  580. pc: ADDRESS; (* for search by address *)
  581. pos: LONGINT; (* symbol position in stream *)
  582. found: BOOLEAN; (* if found *)
  583. END;
  584. (* check if stream contains the string part stored in search record with respective offset *)
  585. PROCEDURE FindString(refs: Modules.Bytes; VAR offset: LONGINT; level: LONGINT; VAR find: Search);
  586. VAR ofs: LONGINT;
  587. BEGIN
  588. ofs := find.nameOffset;
  589. WHILE (refs[offset] # 0X) & (find.name[ofs] = refs[offset]) DO
  590. INC(offset); INC(ofs);
  591. END;
  592. IF (refs[offset] = 0X) THEN
  593. IF find.name[ofs] = 0X THEN
  594. find.found := TRUE;
  595. ELSIF find.name[ofs] = "." THEN
  596. find.minLevel := level+1;
  597. find.nameOffset := ofs+1;
  598. END;
  599. END;
  600. WHILE(refs[offset] # 0X) DO INC(offset) END;
  601. INC(offset);
  602. END FindString;
  603. (* find a symbol by name or pc starting from the procedure stream section *)
  604. PROCEDURE FindInProcedure(refs: Modules.Bytes; VAR offset: LONGINT; level: LONGINT; VAR find: Search);
  605. VAR name: ARRAY 128 OF CHAR; start, end, pos: LONGINT;
  606. BEGIN
  607. TRACE(offset);
  608. pos := offset;
  609. IF ~Expect(GetChar(refs, offset) = sfProcedure) THEN RETURN END;
  610. SkipSize(offset);
  611. FindString(refs, offset, level, find);
  612. start := GetAddress(refs, offset);
  613. end := GetAddress(refs, offset);
  614. find.found := find.found OR (start <= find.pc) & (find.pc <= end);
  615. IF find.found THEN
  616. find.pos := pos;
  617. RETURN;
  618. END;
  619. WHILE (refs[offset] = sfParameter) DO
  620. IF find.minLevel <= level THEN
  621. FindInParameter(refs, offset, level+1, find);
  622. IF find.found THEN RETURN END;
  623. ELSE
  624. SkipParameter(refs, offset)
  625. END;
  626. END;
  627. SkipType(refs, offset);
  628. FindInScope(refs, offset, level+1, find);
  629. END FindInProcedure;
  630. (* find a symbol by name or pc starting from the parameter stream section *)
  631. PROCEDURE FindInParameter(refs: Modules.Bytes; VAR offset: LONGINT; level: LONGINT; VAR find: Search);
  632. VAR name: ARRAY 128 OF CHAR; adr: LONGINT; c: CHAR; pos: LONGINT;
  633. BEGIN
  634. TRACE(offset);
  635. pos := offset;
  636. IF ~Expect(GetChar(refs, offset) = sfParameter) THEN RETURN END;
  637. SkipSize(offset);
  638. FindString(refs, offset, level, find);
  639. IF find.found THEN
  640. find.pos := pos;
  641. RETURN;
  642. END;
  643. SkipSize(offset);
  644. SkipChar(offset);
  645. SkipType(refs, offset);
  646. END FindInParameter;
  647. (* find a symbol by name or pc starting from the variable stream section *)
  648. PROCEDURE FindInVariable(refs: Modules.Bytes; VAR offset: LONGINT; level: LONGINT; VAR find: Search);
  649. VAR name: ARRAY 128 OF CHAR; pos: LONGINT;
  650. BEGIN
  651. TRACE(offset);
  652. pos := offset;
  653. IF ~Expect(GetChar(refs, offset) = sfVariable) THEN RETURN END;
  654. SkipSize(offset);
  655. FindString(refs, offset, level, find);
  656. IF find.found THEN
  657. find.pos := pos;
  658. RETURN;
  659. END;
  660. SkipSize(offset);
  661. SkipType(refs, offset);
  662. END FindInVariable;
  663. (* find a symbol by name or pc starting from the type declaration stream section *)
  664. PROCEDURE FindInTypeDeclaration(refs: Modules.Bytes; VAR offset: LONGINT; level: LONGINT; VAR find: Search);
  665. VAR name: ARRAY 128 OF CHAR; adr, pos: LONGINT;
  666. BEGIN
  667. TRACE(offset);
  668. pos := offset;
  669. IF ~Expect(GetChar(refs, offset) = sfTypeDeclaration) THEN RETURN END;
  670. SkipSize(offset);
  671. FindString(refs, offset, level, find);
  672. IF find.found THEN
  673. find.pos := pos;
  674. RETURN;
  675. END;
  676. SkipAddress(offset);
  677. IF refs[offset] = sfScopeBegin THEN FindInScope(refs, offset, level+1, find) END;
  678. END FindInTypeDeclaration;
  679. (* find a symbol by name or pc in a scope in the stream *)
  680. PROCEDURE FindInScope(refs: Modules.Bytes; VAR offset: LONGINT; level: LONGINT; VAR find: Search);
  681. VAR no,i: LONGINT;
  682. BEGIN
  683. TRACE(offset);
  684. IF ~Expect(GetChar(refs, offset) = sfScopeBegin) THEN RETURN END;
  685. WHILE ~find.found &(refs[offset] = sfVariable) & (find.minLevel <= level) DO (* Variable *)
  686. FindInVariable(refs, offset, level, find);
  687. END;
  688. WHILE ~find.found & (refs[offset] = sfProcedure) & (find.minLevel <= level) DO (* Procedure *)
  689. FindInProcedure(refs, offset, level, find);
  690. END;
  691. WHILE ~find.found & (refs[offset] = sfTypeDeclaration) & (find.minLevel <= level) DO (* TypeDeclaration *)
  692. FindInTypeDeclaration(refs, offset,level, find);
  693. END;
  694. IF find.found OR (find.minLevel > level) THEN RETURN END;
  695. IF ~Expect(GetChar(refs, offset) = sfScopeEnd) THEN RETURN END;
  696. END FindInScope;
  697. PROCEDURE InitSearch(VAR search: Search);
  698. BEGIN
  699. search.found := FALSE;
  700. search.name := "";
  701. search.nameOffset := 0;
  702. search.minLevel := 0;
  703. search.pc := 0;
  704. END InitSearch;
  705. PROCEDURE FindByName*(refs: Modules.Bytes; VAR offset: LONGINT; CONST name: ARRAY OF CHAR): BOOLEAN;
  706. VAR search: Search;
  707. BEGIN
  708. InitSearch(search);
  709. COPY(name, search.name);
  710. offset := 0;
  711. IF ~Expect(GetChar(refs, offset) = 0FFX) THEN RETURN FALSE END;
  712. FindInScope(refs, offset, 0, search);
  713. offset := search.pos;
  714. RETURN search.found;
  715. END FindByName;
  716. PROCEDURE FindByAdr*(refs: Modules.Bytes; VAR offset: LONGINT; pc: ADDRESS): BOOLEAN;
  717. VAR search: Search;
  718. BEGIN
  719. InitSearch(search);
  720. search.pc := pc;
  721. offset := 0;
  722. IF GetChar(refs, offset) # 0FFX THEN RETURN FALSE END;
  723. FindInScope(refs, offset, 0, search);
  724. offset := search.pos;
  725. RETURN search.found;
  726. END FindByAdr;
  727. (** service procedures *)
  728. (** Find procedure name and write it. *)
  729. PROCEDURE WriteProc*(w: Streams.Writer; pc: ADDRESS);
  730. VAR refs: Modules.Bytes; refpos: LONGINT; base: ADDRESS;
  731. BEGIN
  732. WriteProc0(w, Modules.ThisModuleByAdr0(pc), pc, -1, refs, refpos, base)
  733. END WriteProc;
  734. (** Write the state of the specified module. *)
  735. PROCEDURE ModuleState*(w: Streams.Writer; mod: Modules.Module);
  736. VAR offset: LONGINT; base: ADDRESS; refs: Modules.Bytes;
  737. BEGIN
  738. IF mod = NIL THEN RETURN END;
  739. refs := mod.refs;
  740. offset := 0;
  741. w.String("State "); w.String(mod.name); w.Char(":"); w.Ln; Wait(w);
  742. IF (GetChar(refs, offset) = 0FFX) & (GetChar(refs, offset) = sfScopeBegin) THEN
  743. WriteVariables(w, refs, offset, 0)
  744. END;
  745. END ModuleState;
  746. (* Display call trackback. *)
  747. PROCEDURE StackTraceBack*(w: Streams.Writer; pc, bp: ADDRESS; stackhigh: ADDRESS; long, overflow: BOOLEAN);
  748. VAR count,offset: LONGINT; stacklow: ADDRESS; base: ADDRESS; m: Modules.Module; refs: Modules.Bytes;
  749. BEGIN
  750. count := 0; (* frame count *)
  751. stacklow := bp;
  752. REPEAT
  753. m := Modules.ThisModuleByAdr0(pc);
  754. IF (ShowAllProcs OR (m # NIL) OR (count = 0)) & (bp # 0) & (bp >= stacklow) & (bp <= stackhigh) THEN
  755. IF CheckHeapAddress( pc ) THEN
  756. TRACE(pc);
  757. WriteProc0(w, m, pc, bp, refs, offset, base); w.Ln;Wait(w); w.Update;
  758. IF long & (~overflow OR (count > 0)) THEN (* show variables *)
  759. IF offset >= 0 THEN
  760. WriteParameters(w,refs,offset, base);
  761. SkipType(refs, offset);
  762. IF Expect(GetChar(refs, offset) = sfScopeBegin) THEN
  763. WriteVariables(w,refs,offset, base);
  764. END;
  765. END;
  766. IF (m # NIL) & (base # m.sb) & (count = 0) THEN ModuleState(w, m) END
  767. END;
  768. ELSE
  769. w.String( "Unknown external procedure, pc = " ); w.Address( pc ); w.Ln; Wait(w);
  770. END;
  771. SYSTEM.GET(bp + SIZEOF(ADDRESS), pc); (* return addr from stack *)
  772. SYSTEM.GET(bp, bp); (* follow dynamic link *)
  773. INC(count)
  774. ELSE
  775. bp := 0
  776. END;
  777. UNTIL (bp = 0) OR (count = MaxFrames);
  778. IF bp # 0 THEN w.String("...") END
  779. END StackTraceBack;
  780. (** Write a process's state in one line. *)
  781. PROCEDURE WriteProcess*(w: Streams.Writer; p: Objects.Process);
  782. VAR adr: ADDRESS; mode: LONGINT; m: Modules.Module;
  783. BEGIN
  784. IF p # NIL THEN
  785. w.Int(p.id, 5);
  786. mode := p.mode;
  787. IF (mode >= Objects.Ready) & (mode <= Objects.Terminated) THEN
  788. adr := (mode-Objects.Ready)*4;
  789. FOR adr := adr TO adr+3 DO w.Char(modes[adr]) END
  790. ELSE
  791. w.Char(" "); w.Int(mode, 1)
  792. END;
  793. w.Int(p.procID, 2);
  794. w.Int(p.priority, 2);
  795. w.Update;
  796. w.Address (SYSTEM.VAL(ADDRESS, p.obj));
  797. IF p.obj # NIL THEN
  798. SYSTEM.GET(SYSTEM.VAL(ADDRESS, p.obj) - SIZEOF(ADDRESS), adr);
  799. w.Char(":"); WriteType(w, adr)
  800. END;
  801. w.Update;
  802. w.Char(" "); WriteProc(w, p.state.PC);
  803. IF p.mode = Objects.AwaitingLock THEN
  804. adr := SYSTEM.VAL(ADDRESS, p.waitingOn);
  805. w.Address (adr);
  806. w.Update;
  807. IF adr # 0 THEN (* can be 0 when snapshot is taken *)
  808. SYSTEM.GET(adr - SIZEOF(ADDRESS), adr);
  809. IF adr = SYSTEM.TYPECODE(Modules.Module) THEN
  810. w.Char("-");
  811. m := SYSTEM.VAL(Modules.Module, adr);
  812. w.String(m.name)
  813. ELSE
  814. w.Char(":"); WriteType(w, adr)
  815. END;
  816. w.Update;
  817. END
  818. ELSIF p.mode = Objects.AwaitingCond THEN
  819. w.Char(" "); WriteProc(w, SYSTEM.VAL(ADDRESS, p.condition));
  820. w.Address (p.condFP)
  821. END;
  822. w.Char(" "); w.Set(p.flags)
  823. END
  824. END WriteProcess;
  825. (* for interface compatibility *)
  826. PROCEDURE GetVariableAdr*(fp, pc: ADDRESS; CONST name: ARRAY OF CHAR): SIZE;
  827. BEGIN
  828. RETURN -1;
  829. END GetVariableAdr;
  830. PROCEDURE GetProcedureName*(pc: ADDRESS; VAR name: ARRAY OF CHAR; VAR startpc: ADDRESS);
  831. BEGIN
  832. name := ""
  833. END GetProcedureName;
  834. TYPE
  835. Variable* = RECORD
  836. adr-: ADDRESS;
  837. type-, size-, n-, tdadr-: LONGINT
  838. END;
  839. PROCEDURE FindVar*(mod: Modules.Module; CONST name: ARRAY OF CHAR; VAR v: Variable): BOOLEAN;
  840. BEGIN
  841. END FindVar;
  842. PROCEDURE WriteVar*(w: Streams.Writer; v: Variable; VAR col: LONGINT);
  843. BEGIN
  844. END WriteVar;
  845. PROCEDURE ReportType(w:Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT);
  846. VAR size: SIZE; adr: LONGINT; c: CHAR;
  847. BEGIN
  848. c := GetChar(refs, offset);
  849. CASE c OF
  850. sfTypeNone: w.String("no type");
  851. | sfTypePointerToRecord: w.String("POINTER TO RECORD");
  852. | sfTypePointerToArray: w.String("POINTER TO "); ReportType(w, refs, offset);
  853. | sfTypeOpenArray: w.String("ARRAY OF "); ReportType(w, refs, offset);
  854. | sfTypeStaticArray: w.String("ARRAY "); w.Int(GetSize(refs, offset),1 ); w.String(" OF "); ReportType(w, refs, offset);
  855. | sfTypeDynamicArray: w.String("DARRAY OF "); ReportType(w,refs, offset);
  856. | sfTypeMathOpenArray: w.String("ARRAY [*] OF "); ReportType(w, refs, offset);
  857. | sfTypeMathStaticArray: w.String("ARRAY ["); w.Int(GetSize(refs, offset),1); w.String("] OF "); ReportType(w, refs, offset);
  858. | sfTypeMathTensor: w.String("ARRAY [?] OF "); ReportType(w, refs, offset);
  859. | sfTypeRecord: w.String("RECORD "); w.Address(GetAddress(refs, offset));
  860. | sfTypeDelegate:
  861. w.String("PROCEDURE (");
  862. WHILE refs[offset] = sfParameter DO ReportParameter(w, refs, offset) END;
  863. w.String("):"); ReportType(w, refs, offset);
  864. | sfTypeBOOLEAN: w.String("BOOLEAN");
  865. | sfTypeCHAR: w.String("CHAR");
  866. | sfTypeCHAR8: w.String("CHAR8");
  867. | sfTypeCHAR16: w.String("CHAR16");
  868. | sfTypeCHAR32: w.String("CHAR32");
  869. | sfTypeSHORTINT: w.String("SHORTINT");
  870. | sfTypeINTEGER: w.String("INTEGER");
  871. | sfTypeLONGINT: w.String("LONGINT");
  872. | sfTypeHUGEINT: w.String("HUGEINT");
  873. | sfTypeWORD: w.String("WORD");
  874. | sfTypeLONGWORD: w.String("LONGWORD");
  875. | sfTypeSIGNED8: w.String("SIGNED8");
  876. | sfTypeSIGNED16: w.String("SIGNED16");
  877. | sfTypeSIGNED32: w.String("SIGNED32");
  878. | sfTypeSIGNED64: w.String("SIGNED64");
  879. | sfTypeUNSIGNED8: w.String("UNSIGNED8");
  880. | sfTypeUNSIGNED16: w.String("UNSIGNED16");
  881. | sfTypeUNSIGNED32: w.String("UNSIGNED32");
  882. | sfTypeUNSIGNED64: w.String("UNSIGNED64");
  883. | sfTypeREAL: w.String("REAL");
  884. | sfTypeLONGREAL: w.String("LONGREAL");
  885. | sfTypeCOMPLEX: w.String("COMPLEX");
  886. | sfTypeLONGCOMPLEX: w.String("LONGCOMPLEX");
  887. | sfTypeSET: w.String("SET");
  888. | sfTypeANY: w.String("ANY");
  889. | sfTypeOBJECT: w.String("OBJECT");
  890. | sfTypeBYTE: w.String("BYTE");
  891. | sfTypeRANGE: w.String("RANGE");
  892. | sfTypeADDRESS: w.String("ADDRESS");
  893. | sfTypeSIZE: w.String("SIZE");
  894. | sfTypePort: w.String("PORT"); IF GetChar(refs,offset) = sfInPort THEN w.String("IN") ELSE w.String("OUT") END;
  895. ELSE w.String("????? TYPE ?????");
  896. END;
  897. END ReportType;
  898. PROCEDURE ReportProcedure(w: Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT);
  899. VAR name: Name; start, end: LONGINT;
  900. BEGIN
  901. w.Int(offset,1); w.String(":");
  902. w.String("PROCEDURE ");
  903. IF ~Expect(GetChar(refs, offset) = sfProcedure) THEN RETURN END;
  904. SkipSize(offset);
  905. GetString(refs, offset, name);
  906. w.String(name);
  907. start := GetAddress(refs, offset);
  908. end := GetAddress(refs, offset);
  909. w.String("(");
  910. WHILE refs[offset] = sfParameter DO
  911. ReportParameter(w, refs, offset);
  912. END;
  913. w.String(")");
  914. w.String(":");
  915. ReportType(w, refs, offset);
  916. w.String("[@"); w.Address(start); w.String(" - "); w.Address(end); w.String("]");
  917. w.Ln;
  918. ReportScope(w, refs, offset);
  919. END ReportProcedure;
  920. PROCEDURE ReportParameter(w: Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT);
  921. VAR name: ARRAY 128 OF CHAR; adr: LONGINT; c: CHAR;
  922. BEGIN
  923. w.String(" ");
  924. IF ~Expect(GetChar(refs, offset) = sfParameter) THEN RETURN END;
  925. SkipSize(offset);
  926. GetString(refs, offset, name);
  927. w.String(name);
  928. adr := GetSize(refs, offset);
  929. c := GetChar(refs, offset);
  930. IF c = sfVarPar THEN
  931. w.String(" VAR ")
  932. ELSIF c = sfConstPar THEN
  933. w.String(" CONST ")
  934. ELSIF Expect(c = sfValPar) THEN
  935. END;
  936. w.String(":");
  937. ReportType(w, refs, offset);
  938. w.String("[@"); w.Int(adr,1); w.String("]");
  939. w.String("; ");
  940. END ReportParameter;
  941. PROCEDURE ReportVariable(w: Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT);
  942. VAR name: ARRAY 128 OF CHAR; adr: LONGINT;
  943. BEGIN
  944. w.Int(offset,1); w.String(":");
  945. w.String("VAR ");
  946. IF ~Expect(GetChar(refs, offset) = sfVariable) THEN RETURN END;
  947. SkipSize(offset);
  948. GetString(refs, offset, name);
  949. w.String(name);
  950. adr := GetSize(refs, offset);
  951. w.String(":");
  952. ReportType(w, refs, offset);
  953. w.String("[@"); w.Int(offset,1); w.String("]");
  954. w.Ln;
  955. END ReportVariable;
  956. PROCEDURE ReportTypeDeclaration(w: Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT);
  957. VAR name: ARRAY 128 OF CHAR; adr: LONGINT;
  958. BEGIN
  959. w.Int(offset,1); w.String(":");
  960. w.String("TYPE ");
  961. IF ~Expect(GetChar(refs, offset) = sfTypeDeclaration) THEN RETURN END;
  962. SkipSize(offset);
  963. GetString(refs, offset, name);
  964. w.String(name);
  965. adr := GetAddress(refs, offset);
  966. w.String(" ");
  967. w.Address(adr);
  968. w.Ln;
  969. IF refs[offset] = sfScopeBegin THEN ReportScope(w, refs, offset) END;
  970. END ReportTypeDeclaration;
  971. PROCEDURE ReportScope(w:Streams.Writer; refs: Modules.Bytes; VAR offset: LONGINT);
  972. BEGIN
  973. IF ~Expect(GetChar(refs, offset) = sfScopeBegin) THEN RETURN END;
  974. w.Int(offset,1); w.String(": Scope"); w.Ln;
  975. WHILE (refs[offset] = sfVariable) DO (* Variable *)
  976. ReportVariable(w, refs, offset);
  977. END;
  978. WHILE (refs[offset] = sfProcedure) DO (* Procedure *)
  979. ReportProcedure(w, refs, offset);
  980. END;
  981. WHILE (refs[offset] = sfTypeDeclaration) DO (* TypeDeclaration *)
  982. ReportTypeDeclaration(w, refs, offset);
  983. END;
  984. IF ~Expect(GetChar(refs, offset) = sfScopeEnd) THEN RETURN END;
  985. w.String("END"); w.Ln;
  986. END ReportScope;
  987. PROCEDURE Report*(w:Streams.Writer; refs: Modules.Bytes);
  988. VAR offset: LONGINT;
  989. BEGIN
  990. offset := 0;
  991. IF Expect(GetChar(refs, offset) = 0FFX) THEN
  992. ReportScope(w, refs, offset)
  993. END;
  994. END Report;
  995. BEGIN
  996. modes := " rdy run awl awc awe rip"; (* 4 characters per mode from Objects.Ready to Objects.Terminated *)
  997. END Reflection.
  998. SystemTools.Free TestReflection ~
  999. TestReflection.TrapMe ~
  1000. TestReflection.Test
  1001. TestReflection.Trace 09454F69H ~
  1002. SystemTools.FreeDownTo FoxIntermediateBackend ~
  1003. # StaticLinker.Link --fileFormat=PE32 --fileName=A2H.exe --extension=GofW --displacement=401000H Runtime Trace Kernel32 Machine Heaps Modules Objects Kernel KernelLog Streams Commands FIles WinFS Clock Dates Reals Strings Diagnostics BitSets StringPool ObjectFile GenericLinker Reflection GenericLoader BootConsole ~