Visualizer.Mod 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578
  1. MODULE Visualizer; (** AUTHOR "staubesv"; PURPOSE "Generate class diagrams that can be visualized using graphviz"; *)
  2. (**
  3. * This tool generates textual descriptions for class diagrams in the DOT language. These descriptions can be converted in to graphs (postscript, bitmaps,...)
  4. * using the freeware tool graphviz (www.graphviz.org).
  5. *
  6. * Usage:
  7. *
  8. * Visualizer.Generate [options] filename {filename} ~
  9. *
  10. * Usage example:
  11. *
  12. * Visualizer.Generate --size="A3" --mode=2 --file="graph.txt" WMComponents.Mod ~ generates the file graph.txt
  13. *
  14. * Options:
  15. *
  16. * General:
  17. *
  18. * -s / --size A0, A1, ..., A10 paper size
  19. * -l / --landscape paper orientation = landscape (portrait otherwise)
  20. * -f / --file filename output filename
  21. * -o / --options string graph options for graphviz, e.g. --options='page = "A1"'
  22. * -e / --exclude string Whitespace-separated list of modules to be excluded from graph
  23. *
  24. * Visibilities:
  25. *
  26. * -h / --hasA none, public, all If none, no hasA relations are shown. If public, only hasA relations that are established by
  27. * public fields are shown. All hasA relations are shown when set this to 'all'
  28. * -d / --dependencies none, public, all Also include types that are parameters of procedures?
  29. * -t / --types none, pubilc, all Determines which type declarations are included
  30. * -v / --variables none, pubilc, all Determines which variables/fields are included
  31. * -p / --procedures none, public, all Determines which procedures are included
  32. *
  33. * Mode:
  34. *
  35. * -a / --all Show all type declarations (otherwise objects, records and pointer to records only)
  36. * -m / --mode Processing mode:
  37. * 0: Simple. Only show information that is provided directly by parsed modules
  38. * 1: Recursive, depth = :, if a type information is not available by the parsed modules, parse the module
  39. * that provides it and include it
  40. * 2: Recursive, depth = infinity: Do the same as for mode=1, but repeat this until all type information
  41. * is available
  42. *
  43. * Status: BETA
  44. *)
  45. IMPORT
  46. Streams, KernelLog, Commands, Options, Strings, Files, Texts, TextUtilities, Diagnostics, FoxScanner, ModuleParser;
  47. CONST
  48. None = 0;
  49. Public = 1;
  50. All = 2;
  51. DefaultTypes = All;
  52. DefaultVariables = Public;
  53. DefaultProcedures = Public;
  54. DefaultHasA = Public;
  55. DefaultDependencies = None;
  56. DefaultOutputFilename = "graph.txt";
  57. DependsOnFactor = 0.1;
  58. HasAFactor = 0.3;
  59. NodeFontName = "Arial";
  60. NodeFontSize = 48;
  61. (* Generator states *)
  62. Initialized = 0;
  63. Running = 1;
  64. Stopped = 2;
  65. (* Generator modes *)
  66. Simple = 0; (* default *)
  67. Better = 1;
  68. Extreme = 2;
  69. (* ModuleEntry.flags *)
  70. AddSuperType = 0;
  71. Parsed = 1;
  72. ScannedSuperTypes = 2;
  73. TYPE
  74. SizeString = ARRAY 16 OF CHAR;
  75. Entry = POINTER TO RECORD
  76. name : ARRAY 256 OF CHAR;
  77. isSetSuperClass : BOOLEAN;
  78. next : Entry;
  79. END;
  80. List = OBJECT
  81. VAR
  82. head : Entry;
  83. PROCEDURE Add(CONST name : ARRAY OF CHAR) : BOOLEAN;
  84. VAR entry : Entry;
  85. BEGIN {EXCLUSIVE}
  86. IF (Find(name) = NIL) THEN
  87. NEW(entry);
  88. COPY(name, entry.name);
  89. entry.isSetSuperClass := FALSE;
  90. entry.next := head.next;
  91. head.next := entry;
  92. RETURN TRUE;
  93. ELSE
  94. RETURN FALSE;
  95. END;
  96. END Add;
  97. PROCEDURE SetSuperClass(CONST name : ARRAY OF CHAR);
  98. VAR entry : Entry;
  99. BEGIN {EXCLUSIVE}
  100. entry := Find(name);
  101. IF (entry # NIL) THEN
  102. entry.isSetSuperClass := TRUE;
  103. END;
  104. END SetSuperClass;
  105. PROCEDURE IsSetSuperClass(CONST name : ARRAY OF CHAR) : BOOLEAN;
  106. VAR entry : Entry;
  107. BEGIN {EXCLUSIVE}
  108. entry := Find(name);
  109. IF (entry # NIL) THEN
  110. RETURN entry.isSetSuperClass;
  111. ELSE
  112. RETURN TRUE;
  113. END;
  114. END IsSetSuperClass;
  115. PROCEDURE Find(CONST name : ARRAY OF CHAR) : Entry; (* private *)
  116. VAR entry : Entry;
  117. BEGIN
  118. entry := head.next;
  119. WHILE (entry # NIL) & (entry.name # name) DO entry := entry.next; END;
  120. RETURN entry;
  121. END Find;
  122. PROCEDURE &Init; (* private *)
  123. BEGIN
  124. NEW(head); head.name := ""; head.next := NIL;
  125. END Init;
  126. END List;
  127. TYPE
  128. ModuleEntry = OBJECT
  129. VAR
  130. name : ARRAY 128 OF CHAR;
  131. module : ModuleParser.Module;
  132. flags : SET;
  133. next : ModuleEntry;
  134. PROCEDURE &Init(CONST name : ARRAY OF CHAR; module : ModuleParser.Module);
  135. BEGIN
  136. COPY(name, SELF.name);
  137. SELF.module := module;
  138. flags := {AddSuperType};
  139. next := NIL;
  140. END Init;
  141. END ModuleEntry;
  142. ModuleArray = POINTER TO ARRAY OF ModuleEntry;
  143. EnumeratorProc = PROCEDURE {DELEGATE} (entry : ModuleEntry; indent : LONGINT);
  144. ModuleList = OBJECT
  145. VAR
  146. head : ModuleEntry;
  147. nofEntries : LONGINT;
  148. PROCEDURE Add(CONST name : ARRAY OF CHAR; module : ModuleParser.Module) : BOOLEAN;
  149. VAR entry : ModuleEntry;
  150. BEGIN {EXCLUSIVE}
  151. IF (FindByNameX(name) = NIL) THEN
  152. NEW(entry, name, module);
  153. entry.next := head.next;
  154. head.next := entry;
  155. INC(nofEntries);
  156. RETURN TRUE;
  157. ELSE
  158. RETURN FALSE;
  159. END;
  160. END Add;
  161. PROCEDURE GetAll() : ModuleArray;
  162. VAR array : ModuleArray; entry : ModuleEntry; i : LONGINT;
  163. BEGIN {EXCLUSIVE}
  164. IF (nofEntries > 0) THEN
  165. NEW(array, nofEntries);
  166. entry := head.next;
  167. i := 0;
  168. WHILE (entry # NIL) DO
  169. array[i] := entry; INC(i);
  170. entry := entry.next;
  171. END;
  172. ELSE
  173. array := NIL;
  174. END;
  175. RETURN array;
  176. END GetAll;
  177. PROCEDURE Enumerate(proc : EnumeratorProc; indent : LONGINT);
  178. VAR array : ModuleArray; i : LONGINT;
  179. BEGIN
  180. array := GetAll();
  181. IF (array # NIL) THEN
  182. FOR i := 0 TO LEN(array)-1 DO
  183. IF (array[i] # NIL) THEN
  184. proc(array[i], indent);
  185. END;
  186. END;
  187. END;
  188. END Enumerate;
  189. PROCEDURE FindByName(CONST name : ARRAY OF CHAR) : ModuleEntry;
  190. BEGIN {EXCLUSIVE}
  191. RETURN FindByNameX(name);
  192. END FindByName;
  193. PROCEDURE FindByNameX(CONST name : ARRAY OF CHAR) : ModuleEntry;
  194. VAR entry : ModuleEntry;
  195. BEGIN
  196. entry := head.next;
  197. WHILE (entry # NIL) & (entry.name # name) DO entry := entry.next; END;
  198. RETURN entry;
  199. END FindByNameX;
  200. PROCEDURE InclFlag(CONST name : ARRAY OF CHAR; flag : LONGINT);
  201. VAR entry : ModuleEntry;
  202. BEGIN {EXCLUSIVE}
  203. entry := FindByNameX(name);
  204. IF (entry # NIL) THEN INCL(entry.flags, flag); END;
  205. END InclFlag;
  206. PROCEDURE ExclFlag(CONST name : ARRAY OF CHAR; flag : LONGINT);
  207. VAR entry : ModuleEntry;
  208. BEGIN {EXCLUSIVE}
  209. entry := FindByNameX(name);
  210. IF (entry # NIL) THEN EXCL(entry.flags, flag); END;
  211. END ExclFlag;
  212. PROCEDURE &Init;
  213. BEGIN
  214. NEW(head, "", NIL);
  215. nofEntries := 0;
  216. END Init;
  217. END ModuleList;
  218. Edge = POINTER TO RECORD
  219. from, to : ARRAY 128 OF CHAR;
  220. count : LONGINT;
  221. next : Edge;
  222. END;
  223. EdgeEnumerator = PROCEDURE {DELEGATE} (edge : Edge);
  224. EdgeList = OBJECT
  225. VAR
  226. head : Edge;
  227. PROCEDURE Add(CONST from, to : ARRAY OF CHAR);
  228. VAR edge : Edge;
  229. BEGIN
  230. edge := Find(from, to);
  231. IF (edge = NIL) THEN
  232. NEW(edge);
  233. COPY(from, edge.from);
  234. COPY(to, edge.to);
  235. edge.count := 1;
  236. edge.next := head.next;
  237. head.next := edge;
  238. ELSE
  239. INC(edge.count);
  240. END;
  241. END Add;
  242. PROCEDURE Find(CONST from, to : ARRAY OF CHAR) : Edge;
  243. VAR edge : Edge;
  244. BEGIN
  245. edge := head.next;
  246. WHILE (edge # NIL) & ((edge.from # from) OR (edge.to # to)) DO edge := edge.next; END;
  247. RETURN edge;
  248. END Find;
  249. PROCEDURE Enumerate(proc : EdgeEnumerator);
  250. VAR edge : Edge;
  251. BEGIN
  252. edge := head.next;
  253. WHILE (edge # NIL) DO
  254. proc(edge);
  255. edge := edge.next;
  256. END;
  257. END Enumerate;
  258. PROCEDURE &Init;
  259. BEGIN
  260. NEW(head); head.next := NIL;
  261. END Init;
  262. END EdgeList;
  263. TYPE
  264. Generator = OBJECT
  265. VAR
  266. out : Streams.Writer;
  267. list : List;
  268. modules : ModuleList;
  269. types, variables, procedures, hasA, dependencies : LONGINT; (* Enumeration: None | Public | All *)
  270. showAllTypes : BOOLEAN;
  271. mode : LONGINT;
  272. hasAEdges, dependsOnEdges : EdgeList;
  273. excludedModules : Strings.StringArray;
  274. state : LONGINT;
  275. PROCEDURE &Init(out : Streams.Writer); (* private *)
  276. BEGIN
  277. ASSERT(out # NIL);
  278. SELF.out := out;
  279. NEW(list);
  280. NEW(modules);
  281. NEW(hasAEdges); NEW(dependsOnEdges);
  282. state := Initialized;
  283. mode := Simple;
  284. END Init;
  285. PROCEDURE Visibility(identDef : ModuleParser.IdentDef);
  286. BEGIN
  287. ASSERT(identDef # NIL);
  288. IF (identDef.vis = ModuleParser.Public) THEN out.Char("+");
  289. ELSIF (identDef.vis = ModuleParser.PublicRO) THEN out.Char("-");
  290. END;
  291. END Visibility;
  292. PROCEDURE IsPublic(identDef : ModuleParser.IdentDef) :BOOLEAN;
  293. BEGIN
  294. ASSERT(identDef # NIL);
  295. RETURN (identDef.vis = ModuleParser.Public) OR (identDef.vis = ModuleParser.PublicRO);
  296. END IsPublic;
  297. PROCEDURE FormalPars(formalPars : ModuleParser.FormalPars);
  298. VAR module : ModuleParser.Module; fullname : ARRAY 256 OF CHAR; fpSection : ModuleParser.FPSection; ident : ModuleParser.IdentList;
  299. BEGIN
  300. IF (formalPars # NIL) THEN
  301. fpSection := formalPars.fpSectionList;
  302. out.Char("(");
  303. WHILE (fpSection # NIL) DO
  304. IF (fpSection.var) THEN out.String("VAR "); END;
  305. IF (fpSection.const) THEN out.String("CONST "); END;
  306. ident := fpSection.identList;
  307. WHILE (ident # NIL) DO
  308. Type(fpSection.type);
  309. IF (ident.next # NIL) THEN
  310. out.Char(",");
  311. ident := ident.next (ModuleParser.IdentList);
  312. ELSE
  313. ident := NIL;
  314. END;
  315. END;
  316. IF (fpSection.next # NIL) THEN
  317. fpSection := fpSection.next (ModuleParser.FPSection);
  318. out.Char(",");
  319. ELSE
  320. fpSection := NIL;
  321. END;
  322. END;
  323. out.Char(")");
  324. module := formalPars.GetModule();
  325. IF (formalPars.returnType # NIL) THEN
  326. out.String(" : "); Type(formalPars.returnType);
  327. END;
  328. END;
  329. END FormalPars;
  330. PROCEDURE Array(array : ModuleParser.Array);
  331. BEGIN
  332. ASSERT(array # NIL);
  333. out.String("ARRAY ");
  334. IF ~array.open THEN
  335. out.String(array.len.name^); out.Char(" ");
  336. END;
  337. out.String("OF ");
  338. Type(array.base);
  339. END Array;
  340. PROCEDURE Type(type : ModuleParser.Type);
  341. VAR module : ModuleParser.Module; name : Strings.String; fullname : ARRAY 256 OF CHAR;
  342. BEGIN
  343. ASSERT(type # NIL);
  344. module := type.GetModule();
  345. IF (type.qualident # NIL) THEN
  346. FixTypeName(module, type.qualident.ident.name^, fullname);
  347. out.String(fullname);
  348. ELSIF (type.array # NIL) THEN
  349. Array(type.array);
  350. ELSIF (type.record # NIL) THEN
  351. name := GetTypeName(type);
  352. FixTypeName(module, name^, fullname);
  353. out.String(fullname);
  354. ELSIF (type.pointer # NIL) THEN
  355. out.String("POINTER TO "); Type(type.pointer.type);
  356. ELSIF (type.object # NIL) THEN
  357. FixTypeName(module, type.parent(ModuleParser.TypeDecl).identDef.ident.name^, fullname);
  358. out.String(fullname);
  359. ELSIF (type.procedure # NIL) THEN
  360. out.String("PROCEDURE ");
  361. IF (type.procedure.delegate) THEN out.String("[DELEGATE] "); END;
  362. FormalPars(type.procedure.formalPars);
  363. END;
  364. END Type;
  365. PROCEDURE Variable(identList : ModuleParser.IdentList; type : ModuleParser.Type);
  366. BEGIN
  367. ASSERT((identList # NIL) & (type # NIL));
  368. WHILE (identList # NIL) DO
  369. Visibility(identList.identDef); out.Char(" ");
  370. IF IsPublic(identList.identDef) OR (variables = All) THEN
  371. out.String(identList.identDef.ident.name^);
  372. out.String(" : ");
  373. Type(type);
  374. out.String("\l");
  375. END;
  376. IF (identList.next # NIL) THEN
  377. identList := identList.next (ModuleParser.IdentList);
  378. ELSE
  379. identList := NIL;
  380. END;
  381. END;
  382. END Variable;
  383. PROCEDURE VarDecl(varDecl : ModuleParser.VarDecl);
  384. BEGIN
  385. WHILE (varDecl # NIL) DO
  386. Variable(varDecl.identList, varDecl.type);
  387. IF (varDecl.next # NIL) THEN
  388. varDecl := varDecl.next (ModuleParser.VarDecl);
  389. ELSE
  390. varDecl := NIL;
  391. END;
  392. END;
  393. END VarDecl;
  394. PROCEDURE ProcHead(procHead : ModuleParser.ProcHead);
  395. BEGIN
  396. ASSERT(procHead # NIL);
  397. IF IsPublic(procHead.identDef) THEN out.String("+ "); END;
  398. IF (procHead.constructor) THEN out.String("& "); END;
  399. IF (procHead.inline) THEN out.String("[inline] "); END;
  400. out.String(procHead.identDef.ident.name^);
  401. FormalPars(procHead.formalPars);
  402. out.String("\l");
  403. END ProcHead;
  404. PROCEDURE ProcDecl(procDecl : ModuleParser.ProcDecl);
  405. BEGIN
  406. WHILE (procDecl # NIL) DO
  407. IF IsPublic(procDecl.head.identDef) OR (procedures = All) THEN
  408. ProcHead(procDecl.head);
  409. END;
  410. IF (procDecl.next # NIL) THEN
  411. procDecl := procDecl.next (ModuleParser.ProcDecl);
  412. ELSE
  413. procDecl := NIL;
  414. END;
  415. END;
  416. END ProcDecl;
  417. PROCEDURE FieldDecl(fieldDecl : ModuleParser.FieldDecl);
  418. BEGIN
  419. WHILE (fieldDecl # NIL) DO
  420. IF (fieldDecl.identList # NIL) & (fieldDecl.type # NIL) THEN
  421. Variable(fieldDecl.identList, fieldDecl.type);
  422. END;
  423. IF (fieldDecl.next # NIL) THEN
  424. fieldDecl := fieldDecl.next (ModuleParser.FieldDecl);
  425. ELSE
  426. fieldDecl := NIL;
  427. END;
  428. END;
  429. END FieldDecl;
  430. PROCEDURE TypeDecl(typeDecl : ModuleParser.TypeDecl; indent : LONGINT);
  431. BEGIN
  432. ASSERT(typeDecl # NIL);
  433. FixTypeDeclName(typeDecl);
  434. IF list.Add(typeDecl.identDef.ident.name^) THEN
  435. IF ((typeDecl.type.object # NIL) OR (typeDecl.type.record # NIL) OR ((typeDecl.type.pointer # NIL) & (typeDecl.type.pointer.type.record # NIL))) & (IsPublic(typeDecl.identDef) OR (types = All)) THEN
  436. Indent(indent + 4); out.Char('"'); out.String(typeDecl.identDef.ident.name^);
  437. out.Char('"'); out.String(" ["); out.Ln;
  438. IF (typeDecl.type.object # NIL) & (ModuleParser.Active IN typeDecl.type.object.modifiers) THEN
  439. Indent(indent + 8); out.String('color = "red"'); out.Ln;
  440. END;
  441. Indent(indent + 8); out.String('label = "{'); out.String(typeDecl.identDef.ident.name^); Visibility(typeDecl.identDef);
  442. IF (procedures # None) OR (variables # None) THEN
  443. IF (typeDecl.type.object # NIL) THEN
  444. out.String("|");
  445. IF (typeDecl.type.object.declSeq # NIL) & (variables # None) THEN
  446. VarDecl(typeDecl.type.object.declSeq.varDecl);
  447. END;
  448. out.String("|");
  449. IF (typeDecl.type.object.declSeq # NIL) & (procedures # None) THEN
  450. ProcDecl(typeDecl.type.object.declSeq.procDecl);
  451. END;
  452. ELSIF (typeDecl.type.record # NIL) OR ((typeDecl.type.pointer # NIL) & (typeDecl.type.pointer.type.record # NIL)) THEN
  453. out.String("|");
  454. IF (variables # None) THEN
  455. IF (typeDecl.type.record # NIL) THEN
  456. FieldDecl(typeDecl.type.record.fieldList);
  457. ELSE
  458. FieldDecl(typeDecl.type.pointer.type.record.fieldList);
  459. END;
  460. END;
  461. END;
  462. END;
  463. out.String('}"'); out.Ln;
  464. Indent(indent + 4); out.String("]"); out.Ln;
  465. ELSIF showAllTypes & ((types = All) OR IsPublic(typeDecl.identDef)) THEN
  466. Indent(indent + 4); out.Char('"'); out.String(typeDecl.identDef.ident.name^);
  467. out.Char('"'); out.String(" ["); out.Ln;
  468. Indent(indent + 8); out.String('color = blue'); out.Ln;
  469. Indent(indent + 8); out.String('label = "{'); out.String(typeDecl.identDef.ident.name^); Visibility(typeDecl.identDef);
  470. IF (typeDecl.type.qualident # NIL) THEN
  471. out.String("|"); out.String(typeDecl.type.qualident.ident.name^);
  472. ELSIF (typeDecl.type.array # NIL) THEN
  473. out.String("|"); Array(typeDecl.type.array);
  474. ELSIF (typeDecl.type.pointer # NIL) & (typeDecl.type.pointer.type.array # NIL) THEN
  475. out.String("| POINTER TO "); Array(typeDecl.type.pointer.type.array);
  476. ELSIF (typeDecl.type.procedure # NIL) THEN
  477. out.String("| PROCEDURE ");
  478. IF (typeDecl.type.procedure.delegate) THEN out.String("[DELEGATE] "); END;
  479. FormalPars(typeDecl.type.procedure.formalPars);
  480. END;
  481. out.String('}"'); out.Ln;
  482. Indent(indent + 4); out.String("]"); out.Ln;
  483. END;
  484. END;
  485. END TypeDecl;
  486. PROCEDURE Module(module : ModuleParser.Module; indent : LONGINT);
  487. BEGIN
  488. ASSERT(module # NIL);
  489. Indent(indent); out.String("subgraph cluster"); out.String(module.ident.name^); out.String(" {"); out.Ln;
  490. Indent(indent + 4); out.String('label = "'); out.String(module.ident.name^); out.String('"'); out.Ln;
  491. Indent(indent + 4); out.String('bgcolor = "grey96"'); out.Ln;
  492. Indent(indent + 4); out.String('margin = "2,2"'); out.Ln;
  493. GenerateNodes(module, indent + 4);
  494. GenerateModuleNode(module, indent + 4);
  495. Indent(indent); out.String("}"); out.Ln;
  496. END Module;
  497. PROCEDURE GenerateModuleNode(module : ModuleParser.Module; indent : LONGINT);
  498. BEGIN
  499. ASSERT(module # NIL);
  500. IF (module.declSeq # NIL) THEN
  501. Indent(indent + 4); out.Char('"'); out.String("Module"); out.String(module.ident.name^);
  502. out.Char('"'); out.String(" ["); out.Ln;
  503. Indent(indent + 8); out.String('label = "{'); out.String("MODULE "); out.String(module.ident.name^);
  504. out.String("|");
  505. IF (module.declSeq.varDecl # NIL) & (variables # None) THEN
  506. VarDecl(module.declSeq.varDecl);
  507. END;
  508. out.String("|");
  509. IF (module.declSeq.procDecl # NIL) & (procedures # None) THEN
  510. ProcDecl(module.declSeq.procDecl);
  511. END;
  512. out.String('}"'); out.Ln;
  513. Indent(indent + 4); out.String("]"); out.Ln;
  514. END;
  515. END GenerateModuleNode;
  516. PROCEDURE GenerateNodes(module : ModuleParser.Module; indent : LONGINT);
  517. VAR typeDecl : ModuleParser.TypeDecl;
  518. BEGIN
  519. ASSERT(module # NIL);
  520. IF (module.declSeq # NIL) & (module.declSeq.typeDecl # NIL) THEN
  521. typeDecl := module.declSeq.typeDecl;
  522. WHILE (typeDecl # NIL) DO
  523. TypeDecl(typeDecl, indent);
  524. IF (typeDecl.next # NIL) THEN
  525. typeDecl := typeDecl.next (ModuleParser.TypeDecl);
  526. ELSE
  527. typeDecl := NIL;
  528. END;
  529. END;
  530. END;
  531. END GenerateNodes;
  532. PROCEDURE AddEdge(CONST from, to : ARRAY OF CHAR; indent : LONGINT);
  533. BEGIN
  534. Indent(indent);
  535. out.Char('"'); out.String(from); out.String('" -> "'); out.String(to); out.Char('"'); out.Ln;
  536. END AddEdge;
  537. PROCEDURE GenerateHasAEdges(entry : ModuleEntry; indent : LONGINT);
  538. VAR
  539. typeDecl : ModuleParser.TypeDecl;
  540. PROCEDURE AtLeastOneIdentIsPublic(identList : ModuleParser.IdentList) : BOOLEAN;
  541. BEGIN
  542. WHILE (identList # NIL) & ~IsPublic(identList.identDef) DO
  543. IF (identList.next # NIL) THEN
  544. identList := identList.next (ModuleParser.IdentList);
  545. ELSE
  546. identList := NIL;
  547. END;
  548. END;
  549. RETURN identList # NIL;
  550. END AtLeastOneIdentIsPublic;
  551. PROCEDURE GetTargetNodeName(CONST name : ARRAY OF CHAR; entry : ModuleEntry) : Strings.String;
  552. VAR targetNodeName : Strings.String; typeDecl : ModuleParser.TypeDecl;
  553. BEGIN
  554. typeDecl := FindTypeDecl(name, entry);
  555. IF (typeDecl # NIL) & (typeDecl.type # NIL) & ((showAllTypes) OR
  556. ((typeDecl.type.object # NIL) OR (typeDecl.type.record # NIL) OR ((typeDecl.type.pointer # NIL) & (typeDecl.type.pointer.type.record # NIL))))
  557. THEN
  558. targetNodeName := GetTypeName(typeDecl.type);
  559. ELSE
  560. targetNodeName := NIL;
  561. END;
  562. RETURN targetNodeName
  563. END GetTargetNodeName;
  564. PROCEDURE GenerateObjectFieldEdges(object : ModuleParser.Object; entry : ModuleEntry);
  565. VAR varDecl : ModuleParser.VarDecl; name : Strings.String; fullname : ARRAY 128 OF CHAR;
  566. BEGIN
  567. ASSERT(object # NIL);
  568. IF (object.declSeq # NIL) THEN
  569. varDecl := typeDecl.type.object.declSeq.varDecl;
  570. WHILE (varDecl # NIL) DO
  571. IF (varDecl.type.qualident # NIL) & ((hasA = All) OR AtLeastOneIdentIsPublic(varDecl.identList)) THEN
  572. FixTypeName(entry.module, varDecl.type.qualident.ident.name^, fullname);
  573. name := GetTargetNodeName(fullname, entry);
  574. IF (name # NIL) THEN
  575. hasAEdges.Add(typeDecl.identDef.ident.name^, name^);
  576. ELSIF ~IsBasicType(varDecl.type.qualident.ident.name^) THEN
  577. KernelLog.String("Object type not found: "); KernelLog.String(fullname);
  578. KernelLog.Ln;
  579. END;
  580. END;
  581. IF (varDecl.next # NIL) THEN
  582. varDecl := varDecl.next (ModuleParser.VarDecl);
  583. ELSE
  584. varDecl := NIL;
  585. END;
  586. END;
  587. END;
  588. END GenerateObjectFieldEdges;
  589. PROCEDURE GenerateRecordFieldEdges(record : ModuleParser.Record; entry : ModuleEntry);
  590. VAR fieldDecl : ModuleParser.FieldDecl; name : Strings.String;
  591. BEGIN
  592. ASSERT(record # NIL);
  593. fieldDecl := record.fieldList;
  594. WHILE (fieldDecl # NIL) DO
  595. IF (fieldDecl.type # NIL) & (fieldDecl.type.qualident # NIL) & ((hasA = All) OR AtLeastOneIdentIsPublic(fieldDecl.identList)) THEN
  596. name := GetTargetNodeName(fieldDecl.type.qualident.ident.name^, entry);
  597. IF (name # NIL) THEN
  598. hasAEdges.Add(typeDecl.identDef.ident.name^, name^);
  599. ELSIF ~IsBasicType(fieldDecl.type.qualident.ident.name^) THEN
  600. KernelLog.String("Record type not found: "); KernelLog.String(fieldDecl.type.qualident.ident.name^);
  601. KernelLog.Ln;
  602. END;
  603. END;
  604. IF (fieldDecl.next # NIL) THEN
  605. fieldDecl := fieldDecl.next (ModuleParser.FieldDecl);
  606. ELSE
  607. fieldDecl := NIL;
  608. END;
  609. END;
  610. END GenerateRecordFieldEdges;
  611. PROCEDURE GenerateArrayBaseEdge(array : ModuleParser.Array; entry : ModuleEntry);
  612. VAR name : Strings.String;
  613. BEGIN
  614. IF (array.base.qualident # NIL) THEN
  615. name := GetTargetNodeName(array.base.qualident.ident.name^, entry);
  616. IF (name # NIL) THEN
  617. hasAEdges.Add(typeDecl.identDef.ident.name^, name^);
  618. ELSIF ~IsBasicType(array.base.qualident.ident.name^) THEN
  619. KernelLog.String("Array type not found: "); KernelLog.String(array.base.qualident.ident.name^);
  620. KernelLog.Ln;
  621. END;
  622. END;
  623. END GenerateArrayBaseEdge;
  624. BEGIN
  625. IF (entry.module # NIL) & (entry.module.declSeq # NIL) THEN
  626. typeDecl := entry.module.declSeq.typeDecl;
  627. WHILE (typeDecl # NIL) DO
  628. IF (typeDecl.type.object # NIL) THEN
  629. GenerateObjectFieldEdges(typeDecl.type.object, entry);
  630. ELSIF (typeDecl.type.record # NIL) THEN
  631. GenerateRecordFieldEdges(typeDecl.type.record, entry);
  632. ELSIF ((typeDecl.type.pointer # NIL) & (typeDecl.type.pointer.type.record # NIL)) THEN
  633. GenerateRecordFieldEdges(typeDecl.type.pointer.type.record, entry);
  634. ELSIF showAllTypes THEN
  635. IF (typeDecl.type.array # NIL) THEN
  636. GenerateArrayBaseEdge(typeDecl.type.array, entry);
  637. ELSIF ((typeDecl.type.pointer # NIL) & (typeDecl.type.pointer.type.array # NIL)) THEN
  638. GenerateArrayBaseEdge(typeDecl.type.pointer.type.array, entry);
  639. END;
  640. END;
  641. IF (typeDecl.next # NIL) THEN
  642. typeDecl := typeDecl.next (ModuleParser.TypeDecl);
  643. ELSE
  644. typeDecl := NIL;
  645. END;
  646. END;
  647. END;
  648. END GenerateHasAEdges;
  649. PROCEDURE GenerateDependsOnEdges(entry : ModuleEntry; indent : LONGINT);
  650. VAR typeDecl : ModuleParser.TypeDecl;
  651. PROCEDURE CheckProcedures(procDecl : ModuleParser.ProcDecl);
  652. VAR
  653. typeName : Strings.String; fpSection : ModuleParser.FPSection; td : ModuleParser.TypeDecl;
  654. fullname, temp : ARRAY 128 OF CHAR;
  655. BEGIN
  656. WHILE (procDecl # NIL) DO
  657. IF (procDecl.head.formalPars # NIL) THEN
  658. fpSection := procDecl.head.formalPars.fpSectionList;
  659. WHILE (fpSection # NIL) DO
  660. IF (fpSection.type.qualident # NIL) THEN
  661. IF ~IsBasicType(fpSection.type.qualident.ident.name^) THEN
  662. td := FindTypeDecl(fpSection.type.qualident.ident.name^, entry);
  663. IF (td # NIL) THEN
  664. FixTypeName(entry.module, fpSection.type.qualident.ident.name^, fullname);
  665. IF ~Strings.ContainsChar(fullname, ".", FALSE) THEN
  666. COPY(fullname, temp);
  667. COPY(entry.module.ident.name^, fullname);
  668. Strings.Append(fullname, "."); Strings.Append(fullname, temp);
  669. END;
  670. dependsOnEdges.Add(typeDecl.identDef.ident.name^, fullname);
  671. ELSE
  672. KernelLog.String("Type "); KernelLog.String(fpSection.type.qualident.ident.name^);
  673. KernelLog.String(" not found"); KernelLog.Ln;
  674. END;
  675. END;
  676. ELSE
  677. typeName := GetTypeName(fpSection.type);
  678. IF (typeName # NIL) THEN
  679. dependsOnEdges.Add(typeDecl.identDef.ident.name^, typeName^);
  680. END;
  681. END;
  682. IF (fpSection.next # NIL) THEN
  683. fpSection := fpSection.next (ModuleParser.FPSection);
  684. ELSE
  685. fpSection := NIL;
  686. END;
  687. END;
  688. END;
  689. IF (procDecl.next # NIL) THEN
  690. procDecl := procDecl.next (ModuleParser.ProcDecl);
  691. ELSE
  692. procDecl := NIL;
  693. END;
  694. END;
  695. END CheckProcedures;
  696. BEGIN
  697. IF (entry.module # NIL) & (entry.module.declSeq # NIL) THEN
  698. typeDecl := entry.module.declSeq.typeDecl;
  699. WHILE (typeDecl # NIL) DO
  700. IF (typeDecl.type.object # NIL) & (typeDecl.type.object.declSeq # NIL) THEN
  701. CheckProcedures(typeDecl.type.object.declSeq.procDecl);
  702. END;
  703. IF (typeDecl.next # NIL) THEN
  704. typeDecl := typeDecl.next (ModuleParser.TypeDecl);
  705. ELSE
  706. typeDecl := NIL;
  707. END;
  708. END;
  709. END;
  710. END GenerateDependsOnEdges;
  711. PROCEDURE GenerateEdges(entry : ModuleEntry; indent : LONGINT);
  712. VAR typeDecl : ModuleParser.TypeDecl; object : ModuleParser.Object; record : ModuleParser.Record; name, name2 : Strings.String;
  713. PROCEDURE GetRecordName(record : ModuleParser.Record) : Strings.String;
  714. BEGIN
  715. ASSERT(record # NIL);
  716. IF (record.parent.parent IS ModuleParser.TypeDecl) THEN
  717. RETURN record.parent.parent(ModuleParser.TypeDecl).identDef.ident.name;
  718. ELSE
  719. RETURN record.parent.parent.parent.parent(ModuleParser.TypeDecl).identDef.ident.name;
  720. END;
  721. END GetRecordName;
  722. BEGIN
  723. IF (entry.module # NIL) & (entry.module.declSeq # NIL) & (entry.module.declSeq.typeDecl # NIL) THEN
  724. typeDecl := entry.module.declSeq.typeDecl;
  725. WHILE (typeDecl # NIL) DO
  726. IF (typeDecl.type.record # NIL) OR ((typeDecl.type.pointer # NIL) & (typeDecl.type.pointer.type.record # NIL)) THEN
  727. IF (typeDecl.type.record # NIL) THEN
  728. record := typeDecl.type.record;
  729. ELSE
  730. record := typeDecl.type.pointer.type.record;
  731. END;
  732. WHILE (record.superPtr # NIL) DO
  733. name := GetRecordName(record);
  734. IF ~list.IsSetSuperClass(name^) THEN
  735. list.SetSuperClass(name^);
  736. IF (record.superPtr.parent.parent IS ModuleParser.TypeDecl) THEN
  737. FixTypeDeclName(record.superPtr.parent.parent(ModuleParser.TypeDecl));
  738. ELSE
  739. FixTypeDeclName(record.superPtr.parent.parent.parent.parent(ModuleParser.TypeDecl));
  740. END;
  741. name2 := GetRecordName(record.superPtr);
  742. AddEdge(name^, name2^, indent);
  743. END;
  744. record := record.superPtr;
  745. END;
  746. ELSIF (typeDecl.type.object # NIL) THEN
  747. object := typeDecl.type.object;
  748. WHILE (object.superPtr # NIL) DO
  749. IF ~list.IsSetSuperClass(object.parent.parent(ModuleParser.TypeDecl).identDef.ident.name^) THEN
  750. list.SetSuperClass(object.parent.parent(ModuleParser.TypeDecl).identDef.ident.name^);
  751. FixTypeDeclName(object.superPtr.parent.parent(ModuleParser.TypeDecl));
  752. AddEdge(
  753. object.parent.parent(ModuleParser.TypeDecl).identDef.ident.name^,
  754. object.superPtr.parent.parent(ModuleParser.TypeDecl).identDef.ident.name^,
  755. indent
  756. );
  757. END;
  758. object := object.superPtr;
  759. END;
  760. END;
  761. IF (typeDecl.next # NIL) THEN
  762. typeDecl := typeDecl.next (ModuleParser.TypeDecl);
  763. ELSE
  764. typeDecl := NIL;
  765. END;
  766. END;
  767. END;
  768. END GenerateEdges;
  769. PROCEDURE AddSuperTypesSimple(entry : ModuleEntry; indent : LONGINT);
  770. VAR superClass : ModuleParser.Object; superRecord : ModuleParser.Record; typeDecl : ModuleParser.TypeDecl;
  771. BEGIN
  772. IF (AddSuperType IN entry.flags) & (entry.module # NIL) & (entry.module.declSeq # NIL) & (entry.module.declSeq.typeDecl # NIL) THEN
  773. typeDecl := entry.module.declSeq.typeDecl;
  774. WHILE (typeDecl # NIL) DO
  775. IF (typeDecl.type.object # NIL) THEN
  776. superClass := typeDecl.type.object.superPtr;
  777. WHILE (superClass # NIL) DO
  778. TypeDecl(superClass.parent.parent(ModuleParser.TypeDecl), indent);
  779. superClass := superClass.superPtr;
  780. END;
  781. ELSIF (typeDecl.type.record # NIL) OR ((typeDecl.type.pointer # NIL) & (typeDecl.type.pointer.type.record # NIL)) THEN
  782. IF (typeDecl.type.record # NIL) THEN
  783. superRecord := typeDecl.type.record.superPtr;
  784. ELSE
  785. superRecord := typeDecl.type.pointer.type.record.superPtr;
  786. END;
  787. WHILE (superRecord # NIL) DO
  788. IF (superRecord.parent.parent IS ModuleParser.TypeDecl) THEN
  789. TypeDecl(superRecord.parent.parent(ModuleParser.TypeDecl), indent);
  790. ELSE
  791. TypeDecl(superRecord.parent.parent.parent.parent(ModuleParser.TypeDecl), indent);
  792. END;
  793. superRecord := superRecord.superPtr;
  794. END;
  795. END;
  796. IF (typeDecl.next # NIL) THEN
  797. typeDecl := typeDecl.next (ModuleParser.TypeDecl);
  798. ELSE
  799. typeDecl := NIL;
  800. END;
  801. END;
  802. END;
  803. END AddSuperTypesSimple;
  804. PROCEDURE AddSuperTypeModulesToList(entry : ModuleEntry; indent : LONGINT);
  805. VAR
  806. superClass : ModuleParser.Object; superRecord : ModuleParser.Record;
  807. typeDecl : ModuleParser.TypeDecl;
  808. module : ModuleParser.Module;
  809. moduleName, typeName : ARRAY 128 OF CHAR;
  810. ignore : BOOLEAN;
  811. BEGIN
  812. IF (AddSuperType IN entry.flags) & ~(ScannedSuperTypes IN entry.flags) & (entry.module # NIL) & (entry.module.declSeq # NIL) & (entry.module.declSeq.typeDecl # NIL) THEN
  813. typeDecl := entry.module.declSeq.typeDecl;
  814. WHILE (typeDecl # NIL) DO
  815. IF (typeDecl.type.object # NIL) THEN
  816. superClass := typeDecl.type.object.superPtr;
  817. WHILE (superClass # NIL) DO
  818. module := superClass.GetModule();
  819. IF (module # NIL) & (module # entry.module) THEN
  820. IF ~IsExcluded(module.ident.name^) THEN
  821. ignore := modules.Add(module.ident.name^, NIL);
  822. END;
  823. ELSIF (superClass.parent.parent IS ModuleParser.TypeDecl) THEN
  824. ModuleParser.SplitName(superClass.parent.parent(ModuleParser.TypeDecl).identDef.ident.name^, moduleName, typeName);
  825. IF ~IsExcluded(moduleName) THEN
  826. ignore := modules.Add(moduleName, NIL);
  827. END;
  828. ELSE
  829. KernelLog.String("BOOM1: ");
  830. KernelLog.String(superClass.parent.parent(ModuleParser.TypeDecl).identDef.ident.name^); KernelLog.Ln;
  831. END;
  832. superClass := superClass.superPtr;
  833. END;
  834. ELSIF (typeDecl.type.record # NIL) OR ((typeDecl.type.pointer # NIL) & (typeDecl.type.pointer.type.record # NIL)) THEN
  835. IF (typeDecl.type.record # NIL) THEN
  836. superRecord := typeDecl.type.record.superPtr;
  837. ELSE
  838. superRecord := typeDecl.type.pointer.type.record.superPtr;
  839. END;
  840. WHILE (superRecord # NIL) DO
  841. module := superRecord.GetModule();
  842. IF (module # NIL) & (module # entry.module) THEN
  843. IF ~IsExcluded(module.ident.name^) THEN
  844. ignore := modules.Add(module.ident.name^, NIL);
  845. END;
  846. ELSIF (superRecord.parent.parent IS ModuleParser.TypeDecl) THEN
  847. ModuleParser.SplitName(superRecord.parent.parent(ModuleParser.TypeDecl).identDef.ident.name^, moduleName, typeName);
  848. IF ~IsExcluded(moduleName) THEN
  849. ignore := modules.Add(moduleName, NIL);
  850. END;
  851. ELSE
  852. KernelLog.String("BOOM2"); KernelLog.Ln;
  853. END;
  854. superRecord := superRecord.superPtr;
  855. END;
  856. END;
  857. IF (typeDecl.next # NIL) THEN
  858. typeDecl := typeDecl.next (ModuleParser.TypeDecl);
  859. ELSE
  860. typeDecl := NIL;
  861. END;
  862. END;
  863. modules.InclFlag(entry.module.ident.name^, ScannedSuperTypes);
  864. END;
  865. END AddSuperTypeModulesToList;
  866. PROCEDURE AddUsedTypeModulesToList(entry : ModuleEntry; ident : LONGINT);
  867. VAR
  868. typeDecl : ModuleParser.TypeDecl; varDecl : ModuleParser.VarDecl;
  869. moduleName, typeName : ARRAY 128 OF CHAR;
  870. fullname : ARRAY 256 OF CHAR;
  871. ignore : BOOLEAN;
  872. BEGIN
  873. IF (entry.module # NIL) & (entry.module.declSeq # NIL) THEN
  874. typeDecl := entry.module.declSeq.typeDecl;
  875. WHILE (typeDecl # NIL) DO
  876. IF (typeDecl.type.object # NIL) & (typeDecl.type.object.declSeq # NIL) THEN
  877. varDecl := typeDecl.type.object.declSeq.varDecl;
  878. WHILE (varDecl # NIL) DO
  879. IF (varDecl.type.qualident # NIL) THEN
  880. FixTypeName(entry.module, varDecl.type.qualident.ident.name^, fullname);
  881. ModuleParser.SplitName(fullname, moduleName, typeName);
  882. IF (moduleName # "") & (moduleName # entry.name) THEN
  883. IF ~IsExcluded(moduleName) THEN
  884. ignore := modules.Add(moduleName, NIL);
  885. END
  886. END;
  887. END;
  888. IF (varDecl.next # NIL) THEN
  889. varDecl := varDecl.next (ModuleParser.VarDecl);
  890. ELSE
  891. varDecl := NIL;
  892. END;
  893. END;
  894. END;
  895. IF (typeDecl.next # NIL) THEN
  896. typeDecl := typeDecl.next (ModuleParser.TypeDecl);
  897. ELSE
  898. typeDecl := NIL;
  899. END;
  900. END;
  901. END;
  902. END AddUsedTypeModulesToList;
  903. PROCEDURE AddDependeciesModulesToList(entry : ModuleEntry; ident : LONGINT);
  904. VAR
  905. typeDecl : ModuleParser.TypeDecl; procDecl : ModuleParser.ProcDecl;
  906. moduleName, typeName : ARRAY 128 OF CHAR;
  907. PROCEDURE CheckFPSection(fpSection : ModuleParser.FPSection);
  908. VAR type : ModuleParser.Type; ignore : BOOLEAN;
  909. BEGIN
  910. ASSERT((fpSection # NIL) & (fpSection.type # NIL));
  911. type := fpSection.type;
  912. IF (type.object # NIL) THEN
  913. ELSIF (type.record # NIL) THEN
  914. ELSIF (type.pointer # NIL) & (type.pointer.type.record # NIL) THEN
  915. ELSIF (type.qualident # NIL) & ~IsBasicType(type.qualident.ident.name^) THEN
  916. ModuleParser.SplitName(type.qualident.ident.name^, moduleName, typeName);
  917. IF (moduleName # "") & (moduleName # entry.module.ident.name^) THEN
  918. IF ~IsExcluded(moduleName) THEN
  919. ignore := modules.Add(moduleName, NIL);
  920. END;
  921. END;
  922. END;
  923. END CheckFPSection;
  924. PROCEDURE CheckProcDecl(entry : ModuleEntry; procDecl : ModuleParser.ProcDecl);
  925. VAR fpSection : ModuleParser.FPSection;
  926. BEGIN
  927. ASSERT((procDecl # NIL) & (procDecl.head # NIL));
  928. IF (procDecl.head.formalPars # NIL) & (procDecl.head.formalPars.fpSectionList # NIL) THEN
  929. fpSection := procDecl.head.formalPars.fpSectionList;
  930. WHILE (fpSection # NIL) DO
  931. CheckFPSection(fpSection);
  932. IF (fpSection.next # NIL) THEN
  933. fpSection := fpSection.next (ModuleParser.FPSection);
  934. ELSE
  935. fpSection := NIL;
  936. END;
  937. END;
  938. END;
  939. END CheckProcDecl;
  940. BEGIN
  941. ASSERT(entry # NIL);
  942. IF (entry.module # NIL) & (entry.module.declSeq # NIL) THEN
  943. typeDecl := entry.module.declSeq.typeDecl;
  944. WHILE (typeDecl # NIL) DO
  945. IF (typeDecl.type.object # NIL) & (typeDecl.type.object.declSeq # NIL) THEN
  946. procDecl := typeDecl.type.object.declSeq.procDecl;
  947. WHILE (procDecl # NIL) DO
  948. CheckProcDecl(entry, procDecl);
  949. IF (procDecl.next # NIL) THEN
  950. procDecl := procDecl.next (ModuleParser.ProcDecl);
  951. ELSE
  952. procDecl := NIL;
  953. END;
  954. END;
  955. END;
  956. IF (typeDecl.next # NIL) THEN
  957. typeDecl := typeDecl.next (ModuleParser.TypeDecl);
  958. ELSE
  959. typeDecl := NIL;
  960. END;
  961. END;
  962. END;
  963. END AddDependeciesModulesToList;
  964. PROCEDURE FindTypeDecl(CONST name : ARRAY OF CHAR; entry : ModuleEntry) : ModuleParser.TypeDecl;
  965. VAR
  966. moduleName, typeName, fullname : ARRAY 128 OF CHAR;
  967. e : ModuleEntry;
  968. typeDecl : ModuleParser.TypeDecl;
  969. BEGIN
  970. typeDecl := NIL;
  971. ModuleParser.SplitName(name, moduleName, typeName);
  972. IF ~IsBasicType(typeName) & (moduleName # "SYSTEM") THEN
  973. IF (moduleName = entry.name) OR (moduleName = "") THEN
  974. COPY(entry.module.ident.name^, fullname); Strings.Append(fullname, "."); Strings.Append(fullname, typeName);
  975. typeDecl := entry.module.FindTypeDecl(fullname);
  976. ELSE
  977. e := modules.FindByName(moduleName);
  978. IF (e # NIL) & (e.module # NIL) THEN
  979. FixTypeName(e.module, name, fullname);
  980. typeDecl := e.module.FindTypeDecl(fullname);
  981. END;
  982. END;
  983. END;
  984. RETURN typeDecl;
  985. END FindTypeDecl;
  986. PROCEDURE ParseModule(entry : ModuleEntry; ident : LONGINT);
  987. VAR filename : Files.FileName; file : Files.File;
  988. BEGIN
  989. IF (entry.name # "SYSTEM") & (entry.module = NIL) & ~(Parsed IN entry.flags) THEN
  990. COPY(entry.name, filename); Strings.Append(filename, ".Mod");
  991. file := Files.Old(filename);
  992. IF (file = NIL) THEN
  993. KernelLog.String("Visualizer: Cannot open file "); KernelLog.String(filename); KernelLog.String(", try I386.");
  994. KernelLog.String(filename); KernelLog.String(" ... ");
  995. filename := "I386."; Strings.Append(filename, entry.name); Strings.Append(filename, ".Mod");
  996. file := Files.Old(filename);
  997. IF (file # NIL) THEN
  998. KernelLog.String("found!");
  999. ELSE
  1000. KernelLog.String("not found!, Trying Oberon."); KernelLog.String(entry.name); KernelLog.String(" ... ");
  1001. filename := "Oberon-"; Strings.Append(filename, entry.name); Strings.Append(filename, ".Mod");
  1002. file := Files.Old(filename);
  1003. IF (file # NIL) THEN
  1004. KernelLog.String("found!");
  1005. ELSE
  1006. KernelLog.String("not found! Giving up...");
  1007. END;
  1008. END;
  1009. KernelLog.Ln;
  1010. END;
  1011. IF (file # NIL) THEN
  1012. ParseFile(filename, entry.module);
  1013. modules.InclFlag(entry.name, Parsed);
  1014. IF (entry.module # NIL) THEN
  1015. Module(entry.module, 4);
  1016. END;
  1017. ELSE
  1018. KernelLog.String("Visualizer: File "); KernelLog.String(filename); KernelLog.String(" not found - ignore!");
  1019. KernelLog.Ln;
  1020. END;
  1021. END;
  1022. END ParseModule;
  1023. PROCEDURE AddTypes;
  1024. VAR done : BOOLEAN; nofEntries : LONGINT;
  1025. BEGIN
  1026. IF (mode = Simple) THEN
  1027. IF (hasA # None) THEN modules.Enumerate(AddUsedTypeModulesToList, 4); END;
  1028. IF (dependencies # None) THEN modules.Enumerate(AddDependeciesModulesToList, 4); END;
  1029. modules.Enumerate(AddSuperTypesSimple, 4);
  1030. ELSIF (mode = Better) THEN
  1031. modules.Enumerate(AddSuperTypeModulesToList, 4);
  1032. IF (hasA # None) THEN modules.Enumerate(AddUsedTypeModulesToList, 4); END;
  1033. IF (dependencies # None) THEN modules.Enumerate(AddDependeciesModulesToList, 4); END;
  1034. modules.Enumerate(ParseModule, 0);
  1035. modules.Enumerate(AddSuperTypesSimple, 4);
  1036. ELSIF (mode = Extreme) THEN
  1037. done := FALSE;
  1038. WHILE ~done DO
  1039. nofEntries := modules.nofEntries;
  1040. modules.Enumerate(AddSuperTypeModulesToList, 4);
  1041. IF (hasA # None) THEN modules.Enumerate(AddUsedTypeModulesToList, 4); END;
  1042. IF (dependencies # None) THEN modules.Enumerate(AddDependeciesModulesToList, 4); END;
  1043. modules.Enumerate(ParseModule, 0);
  1044. done := nofEntries = modules.nofEntries;
  1045. END;
  1046. modules.Enumerate(AddSuperTypesSimple, 4);
  1047. END;
  1048. END AddTypes;
  1049. PROCEDURE ProcessOptions(options : Options.Options);
  1050. VAR string : ARRAY 512 OF CHAR; integer : LONGINT; sizeString : SizeString; i : LONGINT;
  1051. BEGIN
  1052. sizeString := "";
  1053. IF options.GetString("size", string) THEN
  1054. GetSizeString(string, sizeString);
  1055. END;
  1056. IF options.GetFlag("landscape")THEN
  1057. Rotate(sizeString);
  1058. END;
  1059. IF (sizeString # "") THEN
  1060. Indent(4); out.String('size = "'); out.String(sizeString); out.String('"'); out.Ln;
  1061. END;
  1062. IF options.GetInteger("mode", integer) THEN
  1063. IF (0 <= integer) & (integer <= Extreme) THEN
  1064. SELF.mode := integer;
  1065. END;
  1066. END;
  1067. IF options.GetString("options", string) THEN
  1068. Indent(4); out.String(string); out.Ln;
  1069. END;
  1070. IF options.GetFlag("all") THEN showAllTypes := TRUE; ELSE showAllTypes := FALSE; END;
  1071. IF options.GetString("types", string) THEN
  1072. types := GetMode(string);
  1073. ELSE
  1074. types := DefaultTypes;
  1075. END;
  1076. IF options.GetString("variables", string) THEN
  1077. variables := GetMode(string);
  1078. ELSE
  1079. variables := DefaultVariables;
  1080. END;
  1081. IF options.GetString("procedures", string) THEN
  1082. procedures := GetMode(string);
  1083. ELSE
  1084. procedures := DefaultProcedures;
  1085. END;
  1086. IF options.GetString("hasA", string) THEN
  1087. hasA := GetMode(string);
  1088. ELSE
  1089. hasA := DefaultHasA;
  1090. END;
  1091. IF options.GetString("dependencies", string) THEN
  1092. dependencies := GetMode(string);
  1093. ELSE
  1094. dependencies := DefaultDependencies;
  1095. END;
  1096. IF options.GetString("exclude", string) THEN
  1097. excludedModules := Strings.Split(string, " ");
  1098. FOR i := 0 TO LEN(excludedModules)-1 DO
  1099. Strings.TrimWS(excludedModules[i]^);
  1100. END;
  1101. ELSE
  1102. excludedModules := NIL;
  1103. END;
  1104. END ProcessOptions;
  1105. PROCEDURE IsExcluded(CONST moduleName : ARRAY OF CHAR) : BOOLEAN;
  1106. VAR i : LONGINT;
  1107. BEGIN
  1108. IF (excludedModules # NIL) THEN
  1109. FOR i := 0 TO LEN(excludedModules)-1 DO
  1110. IF (moduleName = excludedModules[i]^) THEN RETURN TRUE; END;
  1111. END;
  1112. END;
  1113. RETURN FALSE;
  1114. END IsExcluded;
  1115. PROCEDURE Open(options : Options.Options);
  1116. BEGIN
  1117. ASSERT(options # NIL);
  1118. ASSERT(state = Initialized);
  1119. state := Running;
  1120. out.String("digraph TEST"); out.String(" {"); out.Ln;
  1121. ProcessOptions(options);
  1122. Indent(4); out.String('rankdir = "BT"'); out.Ln;
  1123. Indent(4); out.String('ranksep = "0.5"'); out.Ln;
  1124. Indent(4); out.String('ratio = "compress"'); out.Ln;
  1125. Indent(4); out.String('remincross = "true"'); out.Ln;
  1126. IF options.GetFlag("landscape") THEN
  1127. Indent(4); out.String('orientation = "landscape"'); out.Ln;
  1128. END;
  1129. Indent(4); out.String("node ["); out.Ln;
  1130. Indent(8); out.String('fontname = "'); out.String(NodeFontName); out.String('"'); out.Ln;
  1131. Indent(8); out.String('fontsize = "'); out.Int(NodeFontSize, 0); out.String('"'); out.Ln;
  1132. Indent(8); out.String('shape = "record"'); out.Ln;
  1133. Indent(4); out.String("]"); out.Ln;
  1134. END Open;
  1135. PROCEDURE AddModule(module : ModuleParser.Module; indent : LONGINT);
  1136. BEGIN
  1137. ASSERT(module # NIL);
  1138. ASSERT(state = Running);
  1139. IF modules.Add(module.ident.name^, module) THEN
  1140. modules.InclFlag(module.ident.name^, Parsed);
  1141. Module(module, indent);
  1142. END;
  1143. END AddModule;
  1144. PROCEDURE WriteHasAEdge(edge : Edge);
  1145. BEGIN
  1146. Indent(4);
  1147. out.Char('"'); out.String(edge.from); out.String('" -> "'); out.String(edge.to); out.Char('"');
  1148. out.String(" [weight = "); out.FloatFix(HasAFactor * edge.count, 4, 1, 0); out.String("]"); out.Ln;
  1149. END WriteHasAEdge;
  1150. PROCEDURE WriteDependsOnEdge(edge : Edge);
  1151. BEGIN
  1152. Indent(4);
  1153. out.Char('"'); out.String(edge.from); out.String('" -> "'); out.String(edge.to); out.Char('"');
  1154. out.String(" [weight = "); out.FloatFix(DependsOnFactor * edge.count, 4, 1, 0); out.String("]"); out.Ln;
  1155. END WriteDependsOnEdge;
  1156. PROCEDURE Close;
  1157. VAR array : ModuleArray; i : LONGINT;
  1158. BEGIN
  1159. ASSERT(state = Running);
  1160. AddTypes;
  1161. KernelLog.String("Included modules: ");
  1162. array := modules.GetAll();
  1163. FOR i := 0 TO LEN(array)-1 DO
  1164. KernelLog.String(array[i].name); KernelLog.String(" ");
  1165. END;
  1166. KernelLog.Ln;
  1167. Indent(4); out.String("edge ["); out.Ln;
  1168. Indent(8); out.String('arrowhead = "normal"'); out.Ln;
  1169. Indent(8); out.String('arrowtail = "none"'); out.Ln;
  1170. Indent(8); out.String('arrowsize = "4.0"'); out.Ln;
  1171. Indent(8); out.String('penwidth = "5"'); out.Ln;
  1172. Indent(8); out.String('color = "black"'); out.Ln;
  1173. Indent(8); out.String('weight = 100'); out.Ln;
  1174. Indent(4); out.String("]"); out.Ln;
  1175. modules.Enumerate(GenerateEdges, 4);
  1176. IF (hasA # None) THEN
  1177. Indent(4); out.String("edge ["); out.Ln;
  1178. Indent(8); out.String('arrowhead = "none"'); out.Ln;
  1179. Indent(8); out.String('arrowtail = "diamond"'); out.Ln;
  1180. Indent(8); out.String('arrowsize = "2.0"'); out.Ln;
  1181. Indent(8); out.String('penwidth = "1"'); out.Ln;
  1182. Indent(8); out.String('color = "blue"'); out.Ln;
  1183. Indent(4); out.String("]"); out.Ln;
  1184. modules.Enumerate(GenerateHasAEdges, 4);
  1185. hasAEdges.Enumerate(WriteHasAEdge);
  1186. END;
  1187. IF (dependencies # None) THEN
  1188. Indent(4); out.String("edge ["); out.Ln;
  1189. Indent(8); out.String('arrowhead = "normal"'); out.Ln;
  1190. Indent(8); out.String('arrowtail = "none"'); out.Ln;
  1191. Indent(8); out.String('arrowsize = "2.0"'); out.Ln;
  1192. Indent(8); out.String('penwidth = "1"'); out.Ln;
  1193. Indent(8); out.String('color = "green"'); out.Ln;
  1194. Indent(8); out.String('style = "dashed"'); out.Ln;
  1195. Indent(4); out.String("]"); out.Ln;
  1196. modules.Enumerate(GenerateDependsOnEdges, 4);
  1197. dependsOnEdges.Enumerate(WriteDependsOnEdge);
  1198. END;
  1199. state := Stopped;
  1200. out.String("}");
  1201. out.Update;
  1202. END Close;
  1203. PROCEDURE Indent(indent : LONGINT); (* private *)
  1204. BEGIN
  1205. WHILE (indent > 0) DO out.Char(" "); DEC(indent); END;
  1206. END Indent;
  1207. END Generator;
  1208. PROCEDURE FixTypeName(module : ModuleParser.Module; CONST name : ARRAY OF CHAR; VAR fullname : ARRAY OF CHAR);
  1209. VAR modulename, importname, typename : ARRAY 256 OF CHAR;
  1210. BEGIN
  1211. ModuleParser.SplitName(name, modulename, typename);
  1212. IF (modulename # "") THEN (* replace import alias by module name *)
  1213. IF (module # NIL) THEN
  1214. FindImport(modulename, module, importname);
  1215. ELSE
  1216. importname := "";
  1217. END;
  1218. IF (modulename # importname) & (importname # "") THEN
  1219. COPY(importname, fullname);
  1220. Strings.Append(fullname, "."); Strings.Append(fullname, typename);
  1221. ELSE
  1222. COPY(name, fullname);
  1223. END;
  1224. ELSE
  1225. COPY(name, fullname);
  1226. END;
  1227. END FixTypeName;
  1228. PROCEDURE FixTypeDeclName(typeDecl : ModuleParser.TypeDecl);
  1229. VAR module : ModuleParser.Module; name, typeName : ARRAY 256 OF CHAR;
  1230. BEGIN
  1231. ASSERT(typeDecl # NIL);
  1232. IF ~Strings.ContainsChar(typeDecl.identDef.ident.name^, ".", FALSE) THEN
  1233. module := typeDecl.GetModule();
  1234. IF (module # NIL) THEN
  1235. COPY(typeDecl.identDef.ident.name^, typeName);
  1236. COPY(module.ident.name^, name);
  1237. Strings.Append(name, ".");
  1238. Strings.Append(name, typeName);
  1239. typeDecl.identDef.ident.name := Strings.NewString(name);
  1240. END;
  1241. END;
  1242. END FixTypeDeclName;
  1243. PROCEDURE GetTypeName(node : ModuleParser.Node) : Strings.String;
  1244. VAR name : Strings.String;
  1245. BEGIN
  1246. WHILE (node # NIL) & (node.parent # node) & ~(node IS ModuleParser.TypeDecl) DO node := node.parent; END;
  1247. IF (node # NIL) & (node IS ModuleParser.TypeDecl) THEN
  1248. name := node(ModuleParser.TypeDecl).identDef.ident.name;
  1249. ELSE
  1250. name := Strings.NewString("UnknownType");
  1251. END;
  1252. RETURN name;
  1253. END GetTypeName;
  1254. PROCEDURE IsBasicType(CONST string : ARRAY OF CHAR) : BOOLEAN;
  1255. BEGIN
  1256. RETURN (string = "CHAR") OR (string = "ANY") OR (string = "BOOLEAN") OR (string = "SET")
  1257. OR (string = "SHORTINT") OR (string = "INTEGER") OR (string = "LONGINT") OR (string = "HUGEINT")
  1258. OR (string = "REAL") OR (string = "LONGREAL")
  1259. OR (string = "ADDRESS") OR (string = "SIZE") OR (string = "SYSTEM.BYTE");
  1260. END IsBasicType;
  1261. PROCEDURE FindImport(CONST name : ARRAY OF CHAR; module : ModuleParser.Module; VAR importName : ARRAY OF CHAR);
  1262. VAR import : ModuleParser.Import;
  1263. BEGIN
  1264. ASSERT(module # NIL);
  1265. importName:= "";
  1266. IF (name # "") THEN
  1267. import := module.FindImport(name);
  1268. IF (import # NIL) THEN
  1269. IF (import.alias # NIL) THEN
  1270. COPY(import.alias.name^, importName);
  1271. ELSE
  1272. COPY(import.ident.name^, importName);
  1273. END;
  1274. END;
  1275. END;
  1276. END FindImport;
  1277. PROCEDURE Rotate(VAR size : SizeString);
  1278. VAR stringArray : Strings.StringArray;
  1279. BEGIN
  1280. stringArray := Strings.Split(size, ",");
  1281. IF (LEN(stringArray) = 2) THEN
  1282. COPY(stringArray[1]^, size);
  1283. Strings.Append(size, ",");
  1284. Strings.Append(size, stringArray[0]^);
  1285. END;
  1286. END Rotate;
  1287. PROCEDURE GetSizeString(CONST size : ARRAY OF CHAR; VAR sizeString : SizeString);
  1288. BEGIN
  1289. IF (size = "A0") THEN sizeString := "33.1,46.8";
  1290. ELSIF (size = "A1") THEN sizeString := "22.4,33.1";
  1291. ELSIF (size = "A2") THEN sizeString := "16.5,23.4";
  1292. ELSIF (size = "A3") THEN sizeString := "11.7,16.5";
  1293. ELSIF (size = "A4") THEN sizeString := "8.3,11.7";
  1294. ELSIF (size = "A5") THEN sizeString := "5.8,8.3";
  1295. ELSIF (size = "A6") THEN sizeString := "4.1,5.8";
  1296. ELSIF (size = "A7") THEN sizeString := "2.9,4.1";
  1297. ELSIF (size = "A8") THEN sizeString := "2.05,2.9";
  1298. ELSIF (size = "A9") THEN sizeString := "1.46,2.05";
  1299. ELSIF (size = "A10") THEN sizeString := "1.02,1.46";
  1300. ELSE
  1301. COPY(size, sizeString);
  1302. END;
  1303. END GetSizeString;
  1304. PROCEDURE ParseFile(CONST filename : ARRAY OF CHAR; VAR module : ModuleParser.Module);
  1305. VAR
  1306. scanner : FoxScanner.Scanner;
  1307. text : Texts.Text;
  1308. reader : TextUtilities.TextReader;
  1309. diagnostics : Diagnostics.StreamDiagnostics;
  1310. writer : Streams.Writer;
  1311. format, res : LONGINT;
  1312. BEGIN
  1313. module := NIL;
  1314. NEW(text);
  1315. TextUtilities.LoadAuto(text, filename, format, res);
  1316. IF (res = 0) THEN
  1317. NEW(writer, KernelLog.Send, 256);
  1318. NEW(diagnostics, writer);
  1319. NEW(reader, text);
  1320. scanner := FoxScanner.NewScanner(filename, reader, 0, diagnostics);
  1321. ModuleParser.Parse(scanner, module);
  1322. IF (module # NIL) THEN
  1323. ModuleParser.SetSuperTypes(module);
  1324. END;
  1325. END;
  1326. END ParseFile;
  1327. PROCEDURE GetMode(CONST string : ARRAY OF CHAR) : LONGINT;
  1328. VAR mode : LONGINT;
  1329. BEGIN
  1330. ASSERT((string = "none") OR (string = "public") OR (string = "all"));
  1331. IF (string = "none") THEN mode := None;
  1332. ELSIF (string = "public") THEN mode := Public;
  1333. ELSIF (string = "all") THEN mode := All;
  1334. END;
  1335. ASSERT((mode = None) OR (mode = Public) OR (mode = All));
  1336. RETURN mode;
  1337. END GetMode;
  1338. PROCEDURE Generate*(context : Commands.Context); (** [options] moduleName {" " modulename} ~ *)
  1339. VAR
  1340. moduleName, outputFilename : Files.FileName;
  1341. module : ModuleParser.Module;
  1342. file : Files.File;
  1343. writer : Files.Writer;
  1344. generator : Generator;
  1345. options : Options.Options;
  1346. PROCEDURE IsValid(CONST string : ARRAY OF CHAR) : BOOLEAN;
  1347. BEGIN
  1348. RETURN (string = "none") OR (string = "public") OR (string = "all");
  1349. END IsValid;
  1350. PROCEDURE CheckOptions(options : Options.Options; out : Streams.Writer) : BOOLEAN;
  1351. VAR string : ARRAY 32 OF CHAR; integer : LONGINT; error : BOOLEAN;
  1352. BEGIN
  1353. ASSERT((options # NIL) & (out # NIL));
  1354. error := FALSE;
  1355. IF options.GetString("types", string) & ~IsValid(string) THEN
  1356. out.String("Option argument wrong: -t / --types = 'none' | 'public' | 'all'"); out.Ln;
  1357. error := TRUE;
  1358. END;
  1359. IF options.GetString("variables", string) & ~IsValid(string) THEN
  1360. out.String("Option argument wrong: -v / --variables = 'none' | 'public' | 'all'"); out.Ln;
  1361. error := TRUE;
  1362. END;
  1363. IF options.GetString("procedures", string) & ~IsValid(string) THEN
  1364. out.String("Option argument wrong: -p / --procedures = 'none' | 'public' | 'all'"); out.Ln;
  1365. error := TRUE;
  1366. END;
  1367. IF options.GetString("hasA", string) & ~IsValid(string) THEN
  1368. out.String("Option argument wrong: -h / --hasA = 'none' | 'public' | 'all'"); out.Ln;
  1369. error := TRUE;
  1370. END;
  1371. IF options.GetString("dependencies", string) & ~IsValid(string) THEN
  1372. out.String("Option argument wrong: -d / --dependencies = 'none' | 'public' | 'all'"); out.Ln;
  1373. error := TRUE;
  1374. END;
  1375. IF options.GetInteger("mode", integer) & (integer # Simple) & (integer # Better) & (integer # Extreme) THEN
  1376. out.String("Option argument wrong: -m / --mode = 0 | 1 | 2"); out.Ln;
  1377. error := TRUE;
  1378. END;
  1379. RETURN ~error;
  1380. END CheckOptions;
  1381. BEGIN
  1382. NEW(options);
  1383. options.Add("a", "all", Options.Flag);
  1384. options.Add("d", "dependencies", Options.String);
  1385. options.Add("s", "size", Options.String);
  1386. options.Add("f", "file", Options.String);
  1387. options.Add("h", "hasA", Options.String);
  1388. options.Add("l", "landscape", Options.Flag);
  1389. options.Add("o", "options", Options.String);
  1390. options.Add("m", "mode", Options.Integer);
  1391. options.Add("t", "types", Options.String);
  1392. options.Add("v", "variables", Options.String);
  1393. options.Add("p", "procedures", Options.String);
  1394. options.Add("e", "exclude", Options.String);
  1395. IF options.Parse(context.arg, context.out) THEN
  1396. IF CheckOptions(options, context.out) THEN
  1397. IF ~options.GetString("file", outputFilename) THEN
  1398. COPY(DefaultOutputFilename, outputFilename);
  1399. END;
  1400. file := Files.New(outputFilename);
  1401. IF (file # NIL) THEN
  1402. NEW(writer, file, 0);
  1403. NEW(generator, writer);
  1404. generator.Open(options);
  1405. WHILE context.arg.GetString(moduleName) DO
  1406. ParseFile(moduleName, module);
  1407. IF (module # NIL) THEN
  1408. generator.AddModule(module, 4);
  1409. context.out.String("Added "); context.out.String(moduleName); context.out.Ln;
  1410. ELSE
  1411. context.out.String("Error: Could not parse module "); context.out.String(moduleName); context.out.Ln;
  1412. END;
  1413. END;
  1414. generator.Close;
  1415. Files.Register(file);
  1416. context.out.String("Graph description written to "); context.out.String(outputFilename); context.out.Ln;
  1417. ELSE
  1418. context.out.String("Could not create file "); context.out.String(moduleName); context.out.Ln;
  1419. END;
  1420. END;
  1421. END;
  1422. END Generate;
  1423. END Visualizer.
  1424. Visualizer.Generate PET.Mod ~
  1425. Visualizer.Generate -s="A3" -m=1 --landscape WMWindowManager.Mod WindowManager.Mod WMComponents.Mod WMStandardComponents.Mod ~
  1426. Visualizer.Generate -s="A3" -l -o='ratio = "compress" '-m=1 Usbdi.Mod Usb.Mod UsbHcdi.Mod UsbEhci.Mod UsbHubDriver.Mod ~
  1427. Visualizer.Generate -s="A3" -l -o='ratio = "compress" '-m=1 -v=all -p=all -h=all -a -d=all Usbdi.Mod Usb.Mod UsbHcdi.Mod UsbEhci.Mod UsbHubDriver.Mod ~
  1428. Visualizer.Generate -s="A3" -m=2 --landscape WMWindowManager.Mod WindowManager.Mod ~
  1429. Visualizer.Generate -s="A3" -o='page = "--landscape PCT.Mod ~
  1430. Visualizer.Generate -s="A0" -l -o='ratio = "fill" '-m=2 -v=public -p=public -h=all -a
  1431. -e="WMFontManager Modules Kernel Raster CLUTs Machine Heaps Objects"
  1432. XMLObjects.Mod XML.Mod WMMessages.Mod WMGraphics.Mod WMFontManager.Mod WindowManager.Mod WMWindowManager.Mod
  1433. WMEvents.Mod WMProperties.Mod WMComponents.Mod ~
  1434. Visualizer.Generate -s="A0" -l -o='ratio = "fill"' -m=2 -v=public -p=public -h=all -a
  1435. -e="Modules"
  1436. Oberon.Objects.Mod Oberon.Links.Mod Oberon.Attributes.Mod Oberon.Gadgets.Mod
  1437. ~
  1438. Visualizer.Generate -a -s="A0" -v=all --procedures=all --hasA=all -d=all --mode=0 Visualizer.Mod ~
  1439. Visualizer.Generate -a -s="A3" ratio="fill"' -v=none -p=none -h=all -m=2 -e="Modules Machine Heaps Objects Kernel Raster XMLObjects XML" WMEvents.Mod WMProperties.Mod WMComponents.Mod WindowManager.Mod ~
  1440. Visualizer.Generate -a -s="A3" -v=all -p=all -h=all -m=2 Trace.Mod I386.Machine.Mod Heaps.Mod Objects.Mod Modules.Mod Kernel.Mod ~
  1441. Visualizer.Generate -a -s="A3" -v=all -p=all -m=1 WMWindowManager.Mod ~
  1442. SystemTools.Free Visualizer ~ Test.svg