123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845 |
- (**
- 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, Runtime, Strings, SymbolFileFormat := FoxBinarySymbolFile, 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);
- PROCEDURE InBounds(val: HUGEINT; bits: LONGINT): BOOLEAN;
- VAR m: HUGEINT;
- BEGIN
- m := Runtime.AslH(1,bits-1);
- RETURN (val < m) & (-val <= m)
- END InBounds;
- BEGIN
- (*! use subtype for representation form ? *)
- IF x.hvalue = MIN(HUGEINT) THEN
- (* special case: display 8000000000000000H without leading minus sign
- to avoid double minus sign for unary expression -8000000000000000H
- *)
- w.Char("0"); w.Hex(x.hvalue,-16); w.Char("H");
- ELSIF InBounds(x.hvalue,32) THEN
- Int(SHORT(x.hvalue));
- ELSE
- Hex(w,x.hvalue); w.Char("H");
- END;
- 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
- diagnostics.Error("",Diagnostics.Invalid, Diagnostics.Invalid,"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]]
- *)
- SystemTools.Free FoxDocumentationHtml FoxDocumentationBackend FoxDocumentationParser FoxDocumentationPrinter FoxDocumentationTree FoxDocumentationScanner ~
- Compiler.Compile -d=*.html -i oc/FoxDocumentationBackend.Mod ~
|