1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828 |
- (**
- The special backend in the Fox compiler suite serves as a documentation generator to produce documents from Oberon source files.
- #author# Felix Friedrich
- #purpose# Documentation Generator
- *)
- MODULE FoxDocumentationBackend;
- (**
- @concept
- = Documentation Backend
- The [[FoxDocumentationBackend|documentation backend]] is mainly a tool to merge different informations, namely:
- # The information from the symbol and module scope structure
- # The information provided by documenting comments
- Documentation comments that immediately precede a symbol or that are directly in the same line as a symbol are associated with this symbol.
- Therefore the documentation contained within the respective comment is on the same level as the description of the symbol itself and will be
- displayed together with the information about the symbol.
- The following describes how a documentation is generated from a module:
- * Association to symbols and preprocessing
- ## A comment that follows a symbol X and stands in the same line as X is associated with this symbol X.
- ## Comments that follow the MODULE (or CELLNET) specification are treated separately to describe the module.
- ## Any other comment that stand in front of some symbol Y is associated with this symbol Y.
- ## Consecutive comments are always merged as character arrays mefore being parsed by the comment parser.
- * Module documentation
- ## Each comment (or sequence of consecutive comments) is parsed by the comment parser into a separate document
- ## During processing of a module, each symbol is described in a separate symbol section. The module itself is described in the module summary section.
- ## Each comment document is merged with the respective symbol section in the overal module document.
- * Module documentation merging
- ## When more than one modules are processed into one documentation file, the module documentats are merged into one global document.
- ## The header of the document contains a linked list of all involved modules.
- == Formatting elements
- === Paragraphs and line breaks
- 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)
- Explicit line breaks can be inserted using two backslashes:
- {{{ This is a line \\ that is broken }}}
- This is a line \\ that is broken
- === Text Styles
- 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.
- |=Name |= Code Example |= Translation |
- | Boldface | {{{ *example text*}}} | *Boldface Text* |
- | Underline | {{{ _example text_}}} | _Underline Text_ |
- | Italics | {{{ /example text/ }}} | /Italics Text/ |
- === bullets and lists
- Bulleted or numbered lists start with an asterisk or number sign, respectively. Description start with a text that is embraced by number signs.
- {{{ * bullet 1
- ** sub bullet1
- ** sub bullet2
- * bullet 2
- # number 1
- ## sub number 1
- ## sub number 2
- # number 2
- #description label# description text
- #description label2# description text2 }}}
- Result
- * bullet 1
- ** sub bullet1
- ** sub bullet2
- * bullet 2
- # number 1
- ## sub number 1
- ## sub number 2
- # number 2
- #description label# description text
- #description label2# description text2
- === Labels and links
- A label in the text is denoted as follows
- {{{ <<labelName>> }}} <<labelName>>
- A link in the text is denoted as
- {{{ [[labelName]] }}}
- or, if an alternative text should be displayed, it can be written as
- {{{ [[labelName|alternative text]] }}}
- === Document Structure
- Documents consist of sections. A section is started with a sequence of {{{@}}} letter as the first characters on a separate line. Examples:
- {{{ @ title of a section of level 1 }}}
- {{{ @@ title of a section of level 2 }}}
- If the first text element of the title is a label, then this lable is attributed to the section.
- {{{ @ <<label>> title }}}
- 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:
- {{{ @label title }}}
- For structuring a section, headings are provided. A heading is started with an equal sign as the first character in a separate line. Examples
- {{{ = title of a paragraph of level 1
- == title of a paragraph of level 2
- =label title
- = <<label>> title }}}
- === Tables
- 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
- while data cells are embraced by vertical lines only:
- {{{
- |= header 1 |= header 2 |= header 3
- | data 1 | data 2 | data 3
- | data 4 | data 5 | data 6 }}}
- Result:
- |= header 1 |= header 2 |= header 3
- | data 1 | data 2 | data 3
- | data 4 | data 5 | data 6 }}}
- **)
- IMPORT Basic := FoxBasic, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal, Scanner := FoxScanner, Backend := FoxBackend, Formats := FoxFormats,
- Options, Streams, Strings, SymbolFileFormat := FoxTextualSymbolFile, Diagnostics,
- DocumentationTree := FoxDocumentationTree, DocumentationPrinter := FoxDocumentationPrinter, DocumentationHtml := FoxDocumentationHtml, DocumentationParser := FoxDocumentationParser, DocumentationScanner := FoxDocumentationScanner,
- D := Debugging, Files;
- CONST
- Section=0;
- Item=1;
- Enum=2;
- MaxLevels=3;
- VisibleConstant*=3; (** visible constant comment **)
- (** second visible constant *)
- SecondVisibleConstant*=4;
- Third*=4;
- DefaultTemplateFile="oc/DocuTemplate.txt";
-
- KeywordElementType = ElementType.Bold;
- QualifiedIdentifierElementType = ElementType.Bold;
- TYPE
- ElementType=DocumentationTree.ElementType;
- ParagraphType=DocumentationTree.ParagraphType;
- State= RECORD
- document: DocumentationTree.Document;
- section: DocumentationTree.Section;
- paragraphs: DocumentationTree.Paragraphs;
- paragraph: DocumentationTree.Paragraph;
- text: DocumentationTree.Text;
- scope: SyntaxTree.Scope;
- END;
- (** Printer object to write the documentation to a stream. Implemented as visitor on the Syntax Tree.*)
- Generator*= OBJECT (SyntaxTree.Visitor)
- VAR
- w,ws: Streams.StringWriter;
- case: LONGINT;
- diagnostics: Diagnostics.Diagnostics;
- (* transient state variables *)
- level: ARRAY MaxLevels OF LONGINT;
- current: State;
- document: DocumentationTree.Document;
- parameterDocument: DocumentationTree.Document;
- short: BOOLEAN;
- backend: DocumentationBackend;
- PROCEDURE &Init*(diagnostics: Diagnostics.Diagnostics);
- VAR i: LONGINT;
- BEGIN
- NEW(w,1024); NEW(ws, 64); case := Scanner.Uppercase;
- FOR i := 0 TO MaxLevels-1 DO level[i] := 0 END;
- SELF.diagnostics := diagnostics;
- current.document := NIL; current.section := NIL; current.paragraphs := NIL; current.text := NIL;
- document := NIL;
- END Init;
- (* helper procedures *)
- PROCEDURE Keyword(CONST a: ARRAY OF CHAR);
- VAR
- str: ARRAY 64 OF CHAR;
- BEGIN
- IF case= Scanner.Lowercase THEN Small(a,str) ELSE COPY(a,str) END;
- w.String(str);
- ToText(w,current.text,KeywordElementType);
- END Keyword;
- PROCEDURE Identifier*(x: SyntaxTree.Identifier);
- VAR str: Scanner.IdentifierString;
- BEGIN
- Basic.GetString(x,str); w.String(str);ToText(w,current.text,ElementType.Default)
- END Identifier;
- (** Procedure used to traverse qualified identifiers **)
- PROCEDURE QualifiedIdentifier*(x: SyntaxTree.QualifiedIdentifier);
- VAR str: Scanner.IdentifierString;
- BEGIN
- IF x.prefix # SyntaxTree.invalidIdentifier THEN Basic.GetString(x.prefix,str); w.String(str); w.String("."); END;
- Basic.GetString(x.suffix,str); w.String(str); ToText(w,current.text,QualifiedIdentifierElementType);
- END QualifiedIdentifier;
- (* types *)
- PROCEDURE Type*(x: SyntaxTree.Type);
- BEGIN
- IF x # NIL THEN x.Accept(SELF) END;
- END Type;
- PROCEDURE VisitType*(x: SyntaxTree.Type);
- BEGIN
- END VisitType;
- PROCEDURE VisitBasicType*(x: SyntaxTree.BasicType);
- BEGIN
- IF x.typeDeclaration # NIL THEN
- Identifier(x.typeDeclaration.name)
- ELSE
- Identifier(x.name)
- END
- END VisitBasicType;
- PROCEDURE VisitBooleanType*(x: SyntaxTree.BooleanType);
- BEGIN VisitBasicType(x)
- END VisitBooleanType;
- PROCEDURE VisitSetType*(x: SyntaxTree.SetType);
- BEGIN VisitBasicType(x)
- END VisitSetType;
- PROCEDURE VisitSizeType*(x: SyntaxTree.SizeType);
- BEGIN VisitBasicType(x)
- END VisitSizeType;
- PROCEDURE VisitCharacterType*(x: SyntaxTree.CharacterType);
- BEGIN VisitBasicType(x)
- END VisitCharacterType;
- PROCEDURE VisitIntegerType*(x: SyntaxTree.IntegerType);
- BEGIN VisitBasicType(x)
- END VisitIntegerType;
- PROCEDURE VisitFloatType*(x: SyntaxTree.FloatType);
- BEGIN VisitBasicType(x)
- END VisitFloatType;
- PROCEDURE VisitComplexType*(x: SyntaxTree.ComplexType);
- BEGIN VisitBasicType(x)
- END VisitComplexType;
- PROCEDURE VisitByteType*(x: SyntaxTree.ByteType);
- BEGIN VisitBasicType(x)
- END VisitByteType;
- PROCEDURE VisitQualifiedType*(x: SyntaxTree.QualifiedType);
- BEGIN
- IF x.qualifiedIdentifier # NIL THEN
- QualifiedIdentifier(x.qualifiedIdentifier)
- END;
- END VisitQualifiedType;
- PROCEDURE VisitStringType*(x: SyntaxTree.StringType);
- BEGIN
- END VisitStringType;
- PROCEDURE VisitEnumerationType*(x: SyntaxTree.EnumerationType);
- VAR e: SyntaxTree.Constant; first: BOOLEAN;
- BEGIN
- Keyword("ENUMERATION"); Whitespace;
- IF x.enumerationBase # NIL THEN
- String("(");
- Type(x.enumerationBase);
- String(")");
- END;
- IF ~short THEN
- e := x.enumerationScope.firstConstant; first := TRUE;
- WHILE (e # NIL) DO
- IF ~first THEN String(","); Whitespace; ELSE first := FALSE END;
- VisitConstant(e);
- e := e.nextConstant;
- END;
- END;
- END VisitEnumerationType;
- PROCEDURE VisitRangeType*(x: SyntaxTree.RangeType);
- BEGIN VisitBasicType(x);
- END VisitRangeType;
- PROCEDURE VisitArrayType*(x: SyntaxTree.ArrayType);
- BEGIN
- Keyword("ARRAY"); Whitespace;
- IF x.length # NIL THEN Expression(x.length);ToText(w,current.text,ElementType.Default);Whitespace; END;
- Keyword("OF");Whitespace;
- Type(x.arrayBase);
- END VisitArrayType;
- PROCEDURE VisitNilType*(x: SyntaxTree.NilType);
- BEGIN
- String("NILTYPE");
- END VisitNilType;
- PROCEDURE VisitAddressType*(x: SyntaxTree.AddressType);
- BEGIN
- String("ADDRESSTYPE");
- END VisitAddressType;
- PROCEDURE VisitObjectType*(x: SyntaxTree.ObjectType);
- BEGIN
- VisitBasicType(x);
- END VisitObjectType;
- PROCEDURE VisitAnyType*(x: SyntaxTree.AnyType);
- BEGIN
- VisitBasicType(x);
- END VisitAnyType;
- PROCEDURE VisitMathArrayType*(x: SyntaxTree.MathArrayType);
- BEGIN
- Keyword("ARRAY" );Whitespace;
- IF x.form = SyntaxTree.Tensor THEN String("[?]");
- ELSE
- String("[");
- IF x.length = NIL THEN
- String("*")
- ELSE
- Expression(x.length);
- END;
- WHILE(x.arrayBase # NIL) & (x.arrayBase IS SyntaxTree.MathArrayType) DO
- x := x.arrayBase(SyntaxTree.MathArrayType);
- String(",");
- IF x.length = NIL THEN
- String("*")
- ELSE
- Expression(x.length);
- END;
- END;
- String("]");Whitespace;
- END;
- IF x.arrayBase # NIL THEN
- Keyword("OF" );Whitespace;
- Type(x.arrayBase);
- END;
- END VisitMathArrayType;
- PROCEDURE VisitPointerType*(x: SyntaxTree.PointerType);
- VAR pointerBase: SyntaxTree.Type;
- BEGIN
- IF x.pointerBase # NIL THEN
- pointerBase := x.pointerBase;
- IF (pointerBase IS SyntaxTree.RecordType) & (pointerBase(SyntaxTree.RecordType).isObject) THEN
- VisitRecordType(pointerBase(SyntaxTree.RecordType))
- ELSE
- Keyword("POINTER"); Whitespace; Keyword("TO" ); Whitespace; Type(x.pointerBase)
- END;
- END;
- END VisitPointerType;
- PROCEDURE VisitPortType*(x: SyntaxTree.PortType);
- BEGIN
- Keyword("PORT");Whitespace;
- IF x.direction = SyntaxTree.OutPort THEN
- Keyword("OUT")
- ELSE
- ASSERT(x.direction = SyntaxTree.InPort);
- Keyword("IN");
- END;
- Whitespace;
- IF x.sizeExpression # NIL THEN
- String("("); Expression(x.sizeExpression); String(")");
- END;
- END VisitPortType;
- PROCEDURE VisitCellType*(x: SyntaxTree.CellType);
- BEGIN
- Keyword("CELL");Whitespace;
- Modifiers(x.modifiers);
- IF x.firstParameter # NIL THEN ParameterList(x.firstParameter) END;
- IF ~short THEN
- Summary(current.paragraphs, x.cellScope);
- Scope(x.cellScope);
- END;
- END VisitCellType;
- PROCEDURE VisitRecordType*(x: SyntaxTree.RecordType);
- VAR prevScope: SyntaxTree.Scope; first: BOOLEAN; variable: SyntaxTree.Variable;
- BEGIN
- IF x.isObject THEN
- Keyword("OBJECT");Whitespace;
- IF x.pointerType # NIL THEN END;
- IF (x.baseType # NIL) THEN
- String( "(" );
- IF (x.baseType IS SyntaxTree.RecordType) & (x.baseType(SyntaxTree.RecordType).pointerType # NIL) THEN
- Type(x.baseType(SyntaxTree.RecordType).pointerType)
- ELSE
- Type(x.baseType);
- END;
- String( ")" );
- END;
- IF ~short THEN
- Summary(current.paragraphs, x.recordScope);
- Scope(x.recordScope);
- END;
- ELSE
- Keyword("RECORD");Whitespace;
- IF (x.baseType # NIL) THEN
- String( "(" );
- IF (x.baseType IS SyntaxTree.RecordType) & (x.baseType(SyntaxTree.RecordType).pointerType # NIL) THEN
- Type(x.baseType(SyntaxTree.RecordType).pointerType)
- ELSE
- Type(x.baseType);
- END;
- String( ")" );
- END;
- IF ~short THEN
- Summary(current.paragraphs, x.recordScope);
- Scope(x.recordScope);
- END;
- END;
- END VisitRecordType;
- PROCEDURE VisitProcedureType*(x: SyntaxTree.ProcedureType);
- VAR first: BOOLEAN;
- BEGIN
- Keyword("PROCEDURE" );
- first := TRUE;
- IF x.isDelegate THEN Flag(Global.NameDelegate,first) END;
- IF x.isInterrupt THEN Flag(Global.NameInterrupt,first) END;
- IF x.noPAF THEN Flag(Global.NameNoPAF,first) END;
- IF x.callingConvention = SyntaxTree.WinAPICallingConvention THEN
- Flag(Global.NameWinAPI,first)
- ELSIF x.callingConvention = SyntaxTree.CCallingConvention THEN
- Flag(Global.NameC,first)
- END;
- IF x.stackAlignment > 1 THEN Value(Global.NameStackAligned,x.stackAlignment,first) END;
- IF ~first THEN String("}") END;
- Whitespace;
- IF (x.firstParameter # NIL) OR (x.returnType # NIL) THEN
- ParameterList(x.firstParameter)
- END;
- IF x.returnType # NIL THEN String( ":" ); Whitespace; Type(x.returnType) END;
- END VisitProcedureType;
- (* expressions *)
- PROCEDURE ExpressionList(x: SyntaxTree.ExpressionList);
- VAR i: LONGINT; expression: SyntaxTree.Expression;
- BEGIN
- FOR i := 0 TO x.Length() - 1 DO
- expression := x.GetExpression( i ); Expression(expression);
- IF i < x.Length() - 1 THEN String( "," ); END;
- END;
- END ExpressionList;
- PROCEDURE Expression*(x: SyntaxTree.Expression);
- BEGIN
- IF x # NIL THEN
- x.Accept(SELF);
- END;
- w.Update;
- END Expression;
- PROCEDURE VisitExpression*(x: SyntaxTree.Expression);
- BEGIN
- END VisitExpression;
- PROCEDURE VisitSet*(x: SyntaxTree.Set);
- BEGIN
- String( "{" ); ExpressionList(x.elements); String( "}" );
- END VisitSet;
- PROCEDURE VisitMathArrayExpression*(x: SyntaxTree.MathArrayExpression);
- BEGIN
- String( "[" ); ExpressionList(x.elements); String( "]" );
- END VisitMathArrayExpression;
- PROCEDURE VisitUnaryExpression*(x: SyntaxTree.UnaryExpression);
- VAR identifier: SyntaxTree.Identifier;
- BEGIN
- IF x.operator = Scanner.Transpose THEN
- identifier := Global.GetIdentifier(x.operator,case);
- Expression(x.left);
- Identifier(identifier);
- ELSE
- identifier := Global.GetIdentifier(x.operator,case);
- Identifier(identifier);
- Expression(x.left);
- END;
- END VisitUnaryExpression;
- PROCEDURE VisitBinaryExpression*(x: SyntaxTree.BinaryExpression);
- VAR identifier: SyntaxTree.Identifier;
- BEGIN
- String( "(" );
- Expression(x.left);
- identifier := Global.GetIdentifier(x.operator,case);
- Identifier(identifier);
- Expression(x.right);
- String(")");
- END VisitBinaryExpression;
- PROCEDURE VisitRangeExpression*(x: SyntaxTree.RangeExpression);
- BEGIN
- IF x.missingFirst & x.missingLast & x.missingStep THEN
- String("*")
- ELSE
- IF ~x.missingFirst THEN Expression(x.first) END;
- String("..");
- IF ~x.missingLast THEN Expression(x.last) END;
- IF ~x.missingStep THEN
- Keyword("BY");
- Expression(x.step)
- END
- END;
- END VisitRangeExpression;
- PROCEDURE VisitTensorRangeExpression*(x: SyntaxTree.TensorRangeExpression);
- BEGIN String("?");
- END VisitTensorRangeExpression;
- PROCEDURE VisitConversion*(x: SyntaxTree.Conversion);
- BEGIN
- IF x.typeExpression # NIL THEN Expression(x.typeExpression); String("(");
- END;
- Expression(x.expression);
- IF x.typeExpression # NIL THEN String(")") END;
- END VisitConversion;
- PROCEDURE VisitSymbolDesignator*(x: SyntaxTree.SymbolDesignator);
- BEGIN
- IF x.left # NIL THEN
- Expression(x.left); String(".");
- END;
- IF x.symbol IS SyntaxTree.Operator THEN
- String('"'); Identifier(x.symbol.name); String('"');
- ELSE
- Identifier(x.symbol.name)
- END;
- END VisitSymbolDesignator;
- PROCEDURE VisitBuiltinCallDesignator*(x: SyntaxTree.BuiltinCallDesignator);
- BEGIN
- IF x.left # NIL THEN
- Expression(x.left);
- ELSE
- String("BUILTIN(");
- w.Int(x.id,1);
- String(")");
- END;
- String("("); ExpressionList(x.parameters); String(")");
- END VisitBuiltinCallDesignator;
- PROCEDURE VisitValue*(x: SyntaxTree.Value);
- BEGIN
- END VisitValue;
- PROCEDURE VisitBooleanValue*(x: SyntaxTree.BooleanValue);
- BEGIN
- IF Scanner.Uppercase = case THEN
- IF x.value THEN String("TRUE" ) ELSE String( "FALSE" ) END
- ELSE
- IF x.value THEN String("true" ) ELSE String( "false" ) END
- END
- END VisitBooleanValue;
- PROCEDURE VisitIntegerValue*(x: SyntaxTree.IntegerValue);
- BEGIN
- w.Int(x.value,1);
- ToText(w,current.text,ElementType.Default);
- END VisitIntegerValue;
- PROCEDURE VisitCharacterValue*(x: SyntaxTree.CharacterValue);
- BEGIN
- Hex(w, ORD(x.value)); w.String( "X" );
- ToText(w,current.text,ElementType.Default);
- END VisitCharacterValue;
- PROCEDURE VisitSetValue*(x: SyntaxTree.SetValue);
- VAR i: LONGINT;
- BEGIN
- w.String("{");
- i := 0;
- WHILE (i<MAX(SET)) & ~(i IN x.value) DO
- INC(i);
- END;
- IF i<MAX(SET) THEN
- w.Int(i,1);
- INC(i);
- WHILE i < MAX(SET) DO
- IF i IN x.value THEN w.String(","); w.Int(i,1); END;
- INC(i)
- END
- END;
- w.String("}");
- ToText(w,current.text,ElementType.Default);
- END VisitSetValue;
- PROCEDURE VisitMathArrayValue*(x: SyntaxTree.MathArrayValue);
- BEGIN
- VisitMathArrayExpression(x.array);
- END VisitMathArrayValue;
- PROCEDURE FormatedFloat(value: LONGREAL; subtype: LONGINT);
- VAR string: ARRAY 128 OF CHAR; i: LONGINT;
- BEGIN
- IF subtype = Scanner.Real THEN
- ws.SetPos(0); ws.Float(value,11(*mantissa X.XXXXXXX *)+5(*exponent E+XXX *)); ws.Get(string);
- i := 0;
- WHILE(i<LEN(string)) & (string[i] # 0X) DO
- IF string[i] = "D" THEN string[i] := "E" END;
- INC(i);
- END;
- String(string);
- ELSIF subtype = Scanner.Longreal THEN
- ws.SetPos(0); ws.Float(value,20(*mantissa X.X..(16)..X *)+5(*exponent E+XXX *) ); ws.Get(string);
- i := 0;
- WHILE(i<LEN(string)) & (string[i] # 0X) DO
- IF string[i] = "E" THEN string[i] := "D" END;
- INC(i);
- END;
- String(string);
- ELSE
- w.Float(value,64);
- ToText(w,current.text,ElementType.Default);
- END;
- END FormatedFloat;
- PROCEDURE VisitRealValue*(x: SyntaxTree.RealValue);
- BEGIN FormatedFloat(x.value, x.subtype)
- END VisitRealValue;
- PROCEDURE VisitComplexValue*(x: SyntaxTree.ComplexValue);
- BEGIN
- IF (x.realValue = 0) & (x.imagValue = 1) THEN
- String("IMAG")
- ELSE
- String("(");
- FormatedFloat(x.realValue, x.subtype) ;
- IF x.imagValue > 0 THEN String("+") END;
- FormatedFloat(x.imagValue, x.subtype);
- String("*IMAG)")
- END
- END VisitComplexValue;
- PROCEDURE VisitStringValue*(x: SyntaxTree.StringValue);
- VAR i: LONGINT;
- BEGIN
- i := 0;
- WHILE (i < LEN( x.value )) & (x.value[i] # 0X) & (x.value[i] # '"') DO INC( i ); END;
- ASSERT(i # LEN(x.value));
- IF (x.value[i] = 0X) THEN (* no double quotes contained in the string *)
- w.String( '"' ); w.String( x.value^ ); w.String( '"' );
- ELSE (* double quotes found in string *)
- w.String( "'" ); w.String( x.value^ ); w.String( "'" );
- END;
- ToText(w,current.text,ElementType.Default);
- END VisitStringValue;
- PROCEDURE VisitNilValue*(x: SyntaxTree.NilValue);
- BEGIN String( "NIL" );
- END VisitNilValue;
- PROCEDURE VisitEnumerationValue*(x: SyntaxTree.EnumerationValue);
- BEGIN w.Int(x.value,1); ToText(w,current.text,ElementType.Default);
- END VisitEnumerationValue;
- (**** symbols ****)
- PROCEDURE VisitParameter*(x: SyntaxTree.Parameter);
- END VisitParameter;
- PROCEDURE PrintSymbol(x: SyntaxTree.Symbol);
- VAR first: BOOLEAN; w: Streams.StringWriter; name: Scanner.IdentifierString;
- BEGIN
- NEW(w,256);
- Basic.GetString(x.name,name);
- IF x IS SyntaxTree.Operator THEN
- w.String('"'); w.String(name); w.String('"')
- ELSE
- w.String(name)
- END;
- IF SyntaxTree.PublicWrite IN x.access THEN w.String( "*" )
- ELSIF SyntaxTree.PublicRead IN x.access THEN
- IF x IS SyntaxTree.Variable THEN
- w.String( "-" )
- ELSIF ~(x IS SyntaxTree.Parameter) THEN
- w.String("*")
- END
- END;
- ToText(w, current.text,ElementType.Default);
- END PrintSymbol;
- PROCEDURE ParameterList*(x: SyntaxTree.Parameter);
- VAR next: SyntaxTree.Parameter; first: BOOLEAN;
- BEGIN
- first := TRUE;
- String( "(" );
- WHILE(x # NIL) DO
- next := x.nextParameter;
- IF (x.access # SyntaxTree.Hidden) THEN
- IF ~first THEN String(";"); Whitespace END;
- first := FALSE;
- IF x.kind = SyntaxTree.VarParameter THEN Keyword("VAR" );Whitespace;
- ELSIF x.kind = SyntaxTree.ConstParameter THEN Keyword("CONST" );Whitespace;
- END;
- PrintSymbol(x);
- IF x.defaultValue # NIL THEN
- String("="); Whitespace; Expression(x.defaultValue);
- END;
- WHILE (next # NIL) & (next.type = x.type) & (next.kind = x.kind) & ((next.access # SyntaxTree.Hidden) ) DO
- String(",");Whitespace;
- PrintSymbol(next);
- IF next.defaultValue # NIL THEN
- String("="); Whitespace; Expression(next.defaultValue);
- END;
- next := next.nextParameter;
- END;
- IF x.access # SyntaxTree.Hidden THEN
- String(":");Whitespace;
- Type(x.type);
- ELSE
- String(":");Whitespace;
- Type(x.type);
- END;
- END;
- x := next;
- END;
- String( ")" );
- END ParameterList;
- PROCEDURE Visible(symbol: SyntaxTree.Symbol): BOOLEAN;
- BEGIN
- RETURN (symbol # NIL) & ( (SyntaxTree.Public * symbol.access # {}) OR backend.internals)
- END Visible;
- PROCEDURE Symbol*(x: SyntaxTree.Symbol);
- BEGIN
- IF Visible(x) THEN x.Accept(SELF) END
- END Symbol;
- PROCEDURE NeedsSection(x: SyntaxTree.Symbol): BOOLEAN;
- VAR declaredType: SyntaxTree.Type;tmp: SyntaxTree.Comment;
- BEGIN
- IF x.comment # NIL THEN
- tmp := x.comment;
- WHILE (tmp # NIL) & (tmp.item = x) DO
- IF tmp.source[0] = "*" THEN RETURN TRUE END;
- tmp := tmp.nextComment
- END;
- END;
- IF x IS SyntaxTree.TypeDeclaration THEN
- declaredType := x(SyntaxTree.TypeDeclaration).declaredType.resolved;
- IF declaredType IS SyntaxTree.PointerType THEN declaredType := declaredType(SyntaxTree.PointerType).pointerBase.resolved END;
- RETURN (declaredType IS SyntaxTree.RecordType) OR (declaredType IS SyntaxTree.EnumerationType)
- END;
- RETURN FALSE
- END NeedsSection;
- PROCEDURE ExtractParameters(x: SyntaxTree.ProcedureType; doc: DocumentationTree.Document; VAR parameters: DocumentationTree.Document);
- VAR par: SyntaxTree.Parameter; paragraph,heading: DocumentationTree.Paragraph; i: LONGINT; element: DocumentationTree.TextElement;
- string: DocumentationTree.String; id: SyntaxTree.Identifier; done: BOOLEAN;
- BEGIN
- i := 0;
- WHILE i < doc.description.Length() DO
- paragraph := doc.description.GetParagraph(i);
- done := FALSE;
- IF (paragraph.type = ParagraphType.Description) & (paragraph.description.Length() = 1) THEN
- element := paragraph.description.GetElement(0);
- string := element.string;
- id := SyntaxTree.NewIdentifier(string^);
- par := x.firstParameter;
- WHILE (par # NIL) & ~done DO
- IF par.name = id THEN
- done := TRUE;
- doc.description.RemoveByIndex(i);
- IF parameters = NIL THEN
- NEW(parameters);
- END;
- parameters.description.Add(paragraph);
- END;
- par := par.nextParameter;
- END;
- IF ~done & ((string^="RESULT") OR (string^="result")) THEN
- doc.description.RemoveByIndex(i);
- IF parameters = NIL THEN
- NEW(parameters);
- END;
- parameters.description.Add(paragraph);
- done := TRUE;
- END;
- END;
- IF ~done THEN INC(i) END;
- END;
- END ExtractParameters;
- PROCEDURE WriteSymbolSection(x: SyntaxTree.Symbol);
- VAR section: DocumentationTree.Section; paragraph: DocumentationTree.Paragraph; commentDoc: DocumentationTree.Document;
- parameters: DocumentationTree.Document;
- BEGIN
- IF Visible(x) & NeedsSection(x) THEN
- section := BeginSymbolSection("",x);
- parameterDocument := NIL;
- IF x.comment # NIL THEN
- commentDoc := DocumentationTree.NewDocument();
- ParseComments(commentDoc,x.comment, NIL,x);
- PatchLinks(commentDoc, x.scope);
- KeepSections(commentDoc);
- IF (x IS SyntaxTree.Procedure) THEN
- ExtractParameters(x.type(SyntaxTree.ProcedureType), commentDoc, parameters);
- END;
- MergeDocument(current.document, section.contents, commentDoc);
- END;
- paragraph := section.contents.AppendNew(ParagraphType.Heading);
- paragraph.SetLevel(2);
- paragraph.text.WriteString("Syntax");
- paragraph := section.contents.AppendNew(ParagraphType.Code);
- current.text := paragraph.text;
- Symbol(x);
- IF parameters # NIL THEN
- paragraph := section.contents.AppendNew(ParagraphType.Heading);
- paragraph.SetLevel(2);
- paragraph.text.WriteString("Parameters");
- MergeDocument(current.document, section.contents, parameters);
- END;
- EndSection(section);
- END;
- END WriteSymbolSection;
- PROCEDURE BeginSymbolSection(CONST title: ARRAY OF CHAR; x: SyntaxTree.Symbol):DocumentationTree.Section;
- VAR section: DocumentationTree.Section; name: Basic.SectionName; paragraph:DocumentationTree.Paragraph;
- BEGIN
- section := BeginSection(current.document);
- current.section := section;
- current.paragraphs := section.contents;
- WriteSymbolLabel(section.title, x);
- (*
- Global.GetSymbolNameInScope(x,(* current.scope*) NIL ,name);
- *)
- WriteReferenceInScope(section.title, x, NIL);
- (*
- section.title.WriteString(name); (* WriteString(section.title,title);*)
- *)
- (*
- section := current.section;
- current.paragraphs := section.contents;
- paragraph := section.contents.AppendNew(ParagraphType.Line);
- paragraph := section.contents.AppendNew(ParagraphType.Heading);
- paragraph.SetLevel(1);
- WriteSymbolLabel(paragraph.text, x);
- Global.GetSymbolNameInScope(x,(* current.scope*) NIL ,name);
- WriteString(paragraph.text, name); (* WriteString(section.title,title);*)
- *)
- RETURN section;
- END BeginSymbolSection;
- PROCEDURE VisitSymbol*(x: SyntaxTree.Symbol);
- BEGIN
- END VisitSymbol;
- PROCEDURE VisitTypeDeclaration*(x: SyntaxTree.TypeDeclaration);
- VAR section: DocumentationTree.Section; paragraph: DocumentationTree.Paragraph;commentDoc: DocumentationTree.Document;
- BEGIN
- IF ~short THEN
- Keyword("TYPE"); Whitespace;
- PrintSymbol(x);
- ELSE
- WriteSymbolReference(current.text, x, current.scope);
- END;
- Whitespace;
- String("="); Type(x.declaredType);
- END VisitTypeDeclaration;
- PROCEDURE VisitConstant*(x: SyntaxTree.Constant);
- VAR section: DocumentationTree.Section;paragraph: DocumentationTree.Paragraph; commentDoc: DocumentationTree.Document;
- BEGIN
- IF ~short THEN
- Keyword("CONST"); Whitespace; PrintSymbol(x)
- ELSE
- WriteSymbolReference(current.text, x, current.scope);
- END;
- IF x.value # NIL THEN
- String( "=" ); Whitespace; Expression(x.value);
- END;
- END VisitConstant;
- PROCEDURE VisitVariable*(x: SyntaxTree.Variable);
- VAR section: DocumentationTree.Section; paragraph: DocumentationTree.Paragraph;commentDoc: DocumentationTree.Document;
- BEGIN
- IF ~short THEN
- Keyword("VAR"); Whitespace; PrintSymbol(x)
- ELSE
- WriteSymbolReference(current.text, x, current.scope);
- END;
- String( ":" );Whitespace;
- Type(x.type);
- END VisitVariable;
- PROCEDURE Flag(identifier: SyntaxTree.Identifier; VAR first: BOOLEAN);
- VAR name: SyntaxTree.IdentifierString;
- BEGIN
- IF first THEN String("{") ELSE String(",") END;
- first := FALSE;
- Basic.GetString(identifier,name);
- String(name);
- END Flag;
- PROCEDURE FlagEnd(first: BOOLEAN);
- BEGIN
- IF ~first THEN String("}") END;
- END FlagEnd;
- PROCEDURE Int(value: LONGINT);
- VAR s: DocumentationTree.String; textElement: DocumentationTree.TextElement;
- BEGIN
- NEW(s,32); Strings.IntToStr(value,s^);
- textElement := current.text.AppendNew(ElementType.Default);
- textElement.SetString(s);
- END Int;
- PROCEDURE Value(identifier: SyntaxTree.Identifier; value: LONGINT; VAR first: BOOLEAN);
- BEGIN
- Flag(identifier,first);
- w.String("("); w.Int(value,1); w.String(")");ToText(w,current.text,ElementType.Default);
- END Value;
- (** process procedure including comments describing the procedure *)
- PROCEDURE VisitProcedure*(x: SyntaxTree.Procedure);
- VAR section: DocumentationTree.Section; paragraph: DocumentationTree.Paragraph; name: Basic.SectionName; first: BOOLEAN; type: SyntaxTree.ProcedureType;
- doc: DocumentationTree.Document; par: SyntaxTree.Parameter;
- BEGIN
- IF ~short THEN
- IF x IS SyntaxTree.Operator THEN
- Keyword("OPERATOR")
- ELSE
- Keyword("PROCEDURE")
- END;
- END;
- IF x.isInline THEN String("-") END;
- IF x.isConstructor THEN String("&") END;
- Whitespace;
- type := x.type(SyntaxTree.ProcedureType);
- first := TRUE;
- IF type.stackAlignment > 1 THEN Value(Global.NameStackAligned,type.stackAlignment,first) END;
- IF (type.isRealtime) THEN Flag(Global.NameRealtime,first) END;
- IF (x.fixed) THEN Value(Global.NameFixed, x.alignment,first)
- ELSIF (x.alignment >1) THEN Value(Global.NameAligned, x.alignment, first)
- END;
- FlagEnd(first);
- IF ~short THEN
- PrintSymbol(x)
- ELSE
- WriteSymbolReference(current.text, x, current.scope);
- END;
- IF (type.firstParameter # NIL) OR (type.returnType # NIL ) THEN (* print parentheses only if not parameterless procedure *)
- Whitespace;
- ParameterList(type.firstParameter);
- END;
- IF type.returnType # NIL THEN
- String( ":" );
- Whitespace;
- Type(type.returnType);
- END;
- END VisitProcedure;
- PROCEDURE String(CONST name: ARRAY OF CHAR);
- BEGIN current.text.WriteString(name);
- END String;
- PROCEDURE Whitespace;
- BEGIN
- current.text.WriteWhitespace
- END Whitespace;
- PROCEDURE VisitOperator*(x: SyntaxTree.Operator);
- BEGIN VisitProcedure(x);
- END VisitOperator;
- PROCEDURE VisitImport*(x: SyntaxTree.Import);
- VAR context: SyntaxTree.Identifier; name: Basic.SectionName;
- BEGIN
- x.GetName(name);
- current.text.WriteLabel(name);
- IF x.moduleName # x.name THEN PrintSymbol(x); String( " := " ); END;
- IF (x.scope = NIL) OR (x.scope.ownerModule = NIL) THEN context := SyntaxTree.invalidIdentifier ELSE context := x.scope.ownerModule.context END;
- WriteReferenceInScope(current.text, x.module, NIL);
- IF (x.context # SyntaxTree.invalidIdentifier) & (x.context#context) THEN
- String(" IN ");
- Identifier(x.context)
- END;
- END VisitImport;
- PROCEDURE VisitBuiltin*(x: SyntaxTree.Builtin);
- BEGIN
- END VisitBuiltin;
- (*** scopes ****)
- PROCEDURE Scope*(x: SyntaxTree.Scope);
- VAR
- constant: SyntaxTree.Constant;
- type: SyntaxTree.TypeDeclaration;
- variable : SyntaxTree.Variable;
- procedure: SyntaxTree.Procedure;
- prevScope: SyntaxTree.Scope;
- BEGIN
- prevScope := current.scope;
- current.scope := x;
- constant := x.firstConstant;
- WHILE constant # NIL DO WriteSymbolSection(constant); constant := constant.nextConstant; END;
- type := x.firstTypeDeclaration;
- WHILE type # NIL DO WriteSymbolSection(type); type := type.nextTypeDeclaration END;
- variable := x.firstVariable;
- WHILE variable # NIL DO WriteSymbolSection(variable); variable := variable.nextVariable END;
- procedure := x.firstProcedure;
- WHILE procedure # NIL DO WriteSymbolSection(procedure); procedure := procedure.nextProcedure END;
- current.scope := prevScope;
- END Scope;
- PROCEDURE SymbolRow(CONST head: ARRAY OF CHAR; symbol: SyntaxTree.Symbol; VAR first: BOOLEAN);
- VAR row, cell: DocumentationTree.TextElement; x: SyntaxTree.Constant;
- BEGIN
- IF Visible(symbol) THEN
- row := current.text.AppendNew(ElementType.Row);
- IF first THEN
- first := FALSE;
- cell := row.text.AppendNew(ElementType.HeaderCell);
- cell.text.WriteString(head);
- ELSE
- cell := row.text.AppendNew(ElementType.DataCell);
- END;
- cell := row.text.AppendNew(ElementType.DataCell);
- current.text := cell.text;
- Symbol(symbol);
- END;
- END SymbolRow;
- PROCEDURE Summary(paragraphs: DocumentationTree.Paragraphs; x: SyntaxTree.Scope);
- VAR
- import: SyntaxTree.Import;
- constant: SyntaxTree.Constant;
- type: SyntaxTree.TypeDeclaration;
- variable : SyntaxTree.Variable;
- procedure: SyntaxTree.Procedure;
- first: BOOLEAN;
- prevScope: SyntaxTree.Scope;
- paragraph: DocumentationTree.Paragraph;
- BEGIN
- prevScope := current.scope;
- current.scope := x;
- paragraph := paragraphs.AppendNew(ParagraphType.Heading); paragraph.SetLevel(2); paragraph.text.WriteString("Summary");
- paragraph := paragraphs.AppendNew(ParagraphType.Table);
- current.text := paragraph.text;
- short := TRUE;
- IF x IS SyntaxTree.ModuleScope THEN
- import := x(SyntaxTree.ModuleScope).firstImport; first := TRUE;
- WHILE import # NIL DO SymbolRow("imports",import,first); import := import.nextImport; END;
- END;
- constant := x.firstConstant; first := TRUE;
- WHILE constant # NIL DO SymbolRow("constants",constant,first); constant := constant.nextConstant; END;
- type := x.firstTypeDeclaration; first := TRUE;
- WHILE type # NIL DO SymbolRow("type declarations", type,first); type := type.nextTypeDeclaration END;
- variable := x.firstVariable; first := TRUE;
- WHILE variable # NIL DO SymbolRow("variables", variable,first); variable := variable.nextVariable END;
- procedure := x.firstProcedure; first := TRUE;
- WHILE procedure # NIL DO SymbolRow("procedures", procedure,first); procedure := procedure.nextProcedure END;
- current.scope := prevScope;
- short := FALSE;
- (*
- paragraph := paragraphs.AppendNew(ParagraphType.TextBlock);
- paragraph.text.WriteLink("ModuleList","List of modules");
- *)
- END Summary;
- PROCEDURE WriteTextElement(textElement: DocumentationTree.TextElement);
- VAR paragraph: DocumentationTree.Paragraph; element: DocumentationTree.TextElement;
- BEGIN
- ASSERT(current.text # NIL);
- CASE textElement.type OF
- ElementType.Italic, ElementType.Bold, ElementType.Underline, ElementType.Code: current.text.Add(textElement);
- current.text := textElement.text;
- | ElementType.HeaderCell, ElementType.DataCell, ElementType.Row:
- ASSERT(current.paragraphs # NIL);
- ASSERT(current.paragraphs.Length() # 0);
- paragraph := current.paragraphs.Last();
- current.text := paragraph.text;
- IF textElement.type # ElementType.Row THEN
- ASSERT(current.text.Length() # 0);
- element := current.text.Last();
- current.text := element.text
- END;
- current.text.Add(textElement);
- current.text := textElement.text;
- ELSE
- current.text.Add(textElement)
- END;
- END WriteTextElement;
- PROCEDURE BeginSection(document: DocumentationTree.Document): DocumentationTree.Section;
- VAR section: DocumentationTree.Section;
- BEGIN
- INC(level[Section]);
- section := document.sections.AppendNew(level[Section]);
- RETURN section;
- END BeginSection;
- PROCEDURE PrefixSection(document: DocumentationTree.Document): DocumentationTree.Section;
- VAR section: DocumentationTree.Section;
- BEGIN
- INC(level[Section]);
- NEW(section, level[Section]);
- document.sections.Insert(0, section);
- RETURN section;
- END PrefixSection;
- PROCEDURE EndSection(section: DocumentationTree.Section);
- BEGIN
- DEC(level[Section]);
- END EndSection;
- PROCEDURE PatchLinkE(element: DocumentationTree.TextElement);
- VAR label: Strings.String; symbol: SyntaxTree.Symbol;name: Basic.SectionName; identifier: SyntaxTree.Identifier;
- BEGIN
- IF (element.type = ElementType.Link) & (element.string # NIL) THEN
- identifier := SyntaxTree.NewIdentifier(element.string^);
- symbol := current.scope.FindSymbol(identifier);
- IF (symbol # NIL) & ~(symbol IS SyntaxTree.Import) THEN
- IF element.text.Length()= 0 THEN element.text.WriteString(element.string^) END;
- Global.GetSymbolNameInScope(symbol, NIL, name);
- element.SetString(Strings.NewString(name));
- END;
- END;
- element.text.ForAllElementsDo(PatchLinkE)
- END PatchLinkE;
- PROCEDURE PatchLinksP(par: DocumentationTree.Paragraph);
- BEGIN
- par.text.ForAllElementsDo(PatchLinkE)
- END PatchLinksP;
- PROCEDURE PatchLinksS(sec: DocumentationTree.Section);
- VAR i: LONGINT;
- BEGIN
- sec.title.ForAllElementsDo(PatchLinkE);
- sec.contents.ForAllParagraphsDo(PatchLinksP)
- END PatchLinksS;
- PROCEDURE PatchLinks(doc: DocumentationTree.Document; scope: SyntaxTree.Scope);
- VAR i: LONGINT; prev: SyntaxTree.Scope;
- BEGIN
- prev := current.scope;
- current.scope := scope;
- doc.sections.ForAllSectionsDo(PatchLinksS);
- doc.description.ForAllParagraphsDo(PatchLinksP);
- current.scope := prev
- END PatchLinks;
-
- PROCEDURE Modifiers(x: SyntaxTree.Modifier);
- VAR name: Scanner.IdentifierString; first: BOOLEAN;
- BEGIN
- first := TRUE;
- WHILE x # NIL DO
- IF first THEN String("{"); first := FALSE ELSE String(", ") END;
- Basic.GetString(x.identifier,name);
- String(name);
- IF x.expression # NIL THEN
- String("(");
- Expression(x.expression);
- String(")");
- END;
- x := x.nextModifier;
- END;
- IF ~first THEN String("} ") END;
- END Modifiers;
- PROCEDURE Module*(x: SyntaxTree.Module; backend: DocumentationBackend): DocumentationTree.Document;
- VAR
- name: SyntaxTree.IdentifierString; section, cs: DocumentationTree.Section; commentDoc: DocumentationTree.Document;
- doc: DocumentationTree.Document; par: DocumentationTree.Paragraph; text: DocumentationTree.Text;
- BEGIN
- SELF.backend := backend;
- ASSERT(x # NIL);
- doc := DocumentationTree.NewDocument();
- level[Section] := 0;
- Global.GetModuleName(x,name);
- section := BeginSection(doc);
- section.WriteLabel("ModuleList");
- par := section.contents.AppendNew(ParagraphType.TextBlock);
- par.text.WriteString("Module");
- par.text.WriteWhitespace;
- par.text.WriteLink(name, name);
- EndSection(section);
- section := BeginSection(doc);
- section.title.WriteLabel(name);
- section.title.WriteWeakLink("ModuleList","Module"); (* if there is a module list, then e refer to it here *)
- section.title.WriteWhitespace;
- section.title.WriteString(name);
- IF x.comment # NIL THEN
- commentDoc := DocumentationTree.NewDocument();
- ParseComments(commentDoc,x.comment, x.closingComment,x);
- PatchLinks(commentDoc, x.moduleScope);
- MergeDocument(doc, section.contents, commentDoc);
- END;
- Summary(section.contents, x.moduleScope);
- EndSection(section);
- IF x.closingComment # NIL THEN
- cs := BeginSection(doc);
- commentDoc := DocumentationTree.NewDocument();
- ParseComments(commentDoc,x.closingComment, NIL,x);
- PatchLinks(commentDoc, x.moduleScope);
- MergeDocument(doc, cs.contents, commentDoc);
- EndSection(cs);
- END;
- current.document := doc;
- INC(level[Section]);
- Scope(x.moduleScope);
- DEC(level[Section]);
- current.scope := x.moduleScope;
- MergeDocument(doc, doc.description, document);
- document := doc;
- RETURN document
- END Module;
- END Generator;
- Checker= OBJECT
- VAR
- labels: DocumentationTree.Text;
- links: DocumentationTree.Text;
- currentScope: SyntaxTree.Scope;
- PROCEDURE CheckElement(element: DocumentationTree.TextElement);
- VAR label: Strings.String; symbol: SyntaxTree.Symbol;name: Basic.SectionName; identifier: SyntaxTree.Identifier;
- BEGIN
- IF (element.type = ElementType.Link) & (element.string # NIL) THEN
- identifier := SyntaxTree.NewIdentifier(element.string^);
- symbol := currentScope.FindSymbol(identifier);
- IF symbol # NIL THEN
- Global.GetSymbolNameInScope(symbol, NIL, name);
- element.SetString(Strings.NewString(name));
- END;
- ELSIF (element.type = ElementType.WeakLink) THEN
- IF labels.FindByString(element.string^) = NIL THEN
- element.SetType(ElementType.Default)
- ELSE
- element.SetType(ElementType.Link)
- END;
- END;
- END CheckElement;
- PROCEDURE CollectElement(element: DocumentationTree.TextElement);
- BEGIN
- IF (element.type = ElementType.WeakLink) THEN
- links.AddElement(element);
- ELSIF (element.type = ElementType.Label) THEN
- labels.Add(element)
- END;
- element.text.ForAllElementsDo(CollectElement);
- END CollectElement;
- PROCEDURE CollectParagraph(par: DocumentationTree.Paragraph);
- BEGIN
- IF par.label # NIL THEN
- labels.WriteLabel(par.label^)
- END;
- par.text.ForAllElementsDo(CollectElement);
- par.description.ForAllElementsDo(CollectElement);
- END CollectParagraph;
- PROCEDURE CollectSection(sec: DocumentationTree.Section);
- BEGIN
- IF sec.label # NIL THEN
- labels.WriteLabel(sec.label^)
- END;
- sec.title.ForAllElementsDo(CollectElement);
- sec.contents.ForAllParagraphsDo(CollectParagraph);
- END CollectSection;
- PROCEDURE Document(doc: DocumentationTree.Document; scope: SyntaxTree.Scope);
- BEGIN
- currentScope := scope;
- NEW(links, 4); NEW(labels, 4);
- doc.description.ForAllParagraphsDo(CollectParagraph);
- doc.sections.ForAllSectionsDo(CollectSection);
- links.ForAllElementsDo(CheckElement)
- END Document;
- END Checker;
- DocumentationBackend= OBJECT (Backend.Backend)
- VAR
- trace: BOOLEAN;
- fileName : Files.FileName;
- generator: Generator;
- templateFile: Files.FileName;
- internals: BOOLEAN;
- PROCEDURE &InitIntermediateBackend*;
- BEGIN
- InitBackend; generator := NIL;
- END InitIntermediateBackend;
- PROCEDURE ParseFile(fileName: ARRAY OF CHAR): DocumentationTree.Document;
- VAR reader: Files.Reader; parser: DocumentationParser.Parser; scanner: DocumentationScanner.Scanner;
- printer: DocumentationPrinter.Printer; document: DocumentationTree.Document;
- file: Files.File;
- BEGIN
- file := Files.Old(fileName);
- IF file = NIL THEN RETURN NIL END;
- NEW(reader, file, 0);
- NEW(scanner, reader,0,NIL);
- NEW(parser, scanner);
- document := DocumentationTree.NewDocument();
- parser.ParseDocument(document);
-
- RETURN document
- END ParseFile;
- PROCEDURE ProcessSyntaxTreeModule*(syntaxTreeModule: SyntaxTree.Module): Formats.GeneratedModule;
- VAR dump: Streams.Writer; printer: DocumentationPrinter.Printer; document, template: DocumentationTree.Document;
- htmlPrinter: DocumentationHtml.Printer; file: Files.File; writer: Files.Writer;
- name, extension: Files.FileName; checker: Checker;
- BEGIN
- Files.SplitExtension(fileName, name, extension);
- IF (name = "*") OR (generator = NIL) THEN
- NEW(generator,diagnostics);
- generator.case := syntaxTreeModule.case;
- END;
- document := generator.Module(syntaxTreeModule,SELF);
- IF templateFile # "" THEN
- template := ParseFile(templateFile);
- IF template # NIL THEN
- MergeDocument(template, NIL, document);
- document := template;
- ELSIF diagnostics # NIL THEN
- Basic.Error(diagnostics, "",Basic.invalidPosition, "could not open / parse documentation template");
- END;
- END;
- NEW(checker);
- checker.Document(document, NIL);
- IF trace THEN
- Global.GetModuleName(syntaxTreeModule, name);
- Strings.Append(name,".docu");
- dump := Basic.GetDebugWriter(name);
- NEW(printer, dump);
- printer.Document(document);
- NEW(htmlPrinter, dump);
- htmlPrinter.Document(document);
- dump.Update;
- END;
- IF name = "*" THEN
- Global.GetModuleName(syntaxTreeModule, name);
- END;
- Files.JoinExtension(name, extension, name);
- file := Files.New(name);
- IF file # NIL THEN
- NEW(writer, file,0);
- IF extension = "html" THEN
- NEW(htmlPrinter, writer);
- htmlPrinter.Document(document);
- ELSE
- NEW(printer, writer);
- printer.Document(document);
- END;
- writer.Update;
- Files.Register(file);
- END;
- RETURN NIL
- END ProcessSyntaxTreeModule;
- PROCEDURE DefineOptions*(options: Options.Options);
- BEGIN
- DefineOptions^(options);
- options.Add(0X,"dtrace",Options.Flag);
- options.Add(0X,"docuTemplate", Options.String);
- options.Add(0X,"internals",Options.Flag);
- END DefineOptions;
- PROCEDURE GetOptions*(options: Options.Options);
- BEGIN
- GetOptions^(options);
- trace := options.GetFlag("dtrace");
- IF ~options.GetString("d", fileName) THEN fileName := "" END;
- IF ~options.GetString("docuTemplate", templateFile) THEN COPY(DefaultTemplateFile, templateFile) END;
- internals := options.GetFlag("internals");
- END GetOptions;
- PROCEDURE DefaultSymbolFileFormat*(): Formats.SymbolFileFormat;
- BEGIN RETURN SymbolFileFormat.Get()
- END DefaultSymbolFileFormat;
- PROCEDURE DefaultObjectFileFormat*(): Formats.ObjectFileFormat;
- BEGIN RETURN NIL
- END DefaultObjectFileFormat;
- END DocumentationBackend;
- (* helper procedures *)
- PROCEDURE Small(CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
- VAR ch: CHAR; i: LONGINT;
- BEGIN
- i := 0;
- REPEAT
- ch := name[i];
- IF (ch >= 'A') & (ch <= 'Z') THEN
- ch := CHR(ORD(ch)-ORD('A')+ORD('a'));
- END;
- result[i] := ch; INC(i);
- UNTIL ch = 0X;
- END Small;
- PROCEDURE Hex(w: Streams.Writer; x: HUGEINT);
- VAR i: LONGINT; a: ARRAY 20 OF CHAR; y: HUGEINT;
- BEGIN
- i := 0;
- REPEAT
- y := x MOD 10H;
- IF y < 10 THEN a[i] := CHR(y+ORD('0'))
- ELSE a[i] := CHR(y-10+ORD('A'))
- END;
- x := x DIV 10H;
- INC(i);
- UNTIL (x=0) OR (i=16);
- IF y >=10 THEN w.Char("0") END;
- REPEAT DEC( i ); w.Char( a[i] ) UNTIL i = 0
- END Hex;
- PROCEDURE ToText(w: Streams.StringWriter; text: DocumentationTree.Text; elementType: ElementType);
- VAR textElement: DocumentationTree.TextElement; s: DocumentationTree.String;
- BEGIN
- NEW(s,w.Pos()+1);
- w.Get(s^);
- textElement := text.AppendNew(elementType);
- textElement.SetString(s);
- w.SetPos(0); (* reset writer *)
- END ToText;
- PROCEDURE WriteSymbolLabel(text: DocumentationTree.Text; symbol: SyntaxTree.Symbol);
- VAR label: Basic.SectionName;
- BEGIN
- Global.GetSymbolNameInScope(symbol,NIL,label);
- text.WriteLabel(label);
- END WriteSymbolLabel;
- PROCEDURE WriteReferenceInScope*(text: DocumentationTree.Text; symbol: SyntaxTree.Symbol; inScope: SyntaxTree.Scope);
- VAR n: SyntaxTree.IdentifierString; td: SyntaxTree.TypeDeclaration; name: Basic.SectionName; write: BOOLEAN;
- PROCEDURE Scope(scope: SyntaxTree.Scope);
- BEGIN
- IF scope = NIL THEN (* do nothing, locally declared temporary symbol *)
- ELSIF scope IS SyntaxTree.ModuleScope THEN
- Scope(NIL);
- Global.GetModuleName(scope.ownerModule, name);
- IF write THEN text.WriteWeakLink(name, name); text.WriteString(".") END;
- Strings.Append(name,".");
- ELSIF scope IS SyntaxTree.RecordScope THEN
- Scope(scope.outerScope);
- td := scope(SyntaxTree.RecordScope).ownerRecord.typeDeclaration;
- IF td = NIL THEN
- td := scope(SyntaxTree.RecordScope).ownerRecord.pointerType.typeDeclaration;
- END;
- td.GetName(n);
- Strings.Append(name,n);
- IF write THEN text.WriteWeakLink(name, n); text.WriteString(".") END;
- Strings.Append(name,".")
- ELSIF scope IS SyntaxTree.ProcedureScope THEN
- Scope(scope.outerScope);
- scope(SyntaxTree.ProcedureScope).ownerProcedure.GetName(n);
- Strings.Append(name,n);
- IF write THEN text.WriteWeakLink(name, n); text.WriteString(".") END;
- Strings.Append(name,".")
- ELSIF scope IS SyntaxTree.CellScope THEN
- Scope(scope.outerScope);
- td := scope(SyntaxTree.CellScope).ownerCell.typeDeclaration;
- td.GetName(n);
- Strings.Append(name,n);
- IF write THEN text.WriteWeakLink(name, n); text.WriteString(".") END;
- Strings.Append(name,".")
- ELSE Scope(scope.outerScope)
- END;
- IF (scope = inScope) THEN write := TRUE END;
- END Scope;
- BEGIN
- write := FALSE;
- name := "";
- Scope(symbol.scope);
- symbol.GetName(n);
- IF symbol IS SyntaxTree.Operator THEN (*! append some more bits to make discrimintation possible *)
- END;
- Strings.Append(name,n);
- text.WriteWeakLink(name, n);
- END WriteReferenceInScope;
- PROCEDURE WriteSymbolReference(text: DocumentationTree.Text; symbol: SyntaxTree.Symbol; scope: SyntaxTree.Scope);
- VAR name, label: Basic.SectionName; textElement: DocumentationTree.TextElement;
- BEGIN
- WriteReferenceInScope(text,symbol,scope);
- (*
- Global.GetSymbolNameInScope(symbol,scope,name);
- Global.GetSymbolNameInScope(symbol,NIL,label);
- IF symbol.comment # NIL THEN
- text.WriteLink(label, name);
- ELSE
- text.WriteString(name)
- END;
- *)
- END WriteSymbolReference;
- (*
- PROCEDURE ConvertSpecialSections(document: DocumentationTree.Document);
- VAR description: DocumentationTree.Paragraphs; i: LONGINT; section: DocumentationTree.Section; par : DocumentationTree.Paragraph;
- BEGIN
- description := document.description;
- FOR i := document.sections.Length()-1 TO 0 BY -1 DO
- section := document.sections.GetSection(i);
- IF (section.label # NIL) THEN
- IF section.label^= "author" THEN
- par := description.AppendNew(ParagraphType.Heading);
- par.SetLevel(4);
- par.text.WriteString("Author");
- par.text.WriteText(section.title);
- document.sections.RemoveByIndex(i);
- END;
- END;
- END;
- END ConvertSpecialSections;
- *)
- PROCEDURE ParseComments(document : DocumentationTree.Document; c,sentinel: SyntaxTree.Comment; x: ANY);
- VAR string: DocumentationTree.String; stringReader: Streams.StringReader; parser: DocumentationParser.Parser; scanner: DocumentationScanner.Scanner;
- printer: DocumentationPrinter.Printer;
- BEGIN
- IF c # NIL THEN
- string := MergeComments(c,sentinel,x);
- NEW(stringReader, LEN(string));
- stringReader.Set(string^);
- NEW(scanner, stringReader,0,NIL);
- NEW(parser, scanner);
- parser.ParseDocument(document);
- (*ConvertSpecialSections(document);*)
- END;
- END ParseComments;
- (* sentinel used for stopping merging at closing comment of a module if the opening comment comes directly before it.*)
- PROCEDURE MergeComments(c,sentinel: SyntaxTree.Comment; x: ANY): DocumentationTree.String;
- VAR i,len: LONGINT; tmp: SyntaxTree.Comment; string: DocumentationTree.String;
- BEGIN
- len := 0; tmp := c;
- WHILE (tmp # sentinel) & (tmp.item = x) DO
- IF tmp.source[0] = "*" THEN
- i := 1;
- WHILE (i<LEN(tmp.source^)) & (tmp.source[i] # 0X) DO
- INC(i); INC(len);
- END;
- END;
- INC(len,2);
- tmp := tmp.nextComment;
- END;
- NEW(string, len+1);
- len := 0; tmp := c;
- WHILE (tmp # sentinel) & (tmp.item = x) DO
- IF tmp.source[0] = "*" THEN
- i := 1;
- WHILE (i<LEN(tmp.source^)) & (tmp.source[i] # 0X) DO
- string[len] := tmp.source[i];
- INC(i); INC(len);
- END;
- IF (len > 0) & (string[len-1] = "*") THEN DEC(len) END; (* remove last "*" from comment *)
- END;
- string[len] := Scanner.CR;
- INC(len);
- string[len] := Scanner.CR;
- INC(len);
- tmp := tmp.nextComment;
- END;
- string[len] := 0X;
- RETURN string
- END MergeComments;
- PROCEDURE KeepSections(in: DocumentationTree.Document);
- VAR i , j: LONGINT; insert, check: DocumentationTree.Section; done: BOOLEAN; paragraph: DocumentationTree.Paragraph; section: DocumentationTree.Section;
- BEGIN
- FOR i := 0 TO in.sections.Length()-1 DO
- section := in.sections.GetSection(i);
- IF section.title.Length() # 0 THEN
- paragraph := in.description.AppendNew(ParagraphType.Heading);
- paragraph.SetLevel(section.level);
- paragraph.text.WriteText(section.title);
- MergeParagraphs(in.description, section.contents);
- END;
- END;
- END KeepSections;
- PROCEDURE MergeDocument(in: DocumentationTree.Document; descriptionSection: DocumentationTree.Paragraphs; this: DocumentationTree.Document);
- VAR i , j: LONGINT; insert, check: DocumentationTree.Section; done: BOOLEAN; paragraph: DocumentationTree.Paragraph; section: DocumentationTree.Section;
- BEGIN
- ASSERT(in # NIL);
- IF descriptionSection = NIL THEN descriptionSection := in.description END;
- IF this # NIL THEN
- FOR i := 0 TO this.description.Length()-1 DO
- descriptionSection.Add(this.description.GetParagraph(i));
- END;
- MergeSections(in.sections, this.sections);
- (*
- FOR i := 0 TO this.sections.Length()-1 DO
- section := this.sections.GetSection(i);
- paragraph := this.description.AppendNew(ParagraphType.Heading);
- paragraph.SetLevel(2);
- paragraph.text.WriteText(section.title);
- MergeParagraphs(this.description, section.contents);
- END;
- *)
- END
- END MergeDocument;
- PROCEDURE MergeParagraphs(in, this: DocumentationTree.Paragraphs);
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO this.Length()-1 DO
- in.AddParagraph(this.GetParagraph(i));
- END;
- END MergeParagraphs;
- PROCEDURE MergeSections(in, this: DocumentationTree.Sections);
- VAR j,i,k,l: LONGINT; insert, check: DocumentationTree.Section; done: BOOLEAN; par, paragraph,checkPar: DocumentationTree.Paragraph; section: DocumentationTree.Section;
- BEGIN
- i := 0;
- WHILE i < this.Length() DO
- insert := this.GetSection(i);
- done := FALSE;
- IF insert.label # NIL THEN
- j := 0;
- WHILE (j < in.Length()) (*& ~done*) DO
- check := in.GetSection(j);
- IF (check.label # NIL) & (check.label^ = insert.label^) THEN
- (* first merge all paragraphs *)
- MergeParagraphs(check.contents, insert.contents);
- done := TRUE;
- ELSE
- k := 0;
- WHILE k < check.contents.Length() DO
- checkPar := check.contents.GetParagraph(k);
- IF (checkPar.type = ParagraphType.Heading) & (checkPar.label # NIL) & (checkPar.label^ = insert.label^) THEN
- done := TRUE;
- REPEAT
- INC(k);
- IF k < check.contents.Length() THEN
- par := check.contents.GetParagraph(k);
- END;
- UNTIL (k = check.contents.Length()) OR (par.type = ParagraphType.Heading) & (par.level >= checkPar.level);
- FOR l := 0 TO insert.contents.Length()-1 DO
- paragraph := insert.contents.GetParagraph(l);
- check.contents.Insert(k,paragraph);
- INC(k);
- END;
- END;
- INC(k);
- END;
- END;
- INC(j);
- END;
- END;
- IF ~done THEN
- in.Add(this.GetSection(i));
- END;
- INC(i);
- END;
- END MergeSections;
- PROCEDURE MergeSectionDocument(section: DocumentationTree.Section; document: DocumentationTree.Document);
- VAR paragraphs: DocumentationTree.Paragraphs; i,j: LONGINT; paragraph: DocumentationTree.Paragraph; first: BOOLEAN; firstSection: DocumentationTree.Section;
- BEGIN
- NEW(paragraphs, document.description.Length() + section.contents.Length());
- FOR i := 0 TO document.description.Length()-1 DO
- paragraphs.Add(document.description.GetParagraph(i));
- END;
- FOR i := 0 TO section.contents.Length()-1 DO
- paragraphs.Add(section.contents.GetParagraph(i));
- END;
- section.SetContents(paragraphs);
- FOR i := 0 TO document.sections.Length()-1 DO
- section := document.sections.GetSection(i);
- IF (section.label # NIL) THEN
- first := TRUE;
- FOR j := 0 TO i-1 DO
- firstSection := document.sections.GetSection(j);
- IF (firstSection.label # NIL) & (firstSection.label^ = section.label^) THEN
- first := FALSE;
- END;
- END;
- IF first THEN
- paragraph := paragraphs.AppendNew(ParagraphType.Heading);
- paragraph.SetLevel(2);
- paragraph.text.WriteString(section.label^);
- paragraph.text.WriteText(section.title);
- END;
- MergeParagraphs(paragraphs, section.contents);
- END;
- END;
- END MergeSectionDocument;
- PROCEDURE Get*(): Backend.Backend;
- VAR documentationBackend: DocumentationBackend;
- BEGIN
- NEW(documentationBackend); RETURN documentationBackend;
- END Get;
- END FoxDocumentationBackend.
- ~~
- (**
- = Documentation Backend Description.
- This closing comment can be used to describe a whole application.
- It may contain sections like this:
- @ Section1
- * bullet1
- ** bullet2
- *boldface* (and in same line)
- *erroneous boldface
- # bullet3
- ## bullet4
- ## bullet5
- # bullet 6
- @ Section2
- The following is a bulleted list
- \* Bullet1
- \* Bullet2
- This is a normal text with *
- There may be references like this: [[Get|FoxDocumentationBackend.Get]]
- *)
- System.Free FoxDocumentationHtml FoxDocumentationBackend FoxDocumentationParser FoxDocumentationPrinter FoxDocumentationTree FoxDocumentationScanner ~
- Compiler.Compile -d=*.html -i oc/FoxDocumentationBackend.Mod ~
|