RE: Extracting calling structure from 4GL program
Posted in 1999
Topics: Stored Procedures & SPL, Connectivity: ESQL/C, 4GL & Embedded SQL, Internationalization & Character Sets
The following script does a pretty good job for me, but I haven't tested it
against a wide range of programming styles. It has two parts: the first
lists files, the functions they contain, and the functions called from them;
the second is what I think you're asking for. Output to the file "outline".
It does not handle library functions (but could be extended to do so, I
think):
#!/bin/ksh
nm=`basename $0`
shelp ()
{
cat <<EOF
Outline functions defined by .4gls -- usage:
$nm [directory] [[-m filename] | [filename [filename . . .]]
If no arguments are given, processes all .4gls in the current directory
If only a directory is given, processes all .4gls in that directory
If the -m flag is used, takes the next filename as a "make" file
and reads the files from that
Output is to the file "outline" in the appropriate directory
EOF
exit
}
parsemake ()
{
awk '/^[a-zA-Z0-9]*[ \\t]*=/ {
On = 1
split ($0, a, "=")
N = split (a[2], b)
for (i = 1; i <= N; i++) {
if (b[i] ~ /\\.4gl$/) { print b[i]; Done = 1 }
else if (b[i] ~ /\\.o$/) {
Q = split (b[i], d, "[)}]")
P = split (d[Q], c, "[.]")
for (j = 1; j < P; j++) printf "%s.", c[j]
printf "4gl\\n"
Done = 1
}
else if (b[i] ~ /\\.4go$/) {
Q = split (b[i], d, "[)}]")
P = split (d[Q], c, "[.]")
for (j = 1; j < P; j++) printf "%s.", c[j]
printf "4gl\\n"
Done = 1
}
}
while (getline > 0) {
if (NF == 0) break
for (i = 1; i <= NF; i++) {
if ($i ~ /\\.4gl$/) { print $i; Done = 1 }
else if ($i ~ /\\.o$/) {
Q = split ($i, d, "[)}]")
P = split (d[Q], c, "[.]")
for (j = 1; j < P; j++) printf "%s.", c[j]
printf "4gl\\n"
Done = 1
}
else if ($i ~ /\\.4go$/) {
Q = split ($i, d, "[)}]")
P = split (d[Q], c, "[.]")
for (j = 1; j < P; j++) printf "%s.", c[j]
printf "4gl\\n"
Done = 1
}
}
}
if (Done == 1) exit
}' $1
}
trap 'rm /tmp/$$.* $$.4gl 2>/dev/null; exit' 0 1 2 15
Mak=
while [ $# -gt 0 ]
do
case $1 in
-m ) Mak=$2; shift;;
-* ) shelp;;
* ) break;;
esac
shift
done
if [ $# -eq 0 ]
then
Dir='.'
else
if [ -d $1 ]
then
Dir=$1
shift
else
Dir='.'
fi
fi
cd $Dir
if [ "$Mak" ]
then
Lst=`parsemake $Mak`
echo $Lst
elif [ $# -eq 0 ]
then
Lst="*.4gl"
else
Lst="$*"
fi
# in case there is just one 4gl, makes grep list the filename
>$$.4gl
# find all function/report declarations
egrep -hi '^[ \\t]*(function|report)[ \\t].*\\(' $Lst |# build a list of search patterns for them
awk '{ split ($2,a,"("); print a[1], "("; print a[1] "(" }' |
sort -u | grep -v '^log_err[ (]' > /tmp/$$.fun
# search for function calls in all the 4gls: separate file names
echo $Lst | xargs fgrep -f /tmp/$$.fun | sed 's/:/ /' >/tmp/$$.outl
# print out function declarations and functions called within them by file
nawk 'BEGIN { L=""; C[" "]; }
{ if ($1 != L) {
for (i in C) if (i != " ") print i
for (i in C) delete C[i]
C[" "]
L = $1; print "\\n\\nFILE: " L
}
if ( $2 ~ /[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]/ ) {
for (i in C) if (i != " ") print i
for (i in C) delete C[i]
C[" "]
$1 = " "; $2 = "FUNCTION"; print ""; print
}
else if ( $2 ~ /[Rr][Ee][Pp][Oo][Rr][Tt]/ ) {
for (i in C) if (i != " ") print i
for (i in C) delete C[i]
C[" "]
$1 = " "; $2 = "REPORT"; print ""; print
}
else { $1 = " "; C[$0] }
}
END { for (i in C) if (i != " ") print i }' /tmp/$$.outl |
grep -v '^[ \\t]*[\\"#]' |
grep -v '^[ \\t]*--' |
sed 's/\\([^ ]\\)(/\\1 (/' |
tee /tmp/$$.out >outline
echo "\\n\\nFunction call hierarchy\\n" >>outline
cat /tmp/$$.fun | tr -d ' (' | sort -u >/tmp/$$.huh
nawk 'function putout (lev, sfun, pfuns, j, n, B, P) {
n = split (Fun[sfun], B, " ")
pn = split (pfuns, P, " ")
for ( j = 1; j <= lev; j++ ) printf "| "
print sfun
for (j = 1; j <= pn; j++) if (P[j] == sfun ) return
lev++
for ( j = 1; j <= n; j++ ) {
if ( B[j] != sfun ) putout(lev,B[j],pfuns " " sfun)
}
}
BEGIN { while ( ( getline s < "'/tmp/$$.huh'" ) == 1 ) SF[s]; LOC[" "] }
/^[ \\t]*$/ { MAIN = 0 }
{ if ( $1 == "FILE:" ) { CF=$2; FUNC = "MAIN";
for ( k in LOC ) delete LOC[k]; LOC[" "]
}
else if ( $1 == "FUNCTION" ) { split ($2,a,"("); FUNC = a[1]
for ( k in LOC ) delete LOC[k]; LOC[" "]
}
else if ( length($0) > 0 ) {
for ( i = 1; i <= NF; i++ ) {
if ( $i in SF ) {
if ( $i in LOC ) { }
else {
Fun[FUNC] = Fun[FUNC] " " $i
LOC[$i]
}
}
}
}
}
END {
putout(0,"MAIN", "")
}' /tmp/$$.out >>outline
> -----Original Message-----
> From: Henk van der Geld [SMTP:H.van.der.Geld@net.hcc.nl]
> Sent: Thursday, December 02, 1999 3:28 PM
> To: informix-list@iiug.org
> Subject: Extracting calling structure from 4GL program
>
> Hi,
>
> Does anyone know of a way to extract the calling structure from a 4GL
> program. If I just have the calling structure, that will give
> programmers not familiar, first insight in a program. I know about a
> tool/script called 4gltree, but I didn't manage to get this running. Any
> suggestion will be appreciated.
>
> Thanx,
> Henk
In article <8291c2$410$1@news.xmission.com>, demusa@hastings-ent.com says... > > The following script does a pretty good job for me, but I haven't tested it > against a wide range of programming styles. It has two parts: the first > lists files, the functions they contain, and the functions called from them; > the second is what I think you're asking for. Output to the file "outline". > It does not handle library functions (but could be extended to do so, I > think): > (...snip...) Thanks. What is nawk? -- Yours, Andrej Falout, http://www.falout.com ICQ 7628616 ++64.21.607517 #----------------------------------------------------------------- globals "std_disclaimer.4gl" Ask yourself just one question: ' Qu' m's se puede hacer y aprender ? - Propellerhead ReBirth RB-338 manual