web viewthe errtyp symbol is used to communicate error codes to the error. handler, ... comand...
TRANSCRIPT
Compliance Checker Documentation Philosophic, User, and Technical
10 Oct 85
15:08:03
DIR = [U0139.RICHARDSO]
COMDOC.MEM
WRITTEN BY CHRIS RICHARDSON OF RICHARDSON COMPUTER RESEARCH P. O. BOX 8744 LA JOLLA, CALIFORNIA 92038-8744 (619)-488-6193 FOR THE NAVAL WEAPONS CENTER AT CHINA LAKE
Compliance Checker Documentation
10 Oct 85
Compliance Checker Documentation
1.0 Compliance Checker Introduction . . . . . . . . . . 1 2.0 MUMPS Compliance Checker Philosophy . . . . . . . . 1 2.1 Automated Tools . . . . . . . . . . . . . . . . . 2 2.2 Configuration Management Approach . . . . . . . . 3 3.0 Compliance Checker Design . . . . . . . . . . . . . 6 4.0 Environmental Constraints . . . . . . . . . . . . . 7 5.0 Loading Instructions for COMPLY . . . . . . . . . . 9 6.0 Run Instructions for COMPLY . . . . . . . . . . . 10 6.1 Available Options . . . . . . . . . . . . . . . 10 6.2 The Execution . . . . . . . . . . . . . . . . . 10 6.3 Examples . . . . . . . . . . . . . . . . . . . . 11 7.0 Programmer Module Breakdown . . . . . . . . . . . 12 7.1 COMARG - Command Argument Controller . . . . . . 12 7.2 COMBLK - Block Structure Control . . . . . . . . 19 7.3 COMERPT - Error Reporting Module . . . . . . . . 22 7.4 COMERR - Error Logging Module . . . . . . . . . 25 7.5 COMFLIN - First Line Convention Handler . . . . 30 7.6 COMFUNC - Function Handler . . . . . . . . . . . 36 7.7 COMLAB - Label Definition Handler . . . . . . . 41 7.8 COMLINE - Command Line Parser . . . . . . . . . 44 7.9 COMLSTK - Routine Label Stack Report . . . . . . 49 7.10 COMMAND - Command Handler . . . . . . . . . . . 60 7.11 COMPKGE - Package Parsing Control . . . . . . . 74 7.12 COMPLY - Compliance Checker Entry Point . . . . 81 7.13 COMPOST - Post-Conditional Handler . . . . . . . 87 7.14 COMRLAB - Label Reference Handler . . . . . . . 92 7.15 COMRPRT - Routine Report Summary . . . . . . . . 96 7.16 COMRSEL - Routine Select Handler . . . . . . . . 98 7.17 COMRTN - Routine Parsing Control . . . . . . . . 102 7.18 COMSTK - Package Routine Stack Report . . . . . 106 7.19 COMSTORE - Loads and Stores Routines into COM . 113 7.20 COMSTRG - String Handler . . . . . . . . . . . . 117 7.21 COMSYM - Symbol Handler . . . . . . . . . . . . 119 7.22 COMTIME - Time and Date Utility . . . . . . . . 125 7.23 COMTOK - Get Next Token and Delimiter . . . . . 126 8.0 WAIVERS TO COMPLIANCE CHECKER . . . . . . . . . . 129 8.1 "1C1" - Non-%ROUTINE Creates "%" Variable . . . 129 8.2 "2A1" - Title Line Not a Single "DO" Command . . 129 8.3 "3D1" - Potentionally Recursive Block Found . . 130 8.4 "3D2.1:4" - Recursive Routine Found . . . . . . 132 8.5 "3E" - Previously Defined Block Invoked . . . . 133 8.6 "3I" - Unreferenced Label . . . . . . . . . . . 133 8.7 "4D" - XECUTE Command Found . . . . . . . . . . 135 9.0 ACKNOWLEDGMENT . . . . . . . . . . . . . . . . . . 136 10.0 COMPLIANCE CHECKER OUTPUT . . . . . . . . . . . . 136 11.0 SAMPLE SYMBOL TABLE . . . . . . . . . . . . . . . 147 12.0 Standards Document . . . . . . . . . . . . . . . . 149 13.0 INDEX . . . . . . . . . . . . . . . . . . . . . . 164
i
1.0 Compliance Checker Introduction
MUMPS is an incredibly easy language to write programs in. It encourages quick development and easy maintainence (microcosmically). Microcosmically maintainable in that an error stop leaves the execution intact so that the problem may be investigated separate from the whole package. The execution may be continued once the problem has been corrected.
Programmers in this environment have a tendency to write "Quick and Dirty" code with the promise to "clean it up later". All too often, this "Quick and Dirty" code ends up as production code with unregulated patches being applied as the production environment evolves.
The Compliance Checker is a tool for the control of MUMPS programming style. It is a training aid and a quality control tool. It should be used as an insentive for the programmer to moderate his own MUMPS coding style.
This document describes the Compliance Checker in all of its current functionality. This document contains routine by routine discussion of the package's execution and customization suggestions. At the end of this document is a copy of the standards document, "MUMPS Programming Standards or How I Stopped Worrying and Learned to Love MUMPS", that this package is written to.
As a matter of convenience to the analyst, this document contains a section on the Compliance Checker Philosophy. For those who want to get to the finer points of this package quickly, this section may be passed for the time being. For those who want additional back-ground to the package, read on.
2.0 MUMPS Compliance Checker Philosophy
The only cure for interpretation is more interpretation. - Anonymous -
MUMPS is an enigmatic language. It provides a rich programming environment that allows the programmer a great deal of flexibility to express concepts and ideas. This same concise, but rich notation may also appear as cryptic to the unfamiliar reader.
The MUMPS language provides the ability to abbreviate most commands to a single character. Presently, this is the heart of the difficulty in modern information systems today. The computer understands these symbols with ease and performs them well
1
(whether employed correctly or incorrectly). The human computer does not accept these symbolic entities in the same pedantic and dogmatic style. Instead, the human computer is highly imaginative and associative, finding inference whether expressed or unimplied.
The human computer constructs tools. This Compliance Checker is one such tool. The Compliance Checker is a means of automating the Quality Control Function. It must be recognized that this is just a tool that reflects a specific set of standards. These standards are an ideal and are not always practical. In the area of tools and standards, a great deal of work remains. As such, this tool should not be viewed as a culmination, but a beginning of an on-going process towards the generation and development of better tools.
2.1 Automated Tools
We human computers build what we call tools to support the man-machine interface. The purpose of tools is to provide a context for special work. This context is for the expressed purpose of allowing the pedantic computer to provide special documented representations for the human computer. By providing this environment, the ideas reflected within MUMPS code become familiar symbols. These symbols are a special re-iteration of the application being modeled. This gives the human computer another aspect from which to view the logical model, and derive a more informed understanding of the application being modeled. The meaning of the model becomes clearer from the other points of view. Hopefully, the value of these tools will be reflected in better control of the model building process.
Any project which reflects the workings of more than a single mind, needs some form of configuration management. To simplify this even further, every development project needs some form of configuration management.
In theory, quality control in the software modeling environment means the validation of the concepts and ideas reflected in the software model. This has been a difficult if not humanly impossible task, however, the task can be readily accomplished. If humans are too slow and prone to overlook the details of quality control, then a tool must be developed that identifies the techniques and styles that confuse and obscure the concepts employed in the model. Once we have such a tool, it is meaningless until we establish the feed-back to the individuals that are generating the questionable code. Here is the starting point for the development of a consistent programming style for a programming team.
2
Traditionally, programming style has been something programmers acquires over a long period by trial and error or conditioning. Like most behaviors, they are enforced by the response of the environment upon the programmer. If the program failed to run properly, who cares. The pay check still arrives like clock-work. Further, with any luck, the programmer won't have to support the package too long before he moves on to another project. Programmers get ahead by changing jobs, don't they? Given these attitudes, the programmer often feels that the remainder of the DP community operates in the same manor. "Why should I program in a supportable manor, nobody ever did that for me."
The elements of programming style in MUMPS have not been well discussed yet. Individual techniques have been anarchy thus far. Each programmer has his own special approach to solving a particular part of a problem. The programmer manipulates the symbols at hand in a fashion which is meaningful at that time. Their individual style prejudice is reflected with the symbols and approaches used. The computer applies no such special significance to these symbols. The computer is restricted to use the limited confines provided by the model. The computer has no problem conveying a meaning to these symbols.
2.2 Configuration Management Approach
To avoid the problems discussed above, Code 084 at the Naval Weapons Center has developed this set of tools to provide a conceptionally automated quality control program package. This approach addresses three specific areas; programmer training, documentation, and support.
3
The philosophy of this approach involves the following;
1. Establish a set of standards.
2. Develope a model which can rigorously test code against these standards.
3. Make the tool available to the programming staff.
4. Establish of a mailbox system in which packages may be delivered for analysis by the designated Quality Control group.
5. Keep a copy of the routines away from the programmers. This will be the configuration management copy that will verify the presumptive production code.
2.2.1 Programmer Training
Exposing the programmer to a copy of the Compliance Checker will provide an understanding of how the checker functions. The code will provide pointers for how the standard can be complied with.
Actually running the code against the compliance checker, will inform the programmer about the techniques the programmer may need to defend. Basically the programmer will normally have the option of rewriting the code to the standards or completing the proper waivers.
2.2.1.1 Modifying the Code
Modifying the code helps the programmer to learn programming techniques which are ultimately embraced by all of the other programmers. This feed-back will help the programming staff to learn to organize their thought processes into structured models. Structured models are inherently easier to support and to modify. They are also easier to bullet-proof. The structured modules which make up the model may be rigorously tested in isolation, apart from the other components or modules of the model.
4
2.2.1.2 Filling out the Waiver
The waiver reflects the concept being expressed in support of the inconsistent code. The reconstruction of the programmer's concept at the time of coding, is the single most difficult problem.
This takes a significantly different type of work than most programmers are willing to become involved in. Essentially, this is the programmers incentive to modify the code to fit the standard. However, if no standard method may be found, the waiver maintains some conceptual integrity in reestablishing the programmer's intent for the code.
2.2.2 Documentation
Documentation reflects more of an integrated approach which results in a significant degree of standardization. The programming staff is generating code in essentially the same programming style. The consistent styles being applied provides for easy analysis by the documentation specialists.
2.2.3 Support
When an assumption has entered into an application, the support programmer (or any other programmer on the staff) will be able to decipher the code quickly. The following advantages will be readily available to the programmer.
1. The code is hierarchical in design.
2. The quality control staff should have the Compliance Checker analysis available.
3. The code is written in a consistent and familiar style.
4. Waivers will be available for non-standard code.
5. Structured MUMPS models are easier to restart in place.
5
3.0 Compliance Checker Design
The Compliance Checker closely follows the syntax of the language and attempts to compare the input code to the ideal of a standard. It is not rigidly intended that everyone must write code which will follow the standard explicitly. Instead, the standard is an ideal, and is to be strived toward but not necessarily attained in all cases. The catch is that the shortcomings are to be documented with waivers.
There are a number of levels that the code uses to examine an input routine. These are:
1. By Package - The first routine is identified and loaded into the ^COM global (^COM("TEXT",RTN,N)). As each external reference is identified, the routine name is stored to be loaded and examined. The relationship of the current routine and the called routine is maintained for package structure analysis at the completion of the run (COMPKGE).
2. By Routine - As the routine is parsed, the labels and the order that they are invoked is saved. The relationships are maintained in the ^COM global for routine structure analysis after each routine (COMLSTK).
3. By Block - A one label, one unconditional exit, block rule is compared and adhered to where possible. The introduction of a new label prior to the closure of the last block is flagged as an error. Unreachable code or unreferenced labels are also flagged as an error.
4. By Line - A line in MUMPS is a specific type of blocking that is peculiar to the MUMPS language. There is a class of commands which control access to the other commands situated to the right on the current line. These are called control commands; (i.e., FOR, IF, QUIT, GOTO, ELSE). There are circumstances which make the execution of commands to the right more or less critical. For example, an unpostconditionalized GOTO that occurs after an IF command does not signify the end of a block. An unpostconditionalized GOTO without a control command signifies the end of a block.
5. By Command - A Command level of evaluation provides some interesting problems with the syntax of the language. There is a series of commands that allow an incredible amount of freedom (and potential danger). The XECUTE command provides the opportunity to subvert every aspect of the standard. It is important to keep track of these and other commands that are potentially ambiguous, such as the ELSE command. The problems with the GOTO are historical to the point of becoming legend.
6
Certain commands are important by the features they impart as well as the symbols they reference. The SET, the FOR, and the READ commands are the only ways that local variables are created or changed in the MUMPS Language. Use of the SET is the only way to create global variable references. The KILL command is used to eliminate both local and global references. All other symbol usages are only references.
6. By Argument - The argument is the most complex of all of the interfaces. Each command references the arguments differently. Further, the richness of the language provides a wide variety of symbol expression as arguments.
There are situations wherein a certain command can have a dramatic effect upon symbols that were explicitly not mentioned. The argumentless KILL command will destroy all local symbols created to the present point. The exclusive KILL will destroy all of the symbols not specified within the exclusion list.
The postconditionalization of a command or argument is a specialization of an expression. It resolves down to one of two outcomes, TRUE or FALSE. Still each reference within the structure of the postconditional must be recorded as a reference.
4.0 Environmental Constraints
The Compliance Checker was designed to run DSM on a VAX. The most significant limitation to note is that this package is a hierarchical model. This model makes heavy use of the stack. However, this allows for a special level of analysis in the form of stack evaluation (on the VAX, DO ^%STACK).
In an effort to make this package as useful as possible on multiple systems, many of the options are described in detail in the module descriptions provided below. An effort has been made to make the code easy to modify for other implementations. Further, there are some 1984 Standards features installed, like the two argument $LENGTH and the "left side of the equals sign" functions ($PIECE only). As a result, these ultimately represent a source of trouble for migration to some older implementations. Solutions to these problems will be published in future editions of this document. In the interim, these extention problems will be considered as "an exercise for the student".
HINT: a relatively inelegant solution for the two argument $LENGTH may be written as a $FIND function driven by a FOR loop.
7
The package does expect at least the first routine to be analyzed to be resident and available as a routine. Also, it would require very little modification to adapt the compliance checker to accept input for routines by tape or other sequential source.
There is a symbol that may be set before a run. This symbol is the default list device. The symbol LISDEV may be set to a file or device ID prior to invoking the routine. In the event that LISDEV does not exist, it will be set to 0 and the actual default device will be used.
Little needs to be change for the Compliance Checker to run on a PDP-11 using DSM-11 Version 3.0 or better. Also, attempts have been made to flag these areas with special comments to describe the activities the code is to perform.
8
5.0 Loading Instructions for COMPLY
The tape supplied is a 9-track, 1600 BPI tape in VAL4 format with 1024 characters per block (unless otherwise indicated). The files are arranged as follows;
1. Routines - 23 Routines in %RR format
2. Globals - COMDEF and COMDOC in %GR format
LODOC D INIT,START ; LOADS DOCUMENT OFF OF TAPE ; 7-SEP-85 ; RCR QUIT INIT S LIST=3 ; OR THE LIST DEVICE YOU ARE USING S N="" ; START THE ARRAY TRAVELER O LIST U LIST ; OR THE LIST DEVICE YOU WISH TO USE QUIT START F LP00=1:1 S N=$O(^COMDOC(N)) Q:N="" W !,^COMDOC(N) C LIST QUIT
The document is in RUNOFF format which contains form-feeds, line-feeds and carriage-returns imbedded within the text. Nearly all printers should be able to handle these control characters.
9
6.0 Run Instructions for COMPLY
6.1 Available Options
In the previous discussion the LISDEV (LISt DEVice) variable was mentioned to include setting up the Compliance Checker up to generate a hardcopy listing. There is also a feature installed that allows you to monitor the execution as it progresses.
Many of the Compliance Checker analyses run for an extended period of time. Each undefined external reference called is another routine which will be subjected to analysis. To allow the user to monitor the progress of these runs without killing the job or seriously impacting the run performance, a status feature has been installed. The status feature provides that any key input will report the current routine to be parsed and the remaining routines on the stack waiting to be parsed. An "E" keyin will report the current status of errors found up to this point. Patience may be required, as the status feature only checks the keyboard between routines. This function may take several minutes to recognize the run time status request.
Should you have entered an "E" and decide that you don't want to see the error list, you may enter another key to "wipe out" the last keyin. It will only respond to the last keyin.
6.2 The Execution
Running the Compliance Checker is relatively straight forward. If a hardcopy is required, it should be called for prior to invoking the COMPLY command. At the time it is invoked, the Compliance Checker identifies itself and requests the entry routine to be checked. At this point the programmer may enter the name of the primary routine for the package or a subordinate routine of a larger application. All of the routines that are invoked from that routine are identified. These will be called in turn. Further, a whole package may be analyzed with a single routine reference.
10
6.3 Examples
When entering COMPLY (for the prompt, "routine to be parsed>") will call all of the other routines in the package. To parse a particular subbranch of execution, the entry should be the subbranch's root routine. For example, entering COMLINE will invoke the following. COMLINE <2> COMERR <2> COMLAB <3> COMERR < STRUCTURE PREVIOUSLY DEFINED > <2> COMTOK
Compare this with the listing from parsing COMPLY.
11
7.0 Programmer Module Breakdown
This package of routines has been written to conform to the structure of the interpretor itself. Each module is documented separately and contains an explanation for its place within the model. The different error messages are elaborated and inverted by error code for mapping back to the routine that generates the error.
7.1 COMARG - Command Argument Controller
7.1.1 Routine Purpose
COMARG is the argument handler for each command being parsed. COMARG will handle arguments which are symbols, globals, labels, functions, strings, and argument expressions as are used in postconditionals. An argument expression may be a mixture of data types as described above. Each type is broken down into its own routine. In order to handle the compound case, each of these types (except for literal string) has the potential to reinvoke COMARG.
The routines potentially invoked by COMARG are as follows. Most of these routines also invoke COMARG (except for COMSTRG).
1. COMSYM - Symbol Handler
2. COMRLAB - Referenced Label Handler
3. COMFUNC - Function Handler
4. COMSTRG - String Handler
5. COMPOST - Postconditional Handler
7.1.2 Environmental Concern
This routine is invoked by the following routine sources:
1. COMMAND - The Primary Control Source
2. COMSYM - Symbol Handler
3. COMRLAB - Referenced Label Handler
12
4. COMFUNC - Function Handler
5. COMPOST - Post-Conditional Handler which is Invoked from COMMAND as well
7.1.3 Symbol Definitions
There are a significant number of controls passed between this routine and the recursive companion routines. As being an Argument parser, this routine must be able to span the complexities of the EXPRESSION. An expression is the most generalized form of the argument or the postconditional. Examples are as follows:
1. $E(LINE,LINPNT)
2. 1
3. A=1:1:20,"APPLE","PEACH",25:2:50
4. B=(A=12)
5. (A,B,C(A))=2
6. ^P($P(REC,"",2),DATE-AGE)=REC
Shown above, there is a large variety of arguments. A recursive solution has been employed to solve the variety of command argument problems existent in argument parsing. The Backus-Naur Forms, (BNF) that define the language are themselves recursive. The solution to a correct model of the language is to mimic these definitions. MUMPS supports recursion (which has positive and negative aspects).
7.1.3.1 ACNT - Argument CouNT
ACNT represents the number of passes that where taken through the argument list. It is only referenced as the scalar in the FOR loop in START.
13
7.1.3.2 ALVL - Argument LeVeL indicator
ALVL indicates the level of argument expression. Its companion arrays are HLDDLM, LVLEND, and TCMDARG. Each time an expression drops a level, ALVL is incremented.
7.1.3.3 APST - Argument PoSTconditional flag
APST is used to determine if the last argument of a GOTO is post-conditionalized or not. This is important for the identification of the end of a block of code.
7.1.3.4 ASET - current Argument SET level
The ASET symbol is either "SET" or "REF". It is used to determine if a symbol is to be referenced or set by a command operation.
7.1.3.5 CMD - CoMmanD id
CMD indicates the name of the command for which the arguments are being passed. It's source is the COMMAND routine.
7.1.3.6 CMDARG - CoMmanD ARGument type
Each command contains its own argument attributes to be resolved. The most difficult to resolve are the FOR and the SET commands. This is because the FOR's single SET reference list can be comprised as a a set-and-range group, a list, a list of set-and-ranges, or any combination of these.
The SET is difficult because of two features. The first is that a group of variables may be set as a single argument evaluation. The second is that a series of set assignments may be issued for a single command. It is essential that adequate tracking is maintained for keeping track of what is set and what is just referenced. The rule set is nontrivial. See labels FORTYP and SETTYP below.
14
7.1.3.7 CMDEND - CoMmanD END flag
This CMDEND flag marks the end of the argument field for the current command set.
7.1.3.8 DELIM - last DELIMiter parsed
The DELIM is the last delimiter identified by the COMTOK routine. The DELIM is integral to the process of argument level determination and argument termination.
7.1.3.9 ENDSTR - END of STRing flag
The ENDSTR flag is killed when the program returns from COMSTRG.
7.1.3.10 EQUFLG - EQUals sign FLaG
The EQUFLG flag indicates the state in processing a SET or FOR argument. Prior to interception of an equal sign, "=", the SLVL references are stored as "SET" types in the ^COM("SYM") portion of the global. Under this condition the EQUFLG will be 0. After the equal sign and before the next ALVL=0 and DELIM=",", EQUFLG will be 1.
7.1.3.11 ERRTYP - ERRor TYPe to be logged
This is an input to the COMERR routine. The errors that may be identified by the COMARG routine are:
1. "7B" - Control Structure Failure
2. "6D" - Indirection Found
7.1.3.12 LINEND - LINe END flag
LINEND is returned by the COMTOK routine when the last token has been parsed from the current line in the LINE buffer.
15
7.1.3.13 LVLEND - argument LeVeL END
LVLEND provides control of the recursive process of argument decomposition. Each time an expression descends another level, a new LVLEND flag is created within this array. Once that level has been satisfied, the flag is set to 1 and the current execution of COMARG is terminated.
7.1.3.14 POSTC - POSTConditional flag
POSTC is for use in identifying that the parsing of a postconditional is in progress. The type of the command has no bearing on the type of expression needed. The type of expression needed for a postconditional is the truth-value.
7.1.3.15 SLVL - Saved set LeVeL
SLVL is the level in a SET or FOR command where a symbol reference before an equals sign is a value change rather than just a reference. For example;
V VV V <Being Referenced S DC(A)=$P(AB(C),"\",5) (SLVL = 1) ^^ <Actually being set or
V <Being Referenced S:A&B (AB(C),D,E,F)=27 (SLVL = 2) ^^ ^ ^ ^ <Actually being set or
V V V<Being Referenced S $P(AB(D),"\",F)=E (SLVL = 2) ^^ <Actually being set
7.1.3.16 SVSET - SaVe SEt Type
SVSET represents the expected argument set types for each command. It is set when the command is identified and restores to ASET the command default between each argument. The types are:
1. SET - This command has the ability to set the variables listed.
16
2. REF - This is the default type. It means that the variable may be referenced from this command, but not changed.
3. KIL - This means that the symbols associated with this command are to be trimmed or deleted (ie, the KILL command). Little has been done in this area yet, however, more is expected to be developed by the next release.
7.1.3.17 TOK - TOKen parsed from LINE
This is the partial decomposition token taken from the current line of code being parsed. It is the product of the COMTOK routine.
7.1.4 Block Description
The block descriptions for the routine include the following eight blocks. Their calling structure is available from the generated listing provided further within this document.
7.1.4.1 INIT - Level Initialization
The INIT block sets up the environment for this pass of the COMARG routine. The ALVL pointer is incremented on the way into the COMARG routine via this mechanism.
7.1.4.2 START - Argument Parsing Control
START controls the extraction of the individual arguments. It is ended when a level has completed, the command set has ended, or the end of the line has been reached and there are no more arguments to parse. Each iteration calls on ARGSTK one time.
7.1.4.3 EXIT - Argument Parse Exit and Cleanup
The LVLEND flag array element for the current level of ALVL is killed to avoid any ambiguity. The ENDSTR flag is also killed at this point to help clean up the symbol table. Finally, the ALVL flag is decremented to complete this argument parsing level.
17
7.1.4.4 TOKARG - Token Argument Parsing
TOKAG is used to determine what type of token we should be examining. The options are;
1. ^COMFUNC - Function Handling
2. ^COMRLAB - Label Reference Handling
3. FORTYP - FOR Loop Pre-interface
4. ^COMSYM - Local or Global Symbol Handling
7.1.4.5 DLMBLK - Delimitor Block
DLMBLK handles the delimiters as they are parsed. There are two special cases that introduce additional structures, DELIM=":" (postconditional) and DELIM="""" (a string).
1. ^COMSTRG - String Handling
2. ^COMPOST - PostConditional Handling
7.1.4.6 FORTYP - FOR Command Handler
The FOR command has a different set-type of syntax than the SET command. It is a special case of the SET argument structure. There is some potential for confusion of the FOR command's "Set and Range" arguments. The Set-and-Range may be mistaken for a strange postconditionalized argument format.
For example;
SET:TRUE A=123 ; Postconditionalized SET Command DO ABLE:TRUE,BAKER:FALSE ; Postconditionalized DO Command Arguments FOR I=1:1:20 ; FOR Command with SET-and-Range FOR I=1:1:20,30:2:40 ; FOR Command with a Group of SET-and-Ranges
18
7.1.5 Errors Handled Directly
7.1.5.1 "6D" - Indirection Found
A commercial "at" sign ("@") has been found. It will always be considered an indirection operator.
7.1.5.2 "7B" - Argument Stack Balance Error
This means that too many right parenthesis have been encountered without matching left parenthesis. Note: one unmatched right parenthesis will cause an error.
7.2 COMBLK - Block Structure Control
7.2.1 Routine Purpose
The COMBLK routine controls the arrangement of lines of the routine into blocks in the form, one entry point and an unconditional exit out of a block.
COMBLK identifies 'block' structure hidden in an application. It is surprising what blocking may be realized in the most unblocked looking code. The process of making the blocking structure more evident is not complicated or difficult when trouble areas are identified by this tool.
7.2.2 Environmental Concern
COMBLK is invoked from COMRTN directly and through a call to COMFLIN. COMBLK expects a routine to be parsed, is already in the ^COM("TEXT") global.
7.2.3 Symbol Definitions
7.2.3.1 BLKEND - BLocK END flag
The BLKEND flag indicates that an unconditional exit condition or redirection situation has occurred. These redirections may be in the form of;
1. An unpostconditionalized GOTO command not in the range of an IF or ELSE command.
19
2. An unpostconditionalized QUIT command not in the range of an IF or ELSE command.
3. The last line of a routine
7.2.3.2 BLKLIN - Lines Per Block
Presently, this statistic is not being saved. BLKLIN includes lines in a block that are comments. Comments should not be added into the count of executable code lines for the block size limit. A better indicator of block size (actual code) can be achieved by the use of CMDONE.
7.2.3.3 CMDCNT - CoMmanD CouNT
CMDCNT represents the number of times that the ^COMMAND routine was called from COMBLK and found a command. CMDCNT is initialized at 0 at the beginning of each line.
7.2.3.4 CMDONE - at least one CoMmand DONE
CMDONE is used to allow comment lines to exist between blocks of code. In a pseudo-compile environment, this type of comment is encouraged.
7.2.3.5 ERRTYP - ERRor TYPe to be logged
ERRTYP is the error type identified for this block. There are two types of errors handled in this block. See the section on Error Generation.
7.2.3.6 LINEND - LINe END flag
LINEND is set by the COMTOK routine which is subsequently called via COMMAND. LINEND signifies that there are no more commands left on the current line to parse.
20
7.2.3.7 LLCNT - Logical Line CouNT
Logical Line CouNT is the number of lines encountered since the last label for the current block being parsed.
7.2.4 Block Description
7.2.4.1 START - Block Parsing Control
The START block controls the loading of lines of code from the ^COM("TEXT") global by calling the COMLINE routine. If this occurs other than at the end of the routine, LINPARS is called to dismantle the line into commands. When an end of block, BLKEND, situation occurs or the end of the routine is found, this FOR loop is exited. The number of lines containing commands is tested for the standard maximum of 20 lines.
7.2.4.2 LINPARS - Line Parsing Within a Block
LINPARS controls the parsing of command sets from the current line of MUMPS code stored in the LINE buffer. CMDCNT is the number of actual command sets found on that line. CMDONE is the total number of commands found since the beginning of the current block. If CMDCNT exceeds 5 command sets, error type "4H" is generated.
7.2.5 Errors Generated by This Routine
7.2.5.1 "3H2" - Block Too Long
The cutoff for this error is set to 20. This can be modified if desired.
7.2.5.2 "4H" - More Than 5 Commands on a Line
By writting code in small 5 or less command sets, the programmer is forced to group similar commands into modules. This restriction is designed to encourage the programmer to think in a more structured manner.
21
7.3 COMERPT - Error Reporting Module
7.3.1 Routine Purpose
This module provides the error report that appears after each routine. It also handles the mid-execution runtime reporting of run status for errors accumulated up to this point.
7.3.2 Environmental Concern
The key to how this routine will behave is reflected in the status of the RouTiNe symbol.
This routine will list the status to the last device that was USEd. In the update mode, the final count will be provided at the end of the Package Structure Report. In the status mode, it will be written to the default device, unit 0.
7.3.3 Symbol Definitions
7.3.3.1 $Y - Lines Used
$Y is a system variable used to keep track of the number of lines that have been used on a particular device between form feeds.
7.3.3.2 %T - Current Time
%T is the current time as generated by the COMTIME routine. This provides the time in an standard printable form. See COMTIME.
7.3.3.3 A - scrAtch variable
The scrAtch variable is used to speed up the application. This variable is expendable in that it is created and destroyed within the scope of this routine.
the scrAtch variable is primarily used for the traversing of the ERRCNT and RERCNT arrays of accumulated errors.
22
7.3.3.4 ERRCNT - package ERRor CouNT array
ERRCNT is the total number of errors encountered up to this point for all routines. ERRCNT is updated within this routine on the update cycle, however, no update will occur during the status cycle.
7.3.3.5 LP02 - LooP counter #02
The LP02 symbol is only used to drive the FOR loop. LP02 will be killed at the end of this routine.
7.3.3.6 RERCNT - Routine ERror CouNT array
The RERCNT stores the errors and counts of the last routine. RERCNT is for use in updating ERRCNT. This array will be killed by a closely related routine, COMRPRT.
7.3.3.7 RNUM - Routine NUMber of errors
RNUM is a scratch variable used for totaling the number of errors found in the ERRCNT array.
7.3.3.8 RTN - RouTine Name
The routine name is to be used for indicating which of the two modes have been entered within; i.e., update or status. The update mode may only be invoked following the processing of all routines. This provides for the accumulation of errors that were encountered during the COMSTK execution for locating inter-routine recursions.
7.3.3.9 RTNNUM - RouTiNes processed NUMber
RTNNUM is the number of routines that have been parsed in this package up to this point. RTNNUM is only reported at the end of the run which takes place during the update cycle.
23
7.3.4 Block Description
7.3.4.1 START - Report Flow Control
The START label drives both the mode selection and reporting flow.
7.3.4.2 NEWERR - Accumulate New Errors
The NEWERR block is only accessed when the routine is in update mode. NEWERR allows the errors accumulated during the COMSTK execution to be added into the ERRCNT array.
7.3.4.3 REPORT - Report the Package Error Totals
This block reports the contents of the ERRCNT array in a standard format.
7.3.5 Errors Generated by This Routine
There are no errors generated by this routine because of the asynchronous method by which it is invoked. It would be inappropriate for this routine to affect the outcome of the application in those cases where in it can be invoked when the user desires to see a status of the run.
24
7.4 COMERR - Error Logging Module
7.4.1 Routine Purpose
COMERR provides for a common error handling interface. COMERR handles the recording and reporting of errors incurred during the run.
7.4.2 Environmental Concern
The only symbol input is the ERRTYP symbol. This symbol will be loaded with a two or three character error code which points to an error message in the ^COMDEF("ERR") global.
7.4.3 Symbol Definitions
7.4.3.1 CMD - CoMmanD id
CMD describes the command that is currently being parsed. CMD is referenced in the error message. CMD was originally used as a debugging aid for the Compliance Checker while in design and has proved to be a helpful feature.
7.4.3.2 CMDCNT - CoMmanD CouNT
CMDCNT is the number of commands processed to this point in the current line of code found in LINE.
7.4.3.3 ERRTYP - ERRor TYPe to be logged
ERRTYP is the only real variable input to the COMERR routine. ERRTYP will be returned as null when complete.
7.4.3.4 LABRTN - LABel RouTiNe reference
LABRTN is the standard connonic form of the line reference used by COMERR and many of the logging references in the COM global. The form of LABRTN is as shown below:
LABEL<+Off-Set>^RTN
25
7.4.3.5 LINE - MUMPS code LINE buffer
The LINE buffer is loaded by the COMLINE routine with a line of MUMPS code from the current RouTiNe.
7.4.3.6 LINPNT - LINe PoiNTer
The LINPNT pointer indicates the next character to be parsed from the LINE buffer. LINPNT indicates where the error indicator will be positioned when reported by the COMERR routine.
7.4.3.7 LINPRT - LINe PRinT flag
LINPRT flag tells the COMERR routine whether the line of code has been printed yet (i.e., were there any other errors).
7.4.3.8 LISDEV - LISt DEVice
LISDEV may be set before the run or may be allowed to default to the default device, (0). Some implementations (especially DSM-11) will default to device 3 (the line printer).
7.4.3.9 RERCNT - Routine ERror CouNT array
RERCNT maintains the number of errors for each type of error that has been found up to this point for the current routine. RERCNT will be killed between routines, after the sums have been added into the ERRCNT array.
7.4.3.10 RNUMER - Routine NUMber of ERrors tallied
RNUMER maintains the total number of errors generated up to this point for this routine. RNUMER will be reset in COMRPRT after the master error count has been updated.
26
7.4.3.11 RTN - RouTine Name
RTN is the name of the current routine being parsed.
7.4.3.12 RTNLAB - RouTiNe LABel reference
RTNLAB is the symbolic reference name of the current line of the current routine being parsed. RTNLAB allows the programmer to return to the line of code in which there is an error. The form of RTNLAB is as shown below:
LABEL<+DISPLACEMENT>^RTN.
7.4.3.13 SPCR - SPecial ChaRacter string
SPCR represents the hyphenated line that appears between lines of code being listed with errors. SPCR has been added only to provide for clarity. In the event this function appears to be undesirable, it may be changed within the COMPLY module.
7.4.3.14 TXTNUM - routine TeXT line NUMber
TXTNUM represents the number of the line currently being parsed from the routine stored within the ^COM("TEXT") global.
7.4.3.15 WRN - Available Option for Warning Message
Instructions for using the WRN feature are provided in a follow-on section and appear immediately after the ^COMDEF error list.
7.4.4 Errors Generated by This Routine
This routine sets no errors itself, but handles the errors as set by other modules. At the end of error handling, this routine clears the ERRTYP symbol.
27
7.4.5 Routine Purpose
7.4.5.1 Block Description
There is no branching in this module except for postconditionals and IF command branching. In that there are no other routines invoked from this level, the overhead of the first link block command structure has been removed. Note that other comment fields have been retained.
When no error type is specified, (which is possible), the routine will return to its source immediately. When there is an error, the error reference is saved within the ^COM("ERR") global with it's associated routine name. The error type is recorded in a local array, RERCNT, for accummulation and tabulation later within COMLSTK. The total number of errors for this routine, RNUMER, is incremented.
WRN is initialized to null at which point the ^COMDEF("ERR") data base is checked to determine if there was a warning message associated with this ERRTYP. If there is a warning message, WRN is set to that warning, and will be reported to the LISt DEVice when the error is reported.
A USE is executed for the LISt DEVice to insure it is bound. If the LINe PRinT flag is set, then this line of code has not yet been printed, and the LINE buffer is printed to the LISt DEVice. Subsequent to these activities, the LINe PRint flag is reset to zero which indicates the LINE buffer of code was printed. LINe PRinT will be reset in COMLINE.
The error message and WaRNing is printed with a pointer to indicate the position of the error in the command LINE buffer. The arrow will usually appear just behind the source of the error. The text of the error description is listed, and the line and routine reference is listed from the LABel RouTiNe symbol. The current command is also listed to help identify the source of the problem.
7.4.5.2 ^COMDEF "ERR" Structure
The error code scheme is taken from the paper, "MUMPS Programming Standards or How I Stopped worrying and Learned to Love MUMPS", which is presented at the end of this document. Error statements that are available within the current package are show below. These are:
28
^COMDEF(ERR
1A First Label does not Match Routine Name 1B Routine does not Match 3 Letter Prefix 1C1 Non-%ROUTINE Creates "%" Variable 1C2 Non "%" Scratch Variable Survives %ROUTINE 2A1 Title Line Not a Single "DO" Command 2A2 Routine Blocks on Title Line not INIT, START, or EXIT 2B No Routine Purpose Comment 2C Not Legal Date on Title Line 2D No Programmer Name Given 2E First Line Does Not Meet Standard Field Count 3A Additional Label Found Before Last Block Closed 3B Numeric Label Found 3C1 Alternate Entry Label Used in Routine Reference 3C2 Displacement Label Reference Found 3D1 Potentially Recursive Block Found 3D2 Recursive ROUTINE Found 3E Previously Defined Block Invoked 3F Program Line Exceeds 80 Characters 3G Block not ended with a QUIT or a HALT 3H1 Block Badly Terminated 3H2 Block Too Long 3H3 Routine Segment Too Long 3H4 Too Many Blocks in Routine 3I Unreferenced label 4A BREAK Command Found 4B ELSE Command Found 4C GOTO Command Found 4D XECUTE Command Found 4E VIEW Command Found 4F Z-Command Found 4G Z-Function Found 4H More than 5 commands on a line 5A Control Command Found After the First Command 5B More Than 2 Control Commands Found on the Same Line 5C Uncontrolled FOR Loop Variable 6A NON % Routine Creates % Variable 6B Variable Survives Longer than Needed 6C Small Variable Referenced after Creation Block 6D Indirection Found 7A Invalid Command 7B Argument Stack Balance Error 7C Post-Conditional Error 7D Bad Argument 7E Bad Label Delimiter 7F String Balance Error 7G Invalid Function 7H Post-conditional not allowed in this command 7I Argument NOT Allowed For This Command 7J Routine NOT Found 7K Unaccessible Commands
29
In the event it is desirable to customize additional messages to the error group, entries will need to be created within COMDEF which resemble the following;
S ^COMDEF("ERR","7J","MSG")="Please Supply Required Routine." or S ^COMDEF("ERR","6A","MSG")="Automatically Waived"
This message will appear each time the associated error is encountered.
7.5 COMFLIN - First Line Convention Handler
7.5.1 Routine Purpose
This routine handles the first line and block of a routine. The requirements under this standard include the following formats;
1. The First Label carries the same name as the routine - 1A
2. The Single "DO" Command - 2A1
3. Description of Routine - 2B
4. Date of Last Change - 2C
5. Programmer's Name - 2D
6. The Presence of These Four Fields on the First Line - 2E
Also, each item carries its own specific error message.
7.5.2 Environmental Concern
COMFLIN expects that the routine has been loaded into the ^COM("TEXT") global by the ^COMSTORE routine. The RTN symbol should exist with the name of that current routine.
7.5.3 Symbol Definitions
30
7.5.3.1 BLKEND - BLocK END flag
The BLKEND flag provides evidence of block closure. BLKEND insures that the previous (i.e., first) block is closed prior to initiation of a search for looking for the next block of code.
7.5.3.2 CMD - CoMmanD id
CMD is the last command processed. CMD is used to test the single "DO" command structure of the first line.
7.5.3.3 CMDCNT - CoMmanD CouNT
The CMDCNT variable returns the number of commands parsed from a line of code. In this case, CMDCNT reflects the number of commands on the first line. That number should be one.
7.5.3.4 ERRTYP - ERRor TYPe to be logged
ERRTYP is the error type interface with the ^COMERR routine.
7.5.3.5 LABEL - LABEL from first line
LABEL is returned by the ^COMLAB routine. This represents the label from the first line of the routine being parsed. The source of LABEL is the LINE buffer.
7.5.3.6 LINEND - LINe END flag
The LINEND flag is set from COMTOK at that point when the last set of tokens has been removed from the LINE buffer. LINEND is reset to zero when a new line is read using the COMLINE routine.
7.5.3.7 LP06 - LooP counter #06
The LP06 scratch symbol is used for eliminating both leading and trailing spaces from the first line fields as they are testing.
31
7.5.3.8 MAXL - MAXimum Length of LINE
MAXL indicates the number of characters acceptable on a line. For the first line, this number is expanded to 120 characters. The numer of characters acceptable on all other lines is set at 80 characters.
7.5.3.9 PKGID - PacKaGe IDentifier
PKGID is the three letter routine group identifier. PKGID is created in the COMPLY routine from the first routine name, FRSTRTN.
7.5.3.10 RTN - RouTine Name
RTN is the current routine being reflected in the ^COM("TEXT") portion of the global.
7.5.3.11 T - Scratch Symbol
"T" is a scratch symbol. The single letter symbol is a time saving feature of some MUMPS implementations. Single letter symbols are usually sorted first in the symbol tables in these implementations. "T" is used to trim excess spaces from the title line field strings.
7.5.4 Block Description
7.5.4.1 START - Begin First Block Acquisition
COMFLIN is used to call COMLINE to load the LINE buffer and parse out the different expected fields of the first line.
7.5.4.2 END - Cleanup
Upon exiting this routine, LP06, and "T" are killed.
32
7.5.4.3 COMMENT - Dissect Parts of First Line
Nearly everything in the LINE buffer at this point is a comment. COMMENT parses the individual fields one at a time. The fields are as follows;
1. Control Command
1. Entry Label
2. Single DO Command to Control Routine Execution
2. Routine Function Description
3. Date of Last Change
4. Programmer's Name
7.5.4.4 DATE - Date Format Check
This was separated out in deference to those older implementations that do not have the n.n form of the pattern match or to include your own date standard format.
7.5.5 Errors Generated by This Routine
7.5.5.1 "1A" - First Label does not Match Routine Name
As a matter of standard routine construction, the routine name should match the first label on the first line of the routine. Quite often a programmer will subtly change the name of a routine to allow for versioning of routines. By this approach, test versions of routines may be included without impacting the production version of routines. This check ensures that no individual version enters the production code inadvertently.
7.5.5.2 "1B" - Routine fails to Match 3 Letter Prefix
As a matter of consistency in style, all of the routines related to a specific application are prefixed with the same first three letters. This allows for the feature that all of the routines of a package may be easily selected by the system utilities such as %RSEL, (usually, dependent on the implementation).
33
7.5.5.3 "2A1" - Title Line Not a Single "Do" Command
This error message was developed in an attempt to encourage the programmer to follow a structured approach to problem solving. The labels accepted for this DO command are shown below;
1. INIT - Initialization of the process
2. START - Perform the process, also used for restartability
3. EXIT - Cleanup after the process
7.5.5.4 "2B" - No Routine Purpose Comment
The routine purpose comment provides a means of helping to identify the goal of the routine. This comment appears on the first line of the routine. This allows printing by use of the %FL utility routine. The Compliance Checker also keeps a table of comments encountered on the first line of each routine it parses from a package. Comments are stored in the ^COM("COM") global.
7.5.5.5 "2C" - Not Legal Date on Title Line
A consistent date is important in that it can be parsed from the title line to help establish the date and version of the routine being parsed. This is a future enhancement of the Compliance Checker, version control.
7.5.5.6 "2D" - No Programmer Name Given
The programmer name is probably the least important item of information appearing on the first line. This is especially true once the application being parsed is written in accordance with these standards.
A table is retained which contains a list of valid programmers and their synonyms. This table is called ^COMDEF("PRG"). Some example names are included. You will have to customize this table for your shop. A mechanism has been installed for using synonyms and different patterns of programmer's names or initials. (See the name "RCR" and "CHRIS RICHARDSON").
34
7.5.5.7 "2E" - First Line Does Not Meet Standard Field Count
In the event the first line is so non-standard that the parts can not be identified, this error message will result. The standards for the field count should be adhered to.
35
7.6 COMFUNC - Function Handler
COMFUNC is used as a means of translating data stored in one form to a different form or informing the application of an attribute to the function's argument. The results of a function are normally a different type than the arguments of the function.
7.6.1 Routine Purpose
The purpose of the COMFUNC routine is to parse the occurrence of functions within the LINE buffer. Functions are allowed to be nested. However, this can become complicated. It is actually a recursive solution problem. As such, this routine is invoked recursively from ^COMARG.
7.6.2 Environmental Concern
This routine is coded in such a way that it expects that LINE contains MUMPS code, and that the last token removed from LINE contained a dollar sign "$" in the first position. COMFUNC is designed to handle both function and system variables. The difference between these two types of variables is that there is a left parenthesis after the function name. With any other delimiter, the reference must be a system variable.
There has been a problem with the $SELECT function. A temporary solution has been implemented between this routine and COMARG. However, it is anticipated that a firmer solution to this problem will be resolved with the next release.
7.6.3 Symbol Definitions
7.6.3.1 ALVL - Argument LeVeL indicator
This represents the level of argument in the expression being parsed up to this point. Each parenthetical expression represents an additional argument level.
7.6.3.2 CMDARG - CoMmanD ARGument type
CMDARG represents the argument type that can be expected for the command being parsed.
36
7.6.3.3 CMDEND - CoMmanD END flag
The CMDEND flag marks the end of the command set currently being parsed. If the command set is finished, the function that is a part of that command set is completed.
7.6.3.4 DELIM - last DELIMiter parsed
This is the last delimiter parsed from the LINE buffer. If the last token picked had a dollar sign, "$", and the delimiter was a parenthesis, the token was probably a function.
7.6.3.5 ERRTYP - ERRor TYPe to be logged
The ERRTYP symbol is used to communicate error codes to the error handler, COMERR. All of the current legal codes may be found in the discusion of that routine. All of the error messages generated by this routine are mentioned below.
7.6.3.6 FLV - Function LeVel
This is the argument of a FOR loop. It is used to count off the number of arguments used in the function.
7.6.3.7 FLVL - Function LeVeL array
This array holds the last value of FLV for recursive calls.
7.6.3.8 FSAV - Function SAVe array
The FSAV array is the list of legal argument types gotten from the ^COMDEF("FUN") global. The different types are saved as groups delimited by back-slashes, "\".
7.6.3.9 FUNC - The name of the FUNCtion
This symbol will contain the name of the function if it is to be found.
37
7.6.3.10 LINPNT - LINe PoiNTer
LINPNT is the pointer into the LINE buffer. LINPNT is used as a reference in the logging of the function location in the routine being parsed and logged in the ^COM("FUN",FUNC) global.
7.6.3.11 RTNLAB - RouTiNe LABel reference
This routine and label reference is also used to identify the source of the function in the logging process.
7.6.3.12 SFUNC - Stacked FUNCtion description array
The SFUNC array describes the level and the attributes of the current function being evaluated.
7.6.3.13 TFUNC - Temporal FUNCtion
The TFUNC symbol is used to manipulate the token being carried into the routine. If the TOKen does not contain a complete function reference, TFUNC loads the next full function reference. As long as TOK and TFUNC are equal this routine assumes that a function has been found.
7.6.3.14 TOK - TOKen parsed from LINE
The TOKen is an input into this function. This routine would be invoked because TOKen contained a dollar sign. The majority of the code is involved with identifying which function or system symbol has been parsed.
7.6.4 Block Description
7.6.4.1 START - Determine If TOK Contains a Valid Function
This block determines the validity of TOKen reference. Upon validation, the TOKen is identified as a function or a system symbol. This is accomplished in the SPLTFUN block.
38
7.6.4.2 SPLTFUN - SPLiT the FUNction
This block controls the logging and splitting of a function or system symbol. If SPLTFUN was a parenthetical delimiter, the input was a function and to be searched for any subsequent arguments. The condition that ends this scan is the presence of a right parenthesis or the total number of arguments in the function have been exhausted. Prior to the COMARG routine being called, the GETLVL block indicates the type of symbol required for this argument.
7.6.4.3 FLVLCNT - Function LeVeL Control
The FLVLCNT block controls the parsing of function arguments. This block will control the calling of GETLVL and the recursive call to the COMARG routine.
7.6.4.4 GETFUN - GET the details of the FUNction
Get the details of the function from the ^COMDEF("FUN") global. Errors associated with the current function are also identified.
7.6.4.5 GETLVL - GET the function argument LeVeL of activity
Each argument of a function may either be an symbolic reference or numeric or a literal string depending upon the function. This block gives the type of the next argument to be parsed with the COMARG routine.
7.6.5 Errors Generated by This Routine
7.6.5.1 "4G" - Z-Function Found
The Z-Functions are extensions to the language and are implementation dependent. Care should be used when using these functions that incompatability are kept visible. This makes field modification and other implementations easier to perform.
39
7.6.5.2 "7G" - Invalid Function
This error indicates a function was attempted which was unknown to the program. Therefore, a new addition to the language was accomplished or the programmmer used an non-standard method of expressing the function.
40
7.7 COMLAB - Label Definition Handler
7.7.1 Routine Purpose
This routine will extract the label from the line of MUMPS code stored in the LINE buffer.
7.7.2 Environmental Concern
This routine is invoked from COMLINE which insures that there will be some form of routine line stored in LINE.
7.7.3 Symbol Definitions
7.7.3.1 BLKEND - BLocK END flag
BLKEND is used in testing to verify that all commands have been processed within this block and for determining the closure block in process. If another label has been accepted before the closure of the current block, an error condition is reported. This flag is reset when a label is found on the current line in the LINE buffer. The flag will be set in COMMAND if the block of code is unconditionally badly terminated.
7.7.3.2 CMDONE - at least one CoMmand DONE
CMDONE flag may appear to resemble a count, however, the purpose of CMDONE is to indicate that some commands have been processed since the last block was terminated. This allows the code to distinguish between commanets and code installed after a block has been closed and before the new block is opened. Comments are acceptible and are to be ignored. Unblocked commands will be reported as an error.
7.7.3.3 DELIM - last DELIMiter parsed
This is the most recent (or in this case, the first) delimiter extracted from the LINE buffer.
41
7.7.3.4 ERRTYP - ERRor TYPe to be logged
ERRTYP is the error type as identified in the code. ERRTYP is decoded when the COMERR routine is invoked.
7.7.3.5 LABEL - LABEL reference
Label references remain unchanged when no label is on the current LINE being parsed. If a token was removed from the LINE buffer before the first delimiter, it was a label. LABEL is updated with this token.
7.7.3.6 LLCNT - Logical Line CouNT
LLCNT reflects the number of lines which have passed since the last label was located. LLCNT is reset to zero when a new label is located.
7.7.3.7 RTN - RouTine Name
RTN is the current routine that is being parsed. RTN is also used in the process of logging new labels.
7.7.3.8 TOK - TOKen parsed from LINE
TOK will contain a new label if a label has been parsed from the label field of the LINE buffer.
7.7.3.9 TXTNUM - routine TeXT line NUMber
TXTNUM reflects the line number within the COM("TEXT",RTN) global from which the LINE buffer was loaded.
7.7.4 Block Description
There is only a single block invoked in this routine. This is the START block and it is exited when a label cannot be located, or after a label has been validated and logged.
42
7.7.5 Errors Generated by This Routine
7.7.5.1 "3A" - Additional Label Found Before Last Block Closed
The "3A" error is generated when a failure to close a previous block allows the label to spill from a previous block and into the current, newly opened block. Blocks should be explicitly invoked to solidify their relationship to one another.
7.7.5.2 "3B" - Numeric Label Found
Numeric labels convey little information about the block or its function. This does not imply that numeric labels can not be used, however, the use of numeric labels must be justified with a waiver.
7.7.5.3 "7E" - Bad Label Delimiter
COMTOK is the source of TOKen and DELIMiter for this routine. In the event the label field of a line is terminated by a delimiter other than a space, this error will result.
43
7.8 COMLINE - Command Line Parser
7.8.1 Routine Purpose
The primary purpose of COMLINE is to control the loading of the next line of text from ^COM("TEXT",RTN) into the local symbol, LINE. COMLINE also handles the generation of relative routine references for this line in support of logging.
7.8.2 Environmental Concern
COMLINE is invoked by COMFLIN and COMBLK to select the next line to be parsed. COMFLIN calls COMLINE to load the routine title line to the LINE buffer and finish the first control block. COMBLK will control all subsequent calls to COMLINE to load the other lines of the routine being parsed.
7.8.3 Symbol Definitions
7.8.3.1 CCMD - Control CoMmanD buffer
The CCMD symbol is used to keep track of the different types of control commands that have been used on the current line. CCMD will be initialized in this routine when a new LINE is loaded. CCMD represents a string of the first character for each control command from the current LINE buffer being parsed.
7.8.3.2 CTRLCMD - ConTRoL CoMmanD
CTRLCMD indicates the length of CCMD. In that CCMD is a string containing the first letter of each control command on a line, the length of CCMD is the number of control commands found on that line. More than two control commands on a line consitutes an error to be logged.
7.8.3.3 ERRTYP - ERRor TYPe to be logged
ERRTYP is the symbol which identifies an error message to the error handler, COMERR.
44
7.8.3.4 LABEL - LABEL reference
This LABEL reference is the label associated with the current block. The LABEL reference will change when another label is encountered by COMLAB.
7.8.3.5 LABRTN - LABel RouTiNe reference
LABRTN represents the standard label entry reference used by COMERR and a number of the logging references in the COM global. LABRTN is represented in the following form:
LABEL<+Off-Set>^RTN
7.8.3.6 LINE - MUMPS code LINE buffer
The LINE buffer contains the current line of MUMPS code being parsed. All code to be parsed will pass through the MUMPS code line buffer.
7.8.3.7 LINEND - LINe END flag
The LINEND flag is set by the COMTOK routine which is called further into the process via COMMAND. LINEND signifies there are no more commands left on the current line to parse.
7.8.3.8 LINPNT - LINe PoiNTer
LINPNT represents the current position holder in the LINE buffer. Code to the left of this pointer has been parsed, and code to the right and under the pointer is yet to be parsed.
7.8.3.9 LINPRT - LINe PRinT flag
The LINPRT flag indicates whether the current line has been printed by COMERR in a previous error condition. LINPRT is set to one with each new line and reset to zero after the first error is printed in COMERR (from any location).
45
7.8.3.10 LLCNT - Logical Line CouNT
The logical line counter represents a displacement count of the last label defined. LLCNT is reset to zero with each new label.
7.8.3.11 MAXL - MAXimum Length of LINE
The MAXL determines the acceptable length of a line of code. In the routine COMFLIN, MAXL is set to 120. Upon exiting COMFLIN and for the rest of the routine being parsed, MAXL is 80. The acceptable length is set at 80.
7.8.3.12 RTN - RouTine Name
RTN represents the name of the routine that is currently being parsed. RTN is used for the construction of the both reference forms for the current line, LABRTN, and RTNLAB.
7.8.3.13 RTNEND - RouTiNe END flag
The RTNEND flag is set when the last line of code for a routine has been parsed. RTNEND is zero while the routine is being parsed. The absence of the next line from the ^COM("TEXT",RTN) global is the point which initiates the setting of RTNEND.
7.8.3.14 RTNLAB - RouTiNe LABel reference
RTNLAB represents another variation of the LABel RouTiNe form. This form is referenced in a number of places in the model, COMERR, COMFUNC, and COMRLAB. RTNLAB is set in a number of other places. The use of RTNLAB by either COMLSTK or COMSTK may be viewed as slight subversions of the original use of the variable. However, when used by either COMLSTK or COMSTK, RTNLAB is used to provide communication to the COMERR routine for identifying a level of recursion or a label that was identified as recursive.
7.8.3.15 TXTNUM - routine TeXT line NUMber
This pointer points into the COM("TEXT",RTN) global.
46
7.8.4 Block Description
7.8.4.1 START - Control Line Acquisition
The START block initializes a number of line dependent variables and checks for the presence of the next line in the ^COM("TEXT",RTN) global. This will be reflected by TXTNUM. In the event there is a line, LINE is loaded, the LINEND flag is reset. At this point, a search for a label is initiated by using GETLAB.
In the event a line is not available, the LINEND and RTNEND flags are set and the routine is exited prior to accessing the next routine.
7.8.4.2 GETLAB - Extract the label and format
GETLAB is initiated by invoking COMTOK and COMLAB. COMTOK will select the first DELIMiter and any existing label will be contained within TOKen. COMLAB will then load that TOKen into LABEL.
The issue of reference reformatting is also of importance. There are a number of places in this model where this line needs to be referenced in different ways. GETLAB will accommodate the update of these references.
1. RTNLAB - LABEL<+Displacement>
2. LABRTN - RTNLAB^Routine Reference
3. RTNLAB - ^Routine Name:LABEL<+Displacement>
7.8.5 Errors Generated by This Routine
7.8.5.1 "3F" - Program Line Exceeds 80 Characters
This error message is a little misleading. On the first line of a routine, as parsed by COMFLIN, the maximum length is 120 characters. This message may appear to be misleading, however, the string length for the first line was expanded to provide more space for the comments.
47
7.8.5.2 "3H3" - Routine Segment Too Long
This identifies blocks that are over 20 lines long, however, most single functions can easily be completed within this space. In the event difficulty is experienced in adhering to this constraint, the problem needs to be further segmented for a clearer understanding. The definition of another block is probably required as a proper solution.
48
7.9 COMLSTK - Routine Label Stack Report
7.9.1 Routine Purpose
COMLSTK provides a means of displaying the calling structure of the current routine after the routine has been parsed. This structure map identifies all labels and external references by their hierarchy of call.
There may be additional sets of maps that may be generated. These are the undefined entry maps. They are the maps of labels not called explicitly in the routine. Each of these maps begins with an error message. The programmer will need to justify labels that are not explicitly called from the code.
7.9.2 Environmental Concern
COMLSTK needs the name of the RouTiNe and the ^COM("LAB",RTN) global to build the structure map.
Recursion is a difficult phenomenon to describe as it relies upon a positional relationship in order to function. Recursion reflects a situation very similar to the concept of family relationships; e.g., parent, child, etc. In the case of recursion, the relation is similar to the parent, as the parent identified is dependent upon which parent the search begins with. With recursion, the initial parent identified is seen to have a parent, which continues upward through a hierarchical parent group.
As outlined above, in recursion, the relative frame of reference is seen to change, dependent upon a given perspective. COMLSTK employs a similar relationship for identifying labels called from other labels. The hierarchy of call is reflected in the relative frames of label reference.
7.9.3 Symbol Definitions
7.9.3.1 A - scrAtch variable
The scrAtch symbol is used to extract the name of an external reference. The routine name in "A" is used to lookup the external routine reference for the first line comment of the routine mentioned.
49
7.9.3.2 BF - scratch BuFfer
This array will hold the label references for a particular level. All of the labels and external references for a routine are stored in a BF string for that level of the map.
7.9.3.3 CMD - CoMmanD id
CMD normally represents the name of the last command parsed from the LINE buffer. In that the LINE buffer is not being used during this end of routine process, the CMD symbol has little validity as it is commonly used. COMLSTK nulls the CMD symbol because it is used as a communication with the COMERR routine.
7.9.3.4 COM - COMment from external reference
COM is a feature to help identify some of the external references the mapping process may encounter. As each routine is parsed, the first line comments are save. When one of these routines is referenced, that comment line is stored in COM for output when the external reference is plotted.
7.9.3.5 ERRTYP - ERRor TYPe to be logged
ERRTYP is the type of error to be communicated to the COMERR routine. This interface is set with the type of error to be logged and the COMERR routine is invoked.
7.9.3.6 I - scratch poInter array
The scratch poInter array has an entry into each level of the map. It serves as a pointer into the BF array for pointing to the descendent reference called by the parent reference.
7.9.3.7 LABRTN - LABel RouTiNe reference
The LABRTN symbol and RTNLAB are representations of routine and label references that are used in the COMERR routine. They are specially loaded for the calls to COMERR.
50
7.9.3.8 LINPNT - LINe PoiNTer
LINPNT is normally the pointer into the LINE buffer. It is loaded with a horizontal map displacement to align the pointer with the routine name on the map when an error is generated from COMERR.
7.9.3.9 LINPRT - LINe PRinT flag
The LINPRT flag calls for the LINE buffer to be printed from COMERR. LINPRT is reset so that the LINE buffer will not be printed at all during this post routine scanning process. The LINE buffer contains no germain information for this process.
7.9.3.10 LISDEV - LISt DEVice
LISDEV represents the LISt DEVice that accepts most of the output generated by the Compliance Checker. The exceptions are the initial routine entry and the run-time status reports requested by the user. These exceptions are sent to the default device, 0.
7.9.3.11 LP01 - LooP counter #01
LP01 is used to drive the process of loading the references called by the routine currently in the SCN symbol. Each of these references will be stored in the BF string array with each reference being separated by commas.
7.9.3.12 LP02 - LooP counter #02
LP02 is used to check for any labels that have not been referenced in the initial structure map.
51
7.9.3.13 LP03 - LooP counter #03
LP03 is used to draw the structure maps for the main entry point and the unreferenced labels. The mapping function supports the display feature where in a string, "! ", is printed at every position not controlled by a recursion. A "+-" is printed at the juncture of a label that is recursive. Any recursion subordinate levels generate a "--" string for that label's line.
TEST ! INIT ! START ! ! PARSE ! ! ! DECODE ! +-----START ^ ^ ^ ^ ^ | | | | + Current label | | +-+-- Subordinate to a recursion | +------ Recursive position +-------- Non-Recursive position
7.9.3.14 LST - Length of STream
LST represents the number of 2 column positions a label is to be displaced when mapped.
7.9.3.15 M - recursion Mark
This is the level where a recursion was located. As LP03 passes this point, the designated symbol changes from a verticle to a plus sign. Subsequently, when LP03 has passed this point, the designated symbol changes to a minus signs to indicate horizontal association.
7.9.3.16 MORE - MORE undefined labels to map
MORE is a flag and an array. The flag indicates the presence of undefined labels. Each element in the MORE array is an unreferenced label encountered during the parse, but specifically unreferenced in the calling structure.
Should one of these labels be referenced during the mapping of another undefined label, the label will not be reiterated.
The MORE array is killed upon entry and exit to insure that no
52
unexpected values are present prior to the execution of this module.
7.9.3.17 MSG - previously defined MeSsaGe
The "previous" message is a means of saving paper and reiteration. This message is initialized with "< STRUCTURE PREVIOUSLY DEFINED >". After this message has been printed once, it is replaced with the shortened version, "< PREVIOUS >>>". Both messages indicate that the current routine in PR has been previously mapped into a position further to the right, than the current level. The position is considered because the structure is elaborated far enough to the left that all of the paths to the right will be displayed.
7.9.3.18 MSG2 - recursive MeSsaGe #2
The recursion message is more direct. If the routine being mapped is found in the superior direct calling stream, the routine is recursive and does not need to be followed any further.
The message is also displayed in two parts. The first occurrence spells out the complete message. The second is an abreviated form.
7.9.3.19 NXT - NeXT label to test
Each of the symbols for this routine are scanned to determine if they contain an entry into the ^COM("LDONE") global. If there is a positive indication, the label was processed during the first mapping process. A negative indication means that this is an unreferenced label which is drawn out as the root for another map.
7.9.3.20 P - Position pointer
This is the level pointer into the map being built. The first routine level is 1. The child references that are called from that level are designated as level 2, etc.
53
7.9.3.21 PASS - PASS to the next level flag
PASS is the authorization flag for the routine to be interpreted as recursive for a particular label. PASS will deny access to recursion when;
1. The current label, PG(P), is discovered in the current active calling structure, PG(M).
2. The current label has been defined at an earlier level.
7.9.3.22 PG - ProGram name Array
The PG array contains the chain of controlling routines that have been traversed up to this point. The initial entry point is at level one. A routine that it calls is at level 2. This level will be replaced with the next label controlled by the initial entry point. The level limit of this calling structure is indeterminate.
7.9.3.23 PR - PRogram name
PR contains the same label reference that are contained by the PG(P) array element. This is the current label being traversed, and a shortened reference to the PG(P) reference is provided.
7.9.3.24 RT - scratch RouTine name
RT is used to traverse the ^COM("LREFS") global for label references. As each reference is located, it is stacked into the BF(P) buffer for this level of P. The RT symbol is expendable beyond the NEXTREF and LOADBF blocks.
7.9.3.25 RTN - RouTine Name
RTN is the input module that identifies what routine is being mapped. RTN will remain unchanged during the course of this routine.
54
7.9.3.26 RTNLAB - RouTiNe LABel reference
RTNLAB and LABRTN are communications symbols with the COMERR routine. They are modified to provide back tracking capability for additional utilities that are not yet developed.
7.9.3.27 SCN - SCaNning label name
The SCN symbol is the new superior calling label that will control the descending levels of call. All of the labels and external references that are called from this level will be elaborated in the next level. At that point, each of the called labels will become SCN and their calling descendency will be elaborated.
7.9.3.28 TMP - scratch variable
TMP is used in the STEPR block which is designed to contain the two character string that will indicate the condition of the calling structure.
1. "! " - Common Descendency
2. "+-" - Recursive at this level
3. "_" - Recursive prior to this level
7.9.4 Block Description
7.9.4.1 INIT - Setup for Routine Mapping
The INIT block provides the initial conditions for the routine. These include
1. P - the stack Pointer to 1
2. PR and PG(1) to the Routine name
3. Prepare for COMERR
1. LINPRT flag is turned off for the COMERR
2. CMD is cleared
55
4. Kill the ^COM("LDONE") flag and the MORE array
5. Initialize the MSG and MSG2 messages
6. Establish COM if a comment exists for this routine.
7. Write the report heading
7.9.4.2 START - Control Mapping Process
This block will control the generation of the primary routine structure map. The remaining labels for this routine are checked for reference. For other labels that were not referenced, additional structure maps are generated until all labels have been referenced.
7.9.4.3 EXIT - Cleanup After Mapping Process
This block kills off the expendable symbols from the symbol table. This cleanup operation can enhance the execution speed of some implementations.
7.9.4.4 PASS2CK - Identify Any Unidentified Labels
The PASS2CK block identifies any labels that have yet to be referenced within a structure. The MORE flag and array indicate that unreferenced elements exist.
7.9.4.5 PASS2 - Map Unidentified Labels
Set up for the generation of an undefined label map. When the symbols have been prepared, the NEXTREF block is invoked to build a map from the starting point of the undefined reference. This is one of the major objectives of this package, namely to identify program Gordian knots designed intentionally or accidentially by a programmer.
56
7.9.4.6 NEXTREF - Recursive Mapping Block
NEXTREF is the recursive interface which saves an incredible amount of additional in-line code. The label is picked up from the PG(P) array. If there are any descendents to this label in the ^COM("LREFS") global, the rest of this block is executed to map those labels. The level pointer, P, is incremented and the descendents are gathered for the label stored in SCN. The called labels for this level will be accumulated within the BF(P) array in the LOADBF block.
The parts of this newly opened level are taken from GETPR which describe the current reference. The condition of that routine is reflected in the symbol, PASS. PASS determines whether a recursion was located or whether the label has been elaborated yet. Once the definition of the label has been obtained and the label failed to contain a recursion or reiteration, this block will be called again to follow this label's descendents. Once this level has been exhausted, the level pointer is decremented.
7.9.4.7 LOADBF - LOAD the level calling array, BF
This block stacks the labels that are referenced into the string, BF(P). There may be a problem with this technique when there are more that 255 characters of labels and commas. Commas separate the labels or references stored in the BF(D) string.
7.9.4.8 GETPR - GET the next PRogram
This block selects the actual label to be parsed from the BF(P) buffer. The COM buffer is initialized to prevent old comments from being carried over into the next label reported. Routine references are the only references that have a comment. The routine name is split into a scratch variable called A.
Should "A" contain a routine name, the COM buffer attempts to pick up the associated comments. The comment will be printed to the right of the routine reference.
Each label is compared against the ascendent parent levels that control it, (stored in PG(M)). Should the label be located as its own parent, M will contain the level the label is recursive with. If the label is found not to match itself, M is loaded with a large number, 99. There is nothing magic about the number 99. STEPR is then called to map this label to the structure as constructed thus far.
The label is then reported as being previously defined or a
57
recursion. In either case, the PASS flag is set to 0. Otherwise, PASS remains 1 and the level is updated in the ^COM("LDONE") global. PASS allows access to additional child references and ^COM("LDONE") helps to identify unreferenced labels.
7.9.4.9 STEPR - Display Label Stepping Structure
This is the mapping process for each label identified. The level pointer, P, determines the depth that the label will map. Each level is two characters wide. The dependency from label to label is mapped as one of three different representations.
1. "! " - Is Controlled From This Level Above
2. "+-" - Is Recursive With This Level Above
3. "--" - Is Recursive Prior To The Level Above
7.9.4.10 RECURS - Recursion Report
Once a recursion has been identified, the following procedure is used to record the event and log the error.
1. Reset the PASS flag to inhibit tracking this calling structure any further. From this point forward, the calling structure is infinite.
2. Write the inline recursion message and reset it to the shorter message for any future recursion message.
3. Establish the interfaces with the error handler, COMERR.
1. Set LINPNT to coincide with the position of the recursive label.
2. Establish RTNLAB and LABRTN line references to something more meaningful.
3. Set the ERRTYP symbol to the appropriate error, "3D1".
4. Call the error handler, COMERR.
58
7.9.5 Errors Generated by This Routine
7.9.5.1 "3D1" - Potentially Recursive Block Found
Recursion may be viewed as having potentially dangerous effects, however, given the proper limitations, it can be an incredibly useful and powerful tool. Beyond these bounds, it can be devastating. It is easy for a programmer to inadvertently include recursion in the execution of a MUMPS application. After running the Compliance Checker against some large packages, the programmer may be surprised at the hidden recursions and implied loops that can be encountered.
7.9.5.2 "3I" - Unreferenced Label
These are usually alternate entry points into the routine, however, the use of alternate entry points are not considered as good practice. One potentially valuable application of the unreferenced label is the use of an error trap label kept within the potentially explosive routine. The error trap can be used to force a reloading of the routine to recover the process that caused the error.
59
7.10 COMMAND - Command Handler
7.10.1 Routine Purpose
The COMMAND module is used to parse a full command from the LINE buffer. COMMAND separates the command field from the argument field of the command set and validates the command type. COMMAND controls the parsing of the arguments associated with this command. It also validates that the command may have a postconditional in the command.
7.10.2 Environmental Concern
COMMAND is coded to expect the LINE buffer to be established and the LINPNT symbol to be pointing at the next command token. Control is returned to the calling routine upon the completion of a complete command set. That condition may be the trailing space after the argument field or the LINEND flag being true.
7.10.3 Symbol Definitions
7.10.3.1 ACNT - Argument CouNT
The ACNT symbol is the argument of a FOR loop. ACNT is used to drive the call to COMARG. As the name implies, ACNT provides a count of the arguments parsed from the command.
7.10.3.2 ALVL - Argument LeVeL indicator
ALVL is initialized with each command parsed, and is killed after the command has been parsed.
7.10.3.3 APST - Argument PoSTconditional flag
The APST flag indicates whether the last argument of a GOTO command contained a postconditional. This is important for use in identifying unconditional branching and denial of access to code following this command. It helps to identify the end of a block.
60
7.10.3.4 ASET - current Argument SET level
The ASET symbol identifies the level that a symbol appearing on the left side of an equals sign is to be set. All other usages are references or kills.
SET ABLE=12,BAKER=20 ^ ^ +--------+---- ASET is at level 1
SET (ABLE,BAKER)=20 ^ ^ +-----+------ ASET is at level 2
7.10.3.5 BLKEND - BLocK END flag
The BLKEND flag identifies the termination of a block of code. BLKEND is set when an unconditional GOTO or QUIT is not found to be under the control of a control command (such as IF, FOR, or ELSE) or a postconditional.
7.10.3.6 CCMD - Control CoMmanD buffer
This string scalor holds the first character of any control commands found on the current line. This assists in determining whether there were more than 2 control characters on a line. In this situation the length of CCMD is greater than two as reflected in CTRLCMD.
7.10.3.7 CMD - CoMmanD id
The CMD is the name of the command that is currently being parsed.
7.10.3.8 CMDARG - CoMmanD ARGument type
The CMDARG is the types of arguments that are expected for this command. The definition is drawn from the ^COMDEF("CMD") global.
61
7.10.3.9 CMDCNT - CoMmanD CouNT
The CMDCNT is the number of commands parsed up to this point on the line. CMDCNT is updated from COMBLK which drives this routine. CMDCNT is the argument of a FOR command within the COMBLK routine.
7.10.3.10 CMDDEF - CoMmanD DEFinition
CMDDEF is the definition of the command being parsed as defined in the ^COMDEF("CMD") global. It will be used to set the CMDMSK, CMDTYP, and CMDHLD.
7.10.3.11 CMDEND - CoMmanD END flag
The CMDEND flag indentifies the end of a command set. CMDEND is set in the COMARG routine after the last argument has been parsed.
7.10.3.12 CMDHLD - CoMmanD HoLD
The CMDHLD symbol keeps the command type definition to reload the CMDTYP symbol between each argument.
7.10.3.13 CMDMSK - CoMmanD MaSK
CMDMSK is a set of three flags for use in indicating the following conditions for every parsed command. Individual Command may have;
1. A postconditional on the command
2. Argument sets
3. Postconditionals on the arguments.
62
7.10.3.14 CMDONE - at least one CoMmand DONE
The CMDONE counter identifies that a number of commands have been processed. This is important, as it allows for a bridge of the gap between the end of one block and the beginning of the next. A block ends with an unconditional surrender of control to the invoking level. The presence of commands between that block end and the next label indicates that those commands cannot be executed without some non-standard practices. In this manner, the CMDONE counter precludes signaling an error on comment lines that lie between the end of one block and the label of another. In brief, if there were no commands processed between the end of one block and the beginning of the next, there was no problem.
7.10.3.15 CMDTYP - CoMmanD TYPe
This symbol identifies the types of actions that a command can have. The types are;
1. B - Break Command
2. C - Control Command (ELSE, FOR, GOTO, IF, QUIT, XECUTE)
3. D - Device Command (OPEN, CLOSE, USE)
4. E - Execution Command (DO, EXECUTE, GOTO)
5. I - Input/Output Commands (PRINT, READ, WRITE, ZLOAD, ZINPUT, ZPRINT, ZWRITE)
6. S - Set Command (SET, READ)
7. T - Terminal Command (Ends A Block, QUIT, HALT, GOTO)
8. X - Excluded Command (Non-standard Command Structure)
7.10.3.16 CPST - Command PoSTconditional flag
Should the command being processed have had a postconditional, the CPST flag is set. It means that this command may be executed conditionally. The end of a block may occur if, for example, a GOTO command and its arguments are not postconditionalized or in the range of a control command. These control terminations are hard to find in most poorly written applications.
63
7.10.3.17 CTRLCMD - ConTRoL CoMmanD
Everytime a control command is encountered in a line of text, the first letter of the command is appended to the end of CCMD. When the last delimiter is parsed and LINEND is set, the length of CCMD is stored in CTRLCMD. It will be tested to be two or less or only two control commands allowed per line.
7.10.3.18 DELIM - last DELIMiter parsed
This is the last delimiter parsed from the command buffer. It is used to indicate if a comment, the beginning of the argument set, the beginning of a postconditional, or the end of an argument has been found.
7.10.3.19 EQUFLG - EQUals sign FLaG
The equals sign flag, EQUFLG, is initialized in between each argument. This resets it for multiple argument fields in the SET command. This flag helps to identify the locations where symbols are set or just being referenced. The left side of an equals sign is a SET (in most cases) and the right side is always a REFerence (direct or indirect).
7.10.3.20 ERRTYP - ERRor TYPe to be logged
This symbol is used to communicate the type of error that is to be logged by the COMERR routine.
7.10.3.21 FLV - Function LeVel
The FLV symbol is created in the COMFUNC routine and killed here to prepare for the next command.
7.10.3.22 FLVL - Function LeVeL array
The function level is created and used by the COMFUNC routine. It is required for repeated nested calls to COMFUNC. It should only be killed after leaving the command set being parsed. This symbol is killed within this routine.
64
7.10.3.23 FSAV - Function SAVe
This is also only used within the COMFUNC routine and is used within the parsing of a single command set. This symbol is only killed in this routine.
7.10.3.24 LINEND - LINe END flag
The LINEND flag is set by the COMTOK routine which is called quite a ways down calling hierarchy via COMMAND. It signifies that there are no more commands left in the current LINE buffer to parse.
7.10.3.25 LP02 - LooP counter #02
The latest versions of MUMPS are still strict about the space between the command field and the argument set for each command. They have relaxed on the requirement for exactly one space between one command set and the next. There can be as many spaces as desired between one command set and the next command. There has to be at least one space between command sets or an end of line ending the last command set. This loop is used to ignore any excess spaces. The symbol is extremely expendible.
7.10.3.26 LVLEND - argument LeVeL END
LVLEND is just part of the cleanup from this routine. It is not used above this point and so need not survive above this point in the calling hierarchy.
7.10.3.27 OKARG - OK for ARGuments
This is one of the flags set from CMDMSK. It identifies that this command may have arguments.
7.10.3.28 POSTC - POSTConditional flag
The POSTC flag indicates that a postconditional evaluation is in progress.
65
7.10.3.29 PSTYP - PoStconditional TYPe indicator
There are two types of postconditionals, one for the command and one for the arguments. Either, both, or no postconditional may occur in the same command set. This counter indicates which. Its values are 1 for command and 3 for arguments. The disparity of one and three are the positions in the CMDMSK for these two bits of information.
7.10.3.30 SLVL - Saved set LeVeL
SLVL points to the parenthetical level that a SET command will actually cause a change in a symbol in the syntax of the MUMPS language.
S A="this is a test" SLVL = 1 ^
S (A,B,C(D))=100 SLVL = 2 ^ ^ ^
S A(B,C)=100 SLVL = 1 ^
7.10.3.31 SVSET - SaVe SEt Type
This is a storage place for the ASET information extracted from the ^COMDEF global.
7.10.3.32 TMPT - TeMPorary Token
This is a scratch variable used for the validation of the CoMmanD as currently stored in the TOKen.
7.10.3.33 TOK - TOKen parsed from LINE
This is the last token extracted from the LINE buffer. At the beginning of this routine, TOK contains the command being brought in. In that capacity, TOK is used to validate the command, in VALCMD, and verify the command, in CMDVRIF.
66
7.10.4 Block Description
7.10.4.1 START - START of process
The COMMAND routine sets the state variables for the next command to be parsed.
7.10.4.2 EXIT - Clean-up After The Command Set
The EXIT block is the common terminator for the parsing of a command set. EXIT insures that all of the commands are terminated in the same fashion.
7.10.4.3 ARGINIT - ARGument INITialization
This block will initialize the argument specific variables at the beginning of the next call to COMARG and as introduction into that section.
7.10.4.4 COMGET - COMmand GET
The parsed command is still in the TOKen symbol at this point. VALCMD is called to validate the command parsed as TOK. Upon return from that operation, the delimiter is examined for the command we have validated. A semi-colon indicates that a comment follows the command immediately. Technically, this is illegal. Most MUMPS interpreters will generate an error on a semi-colon following immediately after the command without the terminators for the command or argument fields (spaces).
Space is the second delimiter that may be expected after a command. It is the most common delimiter and separates the command from the argument field and the argument field from the next command.
The third delimiter is the colon. It introduces a postconditional expression. The postconditional will eventually be terminated by a space that will end the command field.
67
7.10.4.5 VALCMD - VALidate the CoMmanD
The VALCMD block identifies the type of command being parsing. Should the command in the token have been spelled out, control may be returned to the calling block.
The CMDVRIF block is performed, if command can't be found from the token directly. When control returns from CMDVRIF, TOK should contain the name of the command. If it doesn't, control returns to COMGET without creating CMDDEF. Without CMDDEF, an error will result from the START block.
Assuming that the right command has been found, CMD is set to the name of the command stored in TOK and CMDDEF is created from the ^COMDEF("CMD") global.
7.10.4.6 DEFCMD - DEFine CoMmanD
DEFCMD splits the attributes from the CMDDEF symbol. Waiverable errors may result from one of the attributes extracted. This is dependant upon the command being parsed. The BREAK, GOTO, ELSE, and XECUTE commands are some of the commands that generate such errors.
7.10.4.7 BLKCHK - BLocK terminator CHecK
The BLKCHK block is used to identify commands that terminate the block of code being parsed. Block termination is the unconditional end of program flow within a block. This allows us to identify that unlabeled or in-line code following an unconditional terminator is unreachable by acceptable standard means. The NOACS block is called to report this error.
7.10.4.8 NOACS - NO ACceSS check
The NOACS block issues an error message when invoked which warns that there is no access to the command being parsed. This happens when there is an unconditional redirection of program execution that excludes this code.
68
7.10.4.9 CMDVRIF - CoManD VeRIFication
There are a number of commands which have migrated into the command proper from the "Z"-command extention area. Should the first character of the parsed command be a "Z", it is extracted off and compared with the valid commands in the ^COMDEF global. If the name gotten from the global doesn't match the token, it has failed to be identified. If it is identified, the TOKen is replaced with the name extracted from the global.
7.10.4.10 CONTROL - CONTROL command handler
Control commands are a special case. They add complexity to the execution of a line of MUMPS code. As such, the goal is to keep the number of these control commands to a minimum of two control commands per line. The CONTROL block keeps track of the control commands identified on the current line.
If a control command is to occur on a line of code, it should be the first command on that line. An error is generated if the first control command is not the first command on the line. Having the first control command as the first command on the line makes the control much more visible and supportable.
7.10.5 Errors Generated by This Routine
7.10.5.1 Explicit Errors
The explicit errors are those that are specifically tested for within the code. This routine tests a number of them as evidenced below.
7.10.5.1.1 "3H1" - Block Badly Terminated
This occurs when a terminator command has been executed after the first command on the line and until this point, no other control commands have been parsed from the LINE. A terminator command is a QUIT or GOTO which surrenders or redirects control somewhere else. Both of these commands may be postconditionalized. The GOTO may be postconditionalized at the command or the argument. The symbols CPST and APST indicate if there was a postconditional on the command and/or on the last argument.
Terminator commands which are to be executed unconditionally within the flow of the code are of significant interest.
69
IF TEST S A=5 GOTO ABLE ; does not terminate the block because ; of the IF command preceding the GOTO
S A=5 GOTO ABLE ; does terminate the block because there is no S A=10 ; path to this line of code.
S A=5 G:B>5 ABLE ; does not terminate the block because of the S A=10 ; possible non-execution of the GOTO (CPST=1 ; and APST=0).
S A=5 G ABLE:B>5 ; does not terminate the block because of the S A=10 ; possible non-execution of the GOTO (CPST=0 ; and APST=1).
S A=5 G ABLE:B>5,BAKER ; does terminate the block because of the S A=10 ; unconditional execution of the last ; argument of the GOTO command (CPST=0 ; and APST=0).
7.10.5.1.2 "5A" - Control Command Found After the First Command
The purpose of establishing a consistent programming style is to make the control and flow of the applications so visible that any other programmer (primarily those in the programming group) will be familiar with the intent of the code.
One of the single most important means of controlling this is by having control commands appear as the first command on the line it will occur on. A control command is one that controls the possible execution of commands to the right of it and on the same line. It is a command that can redirect the flow of execution. These commands are FOR, IF, ELSE, GOTO, and QUIT. In the case of two control commands on the same line, the first control command should be the first command on the line.
7.10.5.1.3 "5B" - More Than 2 Control Commands Found on the Same Line
To carry the previous error one step further, there should be no more than two control commands per line. This has the effect of keeping the flow simple. Should more control commands be needed, they can be completed within a DO called block. If a programmer finds he needs more than two control commands on a line, it usually means the programmer has not segmented the problem well enough.
70
7.10.5.1.4 "7A" - Invalid Command
This error indicates that the COMMAND routine was unable to determine which command was being specified. It normally means a typo or a quote has been fogotten. This will often cause problems in routine tables if they are not commented out.
7.10.5.1.5 "7I" - Argument NOT Allowed For This Command
There are a number of commands which do not allow arguments, ELSE and QUIT. Should the call to COMARG return with an argument identified, this error will result.
7.10.5.1.6 "7K" - Unaccessible Commands
In the second example of error "3H1", the second SET command could not be reached (legally) because of the unconditional GOTO in the execution stream. This is an error that should be justified or removed. This could mean the programmer has forgotten the original purpose for the code or is hiding some 'cute trick' code. Remember that data and code are easy to hide in MUMPS. It is important to keep this kind of potential trap under control.
7.10.5.2 Implied Errors
The implied errors are those supplied by the COMDEF global because a particular command was found. The set of commands that may be invoked by this means are shown below.
7.10.5.2.1 "4A" - BREAK Command Found
The BREAK command is very useful in the development environment. But it can be a window into disaster within a production program. Once a BREAK command has been executed, a production user is no longer trapped within the security of the application shell. Nothing is protected within the current production user space. The BREAK command is used primarily to help catch programmer oversites.
71
7.10.5.2.2 "4B" - ELSE Command Found
The ELSE command is an unfortunate problem. Many have associated the word ELSE with structured applications. This is not the case in MUMPS. The ELSE is a source of a potential ambiguity. Great care should be exercised in the use of this command. Seemingly simple situations may behave unpredictably should the ELSE be used. A great potential for unexpected error can result by simple code changes in the vicinity of the ELSE command. A waiver is highly recommended to record the intent of the ELSE command.
7.10.5.2.3 "4C" - GOTO Command Found
The GOTO command is notorious for the type of problems that non-structured applications suffer. Control over this command can enhance supportability greatly. Waivers for this command should be accepted only under the most strict of conditions. One such justification would be the implementation of the 'CASE' construct. A case construct is demonstrated in Chapter 11, the Standards Document.
7.10.5.2.4 "4D" - XECUTE Command Found
The XECUTE is included in this list of restricted commands because it can be used to hide any of the other restricted commands from the Compliance Checker. The argument of the XECUTE command can be built at run-time by a clever programmer to perform any operation available in the MUMPS language. This includes the other commands that are restricted, GOTOs, ELSEs, VIEWs, BREAKs, anything. The XECUTE command is very good at hiding "clever" code from the support or quality assurance analysts. A waiver should accompany any XECUTE command to describe the expected code to be operated upon as the argument of the command. A justification is required for the use of this technique over a more conventional approach.
7.10.5.2.5 "4E" - VIEW Command Found
The VIEW command is poorly defined in the MUMPS 1984 ANSI Standard and is very implementation specific. This is used all too often for extended services to an application and is a potential security breach. A waiver should definitly accompany any use of the VIEW command in a production routine.
72
7.10.5.2.6 "4F" - Z-Command Found
The Z-commands are extensions. They are a portability issue and are easily handled with a waiver. The waiver should describe the expected result or service to be derived.
73
7.11 COMPKGE - Package Parsing Control
7.11.1 Routine Purpose
The COMPKGE routine controls the transition from routine to routine. It also provides a means of supplying status for the package during run-time.
7.11.2 Environmental Concern
The COMPKGE routine intercepts run-time input from the keyboard of the default device. COMPKGE will read as many key inputs that the user may queue requesting status.
7.11.3 Symbol Definitions
Many of the symbols mentioned in this routine are actually just being killed off as a means of house keeping. In later versions of the Compliance Checker, an attempt will be made to include a method of optimizing the elimination of symbols within a package. This will allow the symbol tables to be kept to optimal size for increased speed of execution and data management.
7.11.3.1 %T - current Time
This is a utility variable that contains the current date and time in a human presentable format.
7.11.3.2 APST - Argument PoSTconditional flag
The argument postconditional flag is a means of telling if the last argument of a GOTO command was postconditionalized.
7.11.3.3 ASET - current Argument SET level
This symbol is killed in this routine. It is created in the COMMAND routine which is a couple of levels deeper down in the calling hierarchy.
74
7.11.3.4 BLKCNT - BLocK CouNT
BLKCNT is the number of blocks that have been parsed in a given routine. This symbol is killed in this routine and is not used at this level.
7.11.3.5 CCMD - Control CoMmanD buffer
The Control CoMmanD buffer stacks the control commands as a string so that the type and number of control commands can be examined. This symbol is only killed in this routine.
7.11.3.6 CMD - CoMmanD id
The CoMmanD id is the identification of the last command parsed. That command for that routine should be no longer needed. This symbol is only killed in this routine.
7.11.3.7 CPST - Command PoSTconditional flag
The CPST symbol is associated with the determination of the end of a block of code. It is the condition flag indicating a postconditional existing on the last command field parsed. The CPST symbol is only killed in this routine.
7.11.3.8 ERNUM - ERror NUMber type count
This is the number of different kinds of errors that have been accumulated thus far. ERNUM is used to determine if there are any errors to be displayed. It does not survive this routine.
7.11.3.9 INKEY - INtercept KEY
The INKEY symbol is used to intercept the run-time requests for status. The last character intercepted by TMP is the value kept to trigger the type of error report. Additional features may be added for additional levels of support and control of the run-time package.
75
7.11.3.10 LABEL - LABEL reference
LABEL is the last label parsed from the last routine and is not needed any longer. LABEL is only killed in this routine.
7.11.3.11 LINE - MUMPS code LINE buffer
This is the buffer that will hold each line of MUMPS code to be parsed for each routine. At this point it is no longer needed. LINE is only killed in this routine.
7.11.3.12 LINEND - LINe END flag
This flag indicates the end of the parsing of the current LINE buffer. LINEND is only killed in this routine.
7.11.3.13 LINPNT - LINe PoiNTer
LINPNT is a companion state symbol that points to the last point that was being parsed within the LINE buffer. This symbol is only killed in this routine.
7.11.3.14 LINPRT - LINe PRinT flag
LINPRT is a symbol used in the COMERR routine to indicate that the LINE buffer was printed with a previous error message. In that the LINE buffer was just killed, there seems little need for LINPRT any longer. This symbol is only killed in this routine.
7.11.3.15 LISDEV - LISt DEVice
The LISt DEVice is used by the Compliance Checker to list errors, and structure listings. LISDEV is set in the COMPLY routine if not previously set or prior to the run of COMPLY. LISDEV is used in the COMPKGE routine to redirect output to this device after the run-time status report has been displayed. This should be the single symbol that will survive a production run of COMPLY.
76
7.11.3.16 LLCNT - Logical Line CouNT
LLCNT is the number of lines since the last line that had a LABEL defined. Now that LABEL has been killed, so will this one. The LLCNT symbol is only killed in this routine.
7.11.3.17 LP00 - LooP counter #00
LP00 is used to drive the routine parsing events and the QUERY for status. As true to the tradition of a scratch loop symbol, it gets killed in this same routine.
7.11.3.18 LP01 - LooP counter #01
LP01 is used to drive the search for run-time user input. LP01 is used to dump the input buffer between each routine. It, too, gets killed before leaving this routine.
7.11.3.19 LST - Length of STream
This symbol is only killed in this routine.
7.11.3.20 MAXL - MAXimum Length of LINE
This is the boundary for the length of the LINE buffer. Any line over the specified length, causes the generation of a length error. MAXL is only killed in this routine.
7.11.3.21 NUMER - NUMber of ERrors
This is the number of total errors for all routines thus far. NUMER is used as a flag in this routine to indicate that there is something to report for a status request.
7.11.3.22 PKGEND - PacKaGe END
The PKGEND flag is set in COMRTN and indicates that there are no more routines to be parsed. PKGEND marks the division between routine parsing and package analysis.
77
7.11.3.23 PKGID - PacKaGe IDentifier
PKGID is the three letter prefix used to tie routines of a package together. PKGID is created within this routine.
7.11.3.24 POSTC - POSTConditional flag
POSTC is the flag that indicates that a postconditional is in progress. The POSTC symbol is only killed in this routine.
7.11.3.25 PSTYP - PoStconditional TYPe indicator
PSTYP is only killed in this routine.
7.11.3.26 RTN - RouTine Name
The routine name is used to build the PacKaGe IDentifier that will be used to compare the names of invoked routines to be parsed. RTN is also used between the routine status reports.
7.11.3.27 RTNEND - RouTiNe END flag
RTNEND is only killed in this routine.
7.11.3.28 RTNLAB - RouTiNe LABel reference
RTNLAB is only killed in this routine.
7.11.3.29 SPCR - SPecial ChaRacter string
SPCR is only killed in this routine.
7.11.3.30 TMP - scratch variable
The TMP symbol is expendable after the LIST2DO block. TMP provides a traveler symbol to thread the list of routines that are still waiting to be parsed. The list of queued routine names is stored in the ^COM("NXT") global.
78
7.11.3.31 TOK - TOKen parsed from LINE
The TOK symbol is only killed in this routine.
7.11.3.32 TTOK - Temporary TOKen storage
The TTOK symbol is only killed in this routine.
7.11.4 Block Description
7.11.4.1 START - Package control block
The START block establishes the PKGEND flag and the PKGID string before beginning the parsing of each routine in turn. This process continues until there are no more routines to be parsed. The QUERY block checks to see if the user at run-time has requested a status. After that, the package parsing continues to the next routine, as called by COMRTN.
Once all of the routines have been parsed, (ie. PKGEND is 1), many of the symbols used in parsing can be disposed of. Access to this area of code is controlled by the PROD flag.
As a customization to the Compliance Checker, the symbol table cleanup may be inhibited to allow the examination of most of the symbols between runs. This feature is applied by resetting the value of PROD in the COMPLY routine.
7.11.4.2 QUERY - Runtime query block
QUERY performs a zero time read on the default device. This triggers a chain of events that result in the generation of a runtime status report. Additional single character reads are performed to get the very last character input and to clear the input buffer. At the end of the process, INKEY will contain the last character that was in the input buffer.
The LIST2DO block is performed and then print control is returned to the LISt DEVice, the device which the user set or allowed to default.
79
7.11.4.3 LIST2DO - List of routines left to do
LIST2DO is the run-time status report of the routines left to do. LIST2DO derives the routine names from the ^COM("NXT") global. If there were no more routines found in the list, a "LAST ROUTINE" message is displayed. This may be misleading. The user will get this message for the first routine as it begins to be parsed because there have been no other routines identified to this point. There may be all sorts of external references that this routine will sponser, but they have yet to be parsed.
The second part of the status is an error report. This is cumulative for the package thus far. The user can get this extra report by entering a capital letter "E" during the run. As mentioned before, please be patient. The Compliance Checker package is designed to interrogate the keyboard only between routines. If this is too infrequent, these two blocks of code may be moved to an other, higher frequency block, such as COMLINE. This would allow status to be retrieved between every line parsed.
These last two blocks don't change any of the runtime tables so there should be little impact on the model to move them.
80
7.12 COMPLY - Compliance Checker Entry Point
7.12.1 Routine Purpose
COMPLY is the start of The compliance Checker. The VAX version allows for the specification of a LISt DEVice that will hold the output of the analysis. The PDP DSM-11 version assumes that the default spool device will be unit 3. The user will only have to supply the name of the starting routine for the package to be analyzed.
To test out the Compliance Checker implementation, run COMPLY and feed COMPLY to itself. That is, when the prompt asks for the entry of the routine name to analyze, enter COMPLY. The parsing will take about 10 minutes on most machines. It may take longer on some implementations than others.
After COMPLY has been running for about a minute, hit any key. As soon as the current routine is finished, a status report will be listed to the default device. It will only check the keyboard between routines. Hitting the letter "E" will request a report on the number and types of errors encountered thus far. It will respond to the last character that was entered. So if a space was entered and an error status error report was really desired, enter an "E" key. The full error report will be generated just before the next routine is generated.
The runtime status may not work if you do not have type ahead enabled. The Compliance Checker works well for DSM and DSM-11.
7.12.2 Environmental Concern
The COMPLY routine has few environmental requirements since it is the prime entry point for the package. The only symbol that should survive this package should be LISDEV, the list device name.
7.12.3 Symbol Definitions
Many of the symbols here are being initialized at the beginning of the run or killed following the run.
81
7.12.3.1 %T - current Time
%T is the single product of the COMTIME routine. The date and time is displayed in a standard printable format and reflects the time that the COMTIME routine was invoked. It is called at the beginning of every routine parsed and at the start and end of the COMPLY run.
7.12.3.2 ABRT - ABoRT flag
The ABoRT flag is set in the COMRTN routine upon the failure of the loading of the next routine to be parsed. IT is false else where. ABRT is both initialized and eliminated at this point because COMPLY is the lowest common juncture for COMSTORE and COMRTN. COMSTORE requires ABRT to exist and COMPLY initiates it first.
7.12.3.3 BLKEND - BLocK END flag
The BLocK END flag is both initialized and killed in the scope of this routine. BLKEND is used in the COMBLK routine.
7.12.3.4 CMD - CoMmanD id
The CoMmanD symbol is initialized to insure that it exists when referenced by COMERR which is called ubiquitously.
7.12.3.5 CMDCNT - CoMmanD CouNT
CMDCNT is the count of commands processed thus far. It is used as the argument of FOR commands in COMBLK and COMFLIN. CMDCNT still needs to be initialized because it is used in COMERR which may be called before the first command is parsed.
7.12.3.6 CMDONE - at least one CoMmand DONE
The CMDONE flag indicates that a command has been successfully parsed since the last block end condition was encountered.
82
7.12.3.7 ERRCNT - package ERRor CouNT array
The ERRCNT array is used to log errors accumulated during the run of the program. It is updated by the COMRPRT routine between each routine and after the over-all package report, which occurrs at the end of the Compliance Checker run.
7.12.3.8 ERRTYP - ERRor TYPe to be logged
ERRTYP is the communications symbol between the COMERR routine and the rest of the package. ERRTYP is set with an error code and the COMERR routine is called. The error by that name will be reported and logged.
7.12.3.9 FRSTRTN - FiRST RouTiNe
FRSTRTN is the first routine name given at the beginning of the run. It will be the source for the package identifier, PKGID.
7.12.3.10 LISDEV - LISt DEVice
This is the list device defined by the user prior to the execution. If it is not defined, it is defaulted to the default device, "0".
In the DSM-11 version, the LISt DEVice is hard coded to "3". LISDEV is set witin the INIT block.
7.12.3.11 NUMER - NUMber of ERrors
NUMER is initialized and killed in the COMPLY routine so that it will be available for the COMPKGE routine prior to the calling of COMRTN.
7.12.3.12 PKGEND - PacKaGe END
The PKGEND flag indicates that there are no more routines left in the package. The end of the routine parsing phase is finished and the summary is still to be completed.
83
7.12.3.13 PKGID - PacKaGe IDentifier
The package identifier is the first three characters from the first routine, FRSTRNT (actually gotten from RTN for the first routine, see COMPKGE).
7.12.3.14 PROD - Production Flag
The PRODuction flag is used to complete the symbol table cleanup. It allows the package to be included within a larger menu driver without impacting too many other symbols.
7.12.3.15 RNUMER - Routine NUMber of ERrors tallied
RNUMER is the total number of errors accumulated for a routine. It is initialized here. It is incremented in COMERR and tallied in NUMER by the COMRPRT routine.
7.12.3.16 RTN - RouTine Name
RTN is the name of the current routine being parsed. In this situation, RTN contains the first routine name. Later in this routine, at the end of parsing, the symbol is set to null to trigger the COMERPT routine to generate the package error totals. RTN is then killed.
7.12.3.17 RTNEND - RouTiNe END flag
The RTNEND flag indicates that the current routine has been completed. RTNEND is initialized before parsing the next routine and killed just before the Compliance Checker is exited.
7.12.3.18 RTNLAB - RouTiNe LABel reference
The RTNLAB symbol is used to uniquely identify the label of the current line of code being parsed from the current routine. In COMPLY, this symbol is killed during the cleanup phase.
84
7.12.3.19 RTNNUM - RouTiNes processed NUMber
RTNNUM is the number of routines that have been parsed thus far. RTNNUM is initialized at the start and killed at the end of the process.
7.12.3.20 RTNSRC - RouTiNe SeaRCh
RTNSRC is a flag to indicate that the search for a new routine from the ^COM("NXT") global has been successful.
7.12.3.21 SPCR - SPecial ChaRacter string
This is a "Cute Trick" for defining a repeating string of characters. This form of the $PIECE function is new from the 1984 ANSI Standard. It may be replaced in earlier implementations with the following (or similar) code. The actual characters and length are left to the discretion of the user. 34 sets of " -" were used in the distributed code.
S SPCR=" - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
7.12.3.22 TXTNUM - routine TeXT line NUMber
TeXT NUMber is the pointer into the ^COM("TEXT",RTN) global. TXTNUM is killed in this routine.
7.12.4 Block Description
7.12.4.1 INIT - Initialization
This block actually directs the execution of the complete package. The sign-on identifies the Compliance Checker and the version being run. To insure that no carry over occurrs from previous runs, the ^COM global is killed. Counters and flags are then initialized
85
7.12.4.2 START - Begin Actual Processing
Get the current time from the COMTIME routine and report the entry point into the package. The specified routine is then loaded into the ^COM("TEXT") global using COMSTORE. The analysis begins with COMPKGE.
7.12.4.3 EXIT - Close Out of the Process
The cumulative package report is controlled by this block. The COMSTK routine generates the package structure map. The COMERPT is used to generate the error totals for all of the routines from the package and the package structure.
If the run is not a production run, it will quit there (PROD=0). This will leave the symbol table still intact.
7.12.5 Errors Generated by This Routine
There are no errors generated directly by this routine. This is all accomplished by other routines.
7.12.6 Conversion Comments
The INIT block contains an OPEN for the default device, LISDEV. This should be modified to support a specific environment. It is currently setup for VAX DSM version 2.0 and should work on nearly all versions of DSM and DSM-11 after Version 3.0. To modify, simply;
As is;
O LISDEV:NEW:0
Modify to;
O LISDEV ; :NEW:0 ; THIS IS FOR IMPLEMENTATIONS OTHER THAN DSM VAX
86
7.13 COMPOST - Post-Conditional Handler
7.13.1 Routine Purpose
The COMPOST routine controls the parsing of postconditionalized commands and arguments. This routine provides a broad spectrum of types of symbols and functions that potentially may be used in the conditional expression.
7.13.2 Environmental Concern
The greatest concern within this structure has been the difference between the command and the argument postconditional and the few extension exceptions that exist. These exceptions are;
1. The "Set and Range" FOR Loop Expression
2. The Option List on the OPEN, CLOSE, and USE Commands
3. The Timeout Feature for the READ and LOCK Commands
This is a transition type of routine. It may be invoked while processing nearly any command. The trigger for this routine is the colon character, ":". COMPOST provides the mechanism for handling the whole range of expression that a postconditional may take by calling the COMARG routine. Any defined symbols parsed while being called from this routine will yield a type of "REF" when logged. Symbols referenced in a postconditional may not be changed by the reference.
7.13.3 Symbol Definitions
7.13.3.1 ALVL - Argument LeVeL indicator
Each time COMARG is invoked, this level indicator is incremented. Each time COMARG is exited, ALVL gets decremented. This symbol is used to keep track of the stack level of activity that the current token and delimitor represent. This is the prime control within the recursive process.
87
7.13.3.2 ASET - current Argument SET level
The classifications for ASET come from the ^COMDEF global during the execution of the COMMAND routine.
7.13.3.3 CMD - CoMmanD id
The CMD symbol holds the name of the last command parsed. CMD is used to detect if the current command is a FOR command that is being parsed. There is a syntax in the FOR command that is similar to a postconditional. However, it is not.
7.13.3.4 CMDARG - CoMmanD ARGument type
The CMDTYP and CMDARG symbols identify the type of command and type of argument to be parsed. These values are changed from what may have been established from the COMMAND routine. This should be no problem in that these symbols are re-established upon parsing the first or next argument in this command set. These symbols are set to a "Symbol" type of command and an undifferentiated argument, "X".
7.13.3.5 CMDEND - CoMmanD END flag
The CMDEND flag marks the end of the command set, (well, kind of). CMDEND actually indicates here the transition from the command field to the command argument field of the argument set. If the parsing is at the end of the command field, CMDEND will return to the COMMAND routine and be reset. If parsing was at the end of the argument set, the space indicates the end of the entire command set.
7.13.3.6 CMDMSK - CoMmanD MaSK
This is a mask of three bits (1s or 0s) that indicates if:
1. Bit 1 - Legal For Command Postconditional
2. Bit 2 - Legal For Arguments
3. Bit 3 - Legal For Argument Postconditional
88
7.13.3.7 CMDTYP - CoMmanD TYPe
The CoMmanD TYPe identifies the type of command this command is. CMDTYP was previously discussed with the COMARG symbol.
7.13.3.8 DELIM - last DELIMiter parsed
The DELIM symbol is used to identify the end of postconditional processing. There are two delimitors and a condition flag that individually may signal the end of a postconditional situation. The conditions are a comma or a space (non-literal), or the end of the line.
7.13.3.9 ERRTYP - ERRor TYPe to be logged
The ERRTYP symbol communicates an error condition to the COMERR routine for logging.
7.13.3.10 LINEND - LINe END flag
The LINEND flag is set by the COMTOK routine which is called quite a ways down stream via COMMAND. It signifies that there are no more commands left on the current line to parse.
7.13.3.11 LP05 - LooP counter #05
The LP05 symbol is used exclusively for driving a FOR loop. LP05 is killed upon exit from the routine.
7.13.3.12 POSTC - POSTConditional flag
The POSTC flag is set as COMPOST is called from COMMAND. POSTC helps to abreviate the COMARG routine when called from COMPOST.
7.13.3.13 PSTEND - End of the Postconditional Flag
A Postconditional can exist in two forms, as a command conditional and an argument conditional. The COMPOST routine is terminated differently in either case.
89
7.13.3.14 PSTYP - PoStconditional TYPe indicator
PSTYP is a bit map of three bits. The first and the third bits determine whether the command and/or the arguments may have a postconditional.
7.13.3.15 SLVL - Saved set LeVeL
SLVL indicates the level of an argument that could be changed in a SET command. SLVL is referenced form COMARG. This is a serious problem in that COMPOST may be called as a command postconditional prior to the actual parsing of arguments. A postconditional is an expression. As such, it may mean the parsing of expression arguments prior to investigating the arguments of the command and the subsequent command dependent limitations on arguments.
7.13.3.16 SVSET - SaVe SEt Type
This contains the effect this command may have upon the symbol involved, set, referenced, or killed.
7.13.4 Block Description
7.13.4.1 START - Evaluate the Postconditional Expression
The SLVL is guaranteed to exist. Reguardless of the type of command or the argument types that are expected for this command, SLVL is set for a generalized reference. Upon return to COMMAND, SLVL will be restored to its value prior to the call to COMPOST.
The one command exception that may trigger a postconditional is the "FOR" command. The set-and-range format of the command could be mistaken for an argument postconditional.
The one expression exception is the $SELECT function. This bizarre format flies in the face of every other function and command structure defined in the language. In the author's own estimation, $SELECT is a poor attempt to implement the CASE construct into the language. There are better and more standard ways to proceed.
The expression is now ready to be parsed. This is accomplished by calling the COMARG routine until the PSTEND flag becomes true from the POSTEND block. The possible outcome of the postconditional is the end of the command field or the complete
90
command set. Had this expression been a postconditionalized argument field, a space delimiter would signal an end of the argument set and the command set.
There is one last test made before a possible error could be generated. This insures that the command was not a FOR command, or the CMDEND flag was set, or the last delimitor was a comma or a space.
7.13.4.2 EXIT - Reset Flags and Clean-up
The EXIT block resets the POSTC flag and kills those symbols that are only germain to this function.
7.13.4.3 POSTEND - Test for the Postconditional End
This block identifies the end of the postconditional expression. Postconditionals come in two different flavors, command and argument. The ending condition will depend upon which type is currently being parsed. The command postconditional is terminated by a space or an end of line. The argument postconditional is terminated by either of the above or an argument level of 1 and a comma delimiter.
7.13.5 Errors Generated by This Routine
7.13.5.1 "7C" - Post-Conditional Error
A postconditional error indicates that the parser became lost while parsing the postconditional.
7.13.5.2 "7H" - Postconditional NOT Allowed in this Command
This indicates that a situation that was identified as a postconditional was applied to a command or the arguments of a command that does not allow a postcontional. This may occur with code that has been customized to a particular implementation.
91
7.14 COMRLAB - Label Reference Handler
7.14.1 Routine Purpose
The COMRLAB routine parses the label references found as tokens from the arguments of the DO, GOTO, and JOB commands found in the LINE buffer.
7.14.2 Environmental Concern
The COMRLAB routine is recursively called. this allows a wide range of expression in the arguments of the commands mentioned. This routine is called from COMARG when a label-type argument is expected.
7.14.3 Symbol Definitions
7.14.3.1 CMDARG - CoMmanD ARGument type
CMDARG contains the type of argument that this command will be expecting. CMDARG is part of the trigger mechanism used in COMARG to invoke this routine.
7.14.3.2 DELIM - last DELIMiter parsed
The DELIMiter is important. There are two different states being evaluated in this routine. The first type is the prescripted, indirection operator, @. It indicates a mode shift in the form of the actual label being stored as data. The actual argument to be parsed is an indirect symbol, local or global.
The second state type is the more commonly found direct label reference that is expected.
7.14.3.3 ERRTYP - ERRor TYPe to be logged
The ERRTYP symbol is the communications link to the COMERR routine. It contains the error to be logged and reported.
92
7.14.3.4 LABEL - LABEL reference
LABEL is used in logging the command argument label references. LABEL is checked to insure that it exists it is referenced.
7.14.3.5 LINPNT - LINe PoiNTer
The LINPNT symbol points to the current displacement within the LINE buffer. This is the point after the last DELIMiter and TOKen were extracted.
7.14.3.6 NXTRTN - NeXT RouTiNe
NXTRTN is an external reference as parsed from the code. NXTRTN is used to set up a trigger in ^COM("NXT") that will cause that routine to be loaded from COMRTN.
7.14.3.7 RTN - RouTine Name
RTN is the current routine name. It is primarily used in the logging of the label reference.
7.14.3.8 RTNLAB - RouTiNe LABel reference
RTNLAB is the reference used when logging the label as invoked from a particular line in a given routine.
7.14.3.9 TCM - Temporary CoMmand argument storage
TCM is a scratch variable used to hold the command argument type, COMARG, while the indirect symbol reference is being parsed. TCM is killed after it is used.
7.14.3.10 TOK - TOKen parsed from LINE
This is the TOKen extracted from the parsing of the LINE buffer.
93
7.14.3.11 TTOK - Temporary TOKen storage
TTOK stores an offset reference while the offset and a possible external routine are extracted.
7.14.4 Block Description
7.14.4.1 START - Control Label Reference Logging
The indirect references are identified first. These are potentially the most dangerous. The symbol name is not the label, but the symbol name stores the label name. the SYMSRC block will call the COMARG routine to get the entire symbol that contains the indirect reference.
The second condition recovered is the external reference. In some forms, this is a call to an alternate entry point into an external routine. Within the RTNREF block, the external reference will be added to the list of external routines to be loaded during this execution of the Compliance Checker.
The third condition checked for is the relative address. This is waiverable a item according to the standard. Relative address is legal in the syntax of the language and provision must be made to handle it.
Should there be no TOKen, the routine needs to return to where it was invoked, COMARG. The rest of the block is used for logging the references and an additional style error condition, a previously defined block being referenced.
7.14.4.2 SYMSRC - SYMbol reference SeaRCh
The condition of the CoMmanD ARGument type is saved in TCM and the COMARG routine is called. This will obtain the next TOKen to be logged for this command. Once control is returned, the CoMmanD ARGument type is restored and the scratch symbol, TCM, is killed.
D ABLE,@BAKER ^^ ^ !! + "BAKER" is parsed from COMARG as a symbol !+ Identifies that the following token is a symbol, ! not a label + Identifies that the token "ABLE" is a label
94
7.14.4.3 LABSPLT - LABel SPLiT
LABSPLT handles the offset reference from a label. This is a powerful, but dangerous feature of MUMPS. If there was a "+" delimiter, the whole reference has not been parsed. COMTOK is called to get the rest of the label reference. The variety of what that second fetch is broad, but bounded.
ARG 1 ARG 2 ARG 3 Postconditional on ARG 3 ______ ____________ ______________ ___ DO ABLE+5,BAKER+3^RTN2,CHARLIE+3^RTN3:X=1 ^ ^ ^ ^ ^ ^ ^ ! ! ! ! ! ! + Extracted by COMPOST ! ! ! ! ! + Ends call to COMTOK from ! ! ! ! ! COMARG ! ! ! ! + More to be called from LABSPLT ! ! ! + End of Argument, Process in RTNREF ! ! + Another Displacement reference, Call COMARG ! + End of Argument, No external reference + First token which displacement delimitor
7.14.4.4 RTNREF - RouTiNe REFerence logging
The RTNREF block identifies external references. These external references will be stacked in the ^COM("NXT") global and used by the COMPKGE routine to load these referenced routines.
7.14.5 Errors Generated by This Routine
7.14.5.1 "3E" - Previously Defined Block Invoked
Invoking previously defined blocks does not appear to present a problem at first. Invoked previously defined blocks is, in fact, an implied looping condition. This looping situation may be intentional. If so, a waiver needs to be prepared to identify the situation.
7.14.5.2 "3C1" - Alternate Entry Label Used in Routine Reference
The alternate entry point is usually a sign that a feature in another routine has been found to be so useful that it is accessed by jumping into the middle of the containing routine. If this is the case, the solution is to construct that piece of code into a separate routine called from both routines (and usually more). This helps to make these "useful little tools"
95
more visible and accessible to others.
7.14.5.3 "3C2" - Displacement Label Reference Found
Displacement labels are incredibly dangerous. It is very easy at a later time to add another line or delete a line after a label. The displacement label is now pointing to an unintended line of code.
7.15 COMRPRT - Routine Report Summary
7.15.1 Routine Purpose
COMRPRT generates the end-of-routine error report for each routine.
7.15.2 Environmental Concern
There must be some errors stored in the RERCNT array before this routine will run.
7.15.3 Symbol Definitions
7.15.3.1 $Y - universal line count
$Y is a system variable that identifies the number of lines listed to the last device used. It is reset when a form feed is written to that device. It is used to identify whether a page eject is required or not. This may have to be adjusted if you are using other than the 66 line per page standard.
7.15.3.2 %T - Current Time
This is the time and date as generated by the standard utility, COMTIME. It is used to time tag the report.
96
7.15.3.3 A - scrAtch variable
The A symbol is used to hold the different error codes stored in the RERCNT array. It will be killed as the routine exits.
7.15.3.4 ERRCNT - package ERRor CouNT array
The ERRCNT array is updated in this routine. ERRCNT is incremented by the number of occurances of errors found of each type within the routine being parsed.
7.15.3.5 LP02 - LooP counter #02
This is the FOR loop variable that drives the error type reports.
7.15.3.6 NUMER - NUMber of ERrors
NUMER is the total number of errors compiled thus far. It is incremented at the end of this routine by RNUMER, the number of errors found in the last routine parsed.
7.15.3.7 RERCNT - Routine ERror CouNT array
The RERCNT array is the logged errors that the COMERR routine has been keeping for the routine being parsed. During COMRPRT, the array is traversed and the accumulated errors are summed into the ERRCNT array and RNUMER.
7.15.3.8 RNUM - Routine NUMber of errors
The RNUM scratch variable holds the value of a particular error type encountered. RNUM will be killed upon exit from this routine.
7.15.3.9 RNUMER - Routine NUMber of ERrors tallied
RNUMER is the total number of errors accumulated from the RERCNT array. RNUMER is zeroed after the value has been added into the NUMER counter.
97
7.15.3.10 RTN - RouTine Name
The name of the last routine parsed is stored in the RTN symbol. It is used to identify the routine report that will be generated by this routine.
7.15.4 Block Description
7.15.4.1 START - Control Error Report
If there were no errors, no error report will be generated. If there were errors, the routine continues. The need for a page eject is checked by comparing the value of $Y. The current time is obtained from COMTIME and the report heading is printed. Each error in turn is threaded from the RERCNT array with its value and error code by the REPORT block. The tallied number of errors is reported. The counter, NUMER, is updated and RNUMER is zeroed.
7.15.4.2 REPORT - Report Per Error Count
The count of the error pointed to in the RERCNT array by A is loaded into RNUM. That count is formatted on the output line with the code and the description of that code.
7.15.5 Errors Generated by This Routine
The COMRPRT routine only reports errors, it does not create them.
7.16 COMRSEL - Routine Select Handler
7.16.1 Routine Purpose
The COMRSEL routine is used to load the first routine to start the Compliance Checker process. Should that routine not exist, an error will be printed to the default device and the prompt will be re-issued.
98
7.16.2 Environmental Concern
The COMRSEL routine will attempt to load the program name that is specified by the user. A $ZTRAP is set prior to the attempt so that run-time recovery can be handled.
COMRSEL is another routine where the execution leaves the routine buffer and continues in the symbol table. The routine buffer is abandond to allow for the requested routine to be loaded. Should the load fail, (ie. the routine was not in the routine directory), COMRSEL is reloaded and execution continues from the ERRTRAP recovery label. By quiting from the ERRTRAP block, execution is continued after the XECUTE LOADTST command. The COMSTORE routine also leaves the routine buffer during execution.
7.16.3 Symbol Definitions
7.16.3.1 $ZERROR - System Error Message
This symbol provides the text of the last error encountered. This system symbol is set to an error in COMRSEL only if the routine requested was not in the directory.
7.16.3.2 $ZTRAP - System Error Trap Symbol
By setting this system symbol to the label reference, should an error occur, control will continue at the label specified in $ZTRAP.
7.16.3.3 AB - ABort flag
The ABort flag is a means of gracefully exiting the Compliance Checker at the routine selection prompt. The user need only enter a null and the package will terminate.
7.16.3.4 LOADTST - LOAD TeST execution symbol
The LOADTST symbol contains the code that will be in control while the execution leaves the routine buffer.
99
7.16.3.5 LP05 - LooP counter #05
The LP05 symbol is strictly a loop driver. It is killed upon routine exit.
7.16.3.6 OK - Oll Korrect flag
The OK symbol identifies the input RTN as being a legal routine name. It is also used to identify if the load occurred "Oll Korrect". Should the load work properly, the trigger in the ^COM("NXT") global is established. The inhibitor reference, ^COM("DONE",RTN) node is killed to insure that the routine reference will be parsed. The conditions for the execution of the COMRTN routine are ready. The entered input routine may now be loaded and parsed.
7.16.3.7 RTN - RouTine Name
RTN is the initial routine name entered into the Compliance Checker. RTN will be checked by this routine to see if it is first a legal routine name. It will also be used to set the triggers used to start off the loading and parsing.
7.16.4 Block Description
7.16.4.1 START - FOR Loop to Drive Prompting and Loading
The AB and OK flags are initialized to zero. The FOR loop controls the execution of the PROMPT block. Should the user fail to abort the run or enter a valid routine name this FOR loop will remain in control. Should the user fail to enter a valid routine name, an error message will be displayed to the default device.
7.16.4.2 EXIT - Cleanup
The scratch symbols from this routine are killed during this block. The $ZTRAP flag is cleared.
100
7.16.4.3 PROMPT - Prompt for Routine Name Input
The PROMPT block writes out a request for input. Should the user enter only a carrage return, the routine will abort with RTN set to NULL. This will terminate the Compliance Checker without listing.
The OK flag is set to the results of the OR of two pattern matches. The first is to cover the entry of a valid % utility routine name. The second covers a user's routine name. If both pattern matches fail, PROMPT QUITs and control resumes with the FOR loop in START.
The OK flag is again cleared and the LOADTST string is prepared using the input routine name in the string. That string is then executed. Should LOADTST work, OK returns as true.
In this condition, The trigger is set for the COMSTORE routine to load the routine to be parsed. COMSTORE will be called by COMRTN which will be called by COMPKGE which will be called by COMPLY, which called COMRSEL.
> COMPLY +--->COMRSEL ! +--->COMPKGE +--->COMRTN +-->COMSTORE
7.16.4.4 ERRTRAP - Error Trap Handler
ERRTRAP is used to insure that the COMRSEL routine is reloaded should the test load of the input routine fail. ERRTRAP only returns control to the default device, 0, and writes out the error message for the user.
7.16.5 Errors Generated by This Routine
This routine is in direct interactive contact with the user so no errors need to be logged except to the user directly.
101
7.17 COMRTN - Routine Parsing Control
7.17.1 Routine Purpose
COMRTN controls the parsing of the routine specified in RTN. COMRTN controls the first line convention testing, the subsequent block parsing, and the end of routine report.
7.17.2 Environmental Concern
COMRTN is driven by the COMPKG routine. There is a set of ^COM("NXT) global entries that are added from COMRLAB. These are external references that the parser has found. This is the list of the "to be done" routines. As they are processed, they are added to the ^COM("DONE") list. This insures that a routine is not parsed more than once.
The COMFLIN routine is called from COMRTN. COMFLIN starts the parsing process for a routine. There are a series of special attributes that are tested for style in the first block that are not needed in the parsing of the other blocks in a routine.
7.17.3 Symbol Definitions
7.17.3.1 $ZTRAP - Error Trap Trigger Set
This is the mechanism for setting the error trap. Should the routine that will be attempted to load, not be there, control will be directed to the ERTRAP label.
7.17.3.2 ABRT - ABoRT flag
This is the ABoRT flag that indicates to COMRTN that the routine named in RTN is not available to be loaded and parsed. The condition is recorded as an error. The parsing will continue after that condition.
7.17.3.3 BLKCNT - BLocK CouNT
The BLKCNT symbol is the argument of a FOR command. It provides a count of the number of blocks that were parsed in the last routine. It is used as the test for the "3H4" error.
102
7.17.3.4 BLKEND - BLocK END flag
The BLKEND flag is initialized in this routine if the load was successful.
7.17.3.5 ERRTYP - ERRor TYPe to be logged
ERRTYP is the indicator of the error to be processed by the COMERR routine. There are three such error codes generated by this routine.
7.17.3.6 LABEL - LABEL reference
LABEL is the first label from the first block of the newly loaded routine. LABEL is returned from COMFLIN and is checked against the routine name to insure that they match.
7.17.3.7 LP01 - LooP counter #01
The LP01 symbol is a scratch counter used to drive the FOR loop that searches for the next routine. It may be killed locally.
7.17.3.8 PKGEND - PacKaGe END
PKGEND is the flag that terminates the routine scanning pass. If all of the "to do" routines have been processed, COMPKG will continue on to the package summary report.
7.17.3.9 RTN - RouTine Name
This is the name of the next routine to process. It is loaded within the START block from the ^COM("NXT") global.
7.17.3.10 RTNEND - RouTiNe END flag
RTNEND is initialized as the COMRTN routine is entered. This flag is set when the last line of the last block has been read and processed. RTNEND is used to exit the block parsing loop in the PRSRTN block.
103
7.17.3.11 RTNLAB - RouTiNe LABel reference
The RTNLAB label reference is set in anticipation of the COMERR routine being called. It is only affected if an error results from the loading of a routine.
7.17.3.12 RTNSRC - RouTiNe SeaRCh
RTNSRC is the flag that indicates that no routine could be found from the ^COM("NXT") global. It is the situation that terminates the FOR loop in START that searches for the next routine.
7.17.4 Block Description
7.17.4.1 START - Control Next Routine Load and Parse
The START block controls the parsing of the current routine and it attempts to load the next routine to be processed. Control is surrendered to the COMPKGE routine after execution to allow for termination at the end of the "to do" list. The PKGEND symbol indicates that condition.
7.17.4.2 CLRTN - Clear Routine
The CLRTN block tests for the end of the "to do" line in <<<a line missing here>>>
Once a routine has been found, RTN, the trigger in ^COM("NXT") is KILLed for that routine. If the routine has not been "done" (or previously processed), the RTNSRC flag will be true.
7.17.4.3 PRSRTN - Parse the current RTN
PRSRTN tests the LABEL parsed from COMFLIN to validate the "first label equals the routine name" convention.
The FOR loop that follows will parse one block from the loaded routine with each iteration. This will continue until there are no more lines in the routine to parse.
104
7.17.4.4 ERRTRAP - No Routine Error Trap
ERRTRAP allows the recovery from attempts to load routines to be parsed without killing the run.
7.17.5 Errors Generated by This Routine
7.17.5.1 "1A" - First Label does not Match Routine Name
This error reflects the "first block label equals the routine name" convention. This situation should never occur in production code.
7.17.5.2 "3H4" - Too Many Blocks in Routine
There are a few programmers who segment too finely without creating a new routine. Even so, twenty blocks is the limit that is tested for. That is a lot of blocks for one routine in MUMPS.
7.17.5.3 "7J" - Routine NOT Found
This error identifies routines that are not currently loaded. The programmer should be compeled to supply such routines before the code is allowed to pass quality assurance.
7.17.6 Compatability Enhancement
The form of the $ZTRAP varies with the implementation. Some implementations will expect the $ZTRAP to be spelled out and other implementations will only accept the abreviation, $ZT. The decision was made to spell out the system symbol where possible for documentation purposes. It may have to be abreviated for specific implementations.
Change this;
S $ZTRAP="ERRTRAP^COMRTN"
to this;
S $ZT="ERRTRAP^COMRTN"
105
7.18 COMSTK - Package Routine Stack Report
7.18.1 Routine Purpose
The COMSTK routine generates the package structure report for the whole package after the parsing was completed. Additional errors may be found during this evaluation.
7.18.2 Environmental Concern
COMSTK runs after all of the routines to be parsed have been parsed. This routine will yield a structure that identifies how all of the routines drawn into the package related to each other.
7.18.3 Symbol Definitions
7.18.3.1 BF - scratch BuFfer
The BF array is the scratch buffer for a list of routines invoked from the current routine indicated by P. The routine names are arranged as a series separated by commas. This arrangement could be modified to use a second subscript to store the called routine names.
BF(P)="COMFUNC,COMLAB,COMSYM"
Could be changed to;
BF(P,"COMFUNC")="" BF(P,"COMLAB")="" BF(P,"COMSYM")=""
This modification will require a small effort to implement this feature in this manor.
7.18.3.2 CMD - CoMmanD id
CMD is usually the name of the last command parsed. In COMSTK, CMD is subverted in preparation for a possible call to COMERR to report an error. COMSTK is called after all of the input code has been read and parsed so there are no more commands to report. CMD now contains the name of the offending routine in an error situation during the package structuring.
106
7.18.3.3 ERRTYP - ERRor TYPe to be logged
ERRTYP is the communications link with the COMERR routine. It is a means of passing the identifier of the error which found and needed to be logged.
7.18.3.4 FRSTRTN - FiRST RouTiNe
FRSTRTN is the first routine name whose calling structure is being plumbed.
7.18.3.5 I - scratch poInter array
The I array holds the pointers into the BF(P) array.
7.18.3.6 LABRTN - LABel RouTiNe reference
LABRTN is a communications link with the COMERR routine. It is usually used to identify the line and the routine that spawned the error. When the COMSTK routine is running, all of the lines of code have been parsed and no specific line is responsible for the error. It is loaded with the name of the offending routine in the calling structure that is generating the error condition. This is then used by the COMERR routine in reporting and logging the error.
7.18.3.7 LINPNT - LINe PoiNTer
LINPNT is the current parsing position within the LINE buffer. The LINE buffer usually contains one line of MUMPS code. LINE contains nothing at this point because all of the lines of code have been parsed. Instead, LINPNT is used to point to the level of the calling structure that has an error associated with it.
7.18.3.8 LINPRT - LINe PRinT flag
This flag is used to indicate if the line of MUMPS code in LINE has or has not been printed yet. If it has been printed, LINPRT is equal to 0. Since we are not parsing any code in this routine, the LINPRT flag is turned off to keep COMERR from writing the blank LINE buffer.
107
7.18.3.9 LISDEV - LISt DEVice
LISDEV is the LISt DEVice that the Compliance Checker uses to print the routine and package reports.
7.18.3.10 LP00 - LooP counter #00
The LP00 loop driver is used to drive the loading of the BF(P) arrays of routine calls. LP00 is expendable at the end of the run.
7.18.3.11 LP01 - LooP counter #01
The LP01 loop driver is used to drive the search for recursive calls. The active calling structure in the PG array is compared to look for a match.
7.18.3.12 MSG - previously defined MeSsaGe
MSG, the previous message is a means of saving paper and reiteration. This message is initialized with "< STRUCTURE PREVIOUSLY DEFINED >". After this message has been printed once, it is replaced with the shortened version, "< PREVIOUS >>>". Both messages indicate that the current routine in PR has been structure listed previously in a position deeper, (to the right), than the current level. The position is considered because the if the structure is elaborated far enough to the left, all of the paths to the right will be displayed.
7.18.3.13 MSG2 - recursive MeSsaGe #2
MSG2, the recursion message is more direct. If the routine being mapped is found in the superior direct calling stream, the routine is recursive and needs to be followed no further.
The message displayed by MSG2 is of two parts, also. The first occurance spells out the whole message. The second is an abreviated form.
108
7.18.3.14 P - Position pointer
The P symbol is the current stack depth of the mapping process.
7.18.3.15 PASS - PASS to the next level flag
The PASS flag allows the continued descent into the routine calling structure by controlling the re-execution of the START block recursively.
7.18.3.16 PG - ProGram name Array
The PG array is the current calling stack of the package being structured. The P pointer is the current level active in PG.
7.18.3.17 PR - PRogram name
PR is a convenience to avoid having to use a subscript reference in multiple places. PR is synonymous with PG(P).
7.18.3.18 RT - scratch RouTine name
RT is used as a traveler to thread the list of names that are currently in the ^COM("DONE") global subtree. RT is used again as a traveler to thread the list of external references that each routine calls. These are listed in the ^COM("LREFS") global subtree.
7.18.3.19 RTN - RouTine Name
The routine name, RTN, has been subverted to mean the current recursive label. This allows the COMERR error handler to operate and report these problems in a more meaningful way.
7.18.3.20 RTNLAB - RouTiNe LABel reference
RTNLAB is another line and routine reference used by the COMERR routine in reporting and logging an error. RTNLAB is loaded with the name of the offending routine before the COMERR routine is called.
109
7.18.3.21 SCN - SCaNning label name
SCN is the previous routine that is invoking the current routines being handled by PR. The relationship is such that the SCN routine had invoked PR.
7.18.4 Block Description
7.18.4.1 INIT - Setup For Package Structure
The INIT block established an environment for the execution of the START block. It provides some bridges to the utilities of the Compliance Checker. This allows for the slight subversion of these interfaces for duty in this after-the-run report.
The list of routines in the ^COM("DONE") global are initialized to a value of 99. If there is a package that goes deeper than this, it probably has some real problems. The value of 99 could be expanded to 999 if desired. It should have no real effect on the outcome.
The LISt DEVice is attached and the salutation for the this final report is printed.
7.18.4.2 START - Control Traversing the Structure
The START block controls the mapping of the calling structure of the package as called from the initial routine name in FRSTRTN. START does this by only handling two levels at a time, the level entered with and the routines it calls. The called routines are recalled from the ^COM("REFS") global. The current position in the calling structure is the symbol P. The status of the recursive call is maintained in the table described below.
P=1 P=2 P=3 P=4 ... and so on Main calls RTN1 calls RTN2 calls RTN3 BF(P) BF(P) BF(P) BF(P) PG(P) PG(P) PG(P) PG(P) I(P) I(P) I(P) I(P)
110
7.18.4.3 EXIT - Cleanup from Run
The EXIT block cleans up the expendible symbols after the run of this routine.
7.18.4.4 LOADBF - Load the Level Calling Array, BF
The LOADBF block loads the BF array strings. These strings will be lists of the routines called from the ^COM("REFS",SCN) globals. The routine names are separated by single commas.
7.18.4.5 NEXTRTN - Handle the Next Routine
The NEXTRTN block selects the next routine to be mapped. The next routine is loaded from the BF(P) array. That routine is printed starting in the appropriate column to indicate its level, P. The current environment is compared for previous reference and recursion.
If the current position, P, is greater than or equal to the level saved for it in ^COM("DONE",RTN), any further path downwards is cut off by resetting PASS. This is why the ^COM("DONE") subtree was initialized with 99. The "previous" message is also reported.
The check of recursion is also controlled from this block. Once one recursive situation has been found, the rest of the scan for this routine is terminated.
7.18.4.6 RECURS - Recursion Report
The RECURS block controls the reporting of recursive calls found in the structure. The following actions are taken;
1. The PASS flag is turned off.
2. The Communications symbols with the COMERR routine are subverted.
3. The List Device is bound and the error message is printed off of the routine name.
4. The short form of the recursion message is loaded for the next use.
111
5. The ERRTYP is set.
6. The COMERR routine is called.
7.18.5 Errors Generated by This Routine
7.18.5.1 "3D2" - Recursive ROUTINE Found
This error message indicates that a recursion was detected. This means that a routine has the potential of calling itself. This is not necessarily a bad technique if it has been debugged and properly planned. All too often, a programmer will call a routine that calls a routine that calls the first routine. It is not abundently obvious to the programmer that this unintended control loop exists. This error helps to identify these cases and make them more visible.
112
7.19 COMSTORE - Loads and Stores Routines into COM
7.19.1 Routine Purpose
The COMSTORE routine loads other routines into the ^COM("TEXT") global. COMSTORE performs this by loading each routine in turn into the routine buffer (where this routine currently resides). This is done by allowing the execution to leave the routine buffer and continue execution in the symbol table. The execution returns to the routine buffer only after this routine has been restored. Many of the symbols described below are actually lines of code. This makes the support issue critical for this routine. There is a waiver for this routine swapping technique.
7.19.2 Environmental Concern
The COMSTORE routine assumes that the routine name for the next routine, RTN, has a valid routine name in it. All of the rest of the symbols described below are either initialized, created, or eventually destroyed.
7.19.3 Symbol Definitions
In the COMSTORE routine, the difference between data and code breaks down severely. The symbol table contains code and the routine buffer contains data. The code stored in the symbol table is designed to reload this routine when it is finished. The calling order is demonstrated below.
START^COMSTORE ! CNTRL ! ! TRANS ! ! ! LOAD ! ! ! ! SAVE ! ! ! ! ! TXT
7.19.3.1 ABRT - ABoRT flag
The ABRT symbol is set from within the TRANS symbol code. It signifies that the transfer was successful when control returns to the COMRTN routine. This will happen should the routine not exist. There was an error trap set within the COMRTN routine before COMSTORE was called. In case of a failure, control returns to COMRTN.
113
7.19.3.2 CNTRL - transfer CoNTRoL
The CNTRL symbol contains the control code for driving the transfer of the new routine to the routine buffer and the eventual reloading of COMSTORE. It will execute the code stored in TRANS before reloading and resumming the execution of the COMSTORE routine.
S CNTRL="X:'$D(^COM(""DONE"",RTN)) TRANS ZL COMSTORE"
7.19.3.3 J - Scratch Variable
The J local symbol is the FOR loop symbol used from the SAVE symbol. It will be created when the SAVE symbol is executed and destroyed when COMSTORE is exited.
7.19.3.4 LLCNT - Logical Line CouNT
LLCNT is initialized when this routine has been entered. It will be incremented when COMLINE is called later.
7.19.3.5 LOAD - LOAD the routine and reload COMSTORE
The LOAD symbol is invoked by the execution of the TRANS symbol code. It brings about the loading of the routine named in RTN and the execution of the SAVE symbol.
S LOAD="ZL @RTN X SAVE"
7.19.3.6 RTN - RouTine Name
RTN is the only manditory input into this routine. It is the name of the routine to be loaded into the ^COM("TEXT") global. The source for RTN was a global reference, ^COM("NXT",RTN) and will be reflect as successfully loaded by the creation of a global node, ^COM("DONE",RTN).
114
7.19.3.7 RTNNUM - RouTiNes processed NUMber
Each time a routine is loaded with this technique, the RouTiNe NUMber is incremented by one.
7.19.3.8 SAVE - SAVE routine to ^COM("TEXT")
The code in SAVE is a FOR loop that drives the transfer of code from the routine buffer to the global, ^COM("TEXT"). It creates a symbol, TXT, at run-time that will contain the full reference for a SET command.
>SET SAVE="FOR J=1:1 S TXT=TRTN_J_"")"" X TXT I ^(J)="""" K ^(J) Q" >WRITE SAVE FOR J=1:1 S TXT=TRTN_J_")" X TXT I ^(J)="" K ^(J) Q
7.19.3.9 TRTN - Transfer RouTiNe
TRNT is a line of code which is used as a template for the construction of the TXT SET command which is used by the SAVE string.
>SET TRNT="S ^COM(""TEXT"",RTN,J)=$TEXT(+" >SET TXT=TRTN_J_"")"" >WRITE TXT SET ^COM("TEXT",RTN,J)=$TEXT(+12) ! ^^ +---------!! The value of J.
7.19.3.10 TXT - run-time code TeXT transfer
TXT is generated at the runtime of the SAVE code. It is recreated for each line in a routine. and will be in the form below (for this example, the fifth line of a routine.
S ^COM("TEXT",RTN,J)=$T(+5)
115
7.19.3.11 TXTNUM - routine TeXT line NUMber
This is the pointer used by the COMLINE routine to keep track of the line that is currently being parsed. The routine loading point is a natural place to initialize this symbol (and that is what we did).
7.19.4 Block Description
7.19.4.1 INIT - Initialize Store Process
The INIT block initializes the LLCNT and TXTNUM symbols to zero. They will be incremented when we get to COMLINE.
7.19.4.2 START - Perform Store Operation
Within the START block, the old global subtree, ^COM("TEXT") is killed. The execution control is transferred to the symbol CNTRL. The RTNNUM is incremented and the unnecessary symbols are killed. The initialization flag for this routine is killed, ^COM("NXT",RTN), and the loaded flag is set, ^COM("DONE",RTN).
7.19.5 Errors Generated by This Routine
This routine generates no error messages itself. A message can be generated if the transfer of the routine specified in RTN fails to be loaded. The error is generated by the error trap set up in the COMRTN routine. The error generated is "7J", "Routine NOT Found".
116
7.20 COMSTRG - String Handler
7.20.1 Routine Purpose
The COMSTRG routine handles the highest priority delimiter in the language, the double quote. It is so important because any command or data may be contained within its bounds without being executed, yet. Should the quotes be mismatched, that data may be inadvertently executed. Strings may be used to load symbols with code at run-time and executed. This type of situation may be used to hide a GOTO, KILL command, or a recursion.
7.20.2 Environmental Concern
The scanning of the LINE buffer is from left to right like in MUMPS itself. Should the rightmost double quote be missing, the Compliance Checker can not tell (nor can MUMPS) that there is a problem with the code until the literal has been parsed as MUMPS code. See the COMMAND routine for this eventuality.
COMSTRG is the only other routine to move (or potentially move) the LINPNT pointer position in the LINE buffer. COMSTRG will handle literals that have imbedded multiple sets of double quotes and double quotes separated by other characters.
7.20.3 Symbol Definitions
7.20.3.1 DELIM - last DELIMiter parsed
The DELIMiter symbol provides the trigger to invoke this routine. Upon exit, DELIM must be modified to prevent re-execution of this routine because we do not use the standard interface that sets DELIM, the COMTOK routine.
7.20.3.2 ENDSTR - END of STRing flag
The ENDSTR flag is always true when COMSTRG exits. As such, it conveys no useful information outside of the COMSTRG routine. ENDSTR is killed upon exit.
117
7.20.3.3 ERRTYP - ERRor TYPe to be logged
ERRTYP is the error type that may be generated if the double quotes are not matched properly.
7.20.3.4 LINE - MUMPS code LINE buffer
LINE is loaded by the COMLINE routine with a line of MUMPS code from the current RouTiNe.
7.20.3.5 LINPNT - LINe PoiNTer
The LINPNT symbol points into the LINE buffer and marks the starting point to go looking for the next double quote.
7.20.3.6 STRCNT - STRing CouNT
STRCNT is the FOR loop counter and is used to tell if the matching double quote or the beginning of another imbedded double quote has been found. If there is an imbedded double quote, the search continues until another odd double quote has been found that is not followed by a double quote.
7.20.3.7 TLNP - Temporary LiNe Pointer
The TLNP symbol holds the last good value for LINPNT. It is usually killed upon exit from COMSTRG. If it was created within this routine, it will be killed.
7.20.4 Block Description
7.20.4.1 START - Quote Search Control
If the next character is a double quote, assume that it is a NULL and set ENDSTR to true. The next line would then increment the LINPNT and QUIT.
If ENDSTR is false, the string still needs to be traversed. The TLNP saves the current line pointer and the search begins for the next double quote. The path from this FOR loop is the ENDSTR condition being true.
118
Once the FOR loop ends, a check is made to insure that the search did not run off of the end of the LINE buffer. Unfortunately, the rest of the line will probably be messed up and unrecoverable from this point. If the value of STRCNT is even, the "String Balance Error" will be generated. In either case, the scratch symbol TLNP will be killed.
7.20.4.2 EXIT - End of Pass Cleanup
The scratch symbol STRCNT is killed on the cleanup pass. The DELIM local symbol is changed from the double quote to a comma. This is to force the reload of the symbol defaults for the argument to come next, if an argument does follow.
7.20.4.3 STRPRS - STRing PaRSe
The STRing PaRSe block uses a $FIND function to position the LINPNT symbol after the next double quote. The last value of LINPNT is stored in TLNP. The condition for ENDSTR is that the next character in LINE (as pointed to by LINPNT) is not a double quote and the STRing CouNT is odd. ENDSTR is also true if LINPNT is less than 1 (no matching double quote was found).
7.20.5 Errors Generated by This Routine
Only a single error is tested for within this routine. It is "7F", the String Balance Error. This is encountered when there is a mismatch of quotes. An odd number of quotes should be found when scanning for quotes by this routine because this routine was invoked by the left most quote.
W "THIS IS A TEST ^ LINPNT is here when COMSTRNG is called. There is no matching right-most quote to offset this call. The "7F" error results.
7.21 COMSYM - Symbol Handler
119
7.21.1 Routine Purpose
The COMSYM routine provides a mechanism for controlling the identification of symbols (variables and globals) from the LINE buffer. It is invoked by COMARG and also invokes COMARG. This is a recursive relationship.
7.21.2 Environmental Concern
This routine requires that it be called from COMARG. This means that the following symbols must exist.
1. ALVL - Argument LeVeL indicator
2. ASET - Argument SET
3. CMD - CoMmanD id
4. CMDEND - CoMmanD END flag
5. EQUFLG - EQUals sign FLaG
6. LINEND - LINe END flag
7. LINPNT - LINe PoiNTer
8. RTN - RouTine Name
9. SLVL - Saved set LeVeL
10. TOK - TOKen parsed from LINE
11. TXTNUM - routine TeXT line NUMber
7.21.3 Symbol Definitions
7.21.3.1 ALVL - Argument LeVeL indicator
The ALVL level pointer is controlled by the COMARG routine and identifies the recursion level of parenthesis the current symbol is being referenced from.
120
7.21.3.2 ASET - current Argument SET level
The ASET symbol identifies the type of transaction that the symbol within this command will perform, SET, REF, or KIL.
7.21.3.3 CMD - CoMmanD id
CMD is the current command being parsed. The symbol being parsed is either from a command postconditional, an argument, or an argument postconditional.
7.21.3.4 CMDEND - CoMmanD END flag
CMDEND signifies that the end of the command set has been reached.
7.21.3.5 DELIM - last DELIMiter parsed
DELIM is the last right side delimiter for the last token from the LINE buffer.
7.21.3.6 EQUFLG - EQUals sign FLaG
The EQUals FLaG is a means of identifying that the "SET" side of a SET or FOR command has been passed. When an equals sign has been passed, EQUFLG is set to 1.
7.21.3.7 ERRTYP - ERRor TYPe to be logged
ERRTYP indicates the type of error found in the code being parsed. There are two types identified by this routine. They are "1C1" and "1C2".
7.21.3.8 LINEND - LINe END flag
The LINEND flag indicates that the end of the LINE buffer has been reached. There will be no more tokens parsed from the line.
121
7.21.3.9 LINPNT - LINe PoiNTer
The LINe PoiNTer indicates the point that parsing tokens and delimiters from the LINE buffer stopped. LINPNT is modified by the COMSTRG and COMTOK routines.
7.21.3.10 LVLEND - argument LeVeL END
The LVLEND array is used to control the current level of recursion. When the LVLEND symbol subscripted by ALVL is set to one, that level of recursion has completed.
7.21.3.11 RTN - RouTine Name
RTN is the name of the current routine being parsed.
7.21.3.12 SLVL - Saved set LeVeL
The Saved set LeVeL is used to identify that a symbol is being "SET" and not just referenced. When the parsing is on the left side of an equals sign and the command is a SET, FOR, or a READ, this points to the acceptible level that a SET operation will be found. See SLVL under the COMARG routine for more detail.
7.21.3.13 TOK - TOKen parsed from LINE
The TOK symbol is the current token extracted from the LINE buffer. TOK is provided by the COMTOK routine.
7.21.3.14 TXTNUM - routine TeXT line NUMber
The TXTNUM symbol points to the current line of code extracted from the ^COM("TXT") global subtree.
7.21.4 Block Description
122
7.21.4.1 START
The START block performs the following tasks;
1. Test the DELIMiter from COMTOK
1. for a space - End of Command and Level
2. or a comma - End of Level only
2. Test for a SET type of command and set ASET to "SET".
3. If after an equals sign, set ASET to "REF"erence.
4. If the CoMmanD was a KILL, set ASET to "KIL".
5. Set CMDEND to LINEND or CMDEND (ie. LINe END is the end of the command).
6. If there was no TOKen extracted, do the RECURS block.
7. Log the TOKen that was extracted.
8. Test for symbol type errors
1. Test for a percent symbol being set in a non-percent routine.
2. Test for a non-percent symbol being referenced in a percent routine.
9. Do the RECURS block.
7.21.4.2 RECURS
The RECURS routine performes the following activities.
1. The COMSTRG routine is invoked if DELIMitor was a double quote.
2. If the end of the command was reached, QUIT the RECURS block.
3. The COMARG routine is called if the delimitor was a left parenthesis. That indicates that a subscript or group set has been found.
123
7.21.5 Errors Generated by This Routine
7.21.5.1 "1C1" - Non-%ROUTINE Creates "%" Variable
This is a means of identifying interface variables that should only be used for setting up the calling of a utility routine or for reading status or results from a utility. These are areas of concern and potential misunderstanding about symbol interfaces with utilities.
7.21.5.2 "1C2" - Non "%" Scratch Variable Survives %Routine
The referencing of non "%" variables by utility routines is a means that a programmer can inadvertently step on himself. Care should be used when designing utilities so that this eventuality can be avoided. The golden rule is to keep the number of communications symbols to a minimum.
124
7.22 COMTIME - Time and Date Utility
7.22.1 Routine Purpose
This routine provides the utility function of supplying the current date and time in the %T string.
7.22.2 Environmental Concern
The COMTIME routine is a utility and relies on nothing else in the package. It does not destroy anything but replaces the single variable, %T which is the only product. For the DSM-11 version, the %H routine must exist as distributed by the vendor.
7.22.3 Symbol Definitions
This is the easy part. If this is the VAX version, there is only one symbol, %T. %T is in the format of date and time for output. It may be customized to site preference.
7.22.4 Block Description
COMTIME returns a single variable, %T that contains the time and date in format that is acceptable for the Compliance Checker listing and display. This has been singled out because a DSM extension has been used to accomplish this task. In this example, the date and time are reported in the following format.
15-JUN-1985 11:43:07.15
7.22.5 Compatability Enhancement
As stated before, The only important variable returned from this routine is %T. However the date and time is returned to the Compliance Checker, it should be returned in %T. The modifcations are many and pretty simple. This is one alternative.
125
7.23 COMTOK - Get Next Token and Delimiter
7.23.1 Routine Purpose
The token extractor, COMTOK, returns the next token and its following operator (DELIMitor) from the LINE variable. The starting point for the token scan is a pointer called LINPNT. The token, if it exists, will be in TOK. The DELIMiter (operator) will be in DELIM, if it exists. If the last character, C, is NULL, that means that we have hit the end of the line. If C is a semi-colon, ";", the rest of the line is a comment and ignored. The end of the LINE string is indicated by the flag, LINEND.
7.23.2 Environmental Concern
This routine needs very little to operate. What is required is;
1. The LINE buffer is to contain a string that parses like MUMPS code
2. LINPNT points somewhere within the LINE buffer
As output, COMTOK has small number local symbols it provides.
1. DELIM - The next delimiter after the point LINPNT was indicating
2. LINEND - When no more characters may be returned, LINEND=1
3. LINPNT - is incremented each time the ^COMTOK routine is called
4. TOK - The token after the pointer LINPNT indicates
7.23.3 Symbol Definitions
7.23.3.1 C - sCratch variable
This variable is used to hold the current character extracted from the LINE buffer. It is useful only as a short term symbol and has no significance once this routine has been exited.
126
7.23.3.2 DELIM - last DELIMiter parsed
The filling of this symbol indicates the end of this routine. Parsing continues until a delimiter is found or the end of the line is encountered. The types of characters that are accepted as DELIM are all of the characters except;
1. all alpha-numerics (A thru Z, a thru z, and 0 thru 9)
2. the three characters (%, ^, and $)
1. % - Legal in a Symbol or Label Name
2. ^ - Legal in an External Routine or Global Name
3. $ - Legal in Function References
7.23.3.3 I - Scratch FOR Loop Symbol
The I symbol is expendible at the end of the execution.
7.23.3.4 LINE - MUMPS code LINE buffer
LINE is refilled by the COMLINE routine. It holds a single line of MUMPS code.
7.23.3.5 LINEND - LINe END flag
The LINPNT flag is set when LINPNT points off the end of the LINE buffer. This is indicated when the $EXTRACT of LINE, as pointed to by LINPNT, returns a NULL.
7.23.3.6 LINPNT - LINe PoiNTer
LINPNT is a pointer into the LINE buffer. LINPNT is a place holder in the LINE buffer to indicate the position where parsing left off. When COMTOK gets executed again, LINPNT points to the next character to be separated from the LINE buffer.
127
7.23.3.7 TOK - TOKen parsed from LINE
TOKen is the next string of characters that does not contain delimiters. This will be the next command, argument, symbol, or label to be examined by the Compliance Checker package.
7.23.4 Block Description
7.23.4.1 INIT - Token and Delimiter Clearing
As this routine is entered, TOK and DELIM are set to NULL. This prevents old data from being evaluated a second time by the package.
7.23.4.2 START - Begin Parsing the LINE Buffer
As the input buffer is scanned, LINE using LINPNT as the starting point in the loop indexed by I. As soon as a value for DELIM or LINEND has been set, the FOR-Loop is exited and LINPNT is reset to the last value of I plus 1. This prepares for the next calling of COMTOK.
But while still in the FOR-Loop, the character in C is determined as not a delimiter. The character can safely be added to the token, TOK.
What is a delimiter? It is defined as any character that is not of the set 1 alpha or numeric or of the special group "%", "^", or "$".
7.23.4.3 GETCHR
LINE is actually manipulated by GETCHR. The character is saved in C. The character in C is tested to see if it was a delimitor. If so, DELIM is set to that character. This will be the ending condition of this call to COMTOK.
As soon as the end of LINE has been reached, C will be NULL. The LINEND flag is set when a null is returned in C or a comment character has been found.
128
8.0 WAIVERS TO COMPLIANCE CHECKER _____________________________
8.1 "1C1" - Non-%ROUTINE Creates "%" Variable
Routine: COMTIME
START S %T=$P($ZH,",",3) ^1 <** 1C1 Non-%ROUTINE Creates "%" Variable **> START^COMTIME SET
This is a utility item. As such, it deserves to be treated as one. Each facility has its own means of establishing a date and time format. This is just a convenient means of supplying a consistent front end for this date and time feature to interface with the Compliance Checker.
The user need only substitute a call to his home utility for generating a date and time and set the %T symbol to that string. This will provide the current time and date for the different reports used in the Compliance Checker.
8.2 "2A1" - Title Line Not a Single "DO" Command
Routine: COMERR
COMERR Q:ERRTYP="" ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ^1 <** 2A1 Title Line Not a Single "DO" Command **> COMERR^COMERR QUIT
It was felt that this routine had only one real block involved. As such, the overhead of the initial calling block was not needed. Also this gave us the opportunity to demonstrate this error situation.
129
8.3 "3D1" - Potentionally Recursive Block Found
8.3.1 Waiver for Recursion in COMLSTK
Routine: COMLSTK
^COMLSTK ; THREADS FLOW OF EACH ROUTINE LABEL ; 26-JUN-1985 ; RCR ! EXIT ! INIT ! START ! ! NEXTREF ! ! ! GETPR ! ! ! ! RECURS ! ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! ! STEPR ! ! ! LOADBF ! ! +-NEXTREF < STRUCTURE PREVIOUSLY DEFINED > < RECURSIVE AT THIS LEVEL > ^2 <** 3D1 Potentially Recursive Block Found **> NEXTREF^COMLSTK
This routine provides a structured label walk for the routine last processed. In order to not have the process limited by the depth of call, the routine was written as recursive. NEXTREF provides a linkage to the next level of call within the stored relational reference structure, COM("LREF",label,label1).
130
8.3.2 Waiver for Recursion in COMSTK
Routine: COMSTK
^COMSTK ; THREADS FLOW OF COMPLY ROUTINES ; 4-APR-1985 ; RCR ! EXIT ! INIT ! START ! ! LOADBF ! ! NEXTRTN ! ! ! RECURS ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! +-START < STRUCTURE PREVIOUSLY DEFINED > < RECURSIVE AT THIS LEVEL > ^2 <** 3D1 Potentially Recursive Block Found **> START^COMSTK
This situation is very similar to the recursion found in the COMLSTK routine. This, too, is a means of avoiding a great deal of limited but similar code. This recursion allows us to descend as many levels into the structure of a package as our user partition can handle. It has successfully descended more than 40 levels of recursion while parsing the VA File Manager Package.
131
8.4 "3D2.1:4" - Recursive Routine Found
Routine: COMARG
<6> COMARG <7> COMERR < PREVIOUS >>> <7> COMFUNC <8> COMARG < PREVIOUS >>> < RECURSIVE AT THIS LEVEL > ^1 <** 3D2 Recursive ROUTINE Found **> COMARG <8> COMERR < PREVIOUS >>> <7> COMPOST <8> COMARG < PREVIOUS >>> < RECURSIVE *** ^2 <** 3D2 Recursive ROUTINE Found **> COMARG <8> COMERR < PREVIOUS >>> <7> COMRLAB <8> COMARG < PREVIOUS >>> < RECURSIVE *** ^3 <** 3D2 Recursive ROUTINE Found **> COMARG <8> COMERR < PREVIOUS >>> <8> COMTOK < PREVIOUS >>> <7> COMSTRG <8> COMERR < PREVIOUS >>> <7> COMSYM <8> COMARG < PREVIOUS >>> < RECURSIVE *** ^4 <** 3D2 Recursive ROUTINE Found **> COMARG <7> COMTOK < PREVIOUS >>>
Recursively called from COMSYM, COMFUNC, COMRLAB, and COMPOST. Within each of these four groups, the Argument is redefined in the BNF (Bauchus-Naur Forms) structures that descibe the language. This allows us to prepare for any depth the implementor may inflict upon this poor model.
As an example, we offer the following;
WRITE:$P(ABC,$E(DEF),$R(3)+1) POSTCONDITIONAL contains an ARGUMENT which is a FUNCTION which contains an ARGUMENT which is a SYMBOL which is followed by another ARGUMENT which is a FUNCTION which contains another ARGUMENT which is the SYMBOL, DEF. This FUNCTION is followed by another FUNCTION that contains an ARGUMENT which is a SYMBOL and is followed by an operator and another SYMBOL before first Function is closed and the POSTCONDITIONAL is complete.
And this is not a very complicated example. Programmers are capable of much worse. The COMARG routine handles the
132
distribution from SYMBOL to FUNCTION to LABEL reference to POSTCONDITIONAL. Without this routine, a great deal more code would have to be written to cover all the myriad ways.
8.5 "3E" - Previously Defined Block Invoked
8.5.1 Waiver for COMLSTK Previously Defined Block
Routine: COMLSTK
F I(P)=1:1:$L(BF(P),",") D GETPR,NEXTREF:PASS ^1 <** 3E Previously Defined Block Invoked **> NEXTREF+5^COMLSTK DO
This is the mechanism by which the recursion is accomplished for the label structure routine. It is difficult to predict how deep a programmer will nest label references within his routine. This provides a nifty means of covering all of the potential approaches the programmer might throw at the package. This approach boarders on the "cleaver code" concept, so it can only be identified as nifty, not excellent. An excellent solution would be both lucid and functional. In this case, we had to settle for functional rather than lucid.
8.5.2 Waiver for COMSTK Previously Defined Block
Routine: COMSTK
F I(P)=1:1:$L(BF(P),",") D NEXTRTN,START:PASS ^1 <** 3E Previously Defined Block Invoked **> START+5^COMSTK DO
The mechanism here is very similar to the same error found in the COMLSTK routine. In an effort to minimize the amount of code required to do this task. This is the mechanism by which the recursion is accomplished for the package structure routine. It is difficult to predict how deep a package will nest routine calls within itself.
8.6 "3I" - Unreferenced Label
133
8.6.1 Waiver for Unreferenced label in COMRTN
Routine: COMRTN
ERRTRAP ^1 <** 3I Unreferenced label **> ERRTRAP^COMRTN
This is a means of providing a safety net for the beginning of loading subsequent routines. The $ZTRAP is set with this label to jump to if the next routine to be loaded does not exist. The ERRTRAP block will store the routine name as being in error, mark the routine as having been processed, and return to process the next routine.
8.6.2 Waiver for Unreferenced label in COMRSEL
Routine: COMRSEL
ERRTRAP ^1 <** 3I Unreferenced label **> ERRTRAP^COMRSEL
This is a means of providing a safety net for the beginning of loading subsequent routines. The $ZTRAP is set with this label to jump to if the next routine to be loaded does not exist. The ERRTRAP block will report the current error causing the trap. This action forces a reload of the COMRSEL routine and will then proceed. Control is recovered by the COMRSEL routine and the user is again prompted for a routine name.
134
8.7 "4D" - XECUTE Command Found
8.7.1 Waiver for XECUTE Command in COMRSEL
X LOADTST 1 <**4D XECUTE COMMAND Found **> PROMPT+6^COMRSEL
This XECUTE command TESTS the existence of the select=ed rou=tine by trying to load the specified routine into the rou=tine buffer. Should the load fail, the execution will be trapped to routine COMLDERR. All this routine will do is 1) report the error, and 2) reload the COMRSEL routine (indicated by the symbol RTNRTN) and return execution to where we left off.
We can tell if the load test worked or not by value of the symbol, OK. If it loaded properly, and the COMRSEL routine was restored properly, the SET command at the end of the LOADTST XECUTE will set OK to true (1).
This symbol is killed when this block is exited.
8.7.2 Waiver for XECUTE Command in COMSTORE
X CNTRL 1 <**4D XECUTE COMMAND Found **> START+6^COMSTORE
This XECUTE command controls the load=ing of the select=ed rou=tines into the rou=tine buffer. Each rou=tine is dismantl=ed one line at a time and stored into a global called ^COMP("TEXT". The second key is the rou=tine name. The third key is a sequential number indicat=ing which line of this routine is stored in this node. There is a series of lines of MUMPS code creat=ed within the symbol table. The names and call=ing order of these lines are elaborat=ed here.
CNTRL - Invokes TRANS and reloads the COMSTORE routine when done.
LOAD - Loads each routine in turn and invokes SAVE.
SAVE - Extracts each line from the routine buffer using TRNT and TXT.
TRNT - Contains a template for loading the routine lines into ^COM.
TXT - This string is modified from TRNT by SAVE.
All of these symbols are killed when this block is exited.
135
9.0 ACKNOWLEDGMENT
I would like to take this opportunity to thank Code 084 of the Naval Weapons Center, China Lake, California, for their kind indulgence in the development of this package. I would also like to thank the editorial review and suggestions of the following individuals from Computer Sciences Corporation, Kent Birch, Randal Coffee, and William Hadley. Their combined help has made this paper much more readable and hopefully more useful to the reader.
10.0 COMPLIANCE CHECKER OUTPUT _________________________
>DO ^COMPLY Compliance Checker Package, Version 1.02 Enter the routine name to start the analysis >COMPLY
BEGIN LOADING >COMPLY 2-SEP-1985 16:38:58.73
Routine stored, begin analysis
STRUCTURE LISTING FOR ROUTINE COMPLY
^COMPLY ; CHECK FOR COMPLIANCE WITH THE NWC MUMPS PROGRAMMING STANDARDS ; 28-JUL-85 ; RCR ! INIT ! ! START ! ! ! EXIT ! ! ! ! ^COMERPT ! ! ! ! ^COMSTK ! ! ! ^COMPKGE ! ! ! ^COMSTORE ! ! ! ^COMTIME ! ! ^COMRSEL
Begin Routine <COMERPT> Analysis
STRUCTURE LISTING FOR ROUTINE COMERPT
^COMERPT ; ERROR REPORT ON COMPLY PACKAGE PROGRESS ; 26-JUL-85 ; RCR ! START ! ! NEWERR ! ! REPORT ! ! ^COMTIME
136
Begin Routine <COMPKGE> Analysis
STRUCTURE LISTING FOR ROUTINE COMPKGE
^COMPKGE ; PACKAGE PARSER FOR THE COMPLIANCE CHECKER ; 2-AUG-85 ; CHRIS RICHARDSON ! START ! ! QUERY ! ! ! LIST2DO ! ! ! ! ^COMERPT ; ERROR REPORT ON COMPLY PACKAGE PROGRESS ; 26-JUL-85 ; RCR ! ! ^COMRTN
Begin Routine <COMRSEL> Analysis - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - X LOADTST ^1 <** 4D XECUTE Command Found **> PROMPT+6^COMRSEL XECUTE
STRUCTURE LISTING FOR ROUTINE COMRSEL
^COMRSEL ; ROUTINE NAME ENTRY AND LOADING ; 17-MAR-85 ; RCR ! EXIT ! INIT ! START ! ! PROMPT
UNREFERENCED LABEL STRUCTURES
ERRTRAP ^2 <** 3I Unreferenced label **> ERRTRAP^COMRSEL
ERROR DISTRIBUTION FOR COMRSEL 2-SEP-1985 16:42:00.57 COUNT ERROR DESCRIPTION 1 3I Unreferenced label 1 4D XECUTE Command Found
2 ERRORS HANDLED FOR THIS ROUTINE
137
Begin Routine <COMRTN> Analysis
STRUCTURE LISTING FOR ROUTINE COMRTN
^COMRTN ; LOAD AND PARSE A ROUTINE ; 24-AUG-85 ; RCR ! EXIT ! START ! ! CLRTN ! ! PRSRTN ! ! ! ^COMBLK ! ! ! ^COMERR ! ! ! ^COMFLIN ! ! ^COMLSTK ! ! ^COMRPRT ! ! ^COMSTORE
UNREFERENCED LABEL STRUCTURES
ERRTRAP ^1 <** 3I Unreferenced label **> ERRTRAP^COMRTN ! ^COMERR
ERROR DISTRIBUTION FOR COMRTN 2-SEP-1985 16:42:57.45 COUNT ERROR DESCRIPTION 1 3I Unreferenced label
1 ERRORS HANDLED FOR THIS ROUTINE
Begin Routine <COMBLK> Analysis
STRUCTURE LISTING FOR ROUTINE COMBLK
^COMBLK ; PARSES BLOCKS OF CODE FROM A ROUTINE ; 18-MAY-85 ; RCR ! START ! ! LINPARS ! ! ! ^COMERR ! ! ! ^COMMAND ! ! ^COMERR ! ! ^COMLINE
138
Begin Routine <COMERR> Analysis - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - COMERR Q:ERRTYP="" ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ^1 <** 2A1 Title Line Not a Single "DO" Command **> COMERR^COMERR QUIT
STRUCTURE LISTING FOR ROUTINE COMERR
^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR
ERROR DISTRIBUTION FOR COMERR 2-SEP-1985 16:43:52.06 COUNT ERROR DESCRIPTION 1 2A1 Title Line Not a Single "DO" Command
1 ERRORS HANDLED FOR THIS ROUTINE
Begin Routine <COMFLIN> Analysis
STRUCTURE LISTING FOR ROUTINE COMFLIN
^COMFLIN ; FIRST LINE OF ROUTINE PARSING ; 17-MAY-85 ; RCR ! EXIT ! START ! ! COMMENT ! ! ! DATE ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ^COMLINE ! ! ^COMMAND
Begin Routine <COMLINE> Analysis
STRUCTURE LISTING FOR ROUTINE COMLINE
^COMLINE ; GET ONE LINE OF CURRENT ROUTINE TO PARSE ; 17-MAY-85 ; RCR ! START ! ! GETLAB ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! ^COMLAB ! ! ! ^COMTOK ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR
139
Begin Routine <COMLAB> Analysis
STRUCTURE LISTING FOR ROUTINE COMLAB
^COMLAB ; LOAD NEW LABEL AND CHECK FOR PREVIOUS REFERENCE ; 17-MAY-85 ; RCR ! START ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR
Begin Routine <COMLSTK> Analysis - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - F I(P)=1:1:$L(BF(P),",") D GETPR,NEXTREF:PASS ^1 <** 3E Previously Defined Block Invoked **> NEXTREF+4^COMLSTK DO
STRUCTURE LISTING FOR ROUTINE COMLSTK
^COMLSTK ; THREADS FLOW OF EACH ROUTINE LABEL ; 26-JUN-1985 ; RCR ! EXIT ! INIT ! START ! ! NEXTREF ! ! ! GETPR ! ! ! ! RECURS ! ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! ! STEPR ! ! ! LOADBF ! ! +-NEXTREF < STRUCTURE PREVIOUSLY DEFINED > < RECURSIVE AT THIS LEVEL > ^2 <** 3D1 Potentially Recursive Block Found **> NEXTREF^COMLSTK ! ! PASS2 ! ! ! NEXTREF < PREVIOUS >>> ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! PASS2CK
ERROR DISTRIBUTION FOR COMLSTK 2-SEP-1985 16:48:43.30 COUNT ERROR DESCRIPTION 1 3D1 Potentially Recursive Block Found 1 3E Previously Defined Block Invoked
2 ERRORS HANDLED FOR THIS ROUTINE
140
Begin Routine <COMMAND> Analysis
STRUCTURE LISTING FOR ROUTINE COMMAND
^COMMAND ; COMMAND - VALIDATES COMMANDS AND DRIVES ARGUMENT SCAN ; 11-AUG-85 ; RCR ! START ! ! ARGINIT ! ! COMGET ! ! ! BLKCHK ! ! ! ! NOACS ! ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! DEFCMD ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR < STRUCTURE PREVIOUSLY DEFINED > ! ! ! VALCMD ! ! ! ! CMDVRIF ! ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR < PREVIOUS >>> ! ! ! ! DEFCMD < PREVIOUS >>> ! ! ! ^COMPOST ! ! CONTROL ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ^COMARG ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ^COMTOK
Begin Routine <COMARG> Analysis
STRUCTURE LISTING FOR ROUTINE COMARG
^COMARG ; SPLIT OUT ARGUMENTS FROM COMMAND SETS ; 28-JUL-85 ; RCR ! EXIT ! INIT ! START ! ! DLMBLK ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! ^COMPOST ! ! ! ^COMSTRG ! ! TOKARG ! ! ! FORTYP ! ! ! ! ^COMSYM ! ! ! ^COMFUNC ! ! ! ^COMRLAB ! ! ! ^COMSYM ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ^COMTOK
141
Begin Routine <COMFUNC> Analysis
STRUCTURE LISTING FOR ROUTINE COMFUNC
^COMFUNC ; PARSE FUNCTION AND SYTEM VARIABLE SYNTAX ; 13-APR-85 ; RCR ! START ! ! SPLTFUN ! ! ! GETFUN ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! GETLVL ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR < STRUCTURE PREVIOUSLY DEFINED > ! ! ! ^COMARG ; SPLIT OUT ARGUMENTS FROM COMMAND SETS ; 28-JUL-85 ; RCR ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR
Begin Routine <COMPOST> Analysis
STRUCTURE LISTING FOR ROUTINE COMPOST
^COMPOST ; POSTCONDITIONAL HANDLER ; 10-APR-85 ; RCR ! EXIT ! START ! ! POSTEND ! ! ^COMARG ; SPLIT OUT ARGUMENTS FROM COMMAND SETS ; 28-JUL-85 ; RCR ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR
Begin Routine <COMRLAB> Analysis
STRUCTURE LISTING FOR ROUTINE COMRLAB
^COMRLAB ; LABEL REFERENCE ROUTINE ; 15-MAY-85 ; RCR ! START ! ! LABSPLT ! ! ! RTNREF ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! ! ! ^COMTOK ! ! RTNREF ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR < STRUCTURE PREVIOUSLY DEFINED > ! ! SYMSRC ! ! ! ^COMARG ; SPLIT OUT ARGUMENTS FROM COMMAND SETS ; 28-JUL-85 ; RCR ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR
Begin Routine <COMRPRT> Analysis
STRUCTURE LISTING FOR ROUTINE COMRPRT
^COMRPRT ; ERROR REPORT ON LAST ROUTINE ; 28-JUL-85 ; RCR ! START ! ! REPORT ! ! ^COMTIME
142
Begin Routine <COMSTK> Analysis - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - F I(P)=1:1:$L(BF(P),",") D NEXTRTN,START:PASS ^1 <** 3E Previously Defined Block Invoked **> START+5^COMSTK DO
STRUCTURE LISTING FOR ROUTINE COMSTK
^COMSTK ; THREADS FLOW OF COMPLY ROUTINES ; 4-APR-1985 ; RCR ! EXIT ! INIT ! START ! ! LOADBF ! ! NEXTRTN ! ! ! RECURS ! ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR ! +-START < STRUCTURE PREVIOUSLY DEFINED > < RECURSIVE AT THIS LEVEL > ^2 <** 3D1 Potentially Recursive Block Found **> START^COMSTK
ERROR DISTRIBUTION FOR COMSTK 2-SEP-1985 16:56:25.58 COUNT ERROR DESCRIPTION 1 3D1 Potentially Recursive Block Found 1 3E Previously Defined Block Invoked
2 ERRORS HANDLED FOR THIS ROUTINE
Begin Routine <COMSTORE> Analysis - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - X CNTRL ^1 <** 4D XECUTE Command Found **> START+1^COMSTORE XECUTE
STRUCTURE LISTING FOR ROUTINE COMSTORE
^COMSTORE ; LOAD ROUTINE NAMES INTO ^COM("TEXT") ; 2-DEC-84 ; CHRIS RICHARDSON ! INIT ! START
ERROR DISTRIBUTION FOR COMSTORE 2-SEP-1985 16:56:50.63 COUNT ERROR DESCRIPTION 1 4D XECUTE Command Found
1 ERRORS HANDLED FOR THIS ROUTINE
143
Begin Routine <COMSTRG> Analysis
STRUCTURE LISTING FOR ROUTINE COMSTRG
^COMSTRG ; STRING HANDLER ; 30-JUL-85 ; RCR ! EXIT ! START ! ! STRPRS ! ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR
Begin Routine <COMSYM> Analysis
STRUCTURE LISTING FOR ROUTINE COMSYM
^COMSYM ; PARSE STORAGE REFERENCES (GLOBALS AND LOCALS) ; 28-JUL-85 ; RCR ! START ! ! RECURS ! ! ! ^COMARG ; SPLIT OUT ARGUMENTS FROM COMMAND SETS ; 28-JUL-85 ; RCR ! ! ! ^COMSTRG ; STRING HANDLER ; 30-JUL-85 ; RCR ! ! ^COMERR ; ERROR REPORT HANDLER ; 28-JUL-85 ; RCR Begin Routine <COMTIME> Analysis - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - START S %T=$P($ZH,",",3) ^1 <** 1C1 Non-%ROUTINE Creates "%" Variable **> START^COMTIME SET
STRUCTURE LISTING FOR ROUTINE COMTIME
^COMTIME ; TIME AND DATE RETURNED IN %T ; 15-JUN-85 ; RCR ! START
ERROR DISTRIBUTION FOR COMTIME 2-SEP-1985 16:58:07.98 COUNT ERROR DESCRIPTION 1 1C1 Non-%ROUTINE Creates "%" Variable
1 ERRORS HANDLED FOR THIS ROUTINE
Begin Routine <COMTOK> Analysis
STRUCTURE LISTING FOR ROUTINE COMTOK
^COMTOK ; GET NEXT TOKEN AND DELIMINATOR ; 11-APR-85 ; RCR ! START ! ! GETCHR
144
STRUCTURE LISTING FOR COMPLY COMPLY <2> COMERPT <3> COMTIME <2> COMPKGE <3> COMERPT < STRUCTURE PREVIOUSLY DEFINED > <3> COMRTN <4> COMBLK <5> COMERR <5> COMLINE <6> COMERR < PREVIOUS >>> <6> COMLAB <7> COMERR < PREVIOUS >>> <6> COMTOK <5> COMMAND <6> COMARG <7> COMERR < PREVIOUS >>> <7> COMFUNC <8> COMARG < PREVIOUS >>> < RECURSIVE AT THIS LEVEL > ^1 <** 3D2 Recursive ROUTINE Found **> COMARG <6> COMARG <8> COMERR < PREVIOUS >>> <7> COMPOST <8> COMARG < PREVIOUS >>> < RECURSIVE *** ^2 <** 3D2 Recursive ROUTINE Found **> COMARG <6> COMARG <8> COMERR < PREVIOUS >>> <7> COMRLAB <8> COMARG < PREVIOUS >>> < RECURSIVE *** ^3 <** 3D2 Recursive ROUTINE Found **> COMARG <6> COMARG <8> COMERR < PREVIOUS >>> <8> COMTOK < PREVIOUS >>> <7> COMSTRG <8> COMERR < PREVIOUS >>> <7> COMSYM <8> COMARG < PREVIOUS >>> < RECURSIVE *** ^4 <** 3D2 Recursive ROUTINE Found **> COMARG <6> COMARG <8> COMERR < PREVIOUS >>> <8> COMSTRG < PREVIOUS >>> <7> COMTOK < PREVIOUS >>> <6> COMERR < PREVIOUS >>> <6> COMPOST <7> COMARG < PREVIOUS >>> <7> COMERR < PREVIOUS >>> <6> COMTOK < PREVIOUS >>> <4> COMERR <4> COMFLIN <5> COMERR < PREVIOUS >>> <5> COMLINE < PREVIOUS >>> <5> COMMAND < PREVIOUS >>>
145
<4> COMLSTK <5> COMERR < PREVIOUS >>> <4> COMRPRT <5> COMTIME < PREVIOUS >>> <4> COMSTORE <2> COMRSEL <2> COMSTK <3> COMERR <2> COMSTORE <2> COMTIME ERROR DISTRIBUTION 2-SEP-1985 16:58:34.91 COUNT ERROR DESCRIPTION 1 1C1 Non-%ROUTINE Creates "%" Variable 1 2A1 Title Line Not a Single "DO" Command 2 3D1 Potentially Recursive Block Found 4 3D2 Recursive ROUTINE Found 2 3E Previously Defined Block Invoked 2 3I Unreferenced label 2 4D XECUTE Command Found
14 ERRORS HANDLED 23 ROUTINES PROCESSED
146
11.0 SAMPLE SYMBOL TABLE ___________________
C= F=SYM.DAT M=2 P=1 %T=28-AUG-1985 05:22:57.33 ABRT=0 ALVL=0 APST=0 ASET=REF BF(2)=COMERPT,COMPKGE,COMRSEL,COMSTK,COMSTORE,COMTIME BF(3)=COMERR BF(4)=COMBLK,COMERR,COMFLIN,COMLSTK,COMRPRT,COMSTORE BF(5)=COMTIME BF(6)=COMARG,COMERR,COMPOST,COMTOK BF(7)=COMARG,COMERR BF(8)=COMARG,COMERR,COMSTRG BLKEND=1 CCMD= CMD=COMARG CMDARG= CMDCNT=8 CMDDEF=T\100\\ CMDEND=0 CMDMSK=100 CMDONE=0 CPST=0 DELIM= EQUFLG=0 ERRCNT("1C1")=1 ERRCNT("2A1")=1 ERRCNT("3D1")=2 ERRCNT("3D2")=4 ERRCNT("3E")=2 ERRCNT("3I")=2 ERRCNT("4D")=2 FLVL=2 FRSTRTN=COMPLY FSAV=S\N*\N* I(2)=6 I(3)=1 I(4)=6 I(5)=1 I(6)=4 I(7)=2 I(8)=3 LABEL= LABRTN=COMARG <6> LINE= LINEND=1 LINPNT=18
147
LINPRT=0 LISDEV=0 LLCNT=5 LP00=2 LP01=1 LST=4 MAXL=80 MSG= < RECURSIVE *** MSG2= < PREVIOUS >>> NUMER=10 PASS=1 PG(1)=COMPLY PG(2)=COMTIME PG(3)=COMERR PG(4)=COMSTORE PG(5)=COMTIME PG(6)=COMTOK PG(7)=COMERR PG(8)=COMSTRG PKGEND=1 PKGID=COM POSTC=0 PR=COMTIME PROD=0 PSTYP=1 RERCNT("3D2")=4 RNUMER=4 RT= RTN= RTNEND=0 RTNLAB=COMARG <6> RTNNUM=23 SCN=COMTIME SPCR= - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TMP=! TOK=QUIT TXTNUM=4 WRN=
148
12.0 Standards Document __________________
MUMPS Programming Standards or How I Stopped Worrying and Learned to Love MUMPS
by
Robert C. (Chris) Richardson Computer Scientist Computer Sciences Corporation P. O. Box 2217 Ridgecrest, California 93555
ABSTRACT ________
The MUMPS programming language has been called cryptic by its detractors and concise by its advocates.
Applications are all too often developed as network models rather than a hierarchical models, and this can make the program flow mathematically unprovable. The result may well be difficult to decipher let alone support.
At the Naval Weapons Center in China Lake, we have developed some programming standards to aid our programmers in developing good coding techniques. This paper provides a list of these guide lines. These standards should be a guide line and not a stick. We are providing a compliance checker for our program- mers, which allows our programmers to test themselves against the standard. They then develop a consistent programming style which any of the other programmers may follow.
149
BACKGROUND __________
The major MUMPS application at the Naval Weapons Center (Code 084) is the Integrated Disbursing and Accounting (IDA) system. We are currently running DSM-11 on a PDP-11/34 (the production system) and using DSM running on a VAX-11/780 (our development system). We will soon be upgrading the 11/34 to an 11/44.
We have also been using MUMPS for some scientific applications. This includes a parser for 30,000 lines of assembler for the processor on a missile. The parsed tables were then used to generate pseudo-Pascal code.
Additionally, we have Dr. Richard Walter's Micro-MUMPS running on several DEC Rainbows.
"I never met a piece of MUMPS code that I didn't want to rewrite." - Anonymous.
"MUMPS is an Anarchist's dream." - Anonymous.
The Standards _____________
As stated in the abstract, a standard should not be a stick used to make a programmer conform. It should be a series of guide lines on how a shop or a group of programmers should develop code. This allows any of the members of the group to support the code of any of the others.
RATIONALE: __________________________
1. Routine Naming Conventions^COMDOC(8822) __________________________
A. The first label of a routine should be the same as the name of the routine itself.
150
This allows us to make a backup or second version of a routine without impacting the production version and not losing the identity of the original source routine.
B. Routines in the same package should share the same first three letters.
Quite often a MUMPS application package will contain more than a single routine. We recommend that the routines directly associated with a package share the same three character prefix. This allows the routines that are closely related to be listed together. There are usually utilities that allow the selection of groups of routine names. This allows the grouping of related routines.
C. Utility routines
Utilities are a big feature of MUMPS. MUMPS allows the creation of special routines that may be invoked by, but not changed by the user. These routines all start with a "%" character.
* Utility routine names should begin with a '%' (percent) character.
Manager utility routines are an important feature. They allow code to be accessible to users elsewhere on the system. They may use this code, but may not modify it.
* Utility variables should also begin with a '%' character.
Percent variables are reserved for utility routines. This keeps the utility routines from impacting the applications routines which call them. There can't be any confusion over utility variables that start with '%' and application routine variables where the first character may not be '%'.
2. First Line Conventions ______________________
The %FL (First Line) utility supplied with most MUMPS implementa- tions creates a list of the first lines out of each of a series of routines. As mentioned earlier the first three characters of each routine name in a package must be the same. This allows %FL to sort routines of a single functional area (package) together. This in turn allows us to keep track of routines and packages.
151
A. A single "DO" command
This constraint causes every application to have a consistent execution structure, and gives the support programmer an initial understanding of how the routine works.
* In an effort to simplify and unify the execution of application segments, we have divided the execution of any program module into at most, three parts. The arguments following the "DO" command in the first line should be one or more of the following:
a. INIT - Environmental setup.
This establishes the require files and variables that must exist before the production part of the application routine.
b. START - The production portion of the application.
This is where the real work of the application is performed. It is in this area that we will establish the restart capability of the application. Should the application halt, the analyst may look to this area to restart the application run.
c. EXIT - The cleanup from the application.
This section allows us to clean up the scratch variables and globals that are not needed after the production. This is extremely important if the routine is called from a control routine.
* The first operational block below the "DO" command should be one of the labels above, (usually INIT or START).
B. A brief statement of the routine's purpose.
Since the %FL routine lists the first line of each of a series of selected routines, it allows the tracking of related routines and utilities. Routines which share similar or related function can then easily be grouped.
C. The last date the routine was updated.
The last date a routine was updated must be included on the first line. This chronicles back-up copies of a routine, and allows the most recent change to be identified. %FL makes the scanning of these routines easy.
152
D. The name of the author of the routine.
The author's name is important, but less so once these standards have been adopted. "Programming standards should be so thorough that to an outside observer, all programs appear written by the same person." ("Productivity now! (Why Wait?)", by George Proudfoot, Computerworld).
A sample first line is illuatrated in EXAMPLE 1:
EXAMPLE 1:^COMDOC(8967) __________
COMPLY DO INIT,START,EXIT; Compliance Checker Driver ; 2-APR-85 ; RCR
3. Block Structure Conventions^COMDOC(8978) ___________________________
To be consistent with block structuring, the labels mentioned in the title line should be defined immediately after the control block and should be placed in the order called. The block structuring used in this process is not the classic stepped block structure. In this technique, all blocks are defined at the same level. Only three levels are required at a time:
1) The block in question. 2) The block level that calls this block. 3) The blocks that are called from this block.
MUMPS allows the start of execution at any block level. Each block below the current level should be able to be treated as a discrete piece of code. The symbol table may be initialized to simulate the state of execution prior to entry into the block being tested.
A. Each block should have a single label for entry.
Consistent with structured design, this restraint allows for the easy definition of the hierarchical model of the application.
In MUMPS, this is doubly important since the MUMPS language allows the start of execution at any label or an offset from a label.
153
B. A Label should not be numeric.
MUMPS allows the use of numerics as labels. This practice conveys little practical information for support and there may be difficulty with this technique in certain implementations. Some implementations may try to evaluate a numeric label as a value rather than a character string.
C. No label reference should be a displacement off of a label or an alternate entry point into another routine, i.e. Avoid "DO ABLE+5" and "DO BAKER^SORT".
GOTO and DO commands use label references. The use of displace- ment and alternate entry point references are usually used to circumvent structured techniques. These should be carefully watched.
D. No block should call itself. Avoid recursion.
Recursion is a useful tool when used well. Unfortunately, few programmers use this technique properly. It is also a disguised loop. These guidelines are supposed to make loops and levels of control easy to follow.
Potential recursion, or the possibility that a routine may unintentially call itself, must also be avoided. For example, routine A calls routine B. Then routine B calls routine C. Routine C invokes routine A. Who is controlling whom?
E. No block should call a block defined above it.
This simple rule assures that the hierarchical model does not de- grade to a network model. This should extend to the application level. At the routine level, there should be no chance of in- advertent routine looping because of accidental recursion.
154
F. No program line should be over 80 characters in total length.
The importance of this recommendation is not immediately clear. MUMPS has a simple block structuring built into it. The control structure types, FOR, IF, ELSE, and GOTO, provide a line execution capability. This ability to control commands to the right of the control command implies a type of block structure. The maximum line length on a line in a routine in MUMPS is 255 characters. By limiting the length of a line to 80 characters, we force these implied blocks to be brief and concise. Another advantage is that the routines may be edited on a terminal with full screen capability. This also insures that %INDEX listings of a set of routines will not need to have rap-around lines on a 132 column listing.
G. The last command in every block should be a single unconditional "QUIT" or "HALT" command.
The ending of a block is critical to real block structuring. This insures that control does not inadvertently fall into the next block. The flow and visibility of control is essential in a support environment.
The QUIT is usually used to end a block. It provides a means of returning from a block. The use of inline QUITs is normal. It provides the means of conditionally terminating FOR commands and block return. The HALT is an emergency exit from an application.
H. No block should be longer than 20 lines of code.
MUMPS is a very concise means of coding. Most functions that should be contained in a block, can almost always be completed in less than twenty lines. This limitation also keeps the program- mer from getting concepts jumbled together in the same block.
4. Command Conventions^COMDOC(9110) ___________________
The commands in MUMPS are on the surface reminiscent of similar commands in FORTRAN or Pascal. There are some other commands that don't have analogs in any other language.
155
A. Avoid the "BREAK" command in production routines.
The BREAK command is advantageous in the evaluation and testing of code. It has no place in production code, however, since it could allow the user into Programmer Mode and thus destroy any security in the system. Nothing could be more devastating than an uninitiated end user being suddenly confronted with an operat- ing system prompt. BREAK commands must NOT have potential for execution during a live application.
C. Avoid the "ELSE" command.
The MUMPS ELSE command is unlike the 'ELSE' command in any other language, and it is potentially ambiguous. In MUMPS it tests a system environmental status flag, $TEST. It is true that $TEST does reflect the condition of the last IF command, i.e., 1 or 0 (true or false). It also provides for the testing of the successful completion of timed I/O and data base lock features.
The line at code containing the ELSE command may be preceded by variable logic that will affect the outcome of $TEST. The $TEST variable may be changed by a variety of sources. By the time $TEST is evaluated, the command that last changed $TEST may be unpredictable. The only way the ELSE should be used is directly after a device control command. See EXAMPLE 2:
EXAMPLE 2:__________
USE 0 READ !,"enter name>",NAME:10 ELSE WRITE "time out"
It was a cute idea, but it still needs work. A waiver is still required.
D. Avoid the "GOTO" command.
The GOTO is the most dangerous command in a hierarchical model. The GOTO relinquishes control of the current process to whatever label or line of code is mentioned. All of a sudden, a hierarch- ical model become a network model.
There is no CASE command in MUMPS. The GOTO is the closest thing MUMPS has to this useful command. It must be implemented very carefully as in EXAMPLE 3:
156
EXAMPLE 3: __________
DO XSPLIT QUIT XSPLIT USE 0 READ !,"enter value>",X GOTO ABLE:X<1,BAKER:X<1.25,CHARLIE:X=2,DELTA:X>2,EPSILON:1 QUIT ABLE SET X=1 QUIT BAKER SET X=X1+X QUIT CHARLIE SET X=X1-X QUIT DELTA SET X=2 QUIT EPSILON WRITES !,"X is a value between 1.25 and 2.0",?32,X QUIT
In the preceeding example, the GOTO only references blocks defin- ed immediately after itself. Any of the quit commands actually terminate block XSPLIT and not the block it belongs to. The evaluations are attached to the GOTO command after each label and colon (:) attached to the GOTO command. These are known as post- conditionals. The last evaluation, 1, is always true. If all of the other evaluations are false, this last label will be jumped to. As soon as one is found to be true, that label is selected to control the continuing execution. The QUIT at the end of the XSPLIT block is never executed.
E. Avoid the "XECUTE" command.
The XECUTE command is a really neat idea. It allows the MUMPS programmer to store MUMPS code in a string (local variable or stored as a data base). This may be used to hide non-standard code. Usually this can be useful for performing difficult activities utilizing the routine buffer.
F. Avoid the "VIEW" command.
Much of the VIEW command structure and facility is left to the implementor. Ostensibly, it is a means of viewing (and possibly changing) locations in memory. The locations in memory that are usually used are implementation dependent. This means that a waiver for this command is critical.
157
G. Avoid the "Z" - class commands and functions.
The "Z" - class commands and functions are extensions to the standard. This is a means for a software implementor to provide features to the language for inclusion in the standard. It is a laudable idea, but it inhibits the transportability of the code. This is a warning level of error. A waiver is still required to justify these features.
5. Control Structure Conventions _____________________________
FOR, GOTO, IF and ELSE are the control commands. They are used to control the execution flow of commands near them. The FOR, IF, and ELSE control the execution of commands that lie to its right. The GOTO may control the re-execution of code to its left or the redirection of control away from code to its right. This is illustrated in EXAMPLE 4:
EXAMPLE 4: __________
FOR LP01=1:1 R !,"entername>",NM QUIT:NM'?.E1C.E W "no cntrl chars"
The FOR loop will continue to ask for the name until an entry is made that contains no control characters.
A. A control command should be the first command on the line it controls.
Control commands are important. It is important to make them prominent. We do this by putting the first control command as the first command on that line. The 80 character line restric- tion helps to keep the line blocking from being too complex. One of the reasons for these constraints is to teach the programmer to program in "baby talk".
B. No more than two control level commands should be on the same line.
There is a strong tendency in most MUMPS programmers to try to stick as many commands as possible on a single line. It is possible to have many nested FOR loops on a single line. This can make the code difficult to follow.
The control commands are important. The complexity of commands around these control commands can obscure the real control of a piece of code. If more complexity is needed, a block may then
158
elaborate the complexity as a series of discrete lines.
C. Variables in the "FOR" command should be LPnn if they are used for driving a loop.
Loops are fun. Loops are easy. Loops are trouble, especially in MUMPS when the same variable may be used and changed within a FOR loop construct.
6. Variable Conventions ____________________
Variables are always a big problem. Many languages try to write a book in order to follow the variables. MUMPS maintains the symbol table intact during and after the run. There are very few assumptions involved in the use of MUMPS. The length of the variable name is not quite as important in MUMPS as in other languages. However, the use of shorter variable names in MUMPS increases the speed of execution. So there are some conflicting concerns in the MUMPS language.
The restrictions on variables are similar to those specified in other language standards. A variable should be descriptive. MUMPS has a dynamic symbol table and symbols should not survive longer than they are needed. MUMPS does allow a percent character to be used as the first character of a symbol. These are reserved as state variables for utilities (such as %AB for abort and %ERR for errors encountered within a utility process). By restricting scratch variables to one or two characters, we can quickly segregate important variables from scratch variables. Short variable names are not a problem. MUMPS maintains the symbol table even if the process errors off. It is usually easy to tell the purpose of a symbol from its contents.
Variables in MUMPS have self attributes which are available to the programmer. These are length, descendency, numeric value, and dynamic existence. Other languages require specific typing to make such attributes available.
159
A. Variables which are used in generalized utilities should start with a percent character.
The percent sign is valid if used as the first character of a local variable name. These may be created and destroyed by the programmer at will. As a matter of convention, we reserve these variables to be set by generalized utilities. Other routines may interrogate these utility interfaces upon return.
The percent sign may also be used in global names. Only routines running in the manager's partition or account may kill or create percent global nodes.
B. A variable should be created only when it is needed. It should be killed as soon as it is no longer needed.
The dynamics of the MUMPS language allow for the run-time crea- tion and destruction of local variables. This allows the application to clean up as it goes. Should a problem occur, only those variables which are still in existence will remain available in the symbol table.
C. A scratch variable (only used within a single block) may be a single character. All others should be three characters or more.
There is a strong chance that the reuse of variables outside of a particular block will cause a problem, since all local variables are common, it is easy to unintentionally step on the wrong variable. Care must be taken to insure that variables that are assumed to be only local are not inadvertently changed. By the use of the %INDEX routine, it is easy to identify where a variable is just referenced, created, or changed.
D. Avoid Indirection.
Indirection allows the programmer to use a variable to hold a string containing another variable name or MUMPS code. It sounds like using mirrors, but it is a valuable technique.
Indirection is a powerful tool in MUMPS. Like recursion, there are many who try to use this technique, unfortunately there are few who use it well. This technique is a way that a clever programmer can write unsupportable code. (You will notice I used 'clever', not 'good' programmer.) A waiver is required for the use of this powerful technique.
ENFORCMENT: ___________
160
The enforcment of a standard can be a nerve-racking experience for many programmers and their egos. This process can be helped along by the programmers having access to the compliance checking routines. These are the same routines that the quality assurance staff will be using to validate the programmer's style. He should have a waiver ready for each of the exceptions he has had to use. The programmer should be con- fronted with very few surprises from quality assurance.
The waiver process of this standards system is important. Any standard may be waivered (if the standard provides no other way of implementing the logic). The standards effort is an at- tempt to provide consistent, repeatable techniques for the generation of applications code. The waiver should be intentionally slightly difficult to generate, but definitely not impossible. It should be incentive to develop standard conform- ing code. The intent of the standard is two fold, 1) quality control and 2) programmer training.
The management staff will notice that the programmers will begin to program in similar patterns. This means that the initial software design staff doesn't have to be chained to the maintenance staff. The documentation staff will like this because there will be less 'clever' code to decipher and any exceptional code has waiver documentation to cover it. See EXAMPLE 5 for a sample waiver.
161
EXAMPLE 5:__________
1. XECUTE Waiver for COMSTORE
X CNTRL 1 <**4D XECUTE COMMAND Found **> START+6^COMSTORE
This XECUTE command controls the loading of the selected routines into the routine buffer. Each routine is dismantled one line at a time and stored into a global called ^COMP("TEXT". The second key is the routine name. The third key is a sequential number indicating which line of this routine is stored in this node. There is a series of lines of MUMPS code created within the symbol table. The names and calling order of these lines are elaborated here.
CNTRL - Invokes TRANS and reloads the COMSTORE routine when done.
TRANS - Selects each routine in turn and invokes LOAD.
LOAD - Loads each routine in turn and invokes SAVE.
SAVE - Extracts each line from the routine buffer using TRNT and TXT.
TRNT - Contains a template for loading the routine lines into ^COM.
TXT - This string is modified from TRNT by SAVE.
All of these symbols are killed when this block is exited.
162
CONCLUSION: ___________
These are the standards being used by the Computer Sciences Corporation MUMPS programmers at the Naval Weapons Center. These are just a suggestion or a starting point. DO NOT ADOPT THESE STANDARDS, adapt them to your situation.
Be sure to include a mechanism for waiver. There should be a way of circumventing any of these standards, but don't make it too easy to get a waiver. Make sure there is a good reason for the waiver and there is not a way to implement the same algorithm within the standard. Execution speed is seldom a reason for a waiver.
We are working on a routine to serve as a compliance checker. This routine will allow our programmers to develop their own programming style. We will publish this code when completed.
BIBLIOGRAPHY ____________
(1) "Productivity now! (Why wait?), by George Proudfoot, Computerworld, Vol. XIX, N. 5, February 4, 1985, page 29.
(2) "Programmer Productivity, Myths, Methods, and Morphology", by Lowell Jay Arthur, A Wiley-Interscience Publication, John Wiley and Sons, 1983.
(3) "American National Standard, Information Systems, Programming Language, MUMPS", Draft ANSI X11.1 - 1983.
INDEX _____
163
INDEX _____
13.0 INDEX
"1A" - First Label does not Match Routine Name 33, 105 "1B" - Routine fails to Match 3 Letter Prefix 33 "1C1" - Non-%ROUTINE Creates "%" Variable 124, 129 "1C2" - Non "%" Scratch Variable Survives %Routine 124 "2A1" - Title Line Not a Single "DO" Command 34, 129 "2B" - No Routine Purpose Comment 34 "2C" - Not Legal Date on Title Line 34 "2D" - No Programmer Name Given 34 "2E" - First Line Does Not Meet Standard Field Count 35 "3A" - Additional Label Found Before Last Block 43 "3B" - Numeric Label Found 43 "3C1" - Alternate Entry Label Used in Routine 95 "3C2" - Displacement Label Reference Found 96 "3D1" - Potentially Recursive Block Found 59 "3D1" - Potentionally Recursive Block Found 130 "3D2" - Recursive ROUTINE Found 112 "3D2.1:4" - Recursive Routine Found 132 "3E" - Previously Defined Block Invoked 95, 133 "3F" - Program Line Exceeds 80 Characters 47 "3H1" - Block Badly Terminated 69 "3H2" - Block Too Long 21 "3H3" - Routine Segment Too Long 48 "3H4" - Too Many Blocks in Routine 105 "3I" - Unreferenced Label 59, 133 "4A" - BREAK Command Found 71 "4B" - ELSE Command Found 72 "4C" - GOTO Command Found 72 "4D" - XECUTE Command Found 72, 135 "4E" - VIEW Command Found 72 "4F" - Z-Command Found 73 "4G" - Z-Function Found 39 "4H" - More Than 5 Commands on a Line 21 "5A" - Control Command Found After the First Command 70 "5B" - More Than 2 Control Commands Found on the Same 70 "6D" - Indirection Found 19 "7A" - Invalid Command 71 "7B" - Argument Stack Balance Error 19 "7C" - Post-Conditional Error 91 "7E" - Bad Label Delimiter 43 "7G" - Invalid Function 40 "7H" - Postconditional NOT Allowed in this Command 91 "7I" - Argument NOT Allowed For This Command 71 "7J" - Routine NOT Found 105 "7K" - Unaccessible Commands 71 A - scrAtch variable 22, 49, 97
164
INDEX _____
AB - ABort flag 99 ABRT - ABoRT flag 82, 102, 113 ACKNOWLEDGMENT 136 ACNT - Argument CouNT 13, 60 ALVL - Argument LeVeL indicator 14, 36, 60, 87, 120 APST - Argument PoSTconditional flag 14, 60, 74 ARGINIT - ARGument INITialization 67 ASET - current Argument SET level 14, 61, 74, 88, 121 Automated Tools 2 Available Options 10 BF - scratch BuFfer 50, 106 BLKCHK - BLocK terminator CHecK 68 BLKCNT - BLocK CouNT 75, 102 BLKEND - BLocK END flag 19, 31, 41, 61, 82, 103 BLKLIN - Lines Per Block 20 Block Description 17, 21, 24, 28, 32, 38, 42, 47, 55, 67, 79, 85, 90, 94, 98, 100, 104, 110, 116, 118, 122, 125, 128 C - sCratch variable 126 CCMD - Control CoMmanD buffer 44, 61, 75 CLRTN - Clear Routine 104 CMD - CoMmanD id 14, 25, 31, 50, 61, 75, 82, 88, 106, 106, 121 CMDARG - CoMmanD ARGument type 14, 36, 61, 88, 92 CMDCNT - CoMmanD CouNT 20, 25, 31, 62, 82 CMDDEF - CoMmanD DEFinition 62 CMDEND - CoMmanD END flag 15, 37, 62, 88, 121 CMDHLD - CoMmanD HoLD 62 CMDMSK - CoMmanD MaSK 62, 88 CMDONE - at least one CoMmand DONE 20, 41, 63, 82 CMDTYP - CoMmanD TYPe 63, 89 CMDVRIF - CoManD VeRIFication 69 CNTRL - transfer CoNTRoL 114 COM - COMment from external reference 50 COMARG - Command Argument Controller 12 COMBLK - Block Structure Control 19 COMERPT - Error Reporting Module 22 COMERR - Error Logging Module 25 COMFLIN - First Line Convention Handler 30 COMFUNC - Function Handler 36 COMGET - COMmand GET 67 COMLAB - Label Definition Handler 41 COMLINE - Command Line Parser 44 COMLSTK - Routine Label Stack Report 49 COMMAND - Command Handler 60 COMMENT - Dissect Parts of First Line 33 COMPKGE - Package Parsing Control 74 COMPLIANCE CHECKER OUTPUT 136
165
INDEX _____
COMPLY - Compliance Checker Entry Point 81 COMPOST - Post-Conditional Handler 87 COMRLAB - Label Reference Handler 92 COMRPRT - Routine Report Summary 96 COMRSEL - Routine Select Handler 98 COMRTN - Routine Parsing Control 102 COMSTK - Package Routine Stack Report 106 COMSTORE - Loads and Stores Routines into COM 113 COMSTRG - String Handler 117 COMSYM - Symbol Handler 119 COMTIME - Time and Date Utility 125 COMTOK - Get Next Token and Delimiter 126 CONTROL - CONTROL command handler 69 CPST - Command PoSTconditional flag 63, 75 CTRLCMD - ConTRoL CoMmanD 44, 64 Compatability Enhancement 105, 125 Compliance Checker Design 6 Compliance Checker Introduction 1 Configuration Management Approach 3 Conversion Comments 86 DATE - Date Format Check 33 DEFCMD - DEFine CoMmanD 68 DELIM - last DELIMiter parsed 15, 37, 41, 64, 89, 92, 117, 121, 127 DLMBLK - Delimitor Block 18 Documentation 5 END - Cleanup 32 ENDSTR - END of STRing flag 15, 117 EQUFLG - EQUals sign FLaG 15, 64, 121 ERNUM - ERror NUMber type count 75 ERRCNT - package ERRor CouNT array 23, 83, 97 ERRTRAP - Error Trap Handler 101 ERRTRAP - No Routine Error Trap 105 ERRTYP - ERRor TYPe to be logged 15, 20, 25, 31, 37, 42, 44, 50, 64, 83, 89, 92, 103, 107, 118, 121 EXIT - Argument Parse Exit and Cleanup 17 EXIT - Clean-up After The Command Set 67 EXIT - Cleanup 100 EXIT - Cleanup After Mapping Process 56 EXIT - Cleanup from Run 111 EXIT - Close Out of the Process 86 EXIT - End of Pass Cleanup 119 EXIT - Reset Flags and Clean-up 91 Environmental Concern 12, 19, 22, 25, 30, 36, 41, 44, 49, 60, 74, 81, 87, 92, 96, 99, 102, 106, 113, 117, 120, 125, 126 Environmental Constraints 7 Errors Generated by This Routine 21, 24, 27, 33, 39, 43, 47, 59, 69, 86, 91, 95, 98, 101, 105, 112, 116, 119, 124
166
INDEX _____
Errors Handled Directly 19 Examples 11 Explicit Errors 69 FLV - Function LeVel 37, 64 FLVL - Function LeVeL array 37, 64 FLVLCNT - Function LeVeL Control 39 FORTYP - FOR Command Handler 18 FRSTRTN - FiRST RouTiNe 83, 107 FSAV - Function SAVe 65 FSAV - Function SAVe array 37 FUNC - The name of the FUNCtion 37 Filling out the Waiver 5 GETCHR 128 GETFUN - GET the details of the FUNction 39 GETLAB - Extract the label and format 47 GETLVL - GET the function argument LeVeL of activity 39 GETPR - GET the next PRogram 57 I - Scratch FOR Loop Symbol 127 I - scratch poInter array 50, 107 INDEX 164 INIT - Initialization 85 INIT - Initialize Store Process 116 INIT - Level Initialization 17 INIT - Setup For Package Structure 110 INIT - Setup for Routine Mapping 55 INIT - Token and Delimiter Clearing 128 INKEY - INtercept KEY 75 Implied Errors 71 J - Scratch Variable 114 LABEL - LABEL from first line 31 LABEL - LABEL reference 42, 45, 76, 93, 103 LABRTN - LABel RouTiNe reference 25, 45, 50, 107 LABSPLT - LABel SPLiT 95 LINE - MUMPS code LINE buffer 26, 45, 76, 118, 127 LINEND - LINe END flag 15, 20, 31, 45, 65, 76, 89, 121, 121, 127 LINPARS - Line Parsing Within a Block 21 LINPNT - LINe PoiNTer 26, 38, 45, 51, 76, 93, 107, 118, 122, 127 LINPRT - LINe PRinT flag 26, 45, 51, 76, 107 LISDEV - LISt DEVice 26, 51, 76, 83, 108 LIST2DO - List of routines left to do 80 LLCNT - Logical Line CouNT 21, 42, 46, 77, 114 LOAD - LOAD the routine and reload COMSTORE 114 LOADBF - LOAD the level calling array, BF 57 LOADBF - Load the Level Calling Array, BF 111 LOADTST - LOAD TeST execution symbol 99 LP00 - LooP counter #00 77, 108
167
INDEX _____
LP01 - LooP counter #01 51, 77, 103, 108 LP02 - LooP counter #02 23, 51, 65, 97 LP03 - LooP counter #03 52 LP05 - LooP counter #05 89, 100 LP06 - LooP counter #06 31 LST - Length of STream 52, 77 LVLEND - argument LeVeL END 16, 65, 122 Loading Instructions for COMPLY 9 M - recursion Mark 52 MAXL - MAXimum Length of LINE 32, 46, 77 MORE - MORE undefined labels to map 52 MSG - previously defined MeSsaGe 53, 108 MSG2 - recursive MeSsaGe #2 53, 108 MUMPS Compliance Checker Philosophy 1 Modifying the Code 4 NEWERR - Accumulate New Errors 24 NEXTREF - Recursive Mapping Block 57 NEXTRTN - Handle the Next Routine 111 NOACS - NO ACceSS check 68 NUMER - NUMber of ERrors 77, 83, 97 NXT - NeXT label to test 53 NXTRTN - NeXT RouTiNe 93 OK - Oll Korrect flag 100 OKARG - OK for ARGuments 65 P - Position pointer 53, 109 PASS - PASS to the next level flag 54, 109 PASS2 - Map Unidentified Labels 56 PASS2CK - Identify Any Unidentified Labels 56 PG - ProGram name Array 54, 109 PKGEND - PacKaGe END 77, 83, 103 PKGID - PacKaGe IDentifier 32, 78, 84 POSTC - POSTConditional flag 16, 65, 78, 89 POSTEND - Test for the Postconditional End 91 PR - PRogram name 54, 109 PROD - Production Flag 84 PROMPT - Prompt for Routine Name Input 101 PRSRTN - Parse the current RTN 104 PSTEND - End of the Postconditional Flag 89 PSTYP - PoStconditional TYPe indicator 66, 78, 90 Programmer Module Breakdown 12 Programmer Training 4 QUERY - Runtime query block 79 RECURS 123 RECURS - Recursion Report 58, 111 REPORT - Report Per Error Count 98 REPORT - Report the Package Error Totals 24 RERCNT - Routine ERror CouNT array 23, 26, 97 RNUM - Routine NUMber of errors 23, 97
168
INDEX _____
RNUMER - Routine NUMber of ERrors tallied 26, 84, 97 RT - scratch RouTine name 54, 109 RTN - RouTine Name 23, 27, 32, 42, 46, 54, 78, 84, 93, 98, 100, 103, 109, 114, 122 RTNEND - RouTiNe END flag 46, 78, 84, 103 RTNLAB - RouTiNe LABel reference 27, 38, 46, 55, 78, 84, 93, 104, 109 RTNNUM - RouTiNes processed NUMber 23, 85, 115 RTNREF - RouTiNe REFerence logging 95 RTNSRC - RouTiNe SeaRCh 85, 104 Routine Purpose 12, 19, 22, 25, 28, 30, 36, 41, 44, 49, 60, 74, 81, 87, 92, 96, 98, 102, 106, 113, 117, 120, 125, 126 Run Instructions for COMPLY 10 SAMPLE SYMBOL TABLE 147 SAVE - SAVE routine to ^COM("TEXT") 115 SCN - SCaNning label name 55, 110 SFUNC - Stacked FUNCtion description array 38 SLVL - Saved set LeVeL 16, 66, 90, 122 SPCR - SPecial ChaRacter string 27, 78, 85 SPLTFUN - SPLiT the FUNction 39 START 123 START - Argument Parsing Control 17 START - Begin Actual Processing 86 START - Begin First Block Acquisition 32 START - Begin Parsing the LINE Buffer 128 START - Block Parsing Control 21 START - Control Error Report 98 START - Control Label Reference Logging 94 START - Control Line Acquisition 47 START - Control Mapping Process 56 START - Control Next Routine Load and Parse 104 START - Control Traversing the Structure 110 START - Determine If TOK Contains a Valid Function 38 START - Evaluate the Postconditional Expression 90 START - FOR Loop to Drive Prompting and Loading 100 START - Package control block 79 START - Perform Store Operation 116 START - Quote Search Control 118 START - Report Flow Control 24 START - START of process 67 STEPR - Display Label Stepping Structure 58 STRCNT - STRing CouNT 118 STRPRS - STRing PaRSe 119 SVSET - SaVe SEt Type 16, 66, 90 SYMSRC - SYMbol reference SeaRCh 94 Standards Document 149 Support 5
169
INDEX _____
Symbol Definitions 13, 19, 22, 25, 30, 36, 41, 44, 49, 60, 74, 81, 87, 92, 96, 99, 102, 106, 113, 117, 120, 125, 126 T - Scratch Symbol 32 TCM - Temporary CoMmand argument storage 93 TFUNC - Temporal FUNCtion 38 TLNP - Temporary LiNe Pointer 118 TMP - scratch variable 55, 78 TMPT - TeMPorary Token 66 TOK - TOKen parsed from LINE 17, 38, 42, 66, 79, 93, 122, 122, 128 TOKARG - Token Argument Parsing 18 TRTN - Transfer RouTiNe 115 TTOK - Temporary TOKen storage 79, 94 TXT - run-time code TeXT transfer 115 TXTNUM - routine TeXT line NUMber 27, 42, 46, 85, 116, 116, 122 The Execution 10 VALCMD - VALidate the CoMmanD 68 WAIVERS TO COMPLIANCE CHECKER 129 WRN - Available Option for Warning Message 27 Waiver for COMLSTK Previously Defined Block 133 Waiver for COMSTK Previously Defined Block 133 Waiver for Recursion in COMLSTK 130 Waiver for Recursion in COMSTK 131 Waiver for Unreferenced label in COMRSEL 134 Waiver for XECUTE Command in COMSTORE 135 $Y - Lines Used 22 $Y - universal line count 96 $ZERROR - System Error Message 99 $ZTRAP - Error Trap Trigger Set 102 $ZTRAP - System Error Trap Symbol 99 %T - Current Time 22, 96 %T - current Time 74, 82 ^COMDEF "ERR" Structure 28
170