FORCES Programming Conventions


The following programming have been adopted in JFORCES over the years:


1) All code should be written in JFORCES Pseudocode

2) All code files SHOULD have:

    Header defining the purpose of the file

    1. Sample

    2. Differences between Fortran & C
Header section for data and definitions

3) Each code procedure SHOULD have

    1. Definition of Purpose
    2. I/O Documentation
    3. Any Special Notes

4) Variable name convention

  1. Make 'em long - maintenance is MUCH easier.
  2. Capitalization
  1. Objective
  2. Current exceptions
  1. Indentation

5) Introduction to Code Autogeneration


FORCES Pseudocode

What is JFORCES Pseudocode?

FORCES Pseudocode is a simple form of pseudocode that incorporates only the following four constructs:

    1) Sequential processing

      Example:
        Initialize memory
        Verify input data
        Calculate background radiation based upon Nuclear environment
        Send information to the Umpire
        ...
Note that in sequential processing all lines are indented identically and no asterisks ("*") are used to call attention to code segments.

    2) Conditional Programming Via If/Then/Else/elseif branches

      Example:
        * if input value is greater than zero
           then process user's request applied only to this specific asset
            do x
            do y
            ... more sequential processing ...
            * if asset is an aircraft
               then raise error flag
            * end if asset is an aircraft.
           else if input value is less than zero
           then process user's request for the entire group
           else output error message - this is an error
        * end if input value is greater than zero


Note that the words of each line are indented to the same level. That is the "i" of the if statement is aligned with the t of the then statement, which is aligned with the e of the else statement, and so forth. This greatly aids reading the logic later. All lines of an if/then/else construct MUST start with "if", "then", "and", "else", "else if" or "end if". If the comments are indented (as are those starting with the word "do") they are understood to all be part of the component of the statement that's currently being evaluated (i.e. part of the "then" statement in this case.)


Note that ONLY 2 asterisks are allowed within this construct - one at the beginning of the constuct and one at the end. The purpose behind this is that the asterisks indicate the beginning and end of a self-contained code segment and that if all code is removed from between the lines indicated by asterisks (including these lines) then the code should still be functional and compilable, though probably not giving correct results. It is OK (and probably required) to have asterisks within subsegments, as illustrated above with the conditional statement starting "* if the asset is an aircraft", but these subsegments should be indenting accordingly.

Also note that sequential processing and embedded conditional & loop processing is supported within the

    3) Conditional Programming Via Case Statements

      Example:
      * case: Asset color
         case blue: asset is on the blue force
              do x
              do y
        (more sequential coding statements or other embedded logic)
         case red: asset is on the red side
         case white: asset is on the white side
         default: erroneous side - output an error message and
          prevent further processing on this asset
      * end case: Asset color


Note the similarity in indentation and use of asterisks to the if-then-else structure, as described above. See the description of these in the above comments. Notice also the the case condition (and the if condition in the above example) is repeated at the close of the code segment. While this is not required by the JFORCES pseudocode standard, and is often omited for short segments, it can be very useful to programmers maintaining the code later and so is highly recommended for long segment.s

    4) Loops (this includes loop while, loop until and so forth)

      Example:
      * loop until I've lost all my marbles
         do some more boring processing
         lose another marble
      * end loop
Again, note the indentation and use of asterisks is as described in the if-the-else clause, above. Again you can have sequential processing, conditional processing, or loops within this loop structure. All processing perinent to this loop should be done within the lines identified by the asterisks.


Why Use JFORCES Pseudocode?

At this point there's so much code written with embedded pseudocode that we would want to preserve this approach just for consistency. But we've also found this pseudocode to be excellent at incorporating reasonable comments within our code at the point most helpful for future programmers. Basically we've found that from these four constructs we can specify all programming methods within a structured language or structured code snippet. Furthermore, by incorporating the pseudocode directly into the code we:

  1. Develop well documented & standardized code
  2. Tends to keep our documentation up to date
  3. Provide an automated method for developing low level (C-spec equivalent) documentation as needed by simply extracting our pseudocode.

Pseudocode Extraction Procedure

The princple reason that the pseudocode was selected as the documentation standard in early in FORCES development is that pseudocode satisfied the C-spec programmer's documentation requirement. But it could do this only if the pseudocode could readily be extracted and delivered to the customer. Therefore the "countlines" procedure was developed. The reason for naming this procedure "countlines" is that it provided lines-of-code counts for review by managers. Editorial comments withheld. Work was being performed across multiple operating systems, so of necessity the countlines program was kept very naïve.

Countlines primary weakness at this time is that it only works on Fortran. We believe it will be extended to C and TCL in the future, and this is one of the reasons that programmers should always keep the beginning of their pseudocode comments on column 1.

To use countlines a file named "codelist" needs to be created. It will consist of this files that you want to extract the code from. For example, to extract code from all of the fortran files in the ~sim/c2 directory type and start the extraction process type:

cd c2; \ls -l *.F > codelist; countlines

You'll be notified that the following will be extracted:

  1. A list of the embedded pseudocode
  2. A "pretty" version of the code
  3. A count of all executable lines
  4. A count of all executable lines over 72 characters long

