[SCA]
1 – Advanced Query Examples
The examples in this section use the SCA$EXAMPLE library. You are encouraged to try these queries using the example library. 1. FIND CALLED_BY( END=translit, DEPTH=ALL) This query gives the full call tree for TRANSLIT. 2. FIND CALLED_BY( END=translit, BEGIN=signal_duplicate, DEPTH=ALL) This query returns all the call paths emanating from translit that end up calling SIGNAL_DUPLICATE. 3. FIND CALLED_BY( translit, DEPTH=ALL, TRACE=(NOT OPEN*)) This query gives the full call tree for TRANSLIT, but does not show any calls from items named OPEN*. Calls to items named OPEN* appear in the call tree; however, items which are called by OPEN* do not appear. Try the query without the trace expression and compare the results when the TRACE is given. 4. FIND CALLED_BY( END=translit, BEGIN=(NOT DOMAIN=PREDEFINED and NOT lib$*), DEPTH=ALL ) This example leaves predefined functions and functions named LIB$* out of the call graph. Functions such as CHR and WRITELN in Pascal, MAX in FORTRAN, a builtin like _ADAWI in C, and so forth are predefined. These functions are defined by the language, not the programmer. 5. FIND IN( build_table and occ=comp, max_code ) This example finds all occurrences of MAX_CODE in the module BUILD_TABLE. In this case, module has the same meaning as it does in SHOW MODULE. This is the fastest way to limit a query to occurrences in a particular module. The first parameter to the IN function tells SCA in what container to look. The "and occ=comp" part of the query ensures that the BUILD_TABLE you are looking in is one of the modules displayed by SHOW MODULE, rather than something else. The second parameter to the IN function tells SCA what to look for. This is faster than specifying the following: FIND IN( build_table and occ=comp ) and max_code Both queries in this example produce the same result. Routines Used in a Module But Declared Elsewhere In this example, you find functions that are used in a given module but have their primary declaration in some other module. This example is a multistep process that makes use of previous queries. Each query in this section is numbered so that you can refer to a specific query. If you refer to a query, adjust the query name (for example, where @1 is used) to refer to the query name you have created. 1. FIND IN( translit and occurrence=compilation_unit, - symbol=function and domain=(global,inheritable) ) This query finds all occurrences of functions, either declarations or references, in the module TRANSLIT. You use "domain=(global,inheritable)" to limit the query only to occurrence in which you are interested. Only global and inheritable symbols can be imported because module-specific symbols are from the same module, and predefined symbols come from the language. Next, you have to remove any functions that have their primary declaration in the module. 2. FIND @1 AND NOT EXPAND( @1 and occurrence=primary ) This query removes any functions that have a primary declaration in the module TRANSLIT. What remains are those global or inheritable functions that do not have a primary declaration in TRANSLIT. The EXPAND function in this query can be evaluated efficiently by SCA. The parameter to EXPAND, @1 and occurrence=primary, can be evaluated by looking at the result of query 1, so SCA does not have to use the SCA library. Because the overall query does @1 AND ..., everything in the result is present in the result of query 1. All we are doing is removing occurrences. In this case, SCA can evaluate the whole query expression by looking at the result of query 1 and does not have to use the SCA library. Items Declared In a Module But Not Used Anywhere In the Module In this example, you find occurrences of functions or variables that are declared in a module but are not used in the module. This example is a multistep process that makes use of previous queries. The numbers by each query are used to refer to it later. If you refer to a query, adjust the query name (for example, where @1 is used) to refer to the query names you have created. 1. FIND IN( translit and occurrence=compilation_unit, - symbol=(function, variable) ) This query finds all occurrences of functions or variables, either declarations or references, in the module TRANSLIT. 2. FIND @1 AND NOT EXPAND( @1 and occurrence=reference ) This query removes from our first query any functions or variables that have a reference in the module TRANSLIT. What remains are those functions or variables that are not used anywhere in the module. The EXPAND function in this query can be evaluated efficiently by SCA. The parameter to EXPAND, @1 and occ=reference, can be evaluated just by looking at the result of query 1, so SCA does not have to use the SCA library. Because the overall query does @1 AND ..., everything in the result is present in the result of query 1. All we are doing is removing items. In this case, SCA can evaluate the whole query expression by looking at the result of query 1, and does not have to use the SCA library. Finding Unused Functions This example finds functions or subroutines that are never used. It provides several ways of solving the problem. Some of these are easy to understand, but can be very slow on larger SCA libraries. The more complex ones are intended to improve performance on larger SCA libraries. They do not have a significant impact on smaller libraries. The first example finds unused functions only. Note that instead of saying "occurrence=call" to find functions that are called, you specify "occurrence=reference" to find functions that are used at all. The query is as follows: FIND symbol=function AND occurrence=primary - AND NOT EXPAND( symbol=function and occurrence=reference ) On the SCA$EXAMPLE library, this query works well because it is a small library. On a larger library, it may be too slow. To evaluate this query, SCA must first evaluate "symbol=function and occurrence=primary." It must then evaluate "symbol=function and occurrence=reference" before doing any additional processing. In this case, SCA has to do twice what is essentially the same work. Also, SCA does not discard information about functions that are referenced until the end, so it uses a lot of memory. Using Previous Query Results to Find Unused Functions Faster The next example also finds unused functions. However, it uses previous query results, so the work is done only once. For this reason, it is faster than the previous example. It also uses somewhat less memory, but still not enough to make a difference on a large library. FIND symbol=function and occurrence=(primary,reference) In the previous query, we find all the occurrences that we want to use. We ignore the associated declarations at this point because they are not essential to the query. Next, we must select those functions that are not used as in the following query: FIND @1 AND occurrence=primary - AND NOT EXPAND( @1 AND occurrence=reference ) This query removes from the list of functions in our system any that are referenced, leaving only unreferenced functions. Because you are using a previous query with all the information in it, SCA does not have to access the SCA library, and performance is generally faster. However, on a large library, this may still be slow. The reason for this is that it ends up keeping a list of all the functions and all their references in memory. Using Iteration to Find Unused Functions Faster This is the most complex example. It includes some repetitive parts that the query language does not provide directly. You can do these using the callable interface, or by writing a .COM procedure, or you can do the repetitive parts manually. This is also the fastest form of the example and uses less memory. Basically, you are going to split up the work into smaller pieces to avoid having to keep everything in memory at the same time. In this example, you process one module at a time, so you need to get a list of modules first. You can do this by entering the following query: 1. FIND occurrence=compilation_unit In the next step, you have to loop through each of the occurrences found in step 1. This part cannot be done directly using the query language. You can do this using one of the following methods: o Do this manually, stepping through the occurrences in the query one by one, and using INDICATED() in the following queries where module_name is specified. o Use the /DISPLAY options to specify only the name of each occurrence found, capture the result in a file, and write a command procedure to loop over the names. In this case, you use "module_name and occurrence=compilation_unit" in the following queries where module_name is specified. o Use the callable interface. By writing a small program using the callable interface, you can do the loop relatively easily, using SCA$GET_OCCURRENCE and SCA$SELECT_OCCURRENCE. In any case, you repeat the following steps for each of the modules found in step 1. 2. FIND IN( module_name, symbol=function and occurrence=primary ) This step finds primary declarations of functions in the current module. You want only primary declarations at this stage because there may be some calls in other modules. In the next step, you find any references to those functions: 3. FIND EXPAND( @2 ) This finds everything you need. At this point, what you do is very similar to what you did for the examples in the previous section. 4. FIND @3 and occurrence=primary - AND NOT EXPAND( @3 and occurrence=reference ) This finds those functions in a particular module that are not referenced anywhere. Steps 2 through 4 must be repeated for each module.
2 – Basic Query Concepts
This section covers some of the basic concepts underlying SCA queries. You may want to have a hardcopy of this section. The directions for producing a hardcopy are as follows: 1. Place the contents of Basic_Query_Concepts in a printable file by typing the following command at the DCL command line: $ a reference to a routine BAR shows that routine FOO calls routine BAR. The relationship types that are valid for SCA are: CALLED_BY, CALLING, CONTAINED_BY, CONTAINING, TYPED_BY, and TYPING.
15.47 – set
The occurrences that result from each query.
15.48 – static_analysis
The analysis of a software system performed by looking at the source code. This is in contrast to dynamic analysis, which is analysis of the software while it is running. SCA has some commands which do static analysis. These commands are the INSPECT command, which does consistency checking, the REPORT command, that can generate reports about modules, imported and exported objects, and so forth, and some uses of the FIND command, to generate call graphs and type graphs.
15.49 – structured_relationship_expression
A query that uses a relationship function (such as CONTAINED_ BY, CALLED_BY, or TYPED) which asks for structure information. Structure information shows the relationships between occurrences found as well as the occurrences found. Structure information is provided by default.
15.50 – structured_set
A query result which has both occurrences and relationships between occurrences. These are produced by queries which involve relationship functions.
15.51 – symbol
Any object in a program. For example, a FUNCTION, a VARIABLE, a CONSTANT, or any of the entities with which a programmer typically deals. A symbol has occurrences. For example, the declaration of a variable is an occurrence, and uses of the variable are occurrences. SCA determines which occurrences belong to which symbols using the rules of the language you are using. For example, you may have two different variables named INDEX in separate subroutines. According to the rules of your language, these are usually different variables, so they are different symbols for SCA. It does not matter whether all occurrences of a symbol are in a single compilation unit, or spread over several compilation units. All the occurrences still belong to the same symbol. For example, you may have a subroutine SUB1 in one module, and calls to that subroutine in several other modules. These all appear as occurrences of the same symbol, named SUB1. The programmer and SCA should have the same definition of what constitutes a unique item. SCA's term for a unique item is symbol.
15.52 – symbol_checks
A check that INSPECT performs on all occurrences of a symbol. For example, INSPECT can ensure that there are both read and write references to a variable. In this type of check, no single occurrence is either correct or incorrect. If there are problems, the problems are with the symbol as a whole.
15.53 – SYMBOL_CLASS
An attribute selection that identifies the type of symbol. Tells you whether the symbol is a variable, constant, or some other class. You can use the FIND command to find only symbols with a particular symbol class. For example, you can specify "FIND symbol=argument." You can abbreviate both "symbol" and "argument".
15.54 – symbol_class_selection_expression
The expression containing the symbol class for each symbol you want to find.
15.55 – type_graph
A set of occurrences and relationships that describes a complex data type. For example, a declaration of a record consists of a record and some record components. Each record component has a type, which may be another record, a pointer to the same record, a basic data type such as integer, and so forth. In SCA, the type graph connects all these together, with relationships connecting the record to its components and the components to their types.
15.56 – TYPED_BY
See the SCA_Topics TYPED_BY help topic.
15.57 – TYPING
See the SCA_Topics TYPING help topic.
15.58 – union
The operation performed by the OR operator, which indicates that SCA will accept any occurrence that matches either X or Y as follows: FIND X OR Y
15.59 – virtual_library
A library that allows you to split your SCA library into pieces. Each piece is called a physical library. SCA works the same way whether your virtual library has only one physical library or several physical libraries. Some of the reasons for using more than one physical library are as follows: o Physical libraries can be placed on more than one disk, if there is not enough room on a single disk. o Analysis date files can be loaded into more than one physical library at the same time, to make LOAD run faster. o A small personal physical library can be used to keep track of your personal changes without affecting other users. o A separate physical library can be used for each major component in your system. A single virtual library is a list of one or more physical libraries. The order is important. A module in one physical library hides the same module in physical libraries later on in the list. This list of physical libraries is called a library list.
15.60 – visible
See both appearance and visible modules.
15.61 – visible_modules
Modules that SCA can examine when performing a FIND or INSPECT command. The current library list tells you what modules are visible. All modules in the first library in the library list are visible. Modules in the second library which are not in the first library are visible. Modules in the third library which are not in the first or second libraries are visible. Any module which is not visible is hidden.
15.62 – wildcards
Wildcards are used to match more than one name at once. There are two wildcards in SCA: the asterisk (*) and percent (%). For example, in the name expression A*, the wildcard * will match any number of characters, so this would match A, AB, ABC, AXYZ, and so forth. The * wildcard matches any number of characters, and % wildcard matches just one character. If you do not want SCA to use * or % as a wildcard, you use an ampersand (&) to quote it. For example, to find the single name *, you would use &*.
16 – IN
The IN function searches for occurrences inside a container. The IN function is a special case of the CONTAINED_BY function. In its most common form, the function format is as follows: IN( <container>, <containee> ) In this format, <container> and <containee> can be any legal query expression. The IN function returns all occurrences that match the <containee> expression as long as those occurrences are somewhere inside the container. Some examples will help you understand the IN function. The following picture applies to the examples that follow. A (module) +-------------------------+ | | | B (routine) | | +-------------------+ | | | | | | | C (routine) | | | | +-------------+ | | | | | | | | | | | D (variable)| | | | | | | | | | | | | | | | | +-------------+ | | | | | | | +-------------------+ | | | | E (variable) | | | +-------------------------+ Consider the following queries: 1. FIND IN( A, *) 2. FIND IN( B, D) 3. FIND IN( A, SYMBOL_CLASS=ROUTINE and OCCURRENCE=DECLARATION) The first query returns B (a containee), C (a containee), D (a containee) and E (a containee). A is not returned because it is the container. The second query returns only D (the containee). C is not returned because it does not match the <containee> expression. B is not returned because it is the container. The third query returns all routine declarations inside A. In this case, B and C are returned. The IN function is a convenient way to limit a query to a particular container. The full format of the In function is as follows: IN( [END=<container>], [BEGIN=<containee>] ) In this format, <container> and <containee> can be any legal query expression.
17 – INDICATED
The INDICATED function is available only from within LSE. The INDICATED function matches the occurrence on which the cursor is positioned. The INDICATED function has no parameters. The format is as follows: INDICATED() An example of using the INDICATED function is as follows: FIND EXPAND( INDICATED() ) This query finds all occurrences of the item on which the cursor is positioned in LSE.
18 – Language Specific Tables
For information about SCA terms and corresponding language- specific terminology, see the tables under the Getting_Started help topic.
19 – Libraries
19.1 – Project Libraries
There are many ways you can organize the SCA libraries for your project. Usually, there is one library (or set of libraries) for the whole project. Each developer has a personal library containing modules that they have changed but have not yet made available to the entire project. However, if there is only one developer working on the project, it makes more sense to use a single SCA library. There are many ways you can organize your project libraries. You can have one project SCA library if it is a reasonable size. You can use several libraries, one for each subsystem. You may want to organize your SCA libraries the way your development environment is organized. For example, have one SCA library for each CMS library. If your project is divided into different subsystems, you may want one SCA library for each subsystem. For information on creating your own SCA library, see the help topic Buildin_An_SCA_Library. Examples of Typical Libraries Consider a project with three developers: Paul, Mark, and Joanna. The project consists of five different subsystems. Each subsystem has its own SCA library in the following directories: DISK1:[PROJECT.SUBSYSTEM1.SCA] DISK1:[PROJECT.SUBSYSTEM2.SCA] DISK1:[PROJECT.SUBSYSTEM3.SCA] DISK2:[PROJECT.SUBSYSTEM4.SCA] DISK2:[PROJECT.SUBSYSTEM5.SCA] Each of the developers also has a personal SCA library as follows: DISK1:[PAUL.SCA] DISK2:[MARK.SCA] DISK1:[JOANNA.SCA] Paul uses the following command to set up his SCA libraries: LSE Command> SET LIBRARY disk1:[paul.sca], - _LSE Command> disk1:[project.subsystem1.sca], - _LSE Command> disk1:[project.subsystem2.sca], - _LSE Command> disk1:[project.subsystem3.sca], - _LSE Command> disk2:[project.subsystem4.sca], - _LSE Command> disk2:[project.subsystem5.sca] Mark and Joanna use the same command, but the first library in the list is their own SCA library. When Paul changes a module in Subsystem 1, he compiles it and loads it into his personal library in DISK1:[PAUL.SCA]. For Paul, this hides the old version of the module in DISK1:[PROJECT.SUBSYSTEM1.SCA], so his SCA library is up to date and consistent with his changes. Mark and Joanna do not see Paul's changes in their SCA libraries because they are not using the SCA library (DISK1:[PAUL.SCA]) that Paul updated. They still see the old version of the module in DISK1:[PROJECT.SUBSYSTEM1.SCA]. Once Paul has completed his change, the nightly build updates everything for Subsystem 1, replacing the module in DISK1:[PROJECT.SUBSYSTEM1.SCA]. Now Mark and Joanna can both see the change.
19.2 – Virtual Libraries
SCA can use more than one SCA library at the same time when doing queries using the FIND and INSPECT commands. The list of SCA libraries used for this is called a virtual library. The order of SCA libraries in the library list is important. A module in the first library in the library list will hide the same module in other libraries, further on in the library list. For example, suppose PROJECT_LIB has modules A, B, C and library MYLIB has modules A, and D. You can set the library as follows: LSE Command> SET LIBRARY mylib,project_lib The modules visible in the virtual library would be A (from MYLIB), B, and C (both from PROJECT_LIB) and D (from MYLIB). There are many reasons for using more than one physical library as your virtual library: o Using more than one library, you can improve LOAD performance by loading multiple libraries simultaneously. See the help topic Reducing_LOAD_Time. o You can use virtual libraries to allow several developers to maintain a consistent view of their changes to a project, without affecting the other developers, and without having to copy the entire SCA library for each developer. o You can put your SCA libraries on different disks or on different nodes (using the SCA server). This improves performance or takes advantage of the available disk space. o You use the SET LIBRARY and SET NOLIBRARY commands to maintain your virtual library list. You can use the /BEFORE and /AFTER qualifiers to insert and remove libraries without having to reenter a library list. You can specify libraries in your library list using library numbers. For example, the command SET NOLIBRARY 2 removes the second SCA library from the library list.
20 – NAME
NAME is an attribute of an occurrence that is a string of ASCII characters which identifies symbols in your source code. A specific name can be associated with more than one symbol. The language you are using defines the legal characters for a name. Each name has zero or more characters. Any character may appear in a name. Special characters that appear in a name must be quoted using double quotes. You do not need to quote the following: $, _, *, %, &, -, alphanumeric characters. You can use wildcards (* and %) in the name expression. You can override the wildcard characters by using the escape character (&). For example, you can find the name consisting of a single asterisk using the name expression &*. If you want an ampersand in a string, you must use two successive ampersands. The format for NAME can be one of the following: name NAME=(name[,name...])
21 – New Users
The VAX Source Code Analyzer (SCA) is an interactive cross- reference and static analysis tool that works with many languages. It can help you understand the complexities of a large software project. Because it allows you to analyze and understand an entire system, SCA is extremely useful during the implementation and maintenance phases of a project. SCA is included in the VAXset Software Engineering Tools Package. SCA is tightly integrated with the VAX Language-Sensitive Editor (LSE). When SCA is used with LSE, you can interactively edit, compile, debug, navigate, and analyze source code during a single development session. For more information, see the following topics: o Basic_Query_Concepts - Describes some of the basic concepts underlying SCA queries. o Getting_Started - Provides subtopics with information about getting started with specific languages. o SCA_Tutorial - Provides a sample session that allows you to get started after completing the session. o Building_An_SCA_Library - Describes how to quickly create an SCA library. o Advanced_Query_Examples - Provides advanced examples using the SCA$EXAMPLE library. o Glossary - Provides definitions of SCA terms. o Command_Categories - Lists the different types of SCA commands. o Callable_Routines - Provides a complete description of each SCA callable routine. o Callable_SCA - Provides guidelines for using the SCA callable interface. o Libraries - Provides subtopics with information about project libraries and virtual libraries. o Reducing_LOAD_Time - Provides guidelines for reducing your LOAD time. o Quick_Reference_Card - Provides a pointer to the release notes, which contain a quick reference card for the SCA query language. Under SCA_Topics, there is help information for specific keywords. These keywords include attributes, relationships, and functions. For example, you can request help on SCA_Topics SYMBOL_CLASS to get information about the SYMBOL_CLASS attribute.
22 – OCCURRENCE
The occurrence class is an attribute of an occurrence that identifies the type of occurrence. The occurrence class indicates if the occurrence is a declaration, a reference, or one of the other classes in the list that follows. If the occurrence class is a declaration or reference, the occurrence class indicates what type of declaration or reference it is. The format for the occurrence class attribute is as follows: OCCURRENCE=(keyword[,keyword...]) The occurrence class can be one of the following keywords: Declarations o PRIMARY - most significant declaration o ASSOCIATED - associated declaration o DECLARATION - primary or associated References o READ, FETCH - fetch of a symbol value o WRITE, STORE - assignment of a symbol value o ADDRESS, POINTER - reference to the location of a symbol o CALL - call to a routine or macro o COMMAND_LINE - command line file reference o INCLUDE - source file include referenece o PRECOMPILED - precompiled file include referenece o OTHER - any other kind of reference (such as a macro expansion or use of a constant) o REFERENCE - any of the preceding values Other Occurrence Classes o EXPLICIT - explicitly declared o IMPLICIT - implicitly declared o VISIBLE - occurrence appears in the source o HIDDEN - occurrence does not appear in the source o COMPILATION_UNIT - the declaration that contains all occurrences in a particular compilation unit The previous keywords are SCA terms. For information on corresponding language-specific terms, request help for the appropriate language table (for example, FORTRAN_ATTRIBUTES_TABLE) under the Getting_Started help topic. An example using the occurrence class attribute follows: FIND OCCURRENCE=PRIMARY This query finds all PRIMARY occurrences of declarations.
23 – Reducing LOAD Time
There are different means you can use to try to decrease LOAD time. Listed below are a few guidelines that may help you reduce LOAD time: o Loading an SCA library for a software system is a time consuming operation and should be done in batch. Loading more than one module at a time is more efficient than loading modules separately. Using LOAD *.ANA is a common method for loading multiple modules. You use LOAD/DELETE to clean up .ANA files after they are loaded successfully and to use a little less disk space during the load. o With large software systems, it is a good idea to use more than one SCA library and load them all simultaneously. This can lessen the elapsed LOAD time considerbly. You should be able to load several libraries simultaneously on a single disk. Additionally, using more than one CPU to do your loads also helps, but SCA loading is mainly I/O intensive. For more information about how to use multiple libraries, see the help subtopics under Libraries. o Once your SCA library starts getting above 20K blocks, you should consider preallocating the library when you create it. SCA currently extends the library file by 1000 blocks at a time, so for large libraries it frequently extends the library. You can preallocate an SCA library by specifying CREATE LIBRARY /SIZE=xxx, where xxx is the size of the library in disk blocks. Use the size of the SCA$EVENT.DAT file in your current SCA library directory as the value to the /SIZE qualifier. o SCA uses a large number of I/Os during LOAD. Loading an SCA library on a heavily used or badly fragmented disk causes the load to be less efficient. You can tell how badly your SCA libraries are fragmented by using the following command: $ DUMP/HEADER/BLOCK=COUNT=0 - _$ DISK:[sca_library_directory]SCA$EVENT.DAT The interesting portion of the output is the Map area. Each retrieval pointer represents a contiguous section on the disk. Because SCA extends SCA libraries 1000 blocks at a time, having a lot of retrieval pointers smaller than this is a strong indication that some defragmentation is needed.
24 – Quick Reference Card
The release notes contain a quick reference card for the SCA query language. You can find the release notes in SYS$HELP:SCA031.RELEASE_NOTES.
25 – SCA Tutorial
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: $