## BASIC-language Actor

The BasicActor implements a simple dialect of the good old BASIC computer language. It is particularly convenient for implementing arithmetic and simple algorithms directly in a .aud file.

BASIC statements can be either embedded in a .aud file, or written in a text file which the actor loads. The former has the advantages of being self-contained and allowing tighter integration with other actors.

The input and output of the BASIC interpreter are attached to the BasicActor, instead of to a terminal you can interactively type at and view output.

The dialect is Chipmunk Basic, also used by HotPaw on the Palmpilot. (That webpage contains several references, tutorials, and examples.) A command reference is included at the end of this page.

To use the BasicActor, load basic.so and create an actor of type BasicActor.

### BasicActor messages

In addition to the messages understood by all actors, the BasicActor understands the following messages:

Do `hActor message`
  Send the BASIC command `message` to the BASIC interpreter. In other words, "do" that command. This is how you get stuff into the BASIC interpreter. Any output (from PRINT statements) is suppressed.
SendFloats `hActor hMessageGroup message`
  Like "Do", do the BASIC command given by `message`. Unlike "Do", the command should cause one or more whitespace-delimited numbers to be PRINTed (in a single line). This string is then passed to the message group given by `hMessageGroup`, which will parse it as a sequence of floating-point numbers in the usual way. This is how you get data back out of the BASIC interpreter.
Debug `hActor bool`
  The BasicActor echos to standard error the commands it receives, when `bool` is true.

Also note the `printvss` and `printdbg` commands described under `PRINT` below in the Chipmunk BASIC Language Command Reference.
`printvss` is an alternative to SendFloats, which can send a message to VSS or to any actor, not only to a message group. Its generality comes at the expense of hairy syntax (see the "siren" example below).
`printdbg` is useful for debugging.

### Warnings and Tricks

If you're used to programming in C/C++, remember that BASIC's `if` statement requires a `then`.

Note that variable names in BASIC and in VSS inhabit separate spaces.

(In what follows, we assume the following:

    	LoadDSO basic.so;
    	LoadDSO msgGroup.so;
    	bb  = Create BasicActor;
    	mg  = Create MessageGroup;
    	mg2 = Create MessageGroup;

).

The "*" is used by VSS and BASIC in different ways. This will fail:

    	AddMessage mg Do bb "a=b*c";

because VSS tries to parse the * in the sense of *0, *1, etc.: an argument of myMessageGroup. This way avoids the problem, by moving the * out of the line containing "AddMessage myMessageGroup":

    	Do bb "10 a=b*c: return";
    	...
    	AddMessage mg Do bb "gosub 10";

But what if you want * in both senses, multiplication and argument? This

    	AddMessage mg SendFloats bb mg2 "print (42 - *0 * *1) * 0.5";

will fail, but it can be split apart:

    	Do bb "10 print (42 - mgarg0 * mgarg1) * 0.5: return";
    	AddMessage mg SendFloats bb mg2 "mgarg0=*0:mgarg1=*1: gosub 10";

Or you can cheat with reciprocals, though this is dangerously unreadable:

    	AddMessage mg SendFloats bb mg2 "print (42 - *0 / (1/*1)) / 2";

This splitting apart is itself good design, if your BASIC program is of any length at all. Rather than wrapping each line of your BASIC program with AddMessage's, define it with line numbers and then call it with gosub:

    	Do bb "10 ... ";
    	Do bb "20 ... ";
    	...
    	Do bb "70 ... : return";
    	...
    	AddMessage mg Do bb "gosub 10";

### Examples

