RuleWorks

Debugging RuleWorks Programs

You can use the RuleWorks debugging commands to find errors in your program and to interact with it while it is running. If your program calls routines written in another language, you must use that language's debugger to find errors in those routines. That debugger sees the C code generated by the RuleWorks compiler, not your RuleWorks source code. DEBUG qualifier.

Note: that the RuleWorks debugger, unlike other debuggers, is subordinate -- it is called from your program. Other debuggers call your program. You control the appearance of the RuleWorks interpreter with the Debug compilation qualifier, DEBUG action, and the rul_debug RTL routine.

Using the RuleWorks Command Interpreter

The RuleWorks command interpreter lets you interactively control the execution of an entry block by entering RuleWorks commands. Table 9-1 lists these commands with their corresponding operations.

Table 9-1. Debugging Commands

CommandsOperation
@Execute contents of a command file
EBREAK
RBREAK
WBREAK
Use breakpoints
PPCLASSDisplay the inheritance hierarchy of an object class
PPWM
WMHISTORY
Display objects in working memory
MAKE
MODIFY
COPY
SPECIALIZE
REMOVE
REMOVE-EVERY
Change working memory
MATCHESDisplay match information
CS
NEXT
Display the contents of the conflict set
TRACEDisplay trace information

ADDSTATE
RESTORESTATE
SAVESTATE
Save and restore visible working memory and active conflict set
DISABLE
ENABLE
Change the state of program operation
AFTERSet the recognize-act counter for a catcher
RUNExecute recognize-act cycles

 

Entering RuleWorks Commands

The RuleWorks command interpreter displays the following prompt:

To enter a RuleWorks command, type the command, with arguments if appropriate, and then press the Return key. To extend a command over more than one line, you can either enclose it in parentheses (which you can optionally use for single-line commands also) or use the continuation character (-).

An example of a single-line command entered, without parentheses, at the interpreter prompt is shown below:

If you end a line with the continuation character, the command interpreter prompts you for the rest of the command each time you press the Return key. For example:

If you begin a command with a parenthesis, you must make sure you have the same number of left and right parentheses, because the interpreter matches each left parenthesis with a corresponding right parenthesis before it accepts the command. The MAKE command above can also be entered with parentheses but without a continuation character:

If you want to include an extra unmatched parenthesis in such a command, you must enclose it in quote characters, for example, ||. Otherwise the interpreter counts it as a parenthesis to be matched before it allows you to end the command.

Arguments, which can be optional or required, must follow the command name. If you do not specify a required argument, the run-time system displays an error message, shows the correct syntax and an example, and finally redisplays the command interpreter prompt. For example:

Exiting the Command Interpreter

Use the EXIT command to exit the command interpreter. Depending on whether your RuleWorks code is set up as a main program or a callable routine, control returns either to the operating system or to the calling program.

Using RuleWorks Command Files

You can store a list of RuleWorks commands in a file and execute them later by using the RuleWorks @ command inside your ON-ENTRY statement or at the command interpreter. For example, you can have an @ file of MAKE commands to create objects when your program starts.

The following command opens the file ORDER.WM and causes the command interpreter to execute the commands stored in that file:

If the file you specify with the @ command contains information other than RuleWorks commands, the run-time system displays an error message. For example:

Using Breakpoints

A breakpoint causes your program to pause under certain conditions: a specified rule is about to be executed or an object that matches a specified pattern has just been created, changed, or deleted. You can set, delete, and list breakpoints by using the EBREAK command for entry blocks; the RBREAK command for rules and rule groups; and the WBREAK command for WMOs.

When the run-time system encounters a breakpoint, the system finishes executing the current recognize-act cycle, displays an informational message, and then invokes the command interpreter, to allow you to enter debugging commands. The format of the message depends on your operating system. For example, on VMS systems:

If a breakpoint is set for an entry block, the run-time system pauses for the breakpoint after executing the ON-ENTRY and ON-EXIT clauses (if any) of the entry block. If a breakpoint is set for a rule, the run-time system pauses for the breakpoint just before executing that rule. Setting a breakpoint on a rule group is equivalent to setting breakpoints on every rule in the group. If a breakpoint is set for an object pattern, the run-time system pauses for the breakpoint after executing the rule that created, changed, or deleted the object.

Setting Breakpoints

To set a breakpoint, specify the EBREAK, RBREAK, or WBREAK command with the keyword ON and the name of the entry block or rule, or a pattern matched by the WMO.

You can give more than one name with a break command. For example, the following command sets breakpoints on two rules:

The WBREAK command accepts at most one object pattern. This pattern is similar to a CE but more limited: it must include an object class name and can also include attributes with predicates and values. It cannot include variables, function calls or other expressions.

