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.
Any DCL symbol (variable) is created (or defined) using one of the four following assignment operators:
:=. 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:
Okay… but why the two forms, like
:==? 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:
=assignment operators create a DCL variable (symbol) which can contain either a character string value or a numeric (integer) value.
:=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
:= assignment operators, because the
= 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).
$ @RECURSE(see section below) – that command file's level is 1. If an executing command file calls yet another one, that called command file's level 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).
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 $ !
F$ENVIRONMENT(“DEPTH”)to the local variable (symbol)
wso, and use it to output messages and blank lines as needed.
$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).
callnumberis the current number of calls, one greater than the current procedure depth.
callnumberto the next invocation as command line parameter
P1, so you can see & track that value.
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 $