The first output is the only output we care about here. For every filename in codelist an output file named (original_name)d will be created and will contain the embedded pseudocode. For example, if the original name is addc2asset.F the embedded pseudocode will be put in addc2asset.Fd. A file named addc2asset.Fp will also be generated - this is a "Beautiful" version of the original code. In this version all comments are in uppercase and all non-literal codelines are in lower case. We no longer use this file (and it does not correspond to our current capitalization standard) so please discard these files.

Assuming that you don't ask for more information about these options, you'll be asked whether any lines over 72 characters should be echoed to the screen. This is useful only if youre converting Fortran code to a machine that can't handle extended lines. Generally you should answer "n". At this point the program should output lines-of-code information to the screen, for example:

Filename Executable LOC LOC over 72 char

addc2asset.F 50 0
addc2base.F 80 1
addc2sensor.F 74 0
addc2site.F 52 1
...
trackposition.F 19 0
total number of lines in this run = 6634

The documentation files are automatically created. To see the documentation file that was extracted from the Fortran example click here .

Information headers in Fortran and C Code

All code files should incorporate the following information:

1) The purpose of the file. This should be the unifying theme that caused the programmer to combine all of the embedded procedures into a single file. Click here for an example.

2) The data and definitions section. If the data and definitions are used only in one file I tend to incorporate them directly into the file instead of creating a stand-alone header file. If the data and/or definitions are used by multiple files then a header file is created in the ~/common directory. For example, the route structures defined in route_struct.h is included by both ~/sim/objutil/route.c and ~/sim/objutil/motion.c. So a single header named "route_struct.h" was created in the ~/common directory. All applications link to files in this directory. By convention, when the data embedded in the header file is used in a number of source files we just include the header in the application header file (e.g. sim.h, wn.h or rcvr.h). There is at least one file that is included in all of the application headers named common_prototypes.h. Put function prototypes for functions that might be used in any of these applications in this file.

At the top of every procedure within a file always specify the purpose for the procedure. See the C source code example . Note that these key components of the documentation are separated from the major code components by comment lines. These are:

in C:

/*****************************************************/

in Fortran:

c*****************************************************

in TCL:

#####################################################

These separators should only be used for the major structural elements (the file purpose, the common data & definition section, and the purpose for every procedure in the file). By limiting these separators to these sections code can quickly be scanned for individual procedures.


When writing Fortran we've found that it's simplest if each file contains only one routine. Thus the file purpose and the procedure functionality description can be collapsed - see example .


Documenting I/O

The inputs and outputs of every file should be documented. Typically we use the procedure header to document the output in C and use inline documentation for any arguments, as follows:


/*******************************************************************************************/
/*
Procedure: consider_cueing
Function: evaluates cueing options for a specific sensor
Returns: a 0 for any error; the asset ID of the cued sensor otherwise.
*/
/*******************************************************************************************/
int consider_cueing (
sensor_site *site, /* pointer to sensor site */
Asset *tgt) /* pointer to target info */
{


For Fortran this won't work, so instead we document the variables on comment lines, as follows:


c parameters:
c variable i/o   type  size description
c time        i     R*4         simulation time
c objclose  o    I*4          logical flag to say object has
c                                     reached end of route leg


The size would be the array size where appropriate.

Finally, TCL does not permit inline commenting, so we should use a system like we use for Fortran, as follows:

###############################################################
# The procedure sets up the basic table descriptor
# Arguments
#    tablename name of the table in the database
#    subtable name of the specific subtable to ues
###############################################################
proc ps_table { tablename { subtable "" } } {

In practice only the most heavily used TCL routines follow this practice, but it's the task of every programmer to update this information as the code in maintained and to document all new routines to this standard.

Variable Names

Make them long and readible. It's much easier to maintain code with variable names like "SECONDS_PER_DAY" than variables like spd.


The current stardards on capitalization that we're aiming for is:


Current Exceptions:

We're still plagued by conventions set when we were using a Fortran compiler that could not handle capitalization. Many (possibly most) of our defined variables are lower case and the names are shorter than 8 characters. E.G. nmtoft instead of NAUTICAL_MILES_TO_FEET. All programmers are requested to:

Make all new variables follow the new standard

Update old variables to the new standard as time permits and while maintaining the code.

In addition, we are still using an old convention that the define statement for a message number is in lower case while the structure name is capitalized. For example, you'll find the following define in msgdefs.h:

#define msgnewgraphicsclass 261


and the following structure definition in icd.h

typedef struct
{
int clss;
int shape;
int fill_type;
int line_type;
int lock_to_sim_entity;
float priority;
float thickness;
int color;
int icon_type;
char description[LONG_NAME_LENGTH];
char filename[FILE_NAME_LENGTH];
int rotate;
int range_bearing;
float scale;
char category[32];
int coordinates;
} MSGNEWGRAPHICSCLASS;

These standards are enforced by the autogeneration utilities, specifically the genStructs and the genMsgdefs utilities. While it would be easy to change these utilities ferreting out all the problems that might result from changing to the new standard does not seem worthwhile at this time.

Indentation:

Indentation rules are: