Electronics Today International: The Applix Articles

ETI December 1987 — page 70

Project 1616

BASIC

In the first few months of 1987 we published construction details on the Applix 1616 computer, and promised enhancements as they came to hand. Applix Co, the designers, have just released a BASIC to make programming easier, so here it is.

Paul Berger *

THE 1616 BASIC interpreter started life as a public domain UNIX-based program, written by Phil Cockcroft, somewhere in the US of A. We at Applix evaluated the program and decided it provided basis for the 1616 BASIC system.

Almost all of the code for BASIC is written in the ‘C’ language (as usual) and the interpreter has been adapted to run under 1616/OS, shortened, enhanced and considerably sped up by Andrew Morton, one of the Applix Insomniacs (or AI’s, as they are known in the industry).

The language is pretty standard, and includes just about all the features that a BASIC ever had. Those who have used a Microsoft BASIC will be on familiar ground here: such BASIC programs will run under 1616 BASIC with little or no change.

A BASIC program consists of a 1616/OS ASCII text file. Each line of the program has a line number at its start; the line numbers are used for ordering program lines as they are entered and for referencing sections of the program using the ‘goto’ and ‘gosub’ commands, etc. The ASCII program is ‘tokenised’ when it is read in from disk or typed in; this means that each BASIC keyword which is recognised in a new program line is converted into a single byte before being added to the main body of the program. This saves space and increases execution speed.

BASIC program files may be created using the 1616/OS full screen editor, or by editing individual lines from within the BASIC system. The BASIC ‘edit’ command permits the programmer to use the standard 1616/OS line editor to alter existing program lines.

The language features 10 digit floating point variables, 32-bit integer (whole number only) variables, multi-dimensional arrays and character strings. The first 15 characters of a variable’s name are significant. Numbers may be specified in either decimal or hexadecimal notation (hex numbers are preceded by a ’$’ symbol). The 32-bit integers may range from -2,147,483,648 to 2,147,483,647. Programs written using integer variables are considerably faster than those which use floating point, so integers should be used wherever possible.

The BASIC system provides an environment in which you may interactively alter and run BASIC programs; it also supports a ‘direct’ mode where a few BASIC statements may be executed without actually entering them into a program. Any 1616/OS command may be performed from within the BASIC system by preceding it with a right square bracket ‘]’. You may indefinitely escape back to 1616/OS from BASIC by using the ‘shell’ statement; you return to BASIC with the original program and variables intact by entering the 1616/OS ‘quit’ command.

Graphics & video control commands

The 1616-specific video and graphics control commands which are not found in other BASICs are:

set640, setvdp, setvap, setfgcol, setbg-col, setbdcol, setpal, scursmode, plot, sgfgcol, sgbgcol, sgtexture, line, circle, readdot

These commands translate directly into 1616/OS system calls.

File I/O

The file I/O commands are:

open, create, fread, write, close, rename, delete, seek, tell, eof

These commands relate directly to the 1616/OS file I/O system calls and they all return a value which, if negative, indicates some sort of error. A diagnostic message which describes the error may be obtained using the ‘fileerr$’ command (see the example below).

The ‘seek’, ‘tell’ and ‘eof’ commands may be used to implement random-access files.

In addition, the ‘print’, ‘input’, ‘linput’ and ‘get$’ command save modes in which files are used for I/O, rather than character devices.

One interesting feature of 1616 BASIC is that there are four commands which greatly extend the BASIC and make the entire resources of 1616/OS available to BASIC programs. Owners of 1616s appear to be a cunning breed and they will be doing amazing (and probably incomprehensible) things with these commands.

Performing system calls

The ‘syscall’ statement directly performs a 1616/OS system call and passes the 1616 BASIC commands returned value to the BASIC calling program. For example, the following program fragment reads the setting of a joystick:

	1010 nul% = syscall (70, 7): rem Select analogue input #7
	1020 joystickval% = syscall(73): rem Perform the conversion

