[Top: John S. Allen's Home Page] [Up: CAL home page] [Previous: CAL data] [Next: Speeding up CAL programs] |
Bikexprt.com
Web Site |
Writing and debugging CAL programs
John S. Allen
Cakewalk's CAL View lets you run and test your programs as you write them. Though the CAL View is rather Spartan compared with many programming environments, the instant feedback helps make CAL one of the easiest computer languages to learn, and to debug.
Features of the CAL View
Here are some basic guidelines on use of the CAL View, which is a text-editing window that works much like the Windows Notepad:
Up through Cakewalk version 6, buttons at the bottom of the CAL View let you open, save and run files. The "run" button lets you run and test programs as you write them. There is no "stop" button, so hit the escape key to stop a runaway CAL program. The button at the lower right of the window is for the CAL Recorder -- more about that later.
Cakewalk v. 7 and up are different -- they have only Run, Record and Stop Recording buttons in the CAL view. The buttons are at the top left, an improvement -- you can leave them exposed above or to the left of another view and still use them even when most of the CAL view is covered. (And it often will be covered, because 7.0 and 8.0 bring the file on which the CAL program is working to the top as soon as you hit the "Run" button. Apparently, the idea is that you want to see the file the CAL program is working on -- though you would usually rather keep the CAL view fully visible if you are debugging, which is the usual reason to have a CAL View open.)
Right-clicking inside the CAL View (in Windows 95 versions of Cakewalk) brings up a context menu that lets you cut, copy, paste and undo CAL code. CAL has a single-level Undo command, though the other views have a multi-level one. But right-clicking outside the CAL View applies to the .WRK file or other file whose view is active, not to the CAL program.
In Cakewalk v. 7 and up, the main Cakewalk control bar changes to a CAL control bar when you click in a CAL View. The main control bar is where you find the commands that are no longer available inside the CAL View.
The CAL interpreter reads both spaces and tabs as whitespace that separates statements or expressions. But the CAL View up through version 6 uses a proportionally-spaced typeface, so you must use tabs rather than spaces to align items neatly. Tabs also reduce the character count compared with spaces.
The CAL View indents the next line by the same number of tab stops as the current line. When inserting a new line, place the cursor at the end of the previous line, then hit the return key. This will avoid unwanted extra indentation.
Debugging hints
When debugging a CAL program, you run it -- or try to run it -- in CAL View. CAL displays error messages for you.
Still, it is useful to open the program in another editing program at the same time. Most CAL error messages show you the code that causes a problem, but the CAL View has no Find function to help you locate the problem code.
How to get a Find function? Open your CAL program in another text editing program while you are working on it in CAL View. Set the Windows file association for .CAL to the other program. Cakewalk will still find the CAL programs, but then you can also right-click on CAL files (under Windows 95) to open them in the other editing program.
Notepad is simple, and available to all Windows users. Use CAL View to run the program and display error messages. Notepad and CAL View can both have the same file open at the same time. If you make changes to the file in either the CAL View or Notepad, you will have to reopen the file in the other one to update it, but that is only a minor hassle.
Notepad's 8-character tab setting is less than ideal for CAL; you can do even better by using a more sophisticated program editor or word processing program. CAL templates for Microsoft Word '97 and WordPad are posted on this site. The Word template gives you line and column numbering, visible tabs and line end markers, and a fancy printout. There is much more that could be done with Word, such as a special CAL spell-checking dictionary and color-coded text. I expect to get around to that sooner or later, but if you do get around to it sooner, I will be glad to post the results and give you credit. The WordPad template is not as fancy, but it does give you tab spacing consistent with that in CAL View.
Warning: Save CAL files only as plain ASCII text. Word and WordPad both give you this option. Saving in other formats, or including foreign or control characters will make your CAL program crash.
Printing out CAL files: Printing out code often helps you track errors. There is no way to print out CAL code in CAL View. But you can print out a CAL file in Notepad or another text editor. An Internet browser can also display and print a CAL file. Set the browser's preferences to display CAL files as text.
Some CAL error messages are cryptic: mismatched parentheses, expected closing quote and incorrect number of arguments: (if could be almost anywhere in the program. Neither CAL View nor Notepad gives you much help in finding them. Especially if you are writing a long CAL program, you will want to use the following techniques:
Set up a test .wrk file
Create a .wrk file which is as simple and to-the-point as possible to test your CAL program. Are you trying to change event times? Then create the events graphically or quantize them so they are exactly timed, and you can keep track of how your CAL program changes their timing. Are you changing controller settings? Then use the "insert series of controllers" command to create a neat series of precisely timed controller messages over the entire controller range. And so forth. In Cakewalk 7 and above, you can have more than one test file open at a time. You get the idea.
Step back, step ahead
The multiple-level Undo-Redo command in Cakewalk's control bar is a great help when debugging a CAL program. Commands which create an Undo step in Cakewalk editing also create an Undo step when you run a CAL program. Using the Undo and Redo commands, you can step backward and forward through the results of a CAL program and check out what it has done at each step. Use the Ctrl-Z and Ctrl-A keys -- that's faster than repeatedly clicking on "Undo" and "Redo" with the mouse.
You can go back or forward through many steps using the History list -- which also identifies the operation carried out at each step. Going back to the start in the History list will restore your test .wrk file to its original condition, so you are ready to run your CAL program again. Now if you could just keep the History window open while stepping back and forth...
Use (pause ) messages as breakpoints
Use a (pause ) message to stop your program. If you then click on "Cancel") or hit the Escape key, you will be able to use Undo-Redo to review what your program has done up to the (pause ) message.
But more than that, you can also insert program variables into your (pause ) messages to view their values. You can even insert complete CAL expressions. Take this example, from the program to insert RPNs on this site. The expression at the end reconstructs an RPN number from its high and low-order bytes, to test whether my math was correct:
(pause " RPN Number: " wRPNNum " MSB: " wMSBNum " LSB: " |
wLSBNum " Reconstructed: " (+ wLSBNum (* w2^7 wMSBNum))) |
By the way -- if a line in CAL runs to more than one line on your screen, you can split it at a space, as I have done here. Put a space at the beginning of the overflow line, since you can't see the space at the end of a line to be sure it is there.
There is a limit to the length of a pause message (the message itself, not the code which creates it). If the message is too long, you will get a very Zen-like pause dialog box with a cartoon speech balloon pointing at nothing. Don't be alarmed. Edit your message down or split it into two pause messages.
Adding a (pause ) statement may change a simple statement into a compound statement and require that you place them inside a (do ). There is more about compound statements later in this article.
Use the CAL Recorder
The CAL Recorder isn't just some kind of toy for creating "macros." It is a valuable tool in CAL programming. Many CAL commands have long lists of parameters, and it is easier to fill in a dialog box and let the CAL Recorder write the parameters for you rather than to sweat your way through them. In connection with the parameter tables on this site, the CAL Recorder will speed up your programming.
Format to make debugging easier
Always indent!!! Parentheses should match on each line -- with a few exceptions -- the (ForEachEvent, (do, (if, (while and (switch operators. These operate on more than one statement, and their closing parenthesis is moved to the line after the last statement which they affect. Careful indentation helps you trace parenthesis problems. Indent every section where a parenthesis is not closed on the same line.
Track indentation: Color-coded vertical stripes in my Microsoft Word template help you keep track of indentation. If you are using the CAL view or another Spartan editor, here's a very useful trick for tracking indentations: create at least one line of code or comments too wide to fit on the screen, forcing the creation of a horizontal scroll bar. Use the horizontal scroll bar to shift any level of indentation to the left edge of the screen. You then scroll vertically and find that level of indentation anywhere in the CAL file.
Comment the closing parentheses! Long strings of closing parentheses are common in CAL programs. Commenting them will reveal the structure of your program to you. Here's an example:
) ; End of (do expression | |||||
) ; End of test for truncated notes and zero length notes | |||||
) ; End of (do expression within test for notes | |||||
) ; End of test for notes | |||||
) ; End of (ForEachEvent loop | |||||
) ; End of program |
OK, I know that this looks like a series of weird e-mail emoticons (face of sad man lying on left side), but hey, it works.
Mismatches vs. incorrect numbers of arguments
The "One or more mismatched parentheses" error message is posted when there are too few closing parentheses inside an expression. Your program will never run if it has this problem. But if there are too many parentheses, your program may still run. After the CAL interpreter has found closing parentheses to match all of the opening ones, it will stop. Some code at the end of your program will not run, and you will see a message such as "syntax error, (".
Incorrect numbers of arguments can occur if there are too few, or too many arguments. An (if ) will, for example, report this error if it has no arguments (like the one I just wrote) or if it has more than two.
Check the indentation of your lines of code to help you find these problems....
Are your empty lines really empty?
A common but mysterious error results from CAL's handling of whitespace. In the body of the program (between the first (do and its matching parenthesis at the end), CAL ignores extra whitespace. This is nice -- it lets you use formatting to make the program easy to read. But if you place comments before the first (do, beware! whitespace there keeps a program from running! Above the first (do, the first character on every line must be a semicolon or else the line must really be empty. Lines with only spaces and tabs look empty but will result in syntax errors. To solve this problem, select the area above the first (do so you can see where the invisible spaces and tabs are -- then delete the invisible spaces and tabs. Or open the CAL program in my Word '97 template, in which you can see the tab characters.
Removing unnecessary whitespace at the end of lines also isn't a bad idea elsewhere in the program. If your CAL program is long, the saved bytes may bring it in under CAL's 32768-byte length limit. Just remember that there must be at least one space or tab character between words and statements. I suggested earlier that you put the required space at the beginning of overflowing lines. Then you can delete all extra spaces at ends of lines without trashing your program.
Open multiple CAL views
Even if a CAL program doesn't run at all, there are some highly effective debugging tricks. In Cakewalk 7 and higher, you can have more than one CAL view open at a time. If some part of your program is giving you problems, you can copy it into another CAL view and debug it there in order to isolate and correct the problem. If you need your isolated code to run, you will also have to copy in the variable declarations. If you are just looking for mismatched parentheses, you don't need to copy in the variable declarations. CAL will report mismatched parentheses with or without variable declarations.
Using multiple CAL Views is a powerful debugging tool and is a good reason to upgrade.You can even work on a program with (include ) files and place each of these in a separate window. You need to save the included program before the main program will call up its latest version.
Debug by deleting
Whether or not your Cakewalk version allows multiple CAL views, you can use the Cut command to remove parts of the program between matching parentheses. (Commenting the closing parentheses, as I have suggested, helps you find the matching parentheses.) When the offending part is cut out, the program will run. The Undo command will restore the section you have removed. Then you can look through it to find the error.
Save the file before you use this trick, and don't cut or copy anything else before you try to restore, or else you will be forcefully reminded of the CAL window's single-level Undo command.
Compound statements must be enclosed in a (do ) expression: Parenthesis problems and "incorrect number of arguments" errors often result from forgetting to add a (do ).
Just like the {curly brackets} in the C language, the (do ) makes multiple statements look like one statement to CAL. Here's an example:
(if (== 1 foobar) | ||
(do | ||
(= 0 barfoo) | ||
(++ raboof) | ||
) | ||
(do ; Else | ||
(= 1 barfoo) | ||
(-- raboof) | ||
) | ||
) |
If you forget the (do following the (if , the second statement after the (if [here (++ raboof)] becomes the "; Else" -- it is ignored when the (if condition is true and carried out when the condition is false. If the unintended "; Else" is the last statement under the (if , you will get incorrect results. With three or more arguments after an (if, you will get the "incorrect number of arguments" error message.
The (do ) expression is also needed inside a (forEachEvent ) or (while ) loop where there is a compound statement.
The above example can remind you of the difference between the single and double equals sign. The double equals sign (as in the first line of the code) is a comparison operator that evaluates whether foobar is already equal to 1. The single equals sign assigns a value. If I put (if (= 1 foobar) in the first line above, foobar would always be set to one, the (if would always evaluate as true, barfoo would always be set to zero and raboof would always be increased by 1. Some of us like to be right all of the time, but the whole idea of an (if ) is that it is right only some of the time.
Version problems
CAL programs written under later versions may include commands that earlier versions do not recognize. My article on CAL Edit Menu commands describes many of these issues. My article on event types describes others. There are bugs in versions 5 and 6 which can make a program written in Version 7 or 8 not run, even though the syntax looks correct in all versions. Be especially wary of mysteriously changing From and Thru times when you use additive event filter commands, as demonstrated in a file on this site.
Any suggestions?
That's it for my hotlist of CAL debugging suggestions. If there is anything you would like to add, please contact me by e-mail. If I use your suggestion, I will give you credit for it.
[Top: John S. Allen's Home Page] [Up: CAL home page] [Previous: CAL data] [Next: speeding up CAL programs] |
Contents © 1998, 1999 John S. Allen Last revised 5 April 2000 |