[C2HELP]
* NEW: Scripts to generate Gambas documentation files from C/C++ sources git-svn-id: svn://localhost/gambas/trunk@6712 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
parent
a213747294
commit
ea6578d19b
7 changed files with 309 additions and 0 deletions
113
c2help/README
Normal file
113
c2help/README
Normal file
|
@ -0,0 +1,113 @@
|
|||
About c2help
|
||||
------------
|
||||
|
||||
c2help is used to extract Gambas documentation from C/C++ source files and
|
||||
create .help files for a component from them.
|
||||
|
||||
Project compass
|
||||
---------------
|
||||
|
||||
./extract.awk -- Extract help comments
|
||||
./xlate.sh -- Translate C/C++ function names to Gambas symbol names
|
||||
./prefix.awk -- Prefix symbol names with the classes they belong to
|
||||
./mkhelp.gbs3 -- Create a .help file from the (properly formatted) input
|
||||
|
||||
./c2help.sh -- Executes the above programs in the correct order to create
|
||||
the .help in a number of C/C++ sources.
|
||||
|
||||
... and why?
|
||||
------------
|
||||
|
||||
Components written in Gambas can already be documented in-code. This docu-
|
||||
mentation is then stored inside their .info files. With a similar result
|
||||
provided by c2help for C/C++ components, we can document all[*] Gambas in
|
||||
its source files (at least my components will be) which makes it, IMHO,
|
||||
easier to keep the documentation up-to-date. Also the help could be
|
||||
displayed locally by the IDE or remotely once these .help files are imported
|
||||
to the gambaswiki.org site.
|
||||
|
||||
Also, documentation can be bound to a specific source code version, so that
|
||||
you get docs for the version of Gambas you are running, not only for the
|
||||
development branch.
|
||||
|
||||
[*] I'm not sure about intrinsic functions, though. Should be feasible,
|
||||
looking at gbx_class_info.c...
|
||||
|
||||
Great! How do I prepare my component?
|
||||
-------------------------------------
|
||||
|
||||
The No 0 rule is to BE CAREFUL! There are quite some rules to remember:
|
||||
|
||||
1. Documentation syntax.
|
||||
|
||||
You may write a Gambas documentation comment like
|
||||
|
||||
/**G
|
||||
* Here goes the documentation.
|
||||
**/
|
||||
BEGIN_METHOD_VOID(ClassName_MethodName)
|
||||
/* ... */
|
||||
END_METHOD
|
||||
|
||||
or alternatively
|
||||
|
||||
/**G Class Symbol
|
||||
* Documenting Class.Symbol
|
||||
**/
|
||||
|
||||
Instead of the **/ at the end, you may also write */. Cool, huh?
|
||||
|
||||
The difference between both notations is that the first must immediately
|
||||
precede a BEGIN_{PROPERTY,METHOD,METHOD_VOID) line that defines the symbol
|
||||
to which the documentation refers. The second syntax documents the indicated
|
||||
symbol -- no matter where the comment is.
|
||||
|
||||
This is intended to document GB_CONSTANTs or GB_PROPERTY_SELFs which don't
|
||||
have a BEGIN_* line. It can neverthelss be used for any other symbol but
|
||||
NEVER intermix both syntaxes on a single symbol.
|
||||
|
||||
The ClassName_MethodName part I call "(implementation) function name". The
|
||||
particular format shown is not mandatory. The scripts take the function name
|
||||
and look up the corresponding symbol in your GB_DESC[].
|
||||
|
||||
2. Strict regular expressions.
|
||||
|
||||
The regular expressions used to filter these comments are somewhat strict.
|
||||
You have to pass the spaces exactly as indicated in the line where you
|
||||
comment text starts, i.e. <space>*<space>text. Also note that Class and
|
||||
Symbol in the second syntax are case sensitive!
|
||||
|
||||
3. Strict structure.
|
||||
|
||||
Really. The next empty-or-not line after a syntax-1 help block is taken as
|
||||
the symbol definition line. If it's not, you get a wrong symbol name.
|
||||
|
||||
DON'T try to confuse the parsers by not giving information it needs where
|
||||
it expects it.
|
||||
|
||||
4. Synonyms.
|
||||
|
||||
The first match for a function name lookup in a GB_DESC[] is taken as the
|
||||
"primary" implementation of that symbol. That means the help comment will
|
||||
be attched to that symbol. All other symbols which call the same function
|
||||
are considered synonyms and are *automatically* documented with the default
|
||||
sentence: "This is a synonym for <primary-symbol>". DO NOT document them
|
||||
separately using a syntax-2 help block!
|
||||
|
||||
5. Don't reuse method and property implementations (except for synonyms).
|
||||
|
||||
As the implementation function name is searched in the GB_DESC[]s in your
|
||||
source file, you may not put the same function into different classes -- or
|
||||
the parser may get confused.
|
||||
|
||||
Umm... I need an example
|
||||
------------------------
|
||||
|
||||
gb.openssl and gb.data are partially documented that way. Digest.Hash() and
|
||||
Digest._call() in gb.openssl show how to deal with synonyms. There the entry
|
||||
for Hash precedes the entry for _call, thus Hash is the primary symbol and
|
||||
_call a synonym.
|
||||
|
||||
To see a sample .help file (on stdout), you can do at the source tree root:
|
||||
|
||||
$ c2help/c2help.sh gb.openssl
|
1
c2help/TODO
Normal file
1
c2help/TODO
Normal file
|
@ -0,0 +1 @@
|
|||
- Class documentation. Shouldn't be too difficult.
|
27
c2help/c2help.sh
Executable file
27
c2help/c2help.sh
Executable file
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ $# -lt 1 ]
|
||||
then cat >&2 <<EOF
|
||||
|
||||
Usage: $0 SOURCES...
|
||||
|
||||
Extract Gambas help comments from all SOURCES and output a .help file.
|
||||
If SOURCES contains directories, they are searched recursively for .c
|
||||
and .cpp files.
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function doit {
|
||||
for arg in ${@:1}
|
||||
do echo Processing $arg... >&2
|
||||
if [ -d "$arg" ]
|
||||
then doit $(find -H $arg -name \*.c -or -name \*.cpp)
|
||||
else $(dirname $0)/extract.awk <$arg | sed "s/^[ ]*\*/\'/" |
|
||||
$(dirname $0)/xlate.sh $arg | $(dirname $0)/mkhelp.gbs3
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
doit ${@:1}
|
72
c2help/extract.awk
Executable file
72
c2help/extract.awk
Executable file
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/gawk -f
|
||||
|
||||
# Extract comments from C/C++ source files (stdin)
|
||||
|
||||
BEGIN {
|
||||
do_record = 0;
|
||||
not_this = 0;
|
||||
symname = "";
|
||||
FS="";
|
||||
}
|
||||
|
||||
/^[\t ]*\*?\*\/$/ {
|
||||
if (length(symname)) {
|
||||
print "G "symname "\n";
|
||||
do_record = 0;
|
||||
}
|
||||
not_this = 1;
|
||||
}
|
||||
|
||||
/^BEGIN\_.*\(.*/ {
|
||||
if (do_record && length(symname) == 0) {
|
||||
s = gensub(/^BEGIN\_.*\(([^,)]+).*/, "\\1", "");
|
||||
if (length(s) == 0)
|
||||
print "ERROR\n";
|
||||
else
|
||||
print s "\n";
|
||||
do_record = 0;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (do_record && !not_this)
|
||||
print gensub(/^[\t ]*/, " ", "");
|
||||
not_this = 0;
|
||||
}
|
||||
|
||||
# The 'G' flag is important to distinguish intended Gambas documentation
|
||||
# for the wiki (*.help files) and already existing C function commentary.
|
||||
#
|
||||
# The start marker may either be:
|
||||
#
|
||||
# ^/**G$ # Note that this describes an *entire* line
|
||||
#
|
||||
# when it preceeds a symbol definition (BEGIN_*) or alternatively
|
||||
#
|
||||
# /**G Class Symbol$ # Here, only the end of line matters
|
||||
#
|
||||
# if it documents the Gambas symbol "Symbol" in "Class". This is intended
|
||||
# for documentation of symbols that are not to be implemented in something
|
||||
# that begins with BEGIN_*, like GB_CONSTANTs or GB_PROPERTY_SELFs. It can
|
||||
# also be used for any other symbol type but both documentation types should
|
||||
# not be used together on a single symbol.
|
||||
|
||||
/^\/\*\*G$/ {
|
||||
if (do_record)
|
||||
print "ERROR\n";
|
||||
symname = "";
|
||||
do_record = 1;
|
||||
}
|
||||
|
||||
/[\t ]*\/\*\*G .+$/ {
|
||||
if (do_record)
|
||||
print "ERROR\n";
|
||||
symname = gensub(/\/\*\*G (.*)$/, "\\1", "");
|
||||
gsub(/^[\t ]*/, "", symname);
|
||||
do_record = 1;
|
||||
}
|
||||
|
||||
END {
|
||||
if (do_record)
|
||||
print "ERROR\n";
|
||||
}
|
42
c2help/mkhelp.gbs3
Executable file
42
c2help/mkhelp.gbs3
Executable file
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/gbs3
|
||||
|
||||
Private $cHelp As New Collection
|
||||
Private $aCurrent As New String[]
|
||||
|
||||
Public Sub Main()
|
||||
Dim sLine As String
|
||||
Dim cClass As Collection, aHelp, aSyn As String[]
|
||||
Dim iInd As Integer
|
||||
|
||||
For Each sLine in File.In.Lines
|
||||
If Not sLine Then Continue
|
||||
If sLine Begins "'" Then
|
||||
$aCurrent.Add(sLine)
|
||||
Else
|
||||
With Scan(sLine, "* *") ' <Class> <Symbol-and-Synonym-List>
|
||||
.[0] = Trim$(.[0])
|
||||
.[1] = Trim$(.[1])
|
||||
If .Count <> 2 Then
|
||||
Error "Skipping malformed line:";; sLine
|
||||
Continue
|
||||
Endif
|
||||
If Not $cHelp[.[0]] Then $cHelp[.[0]] = New Collection
|
||||
$cHelp[.[0]][.[1]] = $aCurrent
|
||||
$aCurrent = New String[]
|
||||
End With
|
||||
Endif
|
||||
Next
|
||||
|
||||
For Each cClass In $cHelp
|
||||
Print "#"; $cHelp.Key
|
||||
For Each aHelp In cClass
|
||||
aSyn = Split(cClass.Key, " ")
|
||||
Print aSyn[0]
|
||||
If aHelp.Count Then Print aHelp.Join("\n")
|
||||
For iInd = 1 To aSyn.Max
|
||||
Print aSyn[iInd]
|
||||
Print "' A synonym for";; aSyn[0]; "."
|
||||
Next
|
||||
Next
|
||||
Next
|
||||
End
|
16
c2help/prefix.awk
Executable file
16
c2help/prefix.awk
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/gawk -f
|
||||
|
||||
BEGIN {
|
||||
class = "ERROR";
|
||||
}
|
||||
|
||||
/GB_DECLARE/ {
|
||||
class = gensub(/GB_DECLARE\("([^"]+).*/, "\\1", "");
|
||||
gsub(/[\t ]+/, "", class);
|
||||
}
|
||||
|
||||
match($0, "GB_.*" funcname) {
|
||||
printf class " ";
|
||||
# Only print once as there may be synonyms.
|
||||
exit;
|
||||
}
|
38
c2help/xlate.sh
Executable file
38
c2help/xlate.sh
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Translate C/C++ function name to Gambas symbol name
|
||||
|
||||
if [ $# -ne 1 ]
|
||||
then cat >&2 <<EOF
|
||||
|
||||
Usage: $0 CLASSDEF
|
||||
|
||||
Translate C/C++ function names (from stdin) to Gambas symbol
|
||||
names using the class definition in the CLASSDEF file.
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read line
|
||||
do if [ -z "$line" -o "$line" == "NULL" ]
|
||||
then echo $line
|
||||
continue
|
||||
fi
|
||||
if [[ $line == \'* ]]
|
||||
# Quoting is important here to not lose whitespace
|
||||
then echo "$line"
|
||||
continue
|
||||
fi
|
||||
|
||||
# It's the symbol name already (a syntax-2 help block)?
|
||||
if [[ $line =~ ^G[\ ] ]]
|
||||
then echo "$line" | sed 's/^G //'
|
||||
continue
|
||||
fi
|
||||
# Now, we have a C/C++ function name in $line. First search the class.
|
||||
$(dirname $0)/prefix.awk -v funcname=$line <$1
|
||||
# Put all the synonyms behind.
|
||||
egrep "GB_.*$line[,)]" $1 | sed 's/^[\t]*GB_[^(]\+("\([^"]\+\)".*$/\1/' |
|
||||
tr '\n' ' '
|
||||
done
|
Loading…
Reference in a new issue