The first generation Wang 2200 CPU ran the dialect of BASIC known as "Wang BASIC." The CPU went through a few revisions of a relatively minor nature: repackaging as technology advanced, adding more microcode to support additional features. None of those changes affected performance.
While the Wang BASIC was advancing, the design team started a new CPU project from scratch in 1974(?). While the influence of the first microarchitecture is evident in the second, the changes were large and required a complete rewrite of the BASIC interpreter. This new BASIC dialect was called BASIC-2.
Although backward compatibility was a major goal, the designers of BASIC-2 took the opportunity to extend the syntax and power of the language.
This page doesn't try to cover every detail of BASIC-2; it tries to highlight some of the interesting and significant improvements made to the BASIC dialect. It will make the most sense to those who only know Wang BASIC. Those who know BASIC-2 will probably be amazed that Wang BASIC programmers lived without some of these features.
BASIC-2 was nearly a strict superset of Wang BASIC; only a handful of language features were dropped, and the vast majority of Wang BASIC programs ran under BASIC-2 unchanged or with only a minor edit.
Fundamental features of Wang BASIC that didn't change for BASIC-2 included:
- data was statically allocated during the resolve phase
- there was almost no concept of variable scoping; every variable was global
- variable names were limited to a single letter or a letter-number pair
BASIC-2 running on the VP CPU was also dramatically faster, typically about eight times faster. Some of it was due to the shorter microinstruction cycle time, some due to the more powerful instruction set, and the rest due to a shift in priorities to write the interpreter to be fast instead of small.
As noted on the Stupid Tricks page, Wang BASIC had a number of design flaws.
BASIC-2 was much more robust, for a few reasons. One reason was that the VP CPU used static RAM for holding microcode instead of ROMs. This meant that as bugs were discovered, they would be routinely fixed in the next release of the operating system, which entailed mailing out floppy disks, instead of having to upgrade as many as 20 ROMs.
Another reason was simply that the designers of BASIC-2 thought very hard about making it difficult for an end-user to peek into the innards of the implementation. For instance, in Wang BASIC, when a line was recalled for editing, the user was editing the tokenized representation of the line. This allowed injecting bogus token values into the edit buffer. In contrast, BASIC-2 detokenized the line before editing, then retokenized after editing.
As another example of the more robust design, more care was taken to
preserve accuracy in implementing the fundamental computations, namely add,
subtract, multiply, divide, transcendentals, and even
Not only was
RND() almost 100 times faster in BASIC-2,
it was more random!
The simplest kind of improvement that BASIC-2 made was to improve a few of the limits that were part of Wang BASIC operation.
In Wang BASIC, the maximum array dimension was 255. In BASIC-2, 2D arrays retained this limit, but 1D arrays could have a maximum dimension of 65535. Practically speaking, memory capacity would have been exhausted before this limit was reached.
String variables are declared to have a fixed allocation size. BASIC-2 raises the limit per string from 64 bytes to 124. This is important as screens were commonly 80 characters wide.
In a number of commands and functions, BASIC-2 took an existing Wang BASIC feature and added to the syntax to allow for more functionality. Some of these features were common in other BASIC dialects, but many were unique to BASIC-2. Below are some examples.
IF ... THENstatement only allowed branching to some line if the condition was true. BASIC-2 generalized this, like many other BASIC dialects, to allow most statements to be executed.
100 IF A<=0 THEN 110:S=S+A 110 ...
100 IF A>0 THEN S=S+A 110 ...
BASIC-2 added the
ELSEclause to the
IFstatement, common to most BASICs.
100 IF A<=0 THEN 105:S=S+A:GOTO 110 105 A=A+1 110 ...
100 IF A<=0 THEN A=A+1:ELSE S=S+A 110 ...
BASIC-2 added the
ELSEclause to the
ON ... GOTOand
ON ... GOSUBcommands as well.
100 INPUT "(R)ead, (W)rite, (T)est, or (Q)uit", A$ 110 ON POS("RWTQ"=A$) GOTO 100,200,300,400:ELSE PRINT "ERROR":GOTO 100
IFwas improved by allowing conjunctive conditionals. Conditionals were simply evaluated left to right.
100 INPUT "Enter three numbers",A,B,C 110 IF A>=B THEN 120:IF B>=C THEN 120:PRINT "Ascending" 120 ...
100 INPUT "Enter three numbers",A,B,C 110 IF A<B AND B<C THEN PRINT "Ascending"
In the case of nested
FORloops, BASIC-2 allowed specifying the nested completion of the loops in a single statement.
100 FOR I=1 TO 10:FOR J=1 TO 10:PRINT 10*I+J;:NEXT J:NEXT I
100 FOR I=1 TO 10:FOR J=1 TO 10:PRINT 10*I+J;:NEXT J,I
- move cursor to screen location X,Y
- draw a box of a given size at a current screen location
HEXPRINT, but as a function instead of a command
The syntax for assigning to string variables was considerably enhanced. Wang BASIC starting with the 2200B CPU added commands for performing boolean (bitwise) operations on a pair of alphanumeric variables. BASIC-2 turned these into a functional form, and added the
ALL()function as well.
BASIC-2 also added a string concatenation operator,
&, only in the context of string assignment.
Here are some examples of this flexible syntax.
10 INPUT "What is your last name", N$ 20 A$="Mr.":STR(A$,5)=N$:STR(A$,LEN(A$)+1)=", I presume" 30 A$=B$ : AND(A$,C$) 40 AND(A$,B$) 50 AND(A$,B$) : OR(A$,F0) 60 A$=B$ : ADDC(A$,C$) 70 INIT(".") A$
10 INPUT "What is your last name", N$ 20 A$ = "Mr. " & N$ & ", I presume" 30 A$ = B$ AND C$ 40 A$ = AND B$ : REM like A$ = A$ AND B$ 50 A$ = AND B$ OR ALL(F0) 60 A$ = B$ ADDC C$ 70 A$ = ALL(".")
PRINTUSINGwas generalized to accept an image string, not just an image line reference, eg:
10 % #.########## 20 PRINTUSING 10, 1/3
10 % #.########## 20 PRINTUSING 10, 1/3 30 PRINTUSING "#.##########", 1/3 40 A$="#.##########" 50 PRINTUSING A$, 1/3
The output of
PRINTUSINGcould be captured by an alpha variable, although there were some twists to using it. The first two bytes of the receiving var held a count of the bytes received. Each
PRINTUSING TOupdated this count such that a series of
PRINTUSING TO's could be glued together.
10 A$=ALL(00):REM initialize byte count 20 PRINTUSING TO A$, "#.##", SQR(3) 30 PRINTUSING TO A$, "#.##", SQR(5) 40 PRINT STR(A$,3,VAL(A$,2)) :RUN 1.73 2.23
It was often very inconvenient to work with binary data that was larger than 64 bytes due to the fact that Wang BASIC allowed a maximum of 64 bytes per string. BASIC-2 relaxed this somewhat to the seemingly (but with good reason) bizarre 124 bytes. That was an improvement when dealing with strings of that didn't need to be wider than the 80 column CRT screen, but it was of little help to programs which manipulated larger binary strings.
To get around this 124 byte limit, BASIC-2 added a notation which allows a string array to be interpreted as a single large contiguous string. This notation was usable in most contexts that accepted a scalar string.
10 DIM A$(50)50:REM 2500 bytes ... 100 STR(A$(),5,50) = STR(A$(),1000,50) : REM move 50 bytes 110 A$()=ALL(" ") 120 A$(2)="Test" 120 A$(3)="..+.." 130 PRINT LEN(A$()):REM produces 54 140 PRINT POS(A$()="+"):REM produces 103
BASIC-2 generalized both
BIN(A)and its inverse,
VAL(A$), to optionally take a second parameter, which specifies that these convert to and from a 16 bit number, instead of just 8 bits.
10 A$=HEX(1234) 20 PRINT VAL(A$) : REM produces 18 30 PRINT VAL(A$,2) : REM produces 4660
In Wang BASIC,
RENUMBERcould change the line numbers of a block of lines, but the relative order of all lines was not affected. BASIC-2 generalized this to allow renumbering a block of lines such that they moved into an empty range of line numbers.
LISTcommand had quite a few additions
- "decompressed" - one statement printed per line
- line number cross reference
- variable cross reference
- DEFFN' cross reference
LIST T "text"
- find lines containing specified text
- list device tables
- list interrupt table
In the Wang BASIC dialect,
RESTORE 20restored the
READdata pointer to the 20th
DATAelement found in the program.
BASIC-2 added the new syntax
RESTORE LINE 20to restore the
READpointer to the first
DATAelement of line 20.
RETURN CLEARcommand clears one level of subroutine nesting. BASIC-2 extended the syntax to allow the statement
RESTORE CLEAR ALL, which clears the stack of all outstanding subroutines.
ROTATEcommand could rotate 1-7 bits of each byte of a string. The new syntax
ROTATE, but bits carried between bytes of string, such that the rotation was over the entire length of the string.
The General I/O command,
$GIOadded new commands, including branching ops.
BASIC-2 added some new functions, as briefly described here.
- Integer part of the expression
- Same as SGN(v)*INT(ABS(v))
- Finds the remainder of v1/v2
- Rounds v1 to the v2'th decimal place; v2 can be positive or negative
- Finds the maximum value among the specified expressions or numeric array(s)
- Finds the minimum value among the specified expressions or numeric array(s)
- Finds log base 10 of the expression
- verifies that a string matches a given format
Clarifying a bit,
MIN() took a variable
number of arguments, including array references. For example,
100 M = MAX(0, A()) finds the largest number in the array
A(), but if that number is negative, zero is returned instead.
BASIC-2 added some entirely new commands to the language, in addition to the improvements already noted to existing commands. Many other commands were added to BASIC-2 once the MVP OS was developed, but won't be listed here.
INPUTstatement scanned the user's response, removing spaces and breaking fields at commas. This meant that in general using
INPUTto accept a literal string from a user wouldn't be reliable, as they might have entered something with leading spaces or commands.
The answer was the
LINPUT(line input) statement. Whatever the user typed was exactly what was received by the argument variable.
10 LINPUT "Your answer? ", A$ 20 PRINT "OK"; A$ :RUN Your answer? *This, that OK,This, that
$UNPACKcommands took a character string that encoded the format of how data was packed into the receiving variable. Manipulating these codes was error prone, so BASIC-2 added the
$FORMATcommand to make building these format strings more self-documenting and easier to create.
10 REM 3 digit Integer, packed 8.2 number, 10 byte string 20 $FORMAT F$=I3, P8.2, A10 30 $PACK (F=F$) B$() FROM X,Y,A$
The new BASIC-2 commands
HEXPACKand its inverse,
HEXUNPACK, convert to and from ASCII hex strings and packed binary data.
10 DIM A$2,B$1 20 A$="43" 30 HEXPACK B$ FROM A$ 40 HEXPRINT B$:REM produces "43" 50 B$="T" 60 HEXUNPACK B$ TO A$ 70 PRINT A$:REM produces "54"
SELECTwas already the swiss-army knife of Wang BASIC. BASIC-2 added a few more blades.
- Allows suppressing errors below a given threshold
SELECT NO ROUND
- Disables rounding of arithmetic results
- Enables rounding of arithmetic results
- Specify how many lines of text are on an output device
ON <expr> SELECT ...
- Allows performing one of a set of
SELECTstatements with a single command
SELECT ON/<addr> GOSUB <line number>
- Programmable interrupt feature
- Programmable interrupt feature
ON ... SELECTsyntax is quite useful, especially when there were many more I/O choices, such as allowing the user to select a disk drive address.
10 INPUT "Output to Screen or Printer",A$ 20 ON POS("SP"=STR(A$,1,1)) GOTO 30,40:GOTO 10 30 SELECT PRINT/005(80):GOTO 50 40 SELECT PRINT/215(132) 50 ...
10 INPUT "Output to Screen or Printer",A$ 20 ON POS("SP"=STR(A$,1,1)) SELECT PRINT/005(80);PRINT/215(132):ELSE GOTO 10
An entirely new concept was added for BASIC-2, namely an interrupt driven model under program control. The
SELECT ON .. GOSUB ...and other variations were used to trigger a call to a subroutine when a given I/O device signalled it was ready for work. Read Chapter 8 of the BASIC-2 manual for the details, but here is a simple example.
10 SELECT ON/001 GOSUB 100 20 D=0 30 IF D=0 THEN 30:A=A+1:PRINT A;:GOTO 30 ... 100 REM keyboard interrupt routine 110 KEYIN A$ 120 IF A$="G" THEN D=1:REM GO 130 IF A$="S" THEN D=0:REM STOP 140 SELECT ON/001:REM re-enable interrupt 150 RETURN
When the program is run, nothing appears to happen. The program spends all of its time executing line 30, inspecting the variable
D. When the user types a key, the code starting at line 100 is called. If the user has typed a "G",
D=1and line 30 starts filling the display with incrementing numbers. When the user types "S",
D=0and the numbers stop appearing.
The initial releases of BASIC-2 were for the 2200 VP CPU. The VP OS supported a single user, just like the first generation machines. With the introduction of the 2200 MVP CPU, the OS was reworked to perform time sharing between multiple "partitions." Once a partition was selected to run, it would occupy the CPU until either it blocked waiting for some I/O device, or a 30 millisecond timer expired. It would then be put back on the task list, and the next task would be started, in round-robin order.
A partition was a contiguous chunk of memory which held a BASIC context: a program and its associated data. Although the simplest scenario maps each terminal to one partition, it was possible for a single terminal to control multiple partitions, with one in the foreground and one or more in the background. Background partitions would timeslice along with all the other partitions until they blocked trying to access the terminal I/O device. At the point the blocked partition was moved to the foreground status, it would spring back to life.
The details of defining and managing partitions were complicated, such as the minimum and maximum size of a partition, how the partitions mapped into 64 KB "banks" of memory, and how partitions were mapped to terminals. Further complicating things, an 8 KB section of RAM, a "global partition", could be made accessible to other partitions, again with various restrictions. This global code and data could shared between cooperating partitions.
Many commands were introduced into BASIC-2 to manage partitions and resource sharing. Some existing commands that did not play well with resource sharing and time slicing either were modified or had constraints placed on their use. Some commands to manage concurrency and resource sharing.
To get the full story, see Chapter 16 of the BASIC-2 manual.
For the most part, BASIC-2 retained just about all the syntax and functionality of Wang BASIC. See Appendix C of the BASIC-2 manual for a detailed exposition. Here, then, are just a few key differences.
The I/O commands specific to controlling TTY devices (punches), card readers, and cassette tapes were dropped in BASIC-2.
There was simply insufficient demand to justify rewriting that part of the BASIC interpreter.
Wang BASIC had a means of trapping most errors, using the
ON ERROR A$,N$ GOTO 1000syntax. BASIC-2 performs error control using a few different bits of syntax.
SELECT ERROR > nn
- sets threshold of errors to ignore
- returns error code of the most recent error condition
- If an error occurs in the execution of a statement, but
the very next statement is an
ERRORstatement, the normal error processing is ignored and the statements following the
Numeric results could be different in the least significant digit.
The pseudo-random sequence returned by