For example, suppose a breakpoint is already set for objects of class FLOPPY. The following two commands set a new breakpoint for objects with class name DISK and ^PRICE identical to 299.95, and delete the old one on class FLOPPY:

When you specify an object class that has inheriting subclasses, objects of those subclasses are also affected by the WBREAK commands. Thus, the command above affects objects of classes DISK, FLOPPY, FD-5, FD-35, HARD-DISK, HD-30, and HD-200. See Chapter 2 for an illustration of the class inheritance hierarchy of the sample program KIWI.

Listing Breakpoints

To see what breakpoints are set, use the EBREAK, RBREAK, or WBREAK command without any keyword or arguments. The following example shows that breakpoints are set for two rules:

This example shows that breakpoints are set for certain objects of class DISK:

 

Deleting Breakpoints

To delete a breakpoint, specify the EBREAK, RBREAK, or WBREAK command with the keyword OFF, and one of the following:

Use an asterisk to delete all breakpoints. For example:

 

Displaying the Inheritance Hierarchy

Use the PPCLASS command with the name of an object class to display the inheritance hierarchy of that class. This command lists the ancestors of the class you specify, starting at the top-level user-defined class. All attributes declared for that class, including those it inherits, are shown after the class name. For example:

An attribute's default and fill values, if any, are shown inside parentheses after the attribute's name. Compound attributes are also identified as such.

To display which object classes are visible to the active entry block, use the PPCLASS command with no argument. This shows the name of the entry block (and declaration blocks, if any) and the top-level user-defined classes only. For example:

 

Displaying Working-Memory Objects

During a debugging session, you can examine the contents of working memory to make sure it contains correct information. Missing or erroneous objects can cause a rule to be executed at the wrong time. The WM, PPWM, and WMHISTORY commands display the contents of working memory:

Table 9-2. Working Memory Commands

CommandDescription
WMDisplays all objects or objects with specified INSTANCE-IDs.
PPWMDisplays all objects or objects that match a specified pattern.
WMHISTORYDisplays the revision history of the object with a specified INSTANCE-ID, or of a specified attribute of that object.

The WM and PPWM commands provide the following information about each object:

The run-time system displays this information in the following format:

The WMHISTORY command provides the following information about an object

The run-time system displays this information in the following format:

When you create or change an object with an action contained in an "ON-"statement, the name of that statement appears inside the brackets rather than a rule name. When you use a command, the atom RUL appears.

The run-time system does not print an empty attribute unless you have specified a DEFAULT value for it. Empty is defined as a NIL value for scalar attributes, (COMPOUND) for compound attributes. Attributes that have a DEFAULT declaration are always printed.

Displaying the Contents of Working Memory

To display the entire contents of working memory, use either the WM or PPWM command without an argument. For example:

Object #1 was made in the ON-ENTRY statement, so that name appears inside the brackets instead of the name of a rule.

Displaying Specific Working-Memory Objects

To display particular objects, specify their INSTANCE-IDs with the WM command. The following example displays the objects that have INSTANCE-IDs #23 and #24:

You can find out which INSTANCE-IDs are assigned to which objects by setting the run-time system's TRACE level to WM. For further information on trace levels, See the Displaying Trace Information section of this chapter.

Displaying the History of Specific Working-Memory Objects

To display the names of the rules that have created or modified a particular object, specify the INSTANCE-ID of that object with the WMHISTORY command. By default, the WMHISTORY command is disabled. You must enable it with the ENABLE command before running the rules that affect the objects you want to display. The following example shows the history of the object whose INSTANCE-ID is #36:

In this example, the WMHISTORY command shows that the rule EXPAND-PART-SKELETONS:FD-35 most recently changed this object, because that is the rule shown after the time-tag. Another rule, VERIFY-CONFIGURATION:NEED-DISK, originally created the object, because that is the rule shown after the class name. The rule EXPAND-PART-SKELETONS:FD-35 set the values of all the attributes.

If you are interested in which rule set a particular attribute value, you can specify the attribute name with the WMHISTORY command:

When you use a command rather than an action inside a rule to create or modify an object, the atom RUL rather than the name of a rule appears inside the brackets after the time-tag, class name, or attribute value. When you use an action inside an "ON-"statement, the name of that statement appears inside the brackets.

Displaying the Working-Memory Objects of an Object Class

To display the objects of a particular object class, use the PPWM command with the name of that class. For example:

If you specify the name of an object class that has inheriting subclasses, objects of those subclasses are also displayed. For example:

(See Chapter 2 for an illustration of the class inheritance hierarchy of the sample program KIWI.RUL.)

Displaying Working-Memory Objects that Match a Pattern

To display the objects that match a specific object pattern, use the PPWM command with an object class name followed by the pattern you want to match. This pattern is similar to an attribute-value test but variables and function calls are not allowed, except COMPOUND.

