Don't click here unless you want to be banned.

LSL Wiki : debugging

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are ec2-204-236-235-245.compute-1.amazonaws.com

Debugging


So you've written a script, thought you had everything perfect, tried compiling it, and BOOM!

Down went the simulator :-)

(Un)fortunately, that's not how many debugging escapades begin. Even so, it can be a rather daunting task if you don't know where or how to start fixing your script when something goes wrong. "Debugging" as we scripterati call it, is the process by which bugs, mistakes, are removed from the script. There are two main kinds of problems we focus on when we debug, syntax errors and logic errors.

Syntax Errors

These are often called the easiest to fix errors, since the LSL compiler tells you exactly how to fix them when you press the "Save" button. NOT!
Often times, the LSL compiler complains about a line of text completely unrelated to the problem its actually having. Take this for example:

default 
{
    state_entry()
    {
        integer hungry = TRUE;
        if (hungry)
            llSay(0, "I want BAGELS!");
        }
    }
}

When you hit the save button the LSL compiler spits out:
(9, 0) : ERROR: Syntax error
...and leaves the blinking cursor at the last line of the script. The LSL compiler (unlike the Python interpreter) has absolutely no idea where you put whitespace (spaces, newlines) in your script. To it, the above looks like:

default{state_entry(){integer hungry=TRUE;if(hungry)llSay(0,"I want BAGELS!");}}}

The compiler is pendantic about braces because they signify where you should create and destroy scopes and all the variables you declare within them. In order to keep all of this straight, the compiler increments a counter when it encounters an open brace, and decrements it when it encounters a closed brace. If this counter is nonzero once it reaches the end of the script, you either have too many or not enough opening or closing braces. Unfortunately, it tells you this by giving you the extremely general Syntax error. This is where good brace indention style comes in handy. The LSL compiler can't see whitespace, but *you* can! check to see if all of your open braces have a corresponding closed brace, and vice-versa.


Here's another snag people usually hit upon:
default 
{
    state_entry() 
    {
        integer hungry = TRUE;
        if (hungry)
        {
            llSay(0, "I want BAGELS!")
        }
    }
}

In this example, the LSL compiler pulls another confusing whitespace-dependant trick on us. Here, it spits out:
(8, 8) : ERROR : Syntax error
...leaving the blinking cursor before the closing brace after the llSay line. The LSL compiler does this because it's expecting a emicolon to end the llSay() statement, but runs into a closing brace (and because the LSL compiler is stupid, it simply stops at the closing brace). Easiest way to fix these problems - check that all your statements end with a semicolon.


Now you may be asking, "Is there any other way to check my code's syntax without using SL's LSL compiler?" I'm very happy to state YES! The dazzling Masakazu Kojima has written an external program, called lslint, that checks the syntax of LSL scripts. You can access it online here or join in the forum discussion about it here. It shows you in greater detail where your script's syntax is off, and even makes suggestions! It slices, dices and even makes julian fries!

Logic Errors

These beasts range from the simplest "why is this code not running" to the extreme "OMG MY OBJECT EXPLODED!" These errors are not caught by the LSL compiler, because they're errors in what you told SL to do. Computers are intrinsically stupid - they lack intuition - so they will do exactly what you tell them to do, no matter how much that differs from what you intend for them to do or from what any sane person would want them to do. Here are some of the most common ones:

Semicolon After Condition
default 
{
    state_entry()
    {
        integer hungry = FALSE;
        if (hungry);
        {
            llSay(0, "I want BAGELS!");
        }
    }
}

This script compiles, but the llSay statement will always execute, even when hungry is FALSE (as is seen here). - This is because the semicolon after the conditional statement completely negates the conditional's effects, turning it from a scope-starter into a statement that has no effect. To fix this, remove the semicolon from the end of the conditional statement.

Use of == Instead of =, and Vice-Versa
integer FOOD_ITEMS = INVENTORY_OBJECT;
integer hungry;
default
{
    state_entry()
    {
        // Use of == instead of =
        hungry == TRUE;
        if (hungry)
        {
            llSay(0, "I want BAGELS!");
        }
        
        // Use of = instead of ==
        integer foodCount = llGetInventoryNumber(FOOD_ITEMS);
        if (foodCount = 1)
        {
            llSay(0, "Time to stock up on groceries, this script is all that's left!");
        }
    }
}

Unfortunately, this script compiles without any problems, but will never print the "BAGELS!" line and will always print the "groceries" line. Check that variable assignments use the = operator, and equality comparisons use the == operator.

Both of these logic errors occur due to the way LSL's syntax has mimiced C's.

Similarly, watch out for Boolean vs. Bitwise operators
Just as "=" can end up where you meant to have "==", so can "&" vs. "&&" and "|" vs. "||". These bugs can be even more difficult to find because the potential exists that a bitwise operation will yield a result that can then be interpreted as a boolean value. Half of the time your code may seem to be working fine, depending on the circumstances!


General Solution: Isolate-and-Conquer
Logic errors, especially the ones that cause the script to sit there doing nothing when you expect it to do something, can be very tough to find when you're trying to fix them by tinkering with the entire script as a whole. Test small chunks of your script, one part at a time, to make sure they are doing exactly what you want them to. This is easiest if you have divided your script into separate functions.

Finding the source of logic errors can often be like searching for a needle in a haystack. Using this principle, you can throw chunks of haystack off to the side once you're done searching through them.

General Solution: Variable Dumps
If your script isn't easily separable into self-contained chunks, the isolate-and-conquer approach might not be the best solution for you. Instead, at key points in your script (where important data is manipulated or a loop is entered/exited) insert llOwnerSay statements that print out the contents of any relevant variables. This way you can tell what goes wrong with the manipulation or if your script goes into an infinite loop.


Errors
There are 8 comments on this page. [Display comments/form]