This tutorial is for character cell LSE and SCA on
the OpenVMS platform. For a tutorial on the
DECwindows interface, please see the DECset Guide to
Source Code Analyzer.
If you do not have DECwindows, you may want to have a hardcopy
of this tutorial to follow it along interactively. The directions
for producing a hardcopy are as follows:
1. Place the contents of SCA_Tutorial in a printable file
by typing the following command on the DCL command line:
$ HELP/OUTPUT=SCA_TUTORIAL.TXT SCA SCA_Topics SCA_Tutorial
2. Print SCA_TUTORIAL.TXT from the DCL command line as follows:
$ PRINT SCA_TUTORIAL.TXT
SCA allows you to browse through a complex software system. In a
large multimodule software system, you may not be familiar with
all of the source code. It may have been written by different
authors in a number of different programming languages. SCA can
help you browse through the source code and give you important
information about the program structure. If you are familiar with
the source code, SCA will help you navigate directly to the source
code you want, and give you valuable cross-reference information.
This tutorial guides you through a sample SCA session to show how
SCA can improve your software development productivity as you work
on an unfamiliar software system.
If you encounter terms that are unfamiliar, see the SCA online
glossary for definitions. SCA's terminology for program structures
is language independent. If you want to see how this terminology
maps onto the programming language that you use most frequently,
see the language tables under the Getting_Started help topic.
This tutorial assumes that you use SCA while in LSE. You can
still follow the tutorial if you are using SCA from the command
line, but you will not be able to use the GOTO DECLARATION, GOTO
SOURCE, EXPAND, or NEXT STEP commands. The way in which results
are displayed also differ slightly between standalone SCA and SCA
used from within LSE.
Invoking SCA
To invoke SCA through LSE, type the following from the DCL command
line:
$ LSEDIT
Typing Commands
Your cursor is now in an LSE buffer.
Press the DO key or COMMAND key (PF1-KP7). This places you in LSE
command mode.
You will see the "LSE command>" prompt at the bottom of your LSE
window. This means that you can now enter an SCA command. During
this tutorial, when you see SCA commands following an LSE command>
prompt, press the DO key before you try to type the command.
Selecting a Library
SCA gets its information from an SCA library, a database of
information about your source code. You will be using the sample
SCA library provided in this tutorial.
To use the sample SCA library, type the following in LSE command
mode:
LSE command> SET LIBRARY SCA$EXAMPLE:
Later in this tutorial, you will learn how to create your own SCA
library using your own source code.
Looking at Modules
Because the components of the system are unfamiliar to you, the
first thing you may want to do is determine which modules comprise
the system loaded into the SCA library. The SHOW MODULE command
gives you a synopsis of the contents of the library.
To get information about the contents of an SCA library, type the
following command at the LSE Command> prompt:
LSE command> SHOW MODULE
For each module, you will see the module name, the language in
which the source code is written, and some other information. A
module is a logical unit of source code, as determined by your
compiler. In FORTRAN, a module may be a PROGRAM or SUBROUTINE. In
C, it may consist of the source code within one file. If you are
interested in how "module" and other SCA concepts map to different
language specific constructs, see the language tables under the
Getting_Started help topic.
Press the Return key when you are finished looking at the list of
modules.
Creating a Query
Suppose you are assigned the task of changing the output format
for this software system. Because you are unfamiliar with the
source code, you do not know where the system produces output.
Using SCA, you can find out by looking for places where the
program uses WRITELN. WRITELN is a built-in Pascal output
function, similar to PUT_LINE in Ada, or PRINTF in C.
To ask SCA to find all the occurrences of the symbol in the system
with the name WRITELN, type the following command:
LSE command> FIND WRITELN
LSE/SCA creates the following display in your buffer:
WRITELN procedure
COPY_FILE\75 call reference
COPY_FILE\84 call reference
The first line tells you about the existence of a symbol whose
name is WRITELN and whose symbol class is procedure. (A procedure
in Pascal is like a subroutine in FORTRAN, or a function in C. See
the language tables under the Getting_Started help topic.
The subsequent indented lines give you information about where
occurrences of the WRITELN symbol were found. For example, the
first occurrence or use of the WRITELN symbol is in the module
COPY_FILE on line 75, and the occurrence class (the way the symbol
was used) is a call reference.
Navigating the Query Display
Once you have a list of occurrences of the symbol, you will want
to look at the source code corresponding to those occurrences.
You will see that the first two lines of the display are
highlighted. This highlighting tells you which symbol and
occurrence are selected. When an occurrence is selected, you can
use the GOTO SOURCE command to see the corresponding source code.
Press CTRL/G or type the GOTO SOURCE command at the LSE command>
prompt. The file COPYFILE.PAS is read into a buffer by LSE, and
your cursor will be positioned on the first occurrence of WRITELN.
You may now be interested in looking at the source code for the
next occurrence.
Press CTRL/F or type the NEXT STEP command at the LSE command>
prompt. (Note that there is a corresponding CTRL/B command for
PREVIOUS STEP.)
You will see that the second occurrence of WRITELN, on line 84, is
highlighted.
Press CTRL/G again to invoke the GOTO SOURCE command.
Going to a Declaration
Your cursor is again positioned on an occurrence of WRITELN.
Looking at the source code, you see the following line:
WRITELN (out_file, SUBSTR (out_line, 1, out_index));
You might be interested in finding out where the first argument,
the variable OUT_FILE, is declared.
Press the arrow keys to position your cursor on the word OUT_FILE
in the source code. If you are using LSE with DECwindows, you can
also point to the word OUT_FILE by pointing and clicking with the
mouse.
Press CTRL/D or type the GOTO DECLARATION/PRIMARY/INDICATED
command at the LSE Command> prompt.
Your cursor will now be placed on the declaration of OUT_FILE.
Using SCA, you can navigate directly to the declaration of any
symbol declared in your system by placing your cursor on the
symbol, and pressing CTRL/D. If you are not positioned on a
symbol, you can also go to the declaration of a symbol by typing
the following command:
LSE COMMAND> GOTO DECLARATION symbol-name
Using Wildcards to Find Occurrences
Because SCA allows wildcard expressions, it can help you navigate
through the source code, even if you are not quite sure of the
name of the symbols of interest.
Suppose you know of a procedure in the system that you might use
in some new code that you are writing. In order to see how this
procedure has been used elsewhere, you want to look at the source
code for calls to the procedure, but you do not remember its name.
You may only remember that it begins with the letters BUILD. Type
the following command:
LSE command> FIND build*
You will now see the following display:
BUILDTABLE.PAS file
BUILD_TABLE\1 PASCAL command reference
BUILD_TABLE procedure
BUILD_TABLE module
SCA also gives you a message in the message buffer as follows:
5 occurrences found (3 symbols, 2 names)
You can see that two names were found: BUILDTABLE.PAS and BUILD_
TABLE. The BUILDTABLE.PAS symbol has the symbol class "file."
Two different BUILD_TABLE symbols were found. One of these is a
procedure; the other is a module.
You may notice that there are no occurrences displayed for either
the BUILD_TABLE procedure or the BUILD_TABLE module. To prevent
the display from being too cluttered, SCA/LSE displays only the
occurrences of the first symbol.
Because you are interested in seeing the occurrences of the BUILD_
TABLE procedure, you must expand the display as follows;
1. Press CTRL/F, or type the NEXT STEP command at the LSE Command>
prompt, to select the BUILD_TABLE procedure symbol.
2. Press CTRL/E, or type the EXPAND command at the LSE command>
prompt, to expand the display.
In the following display, you will see that three occurrences of
the BUILD_TABLE procedure are now visible:
BUILDTABLE.PAS file
BUILD_TABLE\1 PASCAL command reference
BUILD_TABLE procedure
BUILD_TABLE\41 PROCEDURE declaration
TRANSLIT\61 FORWARD or EXTERNAL PROCEDURE declaration
TRANSLIT\171 call reference
BUILD_TABLE module
You could now look at the corresponding source code if you
desired. Note that there is a corresponding CTRL/\ key, or
COLLAPSE command, that you can use to hide expanded occurrences.
Attribute Selection
To avoid finding more occurrences than you want, SCA lets you
select occurrences based on attributes other than just the name
of a symbol. In the previous example, you were looking for a
procedure named BUILD_TABLE. However, the results included a file
and a module, as well as the procedure you wanted.
To get results that include only the BUILD_TABLE procedure with
its corresponding occurrences, type the following query:
LSE command> FIND NAME=BUILD* AND SYMBOL_CLASS=PROCEDURE
Up to this point, you have selected only occurrences based on
the name of the symbol. The name of a symbol is only one of its
attributes. In fact, FIND BUILD_TABLE is an abbreviation for
FIND NAME=BUILD_TABLE, where "NAME=" specifies which particular
attribute we are using to select the occurrences found. FIND
BUILD_TABLE without "NAME=" works for the following reason. If
you don't specify the attribute, SCA assumes you are selecting
occurrences based on a name because this is the most commonly used
attribute.
In this new query, you have specified that you want to see only
symbols whose name is BUILD_TABLE, and whose symbol class is
PROCEDURE. (Note that the symbol class PROCEDURE is synonymous
with the classes FUNCTION, SUBROUTINE, ROUTINE, and PROGRAM.)
Symbol classes indicate the type of symbols. Examples of other
symbol classes that SCA understands are FIELD, CONSTANT, MACRO,
TASK, TYPE, and VARIABLE. For more information and a complete list
of these symbol classes, see the information under the SYMBOL_
CLASS help topic.
In the previous example, you used two selection clauses to
restrict the items found, NAME=BUILD* and SYMBOL_CLASS=PROCEDURE.
Each of these clauses resulted in a set of occurrences. You
combined the results of the two clauses by using the AND operator,
which resulted in only those occurrences that were found in both
sets of results.
The set operators available in SCA are AND, OR, NOT, and XOR. You
can use any number of set operators to combine attribute selection
clauses (such as SYMBOL_CLASS=PROCEDURE) to specify your query.
In the following display, which resulted from the previous query,
there are two declarations of the BUILD_TABLE procedure and one
call reference:
BUILD_TABLE procedure
BUILD_TABLE\41 PROCEDURE declaration
TRANSLIT\61 FORWARD or EXTERNAL PROCEDURE declaration
TRANSLIT\171 call reference
In the previous example, remember that you are interested in
seeing only call references to this procedure. You can further
restrict your query by using the OCCURRENCE= attribute, which
describes how a particular occurrence of a symbol is used. To do
this, type the query as follows:
LSE Command> FIND BUILD_TABLE AND SYMBOL_CLASS=PROCEDURE -
_LSE Command> AND OCCURRENCE=CALL
This command asks SCA to find the same results as the previous
query, but to limit the results to those occurrences that are
call references. In the resulting occurrence set, the declaration
occurrences no longer appear.
Because this is a very small example, it seems unnecessary to
continue refining these queries because you could look at the
source code for only the occurrences you want. However, if the
system were larger, and thousands of occurrences were found for
each query, it would be more important to give as detailed a query
as possible to avoid extraneous information.
The occurrence class attribute describes how an occurrence is
used. Examples of other occurrence classes that are understood
by SCA are READ, WRITE, POINTER, CALL, DECLARATION , EXPLICIT,
HIDDEN, and REFERENCE. For a complete list and description of
these occurrence classes, see the OCCURRENCE_CLASS help topic.
There are two more attributes that you can use to restrict your
queries. The first attribute, DOMAIN=, allows you to restrict the
occurrences based on the range of source code in which the symbols
might be used. Possible values for DOMAIN= are INHERITABLE,
GLOBAL, PREDEFINED, MULTI-MODULE, and MODULE_SPECIFIC.
The second attribute, FILE=, allows you to limit occurrences to
those found within a particular file, such as COPYFILE.PAS.
You could find all the global symbols (those symbols visible
throughout the program) occurring in the file COPYFILE.PAS by
entering the following query:
LSE Command> FIND DOMAIN=GLOBAL AND FILE="COPYFILE.PAS"
If you do not specify a name, as in the previous example, the
default is NAME=*.
In summary, there are five attributes that you can use to select
occurrences: NAME=, SYMBOL_CLASS=, OCCURRENCE=, FILE=, and
DOMAIN=. You can combine these selection clauses using the AND,
OR, XOR, and NOT operators. For more information, request help for
each attribute.
Relationship Functions
Up to this point, you have been navigating through source code
by asking SCA to find occurrences of interesting symbols. SCA
can also help you see the structure of your code. If you are
debugging a routine, such as READ_COMMAND_LINE, you may want to
know which system library routines might be invoked if you called
READ_COMMAND_LINE. To get this information, type the following:
LSE command> FIND CALLED_BY (READ_COMMAND_LINE)
In this example, you are invoking the CALLED_BY function and
sending it one argument, the name READ_COMMAND_LINE. The resulting
display is as follows:
READ_COMMAND_LINE procedure calls
BUILD_TABLE procedure
CLI$DCL_PARSE function
CLI$GET_VALUE function
CLI$PRESENT function
EXPAND_STRING function
IADDRESS function
LENGTH function
LIB$GET_FOREIGN function
LIB$SIGNAL procedure
ODD function
OPEN_IN procedure
OPEN_OUT procedure
SUBSTR function
The query that you just entered resulted in all the routines
called by READ_COMMAND_LINE.
However, assume you are interested in finding out only which
system library routines are called by READ_COMMAND_LINE. You
can also specify that only some of the routines called by READ_
COMMAND_LINE should be a part of the result. That is, SCA lets
you specify both the caller and the callee in the "called_by"
relationship, as in the following example:
LSE command> FIND CALLED_BY (READ_COMMAND_LINE, LIB$*)
You will then see the following results:
READ_COMMAND_LINE procedure calls
LIB$GET_FOREIGN function
LIB$SIGNAL procedure
The first argument to the CALLED_BY function specified the
caller, and the second argument specified the callee. Both
of these arguments can be general query expressions, such as
SYMBOL=ROUTINE.
You may notice that there is only one level of depth to the call
trees we have seen. That is, LIB$SIGNAL and LIB$GET_FOREIGN are
called directly by READ_COMMAND_LINE. You may be interested in
looking at a complete call tree from READ_COMMAND_LINE to LIB$
routines, including calls through intervening routines.
To specify the number of levels of the call tree you want to see,
type the following command:
LSE command> FIND CALLED_BY (READ_COMMAND_LINE, LIB$*, DEPTH=ALL)
The result is as follows:
READ_COMMAND_LINE procedure calls
BUILD_TABLE procedure calls
. LIB$SIGNAL procedure
. SIGNAL_DUPLICATE procedure calls
. LIB$SIGNAL procedure (See above)
LIB$GET_FOREIGN function
LIB$SIGNAL procedure (See above)
In the previous example, the DEPTH= argument of the CALLED_BY
relationship allowed you to specify the number of levels of the
call tree. For the DEPTH= argument, you can either specify an
integer value (the default is 1), or you can specify the keyword
ALL.
The CALLED_BY relationship is not the only function available in
SCA. As with other relationship functions, the CALLED_BY function
has an inverse, the CALLING function. To find those routines that
call READ_COMMAND_LINE, type the following query:
LSE command> FIND CALLING (READ_COMMAND_LINE, DEPTH=ALL)
The result is as follows:
TRANSLIT procedure calls
READ_COMMAND_LINE procedure calls
If you do not specify the second argument to a relationship
function, it defaults to * (which means anything). This query
translates to "find anything calling READ_COMMAND_LINE, at any
depth." You will see that there is only one call to READ_COMMAND_
LINE from the TRANSLIT procedure.
These relationship displays are like previous query displays in
that you can expand, collapse, and navigate through them.
SCA also has information about two other types of relationships.
The TYPED_BY and TYPING relationship functions are useful for
finding information about how things are typed. For example, you
can learn the following:
o FIND TYPING in_file - tells you the type of the variable in_file
o FIND TYPED_BY integer - tells you what things are of type integer
o FIND TYPING (table, depth=all) - tells you what components make
up the aggregate structure table.
SCA also understands the CONTAINED_BY and CONTAINING
relationships. These functions tell you what symbols are contained
within something else. For example, the following query tells you
all the procedures that are within the signal_duplicate procedure:
LSE Command> FIND CONTAINED_BY (SIGNAL_DUPLICATE, SYMBOL=PROCEDURE)
For more information about the relationship functions, see the
help topic for each relationship.
Because you are debugging READ_COMMAND_LINE, you might be
interested in occurrences of all the symbols contained directly
or indirectly in READ_COMMAND_LINE. You can get this information
by using the CONTAINED_BY function. However, you can use the IN
function instead, which is less general but easier to use. The
IN function lets you specify the container and the containee,
and traces the relationship through all depths (including nested
subroutines, for example).
Type the following query to see all the occurrences of symbols
used within the READ_COMMAND_LINE procedure:
LSE command> FIND IN (READ_COMMAND_LINE)
The results show that 178 occurrences of symbols were used within
the READ_COMMAND_LINE procedure.
Using Previous Queries
As you continue to use SCA, you may be interested in looking at
results from previous queries that you have issued. SCA keeps
track of all your queries, and allows you to move back and forth
between them. To see all your queries, type the following command:
LSE command> SHOW QUERY
You will see the following list:
Name Query expression Description
1 WRITELN (none)
2 BUILD* (none)
3 NAME=BUILD* AND SYMBOL_CLASS=PROCEDURE
(none)
4 BUILD_TABLE AND SYMBOL_CLASS=PROCEDURE AND OCCURRENCE=CALL
(none)
5 CALLED_BY (READ_COMMAND_LINE)
(none)
6 CALLED_BY (READ_COMMAND_LINE, LIB$*)
(none)
7 CALLED_BY (READ_COMMAND_LINE, LIB$*,DEPTH=ALL)
(none)
8 CALLING (READ_COMMAND_LINE, DEPTH=ALL)
(none)
(*) 9 IN (READ_COMMAND_LINE) (none)
You can see that there is an asterisk (*), next to query 9,
which was the last query you entered. This is called the current
query. Because query 9 is the current query, you can navigate its
display, and enter GOTO SOURCE commands for that query.
SCA also lets you set the current query with the PREVIOUS QUERY,
NEXT QUERY, and GOTO QUERY commands.
Suppose you want to look at the results of the FIND NAME=BUILD*
AND SYMBOL_CLASS=PROCEDURE query again. The name of the query
is 3. To see the results of query 3 in a query buffer, type the
following:
LSE Command> GOTO QUERY 3
It is now the current query, and you will be able to navigate it,
and see the source code corresponding to the found occurrences.
You can navigate previously entered queries and use their
results in new queries. Remember that after you entered query
3, NAME=BUILD* AND SYMBOL_CLASS=PROCEDURE, you wanted to refine
that query to see only call occurrences. You then entered a new
query as follows:
LSE Command> FIND BUILD_TABLE AND SYMBOL_CLASS=PROCEDURE -
_LSE Command> AND OCCURRENCE=CALL
You could have entered the new query by typing the following:
LSE Command> FIND @3 AND OCCURRENCE=CALL
The previous command is the same as the following query:
LSE Command> FIND NAME=BUILD* AND SYMBOL_CLASS=PROCEDURE -
_LSE Command> AND OCCURRENCE=CALL
Creating Your Own Library
Now that you have seen how to use SCA, you can create an SCA
library with information about your own source code. The following
example contains the commands for creating a library at the DCL
level. Remember that any SCA commands can also be entered from
within LSE.
In order to create your own SCA library, you must first create
a library directory for it. Using your personal directory, type
the following command to create a subdirectory for a local SCA
library:
$ CREATE/DIRECTORY [.LIB1]
Once you have a directory in which to create a library, enter the
following command to SCA to create a library:
$ SCA CREATE LIBRARY [.LIB1]
You now have an empty SCA library. To add a module to the SCA
library, you must first compile your source code.
If you have a Pascal compiler available, you can compile and load
one of the SCA example files into your new library.
First, copy the example file into your working directory by typing
the following command:
$ COPY SCA$EXAMPLE:TYPES.PAS []
Then, compile it with the /ANALYSIS_DATA qualifier. This creates
the file TYPES.ANA, which can be loaded into your SCA library. To
compile this file, use the following command:
$ PASCAL/ANALYSIS_DATA TYPES.PAS
If you do not have a Pascal compiler, try adding the /ANALYSIS_
DATA qualifier when you use any other supported compiler. For
example:
$ CC/ANALYSIS_DATA myfile.c
Once you have a .ANA file, you can load it into your SCA library
either from LSE or standalone SCA. To load the .ANA file and show
the new module, type the following commands:
SCA> LOAD myfile.ANA
SCA> SHOW MODULE
You will see that the new module has been loaded into the library,
and you will now be able to query that library.