In line 1010 above the value returned by the system call was assigned to the variable ‘nul%’ and then ignored. This is because the BASIC ‘syscair statement comes under the variety of statement which returns a value and must be made part of an arithmetic expression.

Executing 1616/OS commands

The ‘exec’ statement takes as its argument

a single string which is passed as a command to 1616/OS. An error code is returned to BASIC; if it is zero, all went well.

As an example of the use of this statement consider the following program which, amongst other things, sets up the 1616’s function keys to produce some oft-typed commands:

	10 rem Program to demonstrate the use of the 'exec' command
	20 rem
	30 print "Disk directory listing:" : print
	40 nul% = exec("dir"): rem Discard result in nul%
	50 rem
	60 rem Program the function keys 70 rem
	80 for key% — 1 to 10 90 read fkdef$: rem Get a string from the data tables
	100 nul% = exec("fkey" + hex$(key%) + " " + fkdef$)
	110 if (nul%) then print "Function key definition failed": stop
	120 next key%
	130 rem
	140 rem Now display the time
	150 print "On the third stroke it will be";
	160 nul% = exec("date") : rem Use 1616/OS to print the time out
	170 for i% = 1 to 3	
	180 print chr$(7); : rem beep 
	185 nul% = exec("pause .50") : rem Wait for 1 second
	190 next i%
	200 print "precisely"
	210 end 
	220 rem
	230 rem Data for the function keys 240 rem
	250 data "list ", "run ", "print ",
	"save ", "load "
	260 data "]dir ", "for ", "then ", "if ", "edit "

	100 ' Program : STRINGS.BAS - 1616 BASIC 
	110 ' Programmer : Paul Berger, Applix pty limited 
	120 '
	130 cls : set640(0) : scursmode(0, 1,0) : random : base 0
	140 size%=20	
	150 dim xs%(size%), xe%(size%), ys%(size%),ye%(size%)
	160 x1%=100 : x2%-60 : y1%=120 : y2%=175	
	170 z%=rnd(15)+1
	180 d1%=rnd(10)-5 : d2%=rnd(10)-5 : d3%=rnd(10)-5 : d4%=rnd(10)-5
	200 if	x1%+d1%<0	or	x1%+d1%>319	then	d1%=(-d1%)
	210 if	x2%+d2%<0	or	x2%+d2%>319	then	d2%=(-d2%)
	220 if	y1%+d3%<0	or	y1%+d3%>199	then	d3%=(-d3%)
	230 if	y2%+d4%<0	or	y2%+d4%>199	then	d4%=<-d4%)
	240 sgfgcol(0) : line(xs%(y%),ys%{y%),xe%(y%),ye%(y%))
	250 xs%(y%)=x1%+d1% : xe%(y%)=x2%+d2% : ys%(y%)=y1%+d3% : ye%(y%)=y2%+d4% 
	260 x1%=xs%(y%)	: y1%=ys%(y%)	: x2%=xe%(y%) : y2%=ye%(y%)
	270 sgfgcol(z%) : line(xs%(y%),ys%(y%),xe%(y%),ye%(y%)) : next : goto 170

Obtaining pointers to BASIC variables

The ‘varptr’ statement may be used to find the address of a BASIC variable (floating point, integer, array or string). This is very useful for passing references to your BASIC data to 1616/OS or to assembly language subroutines.

For integer (%) variables, a pointer to a 32 bit point is returned. For floating variables a pointer to a 8 byte floating point number is returned. For strings a pointer to the first byte of the null-terminated string is returned.

