PERCEPS The Perl C++ Surveyor version 3.5.0 A C++ Documentation generator Written in Perl Copyright (C) 1999 Mark Peskin Now maintained by Tom Bryan tbryan@python.net PERCEPS is a Perl script designed to parse C/C++ header & source files and automatically generate documentation in a variety of formats based on the class definitions, declarations, and comment information found in those files. This allows you to comment your code and generate useful documentation at the same time with no extra effort. PERCEPS can be useful both as a documentation tool and a simple but effective collaboration tool for both C and C++ projects. Unlike some other documentation generation systems, PERCEPS does not produce a fixed output format. Instead it uses "template" files, plugin filters, and user-defined variables that can be freely modified to produce an almost unlimited variety of output. The example template files included with the distribution produce html pages, but Tex, RTF, man page, plain text or other formats are also possible. Please send comments, questions, or bug reports to: perceps@python.net PERCEPS home page: http://starship.python.net/crew/tbryan/PERCEPS/index.html If you develop interesting new sets of template files and/or plugins for PERCEPS, particularly for new output formats, you are strongly encouraged to share them with the PERCEPS user community. Please contact me (see above) if you would consider allowing your templates to be distributed with PERCEPS. Your input is appreciated. Note: In the following documentation, NAME (all-caps) will be used to refer to a user-defined variable name. USING PERCEPS I) Invoking PERCEPS PERCEPS is invoked from the command line as follows: perceps [-abefrhmncu] [-s suffixes] [-d odir] [-t tdir | -o tdir] [-i idir] [(files|directories)...] Options: -a : Autolink text. This causes PERCEPS to scan all comments, argument lists, etc. for references to documented classes. All such references are automatically linked to the html file ClassName.html. For use with html output only. Autolinking is VERY process intensive for large projects. Avoid it if you're in a hurry. -b : Comment placement. By default PERCEPS assumes that comments referring to a class member follow the associated member. The b-switch causes this assumption to be reversed, so comments coming before a class member refer to that member. -c : Causes standard c-style comments to be included in documentation, unless they are embedded in C++ style comments, in which case they are still ignored. -e : Document all. Forces PERCEPS to attempt to document ALL non-class items regardless of whether they are commented. -f : Find all. Causes all directories specified on the command line to be searched RECURSIVELY for input files matching the suffix list. -h : When set, causes header file comments to be treated as html instead of plaintext. If non-html template files are used, HTML tags will automatically be stripped. -m : Merge function documentation. Causes documentation found with member function definitions to be merged with the documetation for the associated member declaration. When set, member function definitions will not be documented separately. -n : Selective class documentation. Normally PERCEPS documents every class in a project. The -n switch will cause only classes preceeded by comment info to be documented. -q : Quiet mode, supresses diagnostic output -r : Force re-build. Force all output files to be re-generated even if the associated header and template files haven't been modified since the last build. -u : Normally, comments that come before a class definition are only included in the class description if the follow at least one "short description" line (i.e. //:). The -u switch overrides this, causing ALL comments that follow the previous declaration/definition to be included. -s suffixes : A comma delimited list of file suffixes to match when searching directories for input. Wildcards (*,?) are permissible. If -s is not specified, a default suffix list is used (.h,.c,.C,.cpp). -d odir : Directory in which to place output files Defaults to the current working directory. -t tdir : Directory to scan for template files. Defaults to the output directory. -o tdir : Same as -t but uses the contents of the PERCEPS environment variable as a base path -i idir : An additional path to insert before the include file name when the include file is referenced in documentation. (files|directories)... A list of C or C++ files to parse. Directories are searched for all files matching the suffix list. Defaults to the current working directory. NOTE: UNIX users. For UNIX systems that support the #! construct in scripts, you may need to change the first line of the PERCEPS source to point to the location of your perl installation for the most convenient invocation. WARNING: PERCEPS keeps track of build times with a ".perceps" file in the output directory. Deleting this file will force a re-build, and modifying it may prevent PERCEPS from recognizing updates to your header files. If you accidentally modify this file, either delete it or invoke PERCEPS with the -r command line option. II) Directory Searches: PERCEPS will now accept directories as command line arguments. If a directory is specified, it will be searched for all files matching a suffix list. Allowable suffixes can be specified on the command line with the -s switch, or the default suffix list can be used. The default suffix list can easily be changed by editing line 7 of the PERCEPS source. If the -f command line switch is specified, directories will be searched recursively. The "subdir" global variable will be set to the directory where each item is found. This global can then be used to build documentation that respects the folder hierarchy of the code distribution. PERCEPS will search each directory for a ".perceps_conf" file, which can be used to specify per-directory options. Currently, the .perceps_conf file may contain 3 different statement types: suffixes suffix-list Sets the suffix list for the directory and all subdirectories to "suffix-list," which is a comma-delimited list of allowable suffixes for documentable files. (+/-)recursive Turns recursive subdirectory searching (on/off) global NAME = value Sets the default value of the global variable "NAME" to "value" for all files in the directory and its subdirectories. This default value can be overridden using global variable statements within documented files. III) Commenting Your Code: PERCEPS extracts information about your code from source or header files. Items that are recognized and documented by PERCEPS include classes, structs, unions, functions, global variables, typedef statements, and macros. Comment information placed in these files in the proper format can be extracted by PERCEPS for use in documentation. The comment formatting rules are as follows: 1) By default only C++ style comments (//) are examined and all text placed in C-style comments (/* */) will be ignored. This allows you to create "private" comments that will not appear in documentation. The "-c" command line switch overrides this behavior, forcing the inclusion of C-style comments unless they are nested within a C++ comment. 2) In general, comments that appear before an item (where item is a class, function, global, typedef, or macro) refer to that item. Detail description comments and custom comments placed before an item must be preceded by at least one short description comment (see below) unless the "-u" command line switch is enabled. This is to prevent stray comments in the header files from polluting the descriptive comments. Within classes, structs, or unions, by default, comments must follow the member to which they refer while comments that appear before any members refer to the class as a whole. This behavior can be overridden using the "-b"command line switch, which causes comments within classes to refer to the following element. However, in this case all comments referring to the class as a whole must come before the opening brace of the class definition. 3) By default, non-class items are not documented unless they are commented. This means all non-class items (functions, globals, typedefs, macros) that you wish to document should be preceded by a short description comment (or any comment, if the -u option is specified). This selective behavior can be overridden by invoking PERCEPS with the -e option, which will cause ALL non-class items to be documented regardless of whether they are commented. 4) Comments come in four varieties: a) Short descriptions: Short descriptions begin with "//:". Text in short description comments is concatenated to form a brief one line description of the class or member. b) Detail descriptions: Any C++ comments inside a class definition (or following a short description comment that proceeds the class definition) that do not begin with "//:" or "//!" are concatenated to form a detailed description of the class or member. c) User-defined Comment Types: In addition to short and detailed descriptions, you may define your own custom comment classes. These custom comments can be treated differently in template files and/or passed to a special set of plugin filters, allowing extremely flexible output control. The format for user-defined comments is "//!NAME:", where NAME is a alphanumeric user-defined comment name. Custom comment names should be unique, and you should not use the same name for custom comments and global variables. Also, avoid using any of the reserved names listed below, as they are already used internally by PERCEPS. d) User-defined Global Variables: Global variable definitions begin with "//! ". They must occur OUTSIDE of any class declarations. Any text in a global variable definition is searched for special global variable/value pairs of the form : NAME=value These global variables apply to any items found in the header file following the comment in which they are declared. Here is an example of a global comment line: //! author="John Doe" lib=libjdoe.a As with user-defined comments, global variable names should be unique and reserved names (see below) should not be used. There are two predefined global variables. "hfile" contains the name of the header file in which the current item is defined. The markers that are used to distinguish various comment types my be modified by editing the appropriate variables near the beginning of the PERCEPS source, allowing customization of commenting style. See the source code for more information. 5) User-defined comments versus global variables: At this point, you may be wondering why there is a distinction between user-defined comments and global variable, which are also user-defined, and how you should use them. Here is a brief comparison of the two elements: a) User-defined comments only apply to the adjacent item. Global variables apply to all items that follow their definition in a header file, and never apply to class members. b) User-defined comments can be piped to plugin filters, while global variables cannot (except by using the {filter}.. {endfilter construct in the template file... see below). c) Global variables can be looped over using {foreach} statements in template files. User-defined comments cannot be used this way. IV) Creating template files: PERCEPS template files are simply text files marked up with special tags (contained in braces {} by default, see below) used to instruct PERCEPS where to put documentation information. Most of these tags are simply replaced with the appropriate data (item names, member names, arguments, etc.). Several control-flow tags allow blocks of text to be looped over or created conditionally. 1) Naming Template files: PERCEPS expects specific naming conventions for template files. PERCEPS will treat any file in the template directory ending in ".tmpl" as a template file and use it to generate output. In general, output files will have the same name as the template files from which they are generated minus the ".tmpl" extension. Template files with the string "CLASS" (all caps) in the name are treated specially. PERCEPS will generate an output file for EVERY class from such template files, substituting the name of the class for "CLASS." Similarly, template files with the string "@GLOBAL@", where GLOBAL can be any global variable, cause PERCEPS to generate an output file for each value of the specified global. The corresponding global variable value will be substituted for "@GLOBAL@" in the output file name. For the purposes of filename substitution, spaces and file separator characters in the file name will be replaced by underscores ("_"). IMPORTANT: The html autolink feature assumes the existence of a html file ClassName.html for each class ClassName. Thus users generating html output who wish to use the autolink feature should always have a template file named "CLASS.html.tmpl" to generate such files. 2) Template file tags: Template file tags are indicated by the surrounding braces. Tags are either substitutional, in which case they are replaced by specific information, or control flow. NOTE: In the following documentation, optional parameters are surrounded by brackets ("[]"). PERCEPS Template Tags a) Substitutional Tags: { name [@]} Either the current item name, member name, or global variable value depending on context (i.e. the enclosing foreach loop). If the @ modifier is specified and the name refers to a global, underscore substitution will be performed as with template file names containing "@GLOBAL@" (see above). { class } The current class name { classname } The current class name (same as {class}) { classlinked } The current class name with an html link to the page describing a container class, if any. Useful for nested classes and union members. { mname } The current member name { global } The current global variable value { args } Current member arguments (if its a function), or enumeration members (if its an enumeration) { throwclass } If the function or member throws an exception, the exception class name. { throwargs } If the function or member throws an exception, the exception argument list. { member } The current member including any argument list { memberef } A html-clean, unique member label for use with html anchors. { defclass } The class in which the member is defined. { type } The type of the current member { brief } Short description for this member (see above) { detail } detailed description for this member (see above) { templ } Template data for the current class (if template) { parents } A comma separated list of the classes parents { rb } Right bracket (}), or delimeter { lb } Left bracket ({), or delimeter { br } Linebreak. Works even inside {nobreak} blocks (see below) { n } Same as { br } { buildtime } Time the current perceps run was started. { modtime } Modification time of the header file containing definition of the current class. { NAME [@]} User defined-comment or global variable value for the current class or member. If the @ modifier is specified underscore substitution will be performed as with template file names containing "@GLOBAL@" (see above). i) Word Wrap The output of {brief}, {detail}, and user-defined comment ({ NAME }) tags can optionally be word-wrapped by adding a few addional parameters. The format for word wrapping is (taking the {detail} tag as an example): {detail wrap wraplen [nlchar]} where wraplen is the line length (maximum number of characters on a line) and nlchar is an optional string to insert before the newlines while wrapping (it is not counted as part of the line length). For example, the following tag will pring detail comment information, wrapping lines at 50 characters and inserting a
before each newline for html output: {detail wrap 50
} b) Control Flow Tags: i) {foreach argument [all] [sort [sortfunc]]} looptext {next} A for next loop. looptext (including any tags contained therein) is evaluated for every member of the set specified by the argument parameter. Loops can be nested. Recognized values for argument are: item Loops over all documented items class Loops over all classes parent Loops over the parents of the current class child Loops over the children of the current class member Loops over all members of the current class public Loops over the public members of the current class protected Loops over the protected members of the current class private Loops over the private members of the current class friend Loops over friends of the current class union Loops over all non-member unions. func Loops over all non-member functions. global Loops over all non-member variables. typedef Loops over all typedef statements. macro Loops over all macro definitions. NAME Loops over the values of a global variable INCLUDING null. If the "all" keyword is specified for loops over member, public, protected, private, or friend, ALL members of the specified type will be listed including inherited members. Inheritance syntax is respected. If the "all" keyword is specified for loops over parent or child, then every parent or child, across multiple levels of inheritance, will be listed. If the "all" keyword is specified for loops over global variables, PERCEPS will loop over ALL values of the global variable in question, INCLUDING null. This allows listing of classes for which a given global variable is not defined. The "all" keyword is ignored for other types of loops. If the "sort" keyword is specified, the loop items are sorted. If no sortfunc is specified, a default alphabetical sort is performed. For custom sorts, "sortfunc" can be specified as either: 1) a quoted block of perl statements comprising the sort function, or 2) a file (in the template directory) containing perl statements comprising the sort function. The rules for creating sort functions are the same as with the perl "sort" command. The sort function should compare the variables $a and $b and return either -1,0,or 1 to establish their sort order. As an example, the following statement will sort classes in reverse alphabetical order: {foreach class sort "$b cmp $a;"} ...... {next} Due to limitations in the PERCEPS template file parser, quoted blocks cannot contain subexpressions in braces. ii) {if [!]argument} iftext {endif} An if-then statement. iftext (including any tags contained therein) is evaluated if the parameter specified by argument exists, or else iftext is skipped. If-then blocks can be nested. Recognized values for argument are: class True if the current item is a class struct True if the current item is a structure func True if the current item or member is a function global True if the current item is a global typdef True if the current item is a typdef macro True if the current item is a macro union True if the current item is a union first True if the current item is the first item in the enclosing foreach loop. last True if the current item is the last item in the enclosing foreach loop. mid True if the current item is neither the first or last item in the enclosing foreach loop. templ True if the current class is a template lib True if the lib global variable is specified author True if the author global variable is specified parents True if the current class has parents type True if the current member has a type enum True if the current item or member is an enumeration args True if the current member or function has arguments throws True if the current member or function throws exceptions throwclass True if the current member or function throws an exception class throwargs True if the current member or function has exception arguments const True if the current member function is const inherited True if the current member was inherited from a parent class. nested True if the current member is a nested class, structure, or union. brief True if the current item has a brief description detail True if the current item has a detailed description children True if the current class has children public True if the current class has public members protected True if the current class has protected members private True if the current class has private members friend True if the current class has friends anypublic True if the current class has public members, including inherited members. anyprotected True if the current class has protected members, including inherited members. anyprivate True if the current class has private members, including inherited members. anyfriend True if the current class has friends, including inherited friends. hasinlines True if the current class has inline code pure True if the current member is a pure virtual function. abstract True if the current class has pure virtual functions (is abstract). NAME True if the user-defined comment type or global variable "NAME" is defined (non-null) for the current class, member, or global-variable loop iteration. name /rxp/ True if the current item (matched by the {name} tag) matches the perl regular expression "rxp". Due to limitations in the PERCEPS template file parser, rxp cannot contain braces. parent /rxp/ True if any parent of the current class, crossing multiple inheritance levels, matches the perl regular expression "rxp". child /rxp/ True if any child of the current class, crossing multiple inheritance levels, matches the perl regular expression "rxp". Any argument can be negated by placing a "!" in front of it. The {if class}, {if struct}, {if union}, and {if nested} tags, when applied to class members, switch the context of the {if} block to the nested class, structure, or union. Thus, for example, the following code will list the members of nested classes, structs, and unions inside the documentation for the container class: {foreach member} .... {if nested} {foreach member}.....{next} {endif} .... {next} iii) {else} elsetext {endelse} An else statement. elsetext (including any tags contained therein) is evaluated if the previous if-then statement was false. If there was no previous if-then statement then elsetext will always be ignored. The else statement does NOT need to occur immediately after its corresponding if-then statement (you may place other text and tags in between). c) Other Tags: { autolink ARGS } Turns on autolinking if not already on for all following text. Any text in ARGS is passed to the tag in autolinks. This allows window targeting for autolinks. For example: { autolink TARGET="_top" } { !autolink } Turns off autolinking. Overrides the -a command line switch. { keephtml } Turns on html commenting. All comment text after this switch will be treated as html. Overrides the -h command line switch. { !keephtml } Turns off html commenting. All comment text after this switch will be treated as plaintext. Overrides the -h command line switch. { applet ARGS } Inserts the classgraph Java Applet, see below. {filter FILENAME [kt]}....{endfilter} Passes text in the enclosed block to the plugin filter specified by filename after processing. The kt option must be specified in order to process any tags inserted by the filter. Non-absolute pathnames are taken relative to the template directory. See plugin filters, below. {include FILENAME} Inserts template code from the specified file. Non-absolute pathnames are taken relative to the template directory. {nobreak}....{endnobreak} Removes linebreaks from the enclosed text. Linebreaks specified by the {n} tag are still respected. d) File Generation Blocks: PERCEPS provides a method for output files to be generated based on specifications within template files, giving the user precise control over fiel naming and which files are generated using which templates for which items. This is done using a file generation block: {genfile} NAMECODE {|} GENCODE {endgenfile} The block is divided into two sections by the separator tag ("{|}"). The first section, NAMECODE, is parsed to determine the name for the output file. If it parses to "stdout", output will be printed to the screen. The second section, GENCODE, contains template text to parse to create the output. The following example will create output files only for classes whose names contain the string "Obj" using template code in the file "Objtmpl": {foreach class} {if name /Obj/} {genfile}{name}_output.html{|}{include Objtmpl}{endgenfile} {endif} {next} Here is another example that prints a listing of all class members to the screen: {foreach class} ... {genfile}stdout{|}Members of class {name}:\n{endgenfile} {foreach member} ... {genfile}stdout{|}\t{member}\n{endgenfile} {next} {next} This ability to selectively print information to the screen can be particularly useful in conjunction with the -q option, which turns off other screen output, allowing PERCEPS output to be piped to other programs in a UNIX environment. 3) Tag format options: By default, perceps reserves braces ("{" and "}") as tag delimiters. This can be inconvenient for some output formats, notably LaTex and RTF, that also use braces as special characters. For added convenience when working with such formats, PERCEPS allows the tag delimeters to be specified by the user. To change the tag delimiters, add the following line to your template files (which will be ignored in the output): #ptags open close where open and close are the new opening and closing delimiters, respectively. Each delimeter must be a single character, and two different delimeters must be supplied. The new tag delimeters will be applied on any lines following the #ptags statement, and a single template file can contain multiple #ptags statements, allowing different tag delimeters to be mixed in the same template file. For example, the follwing line will change the tag delimeters to square brackets: #ptags [ ] When non-standard delimeters are being used, the {lb} and {rb} tags will produce the delimeters in output. 4) Continuation Lines: Template file lines ending with a backslash ("\") are continued to the next line. If, for some reason, you need to end a line with a backslash, you may do so by adding an additional backslash ("\\"). If you are confused about how to make template files and use tags, which would be understandable at this point, take a look at the example files included in this distribution. The example includes a set of templates to create html pages and uses most of the tags described above. V) Using the ClassGraph Applet in HTML documentation: PERCEPS comes with a Java Applet to display and navigate the C++ class class structure. To use this applet you must include the { applet } tag in your template files. Unlike other template tags, the { applet } tag takes a variable number of arguments that allow control of the applet's appearance. The form for this tag is: { applet [param=value [param=value [...] ] ] } Recognized parameters are: height Applet height width Applet width target Window target for applet links background Background color textcolor Text color maintextcolor Text color for emphasis linecolor Line color textincolor Text color for links with input focus textdowncolor Text color for links when button is pressed Colors are expressed as a 6-digit hexadecimal value (no leading #). Any unrecognized parameters will be passed to the applet via html tags, allowing you to expand the capabilities of the ClassGraph applet without modifying PERCEPS. The Java class files in the classes directory must be copied to the directory containing the generated html pages for the applet to function. IMPORTANT: The html ClassGraph applet assumes the existence of a html file ClassName.html for each class ClassName. Thus users generating html output who wish to use the ClassGraph applet should always have a template file named "CLASS.html.tmpl" to generate such files. VI) Plugin Filters: As of version 2, PERCEPS accepts plugin filters, written in Perl, that give "Power Users" precise control over output. 1) Writing Plugins: Writing plugins is simple. Filters are simply blocks of perl code that are exec'd at run time. All filters must contain a subroutine, "filter," that accepts a single argument (the text to be filtered), and returns the filtered text. Thus, the format for a plugin file is as follows: sub filter { local($str)=@_; ... ... ... return $str; } WARNING: Filters have access to the PERCEPS global variable space. Thus, to be safe, all variables used by the filter should be declared in local blocks to avoid polluting the global name space. If absolutely necessary, filters may declare global variables (This could be useful for preserving information across calls to the filter function), BUT YOU DO SO AT YOUR OWN RISK. Real masochists can even write filters that manipulate the global data used by PERCEPS, but this is not recommended, and I do not plan to provide a detailed description of the perceps internal globals and their uses. 2) Invoking Plugin Filters: Plugin Filters can be invoked in two ways: a) Automatically: PERCEPS automatically searches the template directory for filter files with specific names. If found, specific data items are passed to these filters (before autolinking!). PERCEPS searches for the following filter files automatically: Filename Item Filtered input.flt All input files BEFORE parsing/processing comment.flt All comments or globals brief.flt All short description comments brief_c.flt All short descriptions that refer to a class brief_m.flt All short descriptions that refer to a member detail.flt All detail description comments detail_c.flt All detail descriptions that refer to a class detail_m.flt All detail descriptions that refer to a member NAME.flt All user defined comments or globals of the NAME type NAME_c.flt All NAME descriptions that refer to a class NAME_m.flt All NAME descriptions that refer to a member args.flt Function Argument Lists time.flt The time expressions returned by the {buildtime} and {modtime} tags. IF more than one filter applies to a given data element, the most specific filters will be called first. Thus, if brief_c.flt, brief.flt, and comment.flt all exist. They will be called in that order on short descriptions that refer to a class. b) Manually: Any filter file may be invoked on a block of text within a template file by using the {filter FILENAME}...{endfilter} construct. In this case, the filter is called AFTER the enclosed template text has been processed, so autolinking will already have taken place. Plugin filters can also be invoked from within other plugin filters by calling &FILTER($str,$filename), which returns the filtered $str. 3) Including PERCEPS template tags in filter output: By default, the output of filters that are invoked automatically will NOT be processed as if it contains PERCEPS template tags, and such tags will be ignored. If you would like to create a filter that adds template tags to the output, you can do so by setting the global switch $keeptags to true in your filter code. Note that some items may be passed through several automatically invoked filters, and once the $keeptags switch is set, it will remain set until the filtered text is printed. Text contained in filter blocks invoked manually via template files is filtered after being processed for tags. Any tags added by the filter will be processed only if the "kt" option is specified in the filter invocation. See above. PERCEPS allows the template creator to specify alternate sets of template tag delimeters. If you want to include tags in your filter output but you cannot be sure what delimeters are being used, you can be safe by using the variables $TO and $TC to stand for the opening and closing tag delimeters, respectively. Similarly, $TO_sub and $TC_sub contain the text which is standing in for the delimeters in output . You may call the function &SAFECHAR($str) which makes sure any instances of $TO and $TC in $str are replaced by $TO_sub and $TC_sub, then returns the "safe" (tag-free) string. Note that if filters add HTML tags to the output stream the -h command line option should be enabled. Two example filters, time.flt, which takes the default ctime time format and extracts the month and day, and param.flt, which turns information in the "param" custom comment into an html table, have been included with the example templates. VII) Known Problems: The ClassGraph java applet accepts a target parameter which is passed to the context.showDocument method to set a browser window target for links. Unfortunately, not all browser/java VM combinations handle this target parameter properly, causing creation of an unwanted new window. In particular, I have had this problem with Internet Explorer for MacIntosh and beta versions of Communicator for all platforms. Some versions of Netscape Communicator seem to have trouble parsing the "<" tag (to display "<"). When this problem occurs it can mangle the display of templates in html documentation (The html source generated by PERCEPS is fine... the browser just isn't displaying it properly). Fix: 1) Use a different browser 2) Hope that browser/JVM developers get their act together. Although I have endeavored to make PERCEPS as syntax-transparent as possible, I cannot guarantee that PERCEPS will properly parse header files with bizarre syntax (I know, I know, nobody thinks THEIR syntax is bizarre).