Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, Swift, BASIC, and whatever else I happen to feel like hacking at.

Read BASIC out loud

Jerry Stratton, February 10, 2021

In my continuing quest to make it easier to successfully type programs from books and magazines, I had the great idea of having my Macintosh read the code out loud, freeing me to look solely at the original text while verifying the code. This is useful not just for finding errors that rcheck+ says must exist but also errors in code that doesn’t have checksums such as the one- and two-liners in The Rainbow.

The readBASIC script (Zip file, 3.6 KB) is especially useful for the 1984 run of The Rainbow, which uses an rcheck that simply adds up memory used instead of performing a rudimentary checksum, and Hot CoCo, which has no validation at all unless you count the 32-character lines. I recently acquired several issues of Hot CoCo and I pretty much run readBASIC on all of the programs I type in from that magazine. Whether an error shows up on testing the program or not, I almost certainly mistyped something on any program of any reasonable length. Those bugs are likely to trigger when I least need them.

It turns out I’m not the only person to think of having the computer read code back to you. In the October 1987 issue of The Rainbow, there’s an article by Bob Roberts that does the same thing. Of course, his is more complicated since it has to fit in memory around the BASIC program it’s reading. It doesn’t read the files (although, technically, there’s no reason it couldn’t) but rather reads the actual BASIC program from RAM. Nor is it a machine language program invoked with a special keystroke, like the rcheck+ program. Instead, it’s literally a BASIC program running above the real BASIC program, starting at line number 60000.

Of course, a BASIC program on an eighties computer required special hardware to generate speech. Roberts’s required Radio Shack’s Speech/Sound cartridge. Modern computers have speech built in. You can play around with it on the Macintosh command line using the say command. I go over this command in more detail—how to use the voices of various languages and accents—in the Diversion About History section of 42 Astoundingly Useful Scripts and Automations for the Macintosh.

My first attempt at having the iMac read BASIC code out loud was simply to send each line of BASIC to the say command. Given the lack of spaces in most old-school code, you won’t be surprised to learn that this did not work well.

What I ended up doing is writing what is basically a kind of rudimentary parser for the Color Computer’s BASIC. I suspect that a similar technique could be used to tokenize BASIC text, or to clean up BASIC code and optimize it, or to convert similar dialects between each other.

The script is most useful in the Services menu, so that you can highlight some text in a BASIC file and send it to the script. This is easily done by creating an Automator Quick Action. Unlike most Quick Actions that run shell scripts, this one has no need for checking “Output replaces selected text”.

I have two “read BASIC out loud” Quick Actions. One runs the text straight to ~/bin/readBASIC; the other runs it through ~/bin/rainbow from Rainbow Magazine BASIC program preflight tool and then to ~/bin/readBASIC.

Read BASIC Quick Action

Being able to select BASIC code and have it read out loud is as simple as a one-step Automator Quick Action.

Read Rainbow BASIC Quick Action

And if you want to hear code that’s been wrapped at 32 characters, add one more step.

The latter is required when reading from 32-character lines such as those in The Rainbow and Hot CoCo. The script requires full BASIC lines, not partial lines.

When handling long passages, it can be helpful to pause the script to verify questionable passages. Hold down the SHIFT key or turn on CAPS LOCK to pause reading. Hold down the COMMAND key to cancel reading. This is especially useful when the script is run as a Quick Action, since there is no easy way to interact with a script run as a Quick Action.

I wrote readBASIC as a Perl script. It has a list of keywords that I took from the Color Computer’s manual, a dictionary of pronunciations for the keywords, and a dictionary of character names, so that it can pronounce colon, comma, etc., instead of seeing them as punctuation.

You may wish to change some of the keyword pronunciations. They’re in the %pronunciations array.

Some characters are pronounced differently if encountered inside quotes than if encountered outside of quotes. For example, the asterisk is pronounced “star” inside of quotes and “times” outside of quotes.1

The script accepts files on the command line and text piped to it. The latter allows use of pbpaste to send whatever’s in the clipboard to the script.

  • pbpaste | ~/bin/readBASIC

The script goes through each line of code, parses out the line number, and then parses out the code in the line.

The script attempts to handle text inside of quotes or after a REMARK statement differently than text outside of quotes; text outside of quotes should always be BASIC code, except in a DATA statement. I’m not sure I’m handling DATA statements well, but after several magazines worth of code it seems to be okay.

The big problem is recognizing what text ought to be readable as words, and what must be read character-by-character.

It attempts to handle quoted text after a DRAW or a PLAY differently, since those are not normally pronounceable. Since DRAW and PLAY code is often constructed from previously created strings, if a string of text is longer than twelve characters and has no spaces, or if a “word” inside of a string that contains spaces is longer than 14 characters, the script will read that text character by character instead of as words.

This is obviously not optimal, since many words are longer than that, and many code strings are shorter than that, but it mostly works. Even with a perfect parser—which readBASIC definitely is not—detecting what strings should be read as words and what strings should be read as characters is going to be guesswork.

It does not handle DATA lines in any special way. DATA can be just about anything, from decimal or hexadecimal characters to words and phrases. What I probably need to do is parse out the data elements and speak them separately.

I’m pretty sure that the only thing in this script that requires macOS are the say command and the ability to pause/cancel using modifier keys. The command is in a variable at the top of the script, which you can change if you have a different command for speaking. And the only place the command is used for reading out loud is in the speak subroutine.

If you want to disable the modifier keys, all of the modifier key code is at the top of the script. Comment out the two NS lines and put a return at the top of the pauseOrQuit subroutine.

In response to TRS-80 Color Computer Programming Tools: The TRS-80 Color Computer was a fascinating implementation of the 6809 computer chip, and was, from the Color Computer 1 through 3, possibly the longest-running of the old-school personal computers.

  1. I tried to pronounce the dash as “dash” inside of quotes and “minus” outside of quotes, but it turns out to be difficult to know when a dash is a dash and when it is a mathematical operator.

  1. <- Hex to CoCo BIN