An FM tone rhythmically warbles up and down like a siren. Message group SetMinMax stores two variables, a high and low frequency. A BASIC subroutine gets called every 2 seconds (by a LoopActor) to change the direction of the siren.

    	// Initialize variables: range of siren, and which direction it's going in.
    	LoadDSO basic.so;
    	bb = Create BasicActor;
    	Do bb "freqMin=100: freqMax=400: rising=0";

    	// Start the sound.
    	LoadDSO fm.so;
    	aFM = Create FmActor;
    	sFM = BeginSound aFM SetFreq 400;

    	// This is how you can control the endpoints of the siren swings.
    	SetMinMax = Create MessageGroup;
    	AddMessage SetMinMax Do bb "freqMin=*0: freqMax=*1";

    	// This swings the siren back and forth every 2 seconds.
    	LoadDSO control.so;
    	LoadDSO msgGroup.so;
    	mgLL = Create MessageGroup;
    	AddMessage mgLL Do bb "gosub 10";
    	LL = Create LoopActor;
    	Active LL 0;
    	SetMessageGroup LL mgLL;
    	SetTimeStep LL 2.0; // seconds per tick
    	SetNumLoops LL -1;
    	Active LL 1;

    	// Do a swing of the siren.  BASIC can send messages to
    	// other VSS actors with its printvss command (see PRINT below).
    	// Here, it sends a command of the form "SetFreq sFM 100 2.0".

    	Do bb "10 if rising then printvss" \""SetFreq"\" sFM "freqMin 2.0: rising=0: return";
    	Do bb "20 printvss" \""SetFreq"\" sFM "freqMax 2.0: rising=1: return";

    	// The quotation marks are a bit tricky here.  Three rules:
    	// (1) VSS stuff doesn't get quoted (like sFM).
    	// (2) BASIC stuff goes inside double quotes (like freqMin)...
    	// (3) ...except for literal strings which BASIC needs to send back to VSS;
    	//     they are preceded by \"" and followed by "\" (like SetFreq).

The same escaped-double-quotes incantation of SetFreq above applies here to the "load" command.

    	LoadDSO "basic.so";
    	bb = Create BasicActor;

    	Do bb load \""foo/bar/x.bas"\";
    	/* load the BASIC program "foo/bar/x.bas", relative to the VSS server's current directory. */

    	Do bb print 7*8.001;
    	Do bb "print 42: print 56: y=57";

    	Do bb "run";
    	/* run x.bas now */

    	Do bb "y=59:print y";
    	Do bb "print sqrt(y), 1/y, -53";

### Chipmunk BASIC 1.0 Language Command Reference

#### Commands

          LIST line(s)
             List the specified program lines.  For example,
                   LIST 10, 100-200
             lists line 10, and lines 100 through 200, inclusive.

          RUN [line]
             Begin execution of the program at the first line, or at the
             specified line.  All variables are cleared.

          RUN file[,line]
             Load and run a program.  For example,
                   RUN "FOO", 30
             loads a program from the file FOO.TEXT and begins execution at
             line 30.

          NEW
             Erase the program in memory.

          LOAD file
             Load a program into memory.  The program previously in memory is
             erased.  The file name should be in quotes; a .TEXT extension is
             automatically added.  Files contain ASCII listings of the programs.
             All lines in the file must begin with a line number, but line
             numbers do not need to be in increasing order.

          MERGE file
             Load a program into memory.  The previous program remains in
             memory; if a line exists in both programs, the newly loaded
             line is kept.

          SAVE file
             Save the program in memory to a file.

          BYE
             Return to the operating system.

          DEL line(s)
             Delete the specified program lines.  Line numbers may be
             separated by commas and dashes as in LIST.  If used inside
             a program, DEL will terminate execution only if it deletes
             the line on which it appears.

          RENUM [start[,inc]]
             Renumber program lines.  By default, the new sequence is 10,20,30,...
             The first argument is a new initial line number; the second argument
             is the increment between line numbers.