The following example displays all parts that match the object pattern ^PRICE < 50.00. The ^PRICE attribute is first declared in the PART class. Therefore, to display all objects that have the ^PRICE attribute, the object class name PART is specified in the PPWM command. The objects that actually match the pattern are instances of classes KIWICALC and KIWOS:

 

Modifying Working Memory

If working memory contains incorrect information, the rules in a program might not execute as you anticipate. You can modify working memory by:

Creating Working-Memory Objects

You can create a new object by using the MAKE command with an object class name. You can optionally specify attributes with constant values or the COMPOUND function with constant arguments. The following command creates an object with the class name INPUT-THING and a value for its ^ITEM attribute.

The object could be displayed as follows:

Because the object was created by a command, the atom RUL is used instead of the name of a rule that set the time-tag.

Copying Working-Memory Objects

You can make a new copy of an existing object by using the COPY command with an INSTANCE-ID. You can optionally specify attributes with values. The following command creates another object of class FD-35 with a different attribute value:

RUL is placed in the fields that store the names of the rules that created the object and that last modified it. Note that both the INSTANCE-ID and the time-tag of the new object are different from the older object.

Changing the Class of Objects

You can change the class of an object from a parent class to a subclass with the SPECIALIZE command. For example:

Deleting Objects from Working Memory

The REMOVE command deletes objects from working memory. To delete specific objects, specify their INSTANCE-IDs. The following example deletes the objects whose identifiers are #20 and #63:

To delete all visible objects, specify the command with an asterisk (*). For example:

To delete all instances of an object class and its subclasses, use the REMOVE-EVERY command. For example:

Changing the Values in Working-Memory Objects

To change one or more values in an object, use the MODIFY command with the INSTANCE-ID of the object whose atoms you want to change, and specify the attributes and their new values. Suppose, for example, working memory contains the following objects:

The following command changes the atom for the attribute ^ITEM of the object whose INSTANCE-ID is #16:

The run-time system then changes that attribute and gives the object a new time-tag:

Note that the INSTANCE-ID remains the same.

 

Displaying Match Information

By examining match information, you can detect whether condition elements are being matched correctly by WMOs. You can display match information for specific rules by using the MATCHES command.

Match information includes the INSTANCE-IDs and time-tags of objects that match CEs in the rules you specify. First, the command displays the name of the rule. Then the command lists the time-tags for the objects that match the first CE, the second CE, the first and second CEs, and so on. For example, consider the following rule:

The following objects:

And the following MATCHES command:

The first five lines of output show that the object whose INSTANCE-ID is #46 matches the first CE in the rule and the object whose INSTANCE-ID is #27 matches the second CE. These are called intraelement matches because each CE is considered individually. The next two lines show that the combination of these two objects matches the combination of the first and second CEs. This is called an interelement match.

The MATCHES command then displays the intraelement matches for the third CE, the objects whose INSTANCE-IDs are #37 and #38. Note that each match is displayed on a separate line.

Finally, the command displays the instantiations of the rule. Because two objects match one of the CEs, there are two instantiations.

Instantiations removed from the active conflict set by refraction are not included in the MATCHES output.

Match Information for Negated CEs

Negated CEs are represented in the match information by headers just like the headers for positive CEs. For example, the rule VERIFY-CONFIGURATION:MOUSE-PORT has two positive CEs and one negated CE:

The match information for this rule is shown below:

There is a complete instantiation of this rule in the conflict set (because) there is no match for the negated third CE.

Match Information for Interelement Variables

Interelement variables are bound in one CE and then used again in another CE. In match information, interelement variables result in fewer than expected matches for combinations of CEs, compared to the number of matches for individual CEs.

For example, suppose working memory contains the following objects:

And the program contains this rule

The following command displays the matches for this rule:

There are three intraelement matches for the first CE and two for the second CE, so you might expect six matches for the entire LHS. However, the interelement variable <MEM> limits the interelement matches to the combination of MEMORY #31 with BOX #28.

 

Displaying Conflict Set Information

The instantiations in the conflict set indicate which rules can be executed. You can display the entire contents of the conflict set or the instantiation of the next rule to be executed. The run-time system displays instantiations in the following format:

Displaying the Contents of the Conflict Set

The CS command displays the entire contents of the conflict set. For example:

To display the instantiation of the next rule the run-time system will execute, use the NEXT command. For example:

This shows that the next rule the run-time system will execute is VERIFY-CONFIGURATION:KIWINDOWS-NEEDS-2-MEMORY-CARDS-FOUND-NONE. The rule will be executed with its CEs matched by the objects whose INSTANCE-IDs are #32 and #29.

 

Displaying Trace Information

The RuleWorks run-time system displays trace information while executing a program. Trace information can be enabled for entry blocks (EB), rule groups (RG), rules, working memory (WM), and the conflict set (CS).

Setting the Trace Level

To set the trace level, specify the TRACE command with the keyword ON or OFF and the type of information you want traced or not. The following table shows the valid keywords for the TRACE command. The default setting is OFF *.

Table 9-3. Trace Keywords

NameTrace Information Affected
ENTRY-BLOCK
EB
Entry blocks entered and exited
RULE-GROUP
RG
Rule group containing rule that just fired
RULERule firing counts and name of rule that just fired
WMChanges to working memory
CSChanges to the conflict set
.All trace information

For example, if you want the system to display as much trace information as possible, you can list all the keywords or use the asterisk (*):

Displaying the Current Trace Level

To display the current trace level, use the TRACE command without an argument. For example:

Tracing Entry Blocks

The TRACE ON EB command causes trace messages to be generated upon entering an entry block (before any ON-ENTRY actions are executed) and upon exiting (after any ON-EMPTY or ON-EXIT actions are executed).

The trace output for entry blocks includes the name of the entry block. Trace output for entry blocks starts in column one. All other trace messages are indented. The following example shows sample trace output on entry blocks in italic type.

Example 9-1. Tracing Information on Entry Blocks

Tracing Rule Groups

The TRACE RG command causes trace messages to be generated whenever the rule group that contains the firing rule is different from the rule group that contains the previously fired rule. The trace output for rule groups contains the name of the rule block or entry block that contains the rule group, as well as the name of the rule group itself. The system displays this information in the following format:

Tracing Rules

The TRACE RULE command causes a trace message to be generated each time the system executes a rule. Trace output for rule firings contains the following information:

The run-time system displays this information in the following format:

In the following example trace information for rules is shown in italic print.

Example 9-2. Trace Output for Rules

Tracing Working Memory

When the trace level includes WM, the run-time system displays changes to working memory (that is, objects created, changed, or deleted). The system displays the following information for each object:

The system displays working memory trace information in the following format:

Each line of a working memory trace output is preceded by a symbol that indicates the nature of the change as shown in the following table.

Table 9-4. Working Memory Trace Output Symbols

SymbolMeaning
=>WM:Object added to working memory
<=WM:Object deleted from working memory

When an object is modified or specialized, the system displays two lines of output: the first shows the old version being deleted, the second shows the new version being added. The INSTANCE-ID, of course, does not change.

In the case of a SPECIALIZE action, the attribute changed is ^$INSTANCE-OF.

In the following example, trace output for working memory changes is shown in italic print.

Example 9-3. Trace Ouput for Working Memory

When all visible objects are deleted (for example, in a RESTORESTATE or REMOVE * action), the system displays: <=WM: ** All Objects Removed **

Tracing the Conflict Set

When the trace level includes CS, the run-time system displays the instantiations added to and deleted from the conflict set. The system displays the following information for each instantiation:

The system displays conflict set trace information in the following format:

Each line of conflict set trace output is preceded by a symbol that indicates whether the instantiation was added to or deleted from the conflict set:

Table 9-5. Trace Output Symbols

SymbolMeaning
=>CS:Instantiation added to conflict set
<=CS:Instantiation deleted from conflict set

In the following example, trace output about the conflict set is shown in italic print.

Example 9-4. Trace Ouput for The Conflict Set

When all conflict set elements are deleted, the system displays:

 

Saving and Restoring Program State

If you are debugging a RuleWorks program and you need to stop execution to do something else, you might want to save the state of working memory and the conflict set as it exists at that time. Or, you might want to save a certain state so that you can rerun from that point many times. By using RuleWorks commands you can save the state to a file and then restore it later.

SAVESTATE Command

You can copy the state of visible working memory and the active conflict set to a file by using the SAVESTATE command. The following command copies the state of working memory and the conflict set to the file MY_SAVE.DAT:

RESTORESTATE Command

The RESTORESTATE command clears and restores visible working memory and the active conflict set to the state recorded in a file produced by the SAVESTATE command. Suppose you used the SAVESTATE command to copy the state of working memory and the conflict set to the file MY_SAVE.DAT. The following command restores working memory and the conflict set to the state recorded in the file MY_SAVE.DAT:

The RESTORESTATE command:

The RESTORESTATE command automatically performs ID translation on any INSTANCE-ID values stored in attributes of the saved WMOs. That is, if you use IDs as pointers the relationships among saved WMOs are maintained. (See the description of rul_start_id_translation in Chapter A for details on ID translation.)

ADDSTATE Command

The ADDSTATE command:

Unlike the RESTORESTATE command, the ADDSTATE command does not delete any existing WMOs before creating new ones from the saved file. Like the RESTORESTATE command, ADDSTATE automatically performs ID translation on the saved WMOs (see rul_start_id_translation in Chapter A for details).