Roger Firth's IF pages

Home

InfLight -- Inform debugging

Email
Back up

Although inspecting things from the game's input line is informative, you frequently need to observe how values change during execution. The general term for this process is tracing.

Tracing calls to a routine

One useful technique built into Inform is to trace calls to a routine. As it happens, there are almost no standalone routines in our example game, so to illustrate the point, let's transform an embedded routine into a standalone one:

 
Object  hook "small brass hook" cloakroom
  with  name 'small' 'brass' 'hook' 'peg',
        description [; DescribeHook(self); ],
  has   scenery supporter;

[ DescribeHook obj;
        print "It's just a small brass hook, ";
        if (cloak in obj) "with a cloak hanging on it.";
        "screwed to the wall.";
        ];

So far, this change has no effect on the game's behaviour. But if we modify the declaration of DescribeHook to have an asterisk * as its first parameter, then at run-time we see:

 
[ DescribeHook * obj;
        print "It's just a small brass hook, ";
        dots
 
 
>X HOOK
[ DescribeHook(obj = 26) ]
It's just a small brass hook, screwed to the wall.

Alternatively, you can turn tracing on for all routines -- without having to edit in any asterisks -- by compiling with the g switch. For this simple example game it works reasonably well, but in most cases you get far too much output; you're better selectively tracing where you need to:

 
>X HOOK
[ hook.description() ]
[ DescribeHook(obj = 26) ]
It's just a small brass hook, screwed to the wall.

>HANG CLOAK ON HOOK
[ cloak.before() ]
(first taking it off)

[ cloak.before() ]
[ cloak.after() ]
You take off the velvet cloak.
[ cloak.after() ]
You put the velvet cloak on the small brass hook.

[Your score has just gone up by one point.]

Temporary PRINT statements

The asterisk trick works only on calls to standalone routines. A more general technique, albeit with more typing involved, is simply to add a temporary PRINT statement; this can both clarify which path the program is taking, and show you appropriate values:

 
[ DescribeHook obj;
        print "**** ", obj, " ****^";
        print "It's just a small brass hook, ";
        dots
 
 
>X HOOK
**** 26 ****
It's just a small brass hook, screwed to the wall.

The Dump.h package includes a tool IS which does this more elegantly:

 
[ DescribeHook obj;
        is(obj);
        print "It's just a small brass hook, ";
        dots
 
 
>X HOOK
************************************
** This number: 26 $001A $$0000000000011010
**   Might be an object:    small brass hook
**   Might be an attribute: workflag
**   Might be a property:   react_before
**   Might be an action:    VagueGo
**   Might be a read/write memory address containing: -28778 $8F96 $$1000111110010110
************************************
It's just a small brass hook, screwed to the wall.

You can also use IS as a command:

 
>IS $2AF3
** This number: 10995 $2AF3 $$0010101011110011
**   Might be a read-only memory address containing: 13972 $3694 $$0011011010010100
**   which is dictionary word: 'hook'.
**   Might be a packed routine address $0ABCC.

If you're a bit unsure what exactly a given number represents at some point, IS can be very convenient.

You might also be interested in the DebugLib.h package which does a similar job of printing object information. It gives less detail, but does provide three routines -- Print_Crit(), Print_Warn() and Print_Trace() -- enabling you to select a level of debug output.

 
[ DescribeHook obj;
        Print_Trace(obj, "in DescribeHook()");
        print "It's just a small brass hook, ";
        dots
 
 
>X HOOK
small brass hook trace: In DescribeHook()
It's just a small brass hook, screwed to the wall.

ACTIONS, ROUTINES and TIMERS

An informative commentary is provided by the ACTIONS command:

 
>ACTIONS ON
[Action listing on.]

>WEST
[ Action Go with noun 10 (west wall) ]
[Moving yourself to Cloakroom]

Cloakroom
The walls of this small room were clearly once lined with hooks, though now only
one remains. The exit is a door to the east.
[Giving Cloakroom visited]

>X HOOK
[ Action Examine with noun 26 (small brass hook) ]
It's just a small brass hook, screwed to the wall.

>HANG CLOAK ON HOOK
[ Action PutOn with noun 28 (velvet cloak) and second 26 (small brass hook) ]
[Giving Foyer bar light]
[Giving velvet cloak ~general]
(first taking it off)

[ Action Disrobe with noun 28 (velvet cloak) (from < > statement) ]
[Giving velvet cloak ~worn]
You take off the velvet cloak.
[Moving velvet cloak to small brass hook]
You put the velvet cloak on the small brass hook.

[Your score has just gone up by one point.]

The similar trace from ROUTINES is lengthier, with more evidence of the Library itself:

 
>ROUTINES ON
[Message listing on.]
[ "(Inform Parser)".parse_input(4275) ]

>WEST
[ "(Inform Library)".begin_action(27,10,0,0) ]
[ "yourself".orders() ]
[Moving yourself to Cloakroom]

Cloakroom
The walls of this small room were clearly once lined with hooks, though now only
one remains. The exit is a door to the east.
[Giving Cloakroom visited]
[ "(Inform Library)".end_turn_sequence() ]
[ "(Inform Parser)".parse_input(4275) ]

>X HOOK
[ "(Inform Library)".begin_action(32,26,0,0) ]
[ "yourself".orders() ]
[ "small brass hook".description() ]
It's just a small brass hook, screwed to the wall.
[ "(Inform Library)".end_turn_sequence() ]
[ "(Inform Parser)".parse_input(4275) ]

>HANG CLOAK ON HOOK
[ "(Inform Library)".begin_action(18,28,26,0) ]
[ "yourself".orders() ]
[ "velvet cloak".before() ]
[Giving Foyer bar light]
[Giving velvet cloak ~general]
(first taking it off)

[ "(Inform Library)".begin_action(41,28,0,1) ]
[ "yourself".orders() ]
[ "velvet cloak".before() ]
[Giving velvet cloak ~worn]
[ "velvet cloak".after() ]
You take off the velvet cloak.
[Moving velvet cloak to small brass hook]
[ "velvet cloak".after() ]
You put the velvet cloak on the small brass hook.
[ "(Inform Library)".end_turn_sequence() ]

[Your score has just gone up by one point.]
[ "(Inform Parser)".parse_input(4275) ]

TIMERS does a similar job for daemons and timers, but there aren't any of those in the example game.

TRACE

Finally, you can wheel out the heavyweight TRACE command, which offers five levels of detail about the Parser's operation. Here's what you see with the first three levels:

 
>TRACE 1
[Parser tracing set to level 1.]

>X HOOK
[Parsing for the verb 'x' (1 lines)]
[line 0 * noun -> Examine]
[Line successfully parsed]
It's just a small brass hook, screwed to the wall.

>HANG CLOAK ON HOOK
[Parsing for the verb 'hang' (1 lines)]
[line 0 * held 'on' noun -> PutOn]
[Line successfully parsed]
(first taking it off)

You take off the velvet cloak.
You put the velvet cloak on the small brass hook.

[Your score has just gone up by one point.]
 
 
>TRACE 2
[Parser tracing set to level 2.]

>X HOOK
[ "x" x / "hook" hook ]
[Parsing for the verb 'x' (1 lines)]

[line 0 * noun -> Examine]
 [line 0 token 1 word 2 : noun]
 [line 0 token 2 word 3 : END]
[Line successfully parsed]
It's just a small brass hook, screwed to the wall.

>HANG CLOAK ON HOOK
[ "hang" hang / "cloak" cloak / "on" on / "hook" hook ]
[Parsing for the verb 'hang' (1 lines)]

[line 0 * held 'on' noun -> PutOn]
 [line 0 token 1 word 2 : held]
 [line 0 token 2 word 3 : 'on']
 [line 0 token 3 word 4 : noun]
 [line 0 token 4 word 5 : END]
[Line successfully parsed]
(first taking it off)

You take off the velvet cloak.
You put the velvet cloak on the small brass hook.

[Your score has just gone up by one point.]
 
 
>TRACE 3
[Parser tracing set to level 3.]

>X HOOK
[ "x" x / "hook" hook ]
[Parsing for the verb 'x' (1 lines)]

[line 0 * noun -> Examine]
 [line 0 token 1 word 2 : noun]
  [Object list from word 2]
  [Calling NounDomain on location and actor]
  [ND returned the small brass hook]
  [token resulted in success]
 [line 0 token 2 word 3 : END]
[Line successfully parsed]
It's just a small brass hook, screwed to the wall.

>HANG CLOAK ON HOOK
[ "hang" hang / "cloak" cloak / "on" on / "hook" hook ]
[Parsing for the verb 'hang' (1 lines)]

[line 0 * held 'on' noun -> PutOn]
 [line 0 token 1 word 2 : held]
  [Object list from word 2]
  [token resulted in success]
 [line 0 token 2 word 3 : 'on']
  [token resulted in success]
 [line 0 token 3 word 4 : noun]
  [Object list from word 4]
  [Calling NounDomain on location and actor]
  [ND returned the small brass hook]
  [token resulted in success]
 [line 0 token 4 word 5 : END]
[Line successfully parsed]
(first taking it off)

You take off the velvet cloak.
You put the velvet cloak on the small brass hook.

[Your score has just gone up by one point.]

As you can see, TRACE comes into its own if you've invented a new verb grammar which obstinately fails to work properly. Most of the time, you don't need to know this stuff.


Introduced in the most recent Inform upgrade, the Infix debugger is our next topic.