WordPerfect 6 Macro Debugger

J. Dan Broadhead

A simple macro debugger has been implemented. The implementation is not complete, and is subject to change. The following describes the current implementation.

The debugger may be invoked in several different ways. Some of these methods cause single stepping to be turned on. Once single stepping is in effect, the macro debugger is invoked at the beginning of each macro statement. A statement is a separate macro command or product command. Multiple statements may be placed on a single macro source line, or a statement may span multiple source lines.

The easiest way to turn on single stepping is through the STEP macro command. The STEP command accepts a parameter that specifies whether single stepping of macro statements should be turned on or not. It accepts a single parameter with a value of either On! or Off!. This requires that the source of the macro be available, and that the source be modified and recompiled. This method will probably be supported in future releases.

The other methods of invoking the debugger involve the creation of BIF file settings. These may not be supported in future releases. One of these settings specifies that single stepping should be turned on immediately upon macro startup. The other setting specifies that the debugger should be invoked when an assert (error, cancel or notfound) condition occurrs that is not handled by the macro by a corresponding handler. BIF file settings are case sensitive. These settings are placed into the "WPMacroInterpreter" group, and the "Settings" section.

Single stepping is turned on at macro startup by setting the BIF setting "Invoke Debugger On Startup" to a boolean value of TRUE. The debugger is invoked on non-handled assert conditions by setting the BIF file setting "Invoke Debugger on Errors" to a boolean value of TRUE.

Once the debugger is invoked, it brings up its modal dialog interface. While the debugger interface is active, the macro execution is suspended. The dialog consists of 3 main areas. From top to bottom, these are: the current location in the macro, the call history list, and the variable list. The current location information area shows the reason for the debugger being invoked (such as statement start, error condition, etc.), the next macro statement to be executed (if source is available), and the push buttons used to dismiss the debugger. The RUN push button causes single step mode to be turned off, and the macro continues execution. Unless single step mode is again turned on within the macro, the debugger will not be invoked again. The STEP push button executes the current statement and will be invoked again at the start of the next statement. The ABORT push button causes the macro to be terminated by asserting an error condition.

Normally the source lines for the macro statements are not available to the debugger. In order to make the source lines available, a BIF setting for the Macro Compiler must be set, and the macro must be recompiled. The BIF file setting is in the "WPMacroCompiler" group, the "Settings" sections and is called "Include Debugging Information". If this setting is set to a boolean TRUE value, then the source lines for the macro statements become available to the debugger. This will cause the compiled macro to occupy nearly twice the disk space as when this setting is not used. As with the interpreter settings, this feature may not be supported in this manner in future releases.

The call history list area lists the user-defined functions/procedures and labels that have been called in reverse order. The current location is listed at the top. The name of the function/procedure or label is shown, along with the line number where execution within that function/procedure or label was interrupted, and the file that the function/procedure or label is contained within. By selecting the various entries in this list, the current source line (if source is available) is displayed in the source line information area above, and the variables accessable to the macro at that point are listed in the variables area below.

The variables area displays the list of variables accessable to the macro, the variable's type (Local, Global or Persistent), the type of value the variable contains and the current value of the variable. This area also contains check boxes to specify which variable types to display. The list of variables may be restricted to any combination of Local, Global or Persistent variable types. Even though multiple variables with the same name of different types may appear in the list, only the most locally scoped variable with that name is accessable to the macro as it executes (e.g. If there is both a Local and a Global variable named B, only the Local B may be accessed by the macro. See variable scoping rules in the macro manual).

By selecting the variables in this list, the type (i.e. Local, Global or Persistent) of the variable, the type of the variable's contents (i.e. Undefined, WP String, Integer, Array, etc), and the variable's contents are shown in the area below this list. Once a variable has been declared with the DECLARE, LOCAL, GLOBAL or PERSIST statements, the variable will show up in this list even though its contents may be undefined.

Array variables are displayed in this list with their declared dimensions and a contents type of Array. By double-clicking on an array (or by clicking on the EXPAND push button), the individual array elements are then displayed in the list (or removed from the list if the array was already expanded). The individual elements of the array may then be examined as normal variables. If a variable is an address (alias) parameter to a user-defined function/procedure, then its contents type is displayed as Alias, and it may be expanded and contracted like an array to show the actual variable that it is mapped to. If an alias variable is mapped to a Global or Persistent variable, then the variable type is displayed appropriately. If it is a Local variable, then the type is displayed as "Local to Caller", to distinguish it from a variable that is local to the current function/procedure.

The contents of a variable (or array element) may be changed by first selecting the variable, and then changing the contents in the Variable Contents edit box, and then by clicking on the UPDATE push button. The contents of an array or alias variable may not be changed, but the elements of the array or the variable mapped to the alias may be changed.

The REMOVE push button allows a variable to be removed, or allows the contents of a variable to be reset to an undefined value. There are a few restrictions on this feature depending on the variable type. If the contents of a variable are defined, then either choice is available. If the contents are already undefined, then the variable may only be removed. Array elements can only have their contents reset to undefined, and cannot be removed. Entire arrays and alias variables may only be removed, and cannot have their contents reset to undefined. Variables mapped to an alias variable cannot be removed, but may only be undefined. You should consider carefully before removing a variable, since the macro may rely on the variable being removed.

The CREATE push button allows a new variable to be created. A variable may be created in the Local, Global or Persistent variable areas, and is created with an undefined value. The UPDATE push button may then be used to assign a value to the variable. Alias and array variables may not be created.

As an example of the use of the macro debugger, enter these 3 macros as separate files, compile them and then play the first one.


Macro file STEP.WCM:

use("step2.wcm")

wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwx := "" local a; aa[2;3] bb[] := {1;2;3} global b discard c persist c local Undefined a := "Local a" b := "Global b" c := "Persistent c" local b b := "Local b"

step(on!)

call (lab) p(a; &b; bb[]; &aa[]) run("step2.wcm"; {1; "abc"; 1.3})

step(off!)

prompt("This is the end") pause return

lab: p(a; &b; bb[]; &aa[]) step2(b) run("step2.wcm"; {1; "abc"; 1.3}) return

procedure p(a; &b; cc[]; &dd[]) e := 5 step2(b) run("step2.wcm"; {1; "abc"; 1.3}) endproc

procedure step1(a) step2b(b) endproc


Macro file STEP2.WCM:

use("step.wcm")
prompt("This is step2") pause

step1(2)

procedure step2(a) step1(2) endproc

procedure step2b(a) endproc


Or try this macro called STEP3.WCM:

global aa[1]
declare bb[2;3]
a := 5
aa[] := {1;2;3}

step(on!) p(2; &a; &aa[2]; aa[]; &bb[]) p(2; &c; &bb[2;1]; aa[]; &cc[]) step(off!) prompt("This is the end") pause

procedure p(a; &b; &c; d[]; &e[]) f := 5 b := 3 e[1;1] := 2 pp(c; &b; &a; e[]; &d[]) endproc

procedure pp(a; &b; &c; d[]; &e[]) f := 5 b := 3 endproc


J. Dan Broadhead
18-Oct-1994