#### Statements

          REM comment
             A remark; ignored.  Comments may contain any characters except
             that REM can not be immediately followed by an alphanumeric
             character.

          [LET] var = expr
             Assign a value to a variable.  Variable names contain up to 20
             significant characters, consisting of upper- and lower-case
             letters, digits, underscores, and dollar signs.  Variable names
             are case-sensitive.  Variables hold real numbers normally, or
             strings of up to 255 characters if their names end with $.
             Examples:
                   LET X=20
                   X$="FOO"
                   X$=X$+"BAR"

          DIM var(dimensions), ...
             Allocate memory for arrays.  Arrays may have up to 4 dimensions,
             ranging from 0 to the value specified in the DIM statement.
             The same name must not be used for both a simple variable and
             an array.
             If an array is used before it is dimensioned, each dimension
             is set to 10.
             Example:
                   INPUT "How many elements? "; x
                   DIM array(x,1)
                   FOR i=1 TO x : INPUT array(i,0), array(i,1) : NEXT

          PRINT items
             Print the items on the screen.  Items may be either numeric
             or string expressions, and may be separated by commas, semicolons,
             or nothing.
             Numbers are normally terminated by spaces.  To avoid this space,
             convert the number to a string with STR$.
             The line is terminated by a CR/LF, unless the item list ends
             with a comma or semicolon.
             The word PRINT may be abbreviated as a question mark.
             Examples:
                   PRINT "1+2=", 1+2
                   PRINT X$ "=" Z$;
                   ? x; y+z
             (VSS extensions: PRINTVSS sends commands directly to VSS,
             not to SendFloats.  PRINTDBG goes directly to standard error. )

          INPUT [prompt;] vars
             ( This is disabled in VSS -- there's nowhere to type input. )
             If a prompt string is given, it is printed.  Otherwise, a
             question mark is printed.  The computer then waits for values
             for each variable to be entered.  If several variables are
             listed, their names must be separated by commas.
             If the variables are numeric, their values may be entered
             on separate lines, or combined with commas.  Any numeric expression
             is a valid response.
             If the variables are strings, each string is typed on a separate
             line.  The characters typed are copied verbatim into the string.
             String and numeric variables may be not mixed in a single
             INPUT statement.
             Examples:
                INPUT X$
                INPUT "Type 3 numbers: "; X, Y, Z

          GOTO line
             Begin executing statements at the specified line.  The line
             number may be any numeric expression.
             The word GO TO may be used instead of GOTO if preferable.

          IF condition THEN line/statements ELSE line/statements
             If the condition is true (i.e., the numeric expression has a
             non-zero value), the statements following the word THEN are
             executed.  Otherwise, the statements following ELSE are
             executed.  If there is no ELSE clause, execution proceeds
             to the next line in the program.
             A line number may be used after either THEN or ELSE, for an
             implied GOTO statement.

          END
             Terminate the program.  An END statement is not required.

          STOP
             Terminate the program with an identifying "Break" message.

          FOR var = first TO last [STEP inc]
          {statements}
          NEXT [var]
             Execute {statements} repeatedly while the variable counts from
             "first" to "last," incrementing by 1, or by the STEP value if
             given.  If the STEP value is negative, the variable counts
             downward.
             If "first" is greater than "last" (or less than if STEP is
             negative), execution proceeds directly to the NEXT statement,
             without executing the body of the loop at all.
             The variable name is optional on the NEXT statement.

          WHILE [condition]
          {statements}
          WEND [condition]
             Execute {statements} repeatedly until the WHILE condition (if
             given) becomes false, or until the WEND condition becomes true.
             This structure can emulate Pascal's WHILE-DO and REPEAT-UNTIL,
             or even both at once.  If no conditions are given, the loop will
             never terminate unless the Evil GOTO is used.

          GOSUB line
          RETURN
             Execute the statements beginning at the specified line, then
             when RETURN is reached, return to the statement following the
             GOSUB.

          READ vars
          DATA values
          RESTORE line
             (VSS: This is broken as of 9/30/99.)
             Read numeric or string values from the DATA statements.  Reading
             begins at the first DATA statement in the program and proceeds
             to the last.  Reading past the end the last DATA statement
             generates an error.
             The DATA values must be either numeric or string expressions,
             according to the type of variable being read.  Reading the wrong
             kind of expression produces a Syntax Error.
             The RESTORE statement causes the next READ to re-use the first
             DATA statement in the program, or the first DATA statement on
             or after a particular line.

          ON expr GOTO line, line, ...
          ON expr GOSUB line, line, ...
             If the expression's value, rounded to an integer, is N, go to
             the Nth line number in the list.  If N is less than one or is
             too large, execution continues at the next statement after
             the ON-GOTO or ON-GOSUB.

          POKE addr, data
             Store a byte at the specified address.

#### Numeric Expressions

          x AND y
             Logical AND of two integers.

          x OR y
             Logical OR of two integers.

          x XOR y
             Logical XOR of two integers.

          NOT x
             Logical complement of an integer.

          x+y, x-y, x*y, x/y, x^y, -x
             Typical floating-point arithmetic operations.

          x=y, x<y, x>y, x<=y, x>=y, x<>y
             Comparisons; result is 1 if true, 0 if false.

          x MOD y
             Modulo of two integers.
             (VSS extension: works with floating point too, like C's fmod().)

          RAND x
             VSS extension: return a random integer in [0,x).
             x should be positive.
          RND x
             VSS extension: return a random number in [0,1).  x is ignored.

          SQR x
             Square of X.  Note that parentheses are not required if a function's
             argument is a single entitity; for example, SQR SIN X needs no
             parentheses, but SQR(1+X) does.

          SQRT x
             Square root of X.

          SIN x, COS x, TAN x, ARCTAN x
             Typical trig functions, in radians.

          LOG x, EXP x
             Natural logarithm, and e the power X.

          ABS x
             Absolute value of X.

          SGN x
             Sign of X:  1 if X is positive, 0 if zero, -1 if negative.

          VAL x$
             Value of the expression contained in the string X$.  For example,
             VAL "1+2" yields 3.  X$ may be a single string literal, variable,
             or function, or a string expression in parentheses.

          ASC x$
             ASCII code of the first character in X$, or 0 if X$ is null.

          LEN x$
             Number of characters in X$.

          Precedence:      Parentheses
                            Functions  (including NOT and unary minus)
                                ^
                            *, /, MOD
                              +, -
                       comparison operators
                               AND
                             OR, XOR

#### String Expressions

          "string" or 'string'
             String literal.  Single quotes are converted to double quotes
             internally.

          x$+y$
             Concatenation.  Result must be 255 characters or less.

          x$=y$, x$<y$, etc.
             String comparisons; result is 1 if true, 0 if false.

          STR$(x)
             The number X expressed as a string of digits.  No leading or
             trailing spaces are included; scientific notation is used
             if the absolute values is greater than 1E12 or less than 1E-2.

          CHR$(x)
             The character whose ASCII code is X.

          MID$(x$, y)
          MID$(x$, y, z)
             (Parentheses required.)  The substring consisting of the first
             Z characters starting at position Y of string X$.  Position 1
             is the first character of the string.  If Z is omitted, 255
             is used, i.e., the entire right part of the string.

#### Conventions

          Multiple statements may be written on a line, separated by colons:
                10 X = 42 : PRINT X : Y = X+1

          There is actually no difference between commands and statements;
          both can be used in or out of programs at will.  Certain commands,
          such as NEW, will, of course, halt program execution.

          Line numbers may be any integer from 1 to MAXINT.

          To delete a line, type its line number alone:
                10

          VSS extension: if you reuse a line number, VSS prints a warning
          since it's likely that you've done so unintentionally by copy/pasting
          from another .aud file.
          To leave BASIC, use the BYE command.

          Keywords must be written in all upper- or all lower-case; they are
          always converted to upper-case internally.  Spaces are ignored in
          the input except between quotes.  Square brackets are converted to
          parentheses.
          VSS restriction: Keywords must be written in all lower-case.
          This speeds up parsing significantly for this real-time application.