Generic.Reflection.Mod 31 KB

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