/sys$common/syshlp/helplib.hlb SCA, SCA Topics, SCA Tutorial *Conan The Librarian (sorry for the slow response - running on an old VAX) |
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.
|