As an example, the following program fragments write an array of integers directly to a disk file and read it back in again. Thus its much more efficient than using ‘print’ and ‘input’ statement to and from the file in the normal manner.

	10 dim barofsoap%(100): rem The array of integers
	•
	•
	•
	1000 rem Write the array to disk
	1010 fd% = create("bathtub", 0, 0):
	rem create the file
	1020 if fd% < 0 then ec% = fd% : goto 2000 : rem create failed
	1030 ec% = write(fd%,
	varptr(barofsoap%(0)), 400): rem 4 bytes/integer
	1040 if ec% < 0 then goto 2000:rem write failed
	1050 ec% = close(fd%) : if ec% < 0 then goto 2000
	•
	•
	•
	1500 rem Read the array from disk, ignoring possible errors 
	1510 fd% = open("bathtub", 1) 
	1520 ec% = read(fd%,
	varptr(barofsoap%(0)), 400) 
	1530 ec% = close(fd%)
	2000 rem Handle file I/O errors 
	2010 print chr$(7);"Disk file error:";fileerr$(ec%)
	2020 stop

	100 ' Program : POND.BAS - 1616 BASIC
	110 ' Programmer : Paul Berger, Applix pty limited
	120 '
	130 ' Be patient....
	140 '
	150 set640(1) : els : base 0 : scursmode(0,1,0) : random
	160 dim r(640), c(640), pal(3) : gotoxy(0,24) : print"Wait...";
	170 for i%=1 to 640	: r(i%)-log(i%) :	e(i%) = log(i%)	: next
	180 for r%"1 to 200	: for c%=l	to 640	: x=c%*r(c9£) +r&*c( r%)
	190 x=x/5:y-int(x):z-x-y:z%=int(s*5):plot(c%-1, r%-l,z%+l):next:next 200 '
	210 ' go through palette making sure each entry is a different colour 220 *
	230 pal(0)=rnd(16)
	240 pal(1)=rnd(16): if pal(0) = pal(1) then goto 240
	250 pal(2)=rnd(16): for z=0 to 1 : if pal(z) = pal(2) then pal(2)-rnd(16):	next
	260 pal(3)=rnd(16): for z=0 to 2 : if pal(z) - pal(3) then pal(3)=rnd(16):	next
	270 for z=0 to 3: setpal(z,pal<z)) : next
	280 '
	290 ’ wait 5 seconds then change palette colours again 300 '
	310 ticks=syscall(18)
	320 repeat until syscall(18)=ticks+(50*5)
	330 goto 230

	100 ' Program : SPIRO.BAS - 1616 BASIC
	110 ' Programmer : Paul Berger, Applix pty limited
	120 '
	125 els : set640(0) : c-1
	130 input"Number please (8 to 60 is best)";a 140 els 150 ’
	160 ' now do it]
	170 '
	180 for t1=0 to (2*pi)-.001 step (2*pi)/a
	190 for t2=t1+(2*pi)/a to (2*pi)-.001 step <2*pi)/a
	200 line((cos(tl)*120+160),(sin(tl)*99+100),(cos(t2)*120+160),(sin(t2)*99+100)) 
	210 c=c+1 : sgfgcol(c) : if c>15 then c-1 
	220 next:next 

Calling assembly language subroutines

The BASIC is supplied as a 1616/OS transient program which loads into memory at address $8000, rather than the normal $4000. This provides 16k of memory which is free for assembly language subroutines and data.

The BASIC ‘call’ statement allows the calling of an assembly language subroutine, with a facility for passing up to nine arguments to the subroutine. The ‘call’ statement evaluates as the value which the subroutine returns in the MC68000’s data register 0. The 1616 BASIC ‘varptr’ statement comes into its own here: BASIC programs may pass pointers to arrays of data to assembly code, which can directly access and/or alter the data.

The following program fragment loads such a subroutine and calls it:

	10 dim barofsoap%(23)
	20 sheepdog% = 12
	•
	•
	•
	1000 nul% = exec("mload sheepdip 4000"): rem load the code in
	1010 if nul% then print "Cannot load file sheepdip" : stop
	1020 rem Call the assembly code, put d0 value into result %
	1030 result % = call($4000, 10, varptr(barofsoap% (0)), sheepdog%)

The 1616 Basic is available from Applix for $50 on tape. It will be available in ROM shortly, and readers interested should contact Applix direct. A disk based version will be available just as soon as the disk drives are available. As we go to press a timetable for this had not been finalised. •

BASIC Commands

abs			absolute value
and			logical and standard ‘and’ command
asc			convert ASCII character to its numeric value
atn			arctangent
base			starting base for arrays (0 to 1)
bye			exit BASIC and return to 1616/OS
call			call a machine language routine from BASIC
chr$			converts number to equivalent ASCII character
circle			draw a circle
clear			clear program variables
close			close data file
els			clear the screen
cont			continue interrupted program
cos			cosine
create			create a data file
data			standard data statement
date $			read the current date/time as a formatted string
def fn			user defined function
del			deletes a range of BASIC program lines
delete			delete a data (disk) file
dim			dimension array
edit			edit a program line
end			end program
eof			return number of bytes to end of data (disk) file
errmsg$			return error message string
errline			line number of an error that just occurred
error			generate an error code
ermum			error code of error that just occurred
oval			evaulate a string as an expression
exec			execute 1616/OS command
exit			exit BASIC and return to 1616/OS
exp			exponential function
fileerr$		return file l/o error message
for .. to .. step	standard for loop
freed			read from a data (disk) file
get$			get a record
gosub			execute subroutine
goto			continue program execution at specified line number
gotoxy			position cursor at x, y screen coordinate
hex$			converts number into a string containing 
			a hexadecimal number equivalent to the original number
if .. then .. else	standard 'if’ statement
inkey$			read a character from the keyboard
input			read data from keyboard or data file
instr			find substring within a given string
int			largest integer number less than or equal to argument
lefts			take substring starting with first character
len			length of string
let			standard assignment statement (eg. let a - 3)
line			draw line
linput			read data from keyboard or data file with commas etc
list			list program (or part thereof)
load			load a BASIC program file
log			natural logarithm
merge			merge a BASIC program into program currently in memory
mid$			extract a substring from a given string
mod			remainder of division
new			erase program currently in memory
next			ends ‘for’ loop
normal			for restoring some sanity to all the video modes
not			logical ‘not’
on.. error		enable error trapping
on .. gosub		standard computed 'gosub1 command
on.. goto		standard computed 'goto’ command
open			open a data file
or			logical and standard ‘or’ command
peek			read a value from memory
pi			returns the value of π
plot			plot a graphics pixel
poke			put a specified value into a byte
print			print to the screen or file
random			start a new random number sequence
read			read information from 'data’ statement
readdot			real a graphic pixel value
rem			standard remark statement
rename			rename a data (disk) file
renumber		renumber BASIC program
repeat.. until		repeat until expression is true
restore			reset pointer to 'data’ statements
resume			return from error routine
return			return from subroutine
rights			take substring ending with last character
rnd			random number
run			execute program (at optional line number)
save			save current BASIC program
scursmode		alter cursor mode
seek			seek to a new data (disk) file position
set640			select video mode
setbdcol		set border colour
setbgcol		set text background colour
setfgcol		set text foreground colour
setpal			set video pallette entry
setvap			set video software access page
setvdp			set video display page
sgbgcol			set graphics background colour
sgfgcol			set graphics foreground colour
sgtexture		set graphics line texture
sgn			sign of argument
shell			return to 1616/OS but do not exit BASIC
sin			sine
space$			creates a string full of spaces
sqr			square root
stop			stop program execution
str$			converts a string to a number
strings			creates a string filled with ine ASCII constant
syscall			perform 1616/OS system call
system			exit BASIC and return to 1616/OS
tab			spaces over to an absolute print position
tan			derived function
tell			return current position within a data (disk) file
time$			read the current date/time as a formatted string
val			converts a string containing a number to numeric value
varptr			get address to variable
wend			end 'while’ loop
while			program loop that executes as long as a given condition is true
write			output data to file
xor			exclusive ‘or’