FoxDocumentationBackend.Mod 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828
  1. (**
  2. The special backend in the Fox compiler suite serves as a documentation generator to produce documents from Oberon source files.
  3. #author# Felix Friedrich
  4. #purpose# Documentation Generator
  5. *)
  6. MODULE FoxDocumentationBackend;
  7. (**
  8. @concept
  9. = Documentation Backend
  10. The [[FoxDocumentationBackend|documentation backend]] is mainly a tool to merge different informations, namely:
  11. # The information from the symbol and module scope structure
  12. # The information provided by documenting comments
  13. Documentation comments that immediately precede a symbol or that are directly in the same line as a symbol are associated with this symbol.
  14. Therefore the documentation contained within the respective comment is on the same level as the description of the symbol itself and will be
  15. displayed together with the information about the symbol.
  16. The following describes how a documentation is generated from a module:
  17. * Association to symbols and preprocessing
  18. ## A comment that follows a symbol X and stands in the same line as X is associated with this symbol X.
  19. ## Comments that follow the MODULE (or CELLNET) specification are treated separately to describe the module.
  20. ## Any other comment that stand in front of some symbol Y is associated with this symbol Y.
  21. ## Consecutive comments are always merged as character arrays mefore being parsed by the comment parser.
  22. * Module documentation
  23. ## Each comment (or sequence of consecutive comments) is parsed by the comment parser into a separate document
  24. ## During processing of a module, each symbol is described in a separate symbol section. The module itself is described in the module summary section.
  25. ## Each comment document is merged with the respective symbol section in the overal module document.
  26. * Module documentation merging
  27. ## When more than one modules are processed into one documentation file, the module documentats are merged into one global document.
  28. ## The header of the document contains a linked list of all involved modules.
  29. == Formatting elements
  30. === Paragraphs and line breaks
  31. Text is written in paragraphs. Paragraphs are separated by a blank line. Lines that are not separated by a blank line are considered as contiguous text (such as in LaTex)
  32. Explicit line breaks can be inserted using two backslashes:
  33. {{{ This is a line \\ that is broken }}}
  34. This is a line \\ that is broken
  35. === Text Styles
  36. Text can be written boldface, underlined or in italics. Left and right delimiters of such emphasized text may not be separated from the text by a whitespace.
  37. |=Name |= Code Example |= Translation |
  38. | Boldface | {{{ *example text*}}} | *Boldface Text* |
  39. | Underline | {{{ _example text_}}} | _Underline Text_ |
  40. | Italics | {{{ /example text/ }}} | /Italics Text/ |
  41. === bullets and lists
  42. Bulleted or numbered lists start with an asterisk or number sign, respectively. Description start with a text that is embraced by number signs.
  43. {{{ * bullet 1
  44. ** sub bullet1
  45. ** sub bullet2
  46. * bullet 2
  47. # number 1
  48. ## sub number 1
  49. ## sub number 2
  50. # number 2
  51. #description label# description text
  52. #description label2# description text2 }}}
  53. Result
  54. * bullet 1
  55. ** sub bullet1
  56. ** sub bullet2
  57. * bullet 2
  58. # number 1
  59. ## sub number 1
  60. ## sub number 2
  61. # number 2
  62. #description label# description text
  63. #description label2# description text2
  64. === Labels and links
  65. A label in the text is denoted as follows
  66. {{{ <<labelName>> }}} <<labelName>>
  67. A link in the text is denoted as
  68. {{{ [[labelName]] }}}
  69. or, if an alternative text should be displayed, it can be written as
  70. {{{ [[labelName|alternative text]] }}}
  71. === Document Structure
  72. Documents consist of sections. A section is started with a sequence of {{{@}}} letter as the first characters on a separate line. Examples:
  73. {{{ @ title of a section of level 1 }}}
  74. {{{ @@ title of a section of level 2 }}}
  75. If the first text element of the title is a label, then this lable is attributed to the section.
  76. {{{ @ <<label>> title }}}
  77. This can be written shorter: If there is no whitespace between the leading section letter and a string, the string is also counted as the label of the section:
  78. {{{ @label title }}}
  79. For structuring a section, headings are provided. A heading is started with an equal sign as the first character in a separate line. Examples
  80. {{{ = title of a paragraph of level 1
  81. == title of a paragraph of level 2
  82. =label title
  83. = <<label>> title }}}
  84. === Tables
  85. Tables can be written by writing cells in a separate paragraph. A cell is either a header cell or a data cell. Header cells start with a vertical bar and an equal sign
  86. while data cells are embraced by vertical lines only:
  87. {{{
  88. |= header 1 |= header 2 |= header 3
  89. | data 1 | data 2 | data 3
  90. | data 4 | data 5 | data 6 }}}
  91. Result:
  92. |= header 1 |= header 2 |= header 3
  93. | data 1 | data 2 | data 3
  94. | data 4 | data 5 | data 6 }}}
  95. **)
  96. IMPORT Basic := FoxBasic, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal, Scanner := FoxScanner, Backend := FoxBackend, Formats := FoxFormats,
  97. Options, Streams, Strings, SymbolFileFormat := FoxTextualSymbolFile, Diagnostics,
  98. DocumentationTree := FoxDocumentationTree, DocumentationPrinter := FoxDocumentationPrinter, DocumentationHtml := FoxDocumentationHtml, DocumentationParser := FoxDocumentationParser, DocumentationScanner := FoxDocumentationScanner,
  99. D := Debugging, Files;
  100. CONST
  101. Section=0;
  102. Item=1;
  103. Enum=2;
  104. MaxLevels=3;
  105. VisibleConstant*=3; (** visible constant comment **)
  106. (** second visible constant *)
  107. SecondVisibleConstant*=4;
  108. Third*=4;
  109. DefaultTemplateFile="oc/DocuTemplate.txt";
  110. KeywordElementType = ElementType.Bold;
  111. QualifiedIdentifierElementType = ElementType.Bold;
  112. TYPE
  113. ElementType=DocumentationTree.ElementType;
  114. ParagraphType=DocumentationTree.ParagraphType;
  115. State= RECORD
  116. document: DocumentationTree.Document;
  117. section: DocumentationTree.Section;
  118. paragraphs: DocumentationTree.Paragraphs;
  119. paragraph: DocumentationTree.Paragraph;
  120. text: DocumentationTree.Text;
  121. scope: SyntaxTree.Scope;
  122. END;
  123. (** Printer object to write the documentation to a stream. Implemented as visitor on the Syntax Tree.*)
  124. Generator*= OBJECT (SyntaxTree.Visitor)
  125. VAR
  126. w,ws: Streams.StringWriter;
  127. case: LONGINT;
  128. diagnostics: Diagnostics.Diagnostics;
  129. (* transient state variables *)
  130. level: ARRAY MaxLevels OF LONGINT;
  131. current: State;
  132. document: DocumentationTree.Document;
  133. parameterDocument: DocumentationTree.Document;
  134. short: BOOLEAN;
  135. backend: DocumentationBackend;
  136. PROCEDURE &Init*(diagnostics: Diagnostics.Diagnostics);
  137. VAR i: LONGINT;
  138. BEGIN
  139. NEW(w,1024); NEW(ws, 64); case := Scanner.Uppercase;
  140. FOR i := 0 TO MaxLevels-1 DO level[i] := 0 END;
  141. SELF.diagnostics := diagnostics;
  142. current.document := NIL; current.section := NIL; current.paragraphs := NIL; current.text := NIL;
  143. document := NIL;
  144. END Init;
  145. (* helper procedures *)
  146. PROCEDURE Keyword(CONST a: ARRAY OF CHAR);
  147. VAR
  148. str: ARRAY 64 OF CHAR;
  149. BEGIN
  150. IF case= Scanner.Lowercase THEN Small(a,str) ELSE COPY(a,str) END;
  151. w.String(str);
  152. ToText(w,current.text,KeywordElementType);
  153. END Keyword;
  154. PROCEDURE Identifier*(x: SyntaxTree.Identifier);
  155. VAR str: Scanner.IdentifierString;
  156. BEGIN
  157. Basic.GetString(x,str); w.String(str);ToText(w,current.text,ElementType.Default)
  158. END Identifier;
  159. (** Procedure used to traverse qualified identifiers **)
  160. PROCEDURE QualifiedIdentifier*(x: SyntaxTree.QualifiedIdentifier);
  161. VAR str: Scanner.IdentifierString;
  162. BEGIN
  163. IF x.prefix # SyntaxTree.invalidIdentifier THEN Basic.GetString(x.prefix,str); w.String(str); w.String("."); END;
  164. Basic.GetString(x.suffix,str); w.String(str); ToText(w,current.text,QualifiedIdentifierElementType);
  165. END QualifiedIdentifier;
  166. (* types *)
  167. PROCEDURE Type*(x: SyntaxTree.Type);
  168. BEGIN
  169. IF x # NIL THEN x.Accept(SELF) END;
  170. END Type;
  171. PROCEDURE VisitType*(x: SyntaxTree.Type);
  172. BEGIN
  173. END VisitType;
  174. PROCEDURE VisitBasicType*(x: SyntaxTree.BasicType);
  175. BEGIN
  176. IF x.typeDeclaration # NIL THEN
  177. Identifier(x.typeDeclaration.name)
  178. ELSE
  179. Identifier(x.name)
  180. END
  181. END VisitBasicType;
  182. PROCEDURE VisitBooleanType*(x: SyntaxTree.BooleanType);
  183. BEGIN VisitBasicType(x)
  184. END VisitBooleanType;
  185. PROCEDURE VisitSetType*(x: SyntaxTree.SetType);
  186. BEGIN VisitBasicType(x)
  187. END VisitSetType;
  188. PROCEDURE VisitSizeType*(x: SyntaxTree.SizeType);
  189. BEGIN VisitBasicType(x)
  190. END VisitSizeType;
  191. PROCEDURE VisitCharacterType*(x: SyntaxTree.CharacterType);
  192. BEGIN VisitBasicType(x)
  193. END VisitCharacterType;
  194. PROCEDURE VisitIntegerType*(x: SyntaxTree.IntegerType);
  195. BEGIN VisitBasicType(x)
  196. END VisitIntegerType;
  197. PROCEDURE VisitFloatType*(x: SyntaxTree.FloatType);
  198. BEGIN VisitBasicType(x)
  199. END VisitFloatType;
  200. PROCEDURE VisitComplexType*(x: SyntaxTree.ComplexType);
  201. BEGIN VisitBasicType(x)
  202. END VisitComplexType;
  203. PROCEDURE VisitByteType*(x: SyntaxTree.ByteType);
  204. BEGIN VisitBasicType(x)
  205. END VisitByteType;
  206. PROCEDURE VisitQualifiedType*(x: SyntaxTree.QualifiedType);
  207. BEGIN
  208. IF x.qualifiedIdentifier # NIL THEN
  209. QualifiedIdentifier(x.qualifiedIdentifier)
  210. END;
  211. END VisitQualifiedType;
  212. PROCEDURE VisitStringType*(x: SyntaxTree.StringType);
  213. BEGIN
  214. END VisitStringType;
  215. PROCEDURE VisitEnumerationType*(x: SyntaxTree.EnumerationType);
  216. VAR e: SyntaxTree.Constant; first: BOOLEAN;
  217. BEGIN
  218. Keyword("ENUMERATION"); Whitespace;
  219. IF x.enumerationBase # NIL THEN
  220. String("(");
  221. Type(x.enumerationBase);
  222. String(")");
  223. END;
  224. IF ~short THEN
  225. e := x.enumerationScope.firstConstant; first := TRUE;
  226. WHILE (e # NIL) DO
  227. IF ~first THEN String(","); Whitespace; ELSE first := FALSE END;
  228. VisitConstant(e);
  229. e := e.nextConstant;
  230. END;
  231. END;
  232. END VisitEnumerationType;
  233. PROCEDURE VisitRangeType*(x: SyntaxTree.RangeType);
  234. BEGIN VisitBasicType(x);
  235. END VisitRangeType;
  236. PROCEDURE VisitArrayType*(x: SyntaxTree.ArrayType);
  237. BEGIN
  238. Keyword("ARRAY"); Whitespace;
  239. IF x.length # NIL THEN Expression(x.length);ToText(w,current.text,ElementType.Default);Whitespace; END;
  240. Keyword("OF");Whitespace;
  241. Type(x.arrayBase);
  242. END VisitArrayType;
  243. PROCEDURE VisitNilType*(x: SyntaxTree.NilType);
  244. BEGIN
  245. String("NILTYPE");
  246. END VisitNilType;
  247. PROCEDURE VisitAddressType*(x: SyntaxTree.AddressType);
  248. BEGIN
  249. String("ADDRESSTYPE");
  250. END VisitAddressType;
  251. PROCEDURE VisitObjectType*(x: SyntaxTree.ObjectType);
  252. BEGIN
  253. VisitBasicType(x);
  254. END VisitObjectType;
  255. PROCEDURE VisitAnyType*(x: SyntaxTree.AnyType);
  256. BEGIN
  257. VisitBasicType(x);
  258. END VisitAnyType;
  259. PROCEDURE VisitMathArrayType*(x: SyntaxTree.MathArrayType);
  260. BEGIN
  261. Keyword("ARRAY" );Whitespace;
  262. IF x.form = SyntaxTree.Tensor THEN String("[?]");
  263. ELSE
  264. String("[");
  265. IF x.length = NIL THEN
  266. String("*")
  267. ELSE
  268. Expression(x.length);
  269. END;
  270. WHILE(x.arrayBase # NIL) & (x.arrayBase IS SyntaxTree.MathArrayType) DO
  271. x := x.arrayBase(SyntaxTree.MathArrayType);
  272. String(",");
  273. IF x.length = NIL THEN
  274. String("*")
  275. ELSE
  276. Expression(x.length);
  277. END;
  278. END;
  279. String("]");Whitespace;
  280. END;
  281. IF x.arrayBase # NIL THEN
  282. Keyword("OF" );Whitespace;
  283. Type(x.arrayBase);
  284. END;
  285. END VisitMathArrayType;
  286. PROCEDURE VisitPointerType*(x: SyntaxTree.PointerType);
  287. VAR pointerBase: SyntaxTree.Type;
  288. BEGIN
  289. IF x.pointerBase # NIL THEN
  290. pointerBase := x.pointerBase;
  291. IF (pointerBase IS SyntaxTree.RecordType) & (pointerBase(SyntaxTree.RecordType).isObject) THEN
  292. VisitRecordType(pointerBase(SyntaxTree.RecordType))
  293. ELSE
  294. Keyword("POINTER"); Whitespace; Keyword("TO" ); Whitespace; Type(x.pointerBase)
  295. END;
  296. END;
  297. END VisitPointerType;
  298. PROCEDURE VisitPortType*(x: SyntaxTree.PortType);
  299. BEGIN
  300. Keyword("PORT");Whitespace;
  301. IF x.direction = SyntaxTree.OutPort THEN
  302. Keyword("OUT")
  303. ELSE
  304. ASSERT(x.direction = SyntaxTree.InPort);
  305. Keyword("IN");
  306. END;
  307. Whitespace;
  308. IF x.sizeExpression # NIL THEN
  309. String("("); Expression(x.sizeExpression); String(")");
  310. END;
  311. END VisitPortType;
  312. PROCEDURE VisitCellType*(x: SyntaxTree.CellType);
  313. BEGIN
  314. Keyword("CELL");Whitespace;
  315. Modifiers(x.modifiers);
  316. IF x.firstParameter # NIL THEN ParameterList(x.firstParameter) END;
  317. IF ~short THEN
  318. Summary(current.paragraphs, x.cellScope);
  319. Scope(x.cellScope);
  320. END;
  321. END VisitCellType;
  322. PROCEDURE VisitRecordType*(x: SyntaxTree.RecordType);
  323. VAR prevScope: SyntaxTree.Scope; first: BOOLEAN; variable: SyntaxTree.Variable;
  324. BEGIN
  325. IF x.isObject THEN
  326. Keyword("OBJECT");Whitespace;
  327. IF x.pointerType # NIL THEN END;
  328. IF (x.baseType # NIL) THEN
  329. String( "(" );
  330. IF (x.baseType IS SyntaxTree.RecordType) & (x.baseType(SyntaxTree.RecordType).pointerType # NIL) THEN
  331. Type(x.baseType(SyntaxTree.RecordType).pointerType)
  332. ELSE
  333. Type(x.baseType);
  334. END;
  335. String( ")" );
  336. END;
  337. IF ~short THEN
  338. Summary(current.paragraphs, x.recordScope);
  339. Scope(x.recordScope);
  340. END;
  341. ELSE
  342. Keyword("RECORD");Whitespace;
  343. IF (x.baseType # NIL) THEN
  344. String( "(" );
  345. IF (x.baseType IS SyntaxTree.RecordType) & (x.baseType(SyntaxTree.RecordType).pointerType # NIL) THEN
  346. Type(x.baseType(SyntaxTree.RecordType).pointerType)
  347. ELSE
  348. Type(x.baseType);
  349. END;
  350. String( ")" );
  351. END;
  352. IF ~short THEN
  353. Summary(current.paragraphs, x.recordScope);
  354. Scope(x.recordScope);
  355. END;
  356. END;
  357. END VisitRecordType;
  358. PROCEDURE VisitProcedureType*(x: SyntaxTree.ProcedureType);
  359. VAR first: BOOLEAN;
  360. BEGIN
  361. Keyword("PROCEDURE" );
  362. first := TRUE;
  363. IF x.isDelegate THEN Flag(Global.NameDelegate,first) END;
  364. IF x.isInterrupt THEN Flag(Global.NameInterrupt,first) END;
  365. IF x.noPAF THEN Flag(Global.NameNoPAF,first) END;
  366. IF x.callingConvention = SyntaxTree.WinAPICallingConvention THEN
  367. Flag(Global.NameWinAPI,first)
  368. ELSIF x.callingConvention = SyntaxTree.CCallingConvention THEN
  369. Flag(Global.NameC,first)
  370. END;
  371. IF x.stackAlignment > 1 THEN Value(Global.NameStackAligned,x.stackAlignment,first) END;
  372. IF ~first THEN String("}") END;
  373. Whitespace;
  374. IF (x.firstParameter # NIL) OR (x.returnType # NIL) THEN
  375. ParameterList(x.firstParameter)
  376. END;
  377. IF x.returnType # NIL THEN String( ":" ); Whitespace; Type(x.returnType) END;
  378. END VisitProcedureType;
  379. (* expressions *)
  380. PROCEDURE ExpressionList(x: SyntaxTree.ExpressionList);
  381. VAR i: LONGINT; expression: SyntaxTree.Expression;
  382. BEGIN
  383. FOR i := 0 TO x.Length() - 1 DO
  384. expression := x.GetExpression( i ); Expression(expression);
  385. IF i < x.Length() - 1 THEN String( "," ); END;
  386. END;
  387. END ExpressionList;
  388. PROCEDURE Expression*(x: SyntaxTree.Expression);
  389. BEGIN
  390. IF x # NIL THEN
  391. x.Accept(SELF);
  392. END;
  393. w.Update;
  394. END Expression;
  395. PROCEDURE VisitExpression*(x: SyntaxTree.Expression);
  396. BEGIN
  397. END VisitExpression;
  398. PROCEDURE VisitSet*(x: SyntaxTree.Set);
  399. BEGIN
  400. String( "{" ); ExpressionList(x.elements); String( "}" );
  401. END VisitSet;
  402. PROCEDURE VisitMathArrayExpression*(x: SyntaxTree.MathArrayExpression);
  403. BEGIN
  404. String( "[" ); ExpressionList(x.elements); String( "]" );
  405. END VisitMathArrayExpression;
  406. PROCEDURE VisitUnaryExpression*(x: SyntaxTree.UnaryExpression);
  407. VAR identifier: SyntaxTree.Identifier;
  408. BEGIN
  409. IF x.operator = Scanner.Transpose THEN
  410. identifier := Global.GetIdentifier(x.operator,case);
  411. Expression(x.left);
  412. Identifier(identifier);
  413. ELSE
  414. identifier := Global.GetIdentifier(x.operator,case);
  415. Identifier(identifier);
  416. Expression(x.left);
  417. END;
  418. END VisitUnaryExpression;
  419. PROCEDURE VisitBinaryExpression*(x: SyntaxTree.BinaryExpression);
  420. VAR identifier: SyntaxTree.Identifier;
  421. BEGIN
  422. String( "(" );
  423. Expression(x.left);
  424. identifier := Global.GetIdentifier(x.operator,case);
  425. Identifier(identifier);
  426. Expression(x.right);
  427. String(")");
  428. END VisitBinaryExpression;
  429. PROCEDURE VisitRangeExpression*(x: SyntaxTree.RangeExpression);
  430. BEGIN
  431. IF x.missingFirst & x.missingLast & x.missingStep THEN
  432. String("*")
  433. ELSE
  434. IF ~x.missingFirst THEN Expression(x.first) END;
  435. String("..");
  436. IF ~x.missingLast THEN Expression(x.last) END;
  437. IF ~x.missingStep THEN
  438. Keyword("BY");
  439. Expression(x.step)
  440. END
  441. END;
  442. END VisitRangeExpression;
  443. PROCEDURE VisitTensorRangeExpression*(x: SyntaxTree.TensorRangeExpression);
  444. BEGIN String("?");
  445. END VisitTensorRangeExpression;
  446. PROCEDURE VisitConversion*(x: SyntaxTree.Conversion);
  447. BEGIN
  448. IF x.typeExpression # NIL THEN Expression(x.typeExpression); String("(");
  449. END;
  450. Expression(x.expression);
  451. IF x.typeExpression # NIL THEN String(")") END;
  452. END VisitConversion;
  453. PROCEDURE VisitSymbolDesignator*(x: SyntaxTree.SymbolDesignator);
  454. BEGIN
  455. IF x.left # NIL THEN
  456. Expression(x.left); String(".");
  457. END;
  458. IF x.symbol IS SyntaxTree.Operator THEN
  459. String('"'); Identifier(x.symbol.name); String('"');
  460. ELSE
  461. Identifier(x.symbol.name)
  462. END;
  463. END VisitSymbolDesignator;
  464. PROCEDURE VisitBuiltinCallDesignator*(x: SyntaxTree.BuiltinCallDesignator);
  465. BEGIN
  466. IF x.left # NIL THEN
  467. Expression(x.left);
  468. ELSE
  469. String("BUILTIN(");
  470. w.Int(x.id,1);
  471. String(")");
  472. END;
  473. String("("); ExpressionList(x.parameters); String(")");
  474. END VisitBuiltinCallDesignator;
  475. PROCEDURE VisitValue*(x: SyntaxTree.Value);
  476. BEGIN
  477. END VisitValue;
  478. PROCEDURE VisitBooleanValue*(x: SyntaxTree.BooleanValue);
  479. BEGIN
  480. IF Scanner.Uppercase = case THEN
  481. IF x.value THEN String("TRUE" ) ELSE String( "FALSE" ) END
  482. ELSE
  483. IF x.value THEN String("true" ) ELSE String( "false" ) END
  484. END
  485. END VisitBooleanValue;
  486. PROCEDURE VisitIntegerValue*(x: SyntaxTree.IntegerValue);
  487. BEGIN
  488. w.Int(x.value,1);
  489. ToText(w,current.text,ElementType.Default);
  490. END VisitIntegerValue;
  491. PROCEDURE VisitCharacterValue*(x: SyntaxTree.CharacterValue);
  492. BEGIN
  493. Hex(w, ORD(x.value)); w.String( "X" );
  494. ToText(w,current.text,ElementType.Default);
  495. END VisitCharacterValue;
  496. PROCEDURE VisitSetValue*(x: SyntaxTree.SetValue);
  497. VAR i: LONGINT;
  498. BEGIN
  499. w.String("{");
  500. i := 0;
  501. WHILE (i<MAX(SET)) & ~(i IN x.value) DO
  502. INC(i);
  503. END;
  504. IF i<MAX(SET) THEN
  505. w.Int(i,1);
  506. INC(i);
  507. WHILE i < MAX(SET) DO
  508. IF i IN x.value THEN w.String(","); w.Int(i,1); END;
  509. INC(i)
  510. END
  511. END;
  512. w.String("}");
  513. ToText(w,current.text,ElementType.Default);
  514. END VisitSetValue;
  515. PROCEDURE VisitMathArrayValue*(x: SyntaxTree.MathArrayValue);
  516. BEGIN
  517. VisitMathArrayExpression(x.array);
  518. END VisitMathArrayValue;
  519. PROCEDURE FormatedFloat(value: LONGREAL; subtype: LONGINT);
  520. VAR string: ARRAY 128 OF CHAR; i: LONGINT;
  521. BEGIN
  522. IF subtype = Scanner.Real THEN
  523. ws.SetPos(0); ws.Float(value,11(*mantissa X.XXXXXXX *)+5(*exponent E+XXX *)); ws.Get(string);
  524. i := 0;
  525. WHILE(i<LEN(string)) & (string[i] # 0X) DO
  526. IF string[i] = "D" THEN string[i] := "E" END;
  527. INC(i);
  528. END;
  529. String(string);
  530. ELSIF subtype = Scanner.Longreal THEN
  531. ws.SetPos(0); ws.Float(value,20(*mantissa X.X..(16)..X *)+5(*exponent E+XXX *) ); ws.Get(string);
  532. i := 0;
  533. WHILE(i<LEN(string)) & (string[i] # 0X) DO
  534. IF string[i] = "E" THEN string[i] := "D" END;
  535. INC(i);
  536. END;
  537. String(string);
  538. ELSE
  539. w.Float(value,64);
  540. ToText(w,current.text,ElementType.Default);
  541. END;
  542. END FormatedFloat;
  543. PROCEDURE VisitRealValue*(x: SyntaxTree.RealValue);
  544. BEGIN FormatedFloat(x.value, x.subtype)
  545. END VisitRealValue;
  546. PROCEDURE VisitComplexValue*(x: SyntaxTree.ComplexValue);
  547. BEGIN
  548. IF (x.realValue = 0) & (x.imagValue = 1) THEN
  549. String("IMAG")
  550. ELSE
  551. String("(");
  552. FormatedFloat(x.realValue, x.subtype) ;
  553. IF x.imagValue > 0 THEN String("+") END;
  554. FormatedFloat(x.imagValue, x.subtype);
  555. String("*IMAG)")
  556. END
  557. END VisitComplexValue;
  558. PROCEDURE VisitStringValue*(x: SyntaxTree.StringValue);
  559. VAR i: LONGINT;
  560. BEGIN
  561. i := 0;
  562. WHILE (i < LEN( x.value )) & (x.value[i] # 0X) & (x.value[i] # '"') DO INC( i ); END;
  563. ASSERT(i # LEN(x.value));
  564. IF (x.value[i] = 0X) THEN (* no double quotes contained in the string *)
  565. w.String( '"' ); w.String( x.value^ ); w.String( '"' );
  566. ELSE (* double quotes found in string *)
  567. w.String( "'" ); w.String( x.value^ ); w.String( "'" );
  568. END;
  569. ToText(w,current.text,ElementType.Default);
  570. END VisitStringValue;
  571. PROCEDURE VisitNilValue*(x: SyntaxTree.NilValue);
  572. BEGIN String( "NIL" );
  573. END VisitNilValue;
  574. PROCEDURE VisitEnumerationValue*(x: SyntaxTree.EnumerationValue);
  575. BEGIN w.Int(x.value,1); ToText(w,current.text,ElementType.Default);
  576. END VisitEnumerationValue;
  577. (**** symbols ****)
  578. PROCEDURE VisitParameter*(x: SyntaxTree.Parameter);
  579. END VisitParameter;
  580. PROCEDURE PrintSymbol(x: SyntaxTree.Symbol);
  581. VAR first: BOOLEAN; w: Streams.StringWriter; name: Scanner.IdentifierString;
  582. BEGIN
  583. NEW(w,256);
  584. Basic.GetString(x.name,name);
  585. IF x IS SyntaxTree.Operator THEN
  586. w.String('"'); w.String(name); w.String('"')
  587. ELSE
  588. w.String(name)
  589. END;
  590. IF SyntaxTree.PublicWrite IN x.access THEN w.String( "*" )
  591. ELSIF SyntaxTree.PublicRead IN x.access THEN
  592. IF x IS SyntaxTree.Variable THEN
  593. w.String( "-" )
  594. ELSIF ~(x IS SyntaxTree.Parameter) THEN
  595. w.String("*")
  596. END
  597. END;
  598. ToText(w, current.text,ElementType.Default);
  599. END PrintSymbol;
  600. PROCEDURE ParameterList*(x: SyntaxTree.Parameter);
  601. VAR next: SyntaxTree.Parameter; first: BOOLEAN;
  602. BEGIN
  603. first := TRUE;
  604. String( "(" );
  605. WHILE(x # NIL) DO
  606. next := x.nextParameter;
  607. IF (x.access # SyntaxTree.Hidden) THEN
  608. IF ~first THEN String(";"); Whitespace END;
  609. first := FALSE;
  610. IF x.kind = SyntaxTree.VarParameter THEN Keyword("VAR" );Whitespace;
  611. ELSIF x.kind = SyntaxTree.ConstParameter THEN Keyword("CONST" );Whitespace;
  612. END;
  613. PrintSymbol(x);
  614. IF x.defaultValue # NIL THEN
  615. String("="); Whitespace; Expression(x.defaultValue);
  616. END;
  617. WHILE (next # NIL) & (next.type = x.type) & (next.kind = x.kind) & ((next.access # SyntaxTree.Hidden) ) DO
  618. String(",");Whitespace;
  619. PrintSymbol(next);
  620. IF next.defaultValue # NIL THEN
  621. String("="); Whitespace; Expression(next.defaultValue);
  622. END;
  623. next := next.nextParameter;
  624. END;
  625. IF x.access # SyntaxTree.Hidden THEN
  626. String(":");Whitespace;
  627. Type(x.type);
  628. ELSE
  629. String(":");Whitespace;
  630. Type(x.type);
  631. END;
  632. END;
  633. x := next;
  634. END;
  635. String( ")" );
  636. END ParameterList;
  637. PROCEDURE Visible(symbol: SyntaxTree.Symbol): BOOLEAN;
  638. BEGIN
  639. RETURN (symbol # NIL) & ( (SyntaxTree.Public * symbol.access # {}) OR backend.internals)
  640. END Visible;
  641. PROCEDURE Symbol*(x: SyntaxTree.Symbol);
  642. BEGIN
  643. IF Visible(x) THEN x.Accept(SELF) END
  644. END Symbol;
  645. PROCEDURE NeedsSection(x: SyntaxTree.Symbol): BOOLEAN;
  646. VAR declaredType: SyntaxTree.Type;tmp: SyntaxTree.Comment;
  647. BEGIN
  648. IF x.comment # NIL THEN
  649. tmp := x.comment;
  650. WHILE (tmp # NIL) & (tmp.item = x) DO
  651. IF tmp.source[0] = "*" THEN RETURN TRUE END;
  652. tmp := tmp.nextComment
  653. END;
  654. END;
  655. IF x IS SyntaxTree.TypeDeclaration THEN
  656. declaredType := x(SyntaxTree.TypeDeclaration).declaredType.resolved;
  657. IF declaredType IS SyntaxTree.PointerType THEN declaredType := declaredType(SyntaxTree.PointerType).pointerBase.resolved END;
  658. RETURN (declaredType IS SyntaxTree.RecordType) OR (declaredType IS SyntaxTree.EnumerationType)
  659. END;
  660. RETURN FALSE
  661. END NeedsSection;
  662. PROCEDURE ExtractParameters(x: SyntaxTree.ProcedureType; doc: DocumentationTree.Document; VAR parameters: DocumentationTree.Document);
  663. VAR par: SyntaxTree.Parameter; paragraph,heading: DocumentationTree.Paragraph; i: LONGINT; element: DocumentationTree.TextElement;
  664. string: DocumentationTree.String; id: SyntaxTree.Identifier; done: BOOLEAN;
  665. BEGIN
  666. i := 0;
  667. WHILE i < doc.description.Length() DO
  668. paragraph := doc.description.GetParagraph(i);
  669. done := FALSE;
  670. IF (paragraph.type = ParagraphType.Description) & (paragraph.description.Length() = 1) THEN
  671. element := paragraph.description.GetElement(0);
  672. string := element.string;
  673. id := SyntaxTree.NewIdentifier(string^);
  674. par := x.firstParameter;
  675. WHILE (par # NIL) & ~done DO
  676. IF par.name = id THEN
  677. done := TRUE;
  678. doc.description.RemoveByIndex(i);
  679. IF parameters = NIL THEN
  680. NEW(parameters);
  681. END;
  682. parameters.description.Add(paragraph);
  683. END;
  684. par := par.nextParameter;
  685. END;
  686. IF ~done & ((string^="RESULT") OR (string^="result")) THEN
  687. doc.description.RemoveByIndex(i);
  688. IF parameters = NIL THEN
  689. NEW(parameters);
  690. END;
  691. parameters.description.Add(paragraph);
  692. done := TRUE;
  693. END;
  694. END;
  695. IF ~done THEN INC(i) END;
  696. END;
  697. END ExtractParameters;
  698. PROCEDURE WriteSymbolSection(x: SyntaxTree.Symbol);
  699. VAR section: DocumentationTree.Section; paragraph: DocumentationTree.Paragraph; commentDoc: DocumentationTree.Document;
  700. parameters: DocumentationTree.Document;
  701. BEGIN
  702. IF Visible(x) & NeedsSection(x) THEN
  703. section := BeginSymbolSection("",x);
  704. parameterDocument := NIL;
  705. IF x.comment # NIL THEN
  706. commentDoc := DocumentationTree.NewDocument();
  707. ParseComments(commentDoc,x.comment, NIL,x);
  708. PatchLinks(commentDoc, x.scope);
  709. KeepSections(commentDoc);
  710. IF (x IS SyntaxTree.Procedure) THEN
  711. ExtractParameters(x.type(SyntaxTree.ProcedureType), commentDoc, parameters);
  712. END;
  713. MergeDocument(current.document, section.contents, commentDoc);
  714. END;
  715. paragraph := section.contents.AppendNew(ParagraphType.Heading);
  716. paragraph.SetLevel(2);
  717. paragraph.text.WriteString("Syntax");
  718. paragraph := section.contents.AppendNew(ParagraphType.Code);
  719. current.text := paragraph.text;
  720. Symbol(x);
  721. IF parameters # NIL THEN
  722. paragraph := section.contents.AppendNew(ParagraphType.Heading);
  723. paragraph.SetLevel(2);
  724. paragraph.text.WriteString("Parameters");
  725. MergeDocument(current.document, section.contents, parameters);
  726. END;
  727. EndSection(section);
  728. END;
  729. END WriteSymbolSection;
  730. PROCEDURE BeginSymbolSection(CONST title: ARRAY OF CHAR; x: SyntaxTree.Symbol):DocumentationTree.Section;
  731. VAR section: DocumentationTree.Section; name: Basic.SectionName; paragraph:DocumentationTree.Paragraph;
  732. BEGIN
  733. section := BeginSection(current.document);
  734. current.section := section;
  735. current.paragraphs := section.contents;
  736. WriteSymbolLabel(section.title, x);
  737. (*
  738. Global.GetSymbolNameInScope(x,(* current.scope*) NIL ,name);
  739. *)
  740. WriteReferenceInScope(section.title, x, NIL);
  741. (*
  742. section.title.WriteString(name); (* WriteString(section.title,title);*)
  743. *)
  744. (*
  745. section := current.section;
  746. current.paragraphs := section.contents;
  747. paragraph := section.contents.AppendNew(ParagraphType.Line);
  748. paragraph := section.contents.AppendNew(ParagraphType.Heading);
  749. paragraph.SetLevel(1);
  750. WriteSymbolLabel(paragraph.text, x);
  751. Global.GetSymbolNameInScope(x,(* current.scope*) NIL ,name);
  752. WriteString(paragraph.text, name); (* WriteString(section.title,title);*)
  753. *)
  754. RETURN section;
  755. END BeginSymbolSection;
  756. PROCEDURE VisitSymbol*(x: SyntaxTree.Symbol);
  757. BEGIN
  758. END VisitSymbol;
  759. PROCEDURE VisitTypeDeclaration*(x: SyntaxTree.TypeDeclaration);
  760. VAR section: DocumentationTree.Section; paragraph: DocumentationTree.Paragraph;commentDoc: DocumentationTree.Document;
  761. BEGIN
  762. IF ~short THEN
  763. Keyword("TYPE"); Whitespace;
  764. PrintSymbol(x);
  765. ELSE
  766. WriteSymbolReference(current.text, x, current.scope);
  767. END;
  768. Whitespace;
  769. String("="); Type(x.declaredType);
  770. END VisitTypeDeclaration;
  771. PROCEDURE VisitConstant*(x: SyntaxTree.Constant);
  772. VAR section: DocumentationTree.Section;paragraph: DocumentationTree.Paragraph; commentDoc: DocumentationTree.Document;
  773. BEGIN
  774. IF ~short THEN
  775. Keyword("CONST"); Whitespace; PrintSymbol(x)
  776. ELSE
  777. WriteSymbolReference(current.text, x, current.scope);
  778. END;
  779. IF x.value # NIL THEN
  780. String( "=" ); Whitespace; Expression(x.value);
  781. END;
  782. END VisitConstant;
  783. PROCEDURE VisitVariable*(x: SyntaxTree.Variable);
  784. VAR section: DocumentationTree.Section; paragraph: DocumentationTree.Paragraph;commentDoc: DocumentationTree.Document;
  785. BEGIN
  786. IF ~short THEN
  787. Keyword("VAR"); Whitespace; PrintSymbol(x)
  788. ELSE
  789. WriteSymbolReference(current.text, x, current.scope);
  790. END;
  791. String( ":" );Whitespace;
  792. Type(x.type);
  793. END VisitVariable;
  794. PROCEDURE Flag(identifier: SyntaxTree.Identifier; VAR first: BOOLEAN);
  795. VAR name: SyntaxTree.IdentifierString;
  796. BEGIN
  797. IF first THEN String("{") ELSE String(",") END;
  798. first := FALSE;
  799. Basic.GetString(identifier,name);
  800. String(name);
  801. END Flag;
  802. PROCEDURE FlagEnd(first: BOOLEAN);
  803. BEGIN
  804. IF ~first THEN String("}") END;
  805. END FlagEnd;
  806. PROCEDURE Int(value: LONGINT);
  807. VAR s: DocumentationTree.String; textElement: DocumentationTree.TextElement;
  808. BEGIN
  809. NEW(s,32); Strings.IntToStr(value,s^);
  810. textElement := current.text.AppendNew(ElementType.Default);
  811. textElement.SetString(s);
  812. END Int;
  813. PROCEDURE Value(identifier: SyntaxTree.Identifier; value: LONGINT; VAR first: BOOLEAN);
  814. BEGIN
  815. Flag(identifier,first);
  816. w.String("("); w.Int(value,1); w.String(")");ToText(w,current.text,ElementType.Default);
  817. END Value;
  818. (** process procedure including comments describing the procedure *)
  819. PROCEDURE VisitProcedure*(x: SyntaxTree.Procedure);
  820. VAR section: DocumentationTree.Section; paragraph: DocumentationTree.Paragraph; name: Basic.SectionName; first: BOOLEAN; type: SyntaxTree.ProcedureType;
  821. doc: DocumentationTree.Document; par: SyntaxTree.Parameter;
  822. BEGIN
  823. IF ~short THEN
  824. IF x IS SyntaxTree.Operator THEN
  825. Keyword("OPERATOR")
  826. ELSE
  827. Keyword("PROCEDURE")
  828. END;
  829. END;
  830. IF x.isInline THEN String("-") END;
  831. IF x.isConstructor THEN String("&") END;
  832. Whitespace;
  833. type := x.type(SyntaxTree.ProcedureType);
  834. first := TRUE;
  835. IF type.stackAlignment > 1 THEN Value(Global.NameStackAligned,type.stackAlignment,first) END;
  836. IF (type.isRealtime) THEN Flag(Global.NameRealtime,first) END;
  837. IF (x.fixed) THEN Value(Global.NameFixed, x.alignment,first)
  838. ELSIF (x.alignment >1) THEN Value(Global.NameAligned, x.alignment, first)
  839. END;
  840. FlagEnd(first);
  841. IF ~short THEN
  842. PrintSymbol(x)
  843. ELSE
  844. WriteSymbolReference(current.text, x, current.scope);
  845. END;
  846. IF (type.firstParameter # NIL) OR (type.returnType # NIL ) THEN (* print parentheses only if not parameterless procedure *)
  847. Whitespace;
  848. ParameterList(type.firstParameter);
  849. END;
  850. IF type.returnType # NIL THEN
  851. String( ":" );
  852. Whitespace;
  853. Type(type.returnType);
  854. END;
  855. END VisitProcedure;
  856. PROCEDURE String(CONST name: ARRAY OF CHAR);
  857. BEGIN current.text.WriteString(name);
  858. END String;
  859. PROCEDURE Whitespace;
  860. BEGIN
  861. current.text.WriteWhitespace
  862. END Whitespace;
  863. PROCEDURE VisitOperator*(x: SyntaxTree.Operator);
  864. BEGIN VisitProcedure(x);
  865. END VisitOperator;
  866. PROCEDURE VisitImport*(x: SyntaxTree.Import);
  867. VAR context: SyntaxTree.Identifier; name: Basic.SectionName;
  868. BEGIN
  869. x.GetName(name);
  870. current.text.WriteLabel(name);
  871. IF x.moduleName # x.name THEN PrintSymbol(x); String( " := " ); END;
  872. IF (x.scope = NIL) OR (x.scope.ownerModule = NIL) THEN context := SyntaxTree.invalidIdentifier ELSE context := x.scope.ownerModule.context END;
  873. WriteReferenceInScope(current.text, x.module, NIL);
  874. IF (x.context # SyntaxTree.invalidIdentifier) & (x.context#context) THEN
  875. String(" IN ");
  876. Identifier(x.context)
  877. END;
  878. END VisitImport;
  879. PROCEDURE VisitBuiltin*(x: SyntaxTree.Builtin);
  880. BEGIN
  881. END VisitBuiltin;
  882. (*** scopes ****)
  883. PROCEDURE Scope*(x: SyntaxTree.Scope);
  884. VAR
  885. constant: SyntaxTree.Constant;
  886. type: SyntaxTree.TypeDeclaration;
  887. variable : SyntaxTree.Variable;
  888. procedure: SyntaxTree.Procedure;
  889. prevScope: SyntaxTree.Scope;
  890. BEGIN
  891. prevScope := current.scope;
  892. current.scope := x;
  893. constant := x.firstConstant;
  894. WHILE constant # NIL DO WriteSymbolSection(constant); constant := constant.nextConstant; END;
  895. type := x.firstTypeDeclaration;
  896. WHILE type # NIL DO WriteSymbolSection(type); type := type.nextTypeDeclaration END;
  897. variable := x.firstVariable;
  898. WHILE variable # NIL DO WriteSymbolSection(variable); variable := variable.nextVariable END;
  899. procedure := x.firstProcedure;
  900. WHILE procedure # NIL DO WriteSymbolSection(procedure); procedure := procedure.nextProcedure END;
  901. current.scope := prevScope;
  902. END Scope;
  903. PROCEDURE SymbolRow(CONST head: ARRAY OF CHAR; symbol: SyntaxTree.Symbol; VAR first: BOOLEAN);
  904. VAR row, cell: DocumentationTree.TextElement; x: SyntaxTree.Constant;
  905. BEGIN
  906. IF Visible(symbol) THEN
  907. row := current.text.AppendNew(ElementType.Row);
  908. IF first THEN
  909. first := FALSE;
  910. cell := row.text.AppendNew(ElementType.HeaderCell);
  911. cell.text.WriteString(head);
  912. ELSE
  913. cell := row.text.AppendNew(ElementType.DataCell);
  914. END;
  915. cell := row.text.AppendNew(ElementType.DataCell);
  916. current.text := cell.text;
  917. Symbol(symbol);
  918. END;
  919. END SymbolRow;
  920. PROCEDURE Summary(paragraphs: DocumentationTree.Paragraphs; x: SyntaxTree.Scope);
  921. VAR
  922. import: SyntaxTree.Import;
  923. constant: SyntaxTree.Constant;
  924. type: SyntaxTree.TypeDeclaration;
  925. variable : SyntaxTree.Variable;
  926. procedure: SyntaxTree.Procedure;
  927. first: BOOLEAN;
  928. prevScope: SyntaxTree.Scope;
  929. paragraph: DocumentationTree.Paragraph;
  930. BEGIN
  931. prevScope := current.scope;
  932. current.scope := x;
  933. paragraph := paragraphs.AppendNew(ParagraphType.Heading); paragraph.SetLevel(2); paragraph.text.WriteString("Summary");
  934. paragraph := paragraphs.AppendNew(ParagraphType.Table);
  935. current.text := paragraph.text;
  936. short := TRUE;
  937. IF x IS SyntaxTree.ModuleScope THEN
  938. import := x(SyntaxTree.ModuleScope).firstImport; first := TRUE;
  939. WHILE import # NIL DO SymbolRow("imports",import,first); import := import.nextImport; END;
  940. END;
  941. constant := x.firstConstant; first := TRUE;
  942. WHILE constant # NIL DO SymbolRow("constants",constant,first); constant := constant.nextConstant; END;
  943. type := x.firstTypeDeclaration; first := TRUE;
  944. WHILE type # NIL DO SymbolRow("type declarations", type,first); type := type.nextTypeDeclaration END;
  945. variable := x.firstVariable; first := TRUE;
  946. WHILE variable # NIL DO SymbolRow("variables", variable,first); variable := variable.nextVariable END;
  947. procedure := x.firstProcedure; first := TRUE;
  948. WHILE procedure # NIL DO SymbolRow("procedures", procedure,first); procedure := procedure.nextProcedure END;
  949. current.scope := prevScope;
  950. short := FALSE;
  951. (*
  952. paragraph := paragraphs.AppendNew(ParagraphType.TextBlock);
  953. paragraph.text.WriteLink("ModuleList","List of modules");
  954. *)
  955. END Summary;
  956. PROCEDURE WriteTextElement(textElement: DocumentationTree.TextElement);
  957. VAR paragraph: DocumentationTree.Paragraph; element: DocumentationTree.TextElement;
  958. BEGIN
  959. ASSERT(current.text # NIL);
  960. CASE textElement.type OF
  961. ElementType.Italic, ElementType.Bold, ElementType.Underline, ElementType.Code: current.text.Add(textElement);
  962. current.text := textElement.text;
  963. | ElementType.HeaderCell, ElementType.DataCell, ElementType.Row:
  964. ASSERT(current.paragraphs # NIL);
  965. ASSERT(current.paragraphs.Length() # 0);
  966. paragraph := current.paragraphs.Last();
  967. current.text := paragraph.text;
  968. IF textElement.type # ElementType.Row THEN
  969. ASSERT(current.text.Length() # 0);
  970. element := current.text.Last();
  971. current.text := element.text
  972. END;
  973. current.text.Add(textElement);
  974. current.text := textElement.text;
  975. ELSE
  976. current.text.Add(textElement)
  977. END;
  978. END WriteTextElement;
  979. PROCEDURE BeginSection(document: DocumentationTree.Document): DocumentationTree.Section;
  980. VAR section: DocumentationTree.Section;
  981. BEGIN
  982. INC(level[Section]);
  983. section := document.sections.AppendNew(level[Section]);
  984. RETURN section;
  985. END BeginSection;
  986. PROCEDURE PrefixSection(document: DocumentationTree.Document): DocumentationTree.Section;
  987. VAR section: DocumentationTree.Section;
  988. BEGIN
  989. INC(level[Section]);
  990. NEW(section, level[Section]);
  991. document.sections.Insert(0, section);
  992. RETURN section;
  993. END PrefixSection;
  994. PROCEDURE EndSection(section: DocumentationTree.Section);
  995. BEGIN
  996. DEC(level[Section]);
  997. END EndSection;
  998. PROCEDURE PatchLinkE(element: DocumentationTree.TextElement);
  999. VAR label: Strings.String; symbol: SyntaxTree.Symbol;name: Basic.SectionName; identifier: SyntaxTree.Identifier;
  1000. BEGIN
  1001. IF (element.type = ElementType.Link) & (element.string # NIL) THEN
  1002. identifier := SyntaxTree.NewIdentifier(element.string^);
  1003. symbol := current.scope.FindSymbol(identifier);
  1004. IF (symbol # NIL) & ~(symbol IS SyntaxTree.Import) THEN
  1005. IF element.text.Length()= 0 THEN element.text.WriteString(element.string^) END;
  1006. Global.GetSymbolNameInScope(symbol, NIL, name);
  1007. element.SetString(Strings.NewString(name));
  1008. END;
  1009. END;
  1010. element.text.ForAllElementsDo(PatchLinkE)
  1011. END PatchLinkE;
  1012. PROCEDURE PatchLinksP(par: DocumentationTree.Paragraph);
  1013. BEGIN
  1014. par.text.ForAllElementsDo(PatchLinkE)
  1015. END PatchLinksP;
  1016. PROCEDURE PatchLinksS(sec: DocumentationTree.Section);
  1017. VAR i: LONGINT;
  1018. BEGIN
  1019. sec.title.ForAllElementsDo(PatchLinkE);
  1020. sec.contents.ForAllParagraphsDo(PatchLinksP)
  1021. END PatchLinksS;
  1022. PROCEDURE PatchLinks(doc: DocumentationTree.Document; scope: SyntaxTree.Scope);
  1023. VAR i: LONGINT; prev: SyntaxTree.Scope;
  1024. BEGIN
  1025. prev := current.scope;
  1026. current.scope := scope;
  1027. doc.sections.ForAllSectionsDo(PatchLinksS);
  1028. doc.description.ForAllParagraphsDo(PatchLinksP);
  1029. current.scope := prev
  1030. END PatchLinks;
  1031. PROCEDURE Modifiers(x: SyntaxTree.Modifier);
  1032. VAR name: Scanner.IdentifierString; first: BOOLEAN;
  1033. BEGIN
  1034. first := TRUE;
  1035. WHILE x # NIL DO
  1036. IF first THEN String("{"); first := FALSE ELSE String(", ") END;
  1037. Basic.GetString(x.identifier,name);
  1038. String(name);
  1039. IF x.expression # NIL THEN
  1040. String("(");
  1041. Expression(x.expression);
  1042. String(")");
  1043. END;
  1044. x := x.nextModifier;
  1045. END;
  1046. IF ~first THEN String("} ") END;
  1047. END Modifiers;
  1048. PROCEDURE Module*(x: SyntaxTree.Module; backend: DocumentationBackend): DocumentationTree.Document;
  1049. VAR
  1050. name: SyntaxTree.IdentifierString; section, cs: DocumentationTree.Section; commentDoc: DocumentationTree.Document;
  1051. doc: DocumentationTree.Document; par: DocumentationTree.Paragraph; text: DocumentationTree.Text;
  1052. BEGIN
  1053. SELF.backend := backend;
  1054. ASSERT(x # NIL);
  1055. doc := DocumentationTree.NewDocument();
  1056. level[Section] := 0;
  1057. Global.GetModuleName(x,name);
  1058. section := BeginSection(doc);
  1059. section.WriteLabel("ModuleList");
  1060. par := section.contents.AppendNew(ParagraphType.TextBlock);
  1061. par.text.WriteString("Module");
  1062. par.text.WriteWhitespace;
  1063. par.text.WriteLink(name, name);
  1064. EndSection(section);
  1065. section := BeginSection(doc);
  1066. section.title.WriteLabel(name);
  1067. section.title.WriteWeakLink("ModuleList","Module"); (* if there is a module list, then e refer to it here *)
  1068. section.title.WriteWhitespace;
  1069. section.title.WriteString(name);
  1070. IF x.comment # NIL THEN
  1071. commentDoc := DocumentationTree.NewDocument();
  1072. ParseComments(commentDoc,x.comment, x.closingComment,x);
  1073. PatchLinks(commentDoc, x.moduleScope);
  1074. MergeDocument(doc, section.contents, commentDoc);
  1075. END;
  1076. Summary(section.contents, x.moduleScope);
  1077. EndSection(section);
  1078. IF x.closingComment # NIL THEN
  1079. cs := BeginSection(doc);
  1080. commentDoc := DocumentationTree.NewDocument();
  1081. ParseComments(commentDoc,x.closingComment, NIL,x);
  1082. PatchLinks(commentDoc, x.moduleScope);
  1083. MergeDocument(doc, cs.contents, commentDoc);
  1084. EndSection(cs);
  1085. END;
  1086. current.document := doc;
  1087. INC(level[Section]);
  1088. Scope(x.moduleScope);
  1089. DEC(level[Section]);
  1090. current.scope := x.moduleScope;
  1091. MergeDocument(doc, doc.description, document);
  1092. document := doc;
  1093. RETURN document
  1094. END Module;
  1095. END Generator;
  1096. Checker= OBJECT
  1097. VAR
  1098. labels: DocumentationTree.Text;
  1099. links: DocumentationTree.Text;
  1100. currentScope: SyntaxTree.Scope;
  1101. PROCEDURE CheckElement(element: DocumentationTree.TextElement);
  1102. VAR label: Strings.String; symbol: SyntaxTree.Symbol;name: Basic.SectionName; identifier: SyntaxTree.Identifier;
  1103. BEGIN
  1104. IF (element.type = ElementType.Link) & (element.string # NIL) THEN
  1105. identifier := SyntaxTree.NewIdentifier(element.string^);
  1106. symbol := currentScope.FindSymbol(identifier);
  1107. IF symbol # NIL THEN
  1108. Global.GetSymbolNameInScope(symbol, NIL, name);
  1109. element.SetString(Strings.NewString(name));
  1110. END;
  1111. ELSIF (element.type = ElementType.WeakLink) THEN
  1112. IF labels.FindByString(element.string^) = NIL THEN
  1113. element.SetType(ElementType.Default)
  1114. ELSE
  1115. element.SetType(ElementType.Link)
  1116. END;
  1117. END;
  1118. END CheckElement;
  1119. PROCEDURE CollectElement(element: DocumentationTree.TextElement);
  1120. BEGIN
  1121. IF (element.type = ElementType.WeakLink) THEN
  1122. links.AddElement(element);
  1123. ELSIF (element.type = ElementType.Label) THEN
  1124. labels.Add(element)
  1125. END;
  1126. element.text.ForAllElementsDo(CollectElement);
  1127. END CollectElement;
  1128. PROCEDURE CollectParagraph(par: DocumentationTree.Paragraph);
  1129. BEGIN
  1130. IF par.label # NIL THEN
  1131. labels.WriteLabel(par.label^)
  1132. END;
  1133. par.text.ForAllElementsDo(CollectElement);
  1134. par.description.ForAllElementsDo(CollectElement);
  1135. END CollectParagraph;
  1136. PROCEDURE CollectSection(sec: DocumentationTree.Section);
  1137. BEGIN
  1138. IF sec.label # NIL THEN
  1139. labels.WriteLabel(sec.label^)
  1140. END;
  1141. sec.title.ForAllElementsDo(CollectElement);
  1142. sec.contents.ForAllParagraphsDo(CollectParagraph);
  1143. END CollectSection;
  1144. PROCEDURE Document(doc: DocumentationTree.Document; scope: SyntaxTree.Scope);
  1145. BEGIN
  1146. currentScope := scope;
  1147. NEW(links, 4); NEW(labels, 4);
  1148. doc.description.ForAllParagraphsDo(CollectParagraph);
  1149. doc.sections.ForAllSectionsDo(CollectSection);
  1150. links.ForAllElementsDo(CheckElement)
  1151. END Document;
  1152. END Checker;
  1153. DocumentationBackend= OBJECT (Backend.Backend)
  1154. VAR
  1155. trace: BOOLEAN;
  1156. fileName : Files.FileName;
  1157. generator: Generator;
  1158. templateFile: Files.FileName;
  1159. internals: BOOLEAN;
  1160. PROCEDURE &InitIntermediateBackend*;
  1161. BEGIN
  1162. InitBackend; generator := NIL;
  1163. END InitIntermediateBackend;
  1164. PROCEDURE ParseFile(fileName: ARRAY OF CHAR): DocumentationTree.Document;
  1165. VAR reader: Files.Reader; parser: DocumentationParser.Parser; scanner: DocumentationScanner.Scanner;
  1166. printer: DocumentationPrinter.Printer; document: DocumentationTree.Document;
  1167. file: Files.File;
  1168. BEGIN
  1169. file := Files.Old(fileName);
  1170. IF file = NIL THEN RETURN NIL END;
  1171. NEW(reader, file, 0);
  1172. NEW(scanner, reader,0,NIL);
  1173. NEW(parser, scanner);
  1174. document := DocumentationTree.NewDocument();
  1175. parser.ParseDocument(document);
  1176. RETURN document
  1177. END ParseFile;
  1178. PROCEDURE ProcessSyntaxTreeModule*(syntaxTreeModule: SyntaxTree.Module): Formats.GeneratedModule;
  1179. VAR dump: Streams.Writer; printer: DocumentationPrinter.Printer; document, template: DocumentationTree.Document;
  1180. htmlPrinter: DocumentationHtml.Printer; file: Files.File; writer: Files.Writer;
  1181. name, extension: Files.FileName; checker: Checker;
  1182. BEGIN
  1183. Files.SplitExtension(fileName, name, extension);
  1184. IF (name = "*") OR (generator = NIL) THEN
  1185. NEW(generator,diagnostics);
  1186. generator.case := syntaxTreeModule.case;
  1187. END;
  1188. document := generator.Module(syntaxTreeModule,SELF);
  1189. IF templateFile # "" THEN
  1190. template := ParseFile(templateFile);
  1191. IF template # NIL THEN
  1192. MergeDocument(template, NIL, document);
  1193. document := template;
  1194. ELSIF diagnostics # NIL THEN
  1195. Basic.Error(diagnostics, "",Basic.invalidPosition, "could not open / parse documentation template");
  1196. END;
  1197. END;
  1198. NEW(checker);
  1199. checker.Document(document, NIL);
  1200. IF trace THEN
  1201. Global.GetModuleName(syntaxTreeModule, name);
  1202. Strings.Append(name,".docu");
  1203. dump := Basic.GetDebugWriter(name);
  1204. NEW(printer, dump);
  1205. printer.Document(document);
  1206. NEW(htmlPrinter, dump);
  1207. htmlPrinter.Document(document);
  1208. dump.Update;
  1209. END;
  1210. IF name = "*" THEN
  1211. Global.GetModuleName(syntaxTreeModule, name);
  1212. END;
  1213. Files.JoinExtension(name, extension, name);
  1214. file := Files.New(name);
  1215. IF file # NIL THEN
  1216. NEW(writer, file,0);
  1217. IF extension = "html" THEN
  1218. NEW(htmlPrinter, writer);
  1219. htmlPrinter.Document(document);
  1220. ELSE
  1221. NEW(printer, writer);
  1222. printer.Document(document);
  1223. END;
  1224. writer.Update;
  1225. Files.Register(file);
  1226. END;
  1227. RETURN NIL
  1228. END ProcessSyntaxTreeModule;
  1229. PROCEDURE DefineOptions*(options: Options.Options);
  1230. BEGIN
  1231. DefineOptions^(options);
  1232. options.Add(0X,"dtrace",Options.Flag);
  1233. options.Add(0X,"docuTemplate", Options.String);
  1234. options.Add(0X,"internals",Options.Flag);
  1235. END DefineOptions;
  1236. PROCEDURE GetOptions*(options: Options.Options);
  1237. BEGIN
  1238. GetOptions^(options);
  1239. trace := options.GetFlag("dtrace");
  1240. IF ~options.GetString("d", fileName) THEN fileName := "" END;
  1241. IF ~options.GetString("docuTemplate", templateFile) THEN COPY(DefaultTemplateFile, templateFile) END;
  1242. internals := options.GetFlag("internals");
  1243. END GetOptions;
  1244. PROCEDURE DefaultSymbolFileFormat*(): Formats.SymbolFileFormat;
  1245. BEGIN RETURN SymbolFileFormat.Get()
  1246. END DefaultSymbolFileFormat;
  1247. PROCEDURE DefaultObjectFileFormat*(): Formats.ObjectFileFormat;
  1248. BEGIN RETURN NIL
  1249. END DefaultObjectFileFormat;
  1250. END DocumentationBackend;
  1251. (* helper procedures *)
  1252. PROCEDURE Small(CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
  1253. VAR ch: CHAR; i: LONGINT;
  1254. BEGIN
  1255. i := 0;
  1256. REPEAT
  1257. ch := name[i];
  1258. IF (ch >= 'A') & (ch <= 'Z') THEN
  1259. ch := CHR(ORD(ch)-ORD('A')+ORD('a'));
  1260. END;
  1261. result[i] := ch; INC(i);
  1262. UNTIL ch = 0X;
  1263. END Small;
  1264. PROCEDURE Hex(w: Streams.Writer; x: HUGEINT);
  1265. VAR i: LONGINT; a: ARRAY 20 OF CHAR; y: HUGEINT;
  1266. BEGIN
  1267. i := 0;
  1268. REPEAT
  1269. y := x MOD 10H;
  1270. IF y < 10 THEN a[i] := CHR(y+ORD('0'))
  1271. ELSE a[i] := CHR(y-10+ORD('A'))
  1272. END;
  1273. x := x DIV 10H;
  1274. INC(i);
  1275. UNTIL (x=0) OR (i=16);
  1276. IF y >=10 THEN w.Char("0") END;
  1277. REPEAT DEC( i ); w.Char( a[i] ) UNTIL i = 0
  1278. END Hex;
  1279. PROCEDURE ToText(w: Streams.StringWriter; text: DocumentationTree.Text; elementType: ElementType);
  1280. VAR textElement: DocumentationTree.TextElement; s: DocumentationTree.String;
  1281. BEGIN
  1282. NEW(s,w.Pos()+1);
  1283. w.Get(s^);
  1284. textElement := text.AppendNew(elementType);
  1285. textElement.SetString(s);
  1286. w.SetPos(0); (* reset writer *)
  1287. END ToText;
  1288. PROCEDURE WriteSymbolLabel(text: DocumentationTree.Text; symbol: SyntaxTree.Symbol);
  1289. VAR label: Basic.SectionName;
  1290. BEGIN
  1291. Global.GetSymbolNameInScope(symbol,NIL,label);
  1292. text.WriteLabel(label);
  1293. END WriteSymbolLabel;
  1294. PROCEDURE WriteReferenceInScope*(text: DocumentationTree.Text; symbol: SyntaxTree.Symbol; inScope: SyntaxTree.Scope);
  1295. VAR n: SyntaxTree.IdentifierString; td: SyntaxTree.TypeDeclaration; name: Basic.SectionName; write: BOOLEAN;
  1296. PROCEDURE Scope(scope: SyntaxTree.Scope);
  1297. BEGIN
  1298. IF scope = NIL THEN (* do nothing, locally declared temporary symbol *)
  1299. ELSIF scope IS SyntaxTree.ModuleScope THEN
  1300. Scope(NIL);
  1301. Global.GetModuleName(scope.ownerModule, name);
  1302. IF write THEN text.WriteWeakLink(name, name); text.WriteString(".") END;
  1303. Strings.Append(name,".");
  1304. ELSIF scope IS SyntaxTree.RecordScope THEN
  1305. Scope(scope.outerScope);
  1306. td := scope(SyntaxTree.RecordScope).ownerRecord.typeDeclaration;
  1307. IF td = NIL THEN
  1308. td := scope(SyntaxTree.RecordScope).ownerRecord.pointerType.typeDeclaration;
  1309. END;
  1310. td.GetName(n);
  1311. Strings.Append(name,n);
  1312. IF write THEN text.WriteWeakLink(name, n); text.WriteString(".") END;
  1313. Strings.Append(name,".")
  1314. ELSIF scope IS SyntaxTree.ProcedureScope THEN
  1315. Scope(scope.outerScope);
  1316. scope(SyntaxTree.ProcedureScope).ownerProcedure.GetName(n);
  1317. Strings.Append(name,n);
  1318. IF write THEN text.WriteWeakLink(name, n); text.WriteString(".") END;
  1319. Strings.Append(name,".")
  1320. ELSIF scope IS SyntaxTree.CellScope THEN
  1321. Scope(scope.outerScope);
  1322. td := scope(SyntaxTree.CellScope).ownerCell.typeDeclaration;
  1323. td.GetName(n);
  1324. Strings.Append(name,n);
  1325. IF write THEN text.WriteWeakLink(name, n); text.WriteString(".") END;
  1326. Strings.Append(name,".")
  1327. ELSE Scope(scope.outerScope)
  1328. END;
  1329. IF (scope = inScope) THEN write := TRUE END;
  1330. END Scope;
  1331. BEGIN
  1332. write := FALSE;
  1333. name := "";
  1334. Scope(symbol.scope);
  1335. symbol.GetName(n);
  1336. IF symbol IS SyntaxTree.Operator THEN (*! append some more bits to make discrimintation possible *)
  1337. END;
  1338. Strings.Append(name,n);
  1339. text.WriteWeakLink(name, n);
  1340. END WriteReferenceInScope;
  1341. PROCEDURE WriteSymbolReference(text: DocumentationTree.Text; symbol: SyntaxTree.Symbol; scope: SyntaxTree.Scope);
  1342. VAR name, label: Basic.SectionName; textElement: DocumentationTree.TextElement;
  1343. BEGIN
  1344. WriteReferenceInScope(text,symbol,scope);
  1345. (*
  1346. Global.GetSymbolNameInScope(symbol,scope,name);
  1347. Global.GetSymbolNameInScope(symbol,NIL,label);
  1348. IF symbol.comment # NIL THEN
  1349. text.WriteLink(label, name);
  1350. ELSE
  1351. text.WriteString(name)
  1352. END;
  1353. *)
  1354. END WriteSymbolReference;
  1355. (*
  1356. PROCEDURE ConvertSpecialSections(document: DocumentationTree.Document);
  1357. VAR description: DocumentationTree.Paragraphs; i: LONGINT; section: DocumentationTree.Section; par : DocumentationTree.Paragraph;
  1358. BEGIN
  1359. description := document.description;
  1360. FOR i := document.sections.Length()-1 TO 0 BY -1 DO
  1361. section := document.sections.GetSection(i);
  1362. IF (section.label # NIL) THEN
  1363. IF section.label^= "author" THEN
  1364. par := description.AppendNew(ParagraphType.Heading);
  1365. par.SetLevel(4);
  1366. par.text.WriteString("Author");
  1367. par.text.WriteText(section.title);
  1368. document.sections.RemoveByIndex(i);
  1369. END;
  1370. END;
  1371. END;
  1372. END ConvertSpecialSections;
  1373. *)
  1374. PROCEDURE ParseComments(document : DocumentationTree.Document; c,sentinel: SyntaxTree.Comment; x: ANY);
  1375. VAR string: DocumentationTree.String; stringReader: Streams.StringReader; parser: DocumentationParser.Parser; scanner: DocumentationScanner.Scanner;
  1376. printer: DocumentationPrinter.Printer;
  1377. BEGIN
  1378. IF c # NIL THEN
  1379. string := MergeComments(c,sentinel,x);
  1380. NEW(stringReader, LEN(string));
  1381. stringReader.Set(string^);
  1382. NEW(scanner, stringReader,0,NIL);
  1383. NEW(parser, scanner);
  1384. parser.ParseDocument(document);
  1385. (*ConvertSpecialSections(document);*)
  1386. END;
  1387. END ParseComments;
  1388. (* sentinel used for stopping merging at closing comment of a module if the opening comment comes directly before it.*)
  1389. PROCEDURE MergeComments(c,sentinel: SyntaxTree.Comment; x: ANY): DocumentationTree.String;
  1390. VAR i,len: LONGINT; tmp: SyntaxTree.Comment; string: DocumentationTree.String;
  1391. BEGIN
  1392. len := 0; tmp := c;
  1393. WHILE (tmp # sentinel) & (tmp.item = x) DO
  1394. IF tmp.source[0] = "*" THEN
  1395. i := 1;
  1396. WHILE (i<LEN(tmp.source^)) & (tmp.source[i] # 0X) DO
  1397. INC(i); INC(len);
  1398. END;
  1399. END;
  1400. INC(len,2);
  1401. tmp := tmp.nextComment;
  1402. END;
  1403. NEW(string, len+1);
  1404. len := 0; tmp := c;
  1405. WHILE (tmp # sentinel) & (tmp.item = x) DO
  1406. IF tmp.source[0] = "*" THEN
  1407. i := 1;
  1408. WHILE (i<LEN(tmp.source^)) & (tmp.source[i] # 0X) DO
  1409. string[len] := tmp.source[i];
  1410. INC(i); INC(len);
  1411. END;
  1412. IF (len > 0) & (string[len-1] = "*") THEN DEC(len) END; (* remove last "*" from comment *)
  1413. END;
  1414. string[len] := Scanner.CR;
  1415. INC(len);
  1416. string[len] := Scanner.CR;
  1417. INC(len);
  1418. tmp := tmp.nextComment;
  1419. END;
  1420. string[len] := 0X;
  1421. RETURN string
  1422. END MergeComments;
  1423. PROCEDURE KeepSections(in: DocumentationTree.Document);
  1424. VAR i , j: LONGINT; insert, check: DocumentationTree.Section; done: BOOLEAN; paragraph: DocumentationTree.Paragraph; section: DocumentationTree.Section;
  1425. BEGIN
  1426. FOR i := 0 TO in.sections.Length()-1 DO
  1427. section := in.sections.GetSection(i);
  1428. IF section.title.Length() # 0 THEN
  1429. paragraph := in.description.AppendNew(ParagraphType.Heading);
  1430. paragraph.SetLevel(section.level);
  1431. paragraph.text.WriteText(section.title);
  1432. MergeParagraphs(in.description, section.contents);
  1433. END;
  1434. END;
  1435. END KeepSections;
  1436. PROCEDURE MergeDocument(in: DocumentationTree.Document; descriptionSection: DocumentationTree.Paragraphs; this: DocumentationTree.Document);
  1437. VAR i , j: LONGINT; insert, check: DocumentationTree.Section; done: BOOLEAN; paragraph: DocumentationTree.Paragraph; section: DocumentationTree.Section;
  1438. BEGIN
  1439. ASSERT(in # NIL);
  1440. IF descriptionSection = NIL THEN descriptionSection := in.description END;
  1441. IF this # NIL THEN
  1442. FOR i := 0 TO this.description.Length()-1 DO
  1443. descriptionSection.Add(this.description.GetParagraph(i));
  1444. END;
  1445. MergeSections(in.sections, this.sections);
  1446. (*
  1447. FOR i := 0 TO this.sections.Length()-1 DO
  1448. section := this.sections.GetSection(i);
  1449. paragraph := this.description.AppendNew(ParagraphType.Heading);
  1450. paragraph.SetLevel(2);
  1451. paragraph.text.WriteText(section.title);
  1452. MergeParagraphs(this.description, section.contents);
  1453. END;
  1454. *)
  1455. END
  1456. END MergeDocument;
  1457. PROCEDURE MergeParagraphs(in, this: DocumentationTree.Paragraphs);
  1458. VAR i: LONGINT;
  1459. BEGIN
  1460. FOR i := 0 TO this.Length()-1 DO
  1461. in.AddParagraph(this.GetParagraph(i));
  1462. END;
  1463. END MergeParagraphs;
  1464. PROCEDURE MergeSections(in, this: DocumentationTree.Sections);
  1465. VAR j,i,k,l: LONGINT; insert, check: DocumentationTree.Section; done: BOOLEAN; par, paragraph,checkPar: DocumentationTree.Paragraph; section: DocumentationTree.Section;
  1466. BEGIN
  1467. i := 0;
  1468. WHILE i < this.Length() DO
  1469. insert := this.GetSection(i);
  1470. done := FALSE;
  1471. IF insert.label # NIL THEN
  1472. j := 0;
  1473. WHILE (j < in.Length()) (*& ~done*) DO
  1474. check := in.GetSection(j);
  1475. IF (check.label # NIL) & (check.label^ = insert.label^) THEN
  1476. (* first merge all paragraphs *)
  1477. MergeParagraphs(check.contents, insert.contents);
  1478. done := TRUE;
  1479. ELSE
  1480. k := 0;
  1481. WHILE k < check.contents.Length() DO
  1482. checkPar := check.contents.GetParagraph(k);
  1483. IF (checkPar.type = ParagraphType.Heading) & (checkPar.label # NIL) & (checkPar.label^ = insert.label^) THEN
  1484. done := TRUE;
  1485. REPEAT
  1486. INC(k);
  1487. IF k < check.contents.Length() THEN
  1488. par := check.contents.GetParagraph(k);
  1489. END;
  1490. UNTIL (k = check.contents.Length()) OR (par.type = ParagraphType.Heading) & (par.level >= checkPar.level);
  1491. FOR l := 0 TO insert.contents.Length()-1 DO
  1492. paragraph := insert.contents.GetParagraph(l);
  1493. check.contents.Insert(k,paragraph);
  1494. INC(k);
  1495. END;
  1496. END;
  1497. INC(k);
  1498. END;
  1499. END;
  1500. INC(j);
  1501. END;
  1502. END;
  1503. IF ~done THEN
  1504. in.Add(this.GetSection(i));
  1505. END;
  1506. INC(i);
  1507. END;
  1508. END MergeSections;
  1509. PROCEDURE MergeSectionDocument(section: DocumentationTree.Section; document: DocumentationTree.Document);
  1510. VAR paragraphs: DocumentationTree.Paragraphs; i,j: LONGINT; paragraph: DocumentationTree.Paragraph; first: BOOLEAN; firstSection: DocumentationTree.Section;
  1511. BEGIN
  1512. NEW(paragraphs, document.description.Length() + section.contents.Length());
  1513. FOR i := 0 TO document.description.Length()-1 DO
  1514. paragraphs.Add(document.description.GetParagraph(i));
  1515. END;
  1516. FOR i := 0 TO section.contents.Length()-1 DO
  1517. paragraphs.Add(section.contents.GetParagraph(i));
  1518. END;
  1519. section.SetContents(paragraphs);
  1520. FOR i := 0 TO document.sections.Length()-1 DO
  1521. section := document.sections.GetSection(i);
  1522. IF (section.label # NIL) THEN
  1523. first := TRUE;
  1524. FOR j := 0 TO i-1 DO
  1525. firstSection := document.sections.GetSection(j);
  1526. IF (firstSection.label # NIL) & (firstSection.label^ = section.label^) THEN
  1527. first := FALSE;
  1528. END;
  1529. END;
  1530. IF first THEN
  1531. paragraph := paragraphs.AppendNew(ParagraphType.Heading);
  1532. paragraph.SetLevel(2);
  1533. paragraph.text.WriteString(section.label^);
  1534. paragraph.text.WriteText(section.title);
  1535. END;
  1536. MergeParagraphs(paragraphs, section.contents);
  1537. END;
  1538. END;
  1539. END MergeSectionDocument;
  1540. PROCEDURE Get*(): Backend.Backend;
  1541. VAR documentationBackend: DocumentationBackend;
  1542. BEGIN
  1543. NEW(documentationBackend); RETURN documentationBackend;
  1544. END Get;
  1545. END FoxDocumentationBackend.
  1546. ~~
  1547. (**
  1548. = Documentation Backend Description.
  1549. This closing comment can be used to describe a whole application.
  1550. It may contain sections like this:
  1551. @ Section1
  1552. * bullet1
  1553. ** bullet2
  1554. *boldface* (and in same line)
  1555. *erroneous boldface
  1556. # bullet3
  1557. ## bullet4
  1558. ## bullet5
  1559. # bullet 6
  1560. @ Section2
  1561. The following is a bulleted list
  1562. \* Bullet1
  1563. \* Bullet2
  1564. This is a normal text with *
  1565. There may be references like this: [[Get|FoxDocumentationBackend.Get]]
  1566. *)
  1567. System.Free FoxDocumentationHtml FoxDocumentationBackend FoxDocumentationParser FoxDocumentationPrinter FoxDocumentationTree FoxDocumentationScanner ~
  1568. Compiler.Compile -d=*.html -i oc/FoxDocumentationBackend.Mod ~