global_and_local_symbol_assignment

This is an old revision of the document!


Global and Local Symbol Assignment

For the non-programmer, especially, who is nevertheless writing a DCL command procedure (script), the notion of global vs. local symbols (variables) and symbol tables is at first a bit confusing. This article will hopefully make these concepts more clear.

First, the Practical Matter of Notation

Any DCL symbol (variable) is created (or defined) using one of the four following assignment operators: == or :==, = or :=. Note that the first two assignment operators each use two (double) equal-signs, while the second pair uses only single equal-signs.

These four operators, when spoken aloud, are rather clumsily pronounced: “equals-equals” or “colon-equals-equals”, “equals” or “colon-equals”.

Here are the rules for creating DCL symbols:

  • Global symbols (variables) are always created (defined) with either the double == or :== assignment operators.
  • Local symbols (variables are always created (defined) with either the single = or := assignment operators.

Two Forms of Assignment Operators

Okay… but why the two forms, like == and :==? Here, DCL's HELP command sheds some light (don't attempt to use $ HELP = or $ HELP :=, as these won't work because of command parsing limitations):

$ HELP

HELP

   The   HELP   command   invokes   the  HELP  Facility  to  display
   information about a command or topic.  In response to the "Topic?"
   prompt, you can:

      o Type  the  name of the command  or topic for which you need help.
...

  Additional information available:

  :=         =          @          ABS        ACCOUNTING ACL_Editor ...

Topic? =

=

     Defines a symbolic name for a character string or integer value.

     Format

       symbol-name =[=] expression
       ...

Topic? :=

:=

     Defines a symbolic name for a character string value.

     Format

       symbol-name :=[=] string
       ...

$

Read each of these HELP sections in their entirety. From this HELP text – rather quaint: “Defines a symbolic name…”, but we know that we're just creating variables here – we discover that:

  • Both the == and = assignment operators create a DCL variable (symbol) which can contain either a character string value or a numeric (integer) value.
  • Both the :== and := assignment operators create a DCL variable (symbol) which can contain only a character string value – these assignment operators cannot create symbols having a numeric (integer) value. These operators also have side effects: Each will force the string value to all UPPERCASE letters, and will squeeze out any repeated space or tab characters, replacing those sequences with a single space character for each such sequence.

Because of those side effects (also referred to as data “normalization”), experienced DCL script programmers usually avoid, or at least limit, their use of the :== and := assignment operators, because the == and = operators are more general purpose, and make obvious what the data-type of the value being assigned to a symbol actually is (this is a rule-of-thumb, not a hard-and-fast rule).

Next, Some Definitions

  • Symbols are just Variables – Remember, as explained here, that a DCL symbol is nothing more than a DCL variable, useful for programming and computing with DCL command procedures (scripts), etc.
  • Global Symbols – A global DCL variable is visible (can be used) anywhere in a DCL process, either on the command line, within a batch process, or within a DCL command procedure at any depth (see below).
  • The Global Symbol Table – A memory-resident data structure within a VMS process which holds the names and values of all global variables defined and used by the process. There is only one such global symbol table, and it is automatically created at process creation time.
  • Local Symbols – A local DCL variable has limited visibility or scope; when defined at a particular command procedure depth (see below), a local symbol can be used (referenced) only at/within that procedure depth, or by any command procedure depth below (greater depth) its creator depth.
  • Local Symbol Tables – One or more memory-resident data structures within a VMS process which holds the names and values of all local variables defined and used by the process. A local symbol table is available automatically at command procedure depth 0 (the command line level) if/when any local variables are defined at that level; in addition, a(nother) local symbol table is created on-the-fly for each command procedural depth >0 reached by subsequent command file invocations (see below).
  • Command Procedure Depth – When one command file calls or invokes another one, that called command procedure's depth is one greater than the one which calls/invokes it. By definition, the command line's depth or level is 0 (zero). When you invoke a command file (script) from the command line – for example: $ @RECURSE (see section below) – that command file's depth or level is 1. If an executing command file calls yet another one, that called command file's depth is one greater than the one which calls it. Command file depth is limited to 31 or less; if an attempt is made to invoke a script at depth 32 or more, DCL generates the error message %DCL-W-STKOVF, command procedures too deeply nested - limit to 32 levels (believe me, a depth of 31 is sufficient).

Demonstrating Command Procedure Depth

To best understand both global and local symbol tables, it helps to get a deeper understanding of how command procedure depth works; the following demo script can help you see the behavior of procedure depth and local symbol tables.

The following command procedure, RECURSE.COM, demonstrates this notion of depth. When invoked from the command line, this script then calls itself recursively three times; each invocation displays its view of both the process's global symbol table and it's own instance of the local symbol table:

$ ! RECURSE.COM -- a recursive-call com-file demo, showing procedure depth           !  1
$ !
$ procdepth = F$ENVIRONMENT( "DEPTH" )  ! capture procedure depth in local variable  !  3
$ !
$ wso = "WRITE sys$output"              ! define this local variable (symbol)        !  5
$ wso ""                                                                             !  6
$ !
$ wso "*** == Global Symbol Table (part), always at Procedure Depth 0 ***"           !  8
$ SHOW SYMBOL /GLOBAL $S*                                                            !  9
$ wso "###  = Local Symbol Table (entire) at Procedure Depth ''procdepth' ###"       ! 10
$ SHOW SYMBOL /LOCAL *                                                               ! 11
$ !
$ IF ( procdepth .LT. 3 )                                                            ! 13
$ THEN wso ""                                                                        ! 14
$      callnumber = procdepth + 1                                                    ! 15
$      wso ">>> Recursive call #", callnumber, ": @RECURSE ''callnumber'"            ! 16
$      @RECURSE 'callnumber' ! call self recursively, up to 3 times                  ! 17
$ ENDIF                                                                              ! 18
$ !
$ wso ">>> exiting from recursion #", procdepth                                      ! 20
$ EXIT 1                                                                             ! 21
$ !

Annotations:

  • Line 3 – Assign the value of the lexical function F$ENVIRONMENT(“DEPTH”) to the local variable (symbol) procdepth.
  • Lines 5, 6, 8, 10, 14, 16 & 20 – Create the local command symbol wso, and use it to output messages and blank lines as needed.
  • Line 9 – Display a couple of symbols ($STATUS and $SEVERITY) from the global symbol table, each time this command script is recursively called (this is a selective display; dumping the entire global symbol table would be lengthy and would just obscure things here).
  • Line 11 – Display the whole local symbol table. Note that, each time RECURSE.COM calls (invokes) itself, a new local symbols table (as evidenced from its values) is created and used, one local symbol table for each command procedure depth.
  • Line 13 – Put a limit (of three) on how many times the script calls (recurses) itself.
  • Line 15 – Local symbol callnumber is the current number of calls, one greater than the current procedure depth.
  • Line 17 – The recursive call itself – RECURSE.COM invokes itself, passing the current callnumber to the next invocation as command line parameter P1, so you can see & track that value.
  • Lines 20 & 21 – Once the recursion call limit (3) is reached, each lower invocation “returns” or exits, with a tracing text message so you can see it. The very first invocation returns to the DCL command line (depth = 0) when it exits.

And here's the output/trace from invoking RECURSE.COM, invoked with an illustrative command line parameter P1 – see the above annotations as you read through this output/trace:

$ @RECURSE "from com-line depth=0"

*** == Global Symbol Table (part), always at Procedure Depth 0 ***
  $SEVERITY == "1"
  $STATUS == "%X00010001"
###  = Local Symbol Table (entire) at Procedure Depth 1 ###
  P1 = "from com-line depth=0"
  P2 = ""
  P3 = ""
  P4 = ""
  P5 = ""
  P6 = ""
  P7 = ""
  P8 = ""
  PROCDEPTH = 1   Hex = 00000001  Octal = 00000000001
  WSO = "WRITE sys$output"

>>> Recursive call #2: @RECURSE 2

*** == Global Symbol Table (part), always at Procedure Depth 0 ***
  $SEVERITY == "1"
  $STATUS == "%X00010001"
###  = Local Symbol Table (entire) at Procedure Depth 2 ###
  P1 = "2"
  P2 = ""
  P3 = ""
  P4 = ""
  P5 = ""
  P6 = ""
  P7 = ""
  P8 = ""
  PROCDEPTH = 2   Hex = 00000002  Octal = 00000000002
  WSO = "WRITE sys$output"

>>> Recursive call #3: @RECURSE 3

*** == Global Symbol Table (part), always at Procedure Depth 0 ***
  $SEVERITY == "1"
  $STATUS == "%X00010001"
###  = Local Symbol Table (entire) at Procedure Depth 3 ###
  P1 = "3"
  P2 = ""
  P3 = ""
  P4 = ""
  P5 = ""
  P6 = ""
  P7 = ""
  P8 = ""
  PROCDEPTH = 3   Hex = 00000003  Octal = 00000000003
  WSO = "WRITE sys$output"
>>> exiting from recursion #3
>>> exiting from recursion #2
>>> exiting from recursion #1
$
global_and_local_symbol_assignment.1543866512.txt.gz · Last modified: 2018/12/03 19:48